47#ifndef COMPA_SSDP_COMMON_HPP
48#error "No or wrong ssdp_common.hpp header file included."
50#ifndef COMPA_INTERNAL_CONFIG_HPP
51#error "No or wrong config.hpp header file included."
55#include <umock/sys_socket.hpp>
56#include <umock/winsock2.hpp>
61using compa::uriType::Relative;
102 if (hmsg->
uri.
type != Relative ||
109 (
memptr_cmp(&hdr_value,
"239.255.255.250:1900") != 0 &&
110 memptr_cmp(&hdr_value,
"[FF02::C]:1900") != 0 &&
111 memptr_cmp(&hdr_value,
"[ff02::c]:1900") != 0 &&
112 memptr_cmp(&hdr_value,
"[FF05::C]:1900") != 0 &&
113 memptr_cmp(&hdr_value,
"[ff05::c]:1900") != 0)) {
114 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
115 "Invalid HOST header from SSDP message\n");
146 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
147 "SSDP recvd bad msg code = %d\n", status);
153 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
154 "SSDP recvd bad msg code = %d\n", status);
186#ifdef COMPA_HAVE_CTRLPT_SSDP
190#ifdef COMPA_HAVE_DEVICE_SSDP
213 UPnPsdk_LOGINFO(
"MSG1075")
"Executing...\n";
215 u_char ttl = (u_char)4;
216 ip_mreq ssdpMcastAddr;
217 sockaddr_storage __ss;
218 sockaddr_in* ssdpAddr4 = (
struct sockaddr_in*)&__ss;
223 *ssdpSock = umock::sys_socket_h.socket(AF_INET, SOCK_DGRAM, 0);
224 if (*ssdpSock == INVALID_SOCKET) {
226 UPnPsdk_LOGCRIT(
"MSG1076")
"Error in socket(): "
231 ret = umock::sys_socket_h.setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEADDR,
232 (
char*)&onOff,
sizeof(onOff));
235 UPnPsdk_LOGCRIT(
"MSG1077")
"Error in setsockopt() SO_REUSEADDR: "
240#if (defined(BSD) && !defined(__GNU__)) || defined(__APPLE__)
242 ret = umock::sys_socket_h.setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEPORT,
243 (
char*)&onOff,
sizeof(onOff));
246 UPnPsdk_LOGCRIT(
"MSG1078")
"Error in setsockopt() SO_REUSEP: "
252 memset(&__ss, 0,
sizeof(__ss));
253 ssdpAddr4->sin_family = (sa_family_t)AF_INET;
254 ssdpAddr4->sin_addr.s_addr = htonl(INADDR_ANY);
256 ret = umock::sys_socket_h.bind(*ssdpSock, (sockaddr*)ssdpAddr4,
260 UPnPsdk_LOGCRIT(
"MSG1079")
"Error in bind(), addr="
261 << INADDR_ANY <<
", port=" <<
SSDP_PORT <<
": "
277 memset((
void*)&ssdpMcastAddr, 0,
sizeof ssdpMcastAddr);
278 inet_pton(AF_INET,
gIF_IPV4, &ssdpMcastAddr.imr_interface);
279 inet_pton(AF_INET,
SSDP_IP, &ssdpMcastAddr.imr_multiaddr);
280 ret = umock::sys_socket_h.setsockopt(
281 *ssdpSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (
char*)&ssdpMcastAddr,
282 sizeof(
struct ip_mreq));
285 UPnPsdk_LOGCRIT(
"MSG1080")
"Error in setsockopt() IP_ADD_MEMBERSHIP "
286 "(join multicast group): "
292 memset((
void*)&addr, 0,
sizeof(
struct in_addr));
293 inet_pton(AF_INET,
gIF_IPV4, &addr);
294 ret = umock::sys_socket_h.setsockopt(*ssdpSock, IPPROTO_IP, IP_MULTICAST_IF,
295 (
char*)&addr,
sizeof addr);
298 UPnPsdk_LOGINFO(
"MSG1081")
"Error in setsockopt() IP_MULTICAST_IF (set "
299 "multicast interface): "
304 umock::sys_socket_h.setsockopt(*ssdpSock, IPPROTO_IP, IP_MULTICAST_TTL,
305 (
const char*)&ttl,
sizeof(ttl));
307 ret = umock::sys_socket_h.setsockopt(*ssdpSock, SOL_SOCKET, SO_BROADCAST,
308 (
char*)&onOff,
sizeof(onOff));
312 "MSG1082")
"Error in setsockopt() SO_BROADCAST (set broadcast): "
321 umock::unistd_h.CLOSE_SOCKET_P(*ssdpSock);
327#ifdef UPNP_ENABLE_IPV6
342 UPnPsdk_LOGINFO(
"MSG1083")
"Executing...\n";
344 ipv6_mreq ssdpMcastAddr;
345 sockaddr_storage __ss;
346 sockaddr_in6* ssdpAddr6 = (
struct sockaddr_in6*)&__ss;
350 *ssdpSock = umock::sys_socket_h.socket(AF_INET6, SOCK_DGRAM, 0);
351 if (*ssdpSock == INVALID_SOCKET) {
353 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
354 "Error in socket(): %s\n", errorBuffer);
359 ret = umock::sys_socket_h.setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEADDR,
360 (
char*)&onOff,
sizeof(onOff));
363 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
364 "Error in setsockopt() SO_REUSEADDR: %s\n", errorBuffer);
368#if (defined(BSD) && !defined(__GNU__)) || defined(__APPLE__)
370 ret = umock::sys_socket_h.setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEPORT,
371 (
char*)&onOff,
sizeof(onOff));
374 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
375 "Error in setsockopt() SO_REUSEPORT: %s\n", errorBuffer);
381 ret = umock::sys_socket_h.setsockopt(*ssdpSock, IPPROTO_IPV6, IPV6_V6ONLY,
382 (
char*)&onOff,
sizeof(onOff));
385 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
386 "Error in setsockopt() IPV6_V6ONLY: %s\n", errorBuffer);
390 memset(&__ss, 0,
sizeof(__ss));
391 ssdpAddr6->sin6_family = (sa_family_t)AF_INET6;
392 ssdpAddr6->sin6_addr = in6addr_any;
397 ret = umock::sys_socket_h.bind(*ssdpSock, (
struct sockaddr*)ssdpAddr6,
402 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
403 "Error in bind(), addr=%s, index=%d, port=%d: %s\n",
408 int wsa_err = umock::winsock2_h.WSAGetLastError();
409 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
410 "Error in bind(), addr=%s, index=%d, port=%d: %d\n",
416 memset((
void*)&ssdpMcastAddr, 0,
sizeof(ssdpMcastAddr));
417 ssdpMcastAddr.ipv6mr_interface =
gIF_INDEX;
419 ret = umock::sys_socket_h.setsockopt(*ssdpSock, IPPROTO_IPV6,
420 IPV6_JOIN_GROUP, (
char*)&ssdpMcastAddr,
421 sizeof(ssdpMcastAddr));
424 uint32_t* p = (uint32_t*)&ssdpMcastAddr.ipv6mr_multiaddr;
425 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
426 "Error in setsockopt() IPV6_JOIN_GROUP (join multicast "
428 "SSDP_IPV6_LINKLOCAL = %s,\n"
429 "ipv6mr_interface = %u,\n"
430 "ipv6mr_multiaddr[0,1,2,3] = "
431 "0x%08X:0x%08X:0x%08X:0x%08X\n"
434 ssdpMcastAddr.ipv6mr_interface, p[0], p[1], p[2], p[3],
440 ret = umock::sys_socket_h.setsockopt(*ssdpSock, SOL_SOCKET, SO_BROADCAST,
441 (
char*)&onOff,
sizeof(onOff));
444 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
445 "Error in setsockopt() SO_BROADCAST (set broadcast): "
455 umock::unistd_h.CLOSE_SOCKET_P(*ssdpSock);
462#ifdef UPNP_ENABLE_IPV6
477 UPnPsdk_LOGINFO(
"MSG1084")
"Executing...\n";
479 ipv6_mreq ssdpMcastAddr;
483 *ssdpSock = umock::sys_socket_h.socket(AF_INET6, SOCK_DGRAM, 0);
484 if (*ssdpSock == INVALID_SOCKET) {
486 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
487 "Error in socket(): %s\n", errorBuffer);
492 ret = umock::sys_socket_h.setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEADDR,
493 (
char*)&onOff,
sizeof(onOff));
496 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
497 "Error in setsockopt() SO_REUSEADDR: %s\n", errorBuffer);
501#if (defined(BSD) && !defined(__GNU__)) || defined(__APPLE__)
503 ret = umock::sys_socket_h.setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEPORT,
504 (
char*)&onOff,
sizeof(onOff));
507 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
508 "Error in setsockopt() SO_REUSEPORT: %s\n", errorBuffer);
514 ret = umock::sys_socket_h.setsockopt(*ssdpSock, IPPROTO_IPV6, IPV6_V6ONLY,
515 (
char*)&onOff,
sizeof(onOff));
518 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
519 "Error in setsockopt() IPV6_V6ONLY: %s\n", errorBuffer);
526 saddr.sin6.sin6_family = AF_INET6;
527 saddr.sin6.sin6_addr = in6addr_any;
532 umock::sys_socket_h.bind(*ssdpSock, &saddr.sa,
sizeof(saddr.sin6));
535 UPnPsdk_LOGERR(
"MSG1134")
"in ::bind() with addr=\"[::]:"
536 <<
SSDP_PORT <<
"\": (" << serrObj <<
") "
542 memset((
void*)&ssdpMcastAddr, 0,
sizeof(ssdpMcastAddr));
543 ssdpMcastAddr.ipv6mr_interface =
gIF_INDEX;
546 ret = umock::sys_socket_h.setsockopt(*ssdpSock, IPPROTO_IPV6,
547 IPV6_JOIN_GROUP, (
char*)&ssdpMcastAddr,
548 sizeof(ssdpMcastAddr));
551 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
552 "Error in setsockopt() IPV6_JOIN_GROUP (join multicast "
559 ret = umock::sys_socket_h.setsockopt(*ssdpSock, SOL_SOCKET, SO_BROADCAST,
560 (
char*)&onOff,
sizeof(onOff));
563 UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
564 "Error in setsockopt() SO_BROADCAST (set broadcast): "
574 umock::unistd_h.CLOSE_SOCKET_P(*ssdpSock);
587 char* TempPtr = NULL;
592 int CommandFound = 0;
593 size_t n = (size_t)0;
595 if (strstr(cmd,
"uuid:schemas") != NULL) {
596 ptr1 = strstr(cmd,
":device");
598 ptr2 = strstr(ptr1 + 1,
":");
602 ptr3 = strstr(ptr2 + 1,
":");
606 if (strlen(
"uuid:") + strlen(ptr3 + 1) >=
sizeof Evt->
UDN)
608 snprintf(Evt->
UDN,
sizeof Evt->
UDN,
"uuid:%s", ptr3 + 1);
611 ptr1 = strstr(cmd,
":");
613 n = (size_t)ptr3 - (
size_t)ptr1;
614 n = n >=
sizeof TempBuf ?
sizeof TempBuf - 1 : n;
615 strncpy(TempBuf, ptr1, n);
617 if (strlen(
"urn") + strlen(TempBuf) >=
sizeof(Evt->
DeviceType))
625 if ((TempPtr = strstr(cmd,
"uuid")) != NULL) {
626 if ((Ptr = strstr(cmd,
"::")) != NULL) {
627 n = (size_t)Ptr - (
size_t)TempPtr;
628 n = n >=
sizeof Evt->
UDN ?
sizeof Evt->
UDN - 1 : n;
629 strncpy(Evt->
UDN, TempPtr, n);
632 memset(Evt->
UDN, 0,
sizeof(Evt->
UDN));
633 strncpy(Evt->
UDN, TempPtr,
sizeof Evt->
UDN - 1);
637 if (strstr(cmd,
"urn:") != NULL && strstr(cmd,
":service:") != NULL) {
638 if ((TempPtr = strstr(cmd,
"urn")) != NULL) {
644 if (strstr(cmd,
"urn:") != NULL && strstr(cmd,
":device:") != NULL) {
645 if ((TempPtr = strstr(cmd,
"urn")) != NULL) {
651 if ((TempPtr = strstr(cmd,
"::upnp:rootdevice")) != NULL) {
653 if (TempPtr != cmd) {
654 n = (size_t)TempPtr - (
size_t)cmd;
655 n = n >=
sizeof Evt->
UDN ?
sizeof Evt->
UDN - 1 : n;
656 strncpy(Evt->
UDN, cmd, n);
661 if (CommandFound == 0)
668 if (strstr(cmd,
":all"))
670 if (strstr(cmd,
":rootdevice"))
672 if (strstr(cmd,
"uuid:"))
674 if (strstr(cmd,
"urn:") && strstr(cmd,
":device:"))
676 if (strstr(cmd,
"urn:") && strstr(cmd,
":service:"))
695 TRACE(
"Executing readFromSSDPSocket()")
696 char* requestBuf = NULL;
698 struct sockaddr_storage __ss;
701 socklen_t socklen =
sizeof(__ss);
702 ssize_t byteReceived = 0;
703 char ntop_buf[INET6_ADDRSTRLEN];
705 memset(&job, 0,
sizeof(job));
707 requestBuf = staticBuf;
713#ifdef COMPA_HAVE_CTRLPT_SSDP
715#ifdef UPNP_ENABLE_IPV6
735 umock::sys_socket_h.recvfrom(socket, requestBuf,
BUFSIZE - (
size_t)1, 0,
736 (
struct sockaddr*)&__ss, &socklen);
737 if (byteReceived > 0) {
738 requestBuf[byteReceived] =
'\0';
739 switch (__ss.ss_family) {
741 inet_ntop(AF_INET, &((
struct sockaddr_in*)&__ss)->sin_addr,
742 ntop_buf,
sizeof(ntop_buf));
744#ifdef UPNP_ENABLE_IPV6
746 inet_ntop(AF_INET6, &((
struct sockaddr_in6*)&__ss)->sin6_addr,
747 ntop_buf,
sizeof(ntop_buf));
751 memset(ntop_buf, 0,
sizeof(ntop_buf));
752 strncpy(ntop_buf,
"<Invalid address family>",
sizeof(ntop_buf) - 1);
755 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
756 "Start of received response ----------------------------------------------------\n"
758 "End of received response ------------------------------------------------------\n"
759 "From host %s\n", requestBuf, ntop_buf);
766 memcpy(&data->
dest_addr, &__ss,
sizeof(__ss));
784 UPnPsdk_LOGINFO(
"MSG1057")
"Executing...\n";
786#ifdef COMPA_HAVE_CTRLPT_SSDP
799#ifdef UPNP_ENABLE_IPV6
816#ifdef COMPA_HAVE_CTRLPT_SSDP
824#ifdef UPNP_ENABLE_IPV6
829 umock::unistd_h.CLOSE_SOCKET_P(out->
ssdpSock4);
830#ifdef COMPA_HAVE_CTRLPT_SSDP
841 umock::unistd_h.CLOSE_SOCKET_P(out->
ssdpSock4);
842 umock::unistd_h.CLOSE_SOCKET_P(out->
ssdpSock6);
843#ifdef COMPA_HAVE_CTRLPT_SSDP
http_message_t msg
entire raw message
uri_type uri
Type of a uri, e.g. absolute, relative, etc.
http_method_t method
Http method of an outgoing request.
http_method_t
Method in a HTTP request.
membuffer msg
entire raw message.
#define HDR_HOST
Type of a HTTP header.
http_method_t request_method
Http method of an incoming response.
parse_status_t
Status of parsing.
int valid_ssdp_notify_hack
read-only; this is set to 1 if a NOTIFY request has no content-length. used to read valid sspd notify...
Structure of an HTTP parser object.
Structure of an HTTP message.
size_t size
Size of the buffer.
compa::uriType type
Member variable.
token pathquery
Member variable.
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.
Class for portable handling of network socket errors.
void catch_error()
Catch error for later use.
std::string error_str() const
Get human readable error description of the catched error.
int unique_service_name(char *cmd, SsdpEvent *Evt)
Fills the fields of the event structure like DeviceType, Device UDN and Service Type.
void ssdp_handle_ctrlpt_msg(http_message_t *hmsg, sockaddr_storage *dest_addr, int timeout)
This function handles the ssdp messages from the devices.
int create_ssdp_sock_reqv6(SOCKET *ssdpReqSock)
Creates the SSDP IPv6 socket to be used by the control point.
int create_ssdp_sock_reqv4(SOCKET *ssdpReqSock)
Creates the SSDP IPv4 socket to be used by the control point.
Helpful union of the different socket address structures.
parse_status_t parser_parse(http_parser_t *parser)
The parser function.
void parser_request_init(http_parser_t *parser)
Initializes parser object for a request.
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 parser_response_init(http_parser_t *parser, http_method_t request_method)
Initializes parser object for a response.
void httpmsg_destroy(http_message_t *msg)
Free memory allocated for the http message.
int memptr_cmp(memptr *m, const char *s)
Compares characters of strings passed for number of bytes. If equal for the number of bytes,...
int membuffer_set_size(membuffer *m, size_t new_length)
Increases or decreases buffer cap so that at least 'new_length' bytes can be stored.
size_t length
length of buffer without terminating null byte (read-only).
char * buf
mem buffer; must not write beyond buf[length-1] (read/write).
pointer to a chunk of memory.
#define UPNP_E_SOCKET_ERROR
Generic socket error code for conditions not covered by other error codes.
#define UPNP_E_NETWORK_ERROR
A network error occurred.
#define UPNP_E_SOCKET_BIND
The SDK had a problem binding a socket to a network interface.
#define UPNP_E_SUCCESS
The operation completed successfully.
#define UPNP_E_OUTOF_SOCKET
The SDK cannot create any more sockets.
SOCKET ssdpSock4
IPv4 SSDP datagram Socket for incoming advertisments and search requests.
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 ssdpSock6
IPv6 LLA SSDP Socket for incoming advertisments and search requests.
SOCKET ssdpSock6UlaGua
IPv6 ULA or GUA SSDP Socket for incoming advertisments and search requests.
Provides sockets for all network communications.
int create_ssdp_sock_v6(SOCKET *ssdpSock)
Create an SSDP IPv6 socket.
void free_ssdp_event_handler_data(void *the_data)
Frees the ssdp request.
int create_ssdp_sock_v4(SOCKET *ssdpSock)
Create an SSDP IPv4 socket.
int start_event_handler(void *Data)
Parses the message and dispatches it to a handler which handles the ssdp request msg.
void ssdp_event_handler_thread(void *the_data)
This function is a thread that handles SSDP requests.
int valid_ssdp_msg(http_message_t *hmsg)
Does some quick checking of the ssdp msg.
int create_ssdp_sock_v6_ula_gua(SOCKET *ssdpSock)
Create an SSDP IPv6 ULA_GUA socket.
Socket Module: manage properties and methods but not connections of ONE network socket to handle IPv4...
int ssdp_request_type(char *cmd, SsdpEvent *Evt)
Starts filling the SSDP event structure based upon the request received.
int get_ssdp_sockets(MiniServerSockArray *out)
Creates the IPv4 and IPv6 ssdp sockets required by the control point and device operation.
SsdpSearchType ssdp_request_type1(char *cmd)
This function figures out the type of the SSDP search in the request.
int readFromSSDPSocket(SOCKET socket)
This function reads the data from the ssdp socket.
#define SSDP_PORT
constant
sockaddr_storage dest_addr
destination socket address
char UDN[LINE_SIZE]
Part of SSDP Event.
constexpr size_t ERROR_BUFFER_LEN
Size of the errorBuffer variable, passed to the strerror_r() function.
#define SSDP_IPV6_SITELOCAL
constant
char ServiceType[LINE_SIZE]
Part of SSDP Event.
int ErrCode
Part of SSDP Event.
#define SSDP_IPV6_LINKLOCAL
constant
char DeviceType[LINE_SIZE]
Part of SSDP Event.
#define E_HTTP_SYNTEX
error code
http_parser_t parser
parser
SOCKET gSsdpReqSocket6
If control point API is compiled in, this is the global IPv6 socket for it.
enum SsdpSearchType RequestType
Part of SSDP Event.
#define NO_ERROR_FOUND
error code
SOCKET gSsdpReqSocket4
If control point API is compiled in, this is the global IPv4 socket for it.
SsdpSearchType
Enumeration to define all different types of ssdp searches.
@ SSDP_SERROR
Unknown search command.
@ SSDP_DEVICEUDN
Part of SType.
@ SSDP_DEVICETYPE
Part of SType.
@ SSDP_ROOTDEVICE
Part of SType.
@ SSDP_SERVICE
Part of SType.
Structure to store the SSDP information.
Manage "Step 1: Discovery" of the UPnP+™ specification for Control Points with SSDP.
Manage "Step 1: Discovery" of the UPnP+™ specification for UPnP Devices with SSDP.
void ssdp_handle_device_request(http_message_t *hmsg, struct sockaddr_storage *dest_addr)
Handles the search request.
char gIF_IPV6_ULA_GUA[INET6_ADDRSTRLEN]
Static buffer to contain interface IPv6 unique-local or globally-unique address (ULA or GUA)....
ThreadPool gRecvThreadPool
Receive thread pool.
char gIF_IPV4[INET_ADDRSTRLEN]
Static buffer to contain interface IPv4 address. (extern'ed in upnp.h)
char gIF_NAME[LINE_SIZE]
Static buffer to contain interface name. (extern'ed in upnp.h)
unsigned gIF_INDEX
Contains network interface index of the link local address gIF_IPV6 that is used as its scope_id.
char gIF_IPV6[INET6_ADDRSTRLEN]
Static buffer to contain interface IPv6 link-local address (LLA). (extern'ed in upnp....
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.