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 }