mandelbrot

mandelbrot.git
git clone git://git.lenczewski.org/mandelbrot.git
Log | Files | Refs

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, &region, 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(&region, 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 }