UPnPsdk 0.1
Universal Plug and Play +, Software Development Kit
 
Loading...
Searching...
No Matches
gena_device.cpp
Go to the documentation of this file.
1/*******************************************************************************
2 *
3 * Copyright (c) 2000-2003 Intel Corporation
4 * All rights reserved.
5 * Copyright (c) 2012 France Telecom All rights reserved.
6 * Copyright (C) 2022+ GPL 3 and higher by Ingo Höft, <Ingo@Hoeft-online.de>
7 * Redistribution only with this Copyright remark. Last modified: 2025-07-16
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * - Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * - Neither name of Intel Corporation nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
25 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
29 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 *
33 ******************************************************************************/
34// Last compare with ./Pupnp source file on 2025-07-16, ver 1.14.21
40#include <assert.h>
41
42#include <gena.hpp>
43#include <httpreadwrite.hpp>
44#include <parsetools.hpp>
45#include <ssdp_common.hpp>
46#include <statcodes.hpp>
47#include <unixutil.hpp>
48#include <upnpapi.hpp>
49#include <uuid.hpp>
51#include <webserver.hpp>
52
54#define STALE_JOBID (INVALID_JOB_ID - 1)
55
57#define PRIzu "zu"
59
60namespace {
61
72 char** names,
74 char** values,
76 int count,
78 DOMString* out) {
79 char* buffer;
80 int counter = 0;
81 size_t size = 0;
82
83 /*size += strlen(XML_VERSION);*/
84 size += strlen(XML_PROPERTYSET_HEADER);
85 size += strlen("</e:propertyset>\n\n");
86 for (counter = 0; counter < count; counter++) {
87 size += strlen("<e:property>\n</e:property>\n");
88 size += 2 * strlen(names[counter]) + strlen(values[counter]) +
89 strlen("<></>\n");
90 }
91
92 size_t buffer_len{size + 1};
93 buffer = (char*)malloc(buffer_len);
94 if (buffer == NULL)
96 memset(buffer, 0, size + 1);
97 /*
98 strcpy(buffer,XML_VERSION);
99 strcat(buffer, XML_PROPERTYSET_HEADER);
100 */
101 strcpy(buffer, XML_PROPERTYSET_HEADER);
102 for (counter = 0; counter < count; counter++) {
103 strcat(buffer, "<e:property>\n");
104 snprintf(&buffer[strlen(buffer)], buffer_len,
105 "<%s>%s</%s>\n</e:property>\n", names[counter],
106 values[counter], names[counter]);
107 }
108 strcat(buffer, "</e:propertyset>\n\n");
109 *out = ixmlCloneDOMString(buffer);
110 free(buffer);
111
112 return XML_SUCCESS;
113}
114
121 void* input) {
123
124 (*p->reference_count)--;
125 if (*p->reference_count == 0) {
126 free(p->headers);
128 free(p->servId);
129 free(p->UDN);
130 free(p->reference_count);
131 }
132 free(p);
133}
134
144 uri_type* destination_url,
146 membuffer* mid_msg,
148 char* propertySet,
150 http_parser_t* response) {
151 uri_type url;
152 SOCKET conn_fd;
153 membuffer start_msg;
154 int ret_code;
155 int err_code;
156 int timeout;
157 SOCKINFO info;
158 const char* CRLF = "\r\n";
159
160 /* connect */
161 UpnpPrintf(UPNP_ALL, GENA, __FILE__, __LINE__, "gena notify to: %.*s\n",
162 (int)destination_url->hostport.text.size,
163 destination_url->hostport.text.buff);
164
165 conn_fd = http_Connect(destination_url, &url);
166 if (conn_fd < 0)
167 /* return UPNP error */
169 ret_code = sock_init(&info, conn_fd);
170 if (ret_code) {
171 sock_destroy(&info, SD_BOTH);
172 return ret_code;
173 }
174 /* make start line and HOST header */
175 membuffer_init(&start_msg);
176 if (http_MakeMessage(&start_msg, 1, 1,
177 "q"
178 "s",
179 HTTPMETHOD_NOTIFY, &url, mid_msg->buf) != 0) {
180 membuffer_destroy(&start_msg);
181 sock_destroy(&info, SD_BOTH);
182 return UPNP_E_OUTOF_MEMORY;
183 }
185 /* send msg (note: end of notification will contain "\r\n" twice) */
186 ret_code = http_SendMessage(&info, &timeout, "bbb", start_msg.buf,
187 start_msg.length, propertySet,
188 strlen(propertySet), CRLF, strlen(CRLF));
189 if (ret_code) {
190 membuffer_destroy(&start_msg);
191 sock_destroy(&info, SD_BOTH);
192 return ret_code;
193 }
195 ret_code = http_RecvMessage(&info, response, HTTPMETHOD_NOTIFY, &timeout,
196 &err_code);
197 if (ret_code) {
198 membuffer_destroy(&start_msg);
199 sock_destroy(&info, SD_BOTH);
200 httpmsg_destroy(&response->msg);
201 return ret_code;
202 }
203 /* should shutdown completely when closing socket */
204 sock_destroy(&info, SD_BOTH);
205 membuffer_destroy(&start_msg);
206
207 return UPNP_E_SUCCESS;
208}
209
224 char* headers,
226 char* propertySet,
229 subscription* sub) {
230 size_t i;
231 membuffer mid_msg;
232 uri_type* url;
233 http_parser_t response{};
234 int return_code = -1;
235
236 membuffer_init(&mid_msg);
237 if (http_MakeMessage(&mid_msg, 1, 1,
238 "s"
239 "ssc"
240 "sdcc",
241 headers, "SID: ", sub->sid,
242 "SEQ: ", sub->ToSendEventKey) != 0) {
243 membuffer_destroy(&mid_msg);
244 return UPNP_E_OUTOF_MEMORY;
245 }
246 /* send a notify to each url until one goes thru */
247 for (i = 0; i < sub->DeliveryURLs.size; i++) {
248 url = &sub->DeliveryURLs.parsedURLs[i];
249 return_code =
250 notify_send_and_recv(url, &mid_msg, propertySet, &response);
251 if (return_code == UPNP_E_SUCCESS)
252 break;
253 }
254 membuffer_destroy(&mid_msg);
255 if (return_code == UPNP_E_SUCCESS) {
256 if (response.msg.status_code == HTTP_OK)
257 return_code = GENA_SUCCESS;
258 else {
259 if (response.msg.status_code == HTTP_PRECONDITION_FAILED)
260 /*Invalid SID gets removed */
262 else
263 return_code = GENA_E_NOTIFY_UNACCEPTED;
264 }
265 httpmsg_destroy(&response.msg);
266 }
267
268 return return_code;
269}
270
282 void* input) {
283 subscription* sub;
284 service_info* service;
285 subscription sub_copy;
287 int return_code;
288 struct Handle_Info* handle_info;
289
290 /* This should be a HandleLock and not a HandleReadLock otherwise if
291 * there is a lot of notifications, then multiple threads will acquire a
292 * read lock and the thread which sends the notification will be blocked
293 * forever on the HandleLock at the end of this function. */
294 /*HandleReadLock(); */
295 HandleLock();
296 /* validate context */
297
298 if (GetHandleInfo(in->device_handle, &handle_info) != HND_DEVICE) {
300 HandleUnlock();
301 return;
302 }
303
304 if (((service = FindServiceId(&handle_info->ServiceTable, in->servId,
305 in->UDN)) == 0) ||
306 !service->active ||
307 ((sub = GetSubscriptionSID(in->sid, service)) == 0) ||
308 copy_subscription(sub, &sub_copy) != HTTP_SUCCESS) {
310 HandleUnlock();
311 return;
312 }
313
314 HandleUnlock();
315
316 /* send the notify */
317 return_code = genaNotify(in->headers, in->propertySet, &sub_copy);
318 freeSubscription(&sub_copy);
319 HandleLock();
320 if (GetHandleInfo(in->device_handle, &handle_info) != HND_DEVICE) {
322 HandleUnlock();
323 return;
324 }
325 /* validate context */
326 if (((service = FindServiceId(&handle_info->ServiceTable, in->servId,
327 in->UDN)) == 0) ||
328 !service->active ||
329 ((sub = GetSubscriptionSID(in->sid, service)) == 0)) {
331 HandleUnlock();
332 return;
333 }
334 sub->ToSendEventKey++;
335 if (sub->ToSendEventKey < 0)
336 /* wrap to 1 for overflow */
337 sub->ToSendEventKey = 1;
338
339 /* Remove head of event queue. Possibly activate next */
340 {
341 ListNode* node = ListHead(&sub->outgoing);
342 if (node)
343 ListDelNode(&sub->outgoing, node, 1);
344 if (ListSize(&sub->outgoing) > 0) {
345 ThreadPoolJob* job;
346 ListNode* node2 = ListHead(&sub->outgoing);
347 job = (ThreadPoolJob*)node2->item;
348 /* The new head of queue should not have already been
349 added to the pool, else something is very wrong */
350 assert(job->jobId != STALE_JOBID);
351
352 ThreadPoolAdd(&gSendThreadPool, job, NULL);
353 job->jobId = STALE_JOBID;
354 }
355 }
356
357 if (return_code == GENA_E_NOTIFY_UNACCEPTED_REMOVE_SUB)
358 RemoveSubscriptionSID(in->sid, service);
360
361 HandleUnlock();
362}
363
374 const DOMString propertySet) {
375 static const char* HEADER_LINE_1 =
376 "CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n";
377 static const char* HEADER_LINE_2A = "CONTENT-LENGTH: ";
378 static const char* HEADER_LINE_2B = "\r\n";
379 static const char* HEADER_LINE_3 = "NT: upnp:event\r\n";
380 static const char* HEADER_LINE_4 = "NTS: upnp:propchange\r\n";
381 char* headers = NULL;
382 size_t headers_size = 0;
383 int line = 0;
384 int rc = 0;
385
386 headers_size = strlen(HEADER_LINE_1) + strlen(HEADER_LINE_2A) +
387 MAX_CONTENT_LENGTH + strlen(HEADER_LINE_2B) +
388 strlen(HEADER_LINE_3) + strlen(HEADER_LINE_4) + 1;
389 headers = (char*)malloc(headers_size);
390 if (headers == NULL) {
391 line = __LINE__;
392 goto ExitFunction;
393 }
394 rc = snprintf(headers, headers_size, "%s%s%" PRIzu "%s%s%s", HEADER_LINE_1,
395 HEADER_LINE_2A, strlen(propertySet) + 2, HEADER_LINE_2B,
396 HEADER_LINE_3, HEADER_LINE_4);
397
398ExitFunction:
399 if (headers == NULL || rc < 0 || (unsigned int)rc >= headers_size) {
400 UpnpPrintf(UPNP_ALL, GENA, __FILE__, line,
401 "AllocGenaHeaders(): Error UPNP_E_OUTOF_MEMORY\n");
402 }
403 return headers;
404}
405
407int genaInitNotifyCommon(UpnpDevice_Handle device_handle, char* UDN,
408 char* servId, DOMString propertySet,
409 const Upnp_SID sid) {
410 int ret = GENA_SUCCESS;
411 int line = 0;
412
413 int* reference_count = NULL;
414 char* UDN_copy = NULL;
415 char* servId_copy = NULL;
416 char* headers = NULL;
417 notify_thread_struct* thread_struct = NULL;
418
419 subscription* sub = NULL;
420 service_info* service = NULL;
421 struct Handle_Info* handle_info;
422 ThreadPoolJob* job = NULL;
423
424 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
425 "GENA BEGIN INITIAL NOTIFY COMMON\n");
426
427 job = (ThreadPoolJob*)malloc(sizeof(ThreadPoolJob));
428 if (job == NULL) {
429 line = __LINE__;
431 goto ExitFunction;
432 }
433 memset(job, 0, sizeof(ThreadPoolJob));
434
435 reference_count = (int*)malloc(sizeof(int));
436 if (reference_count == NULL) {
437 line = __LINE__;
439 goto ExitFunction;
440 }
441 *reference_count = 0;
442
443 UDN_copy = strdup(UDN);
444 if (UDN_copy == NULL) {
445 line = __LINE__;
447 goto ExitFunction;
448 }
449
450 servId_copy = strdup(servId);
451 if (servId_copy == NULL) {
452 line = __LINE__;
454 goto ExitFunction;
455 }
456
457 HandleLock();
458
459 if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) {
460 line = __LINE__;
461 ret = GENA_E_BAD_HANDLE;
462 goto ExitFunction;
463 }
464
465 service = FindServiceId(&handle_info->ServiceTable, servId, UDN);
466 if (service == NULL) {
467 line = __LINE__;
468 ret = GENA_E_BAD_SERVICE;
469 goto ExitFunction;
470 }
471 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
472 "FOUND SERVICE IN INIT NOTFY: UDN %s, ServID: %s", UDN, servId);
473
474 sub = GetSubscriptionSID(sid, service);
475 if (sub == NULL || sub->active) {
476 line = __LINE__;
477 ret = GENA_E_BAD_SID;
478 goto ExitFunction;
479 }
480 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
481 "FOUND SUBSCRIPTION IN INIT NOTIFY: SID %s", sid);
482 sub->active = 1;
483
484 headers = AllocGenaHeaders(propertySet);
485 if (headers == NULL) {
486 line = __LINE__;
488 goto ExitFunction;
489 }
490
491 /* schedule thread for initial notification */
492
493 thread_struct = (notify_thread_struct*)malloc(sizeof(notify_thread_struct));
494 if (thread_struct == NULL) {
495 line = __LINE__;
497 } else {
498 *reference_count = 1;
499 thread_struct->servId = servId_copy;
500 thread_struct->UDN = UDN_copy;
501 thread_struct->headers = headers;
502 thread_struct->propertySet = propertySet;
503 memset(thread_struct->sid, 0, sizeof(thread_struct->sid));
504 strncpy(thread_struct->sid, sid, sizeof(thread_struct->sid) - 1);
505 thread_struct->ctime = time(0);
506 thread_struct->reference_count = reference_count;
507 thread_struct->device_handle = device_handle;
508
509 TPJobInit(job, (UPnPsdk::start_routine)genaNotifyThread, thread_struct);
511 TPJobSetPriority(job, MED_PRIORITY);
512
513 ret = ThreadPoolAdd(&gSendThreadPool, job, NULL);
514 if (ret != 0) {
515 if (ret == EOUTOFMEM) {
516 line = __LINE__;
518 }
519 } else {
520 ListNode* node = ListAddTail(&sub->outgoing, job);
521 if (node != NULL) {
522 ((ThreadPoolJob*)node->item)->jobId = STALE_JOBID;
523 line = __LINE__;
524 ret = GENA_SUCCESS;
525 } else {
526 line = __LINE__;
528 }
529 }
530 }
531
532ExitFunction:
533 if (ret != GENA_SUCCESS) {
534 free(job);
535 free(thread_struct);
536 free(headers);
537 ixmlFreeDOMString(propertySet);
538 free(servId_copy);
539 free(UDN_copy);
540 free(reference_count);
541 }
542
543 HandleUnlock();
544
545 UpnpPrintf(UPNP_INFO, GENA, __FILE__, line,
546 "GENA END INITIAL NOTIFY COMMON, ret = %d\n", ret);
547
548 return ret;
549}
550
561 time_t now = time(0L);
563 ThreadPoolJob* p;
564
565 while (ListSize(listp) > 1) {
566 ListNode* node = ListHead(listp);
567 /* The first candidate is the second event: first non-active */
568 if (node == 0 || (node = node->next) == 0) {
569 /* Major inconsistency, really, should abort here. */
570 fprintf(stderr, "gena_device: maybeDiscardEvents: "
571 "list is inconsistent\n");
572 break;
573 }
574
575 p = (ThreadPoolJob*)node->item;
576 ntsp = (notify_thread_struct*)(p->arg);
577 if (ListSize(listp) > g_UpnpSdkEQMaxLen ||
578 now - ntsp->ctime > g_UpnpSdkEQMaxAge) {
579 free_notify_struct(ntsp);
580 free(node->item);
581 ListDelNode(listp, node, 0);
582 } else {
583 /* If the list is smaller than the max and the oldest
584 * task is young enough, stop pruning */
585 break;
586 }
587 }
588}
589
591int genaNotifyAllCommon(UpnpDevice_Handle device_handle, char* UDN,
592 char* servId, DOMString propertySet) {
593 int ret = GENA_SUCCESS;
594 int line = 0;
595
596 int* reference_count = NULL;
597 char* UDN_copy = NULL;
598 char* servId_copy = NULL;
599 char* headers = NULL;
600 notify_thread_struct* thread_s = NULL;
601
602 subscription* finger = NULL;
603 service_info* service = NULL;
604 struct Handle_Info* handle_info;
605
606 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
607 "GENA BEGIN NOTIFY ALL COMMON\n");
608
609 /* Keep this allocation first */
610 reference_count = (int*)malloc(sizeof(int));
611 if (reference_count == NULL) {
612 line = __LINE__;
614 goto ExitFunction;
615 }
616 *reference_count = 0;
617
618 UDN_copy = strdup(UDN);
619 if (UDN_copy == NULL) {
620 line = __LINE__;
622 goto ExitFunction;
623 }
624
625 servId_copy = strdup(servId);
626 if (servId_copy == NULL) {
627 line = __LINE__;
629 goto ExitFunction;
630 }
631
632 headers = AllocGenaHeaders(propertySet);
633 if (headers == NULL) {
634 line = __LINE__;
636 goto ExitFunction;
637 }
638
639 HandleLock();
640
641 if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) {
642 line = __LINE__;
643 ret = GENA_E_BAD_HANDLE;
644 } else {
645 service = FindServiceId(&handle_info->ServiceTable, servId, UDN);
646 if (service != NULL) {
647 finger = GetFirstSubscription(service);
648 while (finger) {
649 ThreadPoolJob* job = NULL;
650 ListNode* node;
651
652 thread_s =
654 if (thread_s == NULL) {
655 line = __LINE__;
657 break;
658 }
659
660 (*reference_count)++;
661 thread_s->reference_count = reference_count;
662 thread_s->UDN = UDN_copy;
663 thread_s->servId = servId_copy;
664 thread_s->headers = headers;
665 thread_s->propertySet = propertySet;
666 strncpy(thread_s->sid, finger->sid, sizeof thread_s->sid);
667 thread_s->sid[sizeof thread_s->sid - 1] = 0;
668 thread_s->ctime = time(0);
669 thread_s->device_handle = device_handle;
670
672 job = (ThreadPoolJob*)malloc(sizeof(ThreadPoolJob));
673 if (!job) {
674 free(thread_s);
675 line = __LINE__;
677 break;
678 }
679 memset(job, 0, sizeof(ThreadPoolJob));
680 TPJobInit(job, (UPnPsdk::start_routine)genaNotifyThread,
681 thread_s);
683 TPJobSetPriority(job, MED_PRIORITY);
684 node = ListAddTail(&finger->outgoing, job);
685
686 /* If there is only one element on the list
687 (which we just
688 added), need to kickstart the threadpool */
689 if (ListSize(&finger->outgoing) == 1) {
690 ret = ThreadPoolAdd(&gSendThreadPool, job, NULL);
691 if (ret != 0) {
692 line = __LINE__;
693 if (ret == EOUTOFMEM) {
694 line = __LINE__;
696 }
697 break;
698 }
699 if (node) {
700 ((ThreadPoolJob*)(node->item))->jobId = STALE_JOBID;
701 }
702 }
703 finger = GetNextSubscription(service, finger);
704 }
705 } else {
706 line = __LINE__;
707 ret = GENA_E_BAD_SERVICE;
708 }
709 }
710
711ExitFunction:
712 /* The only case where we want to free memory here is if the
713 struct was never queued. Else, let the normal cleanup take place.
714 reference_count is allocated first so it's ok to do nothing if it's 0
715 */
716 if (reference_count && *reference_count == 0) {
717 free(headers);
718 ixmlFreeDOMString(propertySet);
719 free(servId_copy);
720 free(UDN_copy);
721 free(reference_count);
722 }
723
724 HandleUnlock();
725
726 UpnpPrintf(UPNP_INFO, GENA, __FILE__, line,
727 "GENA END NOTIFY ALL COMMON, ret = %d\n", ret);
728
729 return ret;
730}
731
739 SOCKINFO* info,
741 int time_out,
743 subscription* sub,
745 http_message_t* request) {
746 int major;
747 int minor;
748 membuffer response;
749 int return_code;
750 char timeout_str[100];
751 int upnp_timeout = UPNP_TIMEOUT;
752 int rc = 0;
753
755 &major, &minor);
756
757 if (time_out >= 0) {
758 rc = snprintf(timeout_str, sizeof(timeout_str), "TIMEOUT: Second-%d",
759 time_out);
760 } else {
761 memset(timeout_str, 0, sizeof(timeout_str));
762 strncpy(timeout_str, "TIMEOUT: Second-infinite",
763 sizeof(timeout_str) - 1);
764 }
765 if (rc < 0 || (unsigned int)rc >= sizeof(timeout_str)) {
766 error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
767 return UPNP_E_OUTOF_MEMORY;
768 }
769
770 membuffer_init(&response);
771 response.size_inc = 30;
772 if (http_MakeMessage(&response, major, minor,
773 "R"
774 "D"
775 "S"
776 "N"
777 "Xc"
778 "ssc"
779 "scc",
780 HTTP_OK, (off_t)0, X_USER_AGENT, "SID: ", sub->sid,
781 timeout_str) != 0) {
782 membuffer_destroy(&response);
783 error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
784 return UPNP_E_OUTOF_MEMORY;
785 }
786
787 return_code = http_SendMessage(info, &upnp_timeout, "b", response.buf,
788 response.length);
789
790 membuffer_destroy(&response);
791
792 return return_code;
793}
794
795} // namespace
796
797
799 int ret = 0;
800 struct Handle_Info* handle_info;
801
802 HandleLock();
803 if (GetHandleInfo(device_handle, &handle_info) != HND_DEVICE) {
804 UpnpPrintf(UPNP_CRITICAL, GENA, __FILE__, __LINE__,
805 "genaUnregisterDevice: BAD Handle: %d\n", device_handle);
806 ret = GENA_E_BAD_HANDLE;
807 } else {
808 freeServiceTable(&handle_info->ServiceTable);
809 ret = UPNP_E_SUCCESS;
810 }
811 HandleUnlock();
812
813 return ret;
814}
815
817 if (ListSize(&sub->outgoing) > 0) {
818 /* The first event is discarded without dealing
819 notify_thread_struct: there is a mirror ThreadPool entry for
820 this one, and it will take care of the refcount etc. Other
821 entries must be fully cleaned-up here */
822 int first = 1;
823 ListNode* node = ListHead(&sub->outgoing);
824 while (node) {
825 ThreadPoolJob* job = (ThreadPoolJob*)node->item;
826 if (first) {
827 first = 0;
828 } else {
830 }
831 free(node->item);
832 ListDelNode(&sub->outgoing, node, 0);
833 node = ListHead(&sub->outgoing);
834 }
835 }
836}
837
838
839int genaInitNotify(UpnpDevice_Handle device_handle, char* UDN, char* servId,
840 char** VarNames, char** VarValues, int var_count,
841 const Upnp_SID sid) {
842 int ret = GENA_SUCCESS;
843 int line = 0;
844 DOMString propertySet = NULL;
845
846 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
847 "GENA BEGIN INITIAL NOTIFY\n");
848
849 if (var_count <= 0) {
850 line = __LINE__;
851 ret = GENA_SUCCESS;
852 goto ExitFunction;
853 }
854
855 ret = GeneratePropertySet(VarNames, VarValues, var_count, &propertySet);
856 if (ret != XML_SUCCESS) {
857 line = __LINE__;
858 goto ExitFunction;
859 }
860 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
861 "GENERATED PROPERTY SET IN INIT NOTIFY: %s", propertySet);
862
863 ret = genaInitNotifyCommon(device_handle, UDN, servId, propertySet, sid);
864
865ExitFunction:
866
867 UpnpPrintf(UPNP_INFO, GENA, __FILE__, line,
868 "GENA END INITIAL NOTIFY, ret = %d\n", ret);
869
870 return ret;
871}
872
873int genaInitNotifyExt(UpnpDevice_Handle device_handle, char* UDN, char* servId,
874 IXML_Document* PropSet, const Upnp_SID sid) {
875 int ret = GENA_SUCCESS;
876 int line = 0;
877
878 DOMString propertySet = NULL;
879
880 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
881 "GENA BEGIN INITIAL NOTIFY EXT\n");
882
883 if (PropSet == 0) {
884 line = __LINE__;
885 ret = GENA_SUCCESS;
886 goto ExitFunction;
887 }
888
889 propertySet = ixmlPrintNode((IXML_Node*)PropSet);
890 if (propertySet == NULL) {
891 line = __LINE__;
893 goto ExitFunction;
894 }
895 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
896 "GENERATED PROPERTY SET IN INIT EXT NOTIFY: %s", propertySet);
897
898 ret = genaInitNotifyCommon(device_handle, UDN, servId, propertySet, sid);
899
900ExitFunction:
901
902 UpnpPrintf(UPNP_INFO, GENA, __FILE__, line,
903 "GENA END INITIAL NOTIFY EXT, ret = %d\n", ret);
904
905 return ret;
906}
907
908int genaNotifyAllExt(UpnpDevice_Handle device_handle, char* UDN, char* servId,
909 IXML_Document* PropSet) {
910 int ret = GENA_SUCCESS;
911 int line = 0;
912
913 DOMString propertySet = NULL;
914
915 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
916 "GENA BEGIN NOTIFY ALL EXT\n");
917
918 propertySet = ixmlPrintNode((IXML_Node*)PropSet);
919 if (propertySet == NULL) {
920 line = __LINE__;
922 goto ExitFunction;
923 }
924 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
925 "GENERATED PROPERTY SET IN EXT NOTIFY: %s", propertySet);
926
927 ret = genaNotifyAllCommon(device_handle, UDN, servId, propertySet);
928
929ExitFunction:
930
931 UpnpPrintf(UPNP_INFO, GENA, __FILE__, line,
932 "GENA END NOTIFY ALL EXT, ret = %d\n", ret);
933
934 return ret;
935}
936
937int genaNotifyAll(UpnpDevice_Handle device_handle, char* UDN, char* servId,
938 char** VarNames, char** VarValues, int var_count) {
939 int ret = GENA_SUCCESS;
940 int line = 0;
941
942 DOMString propertySet = NULL;
943
944 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA BEGIN NOTIFY ALL\n");
945
946 ret = GeneratePropertySet(VarNames, VarValues, var_count, &propertySet);
947 if (ret != XML_SUCCESS) {
948 line = __LINE__;
949 goto ExitFunction;
950 }
951 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
952 "GENERATED PROPERTY SET IN EXT NOTIFY: %s", propertySet);
953
954 ret = genaNotifyAllCommon(device_handle, UDN, servId, propertySet);
955
956ExitFunction:
957
958 UpnpPrintf(UPNP_INFO, GENA, __FILE__, line,
959 "GENA END NOTIFY ALL, ret = %d\n", ret);
960
961 return ret;
962}
963
974 SOCKINFO* info,
976 URL_list* url_list) {
977 size_t i = 0;
978 struct in_addr genaAddr4;
979 struct in_addr genaNetmask;
980 struct sockaddr_in* deliveryAddr4 = NULL;
981 struct in6_addr genaAddr6Lla;
982 struct in6_addr genaAddr6UlaGua;
983 struct in6_addr* genaAddr6 = NULL;
984 unsigned int if_prefix;
985 struct sockaddr_in6* deliveryAddr6 = NULL;
986 char deliveryAddrString[INET6_ADDRSTRLEN];
987
988 if (info == NULL || url_list == NULL) {
989 return 0;
990 }
991
992 switch (info->foreign_sockaddr.ss_family) {
993 case AF_INET:
994 if (!inet_pton(AF_INET, gIF_IPV4, &genaAddr4)) {
995 return -1;
996 }
997
998 if (!inet_pton(AF_INET, gIF_IPV4_NETMASK, &genaNetmask)) {
999 return -1;
1000 }
1001
1002 for (i = 0; i < url_list->size; i++) {
1003 deliveryAddr4 = (struct sockaddr_in*)&url_list->parsedURLs[i]
1005 if ((deliveryAddr4->sin_addr.s_addr & genaNetmask.s_addr) !=
1006 (genaAddr4.s_addr & genaNetmask.s_addr)) {
1007 inet_ntop(AF_INET, &deliveryAddr4->sin_addr, deliveryAddrString,
1008 sizeof(deliveryAddrString));
1009 UpnpPrintf(UPNP_CRITICAL, GENA, __FILE__, __LINE__,
1010 "DeliveryURL %s is invalid.\n"
1011 "It is not in the expected network "
1012 "segment (IPv4: %s, netmask: %s)\n",
1013 deliveryAddrString, gIF_IPV4, gIF_IPV4_NETMASK);
1014 return -1;
1015 }
1016 }
1017 break;
1018 case AF_INET6:
1019 if (!inet_pton(AF_INET6, gIF_IPV6, &genaAddr6Lla)) {
1020 return -1;
1021 }
1022
1023 if (!inet_pton(AF_INET6, gIF_IPV6_ULA_GUA, &genaAddr6UlaGua)) {
1024 return -1;
1025 }
1026
1027 for (i = 0; i < url_list->size; i++) {
1028 deliveryAddr6 = (struct sockaddr_in6*)&url_list->parsedURLs[i]
1030 if (IN6_IS_ADDR_LINKLOCAL(&deliveryAddr6->sin6_addr)) {
1031 genaAddr6 = &genaAddr6Lla;
1032 if_prefix = gIF_IPV6_PREFIX_LENGTH;
1033 } else {
1034 genaAddr6 = &genaAddr6UlaGua;
1036 }
1037 /* We assume that IPv6 prefix is a multiple of 8 */
1038 if (memcmp(deliveryAddr6->sin6_addr.s6_addr, genaAddr6->s6_addr,
1039 if_prefix / 8)) {
1040 inet_ntop(AF_INET6, &deliveryAddr6->sin6_addr,
1041 deliveryAddrString, sizeof(deliveryAddrString));
1042 UpnpPrintf(UPNP_CRITICAL, GENA, __FILE__, __LINE__,
1043 "DeliveryURL %s is invalid.\n"
1044 "It is not in the expected network "
1045 "segment (IPv6: %s, prefix: %d)\n",
1046 deliveryAddrString,
1047 IN6_IS_ADDR_LINKLOCAL(&deliveryAddr6->sin6_addr)
1048 ? gIF_IPV6
1050 if_prefix);
1051 return -1;
1052 }
1053 }
1054 break;
1055 }
1056 return 0;
1057}
1058
1060 http_message_t* request) {
1062 Upnp_SID temp_sid;
1063 int return_code = 1;
1064 int time_out = 1801;
1065 service_info* service;
1066 subscription* sub;
1067 uuid_upnp uid;
1068 struct Handle_Info* handle_info;
1069 void* cookie;
1070 Upnp_FunPtr callback_fun;
1071 UpnpDevice_Handle device_handle;
1072 memptr nt_hdr;
1073 char* event_url_path = NULL;
1074 memptr callback_hdr;
1075 memptr timeout_hdr;
1076 int rc = 0;
1077
1078 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
1079 "Subscription Request Received:\n");
1080
1081 if (httpmsg_find_hdr(request, HDR_NT, &nt_hdr) == NULL) {
1082 error_respond(info, HTTP_BAD_REQUEST, request);
1083 goto exit_function;
1084 }
1085
1086 /* check NT header */
1087 /* Windows Millenium Interoperability: */
1088 /* we accept either upnp:event, or upnp:propchange for the NT header */
1089 if (memptr_cmp_nocase(&nt_hdr, "upnp:event") != 0) {
1090 error_respond(info, HTTP_PRECONDITION_FAILED, request);
1091 goto exit_function;
1092 }
1093
1094 /* if a SID is present then the we have a bad request "incompatible
1095 * headers" */
1096 if (httpmsg_find_hdr(request, HDR_SID, NULL) != NULL) {
1097 error_respond(info, HTTP_BAD_REQUEST, request);
1098 goto exit_function;
1099 }
1100 /* look up service by eventURL */
1101 event_url_path =
1102 str_alloc(request->uri.pathquery.buff, request->uri.pathquery.size);
1103 if (event_url_path == NULL) {
1104 error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
1105 goto exit_function;
1106 }
1107
1108 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
1109 "SubscriptionRequest for event URL path: %s\n", event_url_path);
1110
1111 HandleLock();
1112
1114 event_url_path, info->foreign_sockaddr.ss_family, &device_handle,
1115 &handle_info, &service) != HND_DEVICE) {
1116 free(event_url_path);
1117 error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
1118 HandleUnlock();
1119 goto exit_function;
1120 }
1121 free(event_url_path);
1122
1123 if (service == NULL || !service->active) {
1124 error_respond(info, HTTP_NOT_FOUND, request);
1125 HandleUnlock();
1126 goto exit_function;
1127 }
1128
1129 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
1130 "Subscription Request: Number of Subscriptions already %d\n "
1131 "Max Subscriptions allowed: %d\n",
1132 service->TotalSubscriptions, handle_info->MaxSubscriptions);
1133
1134 /* too many subscriptions */
1135 if (handle_info->MaxSubscriptions != -1 &&
1136 service->TotalSubscriptions >= handle_info->MaxSubscriptions) {
1137 error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
1138 HandleUnlock();
1139 goto exit_function;
1140 }
1141 /* generate new subscription */
1142 sub = (subscription*)malloc(sizeof(subscription));
1143 if (sub == NULL) {
1144 error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
1145 HandleUnlock();
1146 goto exit_function;
1147 }
1148 sub->ToSendEventKey = 0;
1149 sub->active = 0;
1150 sub->next = NULL;
1151 sub->DeliveryURLs.size = 0;
1152 sub->DeliveryURLs.URLs = NULL;
1153 sub->DeliveryURLs.parsedURLs = NULL;
1154 if (ListInit(&sub->outgoing, 0, free) != 0) {
1155 error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
1156 HandleUnlock();
1157 goto exit_function;
1158 }
1159
1160 /* check for valid callbacks */
1161 if (httpmsg_find_hdr(request, HDR_CALLBACK, &callback_hdr) == NULL) {
1162 error_respond(info, HTTP_PRECONDITION_FAILED, request);
1164 HandleUnlock();
1165 goto exit_function;
1166 }
1167 return_code = create_url_list(&callback_hdr, &sub->DeliveryURLs);
1168 if (return_code == 0) {
1169 error_respond(info, HTTP_PRECONDITION_FAILED, request);
1171 HandleUnlock();
1172 goto exit_function;
1173 }
1174 if (return_code == UPNP_E_OUTOF_MEMORY) {
1175 error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
1177 HandleUnlock();
1178 goto exit_function;
1179 }
1180 return_code = gena_validate_delivery_urls(info, &sub->DeliveryURLs);
1181 if (return_code != 0) {
1182 error_respond(info, HTTP_PRECONDITION_FAILED, request);
1184 HandleUnlock();
1185 goto exit_function;
1186 }
1187 /* set the timeout */
1188 if (httpmsg_find_hdr(request, HDR_TIMEOUT, &timeout_hdr) != NULL) {
1189 if (matchstr(timeout_hdr.buf, timeout_hdr.length, "%iSecond-%d%0",
1190 &time_out) == PARSE_OK) {
1191 /* nothing */
1192 } else if (memptr_cmp_nocase(&timeout_hdr, "Second-infinite") == 0) {
1193 /* infinite timeout */
1194 time_out = -1;
1195 } else {
1196 /* default is > 1800 seconds */
1197 time_out = DEFAULT_TIMEOUT;
1198 }
1199 }
1200 /* replace infinite timeout with max timeout, if possible */
1201 if (handle_info->MaxSubscriptionTimeOut != -1) {
1202 if (time_out == -1 || time_out > handle_info->MaxSubscriptionTimeOut) {
1203 time_out = handle_info->MaxSubscriptionTimeOut;
1204 }
1205 }
1206 if (time_out >= 0) {
1207 sub->expireTime = time(NULL) + time_out;
1208 } else {
1209 /* infinite time */
1210 sub->expireTime = 0;
1211 }
1212
1213 /* generate SID */
1214 uuid_create(&uid);
1215 upnp_uuid_unpack(&uid, temp_sid);
1216 rc = snprintf(sub->sid, sizeof(sub->sid), "uuid:%s", temp_sid);
1217
1218 /* respond OK */
1219 if (rc < 0 || (unsigned int)rc >= sizeof(sub->sid) ||
1220 (respond_ok(info, time_out, sub, request) != UPNP_E_SUCCESS)) {
1222 HandleUnlock();
1223 goto exit_function;
1224 }
1225 /* add to subscription list */
1226 sub->next = service->subscriptionList;
1227 service->subscriptionList = sub;
1228 service->TotalSubscriptions++;
1229
1230 /* finally generate callback for init table dump */
1232 service->serviceId);
1233 UpnpSubscriptionRequest_strcpy_UDN(request_struct, service->UDN);
1234 UpnpSubscriptionRequest_strcpy_SID(request_struct, sub->sid);
1235
1236 /* copy callback */
1237 callback_fun = handle_info->Callback;
1238 cookie = handle_info->Cookie;
1239
1240 HandleUnlock();
1241
1242 /* make call back with request struct */
1243 /* in the future should find a way of mainting that the handle */
1244 /* is not unregistered in the middle of a callback */
1245 callback_fun(UPNP_EVENT_SUBSCRIPTION_REQUEST, request_struct, cookie);
1246
1247exit_function:
1248 UpnpSubscriptionRequest_delete(request_struct);
1249}
1250
1252 http_message_t* request) {
1253 Upnp_SID sid;
1254 subscription* sub;
1255 int time_out = 1801;
1256 service_info* service;
1257 struct Handle_Info* handle_info;
1258 UpnpDevice_Handle device_handle;
1259 memptr temp_hdr;
1260 membuffer event_url_path;
1261 memptr timeout_hdr;
1262
1263 /* if a CALLBACK or NT header is present, then it is an error */
1264 if (httpmsg_find_hdr(request, HDR_CALLBACK, NULL) != NULL ||
1265 httpmsg_find_hdr(request, HDR_NT, NULL) != NULL) {
1266 error_respond(info, HTTP_BAD_REQUEST, request);
1267 return;
1268 }
1269 /* get SID */
1270 if (httpmsg_find_hdr(request, HDR_SID, &temp_hdr) == NULL ||
1271 temp_hdr.length > SID_SIZE) {
1272 error_respond(info, HTTP_PRECONDITION_FAILED, request);
1273 return;
1274 }
1275 memcpy(sid, temp_hdr.buf, temp_hdr.length);
1276 sid[temp_hdr.length] = '\0';
1277
1278 /* lookup service by eventURL */
1279 membuffer_init(&event_url_path);
1280 if (membuffer_append(&event_url_path, request->uri.pathquery.buff,
1281 request->uri.pathquery.size) != 0) {
1282 error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
1283 return;
1284 }
1285
1286 HandleLock();
1287
1289 event_url_path.buf, info->foreign_sockaddr.ss_family,
1290 &device_handle, &handle_info, &service) != HND_DEVICE) {
1291 error_respond(info, HTTP_PRECONDITION_FAILED, request);
1292 membuffer_destroy(&event_url_path);
1293 HandleUnlock();
1294 return;
1295 }
1296 membuffer_destroy(&event_url_path);
1297
1298 /* get subscription */
1299 if (service == NULL || !service->active ||
1300 ((sub = GetSubscriptionSID(sid, service)) == NULL)) {
1301 error_respond(info, HTTP_PRECONDITION_FAILED, request);
1302 HandleUnlock();
1303 return;
1304 }
1305
1306 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
1307 "Renew request: Number of subscriptions already: %d\n "
1308 "Max Subscriptions allowed:%d\n",
1309 service->TotalSubscriptions, handle_info->MaxSubscriptions);
1310 /* too many subscriptions */
1311 if (handle_info->MaxSubscriptions != -1 &&
1312 service->TotalSubscriptions > handle_info->MaxSubscriptions) {
1313 error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
1314 RemoveSubscriptionSID(sub->sid, service);
1315 HandleUnlock();
1316 return;
1317 }
1318 /* set the timeout */
1319 if (httpmsg_find_hdr(request, HDR_TIMEOUT, &timeout_hdr) != NULL) {
1320 if (matchstr(timeout_hdr.buf, timeout_hdr.length, "%iSecond-%d%0",
1321 &time_out) == PARSE_OK) {
1322
1323 /*nothing */
1324
1325 } else if (memptr_cmp_nocase(&timeout_hdr, "Second-infinite") == 0) {
1326
1327 time_out = -1; /* inifinite timeout */
1328
1329 } else {
1330 time_out = DEFAULT_TIMEOUT; /* default is > 1800 seconds */
1331 }
1332 }
1333
1334 /* replace infinite timeout with max timeout, if possible */
1335 if (handle_info->MaxSubscriptionTimeOut != -1) {
1336 if (time_out == -1 || time_out > handle_info->MaxSubscriptionTimeOut) {
1337 time_out = handle_info->MaxSubscriptionTimeOut;
1338 }
1339 }
1340
1341 if (time_out == -1) {
1342 sub->expireTime = 0;
1343 } else {
1344 sub->expireTime = time(NULL) + time_out;
1345 }
1346
1347 if (respond_ok(info, time_out, sub, request) != UPNP_E_SUCCESS) {
1348 RemoveSubscriptionSID(sub->sid, service);
1349 }
1350
1351 HandleUnlock();
1352}
1353
1355 Upnp_SID sid;
1356 service_info* service;
1357 struct Handle_Info* handle_info;
1358 UpnpDevice_Handle device_handle;
1359
1360 memptr temp_hdr;
1361 membuffer event_url_path;
1362
1363 /* if a CALLBACK or NT header is present, then it is an error */
1364 if (httpmsg_find_hdr(request, HDR_CALLBACK, NULL) != NULL ||
1365 httpmsg_find_hdr(request, HDR_NT, NULL) != NULL) {
1366 error_respond(info, HTTP_BAD_REQUEST, request);
1367 return;
1368 }
1369 /* get SID */
1370 if (httpmsg_find_hdr(request, HDR_SID, &temp_hdr) == NULL ||
1371 temp_hdr.length > SID_SIZE) {
1372 error_respond(info, HTTP_PRECONDITION_FAILED, request);
1373 return;
1374 }
1375 memcpy(sid, temp_hdr.buf, temp_hdr.length);
1376 sid[temp_hdr.length] = '\0';
1377
1378 /* lookup service by eventURL */
1379 membuffer_init(&event_url_path);
1380 if (membuffer_append(&event_url_path, request->uri.pathquery.buff,
1381 request->uri.pathquery.size) != 0) {
1382 error_respond(info, HTTP_INTERNAL_SERVER_ERROR, request);
1383 return;
1384 }
1385
1386 HandleLock();
1387
1389 event_url_path.buf, info->foreign_sockaddr.ss_family,
1390 &device_handle, &handle_info, &service) != HND_DEVICE) {
1391 error_respond(info, HTTP_PRECONDITION_FAILED, request);
1392 membuffer_destroy(&event_url_path);
1393 HandleUnlock();
1394 return;
1395 }
1396 membuffer_destroy(&event_url_path);
1397
1398 /* validate service */
1399 if (service == NULL || !service->active ||
1400 GetSubscriptionSID(sid, service) == NULL) {
1401 error_respond(info, HTTP_PRECONDITION_FAILED, request);
1402 HandleUnlock();
1403 return;
1404 }
1405
1406 RemoveSubscriptionSID(sid, service);
1407 error_respond(info, HTTP_OK, request); /* success */
1408
1409 HandleUnlock();
1410}
@ UPNP_EVENT_SUBSCRIPTION_REQUEST
Definition Callback.hpp:83
int(* Upnp_FunPtr)(Upnp_EventType EventType, const void *Event, void *Cookie)
Definition Callback.hpp:143
char Upnp_SID[44]
Holds the subscription identifier for a subscription between a client and a device.
Definition API.hpp:431
int UpnpDevice_Handle
Returned when a device application registers with UpnpRegisterRootDevice(),UpnpRegisterRootDevice2(),...
Definition API.hpp:422
int create_url_list(memptr *a_url_list, URL_list *a_out)
Function to parse the Callback header value in subscription requests.
Definition uri.cpp:89
http_message_t msg
entire raw message
uri_type uri
Type of a uri, e.g. absolute, relative, etc.
int major_version
Http major version.
#define HDR_NT
Type of a HTTP header.
#define HDR_CALLBACK
Type of a HTTP header.
@ PARSE_OK
int minor_version
Http minor version.
#define HDR_TIMEOUT
Type of a HTTP header.
#define HDR_SID
Type of a HTTP header.
Structure of an HTTP parser object.
Structure of an HTTP message.
char * URLs
Definition uri.hpp:53
uri_type * parsedURLs
Definition uri.hpp:57
size_t size
Number of urls (not characters).
Definition uri.hpp:52
Represents a list of URLs as in the "callback" header of SUBSCRIBE message in GENA.
Definition uri.hpp:51
#define X_USER_AGENT
Can be overwritten by configure CFLAGS argument.
Definition webserver.hpp:86
long ListSize(LinkedList *list)
Returns the size of the list.
void * ListDelNode(LinkedList *list, ListNode *dnode, int freeItem)
Removes a node from the list. The memory for the node is freed.
ListNode * ListHead(LinkedList *list)
Returns the head of the list.
ListNode * ListAddTail(LinkedList *list, void *item)
Adds a node to the tail of the list. Node gets added immediately before list.tail.
int ListInit(LinkedList *list, cmp_routine cmp_func, free_function free_func)
Initializes LinkedList. Must be called first and only once for List.
#define EOUTOFMEM
Error condition for "out of memory".
Linked list node. Stores generic item and pointers to next and prev.
Linked list (no protection).
int ThreadPoolAdd(ThreadPool *tp, ThreadPoolJob *job, int *jobId)
Adds a job to the thread pool.
int TPJobSetFreeFunction(ThreadPoolJob *job, free_routine func)
Sets the jobs free function.
int TPJobSetPriority(ThreadPoolJob *job, ThreadPriority priority)
Sets the priority of the threadpool job.
int TPJobInit(ThreadPoolJob *job, UPnPsdk::start_routine func, void *arg)
Initializes thread pool job.
void(* free_routine)(void *arg)
Internal ThreadPool Job.
hostport_type hostport
Member variable.
Definition uri.hpp:72
size_t size
Size of the buffer.
Definition uri.hpp:50
const char * buff
Buffer.
Definition uri.hpp:49
token pathquery
Member variable.
Definition uri.hpp:70
sockaddr_storage IPaddress
Network socket address.
Definition uri.hpp:58
constexpr int HTTP_SUCCESS
Yet another success code.
Definition uri.hpp:21
token text
Pointing to the full host:port string representation.
Definition uri.hpp:57
Represents a URI used in parse_uri and elsewhere.
Definition uri.hpp:64
Header file for UpnpSubscriptionRequest methods.
PUPNP_Api int UpnpSubscriptionRequest_strcpy_SID(UpnpSubscriptionRequest *p, const char *s)
PUPNP_Api UpnpSubscriptionRequest * UpnpSubscriptionRequest_new(void)
PUPNP_Api void UpnpSubscriptionRequest_delete(UpnpSubscriptionRequest *p)
PUPNP_Api int UpnpSubscriptionRequest_strcpy_UDN(UpnpSubscriptionRequest *p, const char *s)
PUPNP_Api int UpnpSubscriptionRequest_strcpy_ServiceId(UpnpSubscriptionRequest *p, const char *s)
#define GENA_NOTIFICATION_SENDING_TIMEOUT
The GENA_NOTIFICATION_SENDING_TIMEOUT specifies the number of seconds to wait for sending GENA notifi...
Definition config.hpp:229
#define GENA_NOTIFICATION_ANSWERING_TIMEOUT
The GENA_NOTIFICATION_ANSWERING_TIMEOUT specifies the number of seconds to wait for receiving the ans...
Definition config.hpp:246
Manage Eventing with GENA, the General Event Notification Architecture.
#define GENA_E_BAD_HANDLE
Definition gena.hpp:79
UpnpDevice_Handle device_handle
Definition gena.hpp:102
#define GENA_SUCCESS
Definition gena.hpp:83
#define XML_PROPERTYSET_HEADER
Definition gena.hpp:52
#define XML_SUCCESS
Definition gena.hpp:82
#define GENA_E_NOTIFY_UNACCEPTED
Definition gena.hpp:77
#define GENA_E_NOTIFY_UNACCEPTED_REMOVE_SUB
Definition gena.hpp:78
#define MAX_CONTENT_LENGTH
Definition gena.hpp:67
#define DEFAULT_TIMEOUT
Definition gena.hpp:86
DOMString propertySet
Definition gena.hpp:96
#define GENA_E_BAD_SID
Definition gena.hpp:75
#define GENA_E_BAD_SERVICE
Definition gena.hpp:73
void error_respond(SOCKINFO *info, int error_code, http_message_t *hmsg)
Sends an error message to the control point in the case of incorrect GENA requests.
void freeSubscriptionQueuedEvents(subscription *sub)
???
void gena_process_subscription_request(SOCKINFO *info, http_message_t *request)
Handles a subscription request from a ctrl point. The socket is not closed on return.
int genaNotifyAll(UpnpDevice_Handle device_handle, char *UDN, char *servId, char **VarNames, char **VarValues, int var_count)
Sends a notification to all the subscribed control points.
void gena_process_unsubscribe_request(SOCKINFO *info, http_message_t *request)
Handles a subscription cancellation request from a ctrl point. The connection is not destroyed on ret...
int genaUnregisterDevice(UpnpDevice_Handle device_handle)
Cleans the service table of the device.
void gena_process_subscription_renewal_request(SOCKINFO *info, http_message_t *request)
Handles a subscription renewal request from a ctrl point. The connection is not destroyed on return.
int gena_validate_delivery_urls(SOCKINFO *info, URL_list *url_list)
Validate that the URLs passed by the user are on the same network segment than the device.
int genaNotifyAllExt(UpnpDevice_Handle device_handle, char *UDN, char *servId, IXML_Document *PropSet)
Sends a notification to all the subscribed control points.
int genaInitNotifyExt(UpnpDevice_Handle device_handle, char *UDN, char *servId, IXML_Document *PropSet, const Upnp_SID sid)
Similar to the genaInitNofity. The only difference is that it takes the xml document for the state ta...
#define STALE_JOBID
Invalid job id.
int genaInitNotify(UpnpDevice_Handle device_handle, char *UDN, char *servId, char **VarNames, char **VarValues, int var_count, const Upnp_SID sid)
Sends the intial state table dump to newly subscribed control point.
Data structure common to all types of nodes.
Definition ixml.hpp:132
Data structure representing the DOM Document.
Definition ixml.hpp:155
PUPNP_Api DOMString ixmlPrintNode(IXML_Node *doc)
Renders a Node and all sub-elements into an XML text representation.
Definition ixml.cpp:344
#define DOMString
The type of DOM strings.
Definition ixml.hpp:47
PUPNP_Api void ixmlFreeDOMString(DOMString buf)
Frees a DOMString.
Definition ixml.cpp:423
PUPNP_Api DOMString ixmlCloneDOMString(const DOMString src)
Clones an existing DOMString.
Definition ixml.cpp:415
http_header_t * httpmsg_find_hdr(http_message_t *msg, int header_name_id, memptr *value)
Finds header from a list, with the given 'name_id'.
void httpmsg_destroy(http_message_t *msg)
Free memory allocated for the http message.
parse_status_t matchstr(char *str, size_t slen, const char *fmt,...)
Matches a variable parameter list with a string and takes actions based on the data type specified.
int http_SendMessage(SOCKINFO *info, int *TimeOut, const char *fmt,...)
Sends a message to the destination based on the format parameter.
SOCKET http_Connect(uri_type *destination_url, uri_type *url)
Gets destination address from URL and then connects to the remote end.
void http_CalcResponseVersion(int request_major_vers, int request_minor_vers, int *response_major_vers, int *response_minor_vers)
Calculate HTTP response versions based on the request versions.
int http_RecvMessage(SOCKINFO *info, http_parser_t *parser, http_method_t request_method, int *timeout_secs, int *http_error_code)
Get the data on the socket and take actions based on the read data to modify the parser objects buffe...
int http_MakeMessage(membuffer *buf, int http_major_version, int http_minor_version, const char *fmt,...)
Generate an HTTP message based on the format that is specified in the input parameters.
Performs HTTP read and write messages.
void membuffer_destroy(membuffer *m)
Free's memory allocated for membuffer* m.
char * str_alloc(const char *str, size_t str_len)
Allocate memory and copy information from the input string to the newly allocated memory.
Definition membuffer.cpp:56
void membuffer_init(membuffer *m)
Wrapper to membuffer_initialize().
int membuffer_append(membuffer *m, const void *buf, size_t buf_len)
Invokes function to appends data from a constant buffer to the buffer.
int memptr_cmp_nocase(memptr *m, const char *s)
Compares characters of 2 strings irrespective of the case for a specific count of bytes.
Definition membuffer.cpp:84
size_t size_inc
used to increase size; MUST be > 0; (read/write).
Definition membuffer.hpp:69
size_t length
length of buffer without terminating null byte (read-only).
Definition membuffer.hpp:65
char * buf
mem buffer; must not write beyond buf[length-1] (read/write).
Definition membuffer.hpp:63
size_t length
length of memory without terminating '\0' (read-only).
Definition membuffer.hpp:54
char * buf
start of memory (read/write).
Definition membuffer.hpp:52
pointer to a chunk of memory.
Definition membuffer.hpp:50
Maintains a block of dynamically allocated memory.
Definition membuffer.hpp:61
#define UPNP_E_SOCKET_CONNECT
The SDK had a problem connecting to a remote host.
Definition messages.hpp:209
#define UPNP_E_SUCCESS
The operation completed successfully.
Definition messages.hpp:27
#define UPNP_E_OUTOF_MEMORY
Not enough resources are currently available to complete the operation.
Definition messages.hpp:57
#define UPNP_E_INVALID_PARAM
One or more of the parameters passed to the function is not valid.
Definition messages.hpp:40
int respond_ok(SOCKINFO *info, int time_out, subscription *sub, http_message_t *request)
Returns OK message in the case of a subscription request.
int genaInitNotifyCommon(UpnpDevice_Handle device_handle, char *UDN, char *servId, DOMString propertySet, const Upnp_SID sid)
We take ownership of propertySet and will free it.
char * AllocGenaHeaders(const DOMString propertySet)
Allocates the GENA header.
void maybeDiscardEvents(LinkedList *listp)
This gets called before queuing a new event.
int genaNotify(char *headers, char *propertySet, subscription *sub)
Function to Notify a particular subscription of a particular event.
int GeneratePropertySet(char **names, char **values, int count, DOMString *out)
Generates XML property set for notifications.
int genaNotifyAllCommon(UpnpDevice_Handle device_handle, char *UDN, char *servId, DOMString propertySet)
We take ownership of propertySet and will free it.
int notify_send_and_recv(uri_type *destination_url, membuffer *mid_msg, char *propertySet, http_parser_t *response)
Sends the notify message and returns a reply.
void free_notify_struct(void *input)
Frees memory used in notify_threads if the reference count is 0, otherwise decrements the refrence co...
void genaNotifyThread(void *input)
Thread job to Notify a control point.
Function to extract header information from an http message and match the data with XML data.
subscription * GetFirstSubscription(service_info *service)
Gets pointer to the first subscription node in the service table.
subscription * GetSubscriptionSID(const Upnp_SID sid, service_info *service)
Return the subscription from the service table that matches const Upnp_SID sid value.
int copy_subscription(subscription *in, subscription *out)
Makes a copy of the subscription.
void freeServiceTable(service_table *table)
Free's dynamic memory in table (does not free table, only memory within the structure).
void freeSubscription(subscription *sub)
Free's the memory allocated for storing the URL of the subscription.
void RemoveSubscriptionSID(Upnp_SID sid, service_info *service)
Remove the subscription from the service table and update it.
void freeSubscriptionList(subscription *head)
Free's memory allocated for all the subscriptions in the service table.
subscription * GetNextSubscription(service_info *service, subscription *current)
Get current and valid subscription from the service table.
service_info * FindServiceId(service_table *table, const char *serviceId, const char *UDN)
Traverses through the service table to find a service.
int TotalSubscriptions
Part of Service information.
URL_list DeliveryURLs
Part of subscription.
int active
Part of subscription.
struct subscription * next
Part of subscription.
Upnp_SID sid
Part of subscription.
subscription * subscriptionList
Part of Service information.
DOMString UDN
Part of Service information.
DOMString serviceId
Part of Service information.
LinkedList outgoing
List of queued events for this subscription.
int ToSendEventKey
Part of subscription.
#define SID_SIZE
???
time_t expireTime
Part of subscription.
int active
Part of Service information.
device subscriptions
-brief Service information
int sock_destroy(SOCKINFO *info, int ShutdownMethod)
Shutsdown the socket using the ShutdownMethod to indicate whether sends and receives on the socket wi...
Definition sock.cpp:489
int sock_init(SOCKINFO *info, SOCKET sockfd)
Assign the passed in socket descriptor to socket descriptor in the SOCKINFO structure.
Definition sock.cpp:440
sockaddr_storage foreign_sockaddr
Socket address of the remote node only filled in incoming requests.
Definition sock.hpp:69
Additional socket information for connections and ssl.
Definition sock.hpp:65
Manage "Step 1: Discovery" of the UPnP+™ specification with SSDP.
HTTP status codes.
Unix-specific network utilities.
unsigned gIF_IPV6_ULA_GUA_PREFIX_LENGTH
IPv6 GUA prefix length. (extern'ed in upnp.h)
Definition upnpapi.cpp:147
Upnp_Handle_Type GetHandleInfo(UpnpClient_Handle Hnd, Handle_Info **HndInfo)
Get handle information.
Definition upnpapi.cpp:3339
ThreadPool gSendThreadPool
Send thread pool.
Definition upnpapi.cpp:111
char gIF_IPV6_ULA_GUA[INET6_ADDRSTRLEN]
IPv6 GUA buffer to contain interface IPv6 global-unicast address.
Definition upnpapi.cpp:145
Upnp_Handle_Type GetDeviceHandleInfoForPath(const char *path, int AddressFamily, UpnpDevice_Handle *device_handle_out, struct Handle_Info **HndInfo, service_info **serv_info)
Retrieves the device handle and information of the first device of the address family specified,...
Definition upnpapi.cpp:3302
unsigned gIF_IPV6_PREFIX_LENGTH
IPv6 LLA prefix length. (extern'ed in upnp.h)
Definition upnpapi.cpp:140
int g_UpnpSdkEQMaxLen
Global variable to determines the maximum number of events.
Definition upnpapi.cpp:174
char gIF_IPV4[INET_ADDRSTRLEN]
IPv4 buffer to contain interface address. (extern'ed in upnp.h)
Definition upnpapi.cpp:152
char gIF_IPV4_NETMASK[INET_ADDRSTRLEN]
IPv4 buffer to contain interface netmask. (extern'ed in upnp.h)
Definition upnpapi.cpp:154
int g_UpnpSdkEQMaxAge
Global variable to determine the maximum number of seconds which an event can spend on a subscription...
Definition upnpapi.cpp:185
char gIF_IPV6[INET6_ADDRSTRLEN]
IPv6 LLA buffer to contain interface address. (extern'ed in upnp.h)
Definition upnpapi.cpp:138
Inititalize the compatible library before it can be used.
#define HandleLock()
HandleLock.
Definition upnpapi.hpp:140
service_table ServiceTable
Table holding subscriptions and URL information.
Definition upnpapi.hpp:110
#define UPNP_TIMEOUT
UPNP_TIMEOUT.
Definition upnpapi.hpp:73
#define HandleUnlock()
HandleUnlock.
Definition upnpapi.hpp:149
char * Cookie
???
Definition upnpapi.hpp:89
Upnp_FunPtr Callback
Callback function pointer.
Definition upnpapi.hpp:88
int MaxSubscriptionTimeOut
???
Definition upnpapi.hpp:112
int MaxSubscriptions
???
Definition upnpapi.hpp:111
Data to be stored in handle table for Handle Info.
Definition upnpapi.hpp:86
UPnPsdk_VIS void UpnpPrintf(Upnp_LogLevel DLevel, Dbg_Module Module, const char *DbgFileName, int DbgLineNo, const char *FmtStr,...)
Prints the debug statement.
Manage UUIDs.
void upnp_uuid_unpack(uuid_upnp *u, char *out)
Unpack a UUID.
Definition uuid.cpp:242
int uuid_create(uuid_upnp *uid)
Generate a UUID.
Definition uuid.cpp:211
uuid UPNP
Definition uuid.hpp:42