UPnPsdk 0.1
Universal Plug and Play +, Software Development Kit
 
Loading...
Searching...
No Matches
ssdp_device.cpp
Go to the documentation of this file.
1/**************************************************************************
2 *
3 * Copyright (c) 2000-2003 Intel Corporation
4 * All rights reserved.
5 * Copyright (C) 2011-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-04-30
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 2024-02-16, ver 1.14.18
43#include <ssdp_device.hpp>
44
45#include <httpreadwrite.hpp>
46#include <statcodes.hpp>
47#include <upnpapi.hpp>
48#include <webserver.hpp>
49
50#include <umock/sys_socket.hpp>
51
52#ifndef COMPA_INTERNAL_CONFIG_HPP
53#error "No or wrong config.hpp header file included."
54#endif
55
57#include <cassert>
58#include <thread>
60
61
62namespace {
63
68constexpr int MSGTYPE_SHUTDOWN{0};
69constexpr int MSGTYPE_ADVERTISEMENT{1};
70constexpr int MSGTYPE_REPLY{2};
73
91 struct sockaddr* DestAddr,
93 int NumPacket,
95 char** RqPacket) {
96 char errorBuffer[ERROR_BUFFER_LEN];
97 SOCKET ReplySock;
98 socklen_t socklen = sizeof(struct sockaddr_storage);
99 int Index;
100 struct in_addr replyAddr;
101 /* a/c to UPNP Spec */
102 int ttl = 4;
103#ifdef UPNP_ENABLE_IPV6
104 int hops = 1;
105#endif
106 char buf_ntop[INET6_ADDRSTRLEN];
107 int ret = UPNP_E_SUCCESS;
108
109 if (strlen(gIF_IPV4) > (size_t)0 &&
110 !inet_pton(AF_INET, gIF_IPV4, &replyAddr)) {
112 }
113
114 ReplySock =
115 umock::sys_socket_h.socket((int)DestAddr->sa_family, SOCK_DGRAM, 0);
116 if (ReplySock == INVALID_SOCKET) {
117 strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
118 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
119 "SSDP_LIB: New Request Handler:"
120 "Error in socket(): %s\n",
121 errorBuffer);
122
123 return UPNP_E_OUTOF_SOCKET;
124 }
125
126 switch (DestAddr->sa_family) {
127 case AF_INET:
128 inet_ntop(AF_INET, &((struct sockaddr_in*)DestAddr)->sin_addr, buf_ntop,
129 sizeof(buf_ntop));
130 umock::sys_socket_h.setsockopt(ReplySock, IPPROTO_IP, IP_MULTICAST_IF,
131 (char*)&replyAddr, sizeof(replyAddr));
132 umock::sys_socket_h.setsockopt(ReplySock, IPPROTO_IP, IP_MULTICAST_TTL,
133 (char*)&ttl, sizeof(int));
134 socklen = sizeof(struct sockaddr_in);
135 break;
136#ifdef UPNP_ENABLE_IPV6
137 case AF_INET6:
138 inet_ntop(AF_INET6, &((struct sockaddr_in6*)DestAddr)->sin6_addr,
139 buf_ntop, sizeof(buf_ntop));
140 umock::sys_socket_h.setsockopt(ReplySock, IPPROTO_IPV6,
141 IPV6_MULTICAST_IF, (char*)&gIF_INDEX,
142 sizeof(gIF_INDEX));
143 umock::sys_socket_h.setsockopt(ReplySock, IPPROTO_IPV6,
144 IPV6_MULTICAST_HOPS, (char*)&hops,
145 sizeof(hops));
146 break;
147#endif
148 default:
149 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
150 "Invalid destination address specified.");
152 goto end_NewRequestHandler;
153 }
154
155 for (Index = 0; Index < NumPacket; Index++) {
156 ssize_t rc;
157 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
158 ">>> SSDP SEND to %s >>>\n%s\n", buf_ntop,
159 *(RqPacket + Index));
160 rc = sendto(ReplySock, *(RqPacket + Index),
161 (SIZEP_T)strlen(*(RqPacket + Index)), 0, DestAddr,
162 (SIZEP_T)socklen);
163 if (rc == -1) {
164 strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
165 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
166 "SSDP_LIB: New Request Handler:"
167 "Error in socket(): %s\n",
168 errorBuffer);
170 goto end_NewRequestHandler;
171 }
172 }
173
174end_NewRequestHandler:
175 umock::unistd_h.CLOSE_SOCKET_P(ReplySock);
176
177 return ret;
178}
179
185inline int extractIPv6address( //
186 char* url,
187 char* address
188) {
189 int i = 0;
190 int j = 0;
191 int ret = 0;
192
193 while (url[i] != '[' && url[i] != '\0') {
194 i++;
195 }
196 if (url[i] == '\0') {
197 goto exit_function;
198 }
199
200 /* bracket has been found, we deal with an IPv6 address */
201 i++;
202 while (url[i] != '\0' && url[i] != ']') {
203 address[j] = url[i];
204 i++;
205 j++;
206 }
207 if (url[i] == '\0') {
208 goto exit_function;
209 }
210
211 if (url[i] == ']') {
212 address[j] = '\0';
213 ret = 1;
214 }
215
216exit_function:
217 return ret;
218}
219
227 char* descdocUrl
228) {
229 char address[INET6_ADDRSTRLEN];
230 struct in6_addr v6_addr;
231
232 if (extractIPv6address(descdocUrl, address)) {
233 inet_pton(AF_INET6, address, &v6_addr);
234 return !IN6_IS_ADDR_LINKLOCAL(&v6_addr);
235 }
236
237 return 0;
238}
239
249 int msg_type,
251 const char* nt,
253 char* usn,
255 char* location,
257 int duration,
259 char** packet,
261 int AddressFamily,
263 int PowerState,
265 int SleepPeriod,
267 int RegistrationState) {
268 int ret_code;
269 const char* nts;
270 membuffer buf;
271
272 /* Notf == 0 means service shutdown,
273 * Notf == 1 means service advertisement,
274 * Notf == 2 means reply */
275 membuffer_init(&buf);
276 buf.size_inc = (size_t)30;
277 *packet = NULL;
278 if (msg_type == MSGTYPE_REPLY) {
279 if (PowerState > 0) {
280#ifdef COMPA_HAVE_OPTION_SSDP
281 ret_code = http_MakeMessage(
282 &buf, 1, 1,
283 "R"
284 "sdc"
285 "D"
286 "sc"
287 "ssc"
288 "ssc"
289 "ssc"
290 "S"
291 "Xc"
292 "ssc"
293 "ssc"
294 "sdc"
295 "sdc"
296 "sdcc",
297 HTTP_OK, "CACHE-CONTROL: max-age=", duration,
298 "EXT:", "LOCATION: ", location,
299 "OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01",
300 "01-NLS: ", gUpnpSdkNLSuuid, X_USER_AGENT, "ST: ", nt,
301 "USN: ", usn, "Powerstate: ", PowerState,
302 "SleepPeriod: ", SleepPeriod,
303 "RegistrationState: ", RegistrationState);
304#else
305 ret_code = http_MakeMessage(
306 &buf, 1, 1,
307 "R"
308 "sdc"
309 "D"
310 "sc"
311 "ssc"
312 "S"
313 "ssc"
314 "ssc"
315 "sdc"
316 "sdc"
317 "sdcc",
318 HTTP_OK, "CACHE-CONTROL: max-age=", duration,
319 "EXT:", "LOCATION: ", location, "ST: ", nt, "USN: ", usn,
320 "Powerstate: ", PowerState, "SleepPeriod: ", SleepPeriod,
321 "RegistrationState: ", RegistrationState);
322#endif /* COMPA_HAVE_OPTION_SSDP */
323 } else {
324#ifdef COMPA_HAVE_OPTION_SSDP
325 ret_code = http_MakeMessage(
326 &buf, 1, 1,
327 "R"
328 "sdc"
329 "D"
330 "sc"
331 "ssc"
332 "ssc"
333 "ssc"
334 "S"
335 "Xc"
336 "ssc"
337 "sscc",
338 HTTP_OK, "CACHE-CONTROL: max-age=", duration,
339 "EXT:", "LOCATION: ", location,
340 "OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01",
341 "01-NLS: ", gUpnpSdkNLSuuid, X_USER_AGENT, "ST: ", nt,
342 "USN: ", usn);
343#else
344 ret_code = http_MakeMessage(
345 &buf, 1, 1,
346 "R"
347 "sdc"
348 "D"
349 "sc"
350 "ssc"
351 "S"
352 "ssc"
353 "sscc",
354 HTTP_OK, "CACHE-CONTROL: max-age=", duration,
355 "EXT:", "LOCATION: ", location, "ST: ", nt, "USN: ", usn);
356#endif /* COMPA_HAVE_OPTION_SSDP */
357 }
358 if (ret_code != 0) {
359 return;
360 }
361 } else if (msg_type == MSGTYPE_ADVERTISEMENT ||
362 msg_type == MSGTYPE_SHUTDOWN) {
363 const char* host = NULL;
364
365 if (msg_type == MSGTYPE_ADVERTISEMENT)
366 nts = "ssdp:alive";
367 else
368 /* shutdown */
369 nts = "ssdp:byebye";
370 /* NOTE: The CACHE-CONTROL and LOCATION headers are not present in a
371 * shutdown msg, but are present here for MS WinMe interop. */
372 switch (AddressFamily) {
373 case AF_INET:
374 host = SSDP_IP;
375 break;
376 default:
377 if (isUrlV6UlaGua(location))
378 host = "[" SSDP_IPV6_SITELOCAL "]";
379 else
380 host = "[" SSDP_IPV6_LINKLOCAL "]";
381 }
382 if (PowerState > 0) {
383#ifdef COMPA_HAVE_OPTION_SSDP
384 ret_code = http_MakeMessage(
385 &buf, 1, 1,
386 "Q"
387 "sssdc"
388 "sdc"
389 "ssc"
390 "ssc"
391 "ssc"
392 "ssc"
393 "ssc"
394 "S"
395 "Xc"
396 "ssc"
397 "sdc"
398 "sdc"
399 "sdcc",
400 HTTPMETHOD_NOTIFY, "*", (size_t)1, "HOST: ", host, ":",
401 SSDP_PORT, "CACHE-CONTROL: max-age=", duration,
402 "LOCATION: ", location,
403 "OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01",
404 "01-NLS: ", gUpnpSdkNLSuuid, "NT: ", nt, "NTS: ", nts,
405 X_USER_AGENT, "USN: ", usn, "Powerstate: ", PowerState,
406 "SleepPeriod: ", SleepPeriod,
407 "RegistrationState: ", RegistrationState);
408#else
409 ret_code = http_MakeMessage(
410 &buf, 1, 1,
411 "Q"
412 "sssdc"
413 "sdc"
414 "ssc"
415 "ssc"
416 "ssc"
417 "S"
418 "ssc"
419 "sdc"
420 "sdc"
421 "sdcc",
422 HTTPMETHOD_NOTIFY, "*", (size_t)1, "HOST: ", host, ":",
423 SSDP_PORT, "CACHE-CONTROL: max-age=", duration,
424 "LOCATION: ", location, "NT: ", nt, "NTS: ", nts, "USN: ", usn,
425 "Powerstate: ", PowerState, "SleepPeriod: ", SleepPeriod,
426 "RegistrationState: ", RegistrationState);
427#endif /* COMPA_HAVE_OPTION_SSDP */
428 } else {
429#ifdef COMPA_HAVE_OPTION_SSDP
430 ret_code = http_MakeMessage(
431 &buf, 1, 1,
432 "Q"
433 "sssdc"
434 "sdc"
435 "ssc"
436 "ssc"
437 "ssc"
438 "ssc"
439 "ssc"
440 "S"
441 "Xc"
442 "sscc",
443 HTTPMETHOD_NOTIFY, "*", (size_t)1, "HOST: ", host, ":",
444 SSDP_PORT, "CACHE-CONTROL: max-age=", duration,
445 "LOCATION: ", location,
446 "OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01",
447 "01-NLS: ", gUpnpSdkNLSuuid, "NT: ", nt, "NTS: ", nts,
448 X_USER_AGENT, "USN: ", usn);
449#else
450 ret_code = http_MakeMessage(
451 &buf, 1, 1,
452 "Q"
453 "sssdc"
454 "sdc"
455 "ssc"
456 "ssc"
457 "ssc"
458 "S"
459 "sscc",
460 HTTPMETHOD_NOTIFY, "*", (size_t)1, "HOST: ", host, ":",
461 SSDP_PORT, "CACHE-CONTROL: max-age=", duration,
462 "LOCATION: ", location, "NT: ", nt, "NTS: ", nts, "USN: ", usn);
463#endif /* COMPA_HAVE_OPTION_SSDP */
464 }
465 if (ret_code)
466 return;
467 } else
468 /* unknown msg */
469 assert(0);
470 /* return msg */
471 *packet = membuffer_detach(&buf);
472 membuffer_destroy(&buf);
473
474 return;
475}
476
478} // anonymous namespace
479
480
482 struct sockaddr_storage* dest_addr) {
483 constexpr int MX_FUDGE_FACTOR{10};
484 int handle, start;
485 struct Handle_Info* dev_info = NULL;
486 memptr hdr_value;
487 int mx;
488 char save_char;
489 SsdpEvent event;
490 int ret_code;
491 SsdpSearchReply* threadArg = NULL;
492 ThreadPoolJob job;
493 int replyTime;
494 int maxAge;
495
496 memset(&job, 0, sizeof(job));
497
498 /* check man hdr. */
499 if (httpmsg_find_hdr(hmsg, HDR_MAN, &hdr_value) == NULL ||
500 memptr_cmp(&hdr_value, "\"ssdp:discover\"") != 0)
501 /* bad or missing hdr. */
502 return;
503 /* MX header. */
504 if (httpmsg_find_hdr(hmsg, HDR_MX, &hdr_value) == NULL ||
505 (mx = raw_to_int(&hdr_value, 10)) < 0)
506 return;
507 /* ST header. */
508 if (httpmsg_find_hdr(hmsg, HDR_ST, &hdr_value) == NULL)
509 return;
510 save_char = hdr_value.buf[hdr_value.length];
511 hdr_value.buf[hdr_value.length] = '\0';
512 ret_code = ssdp_request_type(hdr_value.buf, &event);
513 /* restore. */
514 hdr_value.buf[hdr_value.length] = save_char;
515 if (ret_code == -1)
516 /* bad ST header. */
517 return;
518
519 start = 0;
520 for (;;) {
521 HandleLock();
522 /* device info. */
523 switch (GetDeviceHandleInfo(start, (int)dest_addr->ss_family, &handle,
524 &dev_info)) {
525 case HND_DEVICE:
526 break;
527 default:
528 HandleUnlock();
529 /* no info found. */
530 return;
531 }
532 maxAge = dev_info->MaxAge;
533 HandleUnlock();
534
535 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "MAX-AGE = %d\n",
536 maxAge);
537 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "MX = %d\n",
538 event.Mx);
539 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceType = %s\n",
540 event.DeviceType);
541 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "DeviceUuid = %s\n",
542 event.UDN);
543 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "ServiceType = %s\n",
544 event.ServiceType);
545 threadArg = (SsdpSearchReply*)malloc(sizeof(SsdpSearchReply));
546 if (threadArg == NULL)
547 return;
548 threadArg->handle = handle;
549 memcpy(&threadArg->dest_addr, dest_addr, sizeof(threadArg->dest_addr));
550 threadArg->event = event;
551 threadArg->MaxAge = maxAge;
552
553 TPJobInit(&job, advertiseAndReplyThread, threadArg);
555
556 /* Subtract a percentage from the mx to allow for network and processing
557 * delays (i.e. if search is for 30 seconds, respond
558 * within 0 - 27 seconds). */
559 if (mx >= 2)
560 mx -= std::max(1, mx / MX_FUDGE_FACTOR);
561 if (mx < 1)
562 mx = 1;
563 replyTime = rand() % mx;
564 TimerThreadSchedule(&gTimerThread, replyTime, REL_SEC, &job, SHORT_TERM,
565 NULL);
566 start = handle;
567 }
568}
569
570int DeviceAdvertisement(char* DevType, int RootDev, char* Udn, char* Location,
571 int Duration, int AddressFamily, int PowerState,
573 struct sockaddr_storage __ss;
574 struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss;
575 struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss;
576 /* char Mil_Nt[LINE_SIZE] */
577 char Mil_Usn[LINE_SIZE];
578 char* msgs[3];
579 int ret_code = UPNP_E_OUTOF_MEMORY;
580 int rc = 0;
581
582 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
583 "In function DeviceAdvertisement\n");
584 memset(&__ss, 0, sizeof(__ss));
585 switch (AddressFamily) {
586 case AF_INET:
587 DestAddr4->sin_family = (sa_family_t)AF_INET;
588 inet_pton(AF_INET, SSDP_IP, &DestAddr4->sin_addr);
589 DestAddr4->sin_port = htons(SSDP_PORT);
590 break;
591 case AF_INET6:
592 DestAddr6->sin6_family = (sa_family_t)AF_INET6;
593 inet_pton(AF_INET6,
596 &DestAddr6->sin6_addr);
597 DestAddr6->sin6_port = htons(SSDP_PORT);
598 DestAddr6->sin6_scope_id = gIF_INDEX;
599 break;
600 default:
601 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
602 "Invalid device address family.\n");
603 }
604 msgs[0] = NULL;
605 msgs[1] = NULL;
606 msgs[2] = NULL;
607 // If device is a root device, here we need to send 3 advertisement or reply
608 if (RootDev) {
609 rc = snprintf(Mil_Usn, sizeof(Mil_Usn), "%s::upnp:rootdevice", Udn);
610 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Usn))
611 goto error_handler;
612 CreateServicePacket(MSGTYPE_ADVERTISEMENT, "upnp:rootdevice", Mil_Usn,
613 Location, Duration, &msgs[0], AddressFamily,
614 PowerState, SleepPeriod, RegistrationState);
615 }
616 /* both root and sub-devices need to send these two messages */
618 &msgs[1], AddressFamily, PowerState, SleepPeriod,
619 RegistrationState);
620 rc = snprintf(Mil_Usn, sizeof(Mil_Usn), "%s::%s", Udn, DevType);
621 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Usn))
622 goto error_handler;
623 CreateServicePacket(MSGTYPE_ADVERTISEMENT, DevType, Mil_Usn, Location,
624 Duration, &msgs[2], AddressFamily, PowerState,
625 SleepPeriod, RegistrationState);
626 /* check error */
627 if ((RootDev && msgs[0] == NULL) || msgs[1] == NULL || msgs[2] == NULL) {
628 goto error_handler;
629 }
630 /* send packets */
631 if (RootDev) {
632 /* send 3 msg types */
633 ret_code = NewRequestHandler((struct sockaddr*)&__ss, 3, &msgs[0]);
634 } else { /* sub-device */
635
636 /* send 2 msg types */
637 ret_code = NewRequestHandler((struct sockaddr*)&__ss, 2, &msgs[1]);
638 }
639
640error_handler:
641 /* free msgs */
642 free(msgs[0]);
643 free(msgs[1]);
644 free(msgs[2]);
645
646 return ret_code;
647}
648
649int SendReply(struct sockaddr* DestAddr, char* DevType, int RootDev, char* Udn,
650 char* Location, int Duration, int ByType, int PowerState,
651 int SleepPeriod, int RegistrationState) {
652 int ret_code = UPNP_E_OUTOF_MEMORY;
653 char* msgs[2];
654 int num_msgs;
655 char Mil_Usn[LINE_SIZE];
656 int i;
657 int rc = 0;
658
659 msgs[0] = NULL;
660 msgs[1] = NULL;
661 if (RootDev) {
662 /* one msg for root device */
663 num_msgs = 1;
664
665 rc = snprintf(Mil_Usn, sizeof(Mil_Usn), "%s::upnp:rootdevice", Udn);
666 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Usn))
667 goto error_handler;
668 CreateServicePacket(MSGTYPE_REPLY, "upnp:rootdevice", Mil_Usn, Location,
669 Duration, &msgs[0], (int)DestAddr->sa_family,
670 PowerState, SleepPeriod, RegistrationState);
671 } else {
672 /* two msgs for embedded devices */
673 num_msgs = 1;
674
675 /*NK: FIX for extra response when someone searches by udn */
676 if (!ByType) {
677 CreateServicePacket(MSGTYPE_REPLY, Udn, Udn, Location, Duration,
678 &msgs[0], (int)DestAddr->sa_family, PowerState,
679 SleepPeriod, RegistrationState);
680 } else {
681 rc = snprintf(Mil_Usn, sizeof(Mil_Usn), "%s::%s", Udn, DevType);
682 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Usn))
683 goto error_handler;
684 CreateServicePacket(MSGTYPE_REPLY, DevType, Mil_Usn, Location,
685 Duration, &msgs[0], (int)DestAddr->sa_family,
686 PowerState, SleepPeriod, RegistrationState);
687 }
688 }
689 /* check error */
690 for (i = 0; i < num_msgs; i++) {
691 if (msgs[i] == NULL) {
692 goto error_handler;
693 }
694 }
695 /* send msgs */
696 ret_code = NewRequestHandler(DestAddr, num_msgs, msgs);
697
698error_handler:
699 for (i = 0; i < num_msgs; i++) {
700 if (msgs[i] != NULL)
701 free(msgs[i]);
702 }
703
704 return ret_code;
705}
706
707int DeviceReply(struct sockaddr* DestAddr, char* DevType, int RootDev,
708 char* Udn, char* Location, int Duration, int PowerState,
709 int SleepPeriod, int RegistrationState) {
710 char *szReq[3], Mil_Nt[LINE_SIZE], Mil_Usn[LINE_SIZE];
711 int RetVal = UPNP_E_OUTOF_MEMORY;
712 int rc = 0;
713
714 szReq[0] = NULL;
715 szReq[1] = NULL;
716 szReq[2] = NULL;
717 /* create 2 or 3 msgs */
718 if (RootDev) {
719 /* 3 replies for root device */
720 memset(Mil_Nt, 0, sizeof(Mil_Nt));
721 strncpy(Mil_Nt, "upnp:rootdevice", sizeof(Mil_Nt) - 1);
722 rc = snprintf(Mil_Usn, sizeof(Mil_Usn), "%s::upnp:rootdevice", Udn);
723 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Usn))
724 goto error_handler;
725 CreateServicePacket(MSGTYPE_REPLY, Mil_Nt, Mil_Usn, Location, Duration,
726 &szReq[0], (int)DestAddr->sa_family, PowerState,
727 SleepPeriod, RegistrationState);
728 }
729 rc = snprintf(Mil_Nt, sizeof(Mil_Nt), "%s", Udn);
730 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Nt))
731 goto error_handler;
732 rc = snprintf(Mil_Usn, sizeof(Mil_Usn), "%s", Udn);
733 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Usn))
734 goto error_handler;
735 CreateServicePacket(MSGTYPE_REPLY, Mil_Nt, Mil_Usn, Location, Duration,
736 &szReq[1], (int)DestAddr->sa_family, PowerState,
737 SleepPeriod, RegistrationState);
738 rc = snprintf(Mil_Nt, sizeof(Mil_Nt), "%s", DevType);
739 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Nt))
740 goto error_handler;
741 rc = snprintf(Mil_Usn, sizeof(Mil_Usn), "%s::%s", Udn, DevType);
742 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Usn))
743 goto error_handler;
744 CreateServicePacket(MSGTYPE_REPLY, Mil_Nt, Mil_Usn, Location, Duration,
745 &szReq[2], (int)DestAddr->sa_family, PowerState,
746 SleepPeriod, RegistrationState);
747 /* check error */
748 if ((RootDev && szReq[0] == NULL) || szReq[1] == NULL || szReq[2] == NULL) {
749 goto error_handler;
750 }
751 /* send replies */
752 if (RootDev) {
753 RetVal = NewRequestHandler(DestAddr, 3, szReq);
754 } else {
755 RetVal = NewRequestHandler(DestAddr, 2, &szReq[1]);
756 }
757
758error_handler:
759 /* free */
760 free(szReq[0]);
761 free(szReq[1]);
762 free(szReq[2]);
763
764 return RetVal;
765}
766
767int ServiceAdvertisement(char* Udn, char* ServType, char* Location,
768 int Duration, int AddressFamily, int PowerState,
769 int SleepPeriod, int RegistrationState) {
770 char Mil_Usn[LINE_SIZE];
771 char* szReq[1];
772 int RetVal = UPNP_E_OUTOF_MEMORY;
773 struct sockaddr_storage __ss;
774 struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss;
775 struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss;
776 int rc = 0;
777
778 memset(&__ss, 0, sizeof(__ss));
779 szReq[0] = NULL;
780 switch (AddressFamily) {
781 case AF_INET:
782 DestAddr4->sin_family = (sa_family_t)AddressFamily;
783 inet_pton(AF_INET, SSDP_IP, &DestAddr4->sin_addr);
784 DestAddr4->sin_port = htons(SSDP_PORT);
785 break;
786 case AF_INET6:
787 DestAddr6->sin6_family = (sa_family_t)AddressFamily;
788 inet_pton(AF_INET6,
791 &DestAddr6->sin6_addr);
792 DestAddr6->sin6_port = htons(SSDP_PORT);
793 DestAddr6->sin6_scope_id = gIF_INDEX;
794 break;
795 default:
796 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
797 "Invalid device address family.\n");
798 }
799 rc = snprintf(Mil_Usn, sizeof(Mil_Usn), "%s::%s", Udn, ServType);
800 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Usn))
801 goto error_handler;
802 /* CreateServiceRequestPacket(1,szReq[0],Mil_Nt,Mil_Usn,
803 * Server,Location,Duration); */
804 CreateServicePacket(MSGTYPE_ADVERTISEMENT, ServType, Mil_Usn, Location,
805 Duration, &szReq[0], AddressFamily, PowerState,
806 SleepPeriod, RegistrationState);
807 if (szReq[0] == NULL) {
808 goto error_handler;
809 }
810 RetVal = NewRequestHandler((struct sockaddr*)&__ss, 1, szReq);
811
812error_handler:
813 free(szReq[0]);
814
815 return RetVal;
816}
817
818int ServiceReply(struct sockaddr* DestAddr, char* ServType, char* Udn,
819 char* Location, int Duration, int PowerState, int SleepPeriod,
820 int RegistrationState) {
821 char Mil_Usn[LINE_SIZE];
822 char* szReq[1];
823 int RetVal = UPNP_E_OUTOF_MEMORY;
824 int rc = 0;
825
826 szReq[0] = NULL;
827 rc = snprintf(Mil_Usn, sizeof(Mil_Usn), "%s::%s", Udn, ServType);
828 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Usn))
829 goto error_handler;
830 CreateServicePacket(MSGTYPE_REPLY, ServType, Mil_Usn, Location, Duration,
831 &szReq[0], (int)DestAddr->sa_family, PowerState,
832 SleepPeriod, RegistrationState);
833 if (szReq[0] == NULL)
834 goto error_handler;
835 RetVal = NewRequestHandler(DestAddr, 1, szReq);
836
837error_handler:
838 free(szReq[0]);
839
840 return RetVal;
841}
842
843int ServiceShutdown(char* Udn, char* ServType, char* Location, int Duration,
844 int AddressFamily, int PowerState, int SleepPeriod,
845 int RegistrationState) {
846 char Mil_Usn[LINE_SIZE];
847 char* szReq[1];
848 struct sockaddr_storage __ss;
849 struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss;
850 struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss;
851 int RetVal = UPNP_E_OUTOF_MEMORY;
852 int rc = 0;
853
854 memset(&__ss, 0, sizeof(__ss));
855 szReq[0] = NULL;
856 switch (AddressFamily) {
857 case AF_INET:
858 DestAddr4->sin_family = (sa_family_t)AddressFamily;
859 inet_pton(AF_INET, SSDP_IP, &DestAddr4->sin_addr);
860 DestAddr4->sin_port = htons(SSDP_PORT);
861 break;
862 case AF_INET6:
863 DestAddr6->sin6_family = (sa_family_t)AddressFamily;
864 inet_pton(AF_INET6,
867 &DestAddr6->sin6_addr);
868 DestAddr6->sin6_port = htons(SSDP_PORT);
869 DestAddr6->sin6_scope_id = gIF_INDEX;
870 break;
871 default:
872 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
873 "Invalid device address family.\n");
874 }
875 /* sprintf(Mil_Nt,"%s",ServType); */
876 rc = snprintf(Mil_Usn, sizeof(Mil_Usn), "%s::%s", Udn, ServType);
877 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Usn))
878 goto error_handler;
879 /* CreateServiceRequestPacket(0,szReq[0],Mil_Nt,Mil_Usn,
880 * Server,Location,Duration); */
881 CreateServicePacket(MSGTYPE_SHUTDOWN, ServType, Mil_Usn, Location, Duration,
882 &szReq[0], AddressFamily, PowerState, SleepPeriod,
883 RegistrationState);
884 if (szReq[0] == NULL)
885 goto error_handler;
886 RetVal = NewRequestHandler((struct sockaddr*)&__ss, 1, szReq);
887
888error_handler:
889 free(szReq[0]);
890
891 return RetVal;
892}
893
894int DeviceShutdown(char* DevType, int RootDev, char* Udn, char* Location,
895 int Duration, int AddressFamily, int PowerState,
896 int SleepPeriod, int RegistrationState) {
897 struct sockaddr_storage __ss;
898 struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss;
899 struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss;
900 char* msgs[3];
901 char Mil_Usn[LINE_SIZE];
902 int ret_code = UPNP_E_OUTOF_MEMORY;
903 int rc = 0;
904
905 msgs[0] = NULL;
906 msgs[1] = NULL;
907 msgs[2] = NULL;
908 memset(&__ss, 0, sizeof(__ss));
909 switch (AddressFamily) {
910 case AF_INET:
911 DestAddr4->sin_family = (sa_family_t)AddressFamily;
912 inet_pton(AF_INET, SSDP_IP, &DestAddr4->sin_addr);
913 DestAddr4->sin_port = htons(SSDP_PORT);
914 break;
915 case AF_INET6:
916 DestAddr6->sin6_family = (sa_family_t)AddressFamily;
917 inet_pton(AF_INET6,
920 &DestAddr6->sin6_addr);
921 DestAddr6->sin6_port = htons(SSDP_PORT);
922 DestAddr6->sin6_scope_id = gIF_INDEX;
923 break;
924 default:
925 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
926 "Invalid device address family.\n");
927 }
928 /* root device has one extra msg */
929 if (RootDev) {
930 rc = snprintf(Mil_Usn, sizeof(Mil_Usn), "%s::upnp:rootdevice", Udn);
931 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Usn))
932 goto error_handler;
933 CreateServicePacket(MSGTYPE_SHUTDOWN, "upnp:rootdevice", Mil_Usn,
934 Location, Duration, &msgs[0], AddressFamily,
935 PowerState, SleepPeriod, RegistrationState);
936 }
937 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
938 "In function DeviceShutdown\n");
939 /* both root and sub-devices need to send these two messages */
940 CreateServicePacket(MSGTYPE_SHUTDOWN, Udn, Udn, Location, Duration,
941 &msgs[1], AddressFamily, PowerState, SleepPeriod,
942 RegistrationState);
943 rc = snprintf(Mil_Usn, sizeof(Mil_Usn), "%s::%s", Udn, DevType);
944 if (rc < 0 || (unsigned int)rc >= sizeof(Mil_Usn))
945 goto error_handler;
946 CreateServicePacket(MSGTYPE_SHUTDOWN, DevType, Mil_Usn, Location, Duration,
947 &msgs[2], AddressFamily, PowerState, SleepPeriod,
948 RegistrationState);
949 /* check error */
950 if ((RootDev && msgs[0] == NULL) || msgs[1] == NULL || msgs[2] == NULL) {
951 goto error_handler;
952 }
953 /* send packets */
954 if (RootDev) {
955 /* send 3 msg types */
956 ret_code = NewRequestHandler((struct sockaddr*)&__ss, 3, &msgs[0]);
957 } else {
958 /* sub-device */
959 /* send 2 msg types */
960 ret_code = NewRequestHandler((struct sockaddr*)&__ss, 2, &msgs[1]);
961 }
962
963error_handler:
964 /* free msgs */
965 free(msgs[0]);
966 free(msgs[1]);
967 free(msgs[2]);
968
969 return ret_code;
970}
971
973 enum SsdpSearchType SearchType, struct sockaddr* DestAddr,
974 char* DeviceType, char* DeviceUDN, char* ServiceType,
975 int Exp) {
976 constexpr char SERVICELIST_STR[] = "serviceList";
977 int retVal = UPNP_E_SUCCESS;
978 long unsigned int i;
979 long unsigned int j;
980 int defaultExp = DEFAULT_MAXAGE;
981 struct Handle_Info* SInfo = NULL;
982 char UDNstr[100];
983 char devType[100];
984 char servType[100];
985 IXML_NodeList* nodeList = NULL;
986 IXML_NodeList* tmpNodeList = NULL;
987 IXML_Node* tmpNode = NULL;
988 IXML_Node* tmpNode2 = NULL;
989 IXML_Node* textNode = NULL;
990 const DOMString tmpStr;
991 const DOMString dbgStr;
992 int NumCopy = 0;
993
994 memset(UDNstr, 0, sizeof(UDNstr));
995 memset(devType, 0, sizeof(devType));
996 memset(servType, 0, sizeof(servType));
997
998 UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
999 "Inside AdvertiseAndReply with AdFlag = %d\n", AdFlag);
1000
1001 /* Use a read lock */
1003 if (GetHandleInfo(Hnd, &SInfo) != HND_DEVICE) {
1004 retVal = UPNP_E_INVALID_HANDLE;
1005 goto end_function;
1006 }
1007 defaultExp = SInfo->MaxAge;
1008 /* parse the device list and send advertisements/replies */
1009 while (NumCopy == 0 || (AdFlag && NumCopy < NUM_SSDP_COPY)) {
1010 if (NumCopy != 0)
1011 std::this_thread::sleep_for(std::chrono::milliseconds(SSDP_PAUSE));
1012 NumCopy++;
1013 for (i = 0lu;; i++) {
1014 UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
1015 "Entering new device list with i = %lu\n\n", i);
1016 tmpNode = ixmlNodeList_item(SInfo->DeviceList, i);
1017 if (!tmpNode) {
1018 UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
1019 "Exiting new device list with i = "
1020 "%lu\n\n",
1021 i);
1022 break;
1023 }
1024 dbgStr = ixmlNode_getNodeName(tmpNode);
1025 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1026 "Extracting device type once for %s\n", dbgStr);
1027 ixmlNodeList_free(nodeList);
1029 "deviceType");
1030 if (!nodeList)
1031 continue;
1032 UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
1033 "Extracting UDN for %s\n", dbgStr);
1034 UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
1035 "Extracting device type\n");
1036 tmpNode2 = ixmlNodeList_item(nodeList, 0lu);
1037 if (!tmpNode2)
1038 continue;
1039 textNode = ixmlNode_getFirstChild(tmpNode2);
1040 if (!textNode)
1041 continue;
1042 UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
1043 "Extracting device type \n");
1044 tmpStr = ixmlNode_getNodeValue(textNode);
1045 if (!tmpStr)
1046 continue;
1047 strncpy(devType, tmpStr, sizeof(devType) - 1);
1048 UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
1049 "Extracting device type = %s\n", devType);
1050 if (!tmpNode) {
1051 UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
1052 "TempNode is NULL\n");
1053 }
1054 dbgStr = ixmlNode_getNodeName(tmpNode);
1055 UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
1056 "Extracting UDN for %s\n", dbgStr);
1057 ixmlNodeList_free(nodeList);
1058 nodeList =
1060 if (!nodeList) {
1061 UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__,
1062 "UDN not found!\n");
1063 continue;
1064 }
1065 tmpNode2 = ixmlNodeList_item(nodeList, 0lu);
1066 if (!tmpNode2) {
1067 UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__,
1068 "UDN not found!\n");
1069 continue;
1070 }
1071 textNode = ixmlNode_getFirstChild(tmpNode2);
1072 if (!textNode) {
1073 UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__,
1074 "UDN not found!\n");
1075 continue;
1076 }
1077 tmpStr = ixmlNode_getNodeValue(textNode);
1078 if (!tmpStr) {
1079 UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__,
1080 "UDN not found!\n");
1081 continue;
1082 }
1083 strncpy(UDNstr, tmpStr, sizeof(UDNstr) - 1);
1084 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1085 "Sending UDNStr = %s \n", UDNstr);
1086 if (AdFlag) {
1087 /* send the device advertisement */
1088 if (AdFlag == 1) {
1089 DeviceAdvertisement(devType, i == 0lu, UDNstr,
1090 SInfo->DescURL, Exp, SInfo->DeviceAf,
1091 SInfo->PowerState, SInfo->SleepPeriod,
1092 SInfo->RegistrationState);
1093 } else {
1094 /* AdFlag == -1 */
1095 DeviceShutdown(devType, i == 0lu, UDNstr, SInfo->DescURL,
1096 Exp, SInfo->DeviceAf, SInfo->PowerState,
1097 SInfo->SleepPeriod,
1098 SInfo->RegistrationState);
1099 }
1100 } else {
1101 switch (SearchType) {
1102 case SSDP_ALL:
1103 DeviceReply(DestAddr, devType, i == 0lu, UDNstr,
1104 SInfo->DescURL, defaultExp, SInfo->PowerState,
1105 SInfo->SleepPeriod, SInfo->RegistrationState);
1106 break;
1107 case SSDP_ROOTDEVICE:
1108 if (i == 0lu) {
1109 SendReply(DestAddr, devType, 1, UDNstr, SInfo->DescURL,
1110 defaultExp, 0, SInfo->PowerState,
1111 SInfo->SleepPeriod, SInfo->RegistrationState);
1112 }
1113 break;
1114 case SSDP_DEVICEUDN: {
1115 /* clang-format off */
1116 if (DeviceUDN && strlen(DeviceUDN) != (size_t)0) {
1117 if (strcasecmp(DeviceUDN, UDNstr)) {
1118 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1119 "DeviceUDN=%s and search UDN=%s DID NOT match\n",
1120 UDNstr, DeviceUDN);
1121 } else {
1122 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1123 "DeviceUDN=%s and search UDN=%s MATCH\n",
1124 UDNstr, DeviceUDN);
1125 SendReply(DestAddr, devType, 0, UDNstr, SInfo->DescURL, defaultExp, 0,
1126 SInfo->PowerState,
1127 SInfo->SleepPeriod,
1128 SInfo->RegistrationState);
1129 }
1130 }
1131 /* clang-format on */
1132 break;
1133 }
1134 case SSDP_DEVICETYPE: {
1135 /* clang-format off */
1136 if (!strncasecmp(DeviceType, devType, strlen(DeviceType) - (size_t)2)) {
1137 if (atoi(strrchr(DeviceType, ':') + 1)
1138 < atoi(&devType[strlen(devType) - (size_t)1])) {
1139 /* the requested version is lower than the device version
1140 * must reply with the lower version number and the lower
1141 * description URL */
1142 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1143 "DeviceType=%s and search devType=%s MATCH\n",
1144 devType, DeviceType);
1145 SendReply(DestAddr, DeviceType, 0, UDNstr, SInfo->LowerDescURL,
1146 defaultExp, 1,
1147 SInfo->PowerState,
1148 SInfo->SleepPeriod,
1149 SInfo->RegistrationState);
1150 } else if (atoi(strrchr(DeviceType, ':') + 1)
1151 == atoi(&devType[strlen(devType) - (size_t)1])) {
1152 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1153 "DeviceType=%s and search devType=%s MATCH\n",
1154 devType, DeviceType);
1155 SendReply(DestAddr, DeviceType, 0, UDNstr, SInfo->DescURL,
1156 defaultExp, 1,
1157 SInfo->PowerState,
1158 SInfo->SleepPeriod,
1159 SInfo->RegistrationState);
1160 } else {
1161 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1162 "DeviceType=%s and search devType=%s DID NOT MATCH\n",
1163 devType, DeviceType);
1164 }
1165 } else {
1166 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1167 "DeviceType=%s and search devType=%s DID NOT MATCH\n",
1168 devType, DeviceType);
1169 }
1170 /* clang-format on */
1171 break;
1172 }
1173 default:
1174 break;
1175 }
1176 }
1177 /* send service advertisements for services
1178 * corresponding to the same device */
1179 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1180 "Sending service Advertisement\n");
1181 /* Correct service traversal such that each device's
1182 * serviceList is directly traversed as a child of its
1183 * parent device. This ensures that the service's alive
1184 * message uses the UDN of the parent device. */
1185 tmpNode = ixmlNode_getFirstChild(tmpNode);
1186 while (tmpNode) {
1187 dbgStr = ixmlNode_getNodeName(tmpNode);
1188 if (!strncmp(dbgStr, SERVICELIST_STR, sizeof SERVICELIST_STR)) {
1189 break;
1190 }
1191 tmpNode = ixmlNode_getNextSibling(tmpNode);
1192 }
1193 ixmlNodeList_free(nodeList);
1194 if (!tmpNode) {
1195 nodeList = NULL;
1196 continue;
1197 }
1199 "service");
1200 if (!nodeList) {
1201 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1202 "Service not found 3\n");
1203 continue;
1204 }
1205 for (j = 0lu;; j++) {
1206 tmpNode = ixmlNodeList_item(nodeList, j);
1207 if (!tmpNode) {
1208 break;
1209 }
1210 ixmlNodeList_free(tmpNodeList);
1212 (IXML_Element*)tmpNode, "serviceType");
1213 if (!tmpNodeList) {
1214 UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__,
1215 "ServiceType not found \n");
1216 continue;
1217 }
1218 tmpNode2 = ixmlNodeList_item(tmpNodeList, 0lu);
1219 if (!tmpNode2)
1220 continue;
1221 textNode = ixmlNode_getFirstChild(tmpNode2);
1222 if (!textNode)
1223 continue;
1224 /* servType is of format
1225 * Servicetype:ServiceVersion */
1226 tmpStr = ixmlNode_getNodeValue(textNode);
1227 if (!tmpStr)
1228 continue;
1229 strncpy(servType, tmpStr, sizeof(servType) - 1);
1230 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1231 "ServiceType = %s\n", servType);
1232 if (AdFlag) {
1233 if (AdFlag == 1) {
1235 UDNstr, servType, SInfo->DescURL, Exp,
1236 SInfo->DeviceAf, SInfo->PowerState,
1237 SInfo->SleepPeriod, SInfo->RegistrationState);
1238 } else {
1239 /* AdFlag == -1 */
1240 ServiceShutdown(UDNstr, servType, SInfo->DescURL, Exp,
1241 SInfo->DeviceAf, SInfo->PowerState,
1242 SInfo->SleepPeriod,
1243 SInfo->RegistrationState);
1244 }
1245 } else {
1246 switch (SearchType) {
1247 case SSDP_ALL:
1248 ServiceReply(DestAddr, servType, UDNstr, SInfo->DescURL,
1249 defaultExp, SInfo->PowerState,
1250 SInfo->SleepPeriod,
1251 SInfo->RegistrationState);
1252 break;
1253 case SSDP_SERVICE:
1254 /* clang-format off */
1255 if (ServiceType) {
1256 if (!strncasecmp(ServiceType, servType, strlen(ServiceType) - (size_t)2)) {
1257 if (atoi(strrchr(ServiceType, ':') + 1) <
1258 atoi(&servType[strlen(servType) - (size_t)1])) {
1259 /* the requested version is lower than the service version
1260 * must reply with the lower version number and the lower
1261 * description URL */
1262 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1263 "ServiceType=%s and search servType=%s MATCH\n",
1264 ServiceType, servType);
1265 SendReply(DestAddr, ServiceType, 0, UDNstr, SInfo->LowerDescURL,
1266 defaultExp, 1,
1267 SInfo->PowerState,
1268 SInfo->SleepPeriod,
1269 SInfo->RegistrationState);
1270 } else if (atoi(strrchr (ServiceType, ':') + 1) ==
1271 atoi(&servType[strlen(servType) - (size_t)1])) {
1272 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1273 "ServiceType=%s and search servType=%s MATCH\n",
1274 ServiceType, servType);
1275 SendReply(DestAddr, ServiceType, 0, UDNstr, SInfo->DescURL,
1276 defaultExp, 1,
1277 SInfo->PowerState,
1278 SInfo->SleepPeriod,
1279 SInfo->RegistrationState);
1280 } else {
1281 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1282 "ServiceType=%s and search servType=%s DID NOT MATCH\n",
1283 ServiceType, servType);
1284 }
1285 } else {
1286 UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
1287 "ServiceType=%s and search servType=%s DID NOT MATCH\n",
1288 ServiceType, servType);
1289 }
1290 }
1291 /* clang-format on */
1292 break;
1293 default:
1294 break;
1295 }
1296 }
1297 }
1298 ixmlNodeList_free(tmpNodeList);
1299 tmpNodeList = NULL;
1300 ixmlNodeList_free(nodeList);
1301 nodeList = NULL;
1302 }
1303 }
1304
1305end_function:
1306 ixmlNodeList_free(tmpNodeList);
1307 ixmlNodeList_free(nodeList);
1308 UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__,
1309 "Exiting AdvertiseAndReply.\n");
1310 HandleUnlock();
1311
1312 return retVal;
1313}
1314
1315void advertiseAndReplyThread(void* data) {
1316 SsdpSearchReply* arg = (SsdpSearchReply*)data;
1317
1319 (struct sockaddr*)&arg->dest_addr, arg->event.DeviceType,
1320 arg->event.UDN, arg->event.ServiceType, arg->MaxAge);
1321 free(arg);
1322}
int UpnpDevice_Handle
Returned when a device application registers with UpnpRegisterRootDevice(),UpnpRegisterRootDevice2(),...
Definition API.hpp:425
#define LINE_SIZE
Definition API.hpp:45
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.
#define HDR_MX
Type of a HTTP header.
#define HDR_ST
Type of a HTTP header.
#define HDR_MAN
Type of a HTTP header.
Structure of an HTTP message.
#define X_USER_AGENT
Can be overwritten by configure CFLAGS argument.
Definition webserver.hpp:87
int TPJobSetFreeFunction(ThreadPoolJob *job, free_routine func)
Sets the jobs free function.
int TPJobInit(ThreadPoolJob *job, UPnPsdk::start_routine func, void *arg)
Initializes thread pool job.
Duration
Duration.
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.
#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
int ssdp_request_type(char *cmd, SsdpEvent *Evt)
Starts filling the SSDP event structure based upon the request received.
int AdvertiseAndReply(int AdFlag, UpnpDevice_Handle Hnd, enum SsdpSearchType SearchType, struct sockaddr *DestAddr, char *DeviceType, char *DeviceUDN, char *ServiceType, int Exp)
Sends SSDP advertisements, replies and shutdown messages.
Data structure common to all types of nodes.
Definition ixml.hpp:132
Data structure representing a list of nodes.
Definition ixml.hpp:193
Data structure representing an Element node.
Definition ixml.hpp:169
#define DOMString
The type of DOM strings.
Definition ixml.hpp:47
PUPNP_Api IXML_Node * ixmlNode_getNextSibling(IXML_Node *nodeptr)
Retrieves the sibling Node immediately following this Node.
Definition node.cpp:375
PUPNP_Api const DOMString ixmlNode_getNodeValue(IXML_Node *nodeptr)
Returns the value of the Node as a string.
Definition node.cpp:296
PUPNP_Api const DOMString ixmlNode_getNodeName(IXML_Node *nodeptr)
Returns the name of the Node, depending on what type of Node it is, in a read-only string.
Definition node.cpp:179
PUPNP_Api void ixmlNodeList_free(IXML_NodeList *nList)
Frees a NodeList object.
Definition nodeList.cpp:129
PUPNP_Api IXML_Node * ixmlNode_getFirstChild(IXML_Node *nodeptr)
Retrieves the first child Node of a Node.
Definition node.cpp:342
PUPNP_Api IXML_Node * ixmlNodeList_item(IXML_NodeList *nList, unsigned long index)
Retrieves a Node from a NodeList specified by a numerical index.
Definition nodeList.cpp:49
PUPNP_Api IXML_NodeList * ixmlElement_getElementsByTagName(IXML_Element *element, const DOMString tagName)
Returns a NodeList of all descendant Elements with a given tag name, in the order in which they are e...
Definition element.cpp:335
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'.
int raw_to_int(memptr *raw_value, int base)
Converts raw character data to integer value.
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().
char * membuffer_detach(membuffer *m)
Detaches current buffer and returns it. The caller must free the returned buffer using free()....
size_t size_inc
used to increase size; MUST be > 0; (read/write).
Definition membuffer.hpp:69
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_NETWORK_ERROR
A network error occurred.
Definition messages.hpp:169
#define UPNP_E_INVALID_HANDLE
The handle passed to a function is not a recognized as a valid handle.
Definition messages.hpp:32
#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_OUTOF_MEMORY
Not enough resources are currently available to complete the operation.
Definition messages.hpp:57
#define UPNP_E_SOCKET_WRITE
An error happened while writing to a socket.
Definition messages.hpp:179
#define UPNP_E_INVALID_PARAM
One or more of the parameters passed to the function is not valid.
Definition messages.hpp:40
int NewRequestHandler(struct sockaddr *DestAddr, int NumPacket, char **RqPacket)
Works as a request handler which passes the HTTP request string to multicast channel.
int extractIPv6address(char *url, char *address)
Extract IPv6 address.
constexpr int MSGTYPE_REPLY
Message type.
constexpr int MSGTYPE_SHUTDOWN
Message type.
void CreateServicePacket(int msg_type, const char *nt, char *usn, char *location, int duration, char **packet, int AddressFamily, int PowerState, int SleepPeriod, int RegistrationState)
Creates a HTTP request packet.
constexpr int MSGTYPE_ADVERTISEMENT
Message type.
int isUrlV6UlaGua(char *descdocUrl)
Test if a Url contains an ULA or GUA IPv6 address.
#define SSDP_PORT
constant
struct sockaddr_storage dest_addr
part of search reply
char UDN[LINE_SIZE]
Part of SSDP Event.
int Mx
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
UpnpDevice_Handle handle
part of search reply
char ServiceType[LINE_SIZE]
Part of SSDP Event.
#define SSDP_IPV6_LINKLOCAL
constant
char DeviceType[LINE_SIZE]
Part of SSDP Event.
int MaxAge
part of search reply
enum SsdpSearchType RequestType
Part of SSDP Event.
SsdpEvent event
part of search reply
SsdpSearchType
Enumeration to define all different types of ssdp searches.
@ 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 reply.
int DeviceReply(struct sockaddr *DestAddr, char *DevType, int RootDev, char *Udn, char *Location, int Duration, int PowerState, int SleepPeriod, int RegistrationState)
Creates the reply packet and send it to the Control Point address.
int DeviceAdvertisement(char *DevType, int RootDev, char *Udn, char *Location, int Duration, int AddressFamily, int PowerState, int SleepPeriod, int RegistrationState)
Creates the device advertisement request.
int DeviceShutdown(char *DevType, int RootDev, char *Udn, char *Location, int Duration, int AddressFamily, int PowerState, int SleepPeriod, int RegistrationState)
Creates a HTTP device shutdown request packet and send it to the multicast channel through RequestHan...
void ssdp_handle_device_request(http_message_t *hmsg, struct sockaddr_storage *dest_addr)
Handles the search request.
void advertiseAndReplyThread(void *data)
Wrapper function to reply the search request coming from the control point.
int ServiceAdvertisement(char *Udn, char *ServType, char *Location, int Duration, int AddressFamily, int PowerState, int SleepPeriod, int RegistrationState)
Creates the advertisement packet and send it to the multicast channel.
int ServiceShutdown(char *Udn, char *ServType, char *Location, int Duration, int AddressFamily, int PowerState, int SleepPeriod, int RegistrationState)
Creates a HTTP service shutdown request packet and sends it to the multicast channel through RequestH...
int SendReply(struct sockaddr *DestAddr, char *DevType, int RootDev, char *Udn, char *Location, int Duration, int ByType, int PowerState, int SleepPeriod, int RegistrationState)
Creates the reply packet and send it to the Control Point addesss.
int ServiceReply(struct sockaddr *DestAddr, char *ServType, char *Udn, char *Location, int Duration, int PowerState, int SleepPeriod, int RegistrationState)
Creates the advertisement packet and send it to the multicast channel.
Manage "Step 1: Discovery" of the UPnP+™ specification for UPnP Devices with SSDP.
HTTP status codes.
Upnp_Handle_Type GetHandleInfo(UpnpClient_Handle Hnd, Handle_Info **HndInfo)
Get handle information.
Definition upnpapi.cpp:3342
Upnp_SID gUpnpSdkNLSuuid
Global variable used in discovery notifications.
Definition upnpapi.cpp:373
Upnp_Handle_Type GetDeviceHandleInfo(UpnpDevice_Handle start, int AddressFamily, UpnpDevice_Handle *device_handle_out, struct Handle_Info **HndInfo)
Retrieves the device handle and information of the first device of the address family specified....
Definition upnpapi.cpp:3268
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
Inititalize the compatible library before it can be used.
#define HandleLock()
HandleLock.
Definition upnpapi.hpp:138
#define DEFAULT_MAXAGE
DEFAULT_MAXAGE.
Definition upnpapi.hpp:56
int SleepPeriod
Sleep Period as defined by UPnP Low Power.
Definition upnpapi.hpp:100
char LowerDescURL[LINE_SIZE]
URL for the use of SSDP when answering to legacy CPs (CP searching for a v1 when the device is v2).
Definition upnpapi.hpp:94
int RegistrationState
Registration State as defined by UPnP Low Power.
Definition upnpapi.hpp:101
char DescURL[LINE_SIZE]
URL for the use of SSDP.
Definition upnpapi.hpp:93
#define HandleUnlock()
HandleUnlock.
Definition upnpapi.hpp:147
int PowerState
Power State as defined by UPnP Low Power.
Definition upnpapi.hpp:99
IXML_NodeList * DeviceList
List of devices in the description document.
Definition upnpapi.hpp:104
int MaxAge
Advertisement timeout.
Definition upnpapi.hpp:98
int DeviceAf
Address family: AF_INET6 or AF_INET.
Definition upnpapi.hpp:111
#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.