uni

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

rpc_client.c (6644B)


      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 <signal.h>
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include <unistd.h>
     15 
     16 #include "rpc.h"
     17 
     18 static void	serve_client(char *, int);
     19 static void	sighandler(int);
     20 static void	*emalloc(size_t);
     21 static void	usage(void);
     22 
     23 /* program name */
     24 static char	*argv0;
     25 /* becomes true when a termination signal is caught */
     26 static volatile sig_atomic_t f_quit = 0;
     27 
     28 void
     29 calc_avg_prog_1(char *host, int sock)
     30 {
     31 	CLIENT *clnt;
     32 	float  *result_1;
     33 	arg_arr  calc_avg_1_arg;
     34 	int *np, *arrp;
     35 
     36 #ifndef	DEBUG
     37 	clnt = clnt_create(host, calc_avg_PROG, calc_avg_VERS, "netpath");
     38 	if (clnt == (CLIENT *) NULL) {
     39 		clnt_pcreateerror(host);
     40 		exit(1);
     41 	}
     42 #endif	/* DEBUG */
     43 	
     44 	/* avoid typing all this */
     45 	np = &calc_avg_1_arg.n;
     46 
     47 	/* receive number of elements */
     48 	if (recv(sock, np, sizeof(int), 0) < 0)
     49 		goto fail;
     50 	calc_avg_1_arg.arr.arr_len = *np;
     51 	calc_avg_1_arg.arr.arr_val = emalloc(*np * sizeof(int));
     52 	arrp = calc_avg_1_arg.arr.arr_val;
     53 
     54 	/* receive array */
     55 	if (recv(sock, arrp, *np * sizeof(int), 0) < 0)
     56 		goto fail;
     57 
     58 	/* make RPC */
     59 	result_1 = calc_avg_1(&calc_avg_1_arg, clnt);
     60 	if (result_1 == (float *) NULL) {
     61 		clnt_perror(clnt, "call failed");
     62 	}
     63 
     64 	/* send results back to sock_client */
     65 	printf("[%s] sock: %d\tserver response: avg: %.3f\n", argv0, sock, *result_1);
     66 	if (send(sock, result_1, sizeof(float), 0) < 0)
     67 		goto fail;
     68 	return;
     69 fail:
     70 	/* we failed... */
     71 	fprintf(stderr, "[%s] connection with client %d dropped\n", argv0, sock);
     72 	close(sock);
     73 	if (arrp != NULL)
     74 		free(arrp);
     75 #ifndef	DEBUG
     76 	clnt_destroy(clnt);
     77 #endif		/* DEBUG */
     78 }
     79 
     80 
     81 void
     82 calc_minmax_prog_1(char *host, int sock)
     83 {
     84 	CLIENT *clnt;
     85 	struct minmax  *result_1;
     86 	arg_arr  calc_minmax_1_arg;
     87 	int i, *np, *arrp;
     88 
     89 #ifndef	DEBUG
     90 	clnt = clnt_create(host, calc_minmax_PROG, calc_minmax_VERS, "netpath");
     91 	if (clnt == (CLIENT *) NULL) {
     92 		clnt_pcreateerror(host);
     93 		exit(1);
     94 	}
     95 #endif	/* DEBUG */
     96 
     97 	np = &calc_minmax_1_arg.n;
     98 
     99 	if (recv(sock, np, sizeof(int), 0) < 0)
    100 		goto fail;
    101 	calc_minmax_1_arg.arr.arr_len = *np;
    102 	calc_minmax_1_arg.arr.arr_val = emalloc(*np * sizeof(int));
    103 	arrp = calc_minmax_1_arg.arr.arr_val;
    104 
    105 	if (recv(sock, arrp, *np * sizeof(int), 0) < 0)
    106 		goto fail;
    107 
    108 	result_1 = calc_minmax_1(&calc_minmax_1_arg, clnt);
    109 	if (result_1 == (struct minmax *) NULL) {
    110 		clnt_perror(clnt, "call failed");
    111 	}
    112 
    113 	printf("[%s] sock: %d\tserver response: min: %d, max: %d\n",
    114 	    argv0, sock, result_1->arr.arr_val[0], result_1->arr.arr_val[1]);
    115 	if (send(sock, result_1->arr.arr_val, 2 * sizeof(int), 0) < 0)
    116 		goto fail;
    117 	return;
    118 fail:
    119 	fprintf(stderr, "[%s] connection with client %d dropped\n", argv0, sock);
    120 	close(sock);
    121 	if (arrp != NULL)
    122 		free(arrp);
    123 #ifndef	DEBUG
    124 	clnt_destroy(clnt);
    125 #endif		/* DEBUG */
    126 }
    127 
    128 
    129 void
    130 calc_prod_prog_1(char *host, int sock)
    131 {
    132 	CLIENT *clnt;
    133 	struct float_arr  *result_1;
    134 	arg_prod  calc_prod_1_arg;
    135 	int i, *np, *arrp;
    136 	float *ap;
    137 
    138 #ifndef	DEBUG
    139 	clnt = clnt_create(host, calc_prod_PROG, calc_prod_VERS, "netpath");
    140 	if (clnt == (CLIENT *) NULL) {
    141 		clnt_pcreateerror(host);
    142 		exit(1);
    143 	}
    144 #endif	/* DEBUG */
    145 
    146 	ap = &calc_prod_1_arg.a;
    147 	np = &calc_prod_1_arg.arr.n;
    148 
    149 	if (recv(sock, ap, sizeof(float), 0) < 0)
    150 		goto fail;
    151 	if (recv(sock, np, sizeof(int), 0) < 0)
    152 		goto fail;
    153 	calc_prod_1_arg.arr.arr.arr_len = *np;
    154 	calc_prod_1_arg.arr.arr.arr_val = emalloc(*np * sizeof(int));
    155 	arrp = calc_prod_1_arg.arr.arr.arr_val;
    156 
    157 	if (recv(sock, arrp, *np * sizeof(int), 0) < 0)
    158 		goto fail;
    159 
    160 	result_1 = calc_prod_1(&calc_prod_1_arg, clnt);
    161 	if (result_1 == (struct float_arr *) NULL) {
    162 		clnt_perror(clnt, "call failed");
    163 	}
    164 
    165 	printf("[%s] sock: %d\tserver response: [", argv0, sock);
    166 	for (i = 0; i < calc_prod_1_arg.arr.n; i++) {
    167 		printf("%.3f%s", result_1->arr.arr_val[i],
    168 		    i == calc_prod_1_arg.arr.n - 1 ? "" : ", ");
    169 	}
    170 	printf("]\n");
    171 
    172 	if (send(sock, result_1->arr.arr_val, *np * sizeof(float), 0) < 0)
    173 		goto fail;
    174 	return;
    175 fail:
    176 	fprintf(stderr, "[%s] connection with client %d dropped\n", argv0, sock);
    177 	close(sock);
    178 	if (arrp != NULL)
    179 		free(arrp);
    180 #ifndef	DEBUG
    181 	clnt_destroy(clnt);
    182 #endif		/* DEBUG */
    183 }
    184 
    185 static void
    186 serve_client(char *host, int cfd)
    187 {
    188 	int n;
    189 
    190 	for (;;) {
    191 		/* receive option */
    192 		if (recv(cfd, &n, sizeof(int), 0) < 0) {
    193 			/* something went wrong, we cant continue */
    194 			fprintf(stderr, "[%s] connection with %d dropped\n",
    195 			    argv0, cfd);
    196 			close(cfd);
    197 			_exit(0);
    198 		}
    199 		switch (n) {
    200 		case 1:
    201 			calc_avg_prog_1(host, cfd);
    202 			break;
    203 		case 2:
    204 			calc_minmax_prog_1(host, cfd);
    205 			break;
    206 		case 3:
    207 			calc_prod_prog_1(host, cfd);
    208 			break;
    209 		case 4:
    210 			printf("[%s] sock %d disconnected\n", argv0, cfd);
    211 			close(cfd);
    212 			return;
    213 		}
    214 	}
    215 }
    216 
    217 /*
    218  * Gets called in case of a SIGINT or SIGTERM.
    219  */
    220 static void
    221 sighandler(int sig)
    222 {
    223 	f_quit = 1;
    224 }
    225 
    226 /*
    227  * Error checking malloc(3).
    228  */
    229 static void *
    230 emalloc(size_t nb)
    231 {
    232 	void *p;
    233 
    234 	if ((p = malloc(nb)) == NULL)
    235 		err(1, "malloc");
    236 	return (p);
    237 }
    238 
    239 static void
    240 usage(void)
    241 {
    242 	fprintf(stderr, "usage: %s [-b backlog] [-p port] hostname\n", argv0);
    243 	exit(0);
    244 }
    245 
    246 int
    247 main(int argc, char *argv[])
    248 {
    249 	struct sockaddr_in sin;
    250 	struct hostent *hp;
    251 	struct sigaction sa;
    252 	int backlog = 5;
    253 	int port = 9999;
    254 	int sfd, cfd;
    255 	char *host, ch;
    256 
    257 	argv0 = basename(*argv);
    258 	while ((ch = getopt(argc, argv, "b:p:")) != -1) {
    259 		switch (ch) {
    260 		case 'b':
    261 			if ((backlog = atoi(optarg)) < 1)
    262 				errx(1, "backlog value must be > 1");
    263 			break;
    264 		case 'p':
    265 			if ((port = atoi(optarg)) < 1024)
    266 				errx(1, "can't use port number < 1024");
    267 			break;
    268 		case '?':
    269 		default:
    270 			usage();
    271 		}
    272 	}
    273 	argc -= optind;
    274 	argv += optind;
    275 
    276 	if (argc < 1)
    277 		usage();
    278 	host = *argv;
    279 
    280 	memset(&sa, 0, sizeof(sa));
    281 	sigfillset(&sa.sa_mask);
    282 	sa.sa_handler = sighandler;
    283 
    284 	/* be sensitive to termination signals */
    285 	if (sigaction(SIGINT, &sa, NULL) < 0)
    286 		err(1, "sigaction(SIGINT)");
    287 	if (sigaction(SIGTERM, &sa, NULL) < 0)
    288 		err(1, "sigaction(SIGTERM)");
    289 
    290 	if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    291 		err(1, "socket(AF_INET)");
    292 	memset(&sin, 0, sizeof(sin));
    293 	sin.sin_family = AF_INET;
    294 	sin.sin_port = htons(port);
    295 	sin.sin_addr.s_addr = INADDR_ANY;
    296 	if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    297 		err(1, "connect");
    298 	if (listen(sfd, backlog) < 0)
    299 		err(1, "listen");
    300 
    301 	for (;;) {
    302 		if (f_quit)
    303 			break;
    304 
    305 		if ((cfd = accept(sfd, NULL, NULL)) < 0)
    306 			continue;
    307 		printf("[%s] accepted client at sock: %d\n", argv0, cfd);
    308 
    309 		switch (fork()) {
    310 		case -1:
    311 			err(1, "fork");
    312 		case 0:
    313 			serve_client(host, cfd);
    314 			_exit(0);
    315 		default:
    316 			close(cfd);
    317 		}
    318 
    319 	}
    320 	close(sfd);
    321 
    322 	return (0);
    323 }