48#include <umock/sys_socket.hpp>
49#include <umock/pupnp_sock.hpp>
51#ifndef COMPA_INTERNAL_CONFIG_HPP
52#error "No or wrong config.hpp header file included."
101 const char* command =
"M-SEARCH * HTTP/1.1\r\n";
102 const char* man =
"MAN: \"ssdp:discover\"\r\n";
104 memset(TempBuf, 0,
sizeof(TempBuf));
105 if (RqstBufSize <= strlen(command))
107 strcpy(RqstBuf, command);
109 switch (AddressFamily) {
111 rc = snprintf(TempBuf,
sizeof(TempBuf),
"HOST: %s:%d\r\n",
SSDP_IP,
115 rc = snprintf(TempBuf,
sizeof(TempBuf),
"HOST: [%s]:%d\r\n",
121 if (rc < 0 || (
unsigned int)rc >=
sizeof(TempBuf))
124 if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
126 strcat(RqstBuf, TempBuf);
128 if (RqstBufSize <= strlen(RqstBuf) + strlen(man))
130 strcat(RqstBuf, man);
133 rc = snprintf(TempBuf,
sizeof(TempBuf),
"MX: %d\r\n", Mx);
134 if (rc < 0 || (
unsigned int)rc >=
sizeof(TempBuf))
136 if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
138 strcat(RqstBuf, TempBuf);
141 if (SearchTarget != NULL) {
142 rc = snprintf(TempBuf,
sizeof(TempBuf),
"ST: %s\r\n", SearchTarget);
143 if (rc < 0 || (
unsigned int)rc >=
sizeof(TempBuf))
145 if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
147 strcat(RqstBuf, TempBuf);
149 if (RqstBufSize <= strlen(RqstBuf) + strlen(
"\r\n"))
151 strcat(RqstBuf,
"\r\n");
167#ifdef UPNP_ENABLE_IPV6
181 const char* command =
"M-SEARCH * HTTP/1.1\r\n";
182 const char* man =
"MAN: \"ssdp:discover\"\r\n";
184 memset(TempBuf, 0,
sizeof(TempBuf));
185 if (RqstBufSize <= strlen(command))
187 strcpy(RqstBuf, command);
188 switch (AddressFamily) {
190 rc = snprintf(TempBuf,
sizeof(TempBuf),
"HOST: %s:%d\r\n",
SSDP_IP,
194 rc = snprintf(TempBuf,
sizeof(TempBuf),
"HOST: [%s]:%d\r\n",
200 if (rc < 0 || (
unsigned int)rc >=
sizeof(TempBuf))
203 if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
205 strcat(RqstBuf, TempBuf);
207 if (RqstBufSize <= strlen(RqstBuf) + strlen(man))
209 strcat(RqstBuf, man);
212 rc = snprintf(TempBuf,
sizeof(TempBuf),
"MX: %d\r\n", Mx);
213 if (rc < 0 || (
unsigned int)rc >=
sizeof(TempBuf))
215 if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
217 strcat(RqstBuf, TempBuf);
220 rc = snprintf(TempBuf,
sizeof(TempBuf),
"ST: %s\r\n", SearchTarget);
221 if (rc < 0 || (
unsigned int)rc >=
sizeof(TempBuf))
223 if (RqstBufSize <= strlen(RqstBuf) + strlen(TempBuf))
225 strcat(RqstBuf, TempBuf);
227 if (RqstBufSize <= strlen(RqstBuf) + strlen(
"\r\n"))
229 strcat(RqstBuf,
"\r\n");
260 ctrlpt_callback = ctrlpt_info->
Callback;
262 while (node != NULL) {
287 struct sockaddr_storage* dest_addr,
int timeout) {
317 goto end_ssdp_handle_ctrlpt_msg;
322 for (handle = handle_start; handle <
NUM_HANDLE; handle++) {
331 ctrlpt_callback = ctrlpt_info->
Callback;
332 ctrlpt_cookie = ctrlpt_info->
Cookie;
337 goto end_ssdp_handle_ctrlpt_msg;
349 goto end_ssdp_handle_ctrlpt_msg;
372 event.DeviceType[0] =
'\0';
373 event.ServiceType[0] =
'\0';
376 save_char = hdr_value.
buf[hdr_value.
length];
379 hdr_value.
buf[hdr_value.
length] = save_char;
383 save_char = hdr_value.
buf[hdr_value.
length];
386 hdr_value.
buf[hdr_value.
length] = save_char;
388 if (nt_found || usn_found) {
398 goto end_ssdp_handle_ctrlpt_msg;
400 if (
memptr_cmp(&hdr_value,
"ssdp:alive") == 0) {
402 }
else if (
memptr_cmp(&hdr_value,
"ssdp:byebye") == 0) {
406 goto end_ssdp_handle_ctrlpt_msg;
410 if (!nt_found || !usn_found) {
412 goto end_ssdp_handle_ctrlpt_msg;
420 if (!nt_found || !usn_found ||
424 goto end_ssdp_handle_ctrlpt_msg;
429 for (handle = handle_start; handle <
NUM_HANDLE; handle++) {
438 ctrlpt_callback = ctrlpt_info->
Callback;
439 ctrlpt_cookie = ctrlpt_info->
Cookie;
442 ctrlpt_callback(event_type, param, ctrlpt_cookie);
449 save_char = hdr_value.
buf[hdr_value.
length];
452 hdr_value.
buf[hdr_value.
length] = save_char;
457 !usn_found || !st_found) {
459 goto end_ssdp_handle_ctrlpt_msg;
462 for (handle = handle_start; handle <
NUM_HANDLE; handle++) {
471 ctrlpt_callback = ctrlpt_info->
Callback;
472 ctrlpt_cookie = ctrlpt_info->
Cookie;
478 while (node != NULL) {
494 size_t m = std::min(hdr_value.
length,
501 size_t m = std::min(hdr_value.
length,
514 if (threadData != NULL) {
520 memset(&job, 0,
sizeof(job));
541end_ssdp_handle_ctrlpt_msg:
551#ifdef UPNP_ENABLE_IPV6
555 struct sockaddr_storage __ss_v4;
556#ifdef UPNP_ENABLE_IPV6
557 struct sockaddr_storage __ss_v6;
559 struct sockaddr_in* destAddr4 = (
struct sockaddr_in*)&__ss_v4;
560#ifdef UPNP_ENABLE_IPV6
561 struct sockaddr_in6* destAddr6 = (
struct sockaddr_in6*)&__ss_v6;
566 int timeTillRead = 0;
569 struct in_addr addrv4;
577 !inet_pton(AF_INET,
gIF_IPV4, &addrv4)) {
581 memset(&job, 0,
sizeof(job));
586 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
"Inside SearchByTarget\n");
596#ifdef UPNP_ENABLE_IPV6
602 ReqBufv6UlaGua,
sizeof(ReqBufv6UlaGua), timeTillRead, St, AF_INET6);
607 memset(&__ss_v4, 0,
sizeof(__ss_v4));
608 destAddr4->sin_family = (sa_family_t)AF_INET;
609 inet_pton(AF_INET,
SSDP_IP, &destAddr4->sin_addr);
612#ifdef UPNP_ENABLE_IPV6
613 memset(&__ss_v6, 0,
sizeof(__ss_v6));
614 destAddr6->sin6_family = (sa_family_t)AF_INET6;
648 IP_MULTICAST_IF, (
char*)&addrv4,
653#ifdef UPNP_ENABLE_IPV6
662 ret = umock::sys_socket_h.select((
int)max_fd + 1, NULL, &wrSet, NULL, NULL);
665 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
666 "SSDP_LIB: Error in select(): %s\n", errorBuffer);
668#ifdef UPNP_ENABLE_IPV6
673#ifdef UPNP_ENABLE_IPV6
679 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
680 ">>> SSDP SEND M-SEARCH >>>\n%s\n", ReqBufv6UlaGua);
682 (SIZEP_T)strlen(ReqBufv6UlaGua), 0,
683 (
struct sockaddr*)&__ss_v6,
684 (SIZEP_T)
sizeof(
struct sockaddr_in6));
686 std::this_thread::sleep_for(std::chrono::milliseconds(
SSDP_PAUSE));
691 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
692 ">>> SSDP SEND M-SEARCH >>>\n%s\n", ReqBufv6);
694 (
struct sockaddr*)&__ss_v6,
695 (SIZEP_T)
sizeof(
struct sockaddr_in6));
697 std::this_thread::sleep_for(std::chrono::milliseconds(
SSDP_PAUSE));
705 UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
706 ">>> SSDP SEND M-SEARCH >>>\n%s\n", ReqBufv4);
708 (SIZEP_T)strlen(ReqBufv4), 0,
709 (
struct sockaddr*)&__ss_v4,
710 (SIZEP_T)
sizeof(
struct sockaddr_in));
712 std::this_thread::sleep_for(std::chrono::milliseconds(
SSDP_PAUSE));
721 SOCKET* ssdpReqSock) {
722 UPnPsdk_LOGINFO(
"MSG1071")
"Executing...\n";
726 *ssdpReqSock = umock::sys_socket_h.socket(AF_INET, SOCK_DGRAM, 0);
727 if (*ssdpReqSock == INVALID_SOCKET) {
729 UPnPsdk_LOGCRIT(
"MSG1072")
"Error in socket(): "
733 umock::sys_socket_h.setsockopt(*ssdpReqSock, IPPROTO_IP, IP_MULTICAST_TTL,
734 (
const char*)&ttl,
sizeof(ttl));
736 int ret = umock::pupnp_sock.sock_make_no_blocking(*ssdpReqSock);
737 if (ret == SOCKET_ERROR)
739 UPnPsdk_LOGCRIT(
"MSG1090")
"SSDP Request Socket "
741 <<
" failed to set \"no blocking\" but continue...\n";
747#ifdef UPNP_ENABLE_IPV6
750 SOCKET* ssdpReqSock) {
751 UPnPsdk_LOGINFO(
"MSG1073")
"Executing...\n";
755 *ssdpReqSock = umock::sys_socket_h.socket(AF_INET6, SOCK_DGRAM, 0);
756 if (*ssdpReqSock == INVALID_SOCKET) {
758 UPnPsdk_LOGCRIT(
"MSG1074")
"Error in socket(): "
765 umock::sys_socket_h.setsockopt(*ssdpReqSock, IPPROTO_IPV6,
766 IPV6_MULTICAST_HOPS, &hops,
sizeof(hops));
768 umock::pupnp_sock.sock_make_no_blocking(*ssdpReqSock);
enum Upnp_EventType_e Upnp_EventType
Old C stile quirks to make a symbol protected. Look at Upnp_EventType_e.
@ UPNP_DISCOVERY_ADVERTISEMENT_BYEBYE
@ UPNP_DISCOVERY_ADVERTISEMENT_ALIVE
@ UPNP_DISCOVERY_SEARCH_TIMEOUT
int(* Upnp_FunPtr)(Upnp_EventType EventType, const void *Event, void *Cookie)
#define UPNP_E_BUFFER_TOO_SMALL
The operation completed successfully.
int is_request
If 1, msg is a request, else response.
#define HDR_USN
Type of a HTTP header.
#define HDR_DATE
Type of a HTTP header.
#define HDR_NT
Type of a HTTP header.
#define HDR_NTS
Type of a HTTP header.
#define HDR_EXT
Type of a HTTP header.
#define HDR_SERVER
Type of a HTTP header.
#define HDR_ST
Type of a HTTP header.
#define HDR_CACHE_CONTROL
Type of a HTTP header.
#define HDR_LOCATION
Type of a HTTP header.
#define HDR_USER_AGENT
Type of a HTTP header.
Structure of an HTTP message.
void * ListDelNode(LinkedList *list, ListNode *dnode, int freeItem)
Removes a node from the list. The memory for the node is freed.
ListNode * ListNext(LinkedList *list, ListNode *node)
Returns the next item in the list.
ListNode * ListHead(LinkedList *list)
Returns the head of the list.
ListNode * ListAddTail(LinkedList *list, void *item)
Adds a node to the tail of the list. Node gets added immediately before list.tail.
Linked list node. Stores generic item and pointers to next and prev.
void SSDPResultData_Callback(const SSDPResultData *p)
SSDP result data callback function.
SSDPResultData object declararion.
int SSDPResultData_set_Cookie(SSDPResultData *p, void *n)
SSDPResultData_set_Cookie.
int SSDPResultData_set_CtrlptCallback(SSDPResultData *p, Upnp_FunPtr n)
SSDPResultData_set_CtrlptCallback.
void SSDPResultData_delete(SSDPResultData *q)
Destructor.
int SSDPResultData_set_Param(SSDPResultData *p, const UpnpDiscovery *s)
SSDPResultData_set_Param.
int ThreadPoolAdd(ThreadPool *tp, ThreadPoolJob *job, int *jobId)
Adds a job to the thread pool.
int TPJobSetFreeFunction(ThreadPoolJob *job, free_routine func)
Sets the jobs free function.
int TPJobSetPriority(ThreadPoolJob *job, ThreadPriority priority)
Sets the priority of the threadpool job.
int TPJobInit(ThreadPoolJob *job, UPnPsdk::start_routine func, void *arg)
Initializes thread pool job.
void(* free_routine)(void *arg)
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.
PUPNP_Api int UpnpDiscovery_strcpy_DeviceType(UpnpDiscovery *p, const char *s)
PUPNP_Api void UpnpDiscovery_delete(UpnpDiscovery *p)
PUPNP_Api int UpnpDiscovery_strncpy_Location(UpnpDiscovery *p, const char *s, size_t n)
PUPNP_Api UpnpDiscovery * UpnpDiscovery_new(void)
PUPNP_Api int UpnpDiscovery_strcpy_ServiceType(UpnpDiscovery *p, const char *s)
PUPNP_Api int UpnpDiscovery_set_ErrCode(UpnpDiscovery *p, int n)
PUPNP_Api int UpnpDiscovery_strcpy_DeviceID(UpnpDiscovery *p, const char *s)
PUPNP_Api int UpnpDiscovery_set_DestAddr(UpnpDiscovery *p, const struct sockaddr_storage *buf)
PUPNP_Api int UpnpDiscovery_get_Expires(const UpnpDiscovery *p)
PUPNP_Api const UpnpString * UpnpDiscovery_get_Location(const UpnpDiscovery *p)
PUPNP_Api int UpnpDiscovery_set_Expires(UpnpDiscovery *p, int n)
PUPNP_Api int UpnpDiscovery_strncpy_Ext(UpnpDiscovery *p, const char *s, size_t n)
PUPNP_Api int UpnpDiscovery_strncpy_Os(UpnpDiscovery *p, const char *s, size_t n)
PUPNP_Api int UpnpDiscovery_strcpy_Date(UpnpDiscovery *p, const char *s)
Class for portable handling of network socket errors.
void catch_error()
Catch error for later use.
std::string error_str() const
Get human readable error description of the catched error.
#define NUM_SSDP_COPY
This configuration parameter determines how many copies of each SSDP advertisement and search packets...
#define SSDP_PAUSE
This configuration parameter determines the pause between identical SSDP advertisement and search pac...
#define MAX_SEARCH_TIME
The MAX_SEARCH_TIME is the maximum time allowed for an SSDP search by a control point....
#define MIN_SEARCH_TIME
The MIN_SEARCH_TIME is the minimumm time allowed for an SSDP search by a control point....
"protected" structure, addressable with typedef
int ssdp_request_type(char *cmd, SsdpEvent *Evt)
Starts filling the SSDP event structure based upon the request received.
SsdpSearchType ssdp_request_type1(char *cmd)
This function figures out the type of the SSDP search in the request.
SSDPResultData * SSDPResultData_new()
Constructor.
int unique_service_name(char *cmd, SsdpEvent *Evt)
Fills the fields of the event structure like DeviceType, Device UDN and Service Type.
void ssdp_handle_ctrlpt_msg(http_message_t *hmsg, struct sockaddr_storage *dest_addr, int timeout)
This function handles the ssdp messages from the devices.
PUPNP_Api size_t UpnpString_get_Length(const UpnpString *p)
Returns the length of the string.
http_header_t * httpmsg_find_hdr(http_message_t *msg, int header_name_id, memptr *value)
Finds header from a list, with the given 'name_id'.
parse_status_t matchstr(char *str, size_t slen, const char *fmt,...)
Matches a variable parameter list with a string and takes actions based on the data type specified.
int memptr_cmp(memptr *m, const char *s)
Compares characters of strings passed for number of bytes. If equal for the number of bytes,...
size_t length
length of memory (read-only).
char * buf
start of memory (read/write).
pointer to a chunk of memory.
#define UPNP_E_INVALID_ARGUMENT
One or more of the parameters passed to a function is invalid.
#define UPNP_E_SUCCESS
The operation completed successfully.
#define UPNP_E_OUTOF_SOCKET
The SDK cannot create any more sockets.
#define UPNP_E_INVALID_PARAM
One or more of the parameters passed to the function is not valid.
#define UPNP_E_INTERNAL_ERROR
Generic error code for internal conditions not covered by other error codes.
int CreateClientRequestPacketUlaGua(char *RqstBuf, size_t RqstBufSize, int Mx, char *SearchTarget, int AddressFamily)
Creates a HTTP search request packet for IPv6 UlaGua depending on the input parameter.
int CreateClientRequestPacket(char *RqstBuf, size_t RqstBufSize, int Mx, char *SearchTarget, int AddressFamily)
Creates a HTTP search request packet depending on the input parameter.
void send_search_result(void *data)
Sends a callback to the control point application with a SEARCH result.
void searchExpired(void *arg)
Remove search Target from list and call client back.
#define SSDP_PORT
constant
#define COMMAND_LEN
constant
char UDN[LINE_SIZE]
Part of SSDP Event.
constexpr size_t ERROR_BUFFER_LEN
Size of the errorBuffer variable, passed to the strerror_r() function.
#define SSDP_IPV6_SITELOCAL
constant
char ServiceType[LINE_SIZE]
Part of SSDP Event.
int timeoutEventId
timeout event id
#define SSDP_IPV6_LINKLOCAL
constant
char DeviceType[LINE_SIZE]
Part of SSDP Event.
SOCKET gSsdpReqSocket6
If control point API is compiled in, this is the global IPv6 socket for it.
SOCKET gSsdpReqSocket4
If control point API is compiled in, this is the global IPv4 socket for it.
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.
SSDP search exp argument.
int SearchByTarget(int Hnd, int Mx, char *St, void *Cookie)
Creates and send the search request for a specific URL.
int create_ssdp_sock_reqv6(SOCKET *ssdpReqSock)
Creates the SSDP IPv6 socket to be used by the control point.
int create_ssdp_sock_reqv4(SOCKET *ssdpReqSock)
Creates the SSDP IPv4 socket to be used by the control point.
Manage "Step 1: Discovery" of the UPnP+™ specification for Control Points with SSDP.
int timeoutEventId
part of search argument
enum SsdpSearchType requestType
part of search argument
void * cookie
part of search argument
char * searchTarget
part of search argument
Upnp_Handle_Type GetHandleInfo(UpnpClient_Handle Hnd, Handle_Info **HndInfo)
Get handle information.
ThreadPool gRecvThreadPool
Receive thread pool.
char gIF_IPV4[INET_ADDRSTRLEN]
Static buffer to contain interface IPv4 address. (extern'ed in upnp.h)
TimerThread gTimerThread
Global timer thread.
unsigned gIF_INDEX
Contains network interface index of the link local address gIF_IPV6 that is used as its scope_id.
Upnp_Handle_Type GetClientHandleInfo(UpnpClient_Handle *client_handle_out, struct Handle_Info **HndInfo)
Get client handle info.
Inititalize the compatible library before it can be used.
#define HandleLock()
HandleLock.
#define HandleUnlock()
HandleUnlock.
Upnp_FunPtr Callback
Callback function pointer.
constexpr int NUM_HANDLE
Maximal number of available UPnP Unit handles.
LinkedList SsdpSearchList
Active SSDP searches.
#define HandleReadLock()
HandleReadLock.
Data to be stored in handle table for Handle Info.
UPnPsdk_VIS void UpnpPrintf(Upnp_LogLevel DLevel, Dbg_Module Module, const char *DbgFileName, int DbgLineNo, const char *FmtStr,...)
Prints the debug statement.