Annotation of embedaddon/miniupnpc/src/minihttptestserver.c, revision 1.1.1.1

1.1       misho       1: /* $Id: minihttptestserver.c,v 1.25 2020/05/29 21:14:22 nanard 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>