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>