Annotation of embedaddon/miniupnpd/upnphttp.c, revision 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>