File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpc / src / minihttptestserver.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Sep 27 11:21:37 2023 UTC (9 months ago) by misho
Branches: miniupnpc, MAIN
CVS tags: v2_2_5p0, HEAD
Version 2.2.5p0

    1: /* $Id: minihttptestserver.c,v 1.1.1.1 2023/09/27 11:21:37 misho Exp $ */
    2: /* Project : miniUPnP
    3:  * Author : Thomas Bernard
    4:  * Copyright (c) 2011-2018 Thomas Bernard
    5:  * This software is subject to the conditions detailed in the
    6:  * LICENCE file provided in this distribution.
    7:  * */
    8: #include <stdio.h>
    9: #include <stdlib.h>
   10: #include <string.h>
   11: #include <unistd.h>
   12: #include <sys/types.h>
   13: #include <sys/socket.h>
   14: #include <sys/wait.h>
   15: #include <arpa/inet.h>
   16: #include <netinet/in.h>
   17: #include <signal.h>
   18: #include <time.h>
   19: #include <errno.h>
   20: 
   21: #ifndef INADDR_LOOPBACK
   22: #define INADDR_LOOPBACK         0x7f000001
   23: #endif
   24: 
   25: #define CRAP_LENGTH (2048)
   26: 
   27: static int server(unsigned short port, const char * expected_file_name, int ipv6);
   28: 
   29: volatile sig_atomic_t quit = 0;
   30: volatile sig_atomic_t child_to_wait_for = 0;
   31: 
   32: /**
   33:  * signal handler for SIGCHLD (child status has changed)
   34:  */
   35: void handle_signal_chld(int sig)
   36: {
   37: 	(void)sig;
   38: 	/* printf("handle_signal_chld(%d)\n", sig); */
   39: 	++child_to_wait_for;
   40: }
   41: 
   42: /**
   43:  * signal handler for SIGINT (CRTL C)
   44:  */
   45: void handle_signal_int(int sig)
   46: {
   47: 	(void)sig;
   48: 	/* printf("handle_signal_int(%d)\n", sig); */
   49: 	quit = 1;
   50: }
   51: 
   52: /**
   53:  * build a text/plain content of the specified length
   54:  */
   55: void build_content(char * p, size_t n)
   56: {
   57: 	char line_buffer[80];
   58: 	int k;
   59: 	int i = 0;
   60: 
   61: 	while(n > 0) {
   62: 		k = snprintf(line_buffer, sizeof(line_buffer),
   63: 		             "%04d_ABCDEFGHIJKL_This_line_is_64_bytes_long_ABCDEFGHIJKL_%04d\r\n",
   64: 		             i, i);
   65: 		if(k != 64) {
   66: 			fprintf(stderr, "snprintf() returned %d in build_content()\n", k);
   67: 		}
   68: 		++i;
   69: 		if(n >= 64) {
   70: 			memcpy(p, line_buffer, 64);
   71: 			p += 64;
   72: 			n -= 64;
   73: 		} else {
   74: 			memcpy(p, line_buffer, n);
   75: 			p += n;
   76: 			n = 0;
   77: 		}
   78: 	}
   79: }
   80: 
   81: /**
   82:  * build crappy content
   83:  */
   84: void build_crap(char * p, size_t n)
   85: {
   86: 	static const char crap[] = "_CRAP_\r\n";
   87: 	size_t i;
   88: 
   89: 	while(n > 0) {
   90: 		i = sizeof(crap) - 1;
   91: 		if(i > n)
   92: 			i = n;
   93: 		memcpy(p, crap, i);
   94: 		p += i;
   95: 		n -= i;
   96: 	}
   97: }
   98: 
   99: /**
  100:  * build chunked response.
  101:  * return a malloc'ed buffer
  102:  */
  103: char * build_chunked_response(size_t content_length, size_t * response_len)
  104: {
  105: 	char * response_buffer;
  106: 	char * content_buffer;
  107: 	size_t buffer_length;
  108: 	size_t i;
  109: 	unsigned int n;
  110: 
  111: 	/* allocate to have some margin */
  112: 	buffer_length = 256 + content_length + (content_length >> 4);
  113: 	response_buffer = malloc(buffer_length);
  114: 	if(response_buffer == NULL)
  115: 		return NULL;
  116: 	*response_len = snprintf(response_buffer, buffer_length,
  117: 	                         "HTTP/1.1 200 OK\r\n"
  118: 	                         "Content-Type: text/plain\r\n"
  119: 	                         "Transfer-Encoding: chunked\r\n"
  120: 	                         "\r\n");
  121: 
  122: 	/* build the content */
  123: 	content_buffer = malloc(content_length);
  124: 	if(content_buffer == NULL) {
  125: 		free(response_buffer);
  126: 		return NULL;
  127: 	}
  128: 	build_content(content_buffer, content_length);
  129: 
  130: 	/* chunk it */
  131: 	i = 0;
  132: 	while(i < content_length) {
  133: 		n = (rand() % 199) + 1;
  134: 		if(i + n > content_length) {
  135: 			n = content_length - i;
  136: 		}
  137: 		/* TODO : check buffer size ! */
  138: 		*response_len += snprintf(response_buffer + *response_len,
  139: 		                          buffer_length - *response_len,
  140: 		                          "%x\r\n", n);
  141: 		memcpy(response_buffer + *response_len, content_buffer + i, n);
  142: 		*response_len += n;
  143: 		i += n;
  144: 		response_buffer[(*response_len)++] = '\r';
  145: 		response_buffer[(*response_len)++] = '\n';
  146: 	}
  147: 	/* the last chunk : "0\r\n" a empty body and then
  148: 	 * the final "\r\n" */
  149: 	memcpy(response_buffer + *response_len, "0\r\n\r\n", 5);
  150: 	*response_len += 5;
  151: 	free(content_buffer);
  152: 
  153: 	printf("resp_length=%lu buffer_length=%lu content_length=%lu\n",
  154: 	       *response_len, buffer_length, content_length);
  155: 	return response_buffer;
  156: }
  157: 
  158: /* favicon.ico generator */
  159: #ifdef OLD_HEADER
  160: #define FAVICON_LENGTH (6 + 16 + 12 + 8 + 32 * 4)
  161: #else
  162: #define FAVICON_LENGTH (6 + 16 + 40 + 8 + 32 * 4)
  163: #endif
  164: void build_favicon_content(unsigned char * p, size_t n)
  165: {
  166: 	int i;
  167: 	if(n < FAVICON_LENGTH)
  168: 		return;
  169: 	/* header : 6 bytes */
  170: 	*p++ = 0;
  171: 	*p++ = 0;
  172: 	*p++ = 1;	/* type : ICO */
  173: 	*p++ = 0;
  174: 	*p++ = 1;	/* number of images in file */
  175: 	*p++ = 0;
  176: 	/* image directory (1 entry) : 16 bytes */
  177: 	*p++ = 16;	/* width */
  178: 	*p++ = 16;	/* height */
  179: 	*p++ = 2;	/* number of colors in the palette. 0 = no palette */
  180: 	*p++ = 0;	/* reserved */
  181: 	*p++ = 1;	/* color planes */
  182: 	*p++ = 0;	/* " */
  183: 	*p++ = 1;	/* bpp */
  184: 	*p++ = 0;	/* " */
  185: #ifdef OLD_HEADER
  186: 	*p++ = 12 + 8 + 32 * 4;	/* bmp size */
  187: #else
  188: 	*p++ = 40 + 8 + 32 * 4;	/* bmp size */
  189: #endif
  190: 	*p++ = 0;	/* " */
  191: 	*p++ = 0;	/* " */
  192: 	*p++ = 0;	/* " */
  193: 	*p++ = 6 + 16;	/* bmp offset */
  194: 	*p++ = 0;	/* " */
  195: 	*p++ = 0;	/* " */
  196: 	*p++ = 0;	/* " */
  197: 	/* BMP */
  198: #ifdef OLD_HEADER
  199: 	/* BITMAPCOREHEADER */
  200: 	*p++ = 12;	/* size of this header */
  201: 	*p++ = 0;	/* " */
  202: 	*p++ = 0;	/* " */
  203: 	*p++ = 0;	/* " */
  204: 	*p++ = 16;	/* width */
  205: 	*p++ = 0;	/* " */
  206: 	*p++ = 16 * 2;	/* height x 2 ! */
  207: 	*p++ = 0;	/* " */
  208: 	*p++ = 1;	/* color planes */
  209: 	*p++ = 0;	/* " */
  210: 	*p++ = 1;	/* bpp */
  211: 	*p++ = 0;	/* " */
  212: #else
  213: 	/* BITMAPINFOHEADER */
  214: 	*p++ = 40;	/* size of this header */
  215: 	*p++ = 0;	/* " */
  216: 	*p++ = 0;	/* " */
  217: 	*p++ = 0;	/* " */
  218: 	*p++ = 16;	/* width */
  219: 	*p++ = 0;	/* " */
  220: 	*p++ = 0;	/* " */
  221: 	*p++ = 0;	/* " */
  222: 	*p++ = 16 * 2;	/* height x 2 ! */
  223: 	*p++ = 0;	/* " */
  224: 	*p++ = 0;	/* " */
  225: 	*p++ = 0;	/* " */
  226: 	*p++ = 1;	/* color planes */
  227: 	*p++ = 0;	/* " */
  228: 	*p++ = 1;	/* bpp */
  229: 	*p++ = 0;	/* " */
  230: 	/* compression method, image size, ppm x, ppm y */
  231: 	/* colors in the palette ? */
  232: 	/* important colors */
  233: 	for(i = 4 * 6; i > 0; --i)
  234: 		*p++ = 0;
  235: #endif
  236: 	/* palette */
  237: 	*p++ = 0;	/* b */
  238: 	*p++ = 0;	/* g */
  239: 	*p++ = 0;	/* r */
  240: 	*p++ = 0;	/* reserved */
  241: 	*p++ = 255;	/* b */
  242: 	*p++ = 255;	/* g */
  243: 	*p++ = 255;	/* r */
  244: 	*p++ = 0;	/* reserved */
  245: 	/* pixel data */
  246: 	for(i = 16; i > 0; --i) {
  247: 		if(i & 1) {
  248: 			*p++ = 0125;
  249: 			*p++ = 0125;
  250: 		} else {
  251: 			*p++ = 0252;
  252: 			*p++ = 0252;
  253: 		}
  254: 		*p++ = 0;
  255: 		*p++ = 0;
  256: 	}
  257: 	/* Opacity MASK */
  258: 	for(i = 16 * 4; i > 0; --i) {
  259: 		*p++ = 0;
  260: 	}
  261: }
  262: 
  263: enum modes {
  264: 	MODE_INVALID, MODE_CHUNKED, MODE_ADDCRAP, MODE_NORMAL, MODE_FAVICON, MODE_MALFORMED
  265: };
  266: 
  267: const struct {
  268: 	const enum modes mode;
  269: 	const char * text;
  270: } modes_array[] = {
  271: 	{MODE_CHUNKED, "chunked"},
  272: 	{MODE_ADDCRAP, "addcrap"},
  273: 	{MODE_NORMAL, "normal"},
  274: 	{MODE_FAVICON, "favicon.ico"},
  275: 	{MODE_MALFORMED, "malformed"},
  276: 	{MODE_INVALID, NULL}
  277: };
  278: 
  279: /**
  280:  * write the response with random behaviour !
  281:  */
  282: void send_response(int c, const char * buffer, size_t len)
  283: {
  284: 	ssize_t n;
  285: 	while(len > 0) {
  286: 		n = (rand() % 99) + 1;
  287: 		if((size_t)n > len)
  288: 			n = len;
  289: 		n = write(c, buffer, n);
  290: 		if(n < 0) {
  291: 			if(errno != EINTR) {
  292: 				perror("write");
  293: 				return;
  294: 			}
  295: 			/* if errno == EINTR, try again */
  296: 		} else {
  297: 			len -= n;
  298: 			buffer += n;
  299: 			usleep(10000); /* 10ms */
  300: 		}
  301: 	}
  302: }
  303: 
  304: /**
  305:  * handle the HTTP connection
  306:  */
  307: void handle_http_connection(int c)
  308: {
  309: 	char request_buffer[2048];
  310: 	size_t request_len = 0;
  311: 	int headers_found = 0;
  312: 	ssize_t n, m;
  313: 	size_t i;
  314: 	char request_method[16];
  315: 	char request_uri[256];
  316: 	char http_version[16];
  317: 	char * p;
  318: 	char * response_buffer;
  319: 	size_t response_len;
  320: 	enum modes mode;
  321: 	size_t content_length = 16*1024;
  322: 
  323: 	/* read the request */
  324: 	while(request_len < sizeof(request_buffer) && !headers_found) {
  325: 		n = read(c,
  326: 		         request_buffer + request_len,
  327: 		         sizeof(request_buffer) - request_len);
  328: 		if(n < 0) {
  329: 			if(errno == EINTR)
  330: 				continue;
  331: 			perror("read");
  332: 			return;
  333: 		} else if(n==0) {
  334: 			/* remote host closed the connection */
  335: 			break;
  336: 		} else {
  337: 			request_len += n;
  338: 			for(i = 0; i < request_len - 3; i++) {
  339: 				if(0 == memcmp(request_buffer + i, "\r\n\r\n", 4)) {
  340: 					/* found the end of headers */
  341: 					headers_found = 1;
  342: 					break;
  343: 				}
  344: 			}
  345: 		}
  346: 	}
  347: 	if(!headers_found) {
  348: 		/* error */
  349: 		printf("no HTTP header found in the request\n");
  350: 		return;
  351: 	}
  352: 	printf("headers :\n%.*s", (int)request_len, request_buffer);
  353: 	/* the request have been received, now parse the request line */
  354: 	p = request_buffer;
  355: 	for(i = 0; i < sizeof(request_method) - 1; i++) {
  356: 		if(*p == ' ' || *p == '\r')
  357: 			break;
  358: 		request_method[i] = *p;
  359: 		++p;
  360: 	}
  361: 	request_method[i] = '\0';
  362: 	while(*p == ' ')
  363: 		p++;
  364: 	for(i = 0; i < (int)sizeof(request_uri) - 1; i++) {
  365: 		if(*p == ' ' || *p == '\r')
  366: 			break;
  367: 		request_uri[i] = *p;
  368: 		++p;
  369: 	}
  370: 	request_uri[i] = '\0';
  371: 	while(*p == ' ')
  372: 		p++;
  373: 	for(i = 0; i < (int)sizeof(http_version) - 1; i++) {
  374: 		if(*p == ' ' || *p == '\r')
  375: 			break;
  376: 		http_version[i] = *p;
  377: 		++p;
  378: 	}
  379: 	http_version[i] = '\0';
  380: 	printf("Method = %s, URI = %s, %s\n",
  381: 	       request_method, request_uri, http_version);
  382: 	/* check if the request method is allowed */
  383: 	if(0 != strcmp(request_method, "GET")) {
  384: 		const char response405[] = "HTTP/1.1 405 Method Not Allowed\r\n"
  385: 		                           "Allow: GET\r\n\r\n";
  386: 		const char * pc;
  387: 		/* 405 Method Not Allowed */
  388: 		/* The response MUST include an Allow header containing a list
  389: 		 * of valid methods for the requested resource. */
  390: 		n = sizeof(response405) - 1;
  391: 		pc = response405;
  392: 		while(n > 0) {
  393: 			m = write(c, pc, n);
  394: 			if(m<0) {
  395: 				if(errno != EINTR) {
  396: 					perror("write");
  397: 					return;
  398: 				}
  399: 			} else {
  400: 				n -= m;
  401: 				pc += m;
  402: 			}
  403: 		}
  404: 		return;
  405: 	}
  406: 
  407: 	mode = MODE_INVALID;
  408: 	/* use the request URI to know what to do */
  409: 	for(i = 0; modes_array[i].mode != MODE_INVALID; i++) {
  410: 		if(strstr(request_uri, modes_array[i].text)) {
  411: 			mode = modes_array[i].mode; /* found */
  412: 			break;
  413: 		}
  414: 	}
  415: 
  416: 	switch(mode) {
  417: 	case MODE_MALFORMED:
  418: 		response_len = 2048;
  419: 		response_buffer = malloc(response_len);
  420: 		if(!response_buffer)
  421: 			break;
  422: 		n = snprintf(response_buffer, response_len,
  423: 		             "HTTP/1.1 \r\n"
  424: 					 "\r\n"
  425: 					 /*"0000\r\n"*/);
  426: 		for (i = n; i < response_len; i++) {
  427: 			response_buffer[i] = ' ';
  428: 		}
  429: 		response_len = n;
  430: 		break;
  431: 	case MODE_CHUNKED:
  432: 		response_buffer = build_chunked_response(content_length, &response_len);
  433: 		break;
  434: 	case MODE_ADDCRAP:
  435: 		response_len = content_length+256;
  436: 		response_buffer = malloc(response_len);
  437: 		if(!response_buffer)
  438: 			break;
  439: 		n = snprintf(response_buffer, response_len,
  440: 		             "HTTP/1.1 200 OK\r\n"
  441: 		             "Server: minihttptestserver\r\n"
  442: 		             "Content-Type: text/plain\r\n"
  443: 		             "Content-Length: %lu\r\n"
  444: 		             "\r\n", content_length);
  445: 		response_len = content_length+n+CRAP_LENGTH;
  446: 		p = realloc(response_buffer, response_len);
  447: 		if(p == NULL) {
  448: 			/* error 500 */
  449: 			free(response_buffer);
  450: 			response_buffer = NULL;
  451: 			break;
  452: 		}
  453: 		response_buffer = p;
  454: 		build_content(response_buffer + n, content_length);
  455: 		build_crap(response_buffer + n + content_length, CRAP_LENGTH);
  456: 		break;
  457: 	case MODE_FAVICON:
  458: 		content_length = FAVICON_LENGTH;
  459: 		response_len = content_length + 256;
  460: 		response_buffer = malloc(response_len);
  461: 		if(!response_buffer)
  462: 			break;
  463: 		n = snprintf(response_buffer, response_len,
  464: 		             "HTTP/1.1 200 OK\r\n"
  465: 		             "Server: minihttptestserver\r\n"
  466: 		             "Content-Type: image/vnd.microsoft.icon\r\n"
  467: 		             "Content-Length: %lu\r\n"
  468: 		             "\r\n", content_length);
  469: 		/* image/x-icon */
  470: 		build_favicon_content((unsigned char *)(response_buffer + n), content_length);
  471: 		response_len = content_length + n;
  472: 		break;
  473: 	default:
  474: 		response_len = content_length+256;
  475: 		response_buffer = malloc(response_len);
  476: 		if(!response_buffer)
  477: 			break;
  478: 		n = snprintf(response_buffer, response_len,
  479: 		             "HTTP/1.1 200 OK\r\n"
  480: 		             "Server: minihttptestserver\r\n"
  481: 		             "Content-Type: text/plain\r\n"
  482: 		             "\r\n");
  483: 		response_len = content_length+n;
  484: 		p = realloc(response_buffer, response_len);
  485: 		if(p == NULL) {
  486: 			/* Error 500 */
  487: 			free(response_buffer);
  488: 			response_buffer = NULL;
  489: 			break;
  490: 		}
  491: 		response_buffer = p;
  492: 		build_content(response_buffer + n, response_len - n);
  493: 	}
  494: 
  495: 	if(response_buffer) {
  496: 		send_response(c, response_buffer, response_len);
  497: 		free(response_buffer);
  498: 	} else {
  499: 		/* Error 500 */
  500: 	}
  501: }
  502: 
  503: /**
  504:  */
  505: int main(int argc, char * * argv) {
  506: 	int ipv6 = 0;
  507: 	int r, i;
  508: 	unsigned short port = 0;
  509: 	const char * expected_file_name = NULL;
  510: 
  511: 	for(i = 1; i < argc; i++) {
  512: 		if(argv[i][0] == '-') {
  513: 			switch(argv[i][1]) {
  514: 			case '6':
  515: 				ipv6 = 1;
  516: 				break;
  517: 			case 'e':
  518: 				/* write expected file ! */
  519: 				expected_file_name = argv[++i];
  520: 				break;
  521: 			case 'p':
  522: 				/* port */
  523: 				if(++i < argc) {
  524: 					port = (unsigned short)atoi(argv[i]);
  525: 				}
  526: 				break;
  527: 			default:
  528: 				fprintf(stderr, "unknown command line switch '%s'\n", argv[i]);
  529: 			}
  530: 		} else {
  531: 			fprintf(stderr, "unknown command line argument '%s'\n", argv[i]);
  532: 		}
  533: 	}
  534: 
  535: 	srand(time(NULL));
  536: 
  537: 	r = server(port, expected_file_name, ipv6);
  538: 	if(r != 0) {
  539: 		printf("*** ERROR ***\n");
  540: 	}
  541: 	return r;
  542: }
  543: 
  544: static int server(unsigned short port, const char * expected_file_name, int ipv6)
  545: {
  546: 	int s, c;
  547: 	int i;
  548: 	struct sockaddr_storage server_addr;
  549: 	socklen_t server_addrlen;
  550: 	struct sockaddr_storage client_addr;
  551: 	socklen_t client_addrlen;
  552: 	pid_t pid;
  553: 	int child = 0;
  554: 	int status;
  555: 	struct sigaction sa;
  556: 
  557: 	memset(&sa, 0, sizeof(struct sigaction));
  558: 
  559: 	/*signal(SIGCHLD, handle_signal_chld);*/
  560: 	sa.sa_handler = handle_signal_chld;
  561: 	if(sigaction(SIGCHLD, &sa, NULL) < 0) {
  562: 		perror("sigaction");
  563: 		return 1;
  564: 	}
  565: 	/*signal(SIGINT, handle_signal_int);*/
  566: 	sa.sa_handler = handle_signal_int;
  567: 	if(sigaction(SIGINT, &sa, NULL) < 0) {
  568: 		perror("sigaction");
  569: 		return 1;
  570: 	}
  571: 
  572: 	s = socket(ipv6 ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
  573: 	if(s < 0) {
  574: 		perror("socket");
  575: 		return 1;
  576: 	}
  577: 	memset(&server_addr, 0, sizeof(struct sockaddr_storage));
  578: 	memset(&client_addr, 0, sizeof(struct sockaddr_storage));
  579: 	if(ipv6) {
  580: 		struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr;
  581: 		addr->sin6_family = AF_INET6;
  582: 		addr->sin6_port = htons(port);
  583: 		addr->sin6_addr = in6addr_loopback;
  584: 	} else {
  585: 		struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr;
  586: 		addr->sin_family = AF_INET;
  587: 		addr->sin_port = htons(port);
  588: 		addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  589: 	}
  590: 	if(bind(s, (struct sockaddr *)&server_addr,
  591: 	        ipv6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) < 0) {
  592: 		perror("bind");
  593: 		return 1;
  594: 	}
  595: 	if(listen(s, 5) < 0) {
  596: 		perror("listen");
  597: 	}
  598: 	if(port == 0) {
  599: 		server_addrlen = sizeof(struct sockaddr_storage);
  600: 		if(getsockname(s, (struct sockaddr *)&server_addr, &server_addrlen) < 0) {
  601: 			perror("getsockname");
  602: 			return 1;
  603: 		}
  604: 		if(ipv6) {
  605: 			struct sockaddr_in6 * addr = (struct sockaddr_in6 *)&server_addr;
  606: 			port = ntohs(addr->sin6_port);
  607: 		} else {
  608: 			struct sockaddr_in * addr = (struct sockaddr_in *)&server_addr;
  609: 			port = ntohs(addr->sin_port);
  610: 		}
  611: 		printf("Listening on port %hu\n", port);
  612: 		fflush(stdout);
  613: 	}
  614: 
  615: 	/* write expected file */
  616: 	if(expected_file_name) {
  617: 		FILE * f;
  618: 		f = fopen(expected_file_name, "wb");
  619: 		if(f) {
  620: 			char * buffer;
  621: 			buffer = malloc(16*1024);
  622: 			if(buffer == NULL) {
  623: 				fprintf(stderr, "memory allocation error\n");
  624: 			} else {
  625: 				build_content(buffer, 16*1024);
  626: 				i = fwrite(buffer, 1, 16*1024, f);
  627: 				if(i != 16*1024) {
  628: 					fprintf(stderr, "error writing to file %s : %dbytes written (out of %d)\n", expected_file_name, i, 16*1024);
  629: 				}
  630: 				free(buffer);
  631: 			}
  632: 			fclose(f);
  633: 		} else {
  634: 			fprintf(stderr, "error opening file %s for writing\n", expected_file_name);
  635: 		}
  636: 	}
  637: 
  638: 	/* fork() loop */
  639: 	while(!child && !quit) {
  640: 		while(child_to_wait_for > 0) {
  641: 			pid = wait(&status);
  642: 			if(pid < 0) {
  643: 				perror("wait");
  644: 			} else {
  645: 				printf("child(%d) terminated with status %d\n", (int)pid, status);
  646: 			}
  647: 			--child_to_wait_for;
  648: 		}
  649: 		client_addrlen = sizeof(struct sockaddr_storage);
  650: 		c = accept(s, (struct sockaddr *)&client_addr,
  651: 		           &client_addrlen);
  652: 		if(c < 0) {
  653: 			if(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)
  654: 				continue;
  655: 			perror("accept");
  656: 			return 1;
  657: 		}
  658: 		printf("accept...\n");
  659: 		pid = fork();
  660: 		if(pid < 0) {
  661: 			perror("fork");
  662: 			return 1;
  663: 		} else if(pid == 0) {
  664: 			/* child */
  665: 			child = 1;
  666: 			close(s);
  667: 			s = -1;
  668: 			handle_http_connection(c);
  669: 		}
  670: 		close(c);
  671: 	}
  672: 	if(s >= 0) {
  673: 		close(s);
  674: 		s = -1;
  675: 	}
  676: 	if(!child) {
  677: 		while(child_to_wait_for > 0) {
  678: 			pid = wait(&status);
  679: 			if(pid < 0) {
  680: 				perror("wait");
  681: 			} else {
  682: 				printf("child(%d) terminated with status %d\n", (int)pid, status);
  683: 			}
  684: 			--child_to_wait_for;
  685: 		}
  686: 		printf("Bye...\n");
  687: 	}
  688: 	return 0;
  689: }
  690: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>