uni

University stuff
git clone git://git.margiolis.net/uni.git
Log | Files | Refs | README | LICENSE

sock_client.c (4454B)


      1 #include <sys/socket.h>
      2 #include <sys/types.h>
      3 
      4 #include <arpa/inet.h>
      5 #include <netdb.h>
      6 #include <netinet/in.h>
      7 
      8 #include <err.h>
      9 #include <libgen.h>
     10 #include <stdarg.h>
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include <unistd.h>
     15 
     16 static void	esend(int, void *, size_t, int);
     17 static void	erecv(int, void *, size_t, int);
     18 static void	*emalloc(size_t);
     19 static void	safe_scanf(void *, char *, char *, ...);
     20 static void	calc_avg(int);
     21 static void	calc_minmax(int);
     22 static void	calc_prod(int);
     23 static void	usage(void);
     24 
     25 static char	*argv0;
     26 
     27 /*
     28  * Error checking send(2).
     29  */
     30 static void
     31 esend(int fd, void *msg, size_t len, int flags)
     32 {
     33 	if (send(fd, msg, len, flags) < 0)
     34 		err(1, "send");
     35 }
     36 
     37 /*
     38  * Error checking recv(2).
     39  */
     40 static void
     41 erecv(int fd, void *msg, size_t len, int flags)
     42 {
     43 	if (recv(fd, msg, len, flags) < 0)
     44 		err(1, "recv");
     45 }
     46 
     47 /*
     48  * Error checking malloc(3).
     49  */
     50 static void *
     51 emalloc(size_t nb)
     52 {
     53 	void *p;
     54 
     55 	if ((p = malloc(nb)) == NULL)
     56 		err(1, "malloc");
     57 	return (p);
     58 }
     59 
     60 /*
     61  * The server might break if we give it incorrent input, so we have to make
     62  * sure we'll always read proper input from scanf() before we send it to the
     63  * server.
     64  */
     65 static void
     66 safe_scanf(void *n, char *type, char *fmt, ...)
     67 {
     68 	va_list ap;
     69 	char buf[BUFSIZ];
     70 	int rc;
     71 
     72 	do {
     73 		va_start(ap, fmt);
     74 		vsprintf(buf, fmt, ap);
     75 		va_end(ap);
     76 		printf("\r%s", buf);
     77 		rc = scanf(type, n);
     78 		(void)getchar();
     79 	} while (rc != 1);
     80 }
     81 
     82 static void
     83 calc_avg(int fd)
     84 {
     85 	float res;
     86 	int *arr, n, i;
     87 
     88 	safe_scanf(&n, "%d", "%s> n: ", argv0);
     89 	arr = emalloc(n * sizeof(int));
     90 	for (i = 0; i < n; i++)
     91 		safe_scanf(&arr[i], "%d", "%s> arr[%d]: ", argv0, i);
     92 
     93 	esend(fd, &n, sizeof(int), 0);
     94 	esend(fd, arr, n * sizeof(int), 0);
     95 	
     96 	erecv(fd, &res, sizeof(float), 0);
     97 	printf("[%s] server response: %.3f\n", argv0, res);
     98 
     99 	free(arr);
    100 }
    101 
    102 static void
    103 calc_minmax(int fd)
    104 {
    105 	int res[2], *arr, n, i;
    106 
    107 	safe_scanf(&n, "%d", "%s> n: ", argv0);
    108 	arr = emalloc(n * sizeof(int));
    109 	for (i = 0; i < n; i++)
    110 		safe_scanf(&arr[i], "%d", "%s> arr[%d]: ", argv0, i);
    111 
    112 	esend(fd, &n, sizeof(int), 0);
    113 	esend(fd, arr, n * sizeof(int), 0);
    114 
    115 	erecv(fd, &res, 2 * sizeof(int), 0);
    116 	printf("[%s] server response: min: %d, max: %d\n",
    117 	    argv0, res[0], res[1]);
    118 
    119 	free(arr);
    120 }
    121 
    122 static void
    123 calc_prod(int fd)
    124 {
    125 	float *res, a;
    126 	int *arr, n, i;
    127 
    128 	safe_scanf(&a, "%f", "%s> a: ", argv0);
    129 	safe_scanf(&n, "%d", "%s> n: ", argv0);
    130 	arr = emalloc(n * sizeof(int));
    131 	for (i = 0; i < n; i++)
    132 		safe_scanf(&arr[i], "%d", "%s> arr[%d]: ", argv0, i);
    133 
    134 	esend(fd, &a, sizeof(float), 0);
    135 	esend(fd, &n, sizeof(int), 0);
    136 	esend(fd, arr, n * sizeof(int), 0);
    137 
    138 	res = emalloc(n * sizeof(float));
    139 	erecv(fd, res, n * sizeof(float), 0);
    140 	printf("[%s] server response: [", argv0);
    141 	for (i = 0; i < n; i++)
    142 		printf("%.3f%s", res[i], i == n - 1 ? "" : ", ");
    143 	printf("]\n");
    144 
    145 	free(arr);
    146 	free(res);
    147 }
    148 
    149 static void
    150 usage(void)
    151 {
    152 	fprintf(stderr, "usage: %s [-p port] hostname\n", argv0);
    153 	exit(0);
    154 }
    155 
    156 int
    157 main(int argc, char *argv[])
    158 {
    159 	struct sockaddr_in sin;
    160 	struct hostent *hp;
    161 	int port = 9999;
    162 	int fd, n;
    163 	char *host, ch;
    164 
    165 	argv0 = basename(*argv);
    166 	while ((ch = getopt(argc, argv, "p:")) != -1) {
    167 		switch (ch) {
    168 		case 'p':
    169 			if ((port = atoi(optarg)) < 1024)
    170 				errx(1, "can't use port number < 1024");
    171 			break;
    172 		case '?':
    173 		default:
    174 			usage();
    175 		}
    176 	}
    177 	argc -= optind;
    178 	argv += optind;
    179 
    180 	if (argc < 1)
    181 		usage();
    182 	host = *argv;
    183 
    184 	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    185 		err(1, "socket(AF_INET)");
    186 	memset(&sin, 0, sizeof(sin));
    187 	sin.sin_family = AF_INET;
    188 	sin.sin_port = htons(port);
    189 	if (!inet_aton(host, &sin.sin_addr)) {
    190 		if ((hp = gethostbyname(host)) == NULL)
    191 			errx(1, "gethostbyname(%s) failed", host);
    192 		(void)memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
    193 	}
    194 	if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    195 		err(1, "connect");
    196 
    197 	for (;;) {
    198 		printf("1: average\n2: min and max\n3: product\n4: disconnect\n");
    199 		safe_scanf(&n, "%d", "%s> your choice: ", argv0);
    200 
    201 		switch (n) {
    202 		case 1:
    203 			/* 
    204 			 * Send our choice to the server so that it can read at
    205 			 * the appropriate RPC.
    206 			 */
    207 			esend(fd, &n, sizeof(int), 0);
    208 			calc_avg(fd);
    209 			break;
    210 		case 2:
    211 			esend(fd, &n, sizeof(int), 0);
    212 			calc_minmax(fd);
    213 			break;
    214 		case 3:
    215 			esend(fd, &n, sizeof(int), 0);
    216 			calc_prod(fd);
    217 			break;
    218 		case 4:
    219 			esend(fd, &n, sizeof(int), 0);
    220 			goto end;
    221 		default:
    222 			printf("[%s] invalid choice\n", argv0);
    223 		}
    224 	}
    225 end:
    226 	close(fd);
    227 
    228 	return (0);
    229 }