blob: 900eff8fb67b5ba07eaf08b01e0b88c1d7ac7698 [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001
2#include <stdlib.h>
3#include <unistd.h>
4#include <stdio.h>
5#include <string.h>
6#include <sys/types.h>
7#include <sys/socket.h>
8#include <syslog.h>
9#include <arpa/inet.h>
10#include <limits.h>
11#include <sys/ioctl.h>
12#include <net/if.h>
13
14#include "upnphttp.h"
15#include "upnpsoap.h"
16
17static int get_sockfd(void)
18{
19 static int sockfd = -1;
20
21 if (sockfd == -1) {
22 if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) {
23 perror("user: socket creation failed");
24 return(-1);
25 }
26 }
27 return sockfd;
28}
29
30IPCon IPCon_New(char * ifname)
31{
32 IPCon ipcon=NULL;
33
34 ipcon = (IPCon)malloc(sizeof(_IPCon));
35 if (!ipcon) {
36 printf("Error in IPCon_New:Cannot allocate memory\n");
37 return NULL;
38 }
39
40 ipcon->ifname = ifname;
41 return (ipcon);
42}
43
44
45IPCon IPCon_Destroy(IPCon this)
46{
47 if (!this)
48 return (NULL);
49
50 free(this);
51 return (NULL);
52}
53
54BOOLEAN IPCon_GetIpAddr(IPCon this, struct in_addr *adr)
55{
56 struct ifreq ifr;
57 int fd;
58
59 fd = get_sockfd();
60
61 if (fd >= 0) {
62 strcpy(ifr.ifr_name, this->ifname);
63 ifr.ifr_addr.sa_family = AF_INET;
64
65 if (ioctl(fd, SIOCGIFADDR, &ifr) == 0) {
66 memcpy(adr,&((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr,sizeof(struct in_addr));
67 close(fd);
68 return TRUE;
69 } else {
70 close(fd);
71 return FALSE;
72 }
73 }
74
75 return FALSE;
76}
77
78
79char *IPCon_GetIpAddrByStr(IPCon this)
80{
81 struct in_addr adr;
82 BOOLEAN result=FALSE;
83
84 result = IPCon_GetIpAddr(this,&adr);
85
86 if (result == FALSE) {
87 return NULL;
88 } else {
89 return inet_ntoa(adr);
90 }
91
92}
93
94int OpenAndConfHTTPSocket(const char * addr, unsigned short port)
95{
96 int s;
97 int i = 1;
98 struct sockaddr_in listenname;
99
100 if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
101 {
102 syslog(LOG_ERR, "socket(http): %m");
103 return -1;
104 }
105
106 if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
107 {
108 syslog(LOG_WARNING, "setsockopt(http, SO_REUSEADDR): %m");
109 }
110
111 memset(&listenname, 0, sizeof(struct sockaddr_in));
112 listenname.sin_family = AF_INET;
113 listenname.sin_port = htons(port);
114 listenname.sin_addr.s_addr = htonl(INADDR_ANY);
115
116 if(bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0)
117 {
118 syslog(LOG_ERR, "bind(http): %m");
119 return -1;
120 }
121
122 if(listen(s, 6) < 0)
123 {
124 syslog(LOG_ERR, "listen(http): %m");
125 return -1;
126 }
127
128 return s;
129}
130
131int ReliableSend(int socket, const char *data, const int len)
132{
133 int n;
134 unsigned int byte_left = len;
135 int bytes_sent = 0;
136
137 if (socket < 0 || data == NULL || len <= 0)
138 return -1;
139
140 while (byte_left > 0) {
141 // write data
142 n = send(socket, data + bytes_sent, byte_left,
143 MSG_DONTROUTE | MSG_NOSIGNAL );
144 if( n == -1 ) {
145 syslog(LOG_ERR, "ReliableSend: sending failed!");
146 return -1;
147 }
148
149 byte_left = byte_left - n;
150 bytes_sent += n;
151 }
152
153 n = bytes_sent;
154 return n;
155}
156
157struct upnphttp * New_upnphttp(int s)
158{
159 struct upnphttp * ret;
160 if(s<0)
161 return NULL;
162 ret = (struct upnphttp *)malloc(sizeof(struct upnphttp));
163 if(ret == NULL)
164 return NULL;
165 memset(ret, 0, sizeof(struct upnphttp));
166 ret->socket = s;
167 return ret;
168}
169
170void CloseSocket_upnphttp(struct upnphttp * h)
171{
172 close(h->socket);
173 h->socket = -1;
174 h->state = 100;
175}
176
177void Delete_upnphttp(struct upnphttp * h)
178{
179 if(h)
180 {
181 if(h->socket >= 0)
182 {
183
184 close(h->socket);
185 h->socket=-1;
186 }
187
188
189 if(h->req_buf)
190 {
191 free(h->req_buf);
192 h->req_buf=NULL;
193 }
194
195
196 if(h->res_buf)
197 {
198
199 free(h->res_buf);
200 h->res_buf=NULL;
201 }
202
203 free(h);
204 }
205}
206
207/* parse HttpHeaders of the REQUEST */
208static void ParseHttpHeaders(struct upnphttp * h)
209{
210 char * line;
211 char * colon;
212 char * p;
213 int n;
214 line = h->req_buf;
215 /* TODO : check if req_buf, contentoff are ok */
216 while(line < (h->req_buf + h->req_contentoff))
217 {
218 colon = strchr(line, ':');
219 if(colon)
220 {
221 if(strncasecmp(line, "Content-Length", 14)==0)
222 {
223 p = colon;
224 while(*p < '0' || *p > '9')
225 p++;
226 h->req_contentlen = atoi(p);
227 /*printf("*** Content-Lenght = %d ***\n", h->req_contentlen);
228 printf(" readbufflen=%d contentoff = %d\n",
229 h->req_buflen, h->req_contentoff);*/
230 }
231 else if(strncasecmp(line, "SOAPAction", 10)==0)
232 {
233 p = colon;
234 n = 0;
235 while(*p == ':' || *p == ' ' || *p == '\t')
236 p++;
237 while(p[n]>=' ')
238 {
239 n++;
240 }
241 if((p[0] == '"' && p[n-1] == '"')
242 || (p[0] == '\'' && p[n-1] == '\''))
243 {
244 p++; n -= 2;
245 }
246 h->req_soapAction = p;
247 h->req_soapActionLen = n;
248 }
249 }
250 while(!(line[0] == '\r' && line[1] == '\n'))
251 line++;
252 line += 2;
253 }
254}
255
256/* very minimalistic 404 error message */
257static void Send404(struct upnphttp * h)
258{
259 static const char error404[] = "HTTP/1.1 404 Not found\r\n"
260 "Connection: close\r\n"
261 "Content-type: text/html\r\n"
262 "\r\n"
263 "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>"
264 "<BODY><H1>Not Found</H1>The requested URL was not found"
265 " on this server.</BODY></HTML>\r\n";
266 int n;
267
268 n = ReliableSend(h->socket, error404, sizeof(error404) - 1);
269 if (n != (sizeof(error404) - 1))
270 {
271 syslog(LOG_ERR, "Send404: %d bytes sent (out of %d)",
272 n, (sizeof(error404) - 1));
273 }
274 CloseSocket_upnphttp(h);
275}
276
277// support HNAP1
278void SendError(struct upnphttp * h, const int code, const char *title, const char *realm, const char *body)
279{
280 char *error_title=NULL;
281 char *error_realm=NULL;
282 char *error_body=NULL;
283 int len;
284 int n;
285
286 if (code <=0 || title == NULL) {
287 Send404(h);
288 return;
289 }
290
291 error_title = (char *)malloc(2048);
292 sprintf(error_title, "HTTP/1.1 %d %s\r\n"
293 "Connection: close\r\n"
294 "Content-type: text/html\r\n", code, title);
295 if (realm) {
296 error_realm = (char *)malloc(256);
297 sprintf(error_realm, "WWW-Authenticate: Basic realm=\"%s\"\r\n", realm);
298 strcat(error_title, error_realm);
299 }
300
301 strcat(error_title, "\r\n");
302
303 if (body) {
304 error_body = (char *)malloc(1024);
305 sprintf(error_body, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>"
306 "<BODY><H1>%s</H1>%s</BODY></HTML>\r\n", code, title, title, body);
307 strcat(error_title, error_body);
308 }
309
310 len = strlen(error_title);
311
312 n = ReliableSend(h->socket, error_title, len);
313 if (n != len)
314 {
315 syslog(LOG_ERR, "Send%d: %d bytes sent (out of %d)", code,
316 n, len);
317 }
318 CloseSocket_upnphttp(h);
319 if (error_title)
320 {
321 free(error_title);
322 error_title=NULL;
323 }
324
325 if (error_realm)
326 {
327 free(error_realm);
328 error_realm=NULL;
329 }
330
331 if(error_body)
332 {
333 free(error_body);
334 error_body=NULL;
335 }
336
337}
338
339/* Precondition Failed */
340static void Send412PreconditionFailed(struct upnphttp * h)
341{
342 static const char error412[] = "HTTP/1.1 412 Precondition Failed\r\n"
343 "Content-Length: 0\r\n"
344 "Connection: close\r\n\r\n";
345 int n;
346
347 n = ReliableSend(h->socket, error412, sizeof(error412) - 1);
348 if (n != (sizeof(error412) - 1))
349 {
350 syslog(LOG_ERR, "Send412PreconditionFailed: %d bytes sent (out of %d)",
351 n, (sizeof(error412) - 1));
352 }
353 CloseSocket_upnphttp(h);
354}
355
356/* Too Many Subscribers */
357static void Send412TooManySubscribers(struct upnphttp * h)
358{
359 static const char error412[] = "HTTP/1.1 412 Too Many Subscribers\r\n"
360 "Content-Length: 0\r\n"
361 "Connection: close\r\n\r\n";
362 int n;
363
364 n = ReliableSend(h->socket, error412, sizeof(error412) - 1);
365 if (n != (sizeof(error412) - 1))
366 {
367 syslog(LOG_ERR, "Send412TooManySubscribers: %d bytes sent (out of %d)",
368 n, (sizeof(error412) - 1));
369 }
370 CloseSocket_upnphttp(h);
371}
372
373/* very minimalistic 501 error message */
374static void Send501(struct upnphttp * h)
375{
376 static const char error501[] = "HTTP/1.1 501 Not Implemented\r\n"
377 "Connection: close\r\n"
378 "Content-type: text/html\r\n"
379 "\r\n"
380 "<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>"
381 "<BODY><H1>Not Implemented</H1>The HTTP Method "
382 "is not implemented by this server.</BODY></HTML>\r\n";
383 int n;
384
385 n = ReliableSend(h->socket, error501, sizeof(error501) - 1);
386 if (n != (sizeof(error501) - 1))
387 {
388 syslog(LOG_ERR, "Send501: %d bytes sent (out of %d)",
389 n, (sizeof(error501) - 1));
390 }
391 CloseSocket_upnphttp(h);
392}
393
394static const char * findendheaders(const char * s, int len)
395{
396 while(len-->0)
397 {
398 if(s[0]=='\r' && s[1]=='\n' && s[2]=='\r' && s[3]=='\n')
399 return s;
400 s++;
401 }
402 return NULL;
403}
404
405/* Sends the description generated by the parameter */
406static void sendXMLdesc(struct upnphttp * h, char * (f)(int *))
407{
408 char * desc;
409 int len;
410 desc = f(&len);
411 if(!desc)
412 {
413 syslog(LOG_ERR, "XML description generation failed");
414 return;
415 }
416 BuildResp_upnphttp(h, desc, len);
417 SendResp_upnphttp(h);
418 CloseSocket_upnphttp(h);
419 free(desc);
420}
421
422/* ProcessHTTPPOST_upnphttp()
423 * executes the SOAP query if it is possible */
424static void ProcessHTTPPOST_upnphttp(struct upnphttp * h)
425{
426 if((h->req_buflen - h->req_contentoff) >= h->req_contentlen)
427 {
428 if(h->req_soapAction)
429 {
430 /* we can process the request */
431 syslog(LOG_INFO, "SOAPAction: %.*s",
432 h->req_soapActionLen, h->req_soapAction);
433 ExecuteSoapAction(h,
434 h->req_soapAction,
435 h->req_soapActionLen);
436 }
437 else
438 {
439 static const char err400str[] =
440 "<html><body>Bad request</body></html>";
441 syslog(LOG_INFO, "No SOAPAction in HTTP headers");
442 BuildResp2_upnphttp(h, 400, "Bad Request",
443 err400str, sizeof(err400str) - 1);
444 SendResp_upnphttp(h);
445 CloseSocket_upnphttp(h);
446 }
447 }
448 else
449 {
450 /* waiting for remaining data */
451 h->state = 1;
452 }
453}
454
455Upnp_Document CreatePropertySet(void)
456{
457 Upnp_Document PropSet=NULL;
458
459 PropSet = (Upnp_Document) malloc(sizeof(Upnp_Document_CTX));
460 if (PropSet == NULL) {
461 syslog(LOG_ERR, "CreatePropertySet: out of memory!");
462 return NULL;
463 }
464 memset(PropSet, 0, sizeof(Upnp_Document_CTX));
465 LIST_INIT(&PropSet->doc_head);
466 return PropSet;
467}
468
469int UpnpAddToPropertySet(Upnp_Document PropSet,
470 const char *VarName, const char *message)
471{
472 struct Upnp_Document_element *tmp=NULL;
473 char *name=NULL;
474 char *content=NULL;
475
476 if (PropSet == NULL || VarName == NULL || message == NULL)
477 return UPNP_E_INVALID_PARAM;
478
479 tmp = (struct Upnp_Document_element *) malloc(sizeof(struct Upnp_Document_element));
480 if (tmp == NULL) {
481 syslog(LOG_ERR, "UpnpAddToPropertySet: out of memory!");
482 return UPNP_E_OUTOF_MEMORY;
483 }
484 memset(tmp, 0, sizeof(struct Upnp_Document_element));
485
486 name = (char *) malloc(strlen(VarName) + 1);
487 if (name == NULL) {
488 syslog(LOG_ERR, "UpnpAddToPropertySet: out of memory!");
489 free(tmp);
490 return UPNP_E_OUTOF_MEMORY;
491 }
492 memset(name, 0, strlen(VarName) + 1);
493 memcpy(name, VarName, strlen(VarName));
494
495 content = (char *) malloc(strlen(message) + 1);
496 if (content == NULL) {
497 syslog(LOG_ERR, "UpnpAddToPropertySet: out of memory!");
498 free(tmp);
499 free(name);
500 return UPNP_E_OUTOF_MEMORY;
501 }
502 memset(content, 0, strlen(message) + 1);
503 memcpy(content, message, strlen(message));
504
505 PropSet->NumOfVarName += 1;
506 PropSet->TotalMessageLen = strlen(message) + (strlen(VarName) * 2);
507 tmp->VarName = name;
508 tmp->message = content;
509 LIST_INSERT_HEAD(&PropSet->doc_head, tmp, entries);
510
511 return UPNP_E_SUCCESS;
512}
513
514static char *MakeEventBody(Upnp_Document PropSet, unsigned int *total_len)
515{
516 unsigned int len=0;
517 char *buf=NULL;
518 unsigned int buf_len=0;
519 struct Upnp_Document_element *e;
520
521 if (PropSet == NULL || PropSet->NumOfVarName == 0)
522 return NULL;
523
524 buf_len = (strlen("<e:property><></></e:property>") * PropSet->NumOfVarName)
525 + PropSet->TotalMessageLen + 100;
526 buf = (char *) malloc(buf_len);
527 if (buf == NULL) {
528 syslog(LOG_ERR, "MakeEventBody: out of memory!");
529 return NULL;
530 }
531 memset(buf, 0, buf_len);
532
533 for(e = PropSet->doc_head.lh_first; e != NULL; e = e->entries.le_next)
534 {
535 if (e->VarName) {
536 char *tmpbuf=NULL;
537 unsigned int tmpbuf_len=0;
538 unsigned int propertyLen=0;
539
540 tmpbuf_len = strlen("<e:property><></></e:property>")
541 + (strlen(e->VarName) * 2)
542 + strlen(e->message) + 1;
543 tmpbuf = (char *) malloc(tmpbuf_len);
544 if (tmpbuf == NULL) {
545 syslog(LOG_ERR, "MakeEventBody: out of memory!");
546 free(buf);
547 return NULL;
548 }
549 memset(tmpbuf, 0, tmpbuf_len);
550 propertyLen = sprintf(tmpbuf,
551 "<e:property><%s>%s</%s></e:property>",
552 e->VarName, e->message, e->VarName);
553 len += propertyLen;
554 strcat(buf, tmpbuf);
555 free(tmpbuf);
556 }
557 }
558
559 *total_len = len;
560 return buf;
561}
562
563static void UpnpSendEvent(char *packet,
564 const char *EventBody, const unsigned int bodylength,
565 struct upnp_subscription_record *subscribe_list,
566 struct upnp_subscription_element *sub)
567{
568 unsigned int packetLength;
569 struct sockaddr_in dest;
570 int n, sockfd=-1;
571 struct EvtRespElement *EvtResp=NULL;
572
573 if (packet == NULL || EventBody == NULL || bodylength == 0 ||
574 subscribe_list == NULL || sub == NULL)
575 return;
576
577 packetLength = sprintf(packet,
578 "NOTIFY %s HTTP/1.1\r\n"
579 "SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
580 "HOST: %s:%d\r\n"
581 "Content-Type: text/xml; charset=\"utf-8\"\r\n"
582 "NT: upnp:event\r\n"
583 "NTS: upnp:propchange\r\n"
584 "SID: %s\r\n"
585 "SEQ: %d\r\n"
586 "Content-Length: %d\r\n\r\n"
587 "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
588 "<e:propertyset xmlns:e=\"urn:schemas-upnp-org:event-1-0\">"
589 "%s"
590 "</e:propertyset>",
591 sub->callback_url,
592 sub->IP,
593 sub->port,
594 sub->sid,
595 (int)sub->seq,
596 bodylength+110,
597 EventBody);
598
599 sub->seq++;
600 if (sub->seq >= UINT_MAX)
601 sub->seq = 1;
602 //printf("Packet------------>\n%s\n<-----------------Packet\n\n", packet);
603
604 memset(&dest,0,sizeof(struct sockaddr_in));
605 dest.sin_addr.s_addr = sub->IP_inet_addr;
606 dest.sin_port = htons(sub->port);
607 dest.sin_family = AF_INET;
608
609 // create a socket
610 if ((sockfd = socket( AF_INET, SOCK_STREAM, 0 )) == -1) {
611 syslog(LOG_ERR, "UpnpSendEvent: creating a socket falied!");
612 return;
613 }
614 if (connect( sockfd, ( struct sockaddr * )&dest,
615 sizeof( struct sockaddr_in ) ) == -1) {
616 syslog(LOG_ERR, "UpnpSendEvent: connecting a socket falied!");
617 close(sockfd);
618 return;
619 }
620
621 n = ReliableSend(sockfd, packet, packetLength);
622 if (n != packetLength)
623 {
624 syslog(LOG_ERR, "UpnpSendEvent: %d bytes sent (out of %d)",
625 n, packetLength);
626 close(sockfd);
627 return;
628 }
629
630 EvtResp = (struct EvtRespElement *) malloc(sizeof(struct EvtRespElement));
631 if (EvtResp == NULL) {
632 syslog(LOG_ERR, "UpnpSendEvent: out of memory!");
633 close(sockfd);
634 return;
635 }
636 memset(EvtResp, 0, sizeof(struct EvtRespElement));
637 EvtResp->socket = sockfd;
638 memcpy(EvtResp->sid, sub->sid, strlen(sub->sid));
639 EvtResp->TimeOut = 30;
640 LIST_INSERT_HEAD(&subscribe_list->EvtResp_head, EvtResp, entries);
641}
642
643void UpnpSendEventSingle(Upnp_Document PropSet,
644 struct upnp_subscription_record *subscribe_list,
645 struct upnp_subscription_element *sub)
646{
647 char *packet=NULL;
648 unsigned int bodylength=0;
649 char *EventBody=NULL;
650
651 if (PropSet == NULL || sub == NULL || subscribe_list == NULL ||
652 subscribe_list->subscription_head.lh_first == NULL)
653 return;
654
655 EventBody = MakeEventBody(PropSet, &bodylength);
656 if (EventBody == NULL) {
657 syslog(LOG_ERR, "UpnpSendEventSingle: MakeEventBody failed!");
658 return;
659 }
660
661 packet = (char *) malloc(bodylength + 483);
662 if (packet == NULL) {
663 syslog(LOG_ERR, "UpnpSendEventSingle: out of memory!");
664 free(EventBody);
665 return;
666 }
667 memset(packet, 0, bodylength + 483);
668
669 UpnpSendEvent(packet, EventBody, bodylength, subscribe_list, sub);
670 free(EventBody);
671 free(packet);
672}
673
674void ProcessEventingResp(struct EvtRespElement *EvtResp)
675{
676 char *buf=NULL;
677 int n;
678
679 if (EvtResp == NULL)
680 return;
681
682 buf = (char *) malloc(512);
683 if (buf == NULL) {
684 close(EvtResp->socket);
685 return;
686 }
687 memset(buf, 0, 512);
688
689 if ((n = recv(EvtResp->socket, buf, 512, 0)) == -1) {
690 syslog(LOG_ERR, "ProcessEventingResp: Receive failed!");
691 }
692 else if(n==0)
693 {
694 syslog(LOG_WARNING, "ProcessEventingResp: connection closed inexpectedly");
695 }
696
697 //printf("------------>\nProcessEventingResp: sid[%s]\n%s\n<--------------\n", EvtResp->sid, buf);
698 close(EvtResp->socket);
699 free(buf);
700}
701
702void UpnpSendEventAll(Upnp_Document PropSet,
703 struct upnp_subscription_record *sub_list)
704{
705 struct upnp_subscription_element *sub;
706 unsigned int bodylength=0;
707 char *EventBody=NULL;
708 char *packet=NULL;
709
710 if (PropSet == NULL || sub_list == NULL || sub_list->subscription_head.lh_first == NULL)
711 return;
712
713 EventBody = MakeEventBody(PropSet, &bodylength);
714 if (EventBody == NULL) {
715 syslog(LOG_ERR, "UpnpSendEventAll: MakeEventBody failed!");
716 return;
717 }
718
719 packet = (char *) malloc(bodylength + 483);
720 if (packet == NULL) {
721 syslog(LOG_ERR, "UpnpSendEventAll: out of memory!");
722 free(EventBody);
723 return;
724 }
725
726 for (sub = sub_list->subscription_head.lh_first; sub != NULL; sub = sub->entries.le_next)
727 {
728 memset(packet, 0, bodylength + 483);
729 UpnpSendEvent(packet, EventBody, bodylength, sub_list, sub);
730 }
731 free(EventBody);
732 free(packet);
733}
734
735void UpnpDocument_free(Upnp_Document PropSet)
736{
737 struct Upnp_Document_element *e;
738 struct Upnp_Document_element *next;
739
740 if (PropSet == NULL)
741 return;
742
743 for(e = PropSet->doc_head.lh_first; e != NULL; )
744 {
745 next = e->entries.le_next;
746 if (e->VarName)
747 free(e->VarName);
748 if (e->message)
749 free(e->message);
750 LIST_REMOVE(e, entries);
751 free(e);
752 e = next;
753 }
754
755 free(PropSet);
756}
757
758static int BuildSubscribeResponse(struct upnphttp * h, struct process_upnp_subscription *sub)
759{
760 char *Subresp=NULL;
761 int n, packet_len, ret=UPNP_E_SUCCESS;
762
763 Subresp = (char *) malloc(300);
764 if (Subresp == NULL) {
765 syslog(LOG_ERR, "BuildSubscribeResponse: out of memory!");
766 return UPNP_E_OUTOF_MEMORY;
767 }
768 memset(Subresp, 0, 300);
769
770 packet_len = sprintf(Subresp,
771 "HTTP/1.1 200 OK \r\n"
772 "Server: " MINIUPNPD_SERVER_STRING "\r\n"
773 "SID: %s\r\n"
774 "TIMEOUT: Second-%d\r\n"
775 "Content-Length: 0\r\n"
776 "\r\n",
777 sub->sid, (int)h->subscribe_list->max_subscription_time);
778
779 //printf("BuildSubscribeResponse------->\n%s<------------BuildSubscribeResponse\n", Subresp);
780
781 n = ReliableSend(h->socket, Subresp, packet_len);
782 if (n != packet_len)
783 {
784 syslog(LOG_ERR, "BuildSubscribeResponse: %d bytes sent (out of %d)",
785 n, packet_len);
786 }
787
788 free(Subresp);
789 CloseSocket_upnphttp(h);
790 return ret;
791}
792
793static void BuildUnSubscribeResponse(struct upnphttp * h)
794{
795 static const char UnSubresp[] =
796 "HTTP/1.1 200 OK \r\n"
797 "Content-Length: 0\r\n"
798 "\r\n";
799
800 int n;
801
802 n = ReliableSend(h->socket, UnSubresp, sizeof(UnSubresp) - 1);
803 if (n != (sizeof(UnSubresp) - 1))
804 {
805 syslog(LOG_ERR, "BuildUnSubscribeResponse: %d bytes sent (out of %d)",
806 n, (sizeof(UnSubresp) - 1));
807 }
808 CloseSocket_upnphttp(h);
809}
810
811static struct upnp_subscription_element *UPnPTryToSubscribe
812 (struct upnphttp * h, struct process_upnp_subscription *sub)
813{
814 int SIDNumber,rnumber;
815 char *SID=NULL;
816 struct upnp_subscription_element *new_sub=NULL;
817
818 if (h == NULL || sub == NULL)
819 return NULL;
820
821 if (h->subscribe_list->total_subscription >= h->subscribe_list->max_subscription_num)
822 return NULL;
823
824 new_sub = (struct upnp_subscription_element *) malloc(sizeof(struct upnp_subscription_element));
825 if (new_sub == NULL)
826 return NULL;
827 memset(new_sub, 0, sizeof(struct upnp_subscription_element));
828
829 //
830 // The SID must be globally unique, so lets generate it using
831 // a bunch of random hex characters
832 //
833 SID = (char*)malloc(SID_LEN);
834 if (SID == NULL) {
835 free(new_sub);
836 return NULL;
837 }
838 memset(SID,0,SID_LEN);
839 sprintf(SID,"uuid:");
840 for(SIDNumber=5;SIDNumber<=12;++SIDNumber)
841 {
842 rnumber = rand()%16;
843 sprintf(SID+SIDNumber,"%x",rnumber);
844 }
845 sprintf(SID+SIDNumber,"-");
846 for(SIDNumber=14;SIDNumber<=17;++SIDNumber)
847 {
848 rnumber = rand()%16;
849 sprintf(SID+SIDNumber,"%x",rnumber);
850 }
851 sprintf(SID+SIDNumber,"-");
852 for(SIDNumber=19;SIDNumber<=22;++SIDNumber)
853 {
854 rnumber = rand()%16;
855 sprintf(SID+SIDNumber,"%x",rnumber);
856 }
857 sprintf(SID+SIDNumber,"-");
858 for(SIDNumber=24;SIDNumber<=27;++SIDNumber)
859 {
860 rnumber = rand()%16;
861 sprintf(SID+SIDNumber,"%x",rnumber);
862 }
863 sprintf(SID+SIDNumber,"-");
864 for(SIDNumber=29;SIDNumber<=40;++SIDNumber)
865 {
866 rnumber = rand()%16;
867 sprintf(SID+SIDNumber,"%x",rnumber);
868 }
869
870 memcpy(sub->sid, SID, SID_LEN);
871 if (BuildSubscribeResponse(h, sub) != UPNP_E_SUCCESS) {
872 free(SID);
873 free(new_sub);
874 return NULL;
875 }
876
877 memcpy(new_sub->IP, sub->IP, IP_ADDRLEN);
878 new_sub->IP_inet_addr = sub->IP_inet_addr;
879 new_sub->port = sub->port;
880 memcpy(new_sub->sid, SID, SID_LEN);
881 memcpy(new_sub->callback_url, sub->callback_url, URL_MAX_LEN);
882 new_sub->TimeOut = sub->TimeOut;
883//WPS2DOTX
884// new_sub->subscription_timeout = h->subscribe_list->subscription_timeout;
885 new_sub->subscription_timeout = sub->TimeOut;
886
887// printf("\n\nsubscription_timeout=%d\n",new_sub->subscription_timeout);
888
889 new_sub->eventID = UPNP_EVENT_SUBSCRIPTION_REQUEST;
890 LIST_INSERT_HEAD(&h->subscribe_list->subscription_head, new_sub, entries);
891 h->subscribe_list->total_subscription++;
892 syslog(LOG_INFO, "Subscribe: total_subscription [%d]",
893 (int)h->subscribe_list->total_subscription);
894
895 free(SID);
896 return new_sub;
897}
898
899static char *GetTokenValue(const unsigned long buf, const unsigned long len, unsigned int *Value_len)
900{
901 unsigned long start=0, end=0;
902 unsigned long buffer_end;
903 char *line;
904
905 if (len == 0)
906 return NULL;
907
908 line = (char *)buf;
909 buffer_end = (unsigned long)line + len;
910
911 while ((unsigned long)line < buffer_end) {
912 if ((*line == ' ') || (*line == ':') || (*line == '-'))
913 line++;
914 else {
915 start = (unsigned long)line;
916 break;
917 }
918 }
919 if (start == 0) {
920 *Value_len = 0;
921 return NULL;
922 }
923
924 while ((unsigned long)line < buffer_end) {
925 if ((*line == ' ') || (*line == '\r') || (*line == '\n')) {
926 end = (unsigned long)line;
927 break;
928 }
929 else
930 line++;
931 }
932 if (end == 0) {
933 *Value_len = 0;
934 return NULL;
935 }
936
937 *Value_len = (unsigned int)(end - start);
938 return (char *)start;
939}
940
941static __inline__ void GetLineLen(const unsigned long buf, unsigned int *line_len)
942{
943 unsigned long start=0;
944 const unsigned short MaxCharsPerLine = 1000;
945 unsigned short NumChars=0;
946 char *line;
947
948 line = (char *)buf;
949 start = (unsigned long)line;
950 while (*line != '\n') {
951 NumChars++;
952 if (NumChars >= MaxCharsPerLine) {
953 syslog(LOG_WARNING, "Too many characters in a line!");
954 *line_len = 0;
955 return;
956 }
957 line++;
958 }
959
960 *line_len = (unsigned long)line + 1 - start;
961 return;
962}
963
964
965// To do : support IPv6
966static __inline__ int GetIPandPortandCallBack(const unsigned long buf, const unsigned int buf_len,
967 struct process_upnp_subscription *sub)
968{
969 char *line=NULL;
970 unsigned long buffer_end=0;
971 unsigned char dot_count=0;
972 unsigned long start=0;
973 unsigned long end=0;
974 unsigned char GotIPandPort=0;
975
976 line = (char *)buf;
977 buffer_end = (unsigned long)line + buf_len;
978 while ((unsigned long)line < buffer_end) {
979 if (*line == ' ') {
980 line++;
981 continue;
982 }
983 if (strncasecmp("<http://", line, 8) != 0)
984 return UPNP_E_INVALID_PARAM;
985 else
986 break;
987 }
988
989 line += 8;
990 start =(unsigned long) line;
991 while ((unsigned long)line < buffer_end) {
992 if (*line == '.')
993 dot_count++;
994 if ((*line == ':') || (*line == '/')) {
995 if (dot_count != IP_V4_DOT_COUNT)
996 return UPNP_E_INVALID_PARAM;
997 memcpy(sub->IP, (char *)start, (unsigned long)line-start);
998 if ((sub->IP_inet_addr = inet_addr(sub->IP)) == -1)
999 return UPNP_E_INVALID_PARAM;
1000 break;
1001 }
1002 line++;
1003 }
1004
1005 if (*line == '/') {
1006 sub->port = 80;
1007 GotIPandPort = 1;
1008 start = (unsigned long)line;
1009 end = 0;
1010 goto get_callback;
1011 }
1012
1013 line += 1;
1014 start = (unsigned long)line;
1015 while ((unsigned long)line < buffer_end) {
1016 if (*line == '/') {
1017 end = (unsigned long)line;
1018 if (end <= start)
1019 return UPNP_E_INVALID_PARAM;
1020 else {
1021 char port[10];
1022 memset(port, 0, 10);
1023 memcpy(port, (char *)start, end-start);
1024 sub->port = atoi(port);
1025 GotIPandPort = 1;
1026 start = (unsigned long)line;
1027 end = 0;
1028 break;
1029 }
1030 }
1031 line++;
1032 }
1033
1034get_callback:
1035 if (!GotIPandPort)
1036 return UPNP_E_INVALID_PARAM;
1037 while ((unsigned long)line < buffer_end) {
1038 if (*line == '>') {
1039 end = (unsigned long)line;
1040 if (end <= start)
1041 return UPNP_E_INVALID_PARAM;
1042 else {
1043 memcpy(sub->callback_url, (char *)start, end-start);
1044 return UPNP_E_SUCCESS;
1045 }
1046 }
1047 line++;
1048 }
1049
1050 return UPNP_E_INVALID_PARAM;
1051}
1052
1053static int ParseSUBSCRIBEPacket(struct upnphttp * h,
1054 struct process_upnp_subscription *sub)
1055{
1056 char *line=NULL, *value=NULL, *tmp=NULL;
1057 unsigned int line_len=0, value_len=0, tmp_len=0;
1058 unsigned long buffer_end=0;
1059
1060 if (h->req_buf == NULL || h->req_contentoff == 0)
1061 return UPNP_E_INVALID_PARAM;
1062
1063 line = h->req_buf;
1064 buffer_end = (unsigned long)h->req_buf + h->req_contentoff;
1065 while ((unsigned long)line < buffer_end) {
1066 if (*line == ' ') {
1067 line++;
1068 continue;
1069 }
1070 GetLineLen((const unsigned long)line, &line_len);
1071 if (line_len == 0)
1072 return UPNP_E_INVALID_PARAM;
1073 else if (line_len > 2) {
1074 if (strncasecmp("SUBSCRIBE", line, 9) == 0) {
1075 value = GetTokenValue((const unsigned long)line+9, line_len-9, &value_len);
1076 if (value == NULL || value_len == 0)
1077 return UPNP_E_INVALID_PARAM;
1078
1079 if (strncasecmp(h->subscribe_list->event_url, value, value_len) != 0) {
1080 syslog(LOG_WARNING, "SUBSCRIBE event url mismatched!");
1081 return UPNP_E_INVALID_PARAM;
1082 }
1083 }
1084 else if (strncasecmp("UNSUBSCRIBE", line, 11) == 0) {
1085 value = GetTokenValue((const unsigned long)line+11, line_len-11, &value_len);
1086 if (value == NULL || value_len == 0)
1087 return UPNP_E_INVALID_PARAM;
1088
1089 if (strncasecmp(h->subscribe_list->event_url, value, value_len) != 0) {
1090 syslog(LOG_WARNING, "UNSUBSCRIBE event url mismatched!");
1091 return UPNP_E_INVALID_PARAM;
1092 }
1093 }
1094 else if (strncasecmp("Host", line, 4) == 0) {
1095 value = GetTokenValue((const unsigned long)line+4, line_len-4, &value_len);
1096 if (value == NULL || value_len == 0)
1097 return UPNP_E_INVALID_PARAM;
1098
1099 char host_info[30];
1100 memset(host_info, 0, 30);
1101 sprintf(host_info, "%s:%d", h->subscribe_list->my_IP, h->subscribe_list->my_port);
1102 if (strncmp(value, host_info, value_len) != 0) {
1103 syslog(LOG_WARNING, "Wrong host [%s]", host_info);
1104 return UPNP_E_INVALID_PARAM;
1105 }
1106 }
1107 else if (strncasecmp("Callback", line, 8) == 0) {
1108 value = GetTokenValue((const unsigned long)line+8, line_len-8, &value_len);
1109 if (value == NULL || value_len == 0 || (value_len > (URL_MAX_LEN-1)))
1110 return UPNP_E_INVALID_PARAM;
1111
1112 if (GetIPandPortandCallBack((const unsigned long) value, value_len, sub) != UPNP_E_SUCCESS)
1113 return UPNP_E_INVALID_PARAM;
1114 }
1115 else if (strncasecmp("Timeout", line, 7) == 0) {
1116 value = GetTokenValue((const unsigned long)line+7, line_len-7, &value_len);
1117 if (value == NULL || value_len == 0 || value_len < 8)
1118 return UPNP_E_INVALID_PARAM;
1119
1120 if (strncasecmp("Second", value, 6) != 0)
1121 return UPNP_E_INVALID_PARAM;
1122 tmp = value + 6;
1123 tmp_len = value_len - 6;
1124 value = GetTokenValue((const unsigned long)tmp, tmp_len+1, &value_len);
1125 if (value_len == 0)
1126 return UPNP_E_INVALID_PARAM;
1127 else if (value_len == 8 && (strncasecmp("infinite", line, 8) == 0))
1128 sub->TimeOut = MAX_SUB_TIMEOUT;
1129 else {
1130 if (value_len > 4)
1131 sub->TimeOut = MAX_SUB_TIMEOUT;
1132 else {
1133 char time_out[5];
1134 memset(time_out, 0, 5);
1135 memcpy(time_out, value, value_len);
1136 sub->TimeOut = atoi(time_out);
1137 }
1138 }
1139 }
1140 else if (strncasecmp("SID", line, 3) == 0) {
1141 value = GetTokenValue((const unsigned long)line+3, line_len-3, &value_len);
1142 if (value == NULL || value_len == 0 || value_len < 4)
1143 return UPNP_E_INVALID_PARAM;
1144
1145 if (strncasecmp("uuid", value, 4) != 0)
1146 return UPNP_E_INVALID_PARAM;
1147 tmp = value + 4;
1148 tmp_len = value_len - 4;
1149 value = GetTokenValue((const unsigned long)tmp, tmp_len+1, &value_len);
1150 if (value == NULL || value_len == 0 || value_len != 36)
1151 return UPNP_E_INVALID_PARAM;
1152
1153 char sid[SID_LEN];
1154 memset(sid, 0, SID_LEN);
1155 memcpy(sub->sid, "uuid:", 5);
1156 memcpy(sub->sid+5, value, value_len);
1157 }
1158 }
1159
1160 line += line_len;
1161 }
1162
1163 return UPNP_E_SUCCESS;
1164}
1165
1166static void UPnPProcessSUBSCRIBE(struct upnphttp * h)
1167{
1168 struct process_upnp_subscription sub;
1169 struct upnp_subscription_element *new_sub=NULL;
1170 int ret;
1171
1172 memset(&sub, 0, sizeof(struct process_upnp_subscription));
1173 ret = ParseSUBSCRIBEPacket(h, &sub);
1174 if (ret != UPNP_E_SUCCESS) {
1175 Send412PreconditionFailed(h);
1176 return;
1177 }
1178 else {
1179#ifdef DEBUG
1180 printf("IP [%s]\n", sub.IP);
1181 printf("Host [%d.%d.%d.%d:%d]\n", (sub.IP_inet_addr>>24)&0xFF,
1182 (sub.IP_inet_addr>>16)&0xFF,
1183 (sub.IP_inet_addr>>8)&0xFF,
1184 (sub.IP_inet_addr)&0xFF, sub.port);
1185 printf("SID [%s]\n", sub.sid);
1186 printf("CallBack %s\n", sub.callback_url);
1187 printf("Timeout [%d]\n", (int)sub.TimeOut);
1188#endif
1189
1190 if (sub.TimeOut == 0)
1191 sub.TimeOut = MAX_SUB_TIMEOUT;
1192
1193 if (sub.sid[0] == 0)
1194 { //Subscribe
1195 if (sub.callback_url[0] == 0) {
1196 Send412PreconditionFailed(h);
1197 return;
1198 }
1199
1200 new_sub = UPnPTryToSubscribe(h, &sub);
1201 if (new_sub == NULL) {
1202 Send412TooManySubscribers(h);
1203 return;
1204 }
1205
1206 if (h->subscribe_list->EventCallBack)
1207 h->subscribe_list->EventCallBack(new_sub);
1208 }
1209 else
1210 { // Renewal subscription
1211 struct upnp_subscription_element *e;
1212 struct upnp_subscription_element *next;
1213 unsigned char count=0;
1214
1215 for(e = h->subscribe_list->subscription_head.lh_first; e != NULL; )
1216 {
1217 next = e->entries.le_next;
1218 if(strcmp(e->sid, sub.sid) == 0)
1219 {
1220 count++;
1221 if (BuildSubscribeResponse(h, &sub) != UPNP_E_SUCCESS) {
1222 LIST_REMOVE(e, entries);
1223 h->subscribe_list->total_subscription--;
1224 free(e);
1225 syslog(LOG_ERR, "UPnPProcessSUBSCRIBE : renew failed!");
1226 return;
1227 }
1228 else {
1229 //WPS2DOTX
1230 //e->subscription_timeout = h->subscribe_list->subscription_timeout;
1231 e->subscription_timeout = (int)sub.TimeOut;
1232
1233 e->eventID = UPNP_EVENT_RENEWAL_COMPLETE;
1234 }
1235 syslog(LOG_INFO, "Renewal subscription: total_subscription [%d]",
1236 (int)h->subscribe_list->total_subscription);
1237 if (h->subscribe_list->EventCallBack){
1238 h->subscribe_list->EventCallBack(e);
1239 if(e->wscdReNewState == 1){
1240 Send412PreconditionFailed(h);
1241 e->wscdReNewState = 0;
1242 }
1243 }
1244 }
1245 e = next;
1246 }
1247 if (count == 0) {
1248 Send412PreconditionFailed(h);
1249 syslog(LOG_ERR, "UPnPProcessSUBSCRIBE[renew] : Could not find the sid[%s]!", sub.sid);
1250 if (new_sub == NULL) {
1251 new_sub = (struct upnp_subscription_element *)malloc(sizeof(struct upnp_subscription_element));
1252 if (new_sub == NULL)
1253 return;
1254 memset(new_sub, 0, sizeof(struct upnp_subscription_element));
1255 new_sub->eventID = UPNP_EVENT_RENEWAL_COMPLETE;
1256 memcpy(new_sub->sid, sub.sid, strlen(sub.sid));
1257 if (h->subscribe_list->EventCallBack)
1258 h->subscribe_list->EventCallBack(new_sub);
1259 free(new_sub);
1260 }
1261 else
1262 syslog(LOG_ERR, "UPnPProcessSUBSCRIBE[renew] : Could not allocate buffer for new_sub!");
1263 }
1264 }
1265 }
1266}
1267
1268static void UPnPProcessUNSUBSCRIBE(struct upnphttp * h)
1269{
1270 struct process_upnp_subscription sub;
1271 struct upnp_subscription_element *e;
1272 struct upnp_subscription_element *next;
1273 int ret;
1274 unsigned char count=0;
1275
1276 memset(&sub, 0, sizeof(struct process_upnp_subscription));
1277 ret = ParseSUBSCRIBEPacket(h, &sub);
1278 if (ret != UPNP_E_SUCCESS) {
1279 Send412PreconditionFailed(h);
1280 return;
1281 }
1282 else {
1283#ifdef DEBUG
1284 printf("IP [%s]\n", sub.IP);
1285 printf("Host [%d.%d.%d.%d:%d]\n", (sub.IP_inet_addr>>24)&0xFF,
1286 (sub.IP_inet_addr>>16)&0xFF,
1287 (sub.IP_inet_addr>>8)&0xFF,
1288 (sub.IP_inet_addr)&0xFF, sub.port);
1289 printf("SID [%s]\n", sub.sid);
1290 printf("CallBack %s\n", sub.callback_url);
1291 printf("Timeout [%d]\n", (int)sub.TimeOut);
1292#endif
1293
1294 if (sub.sid[0] == 0) {
1295 Send412PreconditionFailed(h);
1296 return;
1297 }
1298
1299 for(e = h->subscribe_list->subscription_head.lh_first; e != NULL; )
1300 {
1301 next = e->entries.le_next;
1302 if(strcmp(e->sid, sub.sid) == 0)
1303 {
1304 count++;
1305 LIST_REMOVE(e, entries);
1306 BuildUnSubscribeResponse(h);
1307 h->subscribe_list->total_subscription--;
1308 syslog(LOG_INFO, "UNSUBSCRIBE: total_subscription [%d]",
1309 (int)h->subscribe_list->total_subscription);
1310
1311 e->eventID = UPNP_EVENT_UNSUBSCRIBE_COMPLETE;
1312 if (h->subscribe_list->EventCallBack)
1313 h->subscribe_list->EventCallBack(e);
1314 free(e);
1315 }
1316 e = next;
1317 }
1318
1319 if (count == 0) {
1320 BuildUnSubscribeResponse(h);
1321 syslog(LOG_ERR, "UPnPProcessUNSUBSCRIBE : Could not find the sid!");
1322 }
1323 }
1324}
1325
1326/* Parse and process Http Query
1327 * called once all the HTTP headers have been received. */
1328static void ProcessHttpQuery_upnphttp(struct upnphttp * h)
1329{
1330 char HttpCommand[16];
1331 char HttpUrl[128];
1332 char * HttpVer;
1333 char * p;
1334 int i;
1335 p = h->req_buf;
1336 if(!p)
1337 return;
1338 for(i = 0; i<15 && *p != ' ' && *p != '\r'; i++)
1339 HttpCommand[i] = *(p++);
1340 HttpCommand[i] = '\0';
1341 while(*p==' ')
1342 p++;
1343 for(i = 0; i<127 && *p != ' ' && *p != '\r'; i++)
1344 HttpUrl[i] = *(p++);
1345 HttpUrl[i] = '\0';
1346 while(*p==' ')
1347 p++;
1348 HttpVer = h->HttpVer;
1349 for(i = 0; i<15 && *p != '\r'; i++)
1350 HttpVer[i] = *(p++);
1351 HttpVer[i] = '\0';
1352 syslog(LOG_INFO, "HTTP REQUEST : %s %s (%s)",
1353 HttpCommand, HttpUrl, HttpVer);
1354 ParseHttpHeaders(h);
1355 if(strcmp("POST", HttpCommand) == 0)
1356 {
1357 h->req_command = EPost;
1358 ProcessHTTPPOST_upnphttp(h);
1359 }
1360 else if(strcmp("GET", HttpCommand) == 0)
1361 {
1362 h->req_command = EGet;
1363
1364 if (strncasecmp((char *)h->req_buf, "GET /HNAP", 9) == 0) {
1365 i = 0;
1366 int len;
1367 while(h->soapMethods[i].methodName)
1368 {
1369 len = strlen(h->soapMethods[i].methodName);
1370 if(strncmp("GetDeviceSettings", h->soapMethods[i].methodName, len) == 0)
1371 {
1372 h->soapMethods[i].methodImpl(h);
1373 return;
1374 }
1375 i++;
1376 }
1377 syslog(LOG_NOTICE, "%s not found, responding ERROR 404", HttpUrl);
1378 Send404(h);
1379 return;
1380 }
1381 i = 0;
1382 if (h->sendDesc) {
1383 while(h->sendDesc[i].DescName)
1384 {
1385 if(strcmp(h->sendDesc[i].DescName, HttpUrl) == 0)
1386 {
1387 sendXMLdesc(h, h->sendDesc[i].sendDescImpl);
1388 return;
1389 }
1390 i++;
1391 }
1392 }
1393
1394 syslog(LOG_NOTICE, "%s not found, responding ERROR 404", HttpUrl);
1395 Send404(h);
1396 }
1397 else if(strcmp("SUBSCRIBE", HttpCommand) == 0)
1398 {
1399 //printf("<<--------------------\n%s\n------------------->>\n", h->req_buf);
1400 UPnPProcessSUBSCRIBE(h);
1401 }
1402 else if(strcmp("UNSUBSCRIBE", HttpCommand) == 0)
1403 {
1404 //printf("<<--------------------\n%s\n------------------->>\n", h->req_buf);
1405 UPnPProcessUNSUBSCRIBE(h);
1406 }
1407 else
1408 {
1409 syslog(LOG_NOTICE, "Unsupported HTTP Command %s", HttpCommand);
1410 Send501(h);
1411 }
1412}
1413
1414
1415void Process_upnphttp(struct upnphttp * h)
1416{
1417 char *buf=NULL;
1418 int n;
1419
1420 if(!h)
1421 return;
1422
1423 buf = (char *) malloc(2048);
1424 if (buf == NULL) {
1425 syslog(LOG_ERR, "Process_upnphttp: out of memory!");
1426 return;
1427 }
1428 memset(buf, 0, 2048);
1429
1430 switch(h->state)
1431 {
1432 case 0:
1433 n = recv(h->socket, buf, 2048, 0);
1434 if(n<0)
1435 {
1436 syslog(LOG_ERR, "recv (state0): %m");
1437 h->state = 100;
1438 }
1439 else if(n==0)
1440 {
1441 syslog(LOG_WARNING, "connection closed inexpectedly");
1442 h->state = 100;
1443 }
1444 else
1445 {
1446 const char * endheaders;
1447 /*printf("== PACKET RECEIVED (%d bytes) ==\n", n);
1448 fwrite(buf, 1, n, stdout); // debug
1449 printf("== END OF PACKET RECEIVED ==\n");*/
1450 /* if 1st arg of realloc() is null,
1451 * realloc behaves the same as malloc() */
1452 //h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen + 1);
1453 h->req_buf = (char *)realloc(h->req_buf, 2048); //Brad modify for HNAP, bug fix
1454 memcpy(h->req_buf + h->req_buflen, buf, n);
1455 h->req_buflen += n;
1456 h->req_buf[h->req_buflen] = '\0';
1457 /* search for the string "\r\n\r\n" */
1458 endheaders = findendheaders(h->req_buf, h->req_buflen);
1459 if(endheaders)
1460 {
1461 h->req_contentoff = endheaders - h->req_buf + 4;
1462 ProcessHttpQuery_upnphttp(h);
1463 }
1464 }
1465 break;
1466 case 1:
1467 n = recv(h->socket, buf, 2048, 0);
1468 if(n<0)
1469 {
1470 syslog(LOG_ERR, "recv (state1): %m");
1471 h->state = 100;
1472 }
1473 else if(n==0)
1474 {
1475 syslog(LOG_WARNING, "connection closed inexpectedly");
1476 h->state = 100;
1477 }
1478 else
1479 {
1480 /*fwrite(buf, 1, n, stdout);*/ /* debug */
1481 h->req_buf = (char *)realloc(h->req_buf, n + h->req_buflen);
1482 memcpy(h->req_buf + h->req_buflen, buf, n);
1483 h->req_buflen += n;
1484 if((h->req_buflen - h->req_contentoff) >= h->req_contentlen)
1485 {
1486 ProcessHTTPPOST_upnphttp(h);
1487 }
1488 }
1489 break;
1490 default:
1491 syslog(LOG_WARNING, "unexpected state (%d)", h->state);
1492 }
1493
1494 free(buf);
1495}
1496
1497static const char httpresphead[] =
1498 "%s %d %s\r\n"
1499 "Content-Type: text/xml; charset=\"utf-8\"\r\n"
1500 "Connection: close\r\n"
1501 "Content-Length: %d\r\n"
1502 "Server: " MINIUPNPD_SERVER_STRING "\r\n"
1503 "Ext:\r\n"
1504 "\r\n";
1505/*
1506 "<?xml version=\"1.0\"?>\n"
1507 "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" "
1508 "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
1509 "<s:Body>"
1510
1511 "</s:Body>"
1512 "</s:Envelope>";
1513*/
1514/* with response code and response message
1515 * also allocate enough memory */
1516void
1517BuildHeader_upnphttp(struct upnphttp * h, int respcode,
1518 const char * respmsg,
1519 int bodylen)
1520{
1521 int templen;
1522 if(!h->res_buf)
1523 {
1524 templen = sizeof(httpresphead) + 64 + bodylen;
1525 h->res_buf = (char *)malloc(templen);
1526 memset(h->res_buf, 0, templen);
1527 h->res_buf_alloclen = templen;
1528 }
1529 h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen,
1530 httpresphead, h->HttpVer,
1531 respcode, respmsg, bodylen);
1532 if(h->res_buf_alloclen < (h->res_buflen + bodylen))
1533 {
1534 h->res_buf = (char *)realloc(h->res_buf, (h->res_buflen + bodylen));
1535 memset(h->res_buf, 0, (h->res_buflen + bodylen));
1536 h->res_buf_alloclen = h->res_buflen + bodylen;
1537 }
1538}
1539
1540void
1541BuildResp2_upnphttp(struct upnphttp * h, int respcode,
1542 const char * respmsg,
1543 const char * body, int bodylen)
1544{
1545 BuildHeader_upnphttp(h, respcode, respmsg, bodylen);
1546 memcpy(h->res_buf + h->res_buflen, body, bodylen);
1547 h->res_buflen += bodylen;
1548}
1549
1550/* responding 200 OK ! */
1551void BuildResp_upnphttp(struct upnphttp * h,
1552 const char * body, int bodylen)
1553{
1554 BuildResp2_upnphttp(h, 200, "OK", body, bodylen);
1555}
1556
1557void SendResp_upnphttp(struct upnphttp * h)
1558{
1559 int n;
1560
1561 n = ReliableSend(h->socket, h->res_buf, h->res_buflen);
1562 if (n != h->res_buflen)
1563 {
1564 syslog(LOG_ERR, "SendResp_upnphttp: %d bytes sent (out of %d)",
1565 n, h->res_buflen);
1566 }
1567}
1568
1569static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1570static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
1571
1572/* encode 3 8-bit binary bytes as 4 '6-bit' characters */
1573static void ILibencodeblock( unsigned char in[3], unsigned char out[4], int len )
1574{
1575 out[0] = cb64[ in[0] >> 2 ];
1576 out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
1577 out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
1578 out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
1579}
1580
1581/*! \fn ILibBase64Encode(unsigned char* input, const int inputlen, unsigned char** output)
1582 \brief Base64 encode a stream adding padding and line breaks as per spec.
1583 \par
1584 \b Note: The encoded stream must be freed
1585 \param input The stream to encode
1586 \param inputlen The length of \a input
1587 \param output The encoded stream
1588 \returns The length of the encoded stream
1589*/
1590int ILibBase64Encode(unsigned char* input, const int inputlen, unsigned char** output)
1591{
1592 unsigned char* out=NULL;
1593 unsigned char* in;
1594
1595 *output = (unsigned char*)malloc(((inputlen * 4) / 3) + 5);
1596 out = *output;
1597 if (out == NULL)
1598 return 0;
1599 in = input;
1600
1601 if (input == NULL || inputlen == 0)
1602 {
1603 *output = NULL;
1604 return 0;
1605 }
1606
1607 while ((in+3) <= (input+inputlen))
1608 {
1609 ILibencodeblock(in, out, 3);
1610 in += 3;
1611 out += 4;
1612 }
1613 if ((input+inputlen)-in == 1)
1614 {
1615 ILibencodeblock(in, out, 1);
1616 out += 4;
1617 }
1618 else
1619 if ((input+inputlen)-in == 2)
1620 {
1621 ILibencodeblock(in, out, 2);
1622 out += 4;
1623 }
1624 *out = 0;
1625
1626 return (int)(out-*output);
1627}
1628
1629/* Decode 4 '6-bit' characters into 3 8-bit binary bytes */
1630static void ILibdecodeblock( unsigned char in[4], unsigned char out[3] )
1631{
1632 out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
1633 out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2);
1634 out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
1635}
1636
1637/*! \fn ILibBase64Decode(unsigned char* input, const int inputlen, unsigned char** output)
1638 \brief Decode a base64 encoded stream discarding padding, line breaks and noise
1639 \par
1640 \b Note: The decoded stream must be freed
1641 \param input The stream to decode
1642 \param inputlen The length of \a input
1643 \param output The decoded stream
1644 \returns The length of the decoded stream
1645*/
1646int ILibBase64Decode(unsigned char* input, const int inputlen, unsigned char** output)
1647{
1648 unsigned char* inptr;
1649 unsigned char* out=NULL;
1650 unsigned char v;
1651 unsigned char in[4];
1652 int i, len;
1653
1654 if (input == NULL || inputlen == 0)
1655 {
1656 *output = NULL;
1657 return 0;
1658 }
1659
1660 *output = (unsigned char*)malloc(((inputlen * 3) / 4) + 4);
1661 out = *output;
1662 if (out == NULL)
1663 return 0;
1664 inptr = input;
1665
1666 while( inptr <= (input+inputlen) )
1667 {
1668 for( len = 0, i = 0; i < 4 && inptr <= (input+inputlen); i++ )
1669 {
1670 v = 0;
1671 while( inptr <= (input+inputlen) && v == 0 ) {
1672 v = (unsigned char) *inptr;
1673 inptr++;
1674 v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
1675 if( v ) {
1676 v = (unsigned char) ((v == '$') ? 0 : v - 61);
1677 }
1678 }
1679 if( inptr <= (input+inputlen) ) {
1680 len++;
1681 if( v ) {
1682 in[ i ] = (unsigned char) (v - 1);
1683 }
1684 }
1685 else {
1686 in[i] = 0;
1687 }
1688 }
1689 if( len )
1690 {
1691 ILibdecodeblock( in, out );
1692 out += len-1;
1693 }
1694 }
1695 *out = 0;
1696 return (int)(out-*output);
1697}
1698
1699int OpenAndConfUNIXSocket(const char *file_path)
1700{
1701 int s, len;
1702 struct sockaddr_un local;
1703
1704 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
1705 perror("UNIXSocket");
1706 return -1;
1707 }
1708
1709 local.sun_family = AF_UNIX;
1710 strcpy(local.sun_path, file_path);
1711 unlink(local.sun_path);
1712 //len = strlen(local.sun_path) + sizeof(local.sun_family);
1713 len = sizeof(struct sockaddr_un);
1714 if (bind(s, (struct sockaddr *)&local, len) == -1) {
1715 perror("UNIXSocket bind");
1716 return -1;
1717 }
1718
1719 if (listen(s, 5) == -1) {
1720 perror("UNIXSocket listen");
1721 return -1;
1722 }
1723
1724 return s;
1725}
1726
1727int CreateUnixSocket(const char *function_name,
1728 const char *file_path,
1729 const int time_out)
1730{
1731 struct sockaddr_un remote;
1732 struct timeval tv;
1733 int len, s;
1734
1735 if (file_path == NULL)
1736 return -1;
1737
1738 if (time_out < 0)
1739 return -1;
1740
1741 // Inter Process Communication
1742 if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
1743 return -1;
1744 }
1745
1746 tv.tv_sec = time_out;
1747 tv.tv_usec = 0;
1748 if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval)) < 0)
1749 {
1750 if (function_name) {
1751 syslog(LOG_WARNING, "%s : setsockopt(unix_socket, SO_RCVTIMEO): %m", function_name);
1752 }
1753 else {
1754 syslog(LOG_WARNING, "setsockopt(unix_socket, SO_RCVTIMEO): %m");
1755 }
1756 }
1757
1758 remote.sun_family = AF_UNIX;
1759 strcpy(remote.sun_path, file_path);
1760 //len = strlen(remote.sun_path) + sizeof(remote.sun_family);
1761 len = sizeof(struct sockaddr_un);
1762 if (connect(s, (struct sockaddr *)&remote, len) == -1) {
1763 close(s);
1764 return -1;
1765 }
1766 return s;
1767}
1768
1769int UnixSocketSendAndReceive(const char *function_name,
1770 const char *file_path,
1771 const int time_out,
1772 const char *in, char *out, const int out_len)
1773{
1774 int s=-1, t, in_len, ret=-1;
1775
1776 if (file_path == NULL || in == NULL || out == NULL || out_len < 1)
1777 return -1;
1778
1779 s = CreateUnixSocket(function_name, file_path, time_out);
1780 if (s == -1) {
1781 if (function_name)
1782 syslog(LOG_ERR, "%s : CreateUnixSocket failed", function_name);
1783 goto finish;
1784 }
1785
1786 in_len = strlen(in);
1787 if (ReliableSend(s, in, in_len) != in_len) {
1788 if (function_name) {
1789 syslog(LOG_ERR, "%s : Unix socket send: %m", function_name);
1790 }
1791 goto finish;
1792 }
1793 if ((t = recv(s, out, out_len, 0)) > 0) {
1794 out[t] = '\0';
1795 ret = 0;
1796 }
1797 else {
1798 if (t < 0) {
1799 if (function_name) {
1800 syslog(LOG_ERR, "%s : Unix socket recv: %m", function_name);
1801 }
1802 }
1803 else {
1804 if (function_name) {
1805 syslog(LOG_WARNING, "%s : Server closed connection: %m", function_name);
1806 }
1807 }
1808 }
1809
1810finish:
1811 if (s >= 0)
1812 close(s);
1813 return ret;
1814}