Annotation of embedaddon/miniupnpd/upnphttp.c, revision 1.1.1.2

1.1.1.2 ! misho       1: /* $Id: upnphttp.c,v 1.61 2011/06/27 11:05:59 nanard Exp $ */
1.1       misho       2: /* Project :  miniupnp
                      3:  * Website :  http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
                      4:  * Author :   Thomas Bernard
1.1.1.2 ! misho       5:  * Copyright (c) 2005-2011 Thomas Bernard
1.1       misho       6:  * This software is subject to the conditions detailed in the
                      7:  * LICENCE file included in this distribution.
                      8:  * */
                      9: #include <stdlib.h>
                     10: #include <unistd.h>
                     11: #include <stdio.h>
                     12: #include <string.h>
                     13: #include <sys/types.h>
                     14: #include <sys/socket.h>
                     15: #include <sys/param.h>
1.1.1.2 ! misho      16: #include <arpa/inet.h>
1.1       misho      17: #include <syslog.h>
                     18: #include <ctype.h>
                     19: #include "config.h"
                     20: #include "upnphttp.h"
                     21: #include "upnpdescgen.h"
                     22: #include "miniupnpdpath.h"
                     23: #include "upnpsoap.h"
                     24: #include "upnpevents.h"
                     25: 
                     26: struct upnphttp * 
                     27: New_upnphttp(int s)
                     28: {
                     29:        struct upnphttp * ret;
                     30:        if(s<0)
                     31:                return NULL;
                     32:        ret = (struct upnphttp *)malloc(sizeof(struct upnphttp));
                     33:        if(ret == NULL)
                     34:                return NULL;
                     35:        memset(ret, 0, sizeof(struct upnphttp));
                     36:        ret->socket = s;
                     37:        return ret;
                     38: }
                     39: 
                     40: void
                     41: CloseSocket_upnphttp(struct upnphttp * h)
                     42: {
                     43:        if(close(h->socket) < 0)
                     44:        {
                     45:                syslog(LOG_ERR, "CloseSocket_upnphttp: close(%d): %m", h->socket);
                     46:        }
                     47:        h->socket = -1;
                     48:        h->state = 100;
                     49: }
                     50: 
                     51: void
                     52: Delete_upnphttp(struct upnphttp * h)
                     53: {
                     54:        if(h)
                     55:        {
                     56:                if(h->socket >= 0)
                     57:                        CloseSocket_upnphttp(h);
                     58:                if(h->req_buf)
                     59:                        free(h->req_buf);
                     60:                if(h->res_buf)
                     61:                        free(h->res_buf);
                     62:                free(h);
                     63:        }
                     64: }
                     65: 
                     66: /* parse HttpHeaders of the REQUEST */
                     67: static void
                     68: ParseHttpHeaders(struct upnphttp * h)
                     69: {
                     70:        char * line;
                     71:        char * colon;
                     72:        char * p;
                     73:        int n;
                     74:        line = h->req_buf;
                     75:        /* TODO : check if req_buf, contentoff are ok */
                     76:        while(line < (h->req_buf + h->req_contentoff))
                     77:        {
                     78:                colon = strchr(line, ':');
                     79:                if(colon)
                     80:                {
                     81:                        if(strncasecmp(line, "Content-Length", 14)==0)
                     82:                        {
                     83:                                p = colon;
                     84:                                while(*p < '0' || *p > '9')
                     85:                                        p++;
                     86:                                h->req_contentlen = atoi(p);
                     87:                                /*printf("*** Content-Lenght = %d ***\n", h->req_contentlen);
                     88:                                printf("    readbufflen=%d contentoff = %d\n",
                     89:                                        h->req_buflen, h->req_contentoff);*/
                     90:                        }
                     91:                        else if(strncasecmp(line, "SOAPAction", 10)==0)
                     92:                        {
                     93:                                p = colon;
                     94:                                n = 0;
                     95:                                while(*p == ':' || *p == ' ' || *p == '\t')
                     96:                                        p++;
                     97:                                while(p[n]>=' ')
                     98:                                {
                     99:                                        n++;
                    100:                                }
                    101:                                if((p[0] == '"' && p[n-1] == '"')
                    102:                                  || (p[0] == '\'' && p[n-1] == '\''))
                    103:                                {
                    104:                                        p++; n -= 2;
                    105:                                }
                    106:                                h->req_soapAction = p;
                    107:                                h->req_soapActionLen = n;
                    108:                        }
                    109: #ifdef ENABLE_EVENTS
                    110:                        else if(strncasecmp(line, "Callback", 8)==0)
                    111:                        {
                    112:                                p = colon;
                    113:                                while(*p != '<' && *p != '\r' )
                    114:                                        p++;
                    115:                                n = 0;
                    116:                                while(p[n] != '>' && p[n] != '\r' )
                    117:                                        n++;
                    118:                                h->req_Callback = p + 1;
                    119:                                h->req_CallbackLen = MAX(0, n - 1);
                    120:                        }
                    121:                        else if(strncasecmp(line, "SID", 3)==0)
                    122:                        {
                    123:                                p = colon + 1;
                    124:                                while(isspace(*p))
                    125:                                        p++;
                    126:                                n = 0;
                    127:                                while(!isspace(p[n]))
                    128:                                        n++;
                    129:                                h->req_SID = p;
                    130:                                h->req_SIDLen = n;
                    131:                        }
                    132:                        /* Timeout: Seconds-nnnn */
                    133: /* TIMEOUT
                    134: Recommended. Requested duration until subscription expires,
                    135: either number of seconds or infinite. Recommendation
                    136: by a UPnP Forum working committee. Defined by UPnP vendor.
                    137:  Consists of the keyword "Second-" followed (without an
                    138: intervening space) by either an integer or the keyword "infinite". */
                    139:                        else if(strncasecmp(line, "Timeout", 7)==0)
                    140:                        {
                    141:                                p = colon + 1;
                    142:                                while(isspace(*p))
                    143:                                        p++;
                    144:                                if(strncasecmp(p, "Second-", 7)==0) {
                    145:                                        h->req_Timeout = atoi(p+7);
                    146:                                }
                    147:                        }
                    148: #endif
                    149:                }
                    150:                while(!(line[0] == '\r' && line[1] == '\n'))
                    151:                        line++;
                    152:                line += 2;
                    153:        }
                    154: }
                    155: 
                    156: /* very minimalistic 404 error message */
                    157: static void
                    158: Send404(struct upnphttp * h)
                    159: {
                    160: /*
                    161:        static const char error404[] = "HTTP/1.1 404 Not found\r\n"
                    162:                "Connection: close\r\n"
                    163:                "Content-type: text/html\r\n"
                    164:                "\r\n"
                    165:                "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>"
                    166:                "<BODY><H1>Not Found</H1>The requested URL was not found"
                    167:                " on this server.</BODY></HTML>\r\n";
                    168:        int n;
                    169:        n = send(h->socket, error404, sizeof(error404) - 1, 0);
                    170:        if(n < 0)
                    171:        {
                    172:                syslog(LOG_ERR, "Send404: send(http): %m");
                    173:        }*/
                    174:        static const char body404[] =
                    175:                "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>"
                    176:                "<BODY><H1>Not Found</H1>The requested URL was not found"
                    177:                " on this server.</BODY></HTML>\r\n";
                    178:        h->respflags = FLAG_HTML;
                    179:        BuildResp2_upnphttp(h, 404, "Not Found",
                    180:                            body404, sizeof(body404) - 1);
                    181:        SendResp_upnphttp(h);
                    182:        CloseSocket_upnphttp(h);
                    183: }
                    184: 
                    185: /* very minimalistic 501 error message */
                    186: static void
                    187: Send501(struct upnphttp * h)
                    188: {
                    189: /*
                    190:        static const char error501[] = "HTTP/1.1 501 Not Implemented\r\n"
                    191:                "Connection: close\r\n"
                    192:                "Content-type: text/html\r\n"
                    193:                "\r\n"
                    194:                "<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>"
                    195:                "<BODY><H1>Not Implemented</H1>The HTTP Method "
                    196:                "is not implemented by this server.</BODY></HTML>\r\n";
                    197:        int n;
                    198:        n = send(h->socket, error501, sizeof(error501) - 1, 0);
                    199:        if(n < 0)
                    200:        {
                    201:                syslog(LOG_ERR, "Send501: send(http): %m");
                    202:        }
                    203: */
                    204:        static const char body501[] = 
                    205:                "<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>"
                    206:                "<BODY><H1>Not Implemented</H1>The HTTP Method "
                    207:                "is not implemented by this server.</BODY></HTML>\r\n";
                    208:        h->respflags = FLAG_HTML;
                    209:        BuildResp2_upnphttp(h, 501, "Not Implemented",
                    210:                            body501, sizeof(body501) - 1);
                    211:        SendResp_upnphttp(h);
                    212:        CloseSocket_upnphttp(h);
                    213: }
                    214: 
                    215: static const char *
                    216: findendheaders(const char * s, int len)
                    217: {
                    218:        while(len-->0)
                    219:        {
                    220:                if(s[0]=='\r' && s[1]=='\n' && s[2]=='\r' && s[3]=='\n')
                    221:                        return s;
                    222:                s++;
                    223:        }
                    224:        return NULL;
                    225: }
                    226: 
                    227: #ifdef HAS_DUMMY_SERVICE
                    228: static void
                    229: sendDummyDesc(struct upnphttp * h)
                    230: {
                    231:        static const char xml_desc[] = "<?xml version=\"1.0\"?>\r\n"
                    232:                "<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">"
                    233:                " <specVersion>"
                    234:                "    <major>1</major>"
                    235:                "    <minor>0</minor>"
                    236:                "  </specVersion>"
                    237:                "  <actionList />"
                    238:                "  <serviceStateTable />"
                    239:                "</scpd>\r\n";
                    240:        BuildResp_upnphttp(h, xml_desc, sizeof(xml_desc)-1);
                    241:        SendResp_upnphttp(h);
                    242:        CloseSocket_upnphttp(h);
                    243: }
                    244: #endif
                    245: 
                    246: /* Sends the description generated by the parameter */
                    247: static void
                    248: sendXMLdesc(struct upnphttp * h, char * (f)(int *))
                    249: {
                    250:        char * desc;
                    251:        int len;
                    252:        desc = f(&len);
                    253:        if(!desc)
                    254:        {
                    255:                static const char error500[] = "<HTML><HEAD><TITLE>Error 500</TITLE>"
                    256:                   "</HEAD><BODY>Internal Server Error</BODY></HTML>\r\n";
                    257:                syslog(LOG_ERR, "Failed to generate XML description");
                    258:                h->respflags = FLAG_HTML;
                    259:                BuildResp2_upnphttp(h, 500, "Internal Server Error",
                    260:                                    error500, sizeof(error500)-1);
                    261:        }
                    262:        else
                    263:        {
                    264:                BuildResp_upnphttp(h, desc, len);
                    265:        }
                    266:        SendResp_upnphttp(h);
                    267:        CloseSocket_upnphttp(h);
                    268:        free(desc);
                    269: }
                    270: 
                    271: /* ProcessHTTPPOST_upnphttp()
                    272:  * executes the SOAP query if it is possible */
                    273: static void
                    274: ProcessHTTPPOST_upnphttp(struct upnphttp * h)
                    275: {
                    276:        if((h->req_buflen - h->req_contentoff) >= h->req_contentlen)
                    277:        {
                    278:                if(h->req_soapAction)
                    279:                {
                    280:                        /* we can process the request */
                    281:                        syslog(LOG_INFO, "SOAPAction: %.*s",
                    282:                           h->req_soapActionLen, h->req_soapAction);
                    283:                        ExecuteSoapAction(h, 
                    284:                                h->req_soapAction,
                    285:                                h->req_soapActionLen);
                    286:                }
                    287:                else
                    288:                {
                    289:                        static const char err400str[] =
                    290:                                "<html><body>Bad request</body></html>";
                    291:                        syslog(LOG_INFO, "No SOAPAction in HTTP headers");
                    292:                        h->respflags = FLAG_HTML;
                    293:                        BuildResp2_upnphttp(h, 400, "Bad Request",
                    294:                                            err400str, sizeof(err400str) - 1);
                    295:                        SendResp_upnphttp(h);
                    296:                        CloseSocket_upnphttp(h);
                    297:                }
                    298:        }
                    299:        else
                    300:        {
                    301:                /* waiting for remaining data */
                    302:                h->state = 1;
                    303:        }
                    304: }
                    305: 
                    306: #ifdef ENABLE_EVENTS
1.1.1.2 ! misho     307: /**
        !           308:  * returns 0 if the callback header value is not valid
        !           309:  * 1 if it is valid.
        !           310:  */
        !           311: static int
        !           312: checkCallbackURL(struct upnphttp * h)
        !           313: {
        !           314:        char addrstr[48];
        !           315:        int ipv6;
        !           316:        const char * p;
        !           317:        int i;
        !           318: 
        !           319:        if(!h->req_Callback || h->req_CallbackLen < 8)
        !           320:                return 0;
        !           321:        if(memcmp(h->req_Callback, "http://", 7) != 0)
        !           322:                return 0;
        !           323:        ipv6 = 0;
        !           324:        i = 0;
        !           325:        p = h->req_Callback + 7;
        !           326:        if(*p == '[') {
        !           327:                p++;
        !           328:                ipv6 = 1;
        !           329:                while(*p != ']' && i < (sizeof(addrstr)-1)
        !           330:                      && p < (h->req_Callback + h->req_CallbackLen))
        !           331:                        addrstr[i++] = *(p++);
        !           332:        } else {
        !           333:                while(*p != '/' && *p != ':' && i < (sizeof(addrstr)-1)
        !           334:                      && p < (h->req_Callback + h->req_CallbackLen))
        !           335:                        addrstr[i++] = *(p++);
        !           336:        }
        !           337:        addrstr[i] = '\0';
        !           338:        if(ipv6) {
        !           339:                struct in6_addr addr;
        !           340:                if(inet_pton(AF_INET6, addrstr, &addr) <= 0)
        !           341:                        return 0;
        !           342: #ifdef ENABLE_IPV6
        !           343:                if(!h->ipv6
        !           344:                  || (0!=memcmp(&addr, &(h->clientaddr_v6), sizeof(struct in6_addr))))
        !           345:                        return 0;
        !           346: #else
        !           347:                return 0;
        !           348: #endif
        !           349:        } else {
        !           350:                struct in_addr addr;
        !           351:                if(inet_pton(AF_INET, addrstr, &addr) <= 0)
        !           352:                        return 0;
        !           353: #ifdef ENABLE_IPV6
        !           354:                if(h->ipv6) {
        !           355:                        if(!IN6_IS_ADDR_V4MAPPED(&(h->clientaddr_v6)))
        !           356:                                return 0;
        !           357:                        if(0!=memcmp(&addr, ((const char *)&(h->clientaddr_v6) + 12), 4))
        !           358:                                return 0;
        !           359:                } else {
        !           360:                        if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr)))
        !           361:                                return 0;
        !           362:                }
        !           363: #else
        !           364:                if(0!=memcmp(&addr, &(h->clientaddr), sizeof(struct in_addr)))
        !           365:                        return 0;
        !           366: #endif
        !           367:        }
        !           368:        return 1;
        !           369: }
        !           370: 
1.1       misho     371: static void
                    372: ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path)
                    373: {
                    374:        const char * sid;
                    375:        syslog(LOG_DEBUG, "ProcessHTTPSubscribe %s", path);
                    376:        syslog(LOG_DEBUG, "Callback '%.*s' Timeout=%d",
                    377:               h->req_CallbackLen, h->req_Callback, h->req_Timeout);
                    378:        syslog(LOG_DEBUG, "SID '%.*s'", h->req_SIDLen, h->req_SID);
                    379:        if(!h->req_Callback && !h->req_SID) {
                    380:                /* Missing or invalid CALLBACK : 412 Precondition Failed.
                    381:                 * If CALLBACK header is missing or does not contain a valid HTTP URL,
                    382:                 * the publisher must respond with HTTP error 412 Precondition Failed*/
                    383:                BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
                    384:                SendResp_upnphttp(h);
                    385:                CloseSocket_upnphttp(h);
                    386:        } else {
                    387:        /* - add to the subscriber list
                    388:         * - respond HTTP/x.x 200 OK 
                    389:         * - Send the initial event message */
                    390: /* Server:, SID:; Timeout: Second-(xx|infinite) */
1.1.1.2 ! misho     391:        /* Check that the callback URL is on the same IP as
        !           392:         * the request, and not on the internet, nor on ourself (DOS attack ?) */
1.1       misho     393:                if(h->req_Callback) {
1.1.1.2 ! misho     394:                        if(checkCallbackURL(h)) {
        !           395:                                sid = upnpevents_addSubscriber(path, h->req_Callback,
        !           396:                                                               h->req_CallbackLen, h->req_Timeout);
        !           397:                                h->respflags = FLAG_TIMEOUT;
        !           398:                                if(sid) {
        !           399:                                        syslog(LOG_DEBUG, "generated sid=%s", sid);
        !           400:                                        h->respflags |= FLAG_SID;
        !           401:                                        h->req_SID = sid;
        !           402:                                        h->req_SIDLen = strlen(sid);
        !           403:                                }
        !           404:                                BuildResp_upnphttp(h, 0, 0);
        !           405:                        } else {
        !           406:                                syslog(LOG_WARNING, "Invalid Callback in SUBSCRIBE %.*s",
        !           407:                               h->req_CallbackLen, h->req_Callback);
        !           408:                                BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
1.1       misho     409:                        }
                    410:                } else {
                    411:                        /* subscription renew */
                    412:                        /* Invalid SID
                    413: 412 Precondition Failed. If a SID does not correspond to a known,
                    414: un-expired subscription, the publisher must respond
                    415: with HTTP error 412 Precondition Failed. */
                    416:                        if(renewSubscription(h->req_SID, h->req_SIDLen, h->req_Timeout) < 0) {
                    417:                                BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
                    418:                        } else {
1.1.1.2 ! misho     419:                                h->respflags = FLAG_TIMEOUT;
1.1       misho     420:                                BuildResp_upnphttp(h, 0, 0);
                    421:                        }
                    422:                }
                    423:                SendResp_upnphttp(h);
                    424:                CloseSocket_upnphttp(h);
                    425:        }
                    426: }
                    427: 
                    428: static void
                    429: ProcessHTTPUnSubscribe_upnphttp(struct upnphttp * h, const char * path)
                    430: {
                    431:        syslog(LOG_DEBUG, "ProcessHTTPUnSubscribe %s", path);
                    432:        syslog(LOG_DEBUG, "SID '%.*s'", h->req_SIDLen, h->req_SID);
                    433:        /* Remove from the list */
                    434:        if(upnpevents_removeSubscriber(h->req_SID, h->req_SIDLen) < 0) {
                    435:                BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0);
                    436:        } else {
                    437:                BuildResp_upnphttp(h, 0, 0);
                    438:        }
                    439:        SendResp_upnphttp(h);
                    440:        CloseSocket_upnphttp(h);
                    441: }
                    442: #endif
                    443: 
                    444: /* Parse and process Http Query 
                    445:  * called once all the HTTP headers have been received. */
                    446: static void
                    447: ProcessHttpQuery_upnphttp(struct upnphttp * h)
                    448: {
                    449:        char HttpCommand[16];
                    450:        char HttpUrl[128];
                    451:        char * HttpVer;
                    452:        char * p;
                    453:        int i;
                    454:        p = h->req_buf;
                    455:        if(!p)
                    456:                return;
                    457:        for(i = 0; i<15 && *p != ' ' && *p != '\r'; i++)
                    458:                HttpCommand[i] = *(p++);
                    459:        HttpCommand[i] = '\0';
                    460:        while(*p==' ')
                    461:                p++;
                    462:        for(i = 0; i<127 && *p != ' ' && *p != '\r'; i++)
                    463:                HttpUrl[i] = *(p++);
                    464:        HttpUrl[i] = '\0';
                    465:        while(*p==' ')
                    466:                p++;
                    467:        HttpVer = h->HttpVer;
                    468:        for(i = 0; i<15 && *p != '\r'; i++)
                    469:                HttpVer[i] = *(p++);
                    470:        HttpVer[i] = '\0';
                    471:        syslog(LOG_INFO, "HTTP REQUEST : %s %s (%s)",
                    472:               HttpCommand, HttpUrl, HttpVer);
                    473:        ParseHttpHeaders(h);
                    474:        if(strcmp("POST", HttpCommand) == 0)
                    475:        {
                    476:                h->req_command = EPost;
                    477:                ProcessHTTPPOST_upnphttp(h);
                    478:        }
                    479:        else if(strcmp("GET", HttpCommand) == 0)
                    480:        {
                    481:                h->req_command = EGet;
                    482:                if(strcasecmp(ROOTDESC_PATH, HttpUrl) == 0)
                    483:                {
                    484:                        sendXMLdesc(h, genRootDesc);
                    485:                }
                    486:                else if(strcasecmp(WANIPC_PATH, HttpUrl) == 0)
                    487:                {
                    488:                        sendXMLdesc(h, genWANIPCn);
                    489:                }
                    490:                else if(strcasecmp(WANCFG_PATH, HttpUrl) == 0)
                    491:                {
                    492:                        sendXMLdesc(h, genWANCfg);
                    493:                }
                    494: #ifdef HAS_DUMMY_SERVICE
                    495:                else if(strcasecmp(DUMMY_PATH, HttpUrl) == 0)
                    496:                {
                    497:                        sendDummyDesc(h);
                    498:                }
                    499: #endif
                    500: #ifdef ENABLE_L3F_SERVICE
                    501:                else if(strcasecmp(L3F_PATH, HttpUrl) == 0)
                    502:                {
                    503:                        sendXMLdesc(h, genL3F);
                    504:                }
                    505: #endif
1.1.1.2 ! misho     506: #ifdef ENABLE_6FC_SERVICE
        !           507:                else if(strcasecmp(WANIP6FC_PATH, HttpUrl) == 0)
        !           508:                {
        !           509:                        sendXMLdesc(h, gen6FC);
        !           510:                }
        !           511: #endif
        !           512: #ifdef ENABLE_DP_SERVICE
        !           513:                else if(strcasecmp(DP_PATH, HttpUrl) == 0)
        !           514:                {
        !           515:                        sendXMLdesc(h, genDP);
        !           516:                }
        !           517: #endif
1.1       misho     518:                else
                    519:                {
                    520:                        syslog(LOG_NOTICE, "%s not found, responding ERROR 404", HttpUrl);
                    521:                        Send404(h);
                    522:                }
                    523:        }
                    524: #ifdef ENABLE_EVENTS
                    525:        else if(strcmp("SUBSCRIBE", HttpCommand) == 0)
                    526:        {
                    527:                h->req_command = ESubscribe;
                    528:                ProcessHTTPSubscribe_upnphttp(h, HttpUrl);
                    529:        }
                    530:        else if(strcmp("UNSUBSCRIBE", HttpCommand) == 0)
                    531:        {
                    532:                h->req_command = EUnSubscribe;
                    533:                ProcessHTTPUnSubscribe_upnphttp(h, HttpUrl);
                    534:        }
                    535: #else
                    536:        else if(strcmp("SUBSCRIBE", HttpCommand) == 0)
                    537:        {
                    538:                syslog(LOG_NOTICE, "SUBSCRIBE not implemented. ENABLE_EVENTS compile option disabled");
                    539:                Send501(h);
                    540:        }
                    541: #endif
                    542:        else
                    543:        {
                    544:                syslog(LOG_NOTICE, "Unsupported HTTP Command %s", HttpCommand);
                    545:                Send501(h);
                    546:        }
                    547: }
                    548: 
                    549: 
                    550: void
                    551: Process_upnphttp(struct upnphttp * h)
                    552: {
                    553:        char buf[2048];
                    554:        int n;
                    555:        if(!h)
                    556:                return;
                    557:        switch(h->state)
                    558:        {
                    559:        case 0:
                    560:                n = recv(h->socket, buf, 2048, 0);
                    561:                if(n<0)
                    562:                {
                    563:                        syslog(LOG_ERR, "recv (state0): %m");
                    564:                        h->state = 100;
                    565:                }
                    566:                else if(n==0)
                    567:                {
                    568:                        syslog(LOG_WARNING, "HTTP Connection closed inexpectedly");
                    569:                        h->state = 100;
                    570:                }
                    571:                else
                    572:                {
                    573:                        const char * endheaders;
                    574:                        /* if 1st arg of realloc() is null,
                    575:                         * realloc behaves the same as malloc() */
                    576:                        h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen + 1);
                    577:                        memcpy(h->req_buf + h->req_buflen, buf, n);
                    578:                        h->req_buflen += n;
                    579:                        h->req_buf[h->req_buflen] = '\0';
                    580:                        /* search for the string "\r\n\r\n" */
                    581:                        endheaders = findendheaders(h->req_buf, h->req_buflen);
                    582:                        if(endheaders)
                    583:                        {
                    584:                                h->req_contentoff = endheaders - h->req_buf + 4;
                    585:                                ProcessHttpQuery_upnphttp(h);
                    586:                        }
                    587:                }
                    588:                break;
                    589:        case 1:
                    590:                n = recv(h->socket, buf, 2048, 0);
                    591:                if(n<0)
                    592:                {
                    593:                        syslog(LOG_ERR, "recv (state1): %m");
                    594:                        h->state = 100;
                    595:                }
                    596:                else if(n==0)
                    597:                {
                    598:                        syslog(LOG_WARNING, "HTTP Connection closed inexpectedly");
                    599:                        h->state = 100;
                    600:                }
                    601:                else
                    602:                {
                    603:                        /*fwrite(buf, 1, n, stdout);*/  /* debug */
                    604:                        h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen);
                    605:                        memcpy(h->req_buf + h->req_buflen, buf, n);
                    606:                        h->req_buflen += n;
                    607:                        if((h->req_buflen - h->req_contentoff) >= h->req_contentlen)
                    608:                        {
                    609:                                ProcessHTTPPOST_upnphttp(h);
                    610:                        }
                    611:                }
                    612:                break;
                    613:        default:
                    614:                syslog(LOG_WARNING, "Unexpected state: %d", h->state);
                    615:        }
                    616: }
                    617: 
                    618: static const char httpresphead[] =
                    619:        "%s %d %s\r\n"
                    620:        /*"Content-Type: text/xml; charset=\"utf-8\"\r\n"*/
                    621:        "Content-Type: %s\r\n"
                    622:        "Connection: close\r\n"
                    623:        "Content-Length: %d\r\n"
                    624:        "Server: " MINIUPNPD_SERVER_STRING "\r\n"
                    625:        ;       /*"\r\n";*/
                    626: /*
                    627:                "<?xml version=\"1.0\"?>\n"
                    628:                "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
                    629:                "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
                    630:                "<s:Body>"
                    631: 
                    632:                "</s:Body>"
                    633:                "</s:Envelope>";
                    634: */
                    635: /* with response code and response message
                    636:  * also allocate enough memory */
                    637: 
                    638: void
                    639: BuildHeader_upnphttp(struct upnphttp * h, int respcode,
                    640:                      const char * respmsg,
                    641:                      int bodylen)
                    642: {
                    643:        int templen;
                    644:        if(!h->res_buf)
                    645:        {
                    646:                templen = sizeof(httpresphead) + 128 + bodylen;
                    647:                h->res_buf = (char *)malloc(templen);
1.1.1.2 ! misho     648:                if(!h->res_buf)
        !           649:                {
        !           650:                        syslog(LOG_ERR, "malloc error in BuildHeader_upnphttp()");
        !           651:                        return;
        !           652:                }
1.1       misho     653:                h->res_buf_alloclen = templen;
                    654:        }
                    655:        h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen,
                    656:                                 httpresphead, h->HttpVer,
                    657:                                 respcode, respmsg,
                    658:                                 (h->respflags&FLAG_HTML)?"text/html":"text/xml",
                    659:                                                         bodylen);
                    660:        /* Additional headers */
                    661: #ifdef ENABLE_EVENTS
                    662:        if(h->respflags & FLAG_TIMEOUT) {
                    663:                h->res_buflen += snprintf(h->res_buf + h->res_buflen,
                    664:                                          h->res_buf_alloclen - h->res_buflen,
                    665:                                          "Timeout: Second-");
                    666:                if(h->req_Timeout) {
                    667:                        h->res_buflen += snprintf(h->res_buf + h->res_buflen,
                    668:                                                  h->res_buf_alloclen - h->res_buflen,
                    669:                                                  "%d\r\n", h->req_Timeout);
                    670:                } else {
                    671:                        h->res_buflen += snprintf(h->res_buf + h->res_buflen,
                    672:                                                  h->res_buf_alloclen - h->res_buflen,
                    673:                                                  "infinite\r\n");
                    674:                }
                    675:        }
                    676:        if(h->respflags & FLAG_SID) {
                    677:                h->res_buflen += snprintf(h->res_buf + h->res_buflen,
                    678:                                          h->res_buf_alloclen - h->res_buflen,
                    679:                                          "SID: %s\r\n", h->req_SID);
                    680:        }
                    681: #endif
                    682:        h->res_buf[h->res_buflen++] = '\r';
                    683:        h->res_buf[h->res_buflen++] = '\n';
                    684:        if(h->res_buf_alloclen < (h->res_buflen + bodylen))
                    685:        {
1.1.1.2 ! misho     686:                char * tmp;
        !           687:                tmp = (char *)realloc(h->res_buf, (h->res_buflen + bodylen));
        !           688:                if(tmp)
        !           689:                {
        !           690:                        h->res_buf = tmp;
        !           691:                        h->res_buf_alloclen = h->res_buflen + bodylen;
        !           692:                }
        !           693:                else
        !           694:                {
        !           695:                        syslog(LOG_ERR, "realloc error in BuildHeader_upnphttp()");
        !           696:                }
1.1       misho     697:        }
                    698: }
                    699: 
                    700: void
                    701: BuildResp2_upnphttp(struct upnphttp * h, int respcode,
                    702:                     const char * respmsg,
                    703:                     const char * body, int bodylen)
                    704: {
                    705:        BuildHeader_upnphttp(h, respcode, respmsg, bodylen);
                    706:        if(body)
                    707:                memcpy(h->res_buf + h->res_buflen, body, bodylen);
                    708:        h->res_buflen += bodylen;
                    709: }
                    710: 
                    711: /* responding 200 OK ! */
                    712: void
                    713: BuildResp_upnphttp(struct upnphttp * h,
                    714:                         const char * body, int bodylen)
                    715: {
                    716:        BuildResp2_upnphttp(h, 200, "OK", body, bodylen);
                    717: }
                    718: 
                    719: void
                    720: SendResp_upnphttp(struct upnphttp * h)
                    721: {
1.1.1.2 ! misho     722:        char * p;
        !           723:        ssize_t n;
        !           724:        size_t len;
        !           725:        p = h->res_buf;
        !           726:        len = h->res_buflen;
        !           727:        while (len > 0)
1.1       misho     728:        {
1.1.1.2 ! misho     729:                n = send(h->socket, p, len, 0);
        !           730:                if(n<0)
        !           731:                {
        !           732:                        syslog(LOG_ERR, "send(res_buf): %m");
        !           733:                }
        !           734:                else if(n == 0)
        !           735:                {
        !           736:                        syslog(LOG_ERR, "send(res_buf): %zd bytes sent (out of %zu)",
        !           737:                                                        n, len);
        !           738:                        break;
        !           739:                }
        !           740:                else
        !           741:                {
        !           742:                        p += n;
        !           743:                        len -= n;
        !           744:                }
1.1       misho     745:        }
                    746: }
                    747: 

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