UPnPsdk 0.1
Universal Plug and Play +, Software Development Kit
 
Loading...
Searching...
No Matches
miniserver.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-15
8 * Cloned from pupnp ver 1.14.15.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither name of Intel Corporation nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR
26 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
30 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 **************************************************************************/
35// Last compare with ./pupnp source file on 2023-08-25, ver 1.14.18
48#include <miniserver.hpp> // Needed for one of the compile options
49
50#include <httpreadwrite.hpp>
51#include <ssdp_common.hpp>
52#include <statcodes.hpp>
53#include <upnpapi.hpp>
54
55#include <umock/sys_socket.hpp>
56#include <umock/stdlib.hpp>
57#include <umock/pupnp_miniserver.hpp>
58#include <umock/pupnp_ssdp.hpp>
59
61#include <thread>
63
64namespace {
65
72 SOCKET connfd;
74 sockaddr_storage foreign_sockaddr;
75};
76
83
90
93#ifdef COMPA_HAVE_WEBSERVER
98
108 char* a_host_port,
109 size_t a_host_port_len
110) {
111 TRACE("Executing host_header_is_numeric()");
112 if (a_host_port_len == 0 || strncmp(a_host_port, "[::]", 4) == 0 ||
113 strncmp(a_host_port, "0.0.0.0", 7) == 0)
114 return 0;
115
116 UPnPsdk::SSockaddr saddrObj;
117 try {
118 saddrObj = std::string(a_host_port, a_host_port_len);
119 } catch (const std::exception& e) {
120 UPnPsdk_LOGCATCH("MSG1049") << e.what() << "\n";
121 return 0;
122 }
123 return 1;
124}
125
135 SOCKET a_socket,
136 char* a_host_port,
137 size_t a_hp_size
138) {
139 TRACE("Executing getNumericHostRedirection()")
140 UPnPsdk::CSocket_basic socketObj(a_socket);
141 try {
142 socketObj.load(); // UPnPsdk::CSocket_basic
144 socketObj.local_saddr(&sa);
145 memcpy(a_host_port, sa.netaddrp().c_str(), a_hp_size);
146 return true;
147
148 } catch (const std::exception& ex) {
149 UPnPsdk_LOGCATCH("MSG1093") "catched next line...\n" << ex.what();
150 }
151 return false;
152}
153
163 SOCKINFO* a_info,
165 http_parser_t* a_hparser) {
166 memptr header;
167 size_t min_size;
168 http_message_t* request;
169 MiniServerCallback callback;
170 WebCallback_HostValidate host_validate_callback = 0;
171 void* cookie{};
172 int rc = UPNP_E_SUCCESS;
173 /* If it does not fit in here, it is likely invalid anyway. */
174 char host_port[NAME_SIZE];
175
176 switch (a_hparser->msg.method) {
177 /* Soap Call */
178 case SOAPMETHOD_POST:
179 case HTTPMETHOD_MPOST:
180 callback = gSoapCallback;
181 UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
182 "miniserver %d: got SOAP msg\n", a_info->socket);
183 break;
184 /* Gena Call */
185 case HTTPMETHOD_NOTIFY:
186 case HTTPMETHOD_SUBSCRIBE:
187 case HTTPMETHOD_UNSUBSCRIBE:
188 callback = gGenaCallback;
189 UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
190 "miniserver %d: got GENA msg\n", a_info->socket);
191 break;
192 /* HTTP server call */
193 case HTTPMETHOD_GET:
194 case HTTPMETHOD_POST:
195 case HTTPMETHOD_HEAD:
196 case HTTPMETHOD_SIMPLEGET:
197 callback = gGetCallback;
198 host_validate_callback = gWebCallback_HostValidate;
200 UPnPsdk_LOGINFO("MSG1107") "miniserver socket="
201 << a_info->socket << ": got WEB server msg.\n";
202 break;
203 default:
204 callback = nullptr;
205 }
206 if (!callback) {
207 rc = HTTP_INTERNAL_SERVER_ERROR;
208 goto ExitFunction;
209 }
210 request = &a_hparser->msg;
211 if (UPnPsdk::g_dbug) {
212 getNumericHostRedirection(a_info->socket, host_port, sizeof host_port);
213 UPnPsdk_LOGINFO("MSG1113") "Redirect host_port=\"" << host_port
214 << "\"\n";
215 }
216 /* check HOST header for an IP number -- prevents DNS rebinding. */
217 if (!httpmsg_find_hdr(request, HDR_HOST, &header)) {
219 goto ExitFunction;
220 }
221 min_size = header.length < ((sizeof host_port) - 1)
222 ? header.length
223 : (sizeof host_port) - 1;
224 memcpy(host_port, header.buf, min_size);
225 host_port[min_size] = 0;
226 if (host_validate_callback) {
227 rc = host_validate_callback(host_port, cookie);
228 if (rc == UPNP_E_BAD_HTTPMSG) {
229 goto ExitFunction;
230 }
231 } else if (!host_header_is_numeric(host_port, min_size)) {
234 UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
235 "Possible DNS Rebind attack prevented.\n");
236 goto ExitFunction;
237 } else {
238 membuffer redir_buf;
239 static const char* redir_fmt = "HTTP/1.1 307 Temporary Redirect\r\n"
240 "Location: http://%s\r\n\r\n";
241 char redir_str[NAME_SIZE];
242 int timeout = HTTP_DEFAULT_TIMEOUT;
243
244 getNumericHostRedirection(a_info->socket, host_port,
245 sizeof host_port);
246 membuffer_init(&redir_buf);
247 snprintf(redir_str, NAME_SIZE, redir_fmt, host_port);
248 membuffer_append_str(&redir_buf, redir_str);
249 rc = http_SendMessage(a_info, &timeout, "b", redir_buf.buf,
250 redir_buf.length);
251 membuffer_destroy(&redir_buf);
252 goto ExitFunction;
253 }
254 }
255 callback(a_hparser, request, a_info);
256
257ExitFunction:
258 return rc;
259}
260
267 void* args) {
268 TRACE("Executing free_handle_request_arg()")
269 if (args == nullptr)
270 return;
271
272 sock_close(static_cast<mserv_request_t*>(args)->connfd);
273 free(args);
274}
275
282 void* args) {
283 TRACE("Executing handle_request()")
284 int http_major_version{1};
285 int http_minor_version{1};
286 int ret_code;
287 mserv_request_t* request_in = (mserv_request_t*)args;
288 SOCKET connfd = request_in->connfd;
289
290 if (UPnPsdk::g_dbug) {
291 UPnPsdk::CSocket_basic sockObj(connfd);
292 sockObj.load();
293 UPnPsdk::SSockaddr local_saObj;
294 sockObj.local_saddr(&local_saObj);
295 UPnPsdk::SSockaddr remote_saObj;
296 remote_saObj = request_in->foreign_sockaddr;
297 UPnPsdk_LOGINFO("MSG1027") "UDevice socket="
298 << connfd << ": READING request on local=\""
299 << local_saObj.netaddrp() << "\" from control point remote=\""
300 << remote_saObj.netaddrp() << "\".\n";
301 }
302
303 /* parser_request_init( &parser ); */ /* LEAK_FIX_MK */
304 http_parser_t parser;
305 http_message_t* hmsg = &parser.msg;
306 SOCKINFO info;
307 ret_code = sock_init_with_ip(
308 &info, connfd,
309 reinterpret_cast<sockaddr*>(&request_in->foreign_sockaddr));
310 if (ret_code != UPNP_E_SUCCESS) {
311 free(request_in);
312 httpmsg_destroy(hmsg);
313 return;
314 }
315
316 /* read */
317 int timeout{HTTP_DEFAULT_TIMEOUT};
318 int http_error_code; // Either negative UPNP_E_XXX error code,
319 // or positve HTTP error code (4XX or 5XX).
320 // Will be initialized by next function.
321 ret_code = http_RecvMessage(&info, &parser, HTTPMETHOD_UNKNOWN, &timeout,
322 &http_error_code);
323 if (ret_code == 0) {
324 UPnPsdk_LOGINFO("MSG1106") "miniserver socket=" << connfd
325 << ": PROCESSING...\n";
326 /* dispatch */
327 http_error_code = dispatch_request(&info, &parser);
328 }
329
330 if (http_error_code > 0) { // only positive HTTP error codes (4XX or 5XX).
331 if (hmsg) {
332 http_major_version = hmsg->major_version;
333 http_minor_version = hmsg->minor_version;
334 }
335 http_SendStatusResponse(&info, http_error_code, http_major_version,
336 http_minor_version);
337 }
338 sock_destroy(&info, SD_BOTH);
339 httpmsg_destroy(hmsg);
340 free(request_in);
341
342 UPnPsdk_LOGINFO("MSG1058") "miniserver socket(" << connfd
343 << "); COMPLETE.\n";
344}
345
352 SOCKET a_connfd,
354 UPnPsdk::SSockaddr& clientAddr) {
355 TRACE("Executing schedule_request_job()")
356 if (UPnPsdk::g_dbug) {
357 UPnPsdk::CSocket_basic sockObj(a_connfd);
358 sockObj.load();
359 UPnPsdk::SSockaddr local_saObj;
360 sockObj.local_saddr(&local_saObj);
361 UPnPsdk::SSockaddr remote_saObj;
362 remote_saObj = clientAddr.ss;
363 UPnPsdk_LOGINFO(
364 "MSG1042") "Schedule UDevice to read incomming request with socket("
365 << a_connfd << ") local=\"" << local_saObj.netaddrp()
366 << "\" remote=\"" << remote_saObj.netaddrp() << "\".\n";
367 }
368
369 ThreadPoolJob job{};
370 mserv_request_t* request{
371 static_cast<mserv_request_t*>(std::malloc(sizeof(mserv_request_t)))};
372 if (request == nullptr) {
373 UPnPsdk_LOGCRIT("MSG1024") "Socket(" << a_connfd
374 << "): out of memory.\n";
375 sock_close(a_connfd);
376 return;
377 }
378 request->connfd = a_connfd;
379 memcpy(&request->foreign_sockaddr, &clientAddr.ss,
380 sizeof(request->foreign_sockaddr));
381 TPJobInit(&job, (UPnPsdk::start_routine)handle_request, request);
383 TPJobSetPriority(&job, MED_PRIORITY);
384 if (ThreadPoolAdd(&gMiniServerThreadPool, &job, NULL) != 0) {
385 UPnPsdk_LOGERR("MSG1025") "Socket("
386 << a_connfd << "): failed to add job to miniserver threadpool.\n";
387 free(request);
388 sock_close(a_connfd);
389 }
390}
391#endif // COMPA_HAVE_WEBSERVER
392
411 SOCKET a_sock,
412 fd_set* a_set
415) {
416 TRACE("Executing fdset_if_valid(): check sockfd=" + std::to_string(a_sock))
417 if (a_sock == INVALID_SOCKET)
418 // This is a defined state and we return silently.
419 return;
420
421 if (a_sock < 3 || a_sock >= FD_SETSIZE) {
422 UPnPsdk_LOGERR("MSG1005")
423 << (a_sock < 0 ? "Invalid" : "Prohibited") << " socket " << a_sock
424 << " not set to be monitored by ::select()"
425 << (a_sock >= 3 ? " because it violates FD_SETSIZE.\n" : ".\n");
426 return;
427 }
428 // Check if socket is valid and bound
429 UPnPsdk::CSocket_basic sockObj(a_sock);
430 try {
431 sockObj.load(); // UPnPsdk::CSocket_basic
432 if (sockObj.local_saddr())
433
434 FD_SET(a_sock, a_set);
435
436 else
437 UPnPsdk_LOGINFO("MSG1002") "Unbound socket "
438 << a_sock << " not set to be monitored by ::select().\n";
439
440 } catch (const std::exception& e) {
441 if (UPnPsdk::g_dbug)
442 std::cerr << e.what();
443 UPnPsdk_LOGCATCH("MSG1009") "Invalid socket "
444 << a_sock << " not set to be monitored by ::select().\n";
445 }
446}
447
461 [[maybe_unused]] SOCKET listen_sock,
463 [[maybe_unused]] fd_set& set) {
464#ifndef COMPA_HAVE_WEBSERVER
466#else
467 TRACE("Executing web_server_accept()")
468 if (listen_sock == INVALID_SOCKET || !FD_ISSET(listen_sock, &set)) {
469 UPnPsdk_LOGINFO("MSG1012") "Socket("
470 << listen_sock << ") invalid or not in file descriptor set.\n";
471 return UPNP_E_SOCKET_ERROR;
472 }
473
474 UPnPsdk::SSockaddr ctrlpnt_saObj;
475 socklen_t ctrlpntLen = sizeof(ctrlpnt_saObj.ss);
476
477 // accept a network request connection
478 SOCKET conn_sock =
479 umock::sys_socket_h.accept(listen_sock, &ctrlpnt_saObj.sa, &ctrlpntLen);
480 if (conn_sock == INVALID_SOCKET) {
481 UPnPsdk_LOGERR("MSG1022") "Error in ::accept(): "
482 << std::strerror(errno) << ".\n";
484 }
485
486 if (UPnPsdk::g_dbug) {
487 // Some helpful status information.
488 UPnPsdk::CSocket_basic listen_sockObj(listen_sock);
489 listen_sockObj.load();
490 UPnPsdk::SSockaddr listen_saObj;
491 listen_sockObj.local_saddr(&listen_saObj);
492
493 UPnPsdk::CSocket_basic conn_sockObj(conn_sock);
494 conn_sockObj.load();
495 UPnPsdk::SSockaddr conn_saObj;
496 conn_sockObj.local_saddr(&conn_saObj);
497
498 UPnPsdk_LOGINFO("MSG1023") "Listening socket("
499 << listen_sock << ") on \"" << listen_saObj.netaddrp()
500 << "\" accept connection socket(" << conn_sock << ") local=\""
501 << conn_saObj.netaddrp() << "\" to remote=\""
502 << ctrlpnt_saObj.netaddrp() << "\".\n";
503 }
504
505 // Schedule a job to manage the UPnP request from the remote control point.
506 schedule_request_job(conn_sock, ctrlpnt_saObj);
507
508 return UPNP_E_SUCCESS;
509#endif /* COMPA_HAVE_WEBSERVER */
510}
511
515void ssdp_read( //
516 SOCKET* rsock,
517 fd_set* set ) {
519 TRACE("Executing ssdp_read()")
520 if (*rsock == INVALID_SOCKET || !FD_ISSET(*rsock, set))
521 return;
522
523#if defined(COMPA_HAVE_CTRLPT_SSDP) || defined(COMPA_HAVE_DEVICE_SSDP)
524 if (readFromSSDPSocket(*rsock) != 0) {
525 UpnpPrintf(UPNP_ERROR, MSERV, __FILE__, __LINE__,
526 "miniserver: Error in readFromSSDPSocket(%d): "
527 "closing socket\n",
528 *rsock);
529 sock_close(*rsock);
530 *rsock = INVALID_SOCKET;
531 }
532#else
533 sock_close(*rsock);
534 *rsock = INVALID_SOCKET;
535#endif
536}
537
552 SOCKET ssock,
553 fd_set* set
555) {
556 TRACE("Executing receive_from_stopSock()")
557 constexpr char shutdown_str[]{"ShutDown"};
558
559 if (!FD_ISSET(ssock, set))
560 return 0; // Nothing to do for this socket
561
562 UPnPsdk::sockaddr_t clientAddr{};
563 socklen_t clientLen{sizeof(clientAddr)}; // May be modified
564
565 // The receive buffer is one byte greater with '\0' than the max receiving
566 // bytes so the received message will always be terminated.
567 char receiveBuf[sizeof(shutdown_str) + 1]{};
568 char buf_ntop[INET6_ADDRSTRLEN];
569
570 // receive from
571 SSIZEP_T byteReceived = umock::sys_socket_h.recvfrom(
572 ssock, receiveBuf, sizeof(shutdown_str), 0, &clientAddr.sa, &clientLen);
573 if (byteReceived == SOCKET_ERROR ||
574 inet_ntop(AF_INET, &clientAddr.sin.sin_addr, buf_ntop,
575 sizeof(buf_ntop)) == nullptr) {
576 UPnPsdk_LOGCRIT("MSG1038") "Failed to receive data from socket "
577 << ssock << ". Stop miniserver.\n";
578 return 1;
579 }
580
581 // integer of "127.0.0.1" is 2130706433.
582 if (clientAddr.sin.sin_addr.s_addr != htonl(2130706433) ||
583 strcmp(receiveBuf, shutdown_str) != 0) //
584 {
585 char nullstr[]{"\\0"};
586 if (byteReceived == 0 || receiveBuf[byteReceived - 1] != '\0')
587 nullstr[0] = '\0';
588 UPnPsdk_LOGERR("MSG1039") "Received \""
589 << receiveBuf << nullstr << "\" from " << buf_ntop << ":"
590 << ntohs(clientAddr.sin.sin_port)
591 << ", must be \"ShutDown\\0\" from 127.0.0.1:*. Don't "
592 "stopping miniserver.\n";
593 return 0;
594 }
595
596 UPnPsdk_LOGINFO("MSG1040") "On socket "
597 << ssock << " received ordinary datagram \"" << receiveBuf
598 << "\\0\" from " << buf_ntop << ":" << ntohs(clientAddr.sin.sin_port)
599 << ". Stop miniserver.\n";
600 return 1;
601}
602
618 MiniServerSockArray* miniSock) {
619 UPnPsdk_LOGINFO("MSG1085") "Executing...\n";
620
621#ifdef COMPA_HAVE_WEBSERVER
622 // Move the current valid socket objects to this scope. They are owner of
623 // the raw socket file descriptor and manage/close it when leaving this
624 // scope.
625 UPnPsdk::CSocket sockLlaObj;
626 if (miniSock->pSockLlaObj != nullptr) {
627 sockLlaObj = std::move(*miniSock->pSockLlaObj);
628 miniSock->pSockLlaObj = &sockLlaObj;
629 }
630 UPnPsdk::CSocket sockGuaObj;
631 if (miniSock->pSockGuaObj != nullptr) {
632 sockGuaObj = std::move(*miniSock->pSockGuaObj);
633 miniSock->pSockGuaObj = &sockGuaObj;
634 }
635 UPnPsdk::CSocket sockIp4Obj;
636 if (miniSock->pSockIp4Obj != nullptr) {
637 sockIp4Obj = std::move(*miniSock->pSockIp4Obj);
638 miniSock->pSockIp4Obj = &sockIp4Obj;
639 }
640#endif
641
642 fd_set expSet;
643 fd_set rdSet;
644 int stopSock = 0;
645
646 // On MS Windows INVALID_SOCKET is unsigned -1 = 18446744073709551615 so we
647 // get maxMiniSock with this big number even if there is only one
648 // INVALID_SOCKET. Incrementing it at the end results in 0. To be portable
649 // we must not assume INVALID_SOCKET to be -1. --Ingo
650 SOCKET maxMiniSock = 0;
651 maxMiniSock = //
652 std::max(maxMiniSock, miniSock->miniServerSock4 == INVALID_SOCKET
653 ? 0
654 : miniSock->miniServerSock4);
655 maxMiniSock = //
656 std::max(maxMiniSock, miniSock->miniServerSock6 == INVALID_SOCKET
657 ? 0
658 : miniSock->miniServerSock6);
659 maxMiniSock = //
660 std::max(maxMiniSock, miniSock->miniServerSock6UlaGua == INVALID_SOCKET
661 ? 0
662 : miniSock->miniServerSock6UlaGua);
663 maxMiniSock = //
664 std::max(maxMiniSock, miniSock->miniServerStopSock == INVALID_SOCKET
665 ? 0
666 : miniSock->miniServerStopSock);
667 maxMiniSock = //
668 std::max(maxMiniSock, miniSock->ssdpSock4 == INVALID_SOCKET
669 ? 0
670 : miniSock->ssdpSock4);
671 maxMiniSock = //
672 std::max(maxMiniSock, miniSock->ssdpSock6 == INVALID_SOCKET
673 ? 0
674 : miniSock->ssdpSock6);
675 maxMiniSock = //
676 std::max(maxMiniSock, miniSock->ssdpSock6UlaGua == INVALID_SOCKET
677 ? 0
678 : miniSock->ssdpSock6UlaGua);
679#ifdef COMPA_HAVE_CTRLPT_SSDP
680 maxMiniSock = //
681 std::max(maxMiniSock, miniSock->ssdpReqSock4 == INVALID_SOCKET
682 ? 0
683 : miniSock->ssdpReqSock4);
684 maxMiniSock = //
685 std::max(maxMiniSock, miniSock->ssdpReqSock6 == INVALID_SOCKET
686 ? 0
687 : miniSock->ssdpReqSock6);
688#endif
689 ++maxMiniSock;
690
692 while (!stopSock) {
693 FD_ZERO(&rdSet);
694 FD_ZERO(&expSet);
695 /* FD_SET()'s */
696 FD_SET(miniSock->miniServerStopSock, &expSet);
697 FD_SET(miniSock->miniServerStopSock, &rdSet);
698 fdset_if_valid(miniSock->miniServerSock4, &rdSet);
699 fdset_if_valid(miniSock->miniServerSock6, &rdSet);
700 fdset_if_valid(miniSock->miniServerSock6UlaGua, &rdSet);
701 fdset_if_valid(miniSock->ssdpSock4, &rdSet);
702 fdset_if_valid(miniSock->ssdpSock6, &rdSet);
703 fdset_if_valid(miniSock->ssdpSock6UlaGua, &rdSet);
704#ifdef COMPA_HAVE_CTRLPT_SSDP
705 fdset_if_valid(miniSock->ssdpReqSock4, &rdSet);
706 fdset_if_valid(miniSock->ssdpReqSock6, &rdSet);
707#endif
708
709 /* select() */
710 int ret = umock::sys_socket_h.select(static_cast<int>(maxMiniSock),
711 &rdSet, NULL, &expSet, NULL);
712
713 if (ret == SOCKET_ERROR) {
714 if (errno == EINTR) {
715 // A signal was caught, not for us. We ignore it and
716 continue;
717 }
718 if (errno == EBADF) {
719 // A closed socket file descriptor was given in one of the
720 // sets. For details look at
721 // REF:_[Should_I_assert_fail_on_select()_EBADF?](https://stackoverflow.com/q/28015859/5014688)
722 // It is difficult to determine here what file descriptor
723 // in rdSet or expSet is invalid. So I ensure that only valid
724 // socket fds are given by checking them with fdset_if_valid()
725 // before calling select(). Doing this I have to
726 continue;
727 }
728 // All other errors EINVAL and ENOMEM are critical and cannot
729 // continue run mininserver.
730 UPnPsdk_LOGCRIT("MSG1021") "Error in ::select(): "
731 << std::strerror(errno) << ".\n";
732 break;
733 }
734
735 // Accept requested connection from a remote control point and run the
736 // connection in a new thread. Due to side effects with threading we
737 // need to avoid lazy evaluation with chained || because all
738 // web_server_accept() must be called.
739 // if (ret1 == UPNP_E_SUCCESS || ret2 == UPNP_E_SUCCESS ||
740 // ret3 == UPNP_E_SUCCESS) {
741 [[maybe_unused]] int ret1 =
742 web_server_accept(miniSock->miniServerSock4, rdSet);
743 [[maybe_unused]] int ret2 =
744 web_server_accept(miniSock->miniServerSock6, rdSet);
745 [[maybe_unused]] int ret3 =
747#ifdef COMPA_HAVE_CTRLPT_SSDP
748 ssdp_read(&miniSock->ssdpReqSock4, &rdSet);
749 ssdp_read(&miniSock->ssdpReqSock6, &rdSet);
750#endif
751 ssdp_read(&miniSock->ssdpSock4, &rdSet);
752 ssdp_read(&miniSock->ssdpSock6, &rdSet);
753 ssdp_read(&miniSock->ssdpSock6UlaGua, &rdSet);
754 // }
755
756 // Check if we have received a packet from
757 // localhost(127.0.0.1) that will stop the miniserver.
758 stopSock = receive_from_stopSock(miniSock->miniServerStopSock, &rdSet);
759 } // while (!stopsock)
760
761 /* Close all sockets. */
762 sock_close(miniSock->miniServerSock4);
763 sock_close(miniSock->miniServerSock6);
766 sock_close(miniSock->ssdpSock4);
767 sock_close(miniSock->ssdpSock6);
768 sock_close(miniSock->ssdpSock6UlaGua);
769#ifdef COMPA_HAVE_CTRLPT_SSDP
770 sock_close(miniSock->ssdpReqSock4);
771 sock_close(miniSock->ssdpReqSock6);
772#endif
773 /* Free minisock. */
774 umock::stdlib_h.free(miniSock);
776
777 UPnPsdk_LOGINFO("MSG1060") "Finished.\n";
778 return;
779}
780
782 umock::pupnp_miniserver.RunMiniServer(miniSock);
783}
784
785
795 SOCKET sockfd,
797 uint16_t* port) {
798 TRACE("Executing get_port(), calls system ::getsockname()")
799 UPnPsdk::sockaddr_t sockinfo{};
800 socklen_t len(sizeof sockinfo); // May be modified by getsockname()
801
802 if (umock::sys_socket_h.getsockname(sockfd, &sockinfo.sa, &len) == -1)
803 // system error (errno etc.) is expected to be unmodified on return.
804 return -1;
805
806 switch (sockinfo.ss.ss_family) {
807 case AF_INET:
808 case AF_INET6:
809 *port = ntohs(sockinfo.sin6.sin6_port);
810 break;
811 default:
812 // system error (errno etc.) is expected to be unmodified on return.
813 return -1;
814 }
815 UPnPsdk_LOGINFO("MSG1063") "sockfd=" << sockfd << ", port=" << *port
816 << ".\n";
817
818 return 0;
819}
820
821#ifdef COMPA_HAVE_WEBSERVER
849 in_port_t listen_port4,
853 in_port_t listen_port6,
857 in_port_t listen_port6UlaGua) {
858 UPnPsdk_LOGINFO("MSG1109") "Executing with listen_port4="
859 << listen_port4 << ", listen_port6=" << listen_port6
860 << ", listen_port6UlaGua=" << listen_port6UlaGua << ".\n";
861
862 int retval{UPNP_E_OUTOF_SOCKET};
863
864 if (out->pSockLlaObj != nullptr && gIF_IPV6[0] != '\0') {
865 try {
866 UPnPsdk::SSockaddr saObj;
867 if (::strncmp(gIF_IPV6, "::1", 3) == 0)
868 // The loopback address belongs to a lla but 'bind()' on win32
869 // does not accept it with scope id.
870 saObj = '[' + std::string(gIF_IPV6) +
871 "]:" + std::to_string(listen_port6);
872 else
873 saObj = '[' + std::string(gIF_IPV6) + '%' +
874 std::to_string(gIF_INDEX) +
875 "]:" + std::to_string(listen_port6);
876 out->pSockLlaObj->bind(SOCK_STREAM, &saObj, AI_PASSIVE);
877 out->pSockLlaObj->listen();
878 out->miniServerSock6 = *out->pSockLlaObj;
879 out->pSockLlaObj->local_saddr(&saObj);
880 out->miniServerPort6 = saObj.port();
881 retval = UPNP_E_SUCCESS;
882 } catch (const std::exception& ex) {
883 UPnPsdk_LOGCATCH("MSG1110") "gIF_IPV6=\""
884 << gIF_IPV6 << "\", catched next line...\n"
885 << ex.what();
886 }
887 }
888
889 // ss6.serverAddr6->sin6_scope_id = gIF_INDEX;
890 // I could not find where sin6_scope_id is read elsewhere to use it.
891 // It is never copied to 'out'. --Ingo
892
893 if (out->pSockGuaObj != nullptr && gIF_IPV6_ULA_GUA[0] != '\0') {
894 try {
895 UPnPsdk::SSockaddr saObj;
896 saObj = '[' + std::string(gIF_IPV6_ULA_GUA) +
897 "]:" + std::to_string(listen_port6UlaGua);
898 out->pSockGuaObj->bind(SOCK_STREAM, &saObj, AI_PASSIVE);
899 out->pSockGuaObj->listen();
900 out->miniServerSock6UlaGua = *out->pSockGuaObj;
901 out->pSockGuaObj->local_saddr(&saObj);
902 out->miniServerPort6UlaGua = saObj.port();
903 retval = UPNP_E_SUCCESS;
904 } catch (const std::exception& ex) {
905 UPnPsdk_LOGCATCH("MSG1117") "gIF_IPV6_ULA_GUA=\""
906 << gIF_IPV6_ULA_GUA << "\", catched next line...\n"
907 << ex.what();
908 }
909 }
910
911 if (out->pSockIp4Obj != nullptr && gIF_IPV4[0] != '\0') {
912 try {
913 UPnPsdk::SSockaddr saObj;
914 saObj = std::string(gIF_IPV4) + ':' + std::to_string(listen_port4);
915 out->pSockIp4Obj->bind(SOCK_STREAM, &saObj, AI_PASSIVE);
916 out->pSockIp4Obj->listen();
917 out->miniServerSock4 = *out->pSockIp4Obj;
918 out->pSockIp4Obj->local_saddr(&saObj);
919 out->miniServerPort4 = saObj.port();
920 retval = UPNP_E_SUCCESS;
921 } catch (const std::exception& ex) {
922 UPnPsdk_LOGCATCH("MSG1114") "gIF_IPV4=\""
923 << gIF_IPV4 << "\", catched next line...\n"
924 << ex.what();
925 }
926 }
927
928 if (retval != UPNP_E_SUCCESS)
929 UPnPsdk_LOGERR("MSG1065") "No valid IP address on a local network "
930 "adapter found for listening.\n";
931 return retval;
932}
933#endif /* COMPA_HAVE_WEBSERVER */
934
953 MiniServerSockArray* out) {
954 TRACE("Executing get_miniserver_stopsock()");
955 sockaddr_in stop_sockaddr;
956
957 UPnPsdk::CSocketErr sockerrObj;
958 SOCKET miniServerStopSock =
959 umock::sys_socket_h.socket(AF_INET, SOCK_DGRAM, 0);
960 if (miniServerStopSock == INVALID_SOCKET) {
961 sockerrObj.catch_error();
962 UPnPsdk_LOGCRIT("MSG1094") "Error in socket(): "
963 << sockerrObj.error_str() << "\n";
964 return UPNP_E_OUTOF_SOCKET;
965 }
966 /* Bind to local socket. */
967 memset(&stop_sockaddr, 0, sizeof(stop_sockaddr));
968 stop_sockaddr.sin_family = AF_INET;
969 inet_pton(AF_INET, "127.0.0.1", &stop_sockaddr.sin_addr);
970 int ret = umock::sys_socket_h.bind(
971 miniServerStopSock, reinterpret_cast<sockaddr*>(&stop_sockaddr),
972 sizeof(stop_sockaddr));
973 if (ret == SOCKET_ERROR) {
974 sockerrObj.catch_error();
975 UPnPsdk_LOGCRIT("MSG1095") "Error in binding localhost: "
976 << sockerrObj.error_str() << "\n";
977 sock_close(miniServerStopSock);
978 return UPNP_E_SOCKET_BIND;
979 }
980 ret = get_port(miniServerStopSock, &miniStopSockPort);
981 if (ret < 0) {
982 sock_close(miniServerStopSock);
984 }
985 out->miniServerStopSock = miniServerStopSock;
987
988 UPnPsdk_LOGINFO("MSG1053") "Bound stop socket="
989 << miniServerStopSock << " to \"127.0.0.1:" << miniStopSockPort
990 << "\".\n";
991
992 return UPNP_E_SUCCESS;
993}
994
999 MiniServerSockArray* miniSocket
1000) {
1001 TRACE("Executing InitMiniServerSockArray()");
1002 miniSocket->miniServerSock4 = INVALID_SOCKET;
1003 miniSocket->miniServerSock6 = INVALID_SOCKET;
1004 miniSocket->miniServerSock6UlaGua = INVALID_SOCKET;
1005 miniSocket->miniServerStopSock = INVALID_SOCKET;
1006 miniSocket->ssdpSock4 = INVALID_SOCKET;
1007 miniSocket->ssdpSock6 = INVALID_SOCKET;
1008 miniSocket->ssdpSock6UlaGua = INVALID_SOCKET;
1009 miniSocket->stopPort = 0u;
1010 miniSocket->miniServerPort4 = 0u;
1011 miniSocket->miniServerPort6 = 0u;
1012 miniSocket->miniServerPort6UlaGua = 0u;
1013#ifdef COMPA_HAVE_CTRLPT_SSDP
1014 miniSocket->ssdpReqSock4 = INVALID_SOCKET;
1015 miniSocket->ssdpReqSock6 = INVALID_SOCKET;
1016#endif
1017#ifdef COMPA_HAVE_WEBSERVER
1018 miniSocket->pSockLlaObj = nullptr;
1019 miniSocket->pSockGuaObj = nullptr;
1020 miniSocket->pSockIp4Obj = nullptr;
1021#endif
1022}
1023
1025} // anonymous namespace
1026
1027
1028#ifdef COMPA_HAVE_DEVICE_SOAP
1030 TRACE("Executing SetSoapCallback()");
1031 gSoapCallback = callback;
1032}
1033#endif
1034
1035#ifdef COMPA_HAVE_DEVICE_GENA
1037 TRACE("Executing SetGenaCallback()");
1038 gGenaCallback = callback;
1039}
1040#endif
1041
1042int StartMiniServer([[maybe_unused]] in_port_t* listen_port4,
1043 [[maybe_unused]] in_port_t* listen_port6,
1044 [[maybe_unused]] in_port_t* listen_port6UlaGua) {
1045 UPnPsdk_LOGINFO("MSG1068") "Executing...\n";
1046 constexpr int max_count{10000};
1047 MiniServerSockArray* miniSocket;
1048 ThreadPoolJob job;
1049 int ret_code{UPNP_E_INTERNAL_ERROR};
1050
1051 memset(&job, 0, sizeof(job));
1052
1053 if (gMServState != MSERV_IDLE) {
1054 /* miniserver running. */
1055 UPnPsdk_LOGERR("MSG1087") "Cannot start. Miniserver is running.\n";
1056 return UPNP_E_INTERNAL_ERROR;
1057 }
1058
1059 miniSocket = (MiniServerSockArray*)malloc(sizeof(MiniServerSockArray));
1060 if (!miniSocket) {
1061 return UPNP_E_OUTOF_MEMORY;
1062 }
1063 InitMiniServerSockArray(miniSocket);
1064
1065#ifdef COMPA_HAVE_WEBSERVER
1066 // These socket objects must be valid until the miniserver has successful
1067 // started. They will be moved to the running miniserver thread.
1068 UPnPsdk::CSocket sockLlaObj;
1069 miniSocket->pSockLlaObj = &sockLlaObj;
1070 UPnPsdk::CSocket sockGuaObj;
1071 miniSocket->pSockGuaObj = &sockGuaObj;
1072 UPnPsdk::CSocket sockIp4Obj;
1073 miniSocket->pSockIp4Obj = &sockIp4Obj;
1074
1075 /* V4 and V6 http listeners. */
1076 ret_code = get_miniserver_sockets(miniSocket, *listen_port4, *listen_port6,
1077 *listen_port6UlaGua);
1078 if (ret_code != UPNP_E_SUCCESS) {
1079 free(miniSocket);
1080 return ret_code;
1081 }
1082#endif
1083
1084 /* Stop socket (To end miniserver processing). */
1085 ret_code = get_miniserver_stopsock(miniSocket);
1086 if (ret_code != UPNP_E_SUCCESS) {
1087 sock_close(miniSocket->miniServerSock4);
1088 sock_close(miniSocket->miniServerSock6);
1089 sock_close(miniSocket->miniServerSock6UlaGua);
1090 free(miniSocket);
1091 return ret_code;
1092 }
1093#if defined(COMPA_HAVE_CTRLPT_SSDP) || defined(COMPA_HAVE_DEVICE_SSDP)
1094 /* SSDP socket for discovery/advertising. */
1095 ret_code = umock::pupnp_ssdp.get_ssdp_sockets(miniSocket);
1096 if (ret_code != UPNP_E_SUCCESS) {
1097 sock_close(miniSocket->miniServerSock4);
1098 sock_close(miniSocket->miniServerSock6);
1099 sock_close(miniSocket->miniServerSock6UlaGua);
1100 sock_close(miniSocket->miniServerStopSock);
1101 free(miniSocket);
1102 return ret_code;
1103 }
1104#endif
1105 // Run miniserver in a new thread.
1106 TPJobInit(&job, (UPnPsdk::start_routine)RunMiniServer_f, (void*)miniSocket);
1107 TPJobSetPriority(&job, MED_PRIORITY);
1109 ret_code = ThreadPoolAddPersistent(&gMiniServerThreadPool, &job, NULL);
1110 if (ret_code != 0) {
1111 sock_close(miniSocket->miniServerSock4);
1112 sock_close(miniSocket->miniServerSock6);
1113 sock_close(miniSocket->miniServerSock6UlaGua);
1114 sock_close(miniSocket->miniServerStopSock);
1115 sock_close(miniSocket->ssdpSock4);
1116 sock_close(miniSocket->ssdpSock6);
1117 sock_close(miniSocket->ssdpSock6UlaGua);
1118#ifdef COMPA_HAVE_CTRLPT_SSDP
1119 sock_close(miniSocket->ssdpReqSock4);
1120 sock_close(miniSocket->ssdpReqSock6);
1121#endif
1122 free(miniSocket);
1123 return UPNP_E_OUTOF_MEMORY;
1124 }
1125 /* Wait for miniserver to start. */
1126 int count{0};
1127 while (gMServState != (MiniServerState)MSERV_RUNNING && count < max_count) {
1128 /* 0.05s */
1129 std::this_thread::sleep_for(std::chrono::milliseconds(50));
1130 count++;
1131 }
1132 if (count >= max_count) {
1133 /* Took it too long to start that thread. */
1134 sock_close(miniSocket->miniServerSock4);
1135 sock_close(miniSocket->miniServerSock6);
1136 sock_close(miniSocket->miniServerSock6UlaGua);
1137 sock_close(miniSocket->miniServerStopSock);
1138 sock_close(miniSocket->ssdpSock4);
1139 sock_close(miniSocket->ssdpSock6);
1140 sock_close(miniSocket->ssdpSock6UlaGua);
1141#ifdef COMPA_HAVE_CTRLPT_SSDP
1142 sock_close(miniSocket->ssdpReqSock4);
1143 sock_close(miniSocket->ssdpReqSock6);
1144#endif
1145 return UPNP_E_INTERNAL_ERROR;
1146 }
1147#ifdef COMPA_HAVE_WEBSERVER
1148 *listen_port4 = miniSocket->miniServerPort4;
1149 *listen_port6 = miniSocket->miniServerPort6;
1150 *listen_port6UlaGua = miniSocket->miniServerPort6UlaGua;
1151#endif
1152
1153 return UPNP_E_SUCCESS;
1154}
1155
1157 UpnpPrintf(UPNP_INFO, MSERV, __FILE__, __LINE__,
1158 "Inside StopMiniServer()\n");
1159
1160 socklen_t socklen = sizeof(struct sockaddr_in);
1161 SOCKET sock;
1162 sockaddr_in ssdpAddr;
1163 char buf[256] = "ShutDown";
1164 // due to required type cast for 'sendto' on WIN32 bufLen must fit to an int
1165 size_t bufLen = strlen(buf);
1166
1167 switch (gMServState) {
1168 case MSERV_RUNNING:
1170 break;
1171 default:
1172 return 0;
1173 }
1174 sock = umock::sys_socket_h.socket(AF_INET, SOCK_DGRAM, 0);
1175 if (sock == INVALID_SOCKET) {
1176 UpnpPrintf(UPNP_ERROR, SSDP, __FILE__, __LINE__,
1177 "SSDP_SERVER: StopSSDPServer: Error in socket() %s\n",
1178 std::strerror(errno));
1179 return 1;
1180 }
1182 ssdpAddr.sin_family = (sa_family_t)AF_INET;
1183 inet_pton(AF_INET, "127.0.0.1", &ssdpAddr.sin_addr);
1184 ssdpAddr.sin_port = htons(miniStopSockPort);
1185 umock::sys_socket_h.sendto(sock, buf, (SIZEP_T)bufLen, 0,
1186 reinterpret_cast<sockaddr*>(&ssdpAddr),
1187 socklen);
1188 std::this_thread::sleep_for(std::chrono::milliseconds(1));
1190 break;
1191 }
1192 std::this_thread::sleep_for(std::chrono::seconds(1));
1193 }
1194
1195 sock_close(sock);
1196 return 0;
1197}
#define UPNP_E_NO_WEB_SERVER
The operation completed successfully.
Definition API.hpp:354
#define NAME_SIZE
Definition API.hpp:46
int http_SendMessage(SOCKINFO *info, int *TimeOut, const char *fmt,...)
Sends a message to the destination based on the format parameter.
int http_SendStatusResponse(SOCKINFO *info, int http_status_code, int request_major_version, int request_minor_version)
Generate a response message for the status query and send the status response.
int http_RecvMessage(SOCKINFO *info, http_parser_t *parser, http_method_t request_method, int *timeout_secs, int *http_error_code)
Get the data on the socket and take actions based on the read data to modify the parser objects buffe...
http_message_t msg
entire raw message
http_method_t method
Http method of an outgoing request.
int major_version
Http major version.
#define HDR_HOST
Type of a HTTP header.
int minor_version
Http minor version.
Structure of an HTTP parser object.
Structure of an HTTP message.
#define HTTP_DEFAULT_TIMEOUT
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.
int ThreadPoolAddPersistent(ThreadPool *tp, ThreadPoolJob *job, int *jobId)
Adds a persistent job to the thread pool.
void(* free_routine)(void *arg)
Internal ThreadPool Job.
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
Get information from a raw network socket file descriptor.
Definition socket.hpp:129
bool local_saddr(SSockaddr *a_saddr=nullptr) const
Get the local socket address the socket is bound to.
Definition socket.cpp:231
void load()
Load the raw socket file descriptor specified with the constructor into the object.
Definition socket.cpp:196
Manage all aspects of a network socket.
Definition socket.hpp:320
void listen()
Set socket to listen.
Definition socket.cpp:552
void bind(const int a_socktype, const SSockaddr *const a_saddr=nullptr, const int a_flags=0)
Bind socket to an ip address of a local network adapter.
Definition socket.cpp:464
int readFromSSDPSocket(SOCKET socket)
This function reads the data from the ssdp socket.
int(* WebCallback_HostValidate)(const char *hostname, void *cookie)
Callback for validating HTTP requests HOST header values.
Definition API.hpp:2800
Helpful union of the different socket address structures.
Definition sockaddr.hpp:34
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.
void membuffer_destroy(membuffer *m)
Free's memory allocated for membuffer* m.
void membuffer_init(membuffer *m)
Wrapper to membuffer_initialize().
int membuffer_append_str(membuffer *m, const char *c_str)
Invokes function to appends data from a constant string to the buffer.
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_SOCKET_ERROR
Generic socket error code for conditions not covered by other error codes.
Definition messages.hpp:243
#define UPNP_E_SOCKET_BIND
The SDK had a problem binding a socket to a network interface.
Definition messages.hpp:199
#define UPNP_E_BAD_HTTPMSG
The HTTP message contains invalid message headers.
Definition messages.hpp:146
#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_ACCEPT
The SDK had a problem accepting a network connection.
Definition messages.hpp:262
#define UPNP_E_INTERNAL_ERROR
Generic error code for internal conditions not covered by other error codes.
Definition messages.hpp:319
void SetSoapCallback(MiniServerCallback callback)
Set SOAP Callback.
int StartMiniServer(in_port_t *listen_port4, in_port_t *listen_port6, in_port_t *listen_port6UlaGua)
Initialize the sockets functionality for the Miniserver.
int StopMiniServer()
Stop and Shutdown the MiniServer and free socket resources.
void SetGenaCallback(MiniServerCallback callback)
Set GENA Callback.
Manage "Step 0: Addressing" of the UPnP+™ specification.
in_port_t miniServerPort6
Corresponding port to miniServerSock6.
in_port_t miniServerPort6UlaGua
Corresponding port to miniServerSock6UlaGua.
SOCKET ssdpSock4
IPv4 SSDP datagram Socket for incoming advertisments and search requests.
void(* MiniServerCallback)(http_parser_t *parser, http_message_t *request, SOCKINFO *info)
For a miniserver callback function.
SOCKET miniServerSock6UlaGua
IPv6 ULA or GUA Socket for listening for miniserver requests.
in_port_t stopPort
Corresponding port to miniServerStopSock. This is set with miniStopSockPort but never used.
SOCKET miniServerSock4
IPv4 socket for listening for miniserver requests.
in_port_t miniServerPort4
Corresponding port to miniServerSock4.
MiniServerCallback gGetCallback
HTTP server callback.
SOCKET ssdpReqSock6
IPv6 SSDP socket for sending search requests and receiving search replies.
SOCKET ssdpReqSock4
IPv4 SSDP socket for sending search requests and receiving search replies.
SOCKET miniServerStopSock
Datagram Socket for stopping miniserver.
SOCKET ssdpSock6
IPv6 LLA SSDP Socket for incoming advertisments and search requests.
SOCKET miniServerSock6
IPv6 LLA Socket for listening for miniserver requests.
SOCKET ssdpSock6UlaGua
IPv6 ULA or GUA SSDP Socket for incoming advertisments and search requests.
Provides sockets for all network communications.
UPnPsdk_EXTERN bool g_dbug
Switch to enable verbose (debug) output.
Definition global.hpp:26
void ssdp_read(SOCKET *rsock, fd_set *set)
Read data from the SSDP socket.
int host_header_is_numeric(char *a_host_port, size_t a_host_port_len)
Check if a network address is numeric.
int get_miniserver_stopsock(MiniServerSockArray *out)
Creates the miniserver STOP socket, usable to listen for stopping the miniserver.
SOCKET connfd
Connection socket file descriptor.
void RunMiniServer(MiniServerSockArray *miniSock)
Run the miniserver.
MiniServerCallback gSoapCallback
SOAP callback.
int web_server_accept(SOCKET listen_sock, fd_set &set)
Accept requested connection from a remote control point and run it in a new thread.
void InitMiniServerSockArray(MiniServerSockArray *miniSocket)
Initialize a miniserver Socket Array.
void schedule_request_job(SOCKET a_connfd, UPnPsdk::SSockaddr &clientAddr)
Initilize the thread pool to handle an incomming request, sets priority for the job and adds the job ...
void free_handle_request_arg(void *args)
Free memory assigned for handling request and unitialize socket functionality.
in_port_t miniStopSockPort
Port of the stop socket.
int getNumericHostRedirection(SOCKET a_socket, char *a_host_port, size_t a_hp_size)
Returns the ip address with port as text that is bound to a socket.
MiniServerCallback gGenaCallback
GENA callback.
int receive_from_stopSock(SOCKET ssock, fd_set *set)
Check if we have received a packet that shall stop the miniserver.
int get_miniserver_sockets(MiniServerSockArray *out, in_port_t listen_port4, in_port_t listen_port6, in_port_t listen_port6UlaGua)
Create STREAM sockets, binds to local network interfaces and listens for incoming connections.
void RunMiniServer_f(MiniServerSockArray *miniSock)
Check if a network address is numeric.
void fdset_if_valid(SOCKET a_sock, fd_set *a_set)
Add a socket file descriptor to an 'fd_set' structure as needed for ::select().
sockaddr_storage foreign_sockaddr
Socket address of the remote control point.
@ MSERV_RUNNING
miniserver is running.
@ MSERV_STOPPING
miniserver is running to stop.
void handle_request(void *args)
Receive the request and dispatch it for handling.
int dispatch_request(SOCKINFO *a_info, http_parser_t *a_hparser)
Based on the type of message, appropriate callback is issued.
MiniServerState gMServState
miniserver state
int get_port(SOCKET sockfd, uint16_t *port)
Returns port to which socket, sockfd, is bound.
miniserver received request message.
int sock_destroy(SOCKINFO *info, int ShutdownMethod)
Shutsdown the socket using the ShutdownMethod to indicate whether sends and receives on the socket wi...
Definition sock.cpp:489
int sock_init_with_ip(SOCKINFO *info, SOCKET sockfd, sockaddr *foreign_sockaddr)
Calls the sock_init function and assigns the passed in IP address and port to the IP address and port...
Definition sock.cpp:451
SOCKET socket
Handle/descriptor to a socket.
Definition sock.hpp:67
int sock_close(SOCKET sock)
Closes the socket if it is different from -1.
Definition sock.hpp:85
Additional socket information for connections and ssl.
Definition sock.hpp:65
Manage "Step 1: Discovery" of the UPnP+™ specification with SSDP.
HTTP status codes.
Trivial ::sockaddr structures enhanced with methods.
Definition sockaddr.hpp:94
const std::string netaddrp() noexcept
Get the assosiated netaddress with port.
Definition sockaddr.cpp:519
sockaddr & sa
Reference to sockaddr struct.
Definition sockaddr.hpp:104
in_port_t port() const
Get the numeric port.
Definition sockaddr.cpp:545
sockaddr_storage & ss
Reference to sockaddr_storage struct.
Definition sockaddr.hpp:96
WebCallback_HostValidate gWebCallback_HostValidate
webCallback for HOST validation.
Definition upnpapi.cpp:271
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
int gAllowLiteralHostRedirection
Allow literal host names redirection to numeric host names.
Definition upnpapi.cpp:277
void * gWebCallback_HostValidateCookie
Cookie to the webCallback for HOST validation.
Definition upnpapi.cpp:274
char gIF_IPV4[INET_ADDRSTRLEN]
Static buffer to contain interface IPv4 address. (extern'ed in upnp.h)
Definition upnpapi.cpp:284
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
ThreadPool gMiniServerThreadPool
Mini server thread pool.
Definition upnpapi.cpp:265
char gIF_IPV6[INET6_ADDRSTRLEN]
Static buffer to contain interface IPv6 link-local address (LLA). (extern'ed in upnp....
Definition upnpapi.cpp:292
Inititalize the compatible library before it can be used.
UPnPsdk_VIS void UpnpPrintf(Upnp_LogLevel DLevel, Dbg_Module Module, const char *DbgFileName, int DbgLineNo, const char *FmtStr,...)
Prints the debug statement.