server.c (3976B)
1 #define _XOPEN_SOURCE 700 2 #define _DEFAULT_SOURCE 1 3 4 #include "mandelbrot.h" 5 6 #include <poll.h> 7 8 #include <sys/socket.h> 9 #include <netdb.h> 10 11 #include <sys/sysinfo.h> 12 13 #include <getopt.h> 14 15 struct opts { 16 int verbose; 17 int threads; 18 char *host, *port; 19 size_t max_clients; 20 } opts = { 21 .verbose = 0, 22 .threads = 1, 23 .host = "localhost", 24 .port = NULL, 25 .max_clients = 16, 26 }; 27 28 #define OPTSTR "hvt:a:p:" 29 30 static void 31 usage(char *prog) 32 { 33 fprintf(stderr, "Usage: %s [-hv] [-t <threads>] [-a <addr> -p <port>] " 34 "[-c <max-clients>]\n", prog); 35 fprintf(stderr, "\t-h : display usage information\n"); 36 fprintf(stderr, "\t-v : enable verbose logging\n"); 37 fprintf(stderr, "\t-t : set number of threads to use (default: 1)\n"); 38 fprintf(stderr, "\t-a : set socket addr to bind to (default: localhost)\n"); 39 fprintf(stderr, "\t-p : set socket port to bind to (default: any)\n"); 40 fprintf(stderr, "\t-c : set maximum concurrent clients (default: 16)\n"); 41 } 42 43 static int 44 parse_opts(int argc, char **argv, struct opts *opts) 45 { 46 int opt; 47 while ((opt = getopt(argc, argv, OPTSTR)) > 0) { 48 switch (opt) { 49 case 'v': 50 opts->verbose = 1; 51 break; 52 53 case 't': 54 opts->threads = strtoull(optarg, NULL, 10); 55 if (opts->threads == 0) { 56 opts->threads = get_nprocs_conf(); 57 fprintf(stderr, "info: using %d threads\n", opts->threads); 58 } 59 break; 60 61 case 'a': 62 opts->host = optarg; 63 break; 64 65 case 'p': 66 opts->port = optarg; 67 break; 68 69 case 'c': 70 opts->max_clients = strtoull(optarg, NULL, 10); 71 if (opts->max_clients == 0) 72 opts->max_clients = 1; 73 break; 74 75 default: 76 return -1; 77 } 78 } 79 80 return 0; 81 } 82 83 static int 84 bind_socket(char const *host, char const *port) 85 { 86 struct addrinfo hints = { 87 .ai_family = AF_UNSPEC, 88 .ai_socktype = SOCK_STREAM, 89 .ai_protocol = IPPROTO_TCP, 90 .ai_flags = AI_PASSIVE, 91 }, *addrinfo, *ptr; 92 93 int res; 94 if ((res = getaddrinfo(host, port, &hints, &addrinfo))) { 95 fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(res)); 96 return -1; 97 } 98 99 int fd; 100 for (ptr = addrinfo; ptr; ptr = ptr->ai_next) { 101 fd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); 102 if (fd < 0) 103 continue; 104 105 if (bind(fd, ptr->ai_addr, ptr->ai_addrlen) < 0) { 106 close(fd); 107 continue; 108 } 109 110 if (listen(fd, 16) < 0) { 111 close(fd); 112 continue; 113 } 114 115 break; 116 } 117 118 freeaddrinfo(addrinfo); 119 120 if (!ptr) 121 return -1; 122 123 struct sockaddr_storage addr; 124 socklen_t addrlen = sizeof addr; 125 getsockname(fd, (struct sockaddr *) &addr, &addrlen); 126 127 char hostbuf[NI_MAXHOST], servbuf[NI_MAXSERV]; 128 getnameinfo((struct sockaddr *) &addr, addrlen, 129 hostbuf, sizeof hostbuf, servbuf, sizeof servbuf, 130 NI_NUMERICHOST | NI_NUMERICSERV); 131 132 printf("Bound socket to %s:%s\n", hostbuf, servbuf); 133 134 return fd; 135 } 136 137 int 138 main(int argc, char **argv) 139 { 140 if (parse_opts(argc, argv, &opts) < 0) { 141 usage(argv[0]); 142 exit(EXIT_FAILURE); 143 } 144 145 if (opts.verbose) { 146 fprintf(stderr, "info: verbose: %d\n", opts.verbose); 147 fprintf(stderr, "info: threads: %d\n", opts.threads); 148 fprintf(stderr, "info: sockaddr: %s:%s\n", 149 opts.host, opts.port ? opts.port : "0"); 150 } 151 152 int socket = bind_socket(opts.host, opts.port); 153 assert(socket > 0); 154 155 while (1) { 156 int client = accept(socket, NULL, NULL); 157 printf("[%d] accept()\n", client); 158 159 struct render_region region; 160 size_t nbytes_recv = recvall(client, ®ion, sizeof region); 161 printf("[%d] recv() %zu bytes\n", client, nbytes_recv); 162 163 size_t pixels = region.xres * region.yres; 164 165 uint32_t *iterbuf = malloc(pixels * sizeof *iterbuf); 166 assert(iterbuf); 167 168 float *abs2buf = malloc(pixels * sizeof *abs2buf); 169 assert(abs2buf); 170 171 render_region(®ion, iterbuf, abs2buf); 172 173 size_t nbytes_send = 0; 174 nbytes_send += sendall(client, iterbuf, pixels * sizeof *iterbuf); 175 nbytes_send += sendall(client, abs2buf, pixels * sizeof *abs2buf); 176 printf("[%d] send() %zu bytes\n", client, nbytes_send); 177 178 free(abs2buf); 179 free(iterbuf); 180 181 close(client); 182 printf("[%d] close()\n", client); 183 } 184 185 exit(EXIT_SUCCESS); 186 }