File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / miniupnpd / upnphttp.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:16:02 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    1: /* $Id: upnphttp.c,v 1.1 2012/02/21 23:16:02 misho 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>