ASR_BASE
Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/package/kernel/realtek-wl/src/Users/mini_upnp/upnphttp.c b/package/kernel/realtek-wl/src/Users/mini_upnp/upnphttp.c
new file mode 100644
index 0000000..900eff8
--- /dev/null
+++ b/package/kernel/realtek-wl/src/Users/mini_upnp/upnphttp.c
@@ -0,0 +1,1814 @@
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <syslog.h>
+#include <arpa/inet.h>
+#include <limits.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+
+#include "upnphttp.h"
+#include "upnpsoap.h"
+
+static int get_sockfd(void)
+{
+ static int sockfd = -1;
+
+ if (sockfd == -1) {
+ if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
+ perror("user: socket creation failed");
+ return(-1);
+ }
+ }
+ return sockfd;
+}
+
+IPCon IPCon_New(char * ifname)
+{
+ IPCon ipcon=NULL;
+
+ ipcon = (IPCon)malloc(sizeof(_IPCon));
+ if (!ipcon) {
+ printf("Error in IPCon_New:Cannot allocate memory\n");
+ return NULL;
+ }
+
+ ipcon->ifname = ifname;
+ return (ipcon);
+}
+
+
+IPCon IPCon_Destroy(IPCon this)
+{
+ if (!this)
+ return (NULL);
+
+ free(this);
+ return (NULL);
+}
+
+BOOLEAN IPCon_GetIpAddr(IPCon this, struct in_addr *adr)
+{
+ struct ifreq ifr;
+ int fd;
+
+ fd = get_sockfd();
+
+ if (fd >= 0) {
+ strcpy(ifr.ifr_name, this->ifname);
+ ifr.ifr_addr.sa_family = AF_INET;
+
+ if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
+ memcpy(adr,&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr,sizeof(struct in_addr));
+ close(fd);
+ return TRUE;
+ } else {
+ close(fd);
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+char *IPCon_GetIpAddrByStr(IPCon this)
+{
+ struct in_addr adr;
+ BOOLEAN result=FALSE;
+
+ result = IPCon_GetIpAddr(this,&adr);
+
+ if (result == FALSE) {
+ return NULL;
+ } else {
+ return inet_ntoa(adr);
+ }
+
+}
+
+int OpenAndConfHTTPSocket(const char * addr, unsigned short port)
+{
+ int s;
+ int i = 1;
+ struct sockaddr_in listenname;
+
+ if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ syslog(LOG_ERR, "socket(http): %m");
+ return -1;
+ }
+
+ if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
+ {
+ syslog(LOG_WARNING, "setsockopt(http, SO_REUSEADDR): %m");
+ }
+
+ memset(&listenname, 0, sizeof(struct sockaddr_in));
+ listenname.sin_family = AF_INET;
+ listenname.sin_port = htons(port);
+ listenname.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if(bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0)
+ {
+ syslog(LOG_ERR, "bind(http): %m");
+ return -1;
+ }
+
+ if(listen(s, 6) < 0)
+ {
+ syslog(LOG_ERR, "listen(http): %m");
+ return -1;
+ }
+
+ return s;
+}
+
+int ReliableSend(int socket, const char *data, const int len)
+{
+ int n;
+ unsigned int byte_left = len;
+ int bytes_sent = 0;
+
+ if (socket < 0 || data == NULL || len <= 0)
+ return -1;
+
+ while (byte_left > 0) {
+ // write data
+ n = send(socket, data + bytes_sent, byte_left,
+ MSG_DONTROUTE | MSG_NOSIGNAL );
+ if( n == -1 ) {
+ syslog(LOG_ERR, "ReliableSend: sending failed!");
+ return -1;
+ }
+
+ byte_left = byte_left - n;
+ bytes_sent += n;
+ }
+
+ n = bytes_sent;
+ return n;
+}
+
+struct upnphttp * New_upnphttp(int s)
+{
+ struct upnphttp * ret;
+ if(s<0)
+ return NULL;
+ ret = (struct upnphttp *)malloc(sizeof(struct upnphttp));
+ if(ret == NULL)
+ return NULL;
+ memset(ret, 0, sizeof(struct upnphttp));
+ ret->socket = s;
+ return ret;
+}
+
+void CloseSocket_upnphttp(struct upnphttp * h)
+{
+ close(h->socket);
+ h->socket = -1;
+ h->state = 100;
+}
+
+void Delete_upnphttp(struct upnphttp * h)
+{
+ if(h)
+ {
+ if(h->socket >= 0)
+ {
+
+ close(h->socket);
+ h->socket=-1;
+ }
+
+
+ if(h->req_buf)
+ {
+ free(h->req_buf);
+ h->req_buf=NULL;
+ }
+
+
+ if(h->res_buf)
+ {
+
+ free(h->res_buf);
+ h->res_buf=NULL;
+ }
+
+ free(h);
+ }
+}
+
+/* parse HttpHeaders of the REQUEST */
+static void ParseHttpHeaders(struct upnphttp * h)
+{
+ char * line;
+ char * colon;
+ char * p;
+ int n;
+ line = h->req_buf;
+ /* TODO : check if req_buf, contentoff are ok */
+ while(line < (h->req_buf + h->req_contentoff))
+ {
+ colon = strchr(line, ':');
+ if(colon)
+ {
+ if(strncasecmp(line, "Content-Length", 14)==0)
+ {
+ p = colon;
+ while(*p < '0' || *p > '9')
+ p++;
+ h->req_contentlen = atoi(p);
+ /*printf("*** Content-Lenght = %d ***\n", h->req_contentlen);
+ printf(" readbufflen=%d contentoff = %d\n",
+ h->req_buflen, h->req_contentoff);*/
+ }
+ else if(strncasecmp(line, "SOAPAction", 10)==0)
+ {
+ p = colon;
+ n = 0;
+ while(*p == ':' || *p == ' ' || *p == '\t')
+ p++;
+ while(p[n]>=' ')
+ {
+ n++;
+ }
+ if((p[0] == '"' && p[n-1] == '"')
+ || (p[0] == '\'' && p[n-1] == '\''))
+ {
+ p++; n -= 2;
+ }
+ h->req_soapAction = p;
+ h->req_soapActionLen = n;
+ }
+ }
+ while(!(line[0] == '\r' && line[1] == '\n'))
+ line++;
+ line += 2;
+ }
+}
+
+/* very minimalistic 404 error message */
+static void Send404(struct upnphttp * h)
+{
+ static const char error404[] = "HTTP/1.1 404 Not found\r\n"
+ "Connection: close\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>"
+ "<BODY><H1>Not Found</H1>The requested URL was not found"
+ " on this server.</BODY></HTML>\r\n";
+ int n;
+
+ n = ReliableSend(h->socket, error404, sizeof(error404) - 1);
+ if (n != (sizeof(error404) - 1))
+ {
+ syslog(LOG_ERR, "Send404: %d bytes sent (out of %d)",
+ n, (sizeof(error404) - 1));
+ }
+ CloseSocket_upnphttp(h);
+}
+
+// support HNAP1
+void SendError(struct upnphttp * h, const int code, const char *title, const char *realm, const char *body)
+{
+ char *error_title=NULL;
+ char *error_realm=NULL;
+ char *error_body=NULL;
+ int len;
+ int n;
+
+ if (code <=0 || title == NULL) {
+ Send404(h);
+ return;
+ }
+
+ error_title = (char *)malloc(2048);
+ sprintf(error_title, "HTTP/1.1 %d %s\r\n"
+ "Connection: close\r\n"
+ "Content-type: text/html\r\n", code, title);
+ if (realm) {
+ error_realm = (char *)malloc(256);
+ sprintf(error_realm, "WWW-Authenticate: Basic realm=\"%s\"\r\n", realm);
+ strcat(error_title, error_realm);
+ }
+
+ strcat(error_title, "\r\n");
+
+ if (body) {
+ error_body = (char *)malloc(1024);
+ sprintf(error_body, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>"
+ "<BODY><H1>%s</H1>%s</BODY></HTML>\r\n", code, title, title, body);
+ strcat(error_title, error_body);
+ }
+
+ len = strlen(error_title);
+
+ n = ReliableSend(h->socket, error_title, len);
+ if (n != len)
+ {
+ syslog(LOG_ERR, "Send%d: %d bytes sent (out of %d)", code,
+ n, len);
+ }
+ CloseSocket_upnphttp(h);
+ if (error_title)
+ {
+ free(error_title);
+ error_title=NULL;
+ }
+
+ if (error_realm)
+ {
+ free(error_realm);
+ error_realm=NULL;
+ }
+
+ if(error_body)
+ {
+ free(error_body);
+ error_body=NULL;
+ }
+
+}
+
+/* Precondition Failed */
+static void Send412PreconditionFailed(struct upnphttp * h)
+{
+ static const char error412[] = "HTTP/1.1 412 Precondition Failed\r\n"
+ "Content-Length: 0\r\n"
+ "Connection: close\r\n\r\n";
+ int n;
+
+ n = ReliableSend(h->socket, error412, sizeof(error412) - 1);
+ if (n != (sizeof(error412) - 1))
+ {
+ syslog(LOG_ERR, "Send412PreconditionFailed: %d bytes sent (out of %d)",
+ n, (sizeof(error412) - 1));
+ }
+ CloseSocket_upnphttp(h);
+}
+
+/* Too Many Subscribers */
+static void Send412TooManySubscribers(struct upnphttp * h)
+{
+ static const char error412[] = "HTTP/1.1 412 Too Many Subscribers\r\n"
+ "Content-Length: 0\r\n"
+ "Connection: close\r\n\r\n";
+ int n;
+
+ n = ReliableSend(h->socket, error412, sizeof(error412) - 1);
+ if (n != (sizeof(error412) - 1))
+ {
+ syslog(LOG_ERR, "Send412TooManySubscribers: %d bytes sent (out of %d)",
+ n, (sizeof(error412) - 1));
+ }
+ CloseSocket_upnphttp(h);
+}
+
+/* very minimalistic 501 error message */
+static void Send501(struct upnphttp * h)
+{
+ static const char error501[] = "HTTP/1.1 501 Not Implemented\r\n"
+ "Connection: close\r\n"
+ "Content-type: text/html\r\n"
+ "\r\n"
+ "<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>"
+ "<BODY><H1>Not Implemented</H1>The HTTP Method "
+ "is not implemented by this server.</BODY></HTML>\r\n";
+ int n;
+
+ n = ReliableSend(h->socket, error501, sizeof(error501) - 1);
+ if (n != (sizeof(error501) - 1))
+ {
+ syslog(LOG_ERR, "Send501: %d bytes sent (out of %d)",
+ n, (sizeof(error501) - 1));
+ }
+ CloseSocket_upnphttp(h);
+}
+
+static const char * findendheaders(const char * s, int len)
+{
+ while(len-->0)
+ {
+ if(s[0]=='\r' && s[1]=='\n' && s[2]=='\r' && s[3]=='\n')
+ return s;
+ s++;
+ }
+ return NULL;
+}
+
+/* Sends the description generated by the parameter */
+static void sendXMLdesc(struct upnphttp * h, char * (f)(int *))
+{
+ char * desc;
+ int len;
+ desc = f(&len);
+ if(!desc)
+ {
+ syslog(LOG_ERR, "XML description generation failed");
+ return;
+ }
+ BuildResp_upnphttp(h, desc, len);
+ SendResp_upnphttp(h);
+ CloseSocket_upnphttp(h);
+ free(desc);
+}
+
+/* ProcessHTTPPOST_upnphttp()
+ * executes the SOAP query if it is possible */
+static void ProcessHTTPPOST_upnphttp(struct upnphttp * h)
+{
+ if((h->req_buflen - h->req_contentoff) >= h->req_contentlen)
+ {
+ if(h->req_soapAction)
+ {
+ /* we can process the request */
+ syslog(LOG_INFO, "SOAPAction: %.*s",
+ h->req_soapActionLen, h->req_soapAction);
+ ExecuteSoapAction(h,
+ h->req_soapAction,
+ h->req_soapActionLen);
+ }
+ else
+ {
+ static const char err400str[] =
+ "<html><body>Bad request</body></html>";
+ syslog(LOG_INFO, "No SOAPAction in HTTP headers");
+ BuildResp2_upnphttp(h, 400, "Bad Request",
+ err400str, sizeof(err400str) - 1);
+ SendResp_upnphttp(h);
+ CloseSocket_upnphttp(h);
+ }
+ }
+ else
+ {
+ /* waiting for remaining data */
+ h->state = 1;
+ }
+}
+
+Upnp_Document CreatePropertySet(void)
+{
+ Upnp_Document PropSet=NULL;
+
+ PropSet = (Upnp_Document) malloc(sizeof(Upnp_Document_CTX));
+ if (PropSet == NULL) {
+ syslog(LOG_ERR, "CreatePropertySet: out of memory!");
+ return NULL;
+ }
+ memset(PropSet, 0, sizeof(Upnp_Document_CTX));
+ LIST_INIT(&PropSet->doc_head);
+ return PropSet;
+}
+
+int UpnpAddToPropertySet(Upnp_Document PropSet,
+ const char *VarName, const char *message)
+{
+ struct Upnp_Document_element *tmp=NULL;
+ char *name=NULL;
+ char *content=NULL;
+
+ if (PropSet == NULL || VarName == NULL || message == NULL)
+ return UPNP_E_INVALID_PARAM;
+
+ tmp = (struct Upnp_Document_element *) malloc(sizeof(struct Upnp_Document_element));
+ if (tmp == NULL) {
+ syslog(LOG_ERR, "UpnpAddToPropertySet: out of memory!");
+ return UPNP_E_OUTOF_MEMORY;
+ }
+ memset(tmp, 0, sizeof(struct Upnp_Document_element));
+
+ name = (char *) malloc(strlen(VarName) + 1);
+ if (name == NULL) {
+ syslog(LOG_ERR, "UpnpAddToPropertySet: out of memory!");
+ free(tmp);
+ return UPNP_E_OUTOF_MEMORY;
+ }
+ memset(name, 0, strlen(VarName) + 1);
+ memcpy(name, VarName, strlen(VarName));
+
+ content = (char *) malloc(strlen(message) + 1);
+ if (content == NULL) {
+ syslog(LOG_ERR, "UpnpAddToPropertySet: out of memory!");
+ free(tmp);
+ free(name);
+ return UPNP_E_OUTOF_MEMORY;
+ }
+ memset(content, 0, strlen(message) + 1);
+ memcpy(content, message, strlen(message));
+
+ PropSet->NumOfVarName += 1;
+ PropSet->TotalMessageLen = strlen(message) + (strlen(VarName) * 2);
+ tmp->VarName = name;
+ tmp->message = content;
+ LIST_INSERT_HEAD(&PropSet->doc_head, tmp, entries);
+
+ return UPNP_E_SUCCESS;
+}
+
+static char *MakeEventBody(Upnp_Document PropSet, unsigned int *total_len)
+{
+ unsigned int len=0;
+ char *buf=NULL;
+ unsigned int buf_len=0;
+ struct Upnp_Document_element *e;
+
+ if (PropSet == NULL || PropSet->NumOfVarName == 0)
+ return NULL;
+
+ buf_len = (strlen("<e:property><></></e:property>") * PropSet->NumOfVarName)
+ + PropSet->TotalMessageLen + 100;
+ buf = (char *) malloc(buf_len);
+ if (buf == NULL) {
+ syslog(LOG_ERR, "MakeEventBody: out of memory!");
+ return NULL;
+ }
+ memset(buf, 0, buf_len);
+
+ for(e = PropSet->doc_head.lh_first; e != NULL; e = e->entries.le_next)
+ {
+ if (e->VarName) {
+ char *tmpbuf=NULL;
+ unsigned int tmpbuf_len=0;
+ unsigned int propertyLen=0;
+
+ tmpbuf_len = strlen("<e:property><></></e:property>")
+ + (strlen(e->VarName) * 2)
+ + strlen(e->message) + 1;
+ tmpbuf = (char *) malloc(tmpbuf_len);
+ if (tmpbuf == NULL) {
+ syslog(LOG_ERR, "MakeEventBody: out of memory!");
+ free(buf);
+ return NULL;
+ }
+ memset(tmpbuf, 0, tmpbuf_len);
+ propertyLen = sprintf(tmpbuf,
+ "<e:property><%s>%s</%s></e:property>",
+ e->VarName, e->message, e->VarName);
+ len += propertyLen;
+ strcat(buf, tmpbuf);
+ free(tmpbuf);
+ }
+ }
+
+ *total_len = len;
+ return buf;
+}
+
+static void UpnpSendEvent(char *packet,
+ const char *EventBody, const unsigned int bodylength,
+ struct upnp_subscription_record *subscribe_list,
+ struct upnp_subscription_element *sub)
+{
+ unsigned int packetLength;
+ struct sockaddr_in dest;
+ int n, sockfd=-1;
+ struct EvtRespElement *EvtResp=NULL;
+
+ if (packet == NULL || EventBody == NULL || bodylength == 0 ||
+ subscribe_list == NULL || sub == NULL)
+ return;
+
+ packetLength = sprintf(packet,
+ "NOTIFY %s HTTP/1.1\r\n"
+ "SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
+ "HOST: %s:%d\r\n"
+ "Content-Type: text/xml; charset=\"utf-8\"\r\n"
+ "NT: upnp:event\r\n"
+ "NTS: upnp:propchange\r\n"
+ "SID: %s\r\n"
+ "SEQ: %d\r\n"
+ "Content-Length: %d\r\n\r\n"
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
+ "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">"
+ "%s"
+ "</e:propertyset>",
+ sub->callback_url,
+ sub->IP,
+ sub->port,
+ sub->sid,
+ (int)sub->seq,
+ bodylength+110,
+ EventBody);
+
+ sub->seq++;
+ if (sub->seq >= UINT_MAX)
+ sub->seq = 1;
+ //printf("Packet------------>\n%s\n<-----------------Packet\n\n", packet);
+
+ memset(&dest,0,sizeof(struct sockaddr_in));
+ dest.sin_addr.s_addr = sub->IP_inet_addr;
+ dest.sin_port = htons(sub->port);
+ dest.sin_family = AF_INET;
+
+ // create a socket
+ if ((sockfd = socket( AF_INET, SOCK_STREAM, 0 )) == -1) {
+ syslog(LOG_ERR, "UpnpSendEvent: creating a socket falied!");
+ return;
+ }
+ if (connect( sockfd, ( struct sockaddr * )&dest,
+ sizeof( struct sockaddr_in ) ) == -1) {
+ syslog(LOG_ERR, "UpnpSendEvent: connecting a socket falied!");
+ close(sockfd);
+ return;
+ }
+
+ n = ReliableSend(sockfd, packet, packetLength);
+ if (n != packetLength)
+ {
+ syslog(LOG_ERR, "UpnpSendEvent: %d bytes sent (out of %d)",
+ n, packetLength);
+ close(sockfd);
+ return;
+ }
+
+ EvtResp = (struct EvtRespElement *) malloc(sizeof(struct EvtRespElement));
+ if (EvtResp == NULL) {
+ syslog(LOG_ERR, "UpnpSendEvent: out of memory!");
+ close(sockfd);
+ return;
+ }
+ memset(EvtResp, 0, sizeof(struct EvtRespElement));
+ EvtResp->socket = sockfd;
+ memcpy(EvtResp->sid, sub->sid, strlen(sub->sid));
+ EvtResp->TimeOut = 30;
+ LIST_INSERT_HEAD(&subscribe_list->EvtResp_head, EvtResp, entries);
+}
+
+void UpnpSendEventSingle(Upnp_Document PropSet,
+ struct upnp_subscription_record *subscribe_list,
+ struct upnp_subscription_element *sub)
+{
+ char *packet=NULL;
+ unsigned int bodylength=0;
+ char *EventBody=NULL;
+
+ if (PropSet == NULL || sub == NULL || subscribe_list == NULL ||
+ subscribe_list->subscription_head.lh_first == NULL)
+ return;
+
+ EventBody = MakeEventBody(PropSet, &bodylength);
+ if (EventBody == NULL) {
+ syslog(LOG_ERR, "UpnpSendEventSingle: MakeEventBody failed!");
+ return;
+ }
+
+ packet = (char *) malloc(bodylength + 483);
+ if (packet == NULL) {
+ syslog(LOG_ERR, "UpnpSendEventSingle: out of memory!");
+ free(EventBody);
+ return;
+ }
+ memset(packet, 0, bodylength + 483);
+
+ UpnpSendEvent(packet, EventBody, bodylength, subscribe_list, sub);
+ free(EventBody);
+ free(packet);
+}
+
+void ProcessEventingResp(struct EvtRespElement *EvtResp)
+{
+ char *buf=NULL;
+ int n;
+
+ if (EvtResp == NULL)
+ return;
+
+ buf = (char *) malloc(512);
+ if (buf == NULL) {
+ close(EvtResp->socket);
+ return;
+ }
+ memset(buf, 0, 512);
+
+ if ((n = recv(EvtResp->socket, buf, 512, 0)) == -1) {
+ syslog(LOG_ERR, "ProcessEventingResp: Receive failed!");
+ }
+ else if(n==0)
+ {
+ syslog(LOG_WARNING, "ProcessEventingResp: connection closed inexpectedly");
+ }
+
+ //printf("------------>\nProcessEventingResp: sid[%s]\n%s\n<--------------\n", EvtResp->sid, buf);
+ close(EvtResp->socket);
+ free(buf);
+}
+
+void UpnpSendEventAll(Upnp_Document PropSet,
+ struct upnp_subscription_record *sub_list)
+{
+ struct upnp_subscription_element *sub;
+ unsigned int bodylength=0;
+ char *EventBody=NULL;
+ char *packet=NULL;
+
+ if (PropSet == NULL || sub_list == NULL || sub_list->subscription_head.lh_first == NULL)
+ return;
+
+ EventBody = MakeEventBody(PropSet, &bodylength);
+ if (EventBody == NULL) {
+ syslog(LOG_ERR, "UpnpSendEventAll: MakeEventBody failed!");
+ return;
+ }
+
+ packet = (char *) malloc(bodylength + 483);
+ if (packet == NULL) {
+ syslog(LOG_ERR, "UpnpSendEventAll: out of memory!");
+ free(EventBody);
+ return;
+ }
+
+ for (sub = sub_list->subscription_head.lh_first; sub != NULL; sub = sub->entries.le_next)
+ {
+ memset(packet, 0, bodylength + 483);
+ UpnpSendEvent(packet, EventBody, bodylength, sub_list, sub);
+ }
+ free(EventBody);
+ free(packet);
+}
+
+void UpnpDocument_free(Upnp_Document PropSet)
+{
+ struct Upnp_Document_element *e;
+ struct Upnp_Document_element *next;
+
+ if (PropSet == NULL)
+ return;
+
+ for(e = PropSet->doc_head.lh_first; e != NULL; )
+ {
+ next = e->entries.le_next;
+ if (e->VarName)
+ free(e->VarName);
+ if (e->message)
+ free(e->message);
+ LIST_REMOVE(e, entries);
+ free(e);
+ e = next;
+ }
+
+ free(PropSet);
+}
+
+static int BuildSubscribeResponse(struct upnphttp * h, struct process_upnp_subscription *sub)
+{
+ char *Subresp=NULL;
+ int n, packet_len, ret=UPNP_E_SUCCESS;
+
+ Subresp = (char *) malloc(300);
+ if (Subresp == NULL) {
+ syslog(LOG_ERR, "BuildSubscribeResponse: out of memory!");
+ return UPNP_E_OUTOF_MEMORY;
+ }
+ memset(Subresp, 0, 300);
+
+ packet_len = sprintf(Subresp,
+ "HTTP/1.1 200 OK \r\n"
+ "Server: " MINIUPNPD_SERVER_STRING "\r\n"
+ "SID: %s\r\n"
+ "TIMEOUT: Second-%d\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n",
+ sub->sid, (int)h->subscribe_list->max_subscription_time);
+
+ //printf("BuildSubscribeResponse------->\n%s<------------BuildSubscribeResponse\n", Subresp);
+
+ n = ReliableSend(h->socket, Subresp, packet_len);
+ if (n != packet_len)
+ {
+ syslog(LOG_ERR, "BuildSubscribeResponse: %d bytes sent (out of %d)",
+ n, packet_len);
+ }
+
+ free(Subresp);
+ CloseSocket_upnphttp(h);
+ return ret;
+}
+
+static void BuildUnSubscribeResponse(struct upnphttp * h)
+{
+ static const char UnSubresp[] =
+ "HTTP/1.1 200 OK \r\n"
+ "Content-Length: 0\r\n"
+ "\r\n";
+
+ int n;
+
+ n = ReliableSend(h->socket, UnSubresp, sizeof(UnSubresp) - 1);
+ if (n != (sizeof(UnSubresp) - 1))
+ {
+ syslog(LOG_ERR, "BuildUnSubscribeResponse: %d bytes sent (out of %d)",
+ n, (sizeof(UnSubresp) - 1));
+ }
+ CloseSocket_upnphttp(h);
+}
+
+static struct upnp_subscription_element *UPnPTryToSubscribe
+ (struct upnphttp * h, struct process_upnp_subscription *sub)
+{
+ int SIDNumber,rnumber;
+ char *SID=NULL;
+ struct upnp_subscription_element *new_sub=NULL;
+
+ if (h == NULL || sub == NULL)
+ return NULL;
+
+ if (h->subscribe_list->total_subscription >= h->subscribe_list->max_subscription_num)
+ return NULL;
+
+ new_sub = (struct upnp_subscription_element *) malloc(sizeof(struct upnp_subscription_element));
+ if (new_sub == NULL)
+ return NULL;
+ memset(new_sub, 0, sizeof(struct upnp_subscription_element));
+
+ //
+ // The SID must be globally unique, so lets generate it using
+ // a bunch of random hex characters
+ //
+ SID = (char*)malloc(SID_LEN);
+ if (SID == NULL) {
+ free(new_sub);
+ return NULL;
+ }
+ memset(SID,0,SID_LEN);
+ sprintf(SID,"uuid:");
+ for(SIDNumber=5;SIDNumber<=12;++SIDNumber)
+ {
+ rnumber = rand()%16;
+ sprintf(SID+SIDNumber,"%x",rnumber);
+ }
+ sprintf(SID+SIDNumber,"-");
+ for(SIDNumber=14;SIDNumber<=17;++SIDNumber)
+ {
+ rnumber = rand()%16;
+ sprintf(SID+SIDNumber,"%x",rnumber);
+ }
+ sprintf(SID+SIDNumber,"-");
+ for(SIDNumber=19;SIDNumber<=22;++SIDNumber)
+ {
+ rnumber = rand()%16;
+ sprintf(SID+SIDNumber,"%x",rnumber);
+ }
+ sprintf(SID+SIDNumber,"-");
+ for(SIDNumber=24;SIDNumber<=27;++SIDNumber)
+ {
+ rnumber = rand()%16;
+ sprintf(SID+SIDNumber,"%x",rnumber);
+ }
+ sprintf(SID+SIDNumber,"-");
+ for(SIDNumber=29;SIDNumber<=40;++SIDNumber)
+ {
+ rnumber = rand()%16;
+ sprintf(SID+SIDNumber,"%x",rnumber);
+ }
+
+ memcpy(sub->sid, SID, SID_LEN);
+ if (BuildSubscribeResponse(h, sub) != UPNP_E_SUCCESS) {
+ free(SID);
+ free(new_sub);
+ return NULL;
+ }
+
+ memcpy(new_sub->IP, sub->IP, IP_ADDRLEN);
+ new_sub->IP_inet_addr = sub->IP_inet_addr;
+ new_sub->port = sub->port;
+ memcpy(new_sub->sid, SID, SID_LEN);
+ memcpy(new_sub->callback_url, sub->callback_url, URL_MAX_LEN);
+ new_sub->TimeOut = sub->TimeOut;
+//WPS2DOTX
+// new_sub->subscription_timeout = h->subscribe_list->subscription_timeout;
+ new_sub->subscription_timeout = sub->TimeOut;
+
+// printf("\n\nsubscription_timeout=%d\n",new_sub->subscription_timeout);
+
+ new_sub->eventID = UPNP_EVENT_SUBSCRIPTION_REQUEST;
+ LIST_INSERT_HEAD(&h->subscribe_list->subscription_head, new_sub, entries);
+ h->subscribe_list->total_subscription++;
+ syslog(LOG_INFO, "Subscribe: total_subscription [%d]",
+ (int)h->subscribe_list->total_subscription);
+
+ free(SID);
+ return new_sub;
+}
+
+static char *GetTokenValue(const unsigned long buf, const unsigned long len, unsigned int *Value_len)
+{
+ unsigned long start=0, end=0;
+ unsigned long buffer_end;
+ char *line;
+
+ if (len == 0)
+ return NULL;
+
+ line = (char *)buf;
+ buffer_end = (unsigned long)line + len;
+
+ while ((unsigned long)line < buffer_end) {
+ if ((*line == ' ') || (*line == ':') || (*line == '-'))
+ line++;
+ else {
+ start = (unsigned long)line;
+ break;
+ }
+ }
+ if (start == 0) {
+ *Value_len = 0;
+ return NULL;
+ }
+
+ while ((unsigned long)line < buffer_end) {
+ if ((*line == ' ') || (*line == '\r') || (*line == '\n')) {
+ end = (unsigned long)line;
+ break;
+ }
+ else
+ line++;
+ }
+ if (end == 0) {
+ *Value_len = 0;
+ return NULL;
+ }
+
+ *Value_len = (unsigned int)(end - start);
+ return (char *)start;
+}
+
+static __inline__ void GetLineLen(const unsigned long buf, unsigned int *line_len)
+{
+ unsigned long start=0;
+ const unsigned short MaxCharsPerLine = 1000;
+ unsigned short NumChars=0;
+ char *line;
+
+ line = (char *)buf;
+ start = (unsigned long)line;
+ while (*line != '\n') {
+ NumChars++;
+ if (NumChars >= MaxCharsPerLine) {
+ syslog(LOG_WARNING, "Too many characters in a line!");
+ *line_len = 0;
+ return;
+ }
+ line++;
+ }
+
+ *line_len = (unsigned long)line + 1 - start;
+ return;
+}
+
+
+// To do : support IPv6
+static __inline__ int GetIPandPortandCallBack(const unsigned long buf, const unsigned int buf_len,
+ struct process_upnp_subscription *sub)
+{
+ char *line=NULL;
+ unsigned long buffer_end=0;
+ unsigned char dot_count=0;
+ unsigned long start=0;
+ unsigned long end=0;
+ unsigned char GotIPandPort=0;
+
+ line = (char *)buf;
+ buffer_end = (unsigned long)line + buf_len;
+ while ((unsigned long)line < buffer_end) {
+ if (*line == ' ') {
+ line++;
+ continue;
+ }
+ if (strncasecmp("<http://", line, 8) != 0)
+ return UPNP_E_INVALID_PARAM;
+ else
+ break;
+ }
+
+ line += 8;
+ start =(unsigned long) line;
+ while ((unsigned long)line < buffer_end) {
+ if (*line == '.')
+ dot_count++;
+ if ((*line == ':') || (*line == '/')) {
+ if (dot_count != IP_V4_DOT_COUNT)
+ return UPNP_E_INVALID_PARAM;
+ memcpy(sub->IP, (char *)start, (unsigned long)line-start);
+ if ((sub->IP_inet_addr = inet_addr(sub->IP)) == -1)
+ return UPNP_E_INVALID_PARAM;
+ break;
+ }
+ line++;
+ }
+
+ if (*line == '/') {
+ sub->port = 80;
+ GotIPandPort = 1;
+ start = (unsigned long)line;
+ end = 0;
+ goto get_callback;
+ }
+
+ line += 1;
+ start = (unsigned long)line;
+ while ((unsigned long)line < buffer_end) {
+ if (*line == '/') {
+ end = (unsigned long)line;
+ if (end <= start)
+ return UPNP_E_INVALID_PARAM;
+ else {
+ char port[10];
+ memset(port, 0, 10);
+ memcpy(port, (char *)start, end-start);
+ sub->port = atoi(port);
+ GotIPandPort = 1;
+ start = (unsigned long)line;
+ end = 0;
+ break;
+ }
+ }
+ line++;
+ }
+
+get_callback:
+ if (!GotIPandPort)
+ return UPNP_E_INVALID_PARAM;
+ while ((unsigned long)line < buffer_end) {
+ if (*line == '>') {
+ end = (unsigned long)line;
+ if (end <= start)
+ return UPNP_E_INVALID_PARAM;
+ else {
+ memcpy(sub->callback_url, (char *)start, end-start);
+ return UPNP_E_SUCCESS;
+ }
+ }
+ line++;
+ }
+
+ return UPNP_E_INVALID_PARAM;
+}
+
+static int ParseSUBSCRIBEPacket(struct upnphttp * h,
+ struct process_upnp_subscription *sub)
+{
+ char *line=NULL, *value=NULL, *tmp=NULL;
+ unsigned int line_len=0, value_len=0, tmp_len=0;
+ unsigned long buffer_end=0;
+
+ if (h->req_buf == NULL || h->req_contentoff == 0)
+ return UPNP_E_INVALID_PARAM;
+
+ line = h->req_buf;
+ buffer_end = (unsigned long)h->req_buf + h->req_contentoff;
+ while ((unsigned long)line < buffer_end) {
+ if (*line == ' ') {
+ line++;
+ continue;
+ }
+ GetLineLen((const unsigned long)line, &line_len);
+ if (line_len == 0)
+ return UPNP_E_INVALID_PARAM;
+ else if (line_len > 2) {
+ if (strncasecmp("SUBSCRIBE", line, 9) == 0) {
+ value = GetTokenValue((const unsigned long)line+9, line_len-9, &value_len);
+ if (value == NULL || value_len == 0)
+ return UPNP_E_INVALID_PARAM;
+
+ if (strncasecmp(h->subscribe_list->event_url, value, value_len) != 0) {
+ syslog(LOG_WARNING, "SUBSCRIBE event url mismatched!");
+ return UPNP_E_INVALID_PARAM;
+ }
+ }
+ else if (strncasecmp("UNSUBSCRIBE", line, 11) == 0) {
+ value = GetTokenValue((const unsigned long)line+11, line_len-11, &value_len);
+ if (value == NULL || value_len == 0)
+ return UPNP_E_INVALID_PARAM;
+
+ if (strncasecmp(h->subscribe_list->event_url, value, value_len) != 0) {
+ syslog(LOG_WARNING, "UNSUBSCRIBE event url mismatched!");
+ return UPNP_E_INVALID_PARAM;
+ }
+ }
+ else if (strncasecmp("Host", line, 4) == 0) {
+ value = GetTokenValue((const unsigned long)line+4, line_len-4, &value_len);
+ if (value == NULL || value_len == 0)
+ return UPNP_E_INVALID_PARAM;
+
+ char host_info[30];
+ memset(host_info, 0, 30);
+ sprintf(host_info, "%s:%d", h->subscribe_list->my_IP, h->subscribe_list->my_port);
+ if (strncmp(value, host_info, value_len) != 0) {
+ syslog(LOG_WARNING, "Wrong host [%s]", host_info);
+ return UPNP_E_INVALID_PARAM;
+ }
+ }
+ else if (strncasecmp("Callback", line, 8) == 0) {
+ value = GetTokenValue((const unsigned long)line+8, line_len-8, &value_len);
+ if (value == NULL || value_len == 0 || (value_len > (URL_MAX_LEN-1)))
+ return UPNP_E_INVALID_PARAM;
+
+ if (GetIPandPortandCallBack((const unsigned long) value, value_len, sub) != UPNP_E_SUCCESS)
+ return UPNP_E_INVALID_PARAM;
+ }
+ else if (strncasecmp("Timeout", line, 7) == 0) {
+ value = GetTokenValue((const unsigned long)line+7, line_len-7, &value_len);
+ if (value == NULL || value_len == 0 || value_len < 8)
+ return UPNP_E_INVALID_PARAM;
+
+ if (strncasecmp("Second", value, 6) != 0)
+ return UPNP_E_INVALID_PARAM;
+ tmp = value + 6;
+ tmp_len = value_len - 6;
+ value = GetTokenValue((const unsigned long)tmp, tmp_len+1, &value_len);
+ if (value_len == 0)
+ return UPNP_E_INVALID_PARAM;
+ else if (value_len == 8 && (strncasecmp("infinite", line, 8) == 0))
+ sub->TimeOut = MAX_SUB_TIMEOUT;
+ else {
+ if (value_len > 4)
+ sub->TimeOut = MAX_SUB_TIMEOUT;
+ else {
+ char time_out[5];
+ memset(time_out, 0, 5);
+ memcpy(time_out, value, value_len);
+ sub->TimeOut = atoi(time_out);
+ }
+ }
+ }
+ else if (strncasecmp("SID", line, 3) == 0) {
+ value = GetTokenValue((const unsigned long)line+3, line_len-3, &value_len);
+ if (value == NULL || value_len == 0 || value_len < 4)
+ return UPNP_E_INVALID_PARAM;
+
+ if (strncasecmp("uuid", value, 4) != 0)
+ return UPNP_E_INVALID_PARAM;
+ tmp = value + 4;
+ tmp_len = value_len - 4;
+ value = GetTokenValue((const unsigned long)tmp, tmp_len+1, &value_len);
+ if (value == NULL || value_len == 0 || value_len != 36)
+ return UPNP_E_INVALID_PARAM;
+
+ char sid[SID_LEN];
+ memset(sid, 0, SID_LEN);
+ memcpy(sub->sid, "uuid:", 5);
+ memcpy(sub->sid+5, value, value_len);
+ }
+ }
+
+ line += line_len;
+ }
+
+ return UPNP_E_SUCCESS;
+}
+
+static void UPnPProcessSUBSCRIBE(struct upnphttp * h)
+{
+ struct process_upnp_subscription sub;
+ struct upnp_subscription_element *new_sub=NULL;
+ int ret;
+
+ memset(&sub, 0, sizeof(struct process_upnp_subscription));
+ ret = ParseSUBSCRIBEPacket(h, &sub);
+ if (ret != UPNP_E_SUCCESS) {
+ Send412PreconditionFailed(h);
+ return;
+ }
+ else {
+#ifdef DEBUG
+ printf("IP [%s]\n", sub.IP);
+ printf("Host [%d.%d.%d.%d:%d]\n", (sub.IP_inet_addr>>24)&0xFF,
+ (sub.IP_inet_addr>>16)&0xFF,
+ (sub.IP_inet_addr>>8)&0xFF,
+ (sub.IP_inet_addr)&0xFF, sub.port);
+ printf("SID [%s]\n", sub.sid);
+ printf("CallBack %s\n", sub.callback_url);
+ printf("Timeout [%d]\n", (int)sub.TimeOut);
+#endif
+
+ if (sub.TimeOut == 0)
+ sub.TimeOut = MAX_SUB_TIMEOUT;
+
+ if (sub.sid[0] == 0)
+ { //Subscribe
+ if (sub.callback_url[0] == 0) {
+ Send412PreconditionFailed(h);
+ return;
+ }
+
+ new_sub = UPnPTryToSubscribe(h, &sub);
+ if (new_sub == NULL) {
+ Send412TooManySubscribers(h);
+ return;
+ }
+
+ if (h->subscribe_list->EventCallBack)
+ h->subscribe_list->EventCallBack(new_sub);
+ }
+ else
+ { // Renewal subscription
+ struct upnp_subscription_element *e;
+ struct upnp_subscription_element *next;
+ unsigned char count=0;
+
+ for(e = h->subscribe_list->subscription_head.lh_first; e != NULL; )
+ {
+ next = e->entries.le_next;
+ if(strcmp(e->sid, sub.sid) == 0)
+ {
+ count++;
+ if (BuildSubscribeResponse(h, &sub) != UPNP_E_SUCCESS) {
+ LIST_REMOVE(e, entries);
+ h->subscribe_list->total_subscription--;
+ free(e);
+ syslog(LOG_ERR, "UPnPProcessSUBSCRIBE : renew failed!");
+ return;
+ }
+ else {
+ //WPS2DOTX
+ //e->subscription_timeout = h->subscribe_list->subscription_timeout;
+ e->subscription_timeout = (int)sub.TimeOut;
+
+ e->eventID = UPNP_EVENT_RENEWAL_COMPLETE;
+ }
+ syslog(LOG_INFO, "Renewal subscription: total_subscription [%d]",
+ (int)h->subscribe_list->total_subscription);
+ if (h->subscribe_list->EventCallBack){
+ h->subscribe_list->EventCallBack(e);
+ if(e->wscdReNewState == 1){
+ Send412PreconditionFailed(h);
+ e->wscdReNewState = 0;
+ }
+ }
+ }
+ e = next;
+ }
+ if (count == 0) {
+ Send412PreconditionFailed(h);
+ syslog(LOG_ERR, "UPnPProcessSUBSCRIBE[renew] : Could not find the sid[%s]!", sub.sid);
+ if (new_sub == NULL) {
+ new_sub = (struct upnp_subscription_element *)malloc(sizeof(struct upnp_subscription_element));
+ if (new_sub == NULL)
+ return;
+ memset(new_sub, 0, sizeof(struct upnp_subscription_element));
+ new_sub->eventID = UPNP_EVENT_RENEWAL_COMPLETE;
+ memcpy(new_sub->sid, sub.sid, strlen(sub.sid));
+ if (h->subscribe_list->EventCallBack)
+ h->subscribe_list->EventCallBack(new_sub);
+ free(new_sub);
+ }
+ else
+ syslog(LOG_ERR, "UPnPProcessSUBSCRIBE[renew] : Could not allocate buffer for new_sub!");
+ }
+ }
+ }
+}
+
+static void UPnPProcessUNSUBSCRIBE(struct upnphttp * h)
+{
+ struct process_upnp_subscription sub;
+ struct upnp_subscription_element *e;
+ struct upnp_subscription_element *next;
+ int ret;
+ unsigned char count=0;
+
+ memset(&sub, 0, sizeof(struct process_upnp_subscription));
+ ret = ParseSUBSCRIBEPacket(h, &sub);
+ if (ret != UPNP_E_SUCCESS) {
+ Send412PreconditionFailed(h);
+ return;
+ }
+ else {
+#ifdef DEBUG
+ printf("IP [%s]\n", sub.IP);
+ printf("Host [%d.%d.%d.%d:%d]\n", (sub.IP_inet_addr>>24)&0xFF,
+ (sub.IP_inet_addr>>16)&0xFF,
+ (sub.IP_inet_addr>>8)&0xFF,
+ (sub.IP_inet_addr)&0xFF, sub.port);
+ printf("SID [%s]\n", sub.sid);
+ printf("CallBack %s\n", sub.callback_url);
+ printf("Timeout [%d]\n", (int)sub.TimeOut);
+#endif
+
+ if (sub.sid[0] == 0) {
+ Send412PreconditionFailed(h);
+ return;
+ }
+
+ for(e = h->subscribe_list->subscription_head.lh_first; e != NULL; )
+ {
+ next = e->entries.le_next;
+ if(strcmp(e->sid, sub.sid) == 0)
+ {
+ count++;
+ LIST_REMOVE(e, entries);
+ BuildUnSubscribeResponse(h);
+ h->subscribe_list->total_subscription--;
+ syslog(LOG_INFO, "UNSUBSCRIBE: total_subscription [%d]",
+ (int)h->subscribe_list->total_subscription);
+
+ e->eventID = UPNP_EVENT_UNSUBSCRIBE_COMPLETE;
+ if (h->subscribe_list->EventCallBack)
+ h->subscribe_list->EventCallBack(e);
+ free(e);
+ }
+ e = next;
+ }
+
+ if (count == 0) {
+ BuildUnSubscribeResponse(h);
+ syslog(LOG_ERR, "UPnPProcessUNSUBSCRIBE : Could not find the sid!");
+ }
+ }
+}
+
+/* Parse and process Http Query
+ * called once all the HTTP headers have been received. */
+static void ProcessHttpQuery_upnphttp(struct upnphttp * h)
+{
+ char HttpCommand[16];
+ char HttpUrl[128];
+ char * HttpVer;
+ char * p;
+ int i;
+ p = h->req_buf;
+ if(!p)
+ return;
+ for(i = 0; i<15 && *p != ' ' && *p != '\r'; i++)
+ HttpCommand[i] = *(p++);
+ HttpCommand[i] = '\0';
+ while(*p==' ')
+ p++;
+ for(i = 0; i<127 && *p != ' ' && *p != '\r'; i++)
+ HttpUrl[i] = *(p++);
+ HttpUrl[i] = '\0';
+ while(*p==' ')
+ p++;
+ HttpVer = h->HttpVer;
+ for(i = 0; i<15 && *p != '\r'; i++)
+ HttpVer[i] = *(p++);
+ HttpVer[i] = '\0';
+ syslog(LOG_INFO, "HTTP REQUEST : %s %s (%s)",
+ HttpCommand, HttpUrl, HttpVer);
+ ParseHttpHeaders(h);
+ if(strcmp("POST", HttpCommand) == 0)
+ {
+ h->req_command = EPost;
+ ProcessHTTPPOST_upnphttp(h);
+ }
+ else if(strcmp("GET", HttpCommand) == 0)
+ {
+ h->req_command = EGet;
+
+ if (strncasecmp((char *)h->req_buf, "GET /HNAP", 9) == 0) {
+ i = 0;
+ int len;
+ while(h->soapMethods[i].methodName)
+ {
+ len = strlen(h->soapMethods[i].methodName);
+ if(strncmp("GetDeviceSettings", h->soapMethods[i].methodName, len) == 0)
+ {
+ h->soapMethods[i].methodImpl(h);
+ return;
+ }
+ i++;
+ }
+ syslog(LOG_NOTICE, "%s not found, responding ERROR 404", HttpUrl);
+ Send404(h);
+ return;
+ }
+ i = 0;
+ if (h->sendDesc) {
+ while(h->sendDesc[i].DescName)
+ {
+ if(strcmp(h->sendDesc[i].DescName, HttpUrl) == 0)
+ {
+ sendXMLdesc(h, h->sendDesc[i].sendDescImpl);
+ return;
+ }
+ i++;
+ }
+ }
+
+ syslog(LOG_NOTICE, "%s not found, responding ERROR 404", HttpUrl);
+ Send404(h);
+ }
+ else if(strcmp("SUBSCRIBE", HttpCommand) == 0)
+ {
+ //printf("<<--------------------\n%s\n------------------->>\n", h->req_buf);
+ UPnPProcessSUBSCRIBE(h);
+ }
+ else if(strcmp("UNSUBSCRIBE", HttpCommand) == 0)
+ {
+ //printf("<<--------------------\n%s\n------------------->>\n", h->req_buf);
+ UPnPProcessUNSUBSCRIBE(h);
+ }
+ else
+ {
+ syslog(LOG_NOTICE, "Unsupported HTTP Command %s", HttpCommand);
+ Send501(h);
+ }
+}
+
+
+void Process_upnphttp(struct upnphttp * h)
+{
+ char *buf=NULL;
+ int n;
+
+ if(!h)
+ return;
+
+ buf = (char *) malloc(2048);
+ if (buf == NULL) {
+ syslog(LOG_ERR, "Process_upnphttp: out of memory!");
+ return;
+ }
+ memset(buf, 0, 2048);
+
+ switch(h->state)
+ {
+ case 0:
+ n = recv(h->socket, buf, 2048, 0);
+ if(n<0)
+ {
+ syslog(LOG_ERR, "recv (state0): %m");
+ h->state = 100;
+ }
+ else if(n==0)
+ {
+ syslog(LOG_WARNING, "connection closed inexpectedly");
+ h->state = 100;
+ }
+ else
+ {
+ const char * endheaders;
+ /*printf("== PACKET RECEIVED (%d bytes) ==\n", n);
+ fwrite(buf, 1, n, stdout); // debug
+ printf("== END OF PACKET RECEIVED ==\n");*/
+ /* if 1st arg of realloc() is null,
+ * realloc behaves the same as malloc() */
+ //h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen + 1);
+ h->req_buf = (char *)realloc(h->req_buf, 2048); //Brad modify for HNAP, bug fix
+ memcpy(h->req_buf + h->req_buflen, buf, n);
+ h->req_buflen += n;
+ h->req_buf[h->req_buflen] = '\0';
+ /* search for the string "\r\n\r\n" */
+ endheaders = findendheaders(h->req_buf, h->req_buflen);
+ if(endheaders)
+ {
+ h->req_contentoff = endheaders - h->req_buf + 4;
+ ProcessHttpQuery_upnphttp(h);
+ }
+ }
+ break;
+ case 1:
+ n = recv(h->socket, buf, 2048, 0);
+ if(n<0)
+ {
+ syslog(LOG_ERR, "recv (state1): %m");
+ h->state = 100;
+ }
+ else if(n==0)
+ {
+ syslog(LOG_WARNING, "connection closed inexpectedly");
+ h->state = 100;
+ }
+ else
+ {
+ /*fwrite(buf, 1, n, stdout);*/ /* debug */
+ h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen);
+ memcpy(h->req_buf + h->req_buflen, buf, n);
+ h->req_buflen += n;
+ if((h->req_buflen - h->req_contentoff) >= h->req_contentlen)
+ {
+ ProcessHTTPPOST_upnphttp(h);
+ }
+ }
+ break;
+ default:
+ syslog(LOG_WARNING, "unexpected state (%d)", h->state);
+ }
+
+ free(buf);
+}
+
+static const char httpresphead[] =
+ "%s %d %s\r\n"
+ "Content-Type: text/xml; charset=\"utf-8\"\r\n"
+ "Connection: close\r\n"
+ "Content-Length: %d\r\n"
+ "Server: " MINIUPNPD_SERVER_STRING "\r\n"
+ "Ext:\r\n"
+ "\r\n";
+/*
+ "<?xml version=\"1.0\"?>\n"
+ "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+ "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
+ "<s:Body>"
+
+ "</s:Body>"
+ "</s:Envelope>";
+*/
+/* with response code and response message
+ * also allocate enough memory */
+void
+BuildHeader_upnphttp(struct upnphttp * h, int respcode,
+ const char * respmsg,
+ int bodylen)
+{
+ int templen;
+ if(!h->res_buf)
+ {
+ templen = sizeof(httpresphead) + 64 + bodylen;
+ h->res_buf = (char *)malloc(templen);
+ memset(h->res_buf, 0, templen);
+ h->res_buf_alloclen = templen;
+ }
+ h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen,
+ httpresphead, h->HttpVer,
+ respcode, respmsg, bodylen);
+ if(h->res_buf_alloclen < (h->res_buflen + bodylen))
+ {
+ h->res_buf = (char *)realloc(h->res_buf, (h->res_buflen + bodylen));
+ memset(h->res_buf, 0, (h->res_buflen + bodylen));
+ h->res_buf_alloclen = h->res_buflen + bodylen;
+ }
+}
+
+void
+BuildResp2_upnphttp(struct upnphttp * h, int respcode,
+ const char * respmsg,
+ const char * body, int bodylen)
+{
+ BuildHeader_upnphttp(h, respcode, respmsg, bodylen);
+ memcpy(h->res_buf + h->res_buflen, body, bodylen);
+ h->res_buflen += bodylen;
+}
+
+/* responding 200 OK ! */
+void BuildResp_upnphttp(struct upnphttp * h,
+ const char * body, int bodylen)
+{
+ BuildResp2_upnphttp(h, 200, "OK", body, bodylen);
+}
+
+void SendResp_upnphttp(struct upnphttp * h)
+{
+ int n;
+
+ n = ReliableSend(h->socket, h->res_buf, h->res_buflen);
+ if (n != h->res_buflen)
+ {
+ syslog(LOG_ERR, "SendResp_upnphttp: %d bytes sent (out of %d)",
+ n, h->res_buflen);
+ }
+}
+
+static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
+
+/* encode 3 8-bit binary bytes as 4 '6-bit' characters */
+static void ILibencodeblock( unsigned char in[3], unsigned char out[4], int len )
+{
+ out[0] = cb64[ in[0] >> 2 ];
+ out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
+ out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
+ out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
+}
+
+/*! \fn ILibBase64Encode(unsigned char* input, const int inputlen, unsigned char** output)
+ \brief Base64 encode a stream adding padding and line breaks as per spec.
+ \par
+ \b Note: The encoded stream must be freed
+ \param input The stream to encode
+ \param inputlen The length of \a input
+ \param output The encoded stream
+ \returns The length of the encoded stream
+*/
+int ILibBase64Encode(unsigned char* input, const int inputlen, unsigned char** output)
+{
+ unsigned char* out=NULL;
+ unsigned char* in;
+
+ *output = (unsigned char*)malloc(((inputlen * 4) / 3) + 5);
+ out = *output;
+ if (out == NULL)
+ return 0;
+ in = input;
+
+ if (input == NULL || inputlen == 0)
+ {
+ *output = NULL;
+ return 0;
+ }
+
+ while ((in+3) <= (input+inputlen))
+ {
+ ILibencodeblock(in, out, 3);
+ in += 3;
+ out += 4;
+ }
+ if ((input+inputlen)-in == 1)
+ {
+ ILibencodeblock(in, out, 1);
+ out += 4;
+ }
+ else
+ if ((input+inputlen)-in == 2)
+ {
+ ILibencodeblock(in, out, 2);
+ out += 4;
+ }
+ *out = 0;
+
+ return (int)(out-*output);
+}
+
+/* Decode 4 '6-bit' characters into 3 8-bit binary bytes */
+static void ILibdecodeblock( unsigned char in[4], unsigned char out[3] )
+{
+ out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
+ out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2);
+ out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
+}
+
+/*! \fn ILibBase64Decode(unsigned char* input, const int inputlen, unsigned char** output)
+ \brief Decode a base64 encoded stream discarding padding, line breaks and noise
+ \par
+ \b Note: The decoded stream must be freed
+ \param input The stream to decode
+ \param inputlen The length of \a input
+ \param output The decoded stream
+ \returns The length of the decoded stream
+*/
+int ILibBase64Decode(unsigned char* input, const int inputlen, unsigned char** output)
+{
+ unsigned char* inptr;
+ unsigned char* out=NULL;
+ unsigned char v;
+ unsigned char in[4];
+ int i, len;
+
+ if (input == NULL || inputlen == 0)
+ {
+ *output = NULL;
+ return 0;
+ }
+
+ *output = (unsigned char*)malloc(((inputlen * 3) / 4) + 4);
+ out = *output;
+ if (out == NULL)
+ return 0;
+ inptr = input;
+
+ while( inptr <= (input+inputlen) )
+ {
+ for( len = 0, i = 0; i < 4 && inptr <= (input+inputlen); i++ )
+ {
+ v = 0;
+ while( inptr <= (input+inputlen) && v == 0 ) {
+ v = (unsigned char) *inptr;
+ inptr++;
+ v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
+ if( v ) {
+ v = (unsigned char) ((v == '$') ? 0 : v - 61);
+ }
+ }
+ if( inptr <= (input+inputlen) ) {
+ len++;
+ if( v ) {
+ in[ i ] = (unsigned char) (v - 1);
+ }
+ }
+ else {
+ in[i] = 0;
+ }
+ }
+ if( len )
+ {
+ ILibdecodeblock( in, out );
+ out += len-1;
+ }
+ }
+ *out = 0;
+ return (int)(out-*output);
+}
+
+int OpenAndConfUNIXSocket(const char *file_path)
+{
+ int s, len;
+ struct sockaddr_un local;
+
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ perror("UNIXSocket");
+ return -1;
+ }
+
+ local.sun_family = AF_UNIX;
+ strcpy(local.sun_path, file_path);
+ unlink(local.sun_path);
+ //len = strlen(local.sun_path) + sizeof(local.sun_family);
+ len = sizeof(struct sockaddr_un);
+ if (bind(s, (struct sockaddr *)&local, len) == -1) {
+ perror("UNIXSocket bind");
+ return -1;
+ }
+
+ if (listen(s, 5) == -1) {
+ perror("UNIXSocket listen");
+ return -1;
+ }
+
+ return s;
+}
+
+int CreateUnixSocket(const char *function_name,
+ const char *file_path,
+ const int time_out)
+{
+ struct sockaddr_un remote;
+ struct timeval tv;
+ int len, s;
+
+ if (file_path == NULL)
+ return -1;
+
+ if (time_out < 0)
+ return -1;
+
+ // Inter Process Communication
+ if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ return -1;
+ }
+
+ tv.tv_sec = time_out;
+ tv.tv_usec = 0;
+ if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)) < 0)
+ {
+ if (function_name) {
+ syslog(LOG_WARNING, "%s : setsockopt(unix_socket, SO_RCVTIMEO): %m", function_name);
+ }
+ else {
+ syslog(LOG_WARNING, "setsockopt(unix_socket, SO_RCVTIMEO): %m");
+ }
+ }
+
+ remote.sun_family = AF_UNIX;
+ strcpy(remote.sun_path, file_path);
+ //len = strlen(remote.sun_path) + sizeof(remote.sun_family);
+ len = sizeof(struct sockaddr_un);
+ if (connect(s, (struct sockaddr *)&remote, len) == -1) {
+ close(s);
+ return -1;
+ }
+ return s;
+}
+
+int UnixSocketSendAndReceive(const char *function_name,
+ const char *file_path,
+ const int time_out,
+ const char *in, char *out, const int out_len)
+{
+ int s=-1, t, in_len, ret=-1;
+
+ if (file_path == NULL || in == NULL || out == NULL || out_len < 1)
+ return -1;
+
+ s = CreateUnixSocket(function_name, file_path, time_out);
+ if (s == -1) {
+ if (function_name)
+ syslog(LOG_ERR, "%s : CreateUnixSocket failed", function_name);
+ goto finish;
+ }
+
+ in_len = strlen(in);
+ if (ReliableSend(s, in, in_len) != in_len) {
+ if (function_name) {
+ syslog(LOG_ERR, "%s : Unix socket send: %m", function_name);
+ }
+ goto finish;
+ }
+ if ((t = recv(s, out, out_len, 0)) > 0) {
+ out[t] = '\0';
+ ret = 0;
+ }
+ else {
+ if (t < 0) {
+ if (function_name) {
+ syslog(LOG_ERR, "%s : Unix socket recv: %m", function_name);
+ }
+ }
+ else {
+ if (function_name) {
+ syslog(LOG_WARNING, "%s : Server closed connection: %m", function_name);
+ }
+ }
+ }
+
+finish:
+ if (s >= 0)
+ close(s);
+ return ret;
+}