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

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

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