Annotation of embedaddon/axTLS/httpd/axhttpd.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (c) Cameron Rich
                      3:  * 
                      4:  * All rights reserved.
                      5:  * 
                      6:  * Redistribution and use in source and binary forms, with or without 
                      7:  * modification, are permitted provided that the following conditions are met:
                      8:  *
                      9:  * * Redistributions of source code must retain the above copyright notice, 
                     10:  *   this list of conditions and the following disclaimer.
                     11:  * * Redistributions in binary form must reproduce the above copyright notice, 
                     12:  *   this list of conditions and the following disclaimer in the documentation 
                     13:  *   and/or other materials provided with the distribution.
                     14:  * * Neither the name of the axTLS project nor the names of its contributors 
                     15:  *   may be used to endorse or promote products derived from this software 
                     16:  *   without specific prior written permission.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
                     19:  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
                     20:  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
                     21:  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
                     22:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
                     23:  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     24:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
                     25:  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
                     26:  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
                     27:  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
                     28:  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     29:  */
                     30: 
                     31: #include <stdio.h>
                     32: #include <string.h>
                     33: #include <sys/types.h>
                     34: #include <signal.h>
                     35: #include <stdlib.h>
                     36: #include <sys/stat.h>
                     37: 
                     38: #if !defined(WIN32)
                     39: #include <pwd.h>
                     40: #endif
                     41: #include "axhttp.h"
                     42: 
                     43: struct serverstruct *servers;
                     44: struct connstruct *usedconns;
                     45: struct connstruct *freeconns;
                     46: const char * const server_version = "axhttpd/"AXTLS_VERSION;
                     47: static const char *webroot = CONFIG_HTTP_WEBROOT;
                     48: 
                     49: static void addtoservers(int sd);
                     50: static int openlistener(char *address, int port);
                     51: static void handlenewconnection(int listenfd, int is_ssl);
                     52: static void addconnection(int sd, char *ip, int is_ssl);
                     53: static void ax_chdir(void);
                     54: 
                     55: #if defined(CONFIG_HTTP_HAS_CGI)
                     56: struct cgiextstruct *cgiexts;
                     57: static void addcgiext(const char *tp);
                     58: 
                     59: #if !defined(WIN32)
                     60: static void reaper(int sigtype) 
                     61: {
                     62:     while (wait3(NULL, WNOHANG, NULL) > 0)
                     63:         continue;
                     64: }
                     65: #endif
                     66: #endif
                     67: 
                     68: #ifdef CONFIG_HTTP_VERBOSE  /* should really be in debug mode or something */
                     69: /* clean up memory for valgrind */
                     70: static void sigint_cleanup(int sig)
                     71: {
                     72:     struct serverstruct *sp;
                     73:     struct connstruct *tp;
                     74: 
                     75:     while (servers != NULL) 
                     76:     {
                     77:         if (servers->is_ssl)
                     78:             ssl_ctx_free(servers->ssl_ctx);
                     79: 
                     80:         sp = servers->next;
                     81:         free(servers);
                     82:         servers = sp;
                     83:     }
                     84: 
                     85:     while (freeconns != NULL)
                     86:     {
                     87:         tp = freeconns->next;
                     88:         free(freeconns);
                     89:         freeconns = tp;
                     90:     }
                     91: 
                     92:     while (usedconns != NULL)
                     93:     {
                     94:         tp = usedconns->next;
                     95:         free(usedconns);
                     96:         usedconns = tp;
                     97:     }
                     98: 
                     99: #if defined(CONFIG_HTTP_HAS_CGI)
                    100:     while (cgiexts)
                    101:     {
                    102:         struct cgiextstruct *cp = cgiexts->next;
                    103:         if (cp == NULL) /* last entry */
                    104:             free(cgiexts->ext);
                    105:         free(cgiexts);
                    106:         cgiexts = cp;
                    107:     }
                    108: #endif
                    109: 
                    110:     exit(0);
                    111: }
                    112: 
                    113: static void die(int sigtype) 
                    114: {
                    115:     exit(0);
                    116: }
                    117: #endif
                    118: 
                    119: int main(int argc, char *argv[]) 
                    120: {
                    121:     fd_set rfds, wfds;
                    122:     struct connstruct *tp, *to;
                    123:     struct serverstruct *sp;
                    124:     int rnum, wnum, active;
                    125:     int i = 1;
                    126:     time_t currtime;
                    127:     char *httpAddress = NULL;
                    128:     int httpPort = CONFIG_HTTP_PORT;
                    129:     char *httpsAddress = NULL;
                    130:     int httpsPort = CONFIG_HTTP_HTTPS_PORT;
                    131:     char *portStr;
                    132: 
                    133: #ifdef WIN32
                    134:     WORD wVersionRequested = MAKEWORD(2, 2);
                    135:     WSADATA wsaData;
                    136:     WSAStartup(wVersionRequested,&wsaData);
                    137: #else
                    138:     signal(SIGPIPE, SIG_IGN);
                    139: #if defined(CONFIG_HTTP_HAS_CGI)
                    140:     signal(SIGCHLD, reaper);
                    141: #endif
                    142: #ifdef CONFIG_HTTP_VERBOSE
                    143:     signal(SIGQUIT, die);
                    144: #endif
                    145: #endif
                    146: 
                    147: #ifdef CONFIG_HTTP_VERBOSE
                    148:     signal(SIGTERM, die);
                    149:     signal(SIGINT, sigint_cleanup);
                    150: #endif
                    151:     tdate_init();
                    152: 
                    153:     /* get some command-line parameters */
                    154:     while (argv[i] != NULL)
                    155:     {
                    156:         if (strcmp(argv[i], "-p") == 0 && argv[i+1] != NULL)
                    157:         {
                    158:             if ((portStr = strchr(argv[i+1], ':')) != NULL)
                    159:             {
                    160:                 httpAddress = argv[i+1];
                    161:                 *portStr = 0;
                    162:                 httpPort = atoi(portStr + 1);
                    163:             }
                    164:             else
                    165:                 httpPort = atoi(argv[i+1]);
                    166: 
                    167:             i += 2;
                    168:             continue;
                    169:         }
                    170: 
                    171:         if (strcmp(argv[i], "-s") == 0 && argv[i+1] != NULL)
                    172:         {
                    173:             if ((portStr = strchr(argv[i+1], ':')) != NULL)
                    174:             {
                    175:                 httpsAddress = argv[i+1];
                    176:                 *portStr = 0;
                    177:                 httpsPort = atoi(portStr + 1);
                    178:             }
                    179:             else
                    180:                 httpsPort = atoi(argv[i+1]);
                    181: 
                    182:             i += 2;
                    183:             continue;
                    184:         }
                    185: 
                    186:         if (strcmp(argv[i], "-w") == 0 && argv[i+1] != NULL)
                    187:         {
                    188:             webroot = argv[i+1];
                    189:             i += 2;
                    190:             continue;
                    191:         }
                    192: 
                    193:         printf("%s:\n"
                    194:                "    [-p [address:]httpport]\n"
                    195:                "    [-s [address:]httpsport]\n"
                    196:                "    [-w webroot]\n", argv[0]);
                    197:         exit(1);
                    198:     }
                    199: 
                    200:     for (i = 0; i < INITIAL_CONNECTION_SLOTS; i++) 
                    201:     {
                    202:         tp = freeconns;
                    203:         freeconns = (struct connstruct *)calloc(1, sizeof(struct connstruct));
                    204:         freeconns->next = tp;
                    205:     }
                    206: 
                    207:     if ((active = openlistener(httpAddress, httpPort)) == -1) 
                    208:     {
                    209: #ifdef CONFIG_HTTP_VERBOSE
                    210:         fprintf(stderr, "ERR: Couldn't bind to port %d\n", httpPort);
                    211: #endif
                    212:         exit(1);
                    213:     }
                    214: 
                    215:     addtoservers(active);
                    216: 
                    217:     if ((active = openlistener(httpsAddress, httpsPort)) == -1) 
                    218:     {
                    219: #ifdef CONFIG_HTTP_VERBOSE
                    220:         fprintf(stderr, "ERR: Couldn't bind to port %d\n", httpsPort);
                    221: #endif
                    222:         exit(1);
                    223:     }
                    224: 
                    225:     addtoservers(active);
                    226:     servers->ssl_ctx = ssl_ctx_new(CONFIG_HTTP_DEFAULT_SSL_OPTIONS, 
                    227:                                 CONFIG_HTTP_SESSION_CACHE_SIZE);
                    228:     servers->is_ssl = 1;
                    229: 
                    230: #if defined(CONFIG_HTTP_HAS_CGI)
                    231:     addcgiext(CONFIG_HTTP_CGI_EXTENSIONS);
                    232: #endif
                    233: 
                    234: #if defined(CONFIG_HTTP_VERBOSE)
                    235: #if defined(CONFIG_HTTP_HAS_CGI)
                    236:     printf("addcgiext %s\n", CONFIG_HTTP_CGI_EXTENSIONS); 
                    237: #endif
                    238:     printf("%s: listening on ports %d (http) and %d (https)\n", 
                    239:             server_version, httpPort, httpsPort);
                    240:     TTY_FLUSH();
                    241: #endif
                    242: 
                    243:     ax_chdir();
                    244: 
                    245: #ifdef CONFIG_HTTP_ENABLE_DIFFERENT_USER
                    246:     {
                    247:         struct passwd *pd = getpwnam(CONFIG_HTTP_USER);
                    248: 
                    249:         if (pd != NULL)
                    250:         {
                    251:             int res = setuid(pd->pw_uid);
                    252:             res |= setgid(pd->pw_gid);
                    253: 
                    254: #if defined(CONFIG_HTTP_VERBOSE)
                    255:             if (res == 0)
                    256:             {
                    257:                 printf("change to '%s' successful\n", CONFIG_HTTP_USER); 
                    258:                 TTY_FLUSH();
                    259:             }
                    260: #endif
                    261:         }
                    262: 
                    263:     }
                    264: #endif
                    265: 
                    266: 
                    267: #ifndef WIN32 
                    268: #ifdef CONFIG_HTTP_IS_DAEMON
                    269:     if (fork() > 0)  /* parent will die */
                    270:         exit(0);
                    271: 
                    272:     setsid();
                    273: #endif
                    274: #endif
                    275: 
                    276:     /* main loop */
                    277:     while (1)
                    278:     {
                    279:         struct timeval tv = { 10, 0 };
                    280:         FD_ZERO(&rfds);
                    281:         FD_ZERO(&wfds);
                    282:         rnum = wnum = -1;
                    283:         sp = servers;
                    284: 
                    285:         while (sp != NULL)  /* read each server port */
                    286:         {
                    287:             FD_SET(sp->sd, &rfds);
                    288: 
                    289:             if (sp->sd > rnum) 
                    290:                 rnum = sp->sd;
                    291:             sp = sp->next;
                    292:         }
                    293: 
                    294:         /* Add the established sockets */
                    295:         tp = usedconns;
                    296:         currtime = time(NULL);
                    297: 
                    298:         while (tp != NULL) 
                    299:         {
                    300:             if (currtime > tp->timeout)     /* timed out? Kill it. */
                    301:             {
                    302:                 to = tp;
                    303:                 tp = tp->next;
                    304:                 removeconnection(to);
                    305:                 continue;
                    306:             }
                    307: 
                    308:             if (tp->state == STATE_WANT_TO_READ_HEAD) 
                    309:             {
                    310:                 FD_SET(tp->networkdesc, &rfds);
                    311:                 if (tp->networkdesc > rnum) 
                    312:                     rnum = tp->networkdesc;
                    313:             }
                    314: 
                    315:             if (tp->state == STATE_WANT_TO_SEND_HEAD) 
                    316:             {
                    317:                 FD_SET(tp->networkdesc, &wfds);
                    318:                 if (tp->networkdesc > wnum) 
                    319:                     wnum = tp->networkdesc;
                    320:             }
                    321: 
                    322:             if (tp->state == STATE_WANT_TO_READ_FILE) 
                    323:             {
                    324:                 FD_SET(tp->filedesc, &rfds);
                    325:                 if (tp->filedesc > rnum) 
                    326:                     rnum = tp->filedesc;
                    327:             }
                    328: 
                    329:             if (tp->state == STATE_WANT_TO_SEND_FILE) 
                    330:             {
                    331:                 FD_SET(tp->networkdesc, &wfds);
                    332:                 if (tp->networkdesc > wnum) 
                    333:                     wnum = tp->networkdesc;
                    334:             }
                    335: 
                    336: #if defined(CONFIG_HTTP_DIRECTORIES)
                    337:             if (tp->state == STATE_DOING_DIR) 
                    338:             {
                    339:                 FD_SET(tp->networkdesc, &wfds);
                    340:                 if (tp->networkdesc > wnum) 
                    341:                     wnum = tp->networkdesc;
                    342:             }
                    343: #endif
                    344:             tp = tp->next;
                    345:         }
                    346: 
                    347:         active = select(wnum > rnum ? wnum+1 : rnum+1,
                    348:                 rnum != -1 ? &rfds : NULL, 
                    349:                 wnum != -1 ? &wfds : NULL,
                    350:                 NULL, usedconns ? &tv : NULL);
                    351: 
                    352:         /* timeout? */
                    353:         if (active == 0)
                    354:             continue;
                    355: 
                    356:         /* New connection? */
                    357:         sp = servers;
                    358:         while (active > 0 && sp != NULL) 
                    359:         {
                    360:             if (FD_ISSET(sp->sd, &rfds)) 
                    361:             {
                    362:                 handlenewconnection(sp->sd, sp->is_ssl);
                    363:                 active--;
                    364:             }
                    365: 
                    366:             sp = sp->next;
                    367:         }
                    368: 
                    369:         /* Handle the established sockets */
                    370:         tp = usedconns;
                    371: 
                    372:         while (active > 0 && tp != NULL) 
                    373:         {
                    374:             to = tp;
                    375:             tp = tp->next;
                    376: 
                    377:             if (to->state == STATE_WANT_TO_READ_HEAD &&
                    378:                         FD_ISSET(to->networkdesc, &rfds)) 
                    379:             {
                    380:                 active--;
                    381: #if defined(CONFIG_HTTP_HAS_CGI)
                    382:                 if (to->post_state)
                    383:                     read_post_data(to);
                    384:                 else
                    385: #endif
                    386:                     procreadhead(to);
                    387:             } 
                    388: 
                    389:             if (to->state == STATE_WANT_TO_SEND_HEAD &&
                    390:                         FD_ISSET(to->networkdesc, &wfds)) 
                    391:             {
                    392:                 active--;
                    393:                 procsendhead(to);
                    394:             } 
                    395: 
                    396:             if (to->state == STATE_WANT_TO_READ_FILE && 
                    397:                         FD_ISSET(to->filedesc, &rfds)) 
                    398:             {
                    399:                 active--;
                    400:                 procreadfile(to);
                    401:             } 
                    402: 
                    403:             if (to->state == STATE_WANT_TO_SEND_FILE && 
                    404:                         FD_ISSET(to->networkdesc, &wfds)) 
                    405:             {
                    406:                 active--;
                    407:                 procsendfile(to);
                    408:             }
                    409: 
                    410: #if defined(CONFIG_HTTP_DIRECTORIES)
                    411:             if (to->state == STATE_DOING_DIR &&
                    412:                         FD_ISSET(to->networkdesc, &wfds)) 
                    413:             {
                    414:                 active--;
                    415:                 procdodir(to);
                    416:             }
                    417: #endif
                    418:         }
                    419:     }
                    420: 
                    421:     return 0;
                    422: }
                    423: 
                    424: #if defined(CONFIG_HTTP_HAS_CGI)
                    425: static void addcgiext(const char *cgi_exts)
                    426: {
                    427:     char *cp = strdup(cgi_exts);
                    428: 
                    429:     /* extenstions are comma separated */
                    430:     do 
                    431:     {
                    432:         struct cgiextstruct *ex = (struct cgiextstruct *)
                    433:                             malloc(sizeof(struct cgiextstruct));
                    434:         ex->ext = cp;
                    435:         ex->next = cgiexts;
                    436:         cgiexts = ex;
                    437:         if ((cp = strchr(cp, ',')) != NULL)
                    438:             *cp++ = 0;
                    439:     } while (cp != NULL);
                    440: }
                    441: #endif
                    442: 
                    443: static void addtoservers(int sd) 
                    444: {
                    445:     struct serverstruct *tp = (struct serverstruct *)
                    446:                             calloc(1, sizeof(struct serverstruct));
                    447:     tp->next = servers;
                    448:     tp->sd = sd;
                    449:     servers = tp;
                    450: }
                    451: 
                    452: #ifdef HAVE_IPV6
                    453: static void handlenewconnection(int listenfd, int is_ssl) 
                    454: {
                    455:     struct sockaddr_in6 their_addr;
                    456:     socklen_t tp = sizeof(their_addr);
                    457:     char ipbuf[100];
                    458:     int connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp);
                    459: 
                    460:     if (tp == sizeof(struct sockaddr_in6)) 
                    461:         inet_ntop(AF_INET6, &their_addr.sin6_addr, ipbuf, sizeof(ipbuf));
                    462:     else if (tp == sizeof(struct sockaddr_in)) 
                    463:         inet_ntop(AF_INET, &(((struct sockaddr_in *)&their_addr)->sin_addr),
                    464:                 ipbuf, sizeof(ipbuf));
                    465:     else 
                    466:         *ipbuf = '\0';
                    467: 
                    468:     if (connfd != -1) /* check for error condition */
                    469:         addconnection(connfd, ipbuf, is_ssl);
                    470: }
                    471: 
                    472: #else
                    473: static void handlenewconnection(int listenfd, int is_ssl) 
                    474: {
                    475:     struct sockaddr_in their_addr;
                    476:     socklen_t tp = sizeof(struct sockaddr_in);
                    477:     int connfd = accept(listenfd, (struct sockaddr *)&their_addr, &tp);
                    478:     addconnection(connfd, inet_ntoa(their_addr.sin_addr), is_ssl);
                    479: }
                    480: #endif
                    481: 
                    482: static int openlistener(char *address, int port) 
                    483: {
                    484:     int sd;
                    485: #ifdef WIN32
                    486:     char tp = 1;
                    487: #else
                    488:     int tp = 1;
                    489: #endif
                    490: #ifndef HAVE_IPV6
                    491:     struct sockaddr_in my_addr;
                    492: 
                    493:     if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == -1) 
                    494:         return -1;
                    495: 
                    496:     memset(&my_addr, 0, sizeof(my_addr));
                    497:     my_addr.sin_family = AF_INET;
                    498:     my_addr.sin_port = htons((short)port);
                    499:     my_addr.sin_addr.s_addr = address == NULL ? 
                    500:                         INADDR_ANY : inet_addr(address);
                    501: #else
                    502:     struct sockaddr_in6 my_addr;
                    503: 
                    504:     if ((sd = socket(AF_INET6, SOCK_STREAM, 0)) == -1) 
                    505:         return -1;
                    506: 
                    507:     my_addr.sin6_family = AF_INET6;
                    508:     my_addr.sin6_port = htons(port);
                    509: 
                    510:     if (address == NULL)
                    511:         my_addr.sin6_addr = in6addr_any;
                    512:     else 
                    513:         inet_pton(AF_INET6, address, &my_addr.sin6_addr);
                    514: #endif
                    515: 
                    516:     setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &tp, sizeof(tp));
                    517:     if (bind(sd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
                    518:     {
                    519:         close(sd);
                    520:         return -1;
                    521:     }
                    522: 
                    523:     listen(sd, BACKLOG);
                    524:     return sd;
                    525: }
                    526: 
                    527: /* Wrapper function for strncpy() that guarantees
                    528:    a null-terminated string. This is to avoid any possible
                    529:    issues due to strncpy()'s behaviour.
                    530:  */
                    531: char *my_strncpy(char *dest, const char *src, size_t n) 
                    532: {
                    533:     strncpy(dest, src, n);
                    534:     dest[n-1] = '\0';
                    535:     return dest;
                    536: }
                    537: 
                    538: int isdir(const char *tpbuf) 
                    539: {
                    540:     struct stat st;
                    541:     char path[MAXREQUESTLENGTH];
                    542:     strcpy(path, tpbuf);
                    543: 
                    544: #ifdef WIN32        /* win32 stat() can't handle trailing '\' */
                    545:     if (path[strlen(path)-1] == '\\')
                    546:         path[strlen(path)-1] = 0;
                    547: #endif
                    548: 
                    549:     if (stat(path, &st) == -1) 
                    550:         return 0;
                    551: 
                    552:     if ((st.st_mode & S_IFMT) == S_IFDIR) 
                    553:         return 1;
                    554: 
                    555:     return 0;
                    556: }
                    557: 
                    558: static void addconnection(int sd, char *ip, int is_ssl) 
                    559: {
                    560:     struct connstruct *tp;
                    561: 
                    562:     /* Get ourselves a connstruct */
                    563:     if (freeconns == NULL) 
                    564:         tp = (struct connstruct *)calloc(1, sizeof(struct connstruct));
                    565:     else 
                    566:     {
                    567:         tp = freeconns;
                    568:         freeconns = tp->next;
                    569:     }
                    570: 
                    571:     /* Attach it to the used list */
                    572:     tp->next = usedconns;
                    573:     usedconns = tp;
                    574:     tp->networkdesc = sd;
                    575: 
                    576:     if (is_ssl)
                    577:         tp->ssl = ssl_server_new(servers->ssl_ctx, sd);
                    578: 
                    579:     tp->is_ssl = is_ssl;
                    580:     tp->filedesc = -1;
                    581: #if defined(CONFIG_HTTP_HAS_DIRECTORIES)
                    582:     tp->dirp = NULL;
                    583: #endif
                    584:     *tp->actualfile = '\0';
                    585:     *tp->filereq = '\0';
                    586:     tp->state = STATE_WANT_TO_READ_HEAD;
                    587:     tp->reqtype = TYPE_GET;
                    588:     tp->close_when_done = 0;
                    589:     tp->timeout = time(NULL) + CONFIG_HTTP_TIMEOUT;
                    590: #if defined(CONFIG_HTTP_HAS_CGI)
                    591:     strcpy(tp->remote_addr, ip);
                    592: #endif
                    593: }
                    594: 
                    595: void removeconnection(struct connstruct *cn) 
                    596: {
                    597:     struct connstruct *tp;
                    598:     int shouldret = 0;
                    599: 
                    600:     tp = usedconns;
                    601: 
                    602:     if (tp == NULL || cn == NULL) 
                    603:         shouldret = 1;
                    604:     else if (tp == cn) 
                    605:         usedconns = tp->next;
                    606:     else 
                    607:     {
                    608:         while (tp != NULL) 
                    609:         {
                    610:             if (tp->next == cn) 
                    611:             {
                    612:                 tp->next = (tp->next)->next;
                    613:                 shouldret = 0;
                    614:                 break;
                    615:             }
                    616: 
                    617:             tp = tp->next;
                    618:             shouldret = 1;
                    619:         }
                    620:     }
                    621: 
                    622:     if (shouldret) 
                    623:         return;
                    624: 
                    625:     /* If we did, add it to the free list */
                    626:     cn->next = freeconns;
                    627:     freeconns = cn;
                    628: 
                    629:     /* Close it all down */
                    630:     if (cn->networkdesc != -1) 
                    631:     {
                    632:         if (cn->is_ssl) 
                    633:         {
                    634:             ssl_free(cn->ssl);
                    635:             cn->ssl = NULL;
                    636:         }
                    637: 
                    638: #ifndef WIN32
                    639:         shutdown(cn->networkdesc, SHUT_WR);
                    640: #endif
                    641:         SOCKET_CLOSE(cn->networkdesc);
                    642:     }
                    643: 
                    644:     if (cn->filedesc != -1) 
                    645:         close(cn->filedesc);
                    646: 
                    647: #if defined(CONFIG_HTTP_HAS_DIRECTORIES)
                    648:     if (cn->dirp != NULL) 
                    649: #ifdef WIN32
                    650:         FindClose(cn->dirp);
                    651: #else
                    652:         closedir(cn->dirp);
                    653: #endif
                    654: #endif
                    655: }
                    656: 
                    657: /*
                    658:  * Change directories one way or the other.
                    659:  */
                    660: 
                    661: static void ax_chdir(void)
                    662: {
                    663:     if (chdir(webroot))
                    664:     {
                    665: #ifdef CONFIG_HTTP_VERBOSE
                    666:         fprintf(stderr, "'%s' is not a directory\n", webroot);
                    667: #endif
                    668:         exit(1);
                    669:     }
                    670: }
                    671: 

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