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-05-05
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 original source file on 2023-06-22, ver 1.14.16
40#include <gena.hpp>
41#include <httpreadwrite.hpp>
42#include <parsetools.hpp>
43#include <statcodes.hpp>
44#include <upnpapi.hpp>
45#include <uuid.hpp>
46
47struct job_arg {
48 int handle;
49 int eventId;
50 void* Event;
51};
52
53namespace {
54
57pthread_mutex_t ctrlpntSubscribe_mutex{};
58
63 if (arg) {
64 if (arg->Event) {
66 }
67 free(arg);
68 }
69}
70
77 void* input) {
78 job_arg* arg = (job_arg*)input;
79 UpnpEventSubscribe* sub_struct = (UpnpEventSubscribe*)arg->Event;
80 void* cookie;
81 Upnp_FunPtr callback_fun;
82 struct Handle_Info* handle_info;
83 int send_callback = 0;
84 int eventType = 0;
85 int timeout = 0;
86 int errCode = 0;
87
88 if constexpr (AUTO_RENEW_TIME == 0) {
89 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA SUB EXPIRED");
91 send_callback = 1;
93 } else {
94 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA AUTO RENEW");
95 timeout = UpnpEventSubscribe_get_TimeOut(sub_struct);
96 errCode = genaRenewSubscription(
97 arg->handle, UpnpEventSubscribe_get_SID(sub_struct), &timeout);
98 UpnpEventSubscribe_set_ErrCode(sub_struct, errCode);
99 UpnpEventSubscribe_set_TimeOut(sub_struct, timeout);
100 if (errCode != UPNP_E_SUCCESS && errCode != GENA_E_BAD_SID &&
101 errCode != GENA_E_BAD_HANDLE) {
102 send_callback = 1;
104 }
105 }
106
107 if (send_callback) {
109 if (GetHandleInfo(arg->handle, &handle_info) != HND_CLIENT) {
110 HandleUnlock();
112 goto end_function;
113 }
114 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "HANDLE IS VALID");
115
116 /* make callback */
117 callback_fun = handle_info->Callback;
118 cookie = handle_info->Cookie;
119 HandleUnlock();
120 callback_fun((Upnp_EventType)eventType, arg->Event, cookie);
121 }
122
124
125end_function:
126 return;
127}
128
137 int client_handle,
139 int TimeOut,
142 UpnpEventSubscribe* RenewEvent = NULL;
143 job_arg* arg = NULL;
144 int return_code = GENA_SUCCESS;
145 ThreadPoolJob job;
146
147 memset(&job, 0, sizeof(job));
148
149 if (TimeOut == UPNP_INFINITE) {
150 return_code = GENA_SUCCESS;
151 goto end_function;
152 }
153
154 RenewEvent = UpnpEventSubscribe_new();
155 if (RenewEvent == NULL) {
156 return_code = UPNP_E_OUTOF_MEMORY;
157 goto end_function;
158 }
159
160 arg = (job_arg*)malloc(sizeof(job_arg));
161 if (arg == NULL) {
162 free(RenewEvent);
163 return_code = UPNP_E_OUTOF_MEMORY;
164 goto end_function;
165 }
166 memset(arg, 0, sizeof(job_arg));
167
168 /* schedule expire event */
170 UpnpEventSubscribe_set_TimeOut(RenewEvent, TimeOut);
175
176 arg->handle = client_handle;
177 arg->Event = RenewEvent;
178
179 TPJobInit(&job, (UPnPsdk::start_routine)GenaAutoRenewSubscription, arg);
181 TPJobSetPriority(&job, MED_PRIORITY);
182
183 /* Schedule the job */
184 return_code =
186 &job, SHORT_TERM, &(arg->eventId));
187 if (return_code != UPNP_E_SUCCESS) {
189 goto end_function;
190 }
191
193
194 return_code = GENA_SUCCESS;
195
196end_function:
197
198 return return_code;
199}
200
209 const UpnpString* url,
211 const UpnpString* sid,
213 http_parser_t* response) {
214 int return_code;
215 uri_type dest_url;
216 membuffer request;
217
218 /* parse url */
219 return_code = http_FixStrUrl(UpnpString_get_String(url),
220 UpnpString_get_Length(url), &dest_url);
221 if (return_code != 0) {
222 return return_code;
223 }
224
225 /* make request msg */
226 membuffer_init(&request);
227 request.size_inc = 30;
228 return_code = http_MakeMessage(&request, 1, 1,
229 "q"
230 "ssc"
231 "Uc",
232 HTTPMETHOD_UNSUBSCRIBE, &dest_url,
233 "SID: ", UpnpString_get_String(sid));
234
235 /* Not able to make the message so destroy the existing buffer */
236 if (return_code != 0) {
237 membuffer_destroy(&request);
238
239 return return_code;
240 }
241
242 /* send request and get reply */
243 return_code = http_RequestAndResponse(
244 &dest_url, request.buf, request.length, HTTPMETHOD_UNSUBSCRIBE,
245 HTTP_DEFAULT_TIMEOUT, response);
246 membuffer_destroy(&request);
247 if (return_code != 0) {
248 httpmsg_destroy(&response->msg);
249 }
250
251 if (return_code == 0 && response->msg.status_code != HTTP_OK) {
252 return_code = UPNP_E_UNSUBSCRIBE_UNACCEPTED;
253 httpmsg_destroy(&response->msg);
254 }
255
256 return return_code;
257}
258
266 const UpnpString* url,
268 int* timeout,
271 const UpnpString* renewal_sid,
273 UpnpString* sid) {
274 int return_code;
275 int parse_ret = 0;
276 int local_timeout = CP_MINIMUM_SUBSCRIPTION_TIME;
277 memptr sid_hdr;
278 memptr timeout_hdr;
279 char timeout_str[25];
280 membuffer request;
281 uri_type dest_url;
282 http_parser_t response;
283 int rc = 0;
284
285 UpnpString_clear(sid);
286
287 /* request timeout to string */
288 if (timeout == NULL) {
289 timeout = &local_timeout;
290 }
291 if (*timeout < 0) {
292 memset(timeout_str, 0, sizeof(timeout_str));
293 strncpy(timeout_str, "infinite", sizeof(timeout_str) - 1);
294 } else if (*timeout < CP_MINIMUM_SUBSCRIPTION_TIME) {
295 rc = snprintf(timeout_str, sizeof(timeout_str), "%d",
297 } else {
298 rc = snprintf(timeout_str, sizeof(timeout_str), "%d", *timeout);
299 }
300 if (rc < 0 || (unsigned int)rc >= sizeof(timeout_str))
301 return UPNP_E_OUTOF_MEMORY;
302
303 /* parse url */
304 return_code = http_FixStrUrl(UpnpString_get_String(url),
305 UpnpString_get_Length(url), &dest_url);
306 if (return_code != 0) {
307 return return_code;
308 }
309
310 /* make request msg */
311 membuffer_init(&request);
312 request.size_inc = 30;
313 if (renewal_sid) {
314 /* renew subscription */
315 return_code =
316 http_MakeMessage(&request, 1, 1,
317 "q"
318 "ssc"
319 "sscc",
320 HTTPMETHOD_SUBSCRIBE, &dest_url,
321 "SID: ", UpnpString_get_String(renewal_sid),
322 "TIMEOUT: Second-", timeout_str);
323 } else {
324 /* subscribe */
325 if (dest_url.hostport.IPaddress.ss_family == AF_INET6) {
326 struct sockaddr_in6* DestAddr6 =
327 (struct sockaddr_in6*)&dest_url.hostport.IPaddress;
328 return_code = http_MakeMessage(
329 &request, 1, 1,
330 "q"
331 "sssdsc"
332 "sc"
333 "sscc",
334 HTTPMETHOD_SUBSCRIBE, &dest_url, "CALLBACK: <http://[",
335 (IN6_IS_ADDR_LINKLOCAL(&DestAddr6->sin6_addr) ||
336 strlen(gIF_IPV6_ULA_GUA) == 0)
337 ? gIF_IPV6
339 "]:",
340 (IN6_IS_ADDR_LINKLOCAL(&DestAddr6->sin6_addr) ||
341 strlen(gIF_IPV6_ULA_GUA) == 0)
344 "/>", "NT: upnp:event", "TIMEOUT: Second-", timeout_str);
345 } else {
346 return_code = http_MakeMessage(
347 &request, 1, 1,
348 "q"
349 "sssdsc"
350 "sc"
351 "sscc",
352 HTTPMETHOD_SUBSCRIBE, &dest_url, "CALLBACK: <http://", gIF_IPV4,
353 ":", LOCAL_PORT_V4, "/>", "NT: upnp:event", "TIMEOUT: Second-",
354 timeout_str);
355 }
356 }
357 if (return_code != 0) {
358 return return_code;
359 }
360
361 /* send request and get reply */
362 return_code = http_RequestAndResponse(&dest_url, request.buf,
363 request.length, HTTPMETHOD_SUBSCRIBE,
364 HTTP_DEFAULT_TIMEOUT, &response);
365 membuffer_destroy(&request);
366
367 if (return_code != 0) {
368 httpmsg_destroy(&response.msg);
369
370 return return_code;
371 }
372 if (response.msg.status_code != HTTP_OK) {
373 httpmsg_destroy(&response.msg);
374
376 }
377
378 /* get SID and TIMEOUT */
379 if (httpmsg_find_hdr(&response.msg, HDR_SID, &sid_hdr) == NULL ||
380 sid_hdr.length == 0 ||
381 httpmsg_find_hdr(&response.msg, HDR_TIMEOUT, &timeout_hdr) == NULL ||
382 timeout_hdr.length == 0) {
383 httpmsg_destroy(&response.msg);
384
385 return UPNP_E_BAD_RESPONSE;
386 }
387
388 /* save timeout */
389 parse_ret =
390 matchstr(timeout_hdr.buf, timeout_hdr.length, "%iSecond-%d%0", timeout);
391 if (parse_ret == PARSE_OK) {
392 /* nothing to do */
393 } else if (memptr_cmp_nocase(&timeout_hdr, "Second-infinite") == 0) {
394 *timeout = -1;
395 } else {
396 httpmsg_destroy(&response.msg);
397
398 return UPNP_E_BAD_RESPONSE;
399 }
400
401 /* save SID */
402 UpnpString_set_StringN(sid, sid_hdr.buf, sid_hdr.length);
403 if (UpnpString_get_String(sid) == NULL) {
404 httpmsg_destroy(&response.msg);
405
406 return UPNP_E_OUTOF_MEMORY;
407 }
408 httpmsg_destroy(&response.msg);
409
410 return UPNP_E_SUCCESS;
411}
412
413} // namespace
414
416 pthread_mutexattr_t attr;
417
418 int ret = pthread_mutexattr_init(&attr);
419 if (ret != 0)
420 return ret;
421 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
422 pthread_mutex_init(&ctrlpntSubscribe_mutex, &attr);
423 pthread_mutexattr_destroy(&attr);
424 return 0;
425}
426
428 return pthread_mutex_destroy(&ctrlpntSubscribe_mutex);
429}
430
433 int return_code = UPNP_E_SUCCESS;
434 struct Handle_Info* handle_info = NULL;
435 http_parser_t response;
436
437 while (1) {
438 HandleLock();
439
440 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
441 HandleUnlock();
442 return_code = GENA_E_BAD_HANDLE;
443 goto exit_function;
444 }
445 if (handle_info->ClientSubList == NULL) {
446 return_code = UPNP_E_SUCCESS;
447 break;
448 }
449 GenlibClientSubscription_assign(sub_copy, handle_info->ClientSubList);
452
453 HandleUnlock();
454
455 return_code = gena_unsubscribe(
457 GenlibClientSubscription_get_ActualSID(sub_copy), &response);
458 if (return_code == 0) {
459 httpmsg_destroy(&response.msg);
460 }
461 free_client_subscription(sub_copy);
462 }
463
464 freeClientSubList(handle_info->ClientSubList);
465 HandleUnlock();
466
467exit_function:
469 return return_code;
470}
471
472int genaUnSubscribe(UpnpClient_Handle client_handle, const UpnpString* in_sid) {
473 GenlibClientSubscription* sub = NULL;
474 int return_code = GENA_SUCCESS;
475 struct Handle_Info* handle_info;
477 http_parser_t response;
478
479 /* validate handle and sid */
480 HandleLock();
481 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
482 HandleUnlock();
483 return_code = GENA_E_BAD_HANDLE;
484 goto exit_function;
485 }
486 sub = GetClientSubClientSID(handle_info->ClientSubList, in_sid);
487 if (sub == NULL) {
488 HandleUnlock();
489 return_code = GENA_E_BAD_SID;
490 goto exit_function;
491 }
492 GenlibClientSubscription_assign(sub_copy, sub);
493 HandleUnlock();
494
495 return_code = gena_unsubscribe(
497 GenlibClientSubscription_get_ActualSID(sub_copy), &response);
498 if (return_code == 0) {
499 httpmsg_destroy(&response.msg);
500 }
501 free_client_subscription(sub_copy);
502
503 HandleLock();
504 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
505 HandleUnlock();
506 return_code = GENA_E_BAD_HANDLE;
507 goto exit_function;
508 }
509 RemoveClientSubClientSID(&handle_info->ClientSubList, in_sid);
510 HandleUnlock();
511
512exit_function:
514 return return_code;
515}
516
518 const UpnpString* PublisherURL, int* TimeOut,
519 UpnpString* out_sid) {
520 int return_code = GENA_SUCCESS;
522 uuid_upnp uid;
523 Upnp_SID temp_sid;
524 Upnp_SID temp_sid2;
525 UpnpString* ActualSID = UpnpString_new();
526 UpnpString* EventURL = UpnpString_new();
527 struct Handle_Info* handle_info;
528 int rc = 0;
529
530 memset(temp_sid, 0, sizeof(temp_sid));
531 memset(temp_sid2, 0, sizeof(temp_sid2));
532
533 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__, "GENA SUBSCRIBE BEGIN");
534
535 UpnpString_clear(out_sid);
536
538 /* validate handle */
539 int ret;
540 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
541 return_code = GENA_E_BAD_HANDLE;
542 ret = pthread_mutex_lock(&ctrlpntSubscribe_mutex);
543 if (ret != 0)
544 UPnPsdk_LOGCRIT("MSG1099") "POSIX thread mutex lock fails with "
545 << (ret == EINVAL ? "EINVAL" : "EDEADLK") << ".\n";
546 goto error_handler;
547 }
548 HandleUnlock();
549
550 /* subscribe */
551 ret = pthread_mutex_lock(&ctrlpntSubscribe_mutex);
552 if (ret != 0)
553 UPnPsdk_LOGCRIT("MSG1138") "POSIX thread mutex lock fails with "
554 << (ret == EINVAL ? "EINVAL" : "EDEADLK") << ".\n";
555 return_code = gena_subscribe(PublisherURL, TimeOut, NULL, ActualSID);
556 HandleLock();
557 if (return_code != UPNP_E_SUCCESS) {
558 UpnpPrintf(UPNP_CRITICAL, GENA, __FILE__, __LINE__,
559 "SUBSCRIBE FAILED in transfer error code: %d "
560 "returned\n",
561 return_code);
562 goto error_handler;
563 }
564
565 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
566 return_code = GENA_E_BAD_HANDLE;
567 goto error_handler;
568 }
569
570 /* generate client SID */
571 uuid_create(&uid);
572 upnp_uuid_unpack(&uid, temp_sid);
573 rc = snprintf(temp_sid2, sizeof(temp_sid2), "uuid:%s", temp_sid);
574 if (rc < 0 || (unsigned int)rc >= sizeof(temp_sid2)) {
575 return_code = UPNP_E_OUTOF_MEMORY;
576 goto error_handler;
577 }
578 UpnpString_set_String(out_sid, temp_sid2);
579
580 /* create event url */
581 UpnpString_assign(EventURL, PublisherURL);
582
583 /* fill subscription */
584 if (newSubscription == NULL) {
585 return_code = UPNP_E_OUTOF_MEMORY;
586 goto error_handler;
587 }
589 GenlibClientSubscription_set_SID(newSubscription, out_sid);
590 GenlibClientSubscription_set_ActualSID(newSubscription, ActualSID);
591 GenlibClientSubscription_set_EventURL(newSubscription, EventURL);
592 GenlibClientSubscription_set_Next(newSubscription,
593 handle_info->ClientSubList);
594 handle_info->ClientSubList = newSubscription;
595
596 /* schedule expiration event */
597 return_code =
598 ScheduleGenaAutoRenew(client_handle, *TimeOut, newSubscription);
599
600error_handler:
601 UpnpString_delete(ActualSID);
602 UpnpString_delete(EventURL);
603 if (return_code != UPNP_E_SUCCESS)
604 GenlibClientSubscription_delete(newSubscription);
605 HandleUnlock();
606 ret = pthread_mutex_unlock(&ctrlpntSubscribe_mutex);
607 if (ret != 0)
608 UPnPsdk_LOGCRIT("MSG1139") "POSIX thread mutex unlock fails with "
609 << (ret == EINVAL ? "EINVAL" : "EPERM") << ".\n";
610
611 return return_code;
612}
613
615 const UpnpString* in_sid, int* TimeOut) {
616 int return_code = GENA_SUCCESS;
617 GenlibClientSubscription* sub = NULL;
619 struct Handle_Info* handle_info;
620 UpnpString* ActualSID = UpnpString_new();
621 ThreadPoolJob tempJob;
622
623 HandleLock();
624
625 /* validate handle and sid */
626 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
627 HandleUnlock();
628
629 return_code = GENA_E_BAD_HANDLE;
630 goto exit_function;
631 }
632
633 sub = GetClientSubClientSID(handle_info->ClientSubList, in_sid);
634 if (sub == NULL) {
635 HandleUnlock();
636
637 return_code = GENA_E_BAD_SID;
638 goto exit_function;
639 }
640
641 /* remove old events */
644 &tempJob) == 0) {
645 tempJob.free_func(tempJob.arg);
646 }
647
648 UpnpPrintf(UPNP_INFO, GENA, __FILE__, __LINE__,
649 "REMOVED AUTO RENEW EVENT");
650
652 GenlibClientSubscription_assign(sub_copy, sub);
653
654 HandleUnlock();
655
656 return_code = gena_subscribe(
657 GenlibClientSubscription_get_EventURL(sub_copy), TimeOut,
658 GenlibClientSubscription_get_ActualSID(sub_copy), ActualSID);
659
660 HandleLock();
661
662 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
663 HandleUnlock();
664 return_code = GENA_E_BAD_HANDLE;
665 goto exit_function;
666 }
667
668 /* we just called GetHandleInfo, so we don't check for return value */
669 /*GetHandleInfo(client_handle, &handle_info); */
670 if (return_code != UPNP_E_SUCCESS) {
671 /* network failure (remove client sub) */
672 RemoveClientSubClientSID(&handle_info->ClientSubList, in_sid);
673 free_client_subscription(sub_copy);
674 HandleUnlock();
675 goto exit_function;
676 }
677
678 /* get subscription */
679 sub = GetClientSubClientSID(handle_info->ClientSubList, in_sid);
680 if (sub == NULL) {
681 free_client_subscription(sub_copy);
682 HandleUnlock();
683 return_code = GENA_E_BAD_SID;
684 goto exit_function;
685 }
686
687 /* store actual sid */
689
690 /* start renew subscription timer */
691 return_code = ScheduleGenaAutoRenew(client_handle, *TimeOut, sub);
692 if (return_code != GENA_SUCCESS) {
695 }
696 free_client_subscription(sub_copy);
697 HandleUnlock();
698
699exit_function:
700 UpnpString_delete(ActualSID);
702 return return_code;
703}
704
706 UpnpEvent* event_struct = UpnpEvent_new();
707 IXML_Document* ChangedVars = NULL;
708 int eventKey;
709 token sid;
711 struct Handle_Info* handle_info;
712 void* cookie;
713 Upnp_FunPtr callback;
714 UpnpClient_Handle client_handle;
715 UpnpClient_Handle client_handle_start;
716 int err_ret = HTTP_PRECONDITION_FAILED;
717
718 memptr sid_hdr;
719 memptr nt_hdr, nts_hdr;
720 memptr seq_hdr;
721
722 /* get SID */
723 if (httpmsg_find_hdr(event, HDR_SID, &sid_hdr) == NULL) {
724 error_respond(info, HTTP_PRECONDITION_FAILED, event);
725 goto exit_function;
726 }
727 sid.buff = sid_hdr.buf;
728 sid.size = sid_hdr.length;
729
730 /* get event key */
731 if (httpmsg_find_hdr(event, HDR_SEQ, &seq_hdr) == NULL ||
732 matchstr(seq_hdr.buf, seq_hdr.length, "%d%0", &eventKey) != PARSE_OK) {
733 error_respond(info, HTTP_BAD_REQUEST, event);
734 goto exit_function;
735 }
736
737 /* get NT and NTS headers */
738 if (httpmsg_find_hdr(event, HDR_NT, &nt_hdr) == NULL ||
739 httpmsg_find_hdr(event, HDR_NTS, &nts_hdr) == NULL) {
740 error_respond(info, HTTP_BAD_REQUEST, event);
741 goto exit_function;
742 }
743
744 /* verify NT and NTS headers */
745 if (memptr_cmp(&nt_hdr, "upnp:event") != 0 ||
746 memptr_cmp(&nts_hdr, "upnp:propchange") != 0) {
747 error_respond(info, HTTP_PRECONDITION_FAILED, event);
748 goto exit_function;
749 }
750
751 /* parse the content (should be XML) */
752 if (!has_xml_content_type(event) || event->msg.length == 0 ||
753 ixmlParseBufferEx(event->entity.buf, &ChangedVars) != IXML_SUCCESS) {
754 error_respond(info, HTTP_BAD_REQUEST, event);
755 goto exit_function;
756 }
757
758 HandleLock();
759
760 /* get client info */
761 if (GetClientHandleInfo(&client_handle_start, &handle_info) != HND_CLIENT) {
762 error_respond(info, HTTP_PRECONDITION_FAILED, event);
763 HandleUnlock();
764 goto exit_function;
765 }
766
767 HandleUnlock();
768
769 for (client_handle = client_handle_start; client_handle < NUM_HANDLE;
770 client_handle++) {
771 HandleLock();
772
773 /* get client info */
774 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
775 HandleUnlock();
776 continue;
777 }
778
779 /* get subscription based on SID */
781 if (subscription == NULL) {
782 if (eventKey == 0) {
783 /* wait until we've finished processing a
784 * subscription */
785 /* (if we are in the middle) */
786 /* this is to avoid mistakenly rejecting the
787 * first event if we */
788 /* receive it before the subscription response
789 */
790 HandleUnlock();
791
792 /* try and get Subscription Lock */
793 /* (in case we are in the process of
794 * subscribing) */
795 int ret = pthread_mutex_lock(&ctrlpntSubscribe_mutex);
796 if (ret != 0)
797 UPnPsdk_LOGCRIT(
798 "MSG1140") "POSIX thread mutex lock fails with "
799 << (ret == EINVAL ? "EINVAL" : "EDEADLK") << ".\n";
800
801 /* get HandleLock again */
802 HandleLock();
803
804 if (GetHandleInfo(client_handle, &handle_info) != HND_CLIENT) {
805 ret = pthread_mutex_unlock(&ctrlpntSubscribe_mutex);
806 if (ret != 0)
807 UPnPsdk_LOGCRIT(
808 "MSG1141") "POSIX thread mutex unlock fails with "
809 << (ret == EINVAL ? "EINVAL" : "EPERM") << ".\n";
810 HandleUnlock();
811 continue;
812 }
813
815 GetClientSubActualSID(handle_info->ClientSubList, &sid);
816 if (subscription == NULL) {
817 ret = pthread_mutex_unlock(&ctrlpntSubscribe_mutex);
818 if (ret != 0)
819 UPnPsdk_LOGCRIT(
820 "MSG1142") "POSIX thread mutex unlock fails with "
821 << (ret == EINVAL ? "EINVAL" : "EPERM") << ".\n";
822 HandleUnlock();
823 continue;
824 }
825
826 ret = pthread_mutex_unlock(&ctrlpntSubscribe_mutex);
827 if (ret != 0)
828 UPnPsdk_LOGCRIT(
829 "MSG1143") "POSIX thread mutex unlock fails with "
830 << (ret == EINVAL ? "EINVAL" : "EPERM") << ".\n";
831 } else {
832 HandleUnlock();
833 continue;
834 }
835 }
836
837 /* success */
838 err_ret = HTTP_OK;
839
840 /* fill event struct */
841 UpnpEvent_set_EventKey(event_struct, eventKey);
842 UpnpEvent_set_ChangedVariables(event_struct, ChangedVars);
843 UpnpEvent_set_SID(event_struct,
845
846 /* copy callback */
847 callback = handle_info->Callback;
848 cookie = handle_info->Cookie;
849
850 HandleUnlock();
851
852 /* make callback with event struct */
853 /* In future, should find a way of mainting */
854 /* that the handle is not unregistered in the middle of a */
855 /* callback */
856 callback(UPNP_EVENT_RECEIVED, event_struct, cookie);
857 }
858
859 error_respond(info, err_ret, event);
860
861exit_function:
862 ixmlDocument_free(ChangedVars);
863 UpnpEvent_delete(event_struct);
864}
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:434
int UpnpClient_Handle
Returned when a control point application registers with UpnpRegisterClient().
Definition API.hpp:415
#define UPNP_INFINITE
Definition API.hpp:51
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.
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_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.
#define HTTP_DEFAULT_TIMEOUT
hostport_type hostport
Member variable.
Definition uri.hpp:100
size_t size
Size of the buffer.
Definition uri.hpp:78
const char * buff
Buffer.
Definition uri.hpp:77
sockaddr_storage IPaddress
Network socket address.
Definition uri.hpp:86
Represents a URI used in parse_uri and elsewhere.
Definition uri.hpp:92
Buffer used in parsinghttp messages, urls, etc. Generally this simply holds a pointer into a larger a...
Definition uri.hpp:76
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.
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:377
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:390
PUPNP_Api void ixmlDocument_free(IXML_Document *doc)
Frees a Document object and all Nodes associated with it.
Definition document.cpp:47
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 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 (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(job_arg *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 ULA or GUA port for the mini-server.
Definition upnpapi.cpp:317
Upnp_Handle_Type GetHandleInfo(UpnpClient_Handle Hnd, Handle_Info **HndInfo)
Get handle information.
Definition upnpapi.cpp:3342
char gIF_IPV6_ULA_GUA[INET6_ADDRSTRLEN]
Static buffer to contain interface IPv6 unique-local or globally-unique address (ULA or GUA)....
Definition upnpapi.cpp:305
in_port_t LOCAL_PORT_V6
IPv6 LLA port for the mini-server.
Definition upnpapi.cpp:314
in_port_t LOCAL_PORT_V4
local IPv4 port for the mini-server
Definition upnpapi.cpp:311
char gIF_IPV4[INET_ADDRSTRLEN]
Static buffer to contain interface IPv4 address. (extern'ed in upnp.h)
Definition upnpapi.cpp:284
TimerThread gTimerThread
Global timer thread.
Definition upnpapi.cpp:256
char gIF_IPV6[INET6_ADDRSTRLEN]
Static buffer to contain interface IPv6 link-local address (LLA). (extern'ed in upnp....
Definition upnpapi.cpp:292
Upnp_Handle_Type GetClientHandleInfo(UpnpClient_Handle *client_handle_out, struct Handle_Info **HndInfo)
Get client handle info.
Definition upnpapi.cpp:3248
Inititalize the compatible library before it can be used.
#define HandleLock()
HandleLock.
Definition upnpapi.hpp:138
GenlibClientSubscription * ClientSubList
Client subscription list.
Definition upnpapi.hpp:118
#define HandleUnlock()
HandleUnlock.
Definition upnpapi.hpp:147
char * Cookie
???
Definition upnpapi.hpp:87
Upnp_FunPtr Callback
Callback function pointer.
Definition upnpapi.hpp:86
constexpr int NUM_HANDLE
Maximal number of available UPnP Unit handles.
Definition upnpapi.hpp:64
#define HandleReadLock()
HandleReadLock.
Definition upnpapi.hpp:144
Data to be stored in handle table for Handle Info.
Definition upnpapi.hpp:84
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