UPnPsdk 0.1
Universal Plug and Play +, Software Development Kit
 
Loading...
Searching...
No Matches
gena_ctrlpt.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 <gena.hpp>
41#include <client_table.hpp>
42#include <httpreadwrite.hpp>
43#include <parsetools.hpp>
44#include <statcodes.hpp>
45#include <upnpapi.hpp>
46#include <uuid.hpp>
47
48struct job_arg {
49 int handle;
50 int eventId;
51 void* Event;
52};
53
54namespace {
55
58pthread_mutex_t ctrlpntSubscribe_mutex{};
59
63void free_subscribe_arg(void* arg) {
64 if (arg) {
65 job_arg* p = (job_arg*)arg;
66 if (p->Event) {
68 }
69 free(p);
70 }
71}
72
79 void* input) {
80 job_arg* arg = (job_arg*)input;
81 UpnpEventSubscribe* sub_struct = (UpnpEventSubscribe*)arg->Event;
82 void* cookie;
83 Upnp_FunPtr callback_fun;
84 struct Handle_Info* handle_info;
85 int send_callback = 0;
86 Upnp_EventType eventType{};
87 int timeout = 0;
88 int errCode = 0;
89
90 if constexpr (AUTO_RENEW_TIME == 0) {
91 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA SUB EXPIRED\n");
93 send_callback = 1;
95 } else {
96 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA AUTO RENEW\n");
97 timeout = UpnpEventSubscribe_get_TimeOut(sub_struct);
98 errCode = genaRenewSubscription(
99 arg->handle, UpnpEventSubscribe_get_SID(sub_struct), &timeout);
100 UpnpEventSubscribe_set_ErrCode(sub_struct, errCode);
101 UpnpEventSubscribe_set_TimeOut(sub_struct, timeout);
102 if (errCode != UPNP_E_SUCCESS && errCode != GENA_E_BAD_SID &&
103 errCode != GENA_E_BAD_HANDLE) {
104 send_callback = 1;
106 }
107 }
108
109 if (send_callback) {
111 if (GetHandleInfo(arg->handle, &handle_info) != HND_CLIENT) {
112 HandleUnlock();
114 goto end_function;
115 }
116 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "HANDLE IS VALID\n");
117
118 /* make callback */
119 callback_fun = handle_info->Callback;
120 cookie = handle_info->Cookie;
121 HandleUnlock();
122 callback_fun((Upnp_EventType)eventType, arg->Event, cookie);
123 }
124
126
127end_function:
128 return;
129}
130
139 int client_handle,
141 int TimeOut,
144 UpnpEventSubscribe* RenewEvent = NULL;
145 job_arg* arg = NULL;
146 int return_code = GENA_SUCCESS;
147 ThreadPoolJob job;
148
149 memset(&job, 0, sizeof(job));
150
151 if (TimeOut == UPNP_INFINITE) {
152 return_code = GENA_SUCCESS;
153 goto end_function;
154 }
155
156 RenewEvent = UpnpEventSubscribe_new();
157 if (RenewEvent == NULL) {
158 return_code = UPNP_E_OUTOF_MEMORY;
159 goto end_function;
160 }
161
162 arg = (job_arg*)malloc(sizeof(job_arg));
163 if (arg == NULL) {
164 free(RenewEvent);
165 return_code = UPNP_E_OUTOF_MEMORY;
166 goto end_function;
167 }
168 memset(arg, 0, sizeof(job_arg));
169
170 /* schedule expire event */
172 UpnpEventSubscribe_set_TimeOut(RenewEvent, TimeOut);
177
178 arg->handle = client_handle;
179 arg->Event = RenewEvent;
180
181 TPJobInit(&job, (UPnPsdk::start_routine)GenaAutoRenewSubscription, arg);
183 TPJobSetPriority(&job, MED_PRIORITY);
184
185 /* Schedule the job */
186 return_code =
188 &job, SHORT_TERM, &(arg->eventId));
189 if (return_code != UPNP_E_SUCCESS) {
191 goto end_function;
192 }
193
195
196 return_code = GENA_SUCCESS;
197
198end_function:
199
200 return return_code;
201}
202
211 const UpnpString* url,
213 const UpnpString* sid,
215 http_parser_t* response) {
216 int return_code;
217 uri_type dest_url;
218 membuffer request;
219
220 /* parse url */
221 return_code = http_FixStrUrl(UpnpString_get_String(url),
222 UpnpString_get_Length(url), &dest_url);
223 if (return_code != 0) {
224 return return_code;
225 }
226
227 /* make request msg */
228 membuffer_init(&request);
229 request.size_inc = 30;
230 return_code = http_MakeMessage(&request, 1, 1,
231 "q"
232 "ssc"
233 "Uc",
234 HTTPMETHOD_UNSUBSCRIBE, &dest_url,
235 "SID: ", UpnpString_get_String(sid));
236
237 /* Not able to make the message so destroy the existing buffer */
238 if (return_code != 0) {
239 membuffer_destroy(&request);
240
241 return return_code;
242 }
243
244 /* send request and get reply */
245 return_code = http_RequestAndResponse(
246 &dest_url, request.buf, request.length, HTTPMETHOD_UNSUBSCRIBE,
247 HTTP_DEFAULT_TIMEOUT, response);
248 membuffer_destroy(&request);
249 if (return_code != 0) {
250 httpmsg_destroy(&response->msg);
251 }
252
253 if (return_code == 0 && response->msg.status_code != HTTP_OK) {
254 return_code = UPNP_E_UNSUBSCRIBE_UNACCEPTED;
255 httpmsg_destroy(&response->msg);
256 }
257
258 return return_code;
259}
260
268 const UpnpString* url,
270 int* timeout,
273 const UpnpString* renewal_sid,
275 UpnpString* sid) {
276 int return_code;
277 parse_status_t parse_ret{};
278 int local_timeout = CP_MINIMUM_SUBSCRIPTION_TIME;
279 memptr sid_hdr;
280 memptr timeout_hdr;
281 char timeout_str[25];
282 membuffer request;
283 uri_type dest_url;
284 http_parser_t response;
285 int rc = 0;
286
287 UpnpString_clear(sid);
288
289 /* request timeout to string */
290 if (timeout == NULL) {
291 timeout = &local_timeout;
292 }
293 if (*timeout < 0) {
294 memset(timeout_str, 0, sizeof(timeout_str));
295 strncpy(timeout_str, "infinite", sizeof(timeout_str) - 1);
296 } else if (*timeout < CP_MINIMUM_SUBSCRIPTION_TIME) {
297 rc = snprintf(timeout_str, sizeof(timeout_str), "%d",
299 } else {
300 rc = snprintf(timeout_str, sizeof(timeout_str), "%d", *timeout);
301 }
302 if (rc < 0 || (unsigned int)rc >= sizeof(timeout_str))
303 return UPNP_E_OUTOF_MEMORY;
304
305 /* parse url */
306 return_code = http_FixStrUrl(UpnpString_get_String(url),
307 UpnpString_get_Length(url), &dest_url);
308 if (return_code != 0) {
309 return return_code;
310 }
311
312 /* make request msg */
313 membuffer_init(&request);
314 request.size_inc = 30;
315 if (renewal_sid) {
316 /* renew subscription */
317 return_code =
318 http_MakeMessage(&request, 1, 1,
319 "q"
320 "ssc"
321 "sscc",
322 HTTPMETHOD_SUBSCRIBE, &dest_url,
323 "SID: ", UpnpString_get_String(renewal_sid),
324 "TIMEOUT: Second-", timeout_str);
325 } else {
326 /* subscribe */
327 if (dest_url.hostport.IPaddress.ss_family == AF_INET6) {
328 struct sockaddr_in6* DestAddr6 =
329 (struct sockaddr_in6*)&dest_url.hostport.IPaddress;
330 return_code = http_MakeMessage(
331 &request, 1, 1,
332 "q"
333 "sssdsc"
334 "sc"
335 "sscc",
336 HTTPMETHOD_SUBSCRIBE, &dest_url, "CALLBACK: <http://[",
337 (IN6_IS_ADDR_LINKLOCAL(&DestAddr6->sin6_addr) ||
338 strlen(gIF_IPV6_ULA_GUA) == 0)
339 ? gIF_IPV6
341 "]:",
342 (IN6_IS_ADDR_LINKLOCAL(&DestAddr6->sin6_addr) ||
343 strlen(gIF_IPV6_ULA_GUA) == 0)
346 "/>", "NT: upnp:event", "TIMEOUT: Second-", timeout_str);
347 } else {
348 return_code = http_MakeMessage(
349 &request, 1, 1,
350 "q"
351 "sssdsc"
352 "sc"
353 "sscc",
354 HTTPMETHOD_SUBSCRIBE, &dest_url, "CALLBACK: <http://", gIF_IPV4,
355 ":", LOCAL_PORT_V4, "/>", "NT: upnp:event", "TIMEOUT: Second-",
356 timeout_str);
357 }
358 }
359 if (return_code != 0) {
360 return return_code;
361 }
362
363 /* send request and get reply */
364 return_code = http_RequestAndResponse(&dest_url, request.buf,
365 request.length, HTTPMETHOD_SUBSCRIBE,
366 HTTP_DEFAULT_TIMEOUT, &response);
367 membuffer_destroy(&request);
368
369 if (return_code != 0) {
370 httpmsg_destroy(&response.msg);
371
372 return return_code;
373 }
374 if (response.msg.status_code != HTTP_OK) {
375 httpmsg_destroy(&response.msg);
376
378 }
379
380 /* get SID and TIMEOUT */
381 if (httpmsg_find_hdr(&response.msg, HDR_SID, &sid_hdr) == NULL ||
382 sid_hdr.length == 0 ||
383 httpmsg_find_hdr(&response.msg, HDR_TIMEOUT, &timeout_hdr) == NULL ||
384 timeout_hdr.length == 0) {
385 httpmsg_destroy(&response.msg);
386
387 return UPNP_E_BAD_RESPONSE;
388 }
389
390 /* save timeout */
391 parse_ret =
392 matchstr(timeout_hdr.buf, timeout_hdr.length, "%iSecond-%d%0", timeout);
393 if (parse_ret == PARSE_OK) {
394 /* nothing to do */
395 } else if (memptr_cmp_nocase(&timeout_hdr, "Second-infinite") == 0) {
396 *timeout = -1;
397 } else {
398 httpmsg_destroy(&response.msg);
399
400 return UPNP_E_BAD_RESPONSE;
401 }
402
403 /* save SID */
404 UpnpString_set_StringN(sid, sid_hdr.buf, sid_hdr.length);
405 if (UpnpString_get_String(sid) == NULL) {
406 httpmsg_destroy(&response.msg);
407
408 return UPNP_E_OUTOF_MEMORY;
409 }
410 httpmsg_destroy(&response.msg);
411
412 return UPNP_E_SUCCESS;
413}
414
415} // namespace
416
418 pthread_mutexattr_t attr;
419
420 int ret = pthread_mutexattr_init(&attr);
421 if (ret != 0)
422 return ret;
423 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
424 pthread_mutex_init(&ctrlpntSubscribe_mutex, &attr);
425 pthread_mutexattr_destroy(&attr);
426 return 0;
427}
428
430 return pthread_mutex_destroy(&ctrlpntSubscribe_mutex);
431}
432
435 int return_code = UPNP_E_SUCCESS;
436 struct Handle_Info* handle_info = NULL;
437 http_parser_t response;
438
439 while (1) {
440 HandleLock();
441
442 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
443 HandleUnlock();
444 return_code = GENA_E_BAD_HANDLE;
445 goto exit_function;
446 }
447 if (handle_info->ClientSubList == NULL) {
448 return_code = UPNP_E_SUCCESS;
449 break;
450 }
451 GenlibClientSubscription_assign(sub_copy, handle_info->ClientSubList);
454
455 HandleUnlock();
456
457 return_code = gena_unsubscribe(
459 GenlibClientSubscription_get_ActualSID(sub_copy), &response);
460 if (return_code == 0) {
461 httpmsg_destroy(&response.msg);
462 }
463 free_client_subscription(sub_copy);
464 }
465
466 freeClientSubList(handle_info->ClientSubList);
467 HandleUnlock();
468
469exit_function:
471 return return_code;
472}
473
474int genaUnSubscribe(UpnpClient_Handle client_handle, const UpnpString* in_sid) {
475 GenlibClientSubscription* sub = NULL;
476 int return_code = GENA_SUCCESS;
477 struct Handle_Info* handle_info;
479 http_parser_t response;
480
481 /* validate handle and sid */
482 HandleLock();
483 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
484 HandleUnlock();
485 return_code = GENA_E_BAD_HANDLE;
486 goto exit_function;
487 }
488 sub = GetClientSubClientSID(handle_info->ClientSubList, in_sid);
489 if (sub == NULL) {
490 HandleUnlock();
491 return_code = GENA_E_BAD_SID;
492 goto exit_function;
493 }
494 GenlibClientSubscription_assign(sub_copy, sub);
495 HandleUnlock();
496
497 return_code = gena_unsubscribe(
499 GenlibClientSubscription_get_ActualSID(sub_copy), &response);
500 if (return_code == 0) {
501 httpmsg_destroy(&response.msg);
502 }
503 free_client_subscription(sub_copy);
504
505 HandleLock();
506 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
507 HandleUnlock();
508 return_code = GENA_E_BAD_HANDLE;
509 goto exit_function;
510 }
511 RemoveClientSubClientSID(&handle_info->ClientSubList, in_sid);
512 HandleUnlock();
513
514exit_function:
516 return return_code;
517}
518
520 const UpnpString* PublisherURL, int* TimeOut,
521 UpnpString* out_sid) {
522 int return_code = GENA_SUCCESS;
524 uuid_upnp uid;
525 Upnp_SID temp_sid;
526 Upnp_SID temp_sid2;
527 UpnpString* ActualSID = UpnpString_new();
528 UpnpString* EventURL = UpnpString_new();
529 struct Handle_Info* handle_info;
530 int rc = 0;
531
532 memset(temp_sid, 0, sizeof(temp_sid));
533 memset(temp_sid2, 0, sizeof(temp_sid2));
534
535 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA SUBSCRIBE BEGIN\n");
536
537 UpnpString_clear(out_sid);
538
540 /* validate handle */
541 int ret;
542 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
543 return_code = GENA_E_BAD_HANDLE;
544 ret = pthread_mutex_lock(&ctrlpntSubscribe_mutex);
545 if (ret != 0)
546 UPnPsdk_LOGCRIT("MSG1099") "POSIX thread mutex lock fails with "
547 << (ret == EINVAL ? "EINVAL" : "EDEADLK") << ".\n";
548 goto error_handler;
549 }
550 HandleUnlock();
551
552 /* subscribe */
553 ret = pthread_mutex_lock(&ctrlpntSubscribe_mutex);
554 if (ret != 0)
555 UPnPsdk_LOGCRIT("MSG1138") "POSIX thread mutex lock fails with "
556 << (ret == EINVAL ? "EINVAL" : "EDEADLK") << ".\n";
557 return_code = gena_subscribe(PublisherURL, TimeOut, NULL, ActualSID);
558 HandleLock();
559 if (return_code != UPNP_E_SUCCESS) {
560 UpnpPrintf(UPNP_CRITICAL, GENA, __FILE__, __LINE__,
561 "SUBSCRIBE FAILED in transfer error code: %d "
562 "returned\n",
563 return_code);
564 goto error_handler;
565 }
566
567 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
568 return_code = GENA_E_BAD_HANDLE;
569 goto error_handler;
570 }
571
572 /* generate client SID */
573 uuid_create(&uid);
574 upnp_uuid_unpack(&uid, temp_sid);
575 rc = snprintf(temp_sid2, sizeof(temp_sid2), "uuid:%s", temp_sid);
576 if (rc < 0 || (unsigned int)rc >= sizeof(temp_sid2)) {
577 return_code = UPNP_E_OUTOF_MEMORY;
578 goto error_handler;
579 }
580 UpnpString_set_String(out_sid, temp_sid2);
581
582 /* create event url */
583 UpnpString_assign(EventURL, PublisherURL);
584
585 /* fill subscription */
586 if (newSubscription == NULL) {
587 return_code = UPNP_E_OUTOF_MEMORY;
588 goto error_handler;
589 }
591 GenlibClientSubscription_set_SID(newSubscription, out_sid);
592 GenlibClientSubscription_set_ActualSID(newSubscription, ActualSID);
593 GenlibClientSubscription_set_EventURL(newSubscription, EventURL);
594 GenlibClientSubscription_set_Next(newSubscription,
595 handle_info->ClientSubList);
596 handle_info->ClientSubList = newSubscription;
597
598 /* schedule expiration event */
599 return_code =
600 ScheduleGenaAutoRenew(client_handle, *TimeOut, newSubscription);
601
602error_handler:
603 UpnpString_delete(ActualSID);
604 UpnpString_delete(EventURL);
605 if (return_code != UPNP_E_SUCCESS)
606 GenlibClientSubscription_delete(newSubscription);
607 HandleUnlock();
608 ret = pthread_mutex_unlock(&ctrlpntSubscribe_mutex);
609 if (ret != 0)
610 UPnPsdk_LOGCRIT("MSG1139") "POSIX thread mutex unlock fails with "
611 << (ret == EINVAL ? "EINVAL" : "EPERM") << ".\n";
612
613 return return_code;
614}
615
617 const UpnpString* in_sid, int* TimeOut) {
618 int return_code = GENA_SUCCESS;
619 GenlibClientSubscription* sub = NULL;
621 struct Handle_Info* handle_info;
622 UpnpString* ActualSID = UpnpString_new();
623 ThreadPoolJob tempJob;
624
625 HandleLock();
626
627 /* validate handle and sid */
628 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
629 HandleUnlock();
630
631 return_code = GENA_E_BAD_HANDLE;
632 goto exit_function;
633 }
634
635 sub = GetClientSubClientSID(handle_info->ClientSubList, in_sid);
636 if (sub == NULL) {
637 HandleUnlock();
638
639 return_code = GENA_E_BAD_SID;
640 goto exit_function;
641 }
642
643 /* remove old events */
646 &tempJob) == 0) {
647 tempJob.free_func(tempJob.arg);
648 }
649
650 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
651 "REMOVED AUTO RENEW EVENT\n");
652
654 GenlibClientSubscription_assign(sub_copy, sub);
655
656 HandleUnlock();
657
658 return_code = gena_subscribe(
659 GenlibClientSubscription_get_EventURL(sub_copy), TimeOut,
660 GenlibClientSubscription_get_ActualSID(sub_copy), ActualSID);
661
662 HandleLock();
663
664 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
665 HandleUnlock();
666 return_code = GENA_E_BAD_HANDLE;
667 goto exit_function;
668 }
669
670 /* we just called GetHandleInfo, so we don't check for return value */
671 /*GetHandleInfo(client_handle, &handle_info); */
672 if (return_code != UPNP_E_SUCCESS) {
673 /* network failure (remove client sub) */
674 RemoveClientSubClientSID(&handle_info->ClientSubList, in_sid);
675 free_client_subscription(sub_copy);
676 HandleUnlock();
677 goto exit_function;
678 }
679
680 /* get subscription */
681 sub = GetClientSubClientSID(handle_info->ClientSubList, in_sid);
682 if (sub == NULL) {
683 free_client_subscription(sub_copy);
684 HandleUnlock();
685 return_code = GENA_E_BAD_SID;
686 goto exit_function;
687 }
688
689 /* store actual sid */
691
692 /* start renew subscription timer */
693 return_code = ScheduleGenaAutoRenew(client_handle, *TimeOut, sub);
694 if (return_code != GENA_SUCCESS) {
697 }
698 free_client_subscription(sub_copy);
699 HandleUnlock();
700
701exit_function:
702 UpnpString_delete(ActualSID);
704 return return_code;
705}
706
708 UpnpEvent* event_struct = UpnpEvent_new();
709 IXML_Document* ChangedVars = NULL;
710 int eventKey;
711 token sid;
713 struct Handle_Info* handle_info;
714 void* cookie;
715 Upnp_FunPtr callback;
716 UpnpClient_Handle client_handle;
717 UpnpClient_Handle client_handle_start;
718 int err_ret = HTTP_PRECONDITION_FAILED;
719
720 memptr sid_hdr;
721 memptr nt_hdr, nts_hdr;
722 memptr seq_hdr;
723
724 /* get SID */
725 if (httpmsg_find_hdr(event, HDR_SID, &sid_hdr) == NULL) {
726 error_respond(info, HTTP_PRECONDITION_FAILED, event);
727 goto exit_function;
728 }
729 sid.buff = sid_hdr.buf;
730 sid.size = sid_hdr.length;
731
732 /* get event key */
733 if (httpmsg_find_hdr(event, HDR_SEQ, &seq_hdr) == NULL ||
734 matchstr(seq_hdr.buf, seq_hdr.length, "%d%0", &eventKey) != PARSE_OK) {
735 error_respond(info, HTTP_BAD_REQUEST, event);
736 goto exit_function;
737 }
738
739 /* get NT and NTS headers */
740 if (httpmsg_find_hdr(event, HDR_NT, &nt_hdr) == NULL ||
741 httpmsg_find_hdr(event, HDR_NTS, &nts_hdr) == NULL) {
742 error_respond(info, HTTP_BAD_REQUEST, event);
743 goto exit_function;
744 }
745
746 /* verify NT and NTS headers */
747 if (memptr_cmp(&nt_hdr, "upnp:event") != 0 ||
748 memptr_cmp(&nts_hdr, "upnp:propchange") != 0) {
749 error_respond(info, HTTP_PRECONDITION_FAILED, event);
750 goto exit_function;
751 }
752
753 /* parse the content (should be XML) */
754 if (!has_xml_content_type(event) || event->msg.length == 0 ||
755 ixmlParseBufferEx(event->entity.buf, &ChangedVars) != IXML_SUCCESS) {
756 error_respond(info, HTTP_BAD_REQUEST, event);
757 goto exit_function;
758 }
759
760 HandleLock();
761
762 /* get client info */
763 if (GetClientHandleInfo(&client_handle_start, &handle_info) != HND_CLIENT) {
764 error_respond(info, HTTP_PRECONDITION_FAILED, event);
765 HandleUnlock();
766 goto exit_function;
767 }
768
769 HandleUnlock();
770
771 for (client_handle = client_handle_start; client_handle < NUM_HANDLE;
772 client_handle++) {
773 HandleLock();
774
775 /* get client info */
776 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
777 HandleUnlock();
778 continue;
779 }
780
781 /* get subscription based on SID */
783 if (subscription == NULL) {
784 if (eventKey == 0) {
785 /* wait until we've finished processing a
786 * subscription */
787 /* (if we are in the middle) */
788 /* this is to avoid mistakenly rejecting the
789 * first event if we */
790 /* receive it before the subscription response
791 */
792 HandleUnlock();
793
794 /* try and get Subscription Lock */
795 /* (in case we are in the process of
796 * subscribing) */
797 int ret = pthread_mutex_lock(&ctrlpntSubscribe_mutex);
798 if (ret != 0)
799 UPnPsdk_LOGCRIT(
800 "MSG1140") "POSIX thread mutex lock fails with "
801 << (ret == EINVAL ? "EINVAL" : "EDEADLK") << ".\n";
802
803 /* get HandleLock again */
804 HandleLock();
805
806 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
807 ret = pthread_mutex_unlock(&ctrlpntSubscribe_mutex);
808 if (ret != 0)
809 UPnPsdk_LOGCRIT(
810 "MSG1141") "POSIX thread mutex unlock fails with "
811 << (ret == EINVAL ? "EINVAL" : "EPERM") << ".\n";
812 HandleUnlock();
813 continue;
814 }
815
817 GetClientSubActualSID(handle_info->ClientSubList, &sid);
818 if (subscription == NULL) {
819 ret = pthread_mutex_unlock(&ctrlpntSubscribe_mutex);
820 if (ret != 0)
821 UPnPsdk_LOGCRIT(
822 "MSG1142") "POSIX thread mutex unlock fails with "
823 << (ret == EINVAL ? "EINVAL" : "EPERM") << ".\n";
824 HandleUnlock();
825 continue;
826 }
827
828 ret = pthread_mutex_unlock(&ctrlpntSubscribe_mutex);
829 if (ret != 0)
830 UPnPsdk_LOGCRIT(
831 "MSG1143") "POSIX thread mutex unlock fails with "
832 << (ret == EINVAL ? "EINVAL" : "EPERM") << ".\n";
833 } else {
834 HandleUnlock();
835 continue;
836 }
837 }
838
839 /* success */
840 err_ret = HTTP_OK;
841
842 /* fill event struct */
843 UpnpEvent_set_EventKey(event_struct, eventKey);
844 UpnpEvent_set_ChangedVariables(event_struct, ChangedVars);
845 UpnpEvent_set_SID(event_struct,
847
848 /* copy callback */
849 callback = handle_info->Callback;
850 cookie = handle_info->Cookie;
851
852 HandleUnlock();
853
854 /* make callback with event struct */
855 /* In future, should find a way of mainting */
856 /* that the handle is not unregistered in the middle of a */
857 /* callback */
858 callback(UPNP_EVENT_RECEIVED, event_struct, cookie);
859 }
860
861 error_respond(info, err_ret, event);
862
863exit_function:
864 ixmlDocument_free(ChangedVars);
865 UpnpEvent_delete(event_struct);
866}
enum Upnp_EventType_e Upnp_EventType
Old C stile quirks to make a symbol protected. Look at Upnp_EventType_e.
Definition Callback.hpp:120
@ UPNP_EVENT_AUTORENEWAL_FAILED
Definition Callback.hpp:108
@ UPNP_EVENT_SUBSCRIPTION_EXPIRED
Definition Callback.hpp:113
@ UPNP_EVENT_RECEIVED
Definition Callback.hpp:88
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 UpnpClient_Handle
Returned when a control point application registers with UpnpRegisterClient().
Definition API.hpp:412
#define UPNP_INFINITE
Definition API.hpp:51
http_message_t msg
entire raw message
memptr entity
message body(entity).
#define HDR_NT
Type of a HTTP header.
#define HDR_NTS
Type of a HTTP header.
membuffer msg
entire raw message.
#define HDR_SEQ
Type of a HTTP header.
parse_status_t
Status of parsing.
@ PARSE_OK
#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.
int GenlibClientSubscription_set_RenewEventId(GenlibClientSubscription *p, int n)
int GenlibClientSubscription_set_ActualSID(GenlibClientSubscription *p, const UpnpString *s)
int GenlibClientSubscription_set_Next(GenlibClientSubscription *p, GenlibClientSubscription *n)
int GenlibClientSubscription_set_EventURL(GenlibClientSubscription *p, const UpnpString *s)
const UpnpString * GenlibClientSubscription_get_ActualSID(const GenlibClientSubscription *p)
GenlibClientSubscription * GenlibClientSubscription_new()
int GenlibClientSubscription_set_SID(GenlibClientSubscription *p, const UpnpString *s)
int GenlibClientSubscription_assign(GenlibClientSubscription *p, const GenlibClientSubscription *q)
const UpnpString * GenlibClientSubscription_get_EventURL(const GenlibClientSubscription *p)
const UpnpString * GenlibClientSubscription_get_SID(const GenlibClientSubscription *p)
int GenlibClientSubscription_get_RenewEventId(const GenlibClientSubscription *p)
void GenlibClientSubscription_delete(GenlibClientSubscription *q)
Genlib Client subscription.
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.
int TimerThreadSchedule(TimerThread *timer, time_t timeout, TimeoutType type, ThreadPoolJob *job, Duration duration, int *id)
Schedules an event to run at a specified time.
int TimerThreadRemove(TimerThread *timer, int id, ThreadPoolJob *out)
Removes an event from the timer Q.
@ REL_SEC
seconds from current time.
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
sockaddr_storage IPaddress
Network socket address.
Definition uri.hpp:58
Represents a URI used in parse_uri and elsewhere.
Definition uri.hpp:64
Buffer used in parsing http messages, urls, etc. Generally this simply holds a pointer into a larger ...
Definition uri.hpp:48
s_UpnpEventSubscribe
PUPNP_Api int UpnpEventSubscribe_set_ErrCode(UpnpEventSubscribe *p, int n)
PUPNP_Api UpnpEventSubscribe * UpnpEventSubscribe_new(void)
PUPNP_Api int UpnpEventSubscribe_set_SID(UpnpEventSubscribe *p, const UpnpString *s)
PUPNP_Api const UpnpString * UpnpEventSubscribe_get_SID(const UpnpEventSubscribe *p)
PUPNP_Api int UpnpEventSubscribe_get_TimeOut(const UpnpEventSubscribe *p)
PUPNP_Api int UpnpEventSubscribe_set_TimeOut(UpnpEventSubscribe *p, int n)
PUPNP_Api void UpnpEventSubscribe_delete(UpnpEventSubscribe *p)
PUPNP_Api int UpnpEventSubscribe_set_PublisherUrl(UpnpEventSubscribe *p, const UpnpString *s)
s_UpnpEvent
Definition UpnpEvent.cpp:16
PUPNP_Api UpnpEvent * UpnpEvent_new(void)
Definition UpnpEvent.cpp:25
PUPNP_Api int UpnpEvent_set_EventKey(UpnpEvent *p, int n)
Definition UpnpEvent.cpp:78
PUPNP_Api int UpnpEvent_set_ChangedVariables(UpnpEvent *p, IXML_Document *n)
Definition UpnpEvent.cpp:88
PUPNP_Api int UpnpEvent_set_SID(UpnpEvent *p, const UpnpString *s)
Definition UpnpEvent.cpp:96
PUPNP_Api void UpnpEvent_delete(UpnpEvent *p)
Definition UpnpEvent.cpp:38
void free_client_subscription(GenlibClientSubscription *sub)
Free memory allocated for client subscription data.
GenlibClientSubscription * GetClientSubClientSID(GenlibClientSubscription *head, const UpnpString *sid)
Return the client subscription from the client table that matches const Upnp_SID sid subscrition id v...
void RemoveClientSubClientSID(GenlibClientSubscription **head, const UpnpString *sid)
Remove the client subscription matching the subscritpion id represented by the const Upnp_SID sid par...
void freeClientSubList(GenlibClientSubscription *list)
Free the client subscription table.
GenlibClientSubscription * GetClientSubActualSID(GenlibClientSubscription *head, token *sid)
Returns the client subscription from the client subscription table that has the matching token *sid b...
#define AUTO_RENEW_TIME
The AUTO_RENEW_TIME is the time, in seconds, before a subscription expires that the SDK automatically...
Definition config.hpp:174
#define CP_MINIMUM_SUBSCRIPTION_TIME
The CP_MINIMUM_SUBSCRIPTION_TIME is the minimum subscription time allowed for a control point using t...
Definition config.hpp:183
Manage Eventing with GENA, the General Event Notification Architecture.
#define GENA_E_BAD_HANDLE
Definition gena.hpp:79
#define GENA_SUCCESS
Definition gena.hpp:83
#define GENA_E_BAD_SID
Definition gena.hpp:75
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.
int clientSubscribeMutexInit()
Initialize the client subsribe mutex.
int genaUnregisterClient(UpnpClient_Handle client_handle)
Unsubcribes all the outstanding subscriptions and cleans the subscription list.
void gena_process_notification_event(SOCKINFO *info, http_message_t *event)
This function processes NOTIFY events that are sent by devices.
int genaUnSubscribe(UpnpClient_Handle client_handle, const UpnpString *in_sid)
Unsubscribes a SID.
int genaSubscribe(UpnpClient_Handle client_handle, const UpnpString *PublisherURL, int *TimeOut, UpnpString *out_sid)
This function subscribes to a PublisherURL (also mentioned as EventURL in some places).
int clientSubscribeMutexDestroy()
Destroy the client subsribe mutex.
int genaRenewSubscription(UpnpClient_Handle client_handle, const UpnpString *in_sid, int *TimeOut)
Renews a SID.
job_arg
Definition upnpapi.cpp:216
Internal implementation of the class UpnpString.
PUPNP_Api int UpnpString_set_StringN(UpnpString *p, const char *s, size_t n)
Sets the string from a pointer to char using a maximum of N chars.
PUPNP_Api int UpnpString_set_String(UpnpString *p, const char *s)
Sets the string from a pointer to char.
PUPNP_Api size_t UpnpString_get_Length(const UpnpString *p)
Returns the length of the string.
PUPNP_Api UpnpString * UpnpString_new(void)
Constructor.
PUPNP_Api const char * UpnpString_get_String(const UpnpString *p)
Returns the pointer to char.
PUPNP_Api void UpnpString_delete(UpnpString *p)
Destructor.
PUPNP_Api void UpnpString_assign(UpnpString *p, const UpnpString *q)
Assignment operator.
PUPNP_Api void UpnpString_clear(UpnpString *p)
Clears the string, sets its size to zero.
Data structure representing the DOM Document.
Definition ixml.hpp:155
PUPNP_Api int ixmlParseBufferEx(const char *buffer, IXML_Document **doc)
Parses an XML text buffer converting it into an IXML DOM representation.
Definition ixml.cpp:396
PUPNP_Api void ixmlDocument_free(IXML_Document *doc)
Frees a Document object and all Nodes associated with it.
Definition document.cpp:49
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_RequestAndResponse(uri_type *destination, const char *request, size_t request_length, http_method_t req_method, int timeout_secs, http_parser_t *response)
Initiates socket, connects to the remote host, sends a request and waits for the response from the re...
int http_FixStrUrl(const char *urlstr, size_t urlstrlen, uri_type *fixed_url)
Parses URL and then validates URL.
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.
#define HTTP_DEFAULT_TIMEOUT
int memptr_cmp(memptr *m, const char *s)
Compares characters of strings passed for number of bytes. If equal for the number of bytes,...
Definition membuffer.cpp:70
void membuffer_destroy(membuffer *m)
Free's memory allocated for membuffer* m.
void membuffer_init(membuffer *m)
Wrapper to membuffer_initialize().
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_SUCCESS
The operation completed successfully.
Definition messages.hpp:27
#define UPNP_E_SUBSCRIBE_UNACCEPTED
A subscription request was rejected from the remote side.
Definition messages.hpp:269
#define UPNP_E_OUTOF_MEMORY
Not enough resources are currently available to complete the operation.
Definition messages.hpp:57
#define UPNP_E_UNSUBSCRIBE_UNACCEPTED
An unsubscribe request was rejected from the remote side.
Definition messages.hpp:274
#define UPNP_E_BAD_RESPONSE
The response received from the remote side of a connection is not correct for the protocol.
Definition messages.hpp:103
void GenaAutoRenewSubscription(void *input)
This is a thread function to send the renewal just before the subscription times out.
void free_subscribe_arg(void *arg)
Free memory associated with job's argument.
int ScheduleGenaAutoRenew(int client_handle, int TimeOut, GenlibClientSubscription *sub)
Schedules a job to renew the subscription just before time out.
int gena_subscribe(const UpnpString *url, int *timeout, const UpnpString *renewal_sid, UpnpString *sid)
Subscribes or renew subscription.
pthread_mutex_t ctrlpntSubscribe_mutex
Mutex to synchronize the subscription handling at the control point side.
int gena_unsubscribe(const UpnpString *url, const UpnpString *sid, http_parser_t *response)
Sends the UNSUBCRIBE gena request and recieves the response from the device and returns it as a param...
int has_xml_content_type(http_message_t *hmsg)
Find the header from the HTTP message and match the header for xml data.
Function to extract header information from an http message and match the data with XML data.
device subscriptions
Additional socket information for connections and ssl.
Definition sock.hpp:65
HTTP status codes.
in_port_t LOCAL_PORT_V6_ULA_GUA
IPv6 GUA port for the mini-server.
Definition upnpapi.cpp:149
Upnp_Handle_Type GetHandleInfo(UpnpClient_Handle Hnd, Handle_Info **HndInfo)
Get handle information.
Definition upnpapi.cpp:3339
char gIF_IPV6_ULA_GUA[INET6_ADDRSTRLEN]
IPv6 GUA buffer to contain interface IPv6 global-unicast address.
Definition upnpapi.cpp:145
in_port_t LOCAL_PORT_V6
IPv6 LLA port for the mini-server.
Definition upnpapi.cpp:142
in_port_t LOCAL_PORT_V4
IPv4 local port for the mini-server.
Definition upnpapi.cpp:156
char gIF_IPV4[INET_ADDRSTRLEN]
IPv4 buffer to contain interface address. (extern'ed in upnp.h)
Definition upnpapi.cpp:152
TimerThread gTimerThread
Global timer thread.
Definition upnpapi.cpp:108
char gIF_IPV6[INET6_ADDRSTRLEN]
IPv6 LLA buffer to contain interface address. (extern'ed in upnp.h)
Definition upnpapi.cpp:138
Upnp_Handle_Type GetClientHandleInfo(UpnpClient_Handle *client_handle_out, struct Handle_Info **HndInfo)
Get client handle info.
Definition upnpapi.cpp:3245
Inititalize the compatible library before it can be used.
#define HandleLock()
HandleLock.
Definition upnpapi.hpp:140
GenlibClientSubscription * ClientSubList
Client subscription list.
Definition upnpapi.hpp:120
#define HandleUnlock()
HandleUnlock.
Definition upnpapi.hpp:149
char * Cookie
???
Definition upnpapi.hpp:89
Upnp_FunPtr Callback
Callback function pointer.
Definition upnpapi.hpp:88
constexpr int NUM_HANDLE
Maximal number of available UPnP Unit handles.
Definition upnpapi.hpp:66
#define HandleReadLock()
HandleReadLock.
Definition upnpapi.hpp:146
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