UPnPsdk 0.1
Universal Plug and Play +, Software Development Kit
 
Loading...
Searching...
No Matches
ssdp_ctrlpt.cpp
Go to the documentation of this file.
1/**************************************************************************
2 *
3 * Copyright (c) 2000-2003 Intel Corporation
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 * Copyright (C) 2022+ GPL 3 and higher by Ingo Höft, <Ingo@Hoeft-online.de>
9 * Redistribution only with this Copyright remark. Last modified: 2025-04-30
10 *
11 * - Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright notice,
14 * this list of conditions and the following disclaimer in the documentation
15 * and/or other materials provided with the distribution.
16 * - Neither name of Intel Corporation nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
28 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 **************************************************************************/
33// Last compare with ./pupnp source file on 2024-02-15, ver 1.14.18
42#include <ssdp_ctrlpt.hpp>
43
45#include <statcodes.hpp>
46#include <upnpapi.hpp>
47
48#include <umock/sys_socket.hpp>
49#include <umock/pupnp_sock.hpp>
50
51#ifndef COMPA_INTERNAL_CONFIG_HPP
52#error "No or wrong config.hpp header file included."
53#endif
54
56#include <thread>
58
59namespace {
70 void* data) {
71 SSDPResultData* temp = (SSDPResultData*)data;
72
75}
76
90 char* RqstBuf,
92 size_t RqstBufSize,
94 int Mx,
96 char* SearchTarget,
98 int AddressFamily) {
99 int rc;
100 char TempBuf[COMMAND_LEN];
101 const char* command = "M-SEARCH * HTTP/1.1\r\n";
102 const char* man = "MAN: \"ssdp:discover\"\r\n";
103
104 memset(TempBuf, 0, sizeof(TempBuf));
105 if (RqstBufSize <= strlen(command))
107 strcpy(RqstBuf, command);
108
109 switch (AddressFamily) {
110 case AF_INET:
111 rc = snprintf(TempBuf, sizeof(TempBuf), "HOST: %s:%d\r\n", SSDP_IP,
112 SSDP_PORT);
113 break;
114 case AF_INET6:
115 rc = snprintf(TempBuf, sizeof(TempBuf), "HOST: [%s]:%d\r\n",
117 break;
118 default:
120 }
121 if (rc < 0 || (unsigned int)rc >= sizeof(TempBuf))
123
124 if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
126 strcat(RqstBuf, TempBuf);
127
128 if (RqstBufSize <= strlen(RqstBuf) + strlen(man))
130 strcat(RqstBuf, man);
131
132 if (Mx > 0) {
133 rc = snprintf(TempBuf, sizeof(TempBuf), "MX: %d\r\n", Mx);
134 if (rc < 0 || (unsigned int)rc >= sizeof(TempBuf))
136 if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
138 strcat(RqstBuf, TempBuf);
139 }
140
141 if (SearchTarget != NULL) {
142 rc = snprintf(TempBuf, sizeof(TempBuf), "ST: %s\r\n", SearchTarget);
143 if (rc < 0 || (unsigned int)rc >= sizeof(TempBuf))
145 if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
147 strcat(RqstBuf, TempBuf);
148 }
149 if (RqstBufSize <= strlen(RqstBuf) + strlen("\r\n"))
151 strcat(RqstBuf, "\r\n");
152
153 return UPNP_E_SUCCESS;
154}
155
167#ifdef UPNP_ENABLE_IPV6
170 char* RqstBuf,
172 size_t RqstBufSize,
174 int Mx,
176 char* SearchTarget,
178 int AddressFamily) {
179 int rc;
180 char TempBuf[COMMAND_LEN];
181 const char* command = "M-SEARCH * HTTP/1.1\r\n";
182 const char* man = "MAN: \"ssdp:discover\"\r\n";
183
184 memset(TempBuf, 0, sizeof(TempBuf));
185 if (RqstBufSize <= strlen(command))
187 strcpy(RqstBuf, command);
188 switch (AddressFamily) {
189 case AF_INET:
190 rc = snprintf(TempBuf, sizeof(TempBuf), "HOST: %s:%d\r\n", SSDP_IP,
191 SSDP_PORT);
192 break;
193 case AF_INET6:
194 rc = snprintf(TempBuf, sizeof(TempBuf), "HOST: [%s]:%d\r\n",
196 break;
197 default:
199 }
200 if (rc < 0 || (unsigned int)rc >= sizeof(TempBuf))
202
203 if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
205 strcat(RqstBuf, TempBuf);
206
207 if (RqstBufSize <= strlen(RqstBuf) + strlen(man))
209 strcat(RqstBuf, man);
210
211 if (Mx > 0) {
212 rc = snprintf(TempBuf, sizeof(TempBuf), "MX: %d\r\n", Mx);
213 if (rc < 0 || (unsigned int)rc >= sizeof(TempBuf))
215 if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
217 strcat(RqstBuf, TempBuf);
218 }
219 if (SearchTarget) {
220 rc = snprintf(TempBuf, sizeof(TempBuf), "ST: %s\r\n", SearchTarget);
221 if (rc < 0 || (unsigned int)rc >= sizeof(TempBuf))
223 if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
225 strcat(RqstBuf, TempBuf);
226 }
227 if (RqstBufSize <= strlen(RqstBuf) + strlen("\r\n"))
229 strcat(RqstBuf, "\r\n");
230
231 return UPNP_E_SUCCESS;
232}
233#endif /* UPNP_ENABLE_IPV6 */
234
238inline void searchExpired(
240 void* arg) {
241 int id = ((SsdpSearchExpArg*)arg)->timeoutEventId;
242 int handle = ((SsdpSearchExpArg*)arg)->handle;
243 struct Handle_Info* ctrlpt_info = NULL;
244
245 /* remove search Target from list and call client back */
246 ListNode* node = NULL;
247 SsdpSearchArg* item;
248 Upnp_FunPtr ctrlpt_callback;
249 void* cookie = NULL;
250 int found = 0;
251
252 HandleLock();
253
254 /* remove search target from search list */
255 if (GetHandleInfo(handle, &ctrlpt_info) != HND_CLIENT) {
256 free(arg);
257 HandleUnlock();
258 return;
259 }
260 ctrlpt_callback = ctrlpt_info->Callback;
261 node = ListHead(&ctrlpt_info->SsdpSearchList);
262 while (node != NULL) {
263 item = (SsdpSearchArg*)node->item;
264 if (item->timeoutEventId == id) {
265 free(item->searchTarget);
266 cookie = item->cookie;
267 found = 1;
268 item->searchTarget = NULL;
269 free(item);
270 ListDelNode(&ctrlpt_info->SsdpSearchList, node, 0);
271 break;
272 }
273 node = ListNext(&ctrlpt_info->SsdpSearchList, node);
274 }
275 HandleUnlock();
276
277 if (found)
278 ctrlpt_callback(UPNP_DISCOVERY_SEARCH_TIMEOUT, NULL, cookie);
279
280 free(arg);
281}
282
284} // anonymous namespace
285
287 struct sockaddr_storage* dest_addr, int timeout) {
288 int handle;
289 int handle_start;
290 struct Handle_Info* ctrlpt_info = NULL;
291 memptr hdr_value;
292 /* byebye or alive */
293 int is_byebye;
295 int expires;
296 int ret;
297 SsdpEvent event;
298 int nt_found;
299 int usn_found;
300 int st_found;
301 char save_char;
302 Upnp_EventType event_type;
303 Upnp_FunPtr ctrlpt_callback;
304 void* ctrlpt_cookie;
305 ListNode* node = NULL;
306 SsdpSearchArg* searchArg = NULL;
307 int matched = 0;
308 SSDPResultData* threadData = NULL;
309 ThreadPoolJob job;
310
311 /* we are assuming that there can be only one client supported at a time
312 */
314
315 if (GetClientHandleInfo(&handle_start, &ctrlpt_info) != HND_CLIENT) {
316 HandleUnlock();
317 goto end_ssdp_handle_ctrlpt_msg;
318 }
319 HandleUnlock();
320 /* search timeout */
321 if (timeout) {
322 for (handle = handle_start; handle < NUM_HANDLE; handle++) {
323 HandleLock();
324
325 /* get client info */
326 if (GetHandleInfo(handle, &ctrlpt_info) != HND_CLIENT) {
327 HandleUnlock();
328 continue;
329 }
330 /* copy */
331 ctrlpt_callback = ctrlpt_info->Callback;
332 ctrlpt_cookie = ctrlpt_info->Cookie;
333 HandleUnlock();
334
335 ctrlpt_callback(UPNP_DISCOVERY_SEARCH_TIMEOUT, NULL, ctrlpt_cookie);
336 }
337 goto end_ssdp_handle_ctrlpt_msg;
338 }
339
341 /* MAX-AGE, assume error */
342 expires = -1;
343 UpnpDiscovery_set_Expires(param, expires);
344 if (httpmsg_find_hdr(hmsg, HDR_CACHE_CONTROL, &hdr_value) != NULL) {
345 ret = matchstr(hdr_value.buf, hdr_value.length, "%imax-age = %d%0",
346 &expires);
347 UpnpDiscovery_set_Expires(param, expires);
348 if (ret != PARSE_OK)
349 goto end_ssdp_handle_ctrlpt_msg;
350 }
351 /* DATE */
352 if (httpmsg_find_hdr(hmsg, HDR_DATE, &hdr_value) != NULL) {
353 UpnpDiscovery_strcpy_Date(param, hdr_value.buf);
354 }
355 /* dest addr */
356 UpnpDiscovery_set_DestAddr(param, dest_addr);
357 /* EXT */
358 if (httpmsg_find_hdr(hmsg, HDR_EXT, &hdr_value) != NULL) {
359 UpnpDiscovery_strncpy_Ext(param, hdr_value.buf, hdr_value.length);
360 }
361 /* LOCATION */
362 if (httpmsg_find_hdr(hmsg, HDR_LOCATION, &hdr_value) != NULL) {
363 UpnpDiscovery_strncpy_Location(param, hdr_value.buf, hdr_value.length);
364 }
365 /* SERVER / USER-AGENT */
366 if (httpmsg_find_hdr(hmsg, HDR_SERVER, &hdr_value) != NULL ||
367 httpmsg_find_hdr(hmsg, HDR_USER_AGENT, &hdr_value) != NULL) {
368 UpnpDiscovery_strncpy_Os(param, hdr_value.buf, hdr_value.length);
369 }
370 /* clear everything */
371 event.UDN[0] = '\0';
372 event.DeviceType[0] = '\0';
373 event.ServiceType[0] = '\0';
374 nt_found = 0;
375 if (httpmsg_find_hdr(hmsg, HDR_NT, &hdr_value) != NULL) {
376 save_char = hdr_value.buf[hdr_value.length];
377 hdr_value.buf[hdr_value.length] = '\0';
378 nt_found = (ssdp_request_type(hdr_value.buf, &event) == 0);
379 hdr_value.buf[hdr_value.length] = save_char;
380 }
381 usn_found = 0;
382 if (httpmsg_find_hdr(hmsg, HDR_USN, &hdr_value) != NULL) {
383 save_char = hdr_value.buf[hdr_value.length];
384 hdr_value.buf[hdr_value.length] = '\0';
385 usn_found = (unique_service_name(hdr_value.buf, &event) == 0);
386 hdr_value.buf[hdr_value.length] = save_char;
387 }
388 if (nt_found || usn_found) {
392 }
393 /* ADVERT. OR BYEBYE */
394 if (hmsg->is_request) {
395 /* use NTS hdr to determine advert., or byebye */
396 if (httpmsg_find_hdr(hmsg, HDR_NTS, &hdr_value) == NULL) {
397 /* error; NTS header not found */
398 goto end_ssdp_handle_ctrlpt_msg;
399 }
400 if (memptr_cmp(&hdr_value, "ssdp:alive") == 0) {
401 is_byebye = 0;
402 } else if (memptr_cmp(&hdr_value, "ssdp:byebye") == 0) {
403 is_byebye = 1;
404 } else {
405 /* bad value */
406 goto end_ssdp_handle_ctrlpt_msg;
407 }
408 if (is_byebye) {
409 /* check device byebye */
410 if (!nt_found || !usn_found) {
411 /* bad byebye */
412 goto end_ssdp_handle_ctrlpt_msg;
413 }
415 } else {
416 /* check advertisement.
417 * Expires is valid if positive. This is for testing
418 * only. Expires should be greater than 1800 (30 mins)
419 */
420 if (!nt_found || !usn_found ||
422 UpnpDiscovery_get_Expires(param) <= 0) {
423 /* bad advertisement */
424 goto end_ssdp_handle_ctrlpt_msg;
425 }
427 }
428 /* call callback */
429 for (handle = handle_start; handle < NUM_HANDLE; handle++) {
430 HandleLock();
431
432 /* get client info */
433 if (GetHandleInfo(handle, &ctrlpt_info) != HND_CLIENT) {
434 HandleUnlock();
435 continue;
436 }
437 /* copy */
438 ctrlpt_callback = ctrlpt_info->Callback;
439 ctrlpt_cookie = ctrlpt_info->Cookie;
440 HandleUnlock();
441
442 ctrlpt_callback(event_type, param, ctrlpt_cookie);
443 }
444 } else {
445 /* reply (to a SEARCH) */
446 /* only checking to see if there is a valid ST header */
447 st_found = 0;
448 if (httpmsg_find_hdr(hmsg, HDR_ST, &hdr_value) != NULL) {
449 save_char = hdr_value.buf[hdr_value.length];
450 hdr_value.buf[hdr_value.length] = '\0';
451 st_found = ssdp_request_type(hdr_value.buf, &event) == 0;
452 hdr_value.buf[hdr_value.length] = save_char;
453 }
454 if (hmsg->status_code != HTTP_OK ||
455 UpnpDiscovery_get_Expires(param) <= 0 ||
457 !usn_found || !st_found) {
458 /* bad reply */
459 goto end_ssdp_handle_ctrlpt_msg;
460 }
461 /* check each current search */
462 for (handle = handle_start; handle < NUM_HANDLE; handle++) {
463 HandleLock();
464
465 /* get client info */
466 if (GetHandleInfo(handle, &ctrlpt_info) != HND_CLIENT) {
467 HandleUnlock();
468 continue;
469 }
470 /* copy */
471 ctrlpt_callback = ctrlpt_info->Callback;
472 ctrlpt_cookie = ctrlpt_info->Cookie;
473
474 node = ListHead(&ctrlpt_info->SsdpSearchList);
475 /* temporary add null termination */
476 /*save_char = hdr_value.buf[ hdr_value.length ]; */
477 /*hdr_value.buf[ hdr_value.length ] = '\0'; */
478 while (node != NULL) {
479 searchArg = (SsdpSearchArg*)node->item;
480 /* check for match of ST header and search
481 * target */
482 switch (searchArg->requestType) {
483 case SSDP_ALL:
484 matched = 1;
485 break;
486 case SSDP_ROOTDEVICE:
487 matched = (event.RequestType == SSDP_ROOTDEVICE);
488 break;
489 case SSDP_DEVICEUDN:
490 matched = !strncmp(searchArg->searchTarget, hdr_value.buf,
491 hdr_value.length);
492 break;
493 case SSDP_DEVICETYPE: {
494 size_t m = std::min(hdr_value.length,
495 strlen(searchArg->searchTarget));
496 matched =
497 !strncmp(searchArg->searchTarget, hdr_value.buf, m);
498 break;
499 }
500 case SSDP_SERVICE: {
501 size_t m = std::min(hdr_value.length,
502 strlen(searchArg->searchTarget));
503 matched =
504 !strncmp(searchArg->searchTarget, hdr_value.buf, m);
505 break;
506 }
507 default:
508 matched = 0;
509 break;
510 }
511 if (matched) {
512 /* schedule call back */
513 threadData = SSDPResultData_new();
514 if (threadData != NULL) {
515 SSDPResultData_set_Param(threadData, param);
516 SSDPResultData_set_Cookie(threadData,
517 searchArg->cookie);
519 ctrlpt_callback);
520 memset(&job, 0, sizeof(job));
521
522 TPJobInit(&job,
523 (UPnPsdk::start_routine)send_search_result,
524 threadData);
525 TPJobSetPriority(&job, MED_PRIORITY);
527 if (ThreadPoolAdd(&gRecvThreadPool, &job, NULL) != 0) {
528 SSDPResultData_delete(threadData);
529 }
530 }
531 }
532 node = ListNext(&ctrlpt_info->SsdpSearchList, node);
533 }
534
535 HandleUnlock();
536 /*ctrlpt_callback( UPNP_DISCOVERY_SEARCH_RESULT, param,
537 * ctrlpt_cookie ); */
538 }
539 }
540
541end_ssdp_handle_ctrlpt_msg:
543}
544
545
546int SearchByTarget(int Hnd, int Mx, char* St, void* Cookie) {
547 char errorBuffer[ERROR_BUFFER_LEN];
548 int* id = NULL;
549 int ret = 0;
550 char ReqBufv4[BUFSIZE];
551#ifdef UPNP_ENABLE_IPV6
552 char ReqBufv6[BUFSIZE];
553 char ReqBufv6UlaGua[BUFSIZE];
554#endif
555 struct sockaddr_storage __ss_v4;
556#ifdef UPNP_ENABLE_IPV6
557 struct sockaddr_storage __ss_v6;
558#endif
559 struct sockaddr_in* destAddr4 = (struct sockaddr_in*)&__ss_v4;
560#ifdef UPNP_ENABLE_IPV6
561 struct sockaddr_in6* destAddr6 = (struct sockaddr_in6*)&__ss_v6;
562#endif
563 fd_set wrSet;
564 SsdpSearchArg* newArg = NULL;
565 SsdpSearchExpArg* expArg = NULL;
566 int timeTillRead = 0;
567 struct Handle_Info* ctrlpt_info = NULL;
568 enum SsdpSearchType requestType;
569 struct in_addr addrv4;
570 SOCKET max_fd = 0;
571 int retVal;
572
573 /*ThreadData *ThData; */
574 ThreadPoolJob job;
575
576 if (strlen(gIF_IPV4) > (size_t)0 &&
577 !inet_pton(AF_INET, gIF_IPV4, &addrv4)) {
579 }
580
581 memset(&job, 0, sizeof(job));
582
583 requestType = ssdp_request_type1(St);
584 if (requestType == SSDP_SERROR)
586 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, "Inside SearchByTarget\n");
587 timeTillRead = Mx;
588 if (timeTillRead < MIN_SEARCH_TIME)
589 timeTillRead = MIN_SEARCH_TIME;
590 else if (timeTillRead > MAX_SEARCH_TIME)
591 timeTillRead = MAX_SEARCH_TIME;
592 retVal = CreateClientRequestPacket(ReqBufv4, sizeof(ReqBufv4), timeTillRead,
593 St, AF_INET);
594 if (retVal != UPNP_E_SUCCESS)
595 return retVal;
596#ifdef UPNP_ENABLE_IPV6
597 retVal = CreateClientRequestPacket(ReqBufv6, sizeof(ReqBufv6), timeTillRead,
598 St, AF_INET6);
599 if (retVal != UPNP_E_SUCCESS)
600 return retVal;
602 ReqBufv6UlaGua, sizeof(ReqBufv6UlaGua), timeTillRead, St, AF_INET6);
603 if (retVal != UPNP_E_SUCCESS)
604 return retVal;
605#endif
606
607 memset(&__ss_v4, 0, sizeof(__ss_v4));
608 destAddr4->sin_family = (sa_family_t)AF_INET;
609 inet_pton(AF_INET, SSDP_IP, &destAddr4->sin_addr);
610 destAddr4->sin_port = htons(SSDP_PORT);
611
612#ifdef UPNP_ENABLE_IPV6
613 memset(&__ss_v6, 0, sizeof(__ss_v6));
614 destAddr6->sin6_family = (sa_family_t)AF_INET6;
615 inet_pton(AF_INET6, SSDP_IPV6_SITELOCAL, &destAddr6->sin6_addr);
616 destAddr6->sin6_port = htons(SSDP_PORT);
617 destAddr6->sin6_scope_id = gIF_INDEX;
618#endif
619
620 /* add search criteria to list */
621 HandleLock();
622 if (GetHandleInfo(Hnd, &ctrlpt_info) != HND_CLIENT) {
623 HandleUnlock();
625 }
626 newArg = (SsdpSearchArg*)malloc(sizeof(SsdpSearchArg));
627 newArg->searchTarget = strdup(St);
628 newArg->cookie = Cookie;
629 newArg->requestType = requestType;
630
631 expArg = (SsdpSearchExpArg*)malloc(sizeof(SsdpSearchExpArg));
632 expArg->handle = Hnd;
633 id = (int*)&(expArg->timeoutEventId);
634 TPJobInit(&job, (UPnPsdk::start_routine)searchExpired, expArg);
635 TPJobSetPriority(&job, MED_PRIORITY);
637 /* Schedule a timeout event to remove search Arg */
638 TimerThreadSchedule(&gTimerThread, timeTillRead, REL_SEC, &job, SHORT_TERM,
639 id);
640 newArg->timeoutEventId = *id;
641 ListAddTail(&ctrlpt_info->SsdpSearchList, newArg);
642 HandleUnlock();
643 /* End of lock */
644
645 FD_ZERO(&wrSet);
646 if (gSsdpReqSocket4 != INVALID_SOCKET) {
647 umock::sys_socket_h.setsockopt(gSsdpReqSocket4, IPPROTO_IP,
648 IP_MULTICAST_IF, (char*)&addrv4,
649 sizeof(addrv4));
650 FD_SET(gSsdpReqSocket4, &wrSet);
651 max_fd = std::max(max_fd, gSsdpReqSocket4);
652 }
653#ifdef UPNP_ENABLE_IPV6
654 if (gSsdpReqSocket6 != INVALID_SOCKET) {
655 umock::sys_socket_h.setsockopt(gSsdpReqSocket6, IPPROTO_IPV6,
656 IPV6_MULTICAST_IF, (char*)&gIF_INDEX,
657 sizeof(gIF_INDEX));
658 FD_SET(gSsdpReqSocket6, &wrSet);
659 max_fd = std::max(max_fd, gSsdpReqSocket6);
660 }
661#endif
662 ret = umock::sys_socket_h.select((int)max_fd + 1, NULL, &wrSet, NULL, NULL);
663 if (ret == -1) {
664 strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
665 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
666 "SSDP_LIB: Error in select(): %s\n", errorBuffer);
667 umock::unistd_h.CLOSE_SOCKET_P(gSsdpReqSocket4);
668#ifdef UPNP_ENABLE_IPV6
669 umock::unistd_h.CLOSE_SOCKET_P(gSsdpReqSocket6);
670#endif
672 }
673#ifdef UPNP_ENABLE_IPV6
674 if (gSsdpReqSocket6 != INVALID_SOCKET &&
675 FD_ISSET(gSsdpReqSocket6, &wrSet)) {
676 int NumCopy = 0;
677
678 while (NumCopy < NUM_SSDP_COPY) {
679 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
680 ">>> SSDP SEND M-SEARCH >>>\n%s\n", ReqBufv6UlaGua);
681 sendto(gSsdpReqSocket6, ReqBufv6UlaGua,
682 (SIZEP_T)strlen(ReqBufv6UlaGua), 0,
683 (struct sockaddr*)&__ss_v6,
684 (SIZEP_T)sizeof(struct sockaddr_in6));
685 NumCopy++;
686 std::this_thread::sleep_for(std::chrono::milliseconds(SSDP_PAUSE));
687 }
688 NumCopy = 0;
689 inet_pton(AF_INET6, SSDP_IPV6_LINKLOCAL, &destAddr6->sin6_addr);
690 while (NumCopy < NUM_SSDP_COPY) {
691 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
692 ">>> SSDP SEND M-SEARCH >>>\n%s\n", ReqBufv6);
693 sendto(gSsdpReqSocket6, ReqBufv6, (SIZEP_T)strlen(ReqBufv6), 0,
694 (struct sockaddr*)&__ss_v6,
695 (SIZEP_T)sizeof(struct sockaddr_in6));
696 NumCopy++;
697 std::this_thread::sleep_for(std::chrono::milliseconds(SSDP_PAUSE));
698 }
699 }
700#endif /* IPv6 */
701 if (gSsdpReqSocket4 != INVALID_SOCKET &&
702 FD_ISSET(gSsdpReqSocket4, &wrSet)) {
703 int NumCopy = 0;
704 while (NumCopy < NUM_SSDP_COPY) {
705 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
706 ">>> SSDP SEND M-SEARCH >>>\n%s\n", ReqBufv4);
707 umock::sys_socket_h.sendto(gSsdpReqSocket4, ReqBufv4,
708 (SIZEP_T)strlen(ReqBufv4), 0,
709 (struct sockaddr*)&__ss_v4,
710 (SIZEP_T)sizeof(struct sockaddr_in));
711 NumCopy++;
712 std::this_thread::sleep_for(std::chrono::milliseconds(SSDP_PAUSE));
713 }
714 }
715
716 return 1;
717}
718
721 SOCKET* ssdpReqSock) {
722 UPnPsdk_LOGINFO("MSG1071") "Executing...\n";
723 u_char ttl = 4;
724
725 UPnPsdk::CSocketErr sockerrObj;
726 *ssdpReqSock = umock::sys_socket_h.socket(AF_INET, SOCK_DGRAM, 0);
727 if (*ssdpReqSock == INVALID_SOCKET) {
728 sockerrObj.catch_error();
729 UPnPsdk_LOGCRIT("MSG1072") "Error in socket(): "
730 << sockerrObj.error_str() << ".\n";
731 return UPNP_E_OUTOF_SOCKET;
732 }
733 umock::sys_socket_h.setsockopt(*ssdpReqSock, IPPROTO_IP, IP_MULTICAST_TTL,
734 (const char*)&ttl, sizeof(ttl));
735 /* just do it, regardless if fails or not. */
736 int ret = umock::pupnp_sock.sock_make_no_blocking(*ssdpReqSock);
737 if (ret == SOCKET_ERROR)
738 // But at least give a critical error message.
739 UPnPsdk_LOGCRIT("MSG1090") "SSDP Request Socket "
740 << *ssdpReqSock
741 << " failed to set \"no blocking\" but continue...\n";
742
743 /* Again, just do it, regardless if fails or not. */
744 return UPNP_E_SUCCESS;
745}
746
747#ifdef UPNP_ENABLE_IPV6
750 SOCKET* ssdpReqSock) {
751 UPnPsdk_LOGINFO("MSG1073") "Executing...\n";
752 char hops = 1;
753
754 UPnPsdk::CSocketErr sockerrObj;
755 *ssdpReqSock = umock::sys_socket_h.socket(AF_INET6, SOCK_DGRAM, 0);
756 if (*ssdpReqSock == INVALID_SOCKET) {
757 sockerrObj.catch_error();
758 UPnPsdk_LOGCRIT("MSG1074") "Error in socket(): "
759 << sockerrObj.error_str() << ".\n";
760 return UPNP_E_OUTOF_SOCKET;
761 }
762 /* MUST use scoping of IPv6 addresses to control the propagation os SSDP
763 * messages instead of relying on the Hop Limit (Equivalent to the TTL
764 * limit in IPv4). */
765 umock::sys_socket_h.setsockopt(*ssdpReqSock, IPPROTO_IPV6,
766 IPV6_MULTICAST_HOPS, &hops, sizeof(hops));
767 /* just do it, regardless if fails or not. */
768 umock::pupnp_sock.sock_make_no_blocking(*ssdpReqSock);
769
770 return UPNP_E_SUCCESS;
771}
772#endif /* IPv6 */
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_DISCOVERY_ADVERTISEMENT_BYEBYE
Definition Callback.hpp:59
@ UPNP_DISCOVERY_ADVERTISEMENT_ALIVE
Definition Callback.hpp:54
@ UPNP_DISCOVERY_SEARCH_TIMEOUT
Definition Callback.hpp:70
int(* Upnp_FunPtr)(Upnp_EventType EventType, const void *Event, void *Cookie)
Definition Callback.hpp:143
#define UPNP_E_BUFFER_TOO_SMALL
The operation completed successfully.
Definition API.hpp:115
int is_request
If 1, msg is a request, else response.
#define HDR_USN
Type of a HTTP header.
#define HDR_DATE
Type of a HTTP header.
#define HDR_NT
Type of a HTTP header.
#define HDR_NTS
Type of a HTTP header.
#define HDR_EXT
Type of a HTTP header.
#define HDR_SERVER
Type of a HTTP header.
#define HDR_ST
Type of a HTTP header.
#define HDR_CACHE_CONTROL
Type of a HTTP header.
#define HDR_LOCATION
Type of a HTTP header.
#define HDR_USER_AGENT
Type of a HTTP header.
@ PARSE_OK
Structure of an HTTP message.
void * ListDelNode(LinkedList *list, ListNode *dnode, int freeItem)
Removes a node from the list. The memory for the node is freed.
ListNode * ListNext(LinkedList *list, ListNode *node)
Returns the next item in the list.
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.
Linked list node. Stores generic item and pointers to next and prev.
void SSDPResultData_Callback(const SSDPResultData *p)
SSDP result data callback function.
SSDPResultData object declararion.
int SSDPResultData_set_Cookie(SSDPResultData *p, void *n)
SSDPResultData_set_Cookie.
int SSDPResultData_set_CtrlptCallback(SSDPResultData *p, Upnp_FunPtr n)
SSDPResultData_set_CtrlptCallback.
void SSDPResultData_delete(SSDPResultData *q)
Destructor.
int SSDPResultData_set_Param(SSDPResultData *p, const UpnpDiscovery *s)
SSDPResultData_set_Param.
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.
int TimerThreadSchedule(TimerThread *timer, time_t timeout, TimeoutType type, ThreadPoolJob *job, Duration duration, int *id)
Schedules an event to run at a specified time.
@ REL_SEC
seconds from current time.
s_UpnpDiscovery
PUPNP_Api int UpnpDiscovery_strcpy_DeviceType(UpnpDiscovery *p, const char *s)
PUPNP_Api void UpnpDiscovery_delete(UpnpDiscovery *p)
PUPNP_Api int UpnpDiscovery_strncpy_Location(UpnpDiscovery *p, const char *s, size_t n)
PUPNP_Api UpnpDiscovery * UpnpDiscovery_new(void)
PUPNP_Api int UpnpDiscovery_strcpy_ServiceType(UpnpDiscovery *p, const char *s)
PUPNP_Api int UpnpDiscovery_set_ErrCode(UpnpDiscovery *p, int n)
PUPNP_Api int UpnpDiscovery_strcpy_DeviceID(UpnpDiscovery *p, const char *s)
PUPNP_Api int UpnpDiscovery_set_DestAddr(UpnpDiscovery *p, const struct sockaddr_storage *buf)
PUPNP_Api int UpnpDiscovery_get_Expires(const UpnpDiscovery *p)
PUPNP_Api const UpnpString * UpnpDiscovery_get_Location(const UpnpDiscovery *p)
PUPNP_Api int UpnpDiscovery_set_Expires(UpnpDiscovery *p, int n)
PUPNP_Api int UpnpDiscovery_strncpy_Ext(UpnpDiscovery *p, const char *s, size_t n)
PUPNP_Api int UpnpDiscovery_strncpy_Os(UpnpDiscovery *p, const char *s, size_t n)
PUPNP_Api int UpnpDiscovery_strcpy_Date(UpnpDiscovery *p, const char *s)
Class for portable handling of network socket errors.
Definition socket.hpp:537
void catch_error()
Catch error for later use.
Definition socket.cpp:609
std::string error_str() const
Get human readable error description of the catched error.
Definition socket.cpp:618
#define NUM_SSDP_COPY
This configuration parameter determines how many copies of each SSDP advertisement and search packets...
Definition config.hpp:142
#define SSDP_PAUSE
This configuration parameter determines the pause between identical SSDP advertisement and search pac...
Definition config.hpp:149
#define MAX_SEARCH_TIME
The MAX_SEARCH_TIME is the maximum time allowed for an SSDP search by a control point....
Definition config.hpp:190
#define MIN_SEARCH_TIME
The MIN_SEARCH_TIME is the minimumm time allowed for an SSDP search by a control point....
Definition config.hpp:197
"protected" structure, addressable with typedef
int ssdp_request_type(char *cmd, SsdpEvent *Evt)
Starts filling the SSDP event structure based upon the request received.
SsdpSearchType ssdp_request_type1(char *cmd)
This function figures out the type of the SSDP search in the request.
SSDPResultData * SSDPResultData_new()
Constructor.
int unique_service_name(char *cmd, SsdpEvent *Evt)
Fills the fields of the event structure like DeviceType, Device UDN and Service Type.
void ssdp_handle_ctrlpt_msg(http_message_t *hmsg, struct sockaddr_storage *dest_addr, int timeout)
This function handles the ssdp messages from the devices.
PUPNP_Api size_t UpnpString_get_Length(const UpnpString *p)
Returns the length of the string.
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'.
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
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
#define UPNP_E_INVALID_ARGUMENT
One or more of the parameters passed to a function is invalid.
Definition messages.hpp:287
#define UPNP_E_SUCCESS
The operation completed successfully.
Definition messages.hpp:27
#define UPNP_E_OUTOF_SOCKET
The SDK cannot create any more sockets.
Definition messages.hpp:219
#define UPNP_E_INVALID_PARAM
One or more of the parameters passed to the function is not valid.
Definition messages.hpp:40
#define UPNP_E_INTERNAL_ERROR
Generic error code for internal conditions not covered by other error codes.
Definition messages.hpp:319
int CreateClientRequestPacketUlaGua(char *RqstBuf, size_t RqstBufSize, int Mx, char *SearchTarget, int AddressFamily)
Creates a HTTP search request packet for IPv6 UlaGua depending on the input parameter.
int CreateClientRequestPacket(char *RqstBuf, size_t RqstBufSize, int Mx, char *SearchTarget, int AddressFamily)
Creates a HTTP search request packet depending on the input parameter.
void send_search_result(void *data)
Sends a callback to the control point application with a SEARCH result.
void searchExpired(void *arg)
Remove search Target from list and call client back.
#define SSDP_PORT
constant
#define COMMAND_LEN
constant
char UDN[LINE_SIZE]
Part of SSDP Event.
constexpr size_t ERROR_BUFFER_LEN
Size of the errorBuffer variable, passed to the strerror_r() function.
#define SSDP_IP
constant
#define SSDP_IPV6_SITELOCAL
constant
char ServiceType[LINE_SIZE]
Part of SSDP Event.
int timeoutEventId
timeout event id
#define SSDP_IPV6_LINKLOCAL
constant
char DeviceType[LINE_SIZE]
Part of SSDP Event.
SOCKET gSsdpReqSocket6
If control point API is compiled in, this is the global IPv6 socket for it.
SOCKET gSsdpReqSocket4
If control point API is compiled in, this is the global IPv4 socket for it.
#define BUFSIZE
constant
SsdpSearchType
Enumeration to define all different types of ssdp searches.
@ SSDP_SERROR
Unknown search command.
@ SSDP_DEVICEUDN
Part of SType.
@ SSDP_DEVICETYPE
Part of SType.
@ SSDP_ROOTDEVICE
Part of SType.
@ SSDP_SERVICE
Part of SType.
@ SSDP_ALL
Part of SType.
Structure to store the SSDP information.
SSDP search exp argument.
int SearchByTarget(int Hnd, int Mx, char *St, void *Cookie)
Creates and send the search request for a specific URL.
int create_ssdp_sock_reqv6(SOCKET *ssdpReqSock)
Creates the SSDP IPv6 socket to be used by the control point.
int create_ssdp_sock_reqv4(SOCKET *ssdpReqSock)
Creates the SSDP IPv4 socket to be used by the control point.
Manage "Step 1: Discovery" of the UPnP+™ specification for Control Points with SSDP.
int timeoutEventId
part of search argument
enum SsdpSearchType requestType
part of search argument
void * cookie
part of search argument
char * searchTarget
part of search argument
SSDP search argument.
HTTP status codes.
Upnp_Handle_Type GetHandleInfo(UpnpClient_Handle Hnd, Handle_Info **HndInfo)
Get handle information.
Definition upnpapi.cpp:3342
ThreadPool gRecvThreadPool
Receive thread pool.
Definition upnpapi.cpp:262
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
unsigned gIF_INDEX
Contains network interface index of the link local address gIF_IPV6 that is used as its scope_id.
Definition upnpapi.cpp:299
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
#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
LinkedList SsdpSearchList
Active SSDP searches.
Definition upnpapi.hpp:119
#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.