diff --git a/ChangeLog b/ChangeLog index cc96bf4..b374f32 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,9 @@ Version 1.8.0 ******************************************************************************* +2008-05-02 Marcelo Jimenez + * Merged Charles Nepveu's IPv6 work. libupnp now is IPv6 enabled. + 2008-02-06 Marcelo Jimenez * Breaking API so that we now hide internal data structures. diff --git a/TODO b/TODO index 00c2dee..aa9181e 100644 --- a/TODO +++ b/TODO @@ -18,6 +18,10 @@ http://sourceforge.net/tracker/?group_id=7189&atid=307189 - make API clean for large files and 64 bits +- Why is NUM_HANDLE defined to 200 when we can register only: + A) One client(1) + B) An IPv4 and IPv6 device (2) + NUM_HANDLE should be 3 To Be Decided ============= diff --git a/build/vc8/libupnp.vcproj b/build/vc8/libupnp.vcproj index df0ddd1..f0768cc 100644 --- a/build/vc8/libupnp.vcproj +++ b/build/vc8/libupnp.vcproj @@ -4,6 +4,7 @@ Version="8.00" Name="libupnp" ProjectGUID="{6227F51A-1498-4C4A-B213-F6FDED605125}" + RootNamespace="libupnp" > + + diff --git a/configure.ac b/configure.ac index 125af4e..9986ab4 100644 --- a/configure.ac +++ b/configure.ac @@ -149,7 +149,7 @@ dnl # "current:revision:age" dnl # dnl # - Code has changed in upnp dnl # revision: 5 -> 6 -dnl # - Interface has changed in upnp +dnl # - Interfaces have been changed, added and removed in upnp dnl # current: 3 -> 4 dnl # revision: 6 -> 0 dnl # - Interface has been removed in upnp diff --git a/upnp/inc/ActionRequest.h b/upnp/inc/ActionRequest.h index 12b7082..51f34e8 100644 --- a/upnp/inc/ActionRequest.h +++ b/upnp/inc/ActionRequest.h @@ -69,8 +69,8 @@ IXML_Document *UpnpActionRequest_get_ActionResult(const UpnpActionRequest *p); void UpnpActionRequest_set_ActionResult(UpnpActionRequest *p, IXML_Document *d); /** IP address of the control point requesting this action */ -struct in_addr *UpnpActionRequest_get_CtrlPtIPAddr(const UpnpActionRequest *p); -void UpnpActionRequest_set_CtrlPtIPAddr(UpnpActionRequest *p, struct in_addr *ia); +struct sockaddr_storage *UpnpActionRequest_get_CtrlPtIPAddr(const UpnpActionRequest *p); +void UpnpActionRequest_set_CtrlPtIPAddr(UpnpActionRequest *p, struct sockaddr_storage *ia); /** The DOM document containing the information from the SOAP header */ IXML_Document *UpnpActionRequest_get_SoapHeader(const UpnpActionRequest *p); diff --git a/upnp/inc/Discovery.h b/upnp/inc/Discovery.h index fd0f430..4ac5667 100644 --- a/upnp/inc/Discovery.h +++ b/upnp/inc/Discovery.h @@ -83,8 +83,8 @@ void UpnpDiscovery_strcpy_Ext(UpnpDiscovery *p, const char *s); void UpnpDiscovery_strncpy_Ext(UpnpDiscovery *p, const char *s, int n); /** The host address of the device responding to the search. */ -struct sockaddr_in *UpnpDiscovery_get_DestAddr(const UpnpDiscovery *p); -void UpnpDiscovery_set_DestAddr(UpnpDiscovery *p, struct sockaddr_in *sa); +struct sockaddr *UpnpDiscovery_get_DestAddr(const UpnpDiscovery *p); +void UpnpDiscovery_set_DestAddr(UpnpDiscovery *p, struct sockaddr *sa); #ifdef __cplusplus diff --git a/upnp/inc/StateVarRequest.h b/upnp/inc/StateVarRequest.h index dd1224f..2819de1 100644 --- a/upnp/inc/StateVarRequest.h +++ b/upnp/inc/StateVarRequest.h @@ -62,8 +62,8 @@ void UpnpStateVarRequest_set_StateVarName(UpnpStateVarRequest *p, const UpnpStri void UpnpStateVarRequest_strcpy_StateVarName(UpnpStateVarRequest *p, const char *s); /** IP address of sender requesting the state variable. */ -struct in_addr *UpnpStateVarRequest_get_CtrlPtIPAddr(const UpnpStateVarRequest *p); -void UpnpStateVarRequest_set_CtrlPtIPAddr(UpnpStateVarRequest *p, struct in_addr *ia); +struct sockaddr_storage *UpnpStateVarRequest_get_CtrlPtIPAddr(const UpnpStateVarRequest *p); +void UpnpStateVarRequest_set_CtrlPtIPAddr(UpnpStateVarRequest *p, struct sockaddr_storage *ia); /** The current value of the variable. This needs to be allocated by * the caller. When finished with it, the SDK frees this {\bf DOMString}. */ diff --git a/upnp/inc/upnp.h b/upnp/inc/upnp.h index d30c1fd..750e816 100644 --- a/upnp/inc/upnp.h +++ b/upnp/inc/upnp.h @@ -106,13 +106,15 @@ #endif #ifndef WIN32 #define SOCKET int + #define INVALID_SOCKET (SOCKET)(~0) #endif #ifndef WIN32 #include #else - #include + #include + #include #include #endif @@ -296,6 +298,15 @@ #define UPNP_E_ALREADY_REGISTERED -120 /*! @} */ +/** @name UPNP_E_INVALID_INTERFACE [-121] + * {\tt UPNP_E_INVALID_INTERFACE} signifies that the interface provided to + * {\bf UpnpInit2} is unknown or does not have a valid IPv4 or IPv6 + * address configured. + */ +/*! @{ */ +#define UPNP_E_INVALID_INTERFACE -121 +/*! @} */ + /** @name UPNP_E_NETWORK_ERROR [-200] * {\tt UPNP_E_NETWORK_ERROR} signifies that a network error occurred. It * is the generic error code for network problems that are not covered under @@ -930,6 +941,51 @@ EXPORT_SPEC int UpnpInit( will pick an arbitrary free port. */ ); + +/*! @name Initialization and Registration */ +/*! @{ */ +/** Initializes the Linux SDK for UPnP Devices. This function must be called + * before any other API function can be called. It should be called + * only once. Subsequent calls to this API return a {\tt UPNP_E_INIT} + * error code. + * + * Optionally, the application can specify an interface name (in the + * case of a multi-homed configuration) and a port number to use for + * all UPnP operations. Since a port number can be used only by one + * process, multiple processes using the SDK must specify + * different port numbers. + * + * If unspecified, the SDK will use the first suitable interface and an + * arbitrary port. + * + * This call is synchronous. + * + * @return [int] An integer representing one of the following: + * \begin{itemize} + * \item {\tt UPNP_E_SUCCESS}: The operation completed successfully. + * \item {\tt UPNP_E_OUTOF_MEMORY}: Insufficient resources exist + * to initialize the SDK. + * \item {\tt UPNP_E_INIT}: The SDK is already initialized. + * \item {\tt UPNP_E_INIT_FAILED}: The SDK initialization + * failed for an unknown reason. + * \item {\tt UPNP_E_SOCKET_BIND}: An error occurred binding a socket. + * \item {\tt UPNP_E_LISTEN}: An error occurred listening to a socket. + * \item {\tt UPNP_E_OUTOF_SOCKET}: An error ocurred creating a socket. + * \item {\tt UPNP_E_INTERNAL_ERROR}: An internal error ocurred. + * \item {\tt UPNP_E_INVALID_INTERFACE}: IfName is invalid or doees not + * have a valid IPv4 or IPv6 addresss configured. + * \end{itemize} */ + +EXPORT_SPEC int UpnpInit2( + IN const char *IfName, /** The interface name to use by the UPnP SDK + operations. Examples: "eth0", "xl0", + "Local Area Connection", {\tt NULL} to + use the first suitable interface. */ + IN unsigned short DestPort /** The destination port number to use. 0 + will pick an arbitrary free port. */ + ); + + /** Terminates the Linux SDK for UPnP Devices. This function must be the last * API function called. It should be called only once. Subsequent calls to * this API return a {\tt UPNP_E_FINISH} error code. @@ -949,20 +1005,40 @@ EXPORT_SPEC int UpnpFinish(); * returned. * * @return [unsigned short] The port on which an internal server is - * listening for UPnP related requests. + * listening for IPv4 UPnP related requests. */ EXPORT_SPEC unsigned short UpnpGetServerPort(void); -/** If {\tt NULL} is used as the IP address in {\bf UpnpInit}, then this +/** If '0' is used as the port number in {\bf UpnpInit}, then this + * function can be used to retrieve the actual port allocated to + * the SDK. If {\bf UpnpInit} has not succeeded then 0 is + * returned. + * + * @return [unsigned short] The port on which an internal server is + * listening for IPv6 UPnP related requests. + */ +EXPORT_SPEC unsigned short UpnpGetServerPort6(void); + +/** If {\tt NULL} is used as the IPv4 address in {\bf UpnpInit}, then this * function can be used to retrieve the actual interface address * on which device is running. If {\bf UpnpInit} has not succeeded * then {\tt NULL} is returned. * - * @return [char*] The IP address on which an internal server is listening + * @return [char*] The IPv4 address on which an internal server is listening * for UPnP related requests. */ EXPORT_SPEC char * UpnpGetServerIpAddress(void); +/** If {\tt NULL} is used as the IPv6 address in {\bf UpnpInit}, then this + * function can be used to retrieve the actual interface address + * on which device is running. If {\bf UpnpInit} has not succeeded + * then {\tt NULL} is returned. + * + * @return [char*] The IPv6 address on which an internal server is listening + * for UPnP related requests. + */ +EXPORT_SPEC char * UpnpGetServerIp6Address(void); + /** {\bf UpnpRegisterClient} registers a control point application with the * SDK. A control point application cannot make any other API calls * until it registers using this function. @@ -1129,6 +1205,58 @@ EXPORT_SPEC int UpnpRegisterRootDevice2( the new device handle. */ ); + +/** {\bf UpnpRegisterRootDevice3} registers a device application for a + * specific address family with the SDK. A device application cannot + * make any other API calls until it registers using this function. + * Device applications can also register as control points (see + * {\bf UpnpRegisterClient} to get a control point handle to perform + * control point functionality). + * + * {\bf UpnpRegisterRootDevice} is synchronous and does not generate + * any callbacks. Callbacks can occur as soon as this function returns. + * + * @return [int] An integer representing one of the following: + * \begin{itemize} + * \item {\tt UPNP_E_SUCCESS}: The operation completed successfully. + * \item {\tt UPNP_E_FINISH}: The SDK is already terminated or + * is not initialized. + * \item {\tt UPNP_E_INVALID_DESC}: The description document was not + * a valid device description. + * \item {\tt UPNP_E_INVALID_URL}: The URL for the description document + * is not valid. + * \item {\tt UPNP_E_INVALID_PARAM}: Either {\bf Callback} or {\bf Hnd} + * is not a valid pointer or {\bf DescURL} is {\tt NULL}. + * \item {\tt UPNP_E_NETWORK_ERROR}: A network error occurred. + * \item {\tt UPNP_E_SOCKET_WRITE}: An error or timeout occurred writing + * to a socket. + * \item {\tt UPNP_E_SOCKET_READ}: An error or timeout occurred reading + * from a socket. + * \item {\tt UPNP_E_SOCKET_BIND}: An error occurred binding a socket. + * \item {\tt UPNP_E_SOCKET_CONNECT}: An error occurred connecting the + * socket. + * \item {\tt UPNP_E_OUTOF_SOCKET}: Too many sockets are currently + * allocated. + * \item {\tt UPNP_E_OUTOF_MEMORY}: There are insufficient resources to + * register this root device. + * \end{itemize} */ + +EXPORT_SPEC int UpnpRegisterRootDevice3( + IN const char *DescUrl, /** Pointer to a string containing the + description URL for this root device + instance. */ + IN Upnp_FunPtr Callback, /** Pointer to the callback function for + receiving asynchronous events. */ + IN const void *Cookie, /** Pointer to user data returned with the + callback function when invoked. */ + OUT UpnpDevice_Handle *Hnd,/** Pointer to a variable to store the + new device handle. */ + IN const int AddressFamily /** Address family of this device. Can be + AF_INET for an IPv4 device, or AF_INET6 + for an IPv6 device. Defaults to AF_INET. */ + ); + + /** {\bf UpnpUnRegisterClient} unregisters a control point application, * unsubscribing all active subscriptions. After this call, the * {\bf UpnpClient_Handle} is no longer valid. diff --git a/upnp/src/api/ActionRequest.c b/upnp/src/api/ActionRequest.c index 8c59ab7..84086be 100644 --- a/upnp/src/api/ActionRequest.c +++ b/upnp/src/api/ActionRequest.c @@ -21,7 +21,7 @@ struct SUpnpActionRequest IXML_Document *m_actionRequest; IXML_Document *m_actionResult; IXML_Document *m_soapHeader; - struct in_addr m_ctrlPtIPAddr; + struct sockaddr_storage m_ctrlPtIPAddr; }; @@ -41,7 +41,7 @@ UpnpActionRequest *UpnpActionRequest_new() p->m_actionRequest = NULL; p->m_actionResult = NULL; p->m_soapHeader = NULL; - memset(&p->m_ctrlPtIPAddr, 0, sizeof (struct in_addr)); + memset(&p->m_ctrlPtIPAddr, 0, sizeof (struct sockaddr_storage)); #endif return (UpnpActionRequest *)p; } @@ -73,7 +73,7 @@ void UpnpActionRequest_delete(UpnpActionRequest *p) UpnpActionRequest_set_SoapHeader(p, NULL); - memset(&q->m_ctrlPtIPAddr, 0, sizeof (struct in_addr)); + memset(&q->m_ctrlPtIPAddr, 0, sizeof (struct sockaddr_storage)); free(p); } @@ -224,13 +224,13 @@ void UpnpActionRequest_set_ActionResult(UpnpActionRequest *p, IXML_Document *d) } -struct in_addr *UpnpActionRequest_get_CtrlPtIPAddr(const UpnpActionRequest *p) +struct sockaddr_storage *UpnpActionRequest_get_CtrlPtIPAddr(const UpnpActionRequest *p) { return &((struct SUpnpActionRequest *)p)->m_ctrlPtIPAddr; } -void UpnpActionRequest_set_CtrlPtIPAddr(UpnpActionRequest *p, struct in_addr *ia) +void UpnpActionRequest_set_CtrlPtIPAddr(UpnpActionRequest *p, struct sockaddr_storage *ia) { ((struct SUpnpActionRequest *)p)->m_ctrlPtIPAddr = *ia; } diff --git a/upnp/src/api/Discovery.c b/upnp/src/api/Discovery.c index e059f53..b6d246f 100644 --- a/upnp/src/api/Discovery.c +++ b/upnp/src/api/Discovery.c @@ -22,7 +22,7 @@ struct SUpnpDiscovery UpnpString *m_os; UpnpString *m_date; UpnpString *m_ext; - struct sockaddr_in m_destAddr; + struct sockaddr m_destAddr; }; @@ -332,13 +332,13 @@ void UpnpDiscovery_strncpy_Ext(UpnpDiscovery *p, const char *s, int n) } -struct sockaddr_in *UpnpDiscovery_get_DestAddr(const UpnpDiscovery *p) +struct sockaddr *UpnpDiscovery_get_DestAddr(const UpnpDiscovery *p) { return &((struct SUpnpDiscovery *)p)->m_destAddr; } -void UpnpDiscovery_set_DestAddr(UpnpDiscovery *p, struct sockaddr_in *sa) +void UpnpDiscovery_set_DestAddr(UpnpDiscovery *p, struct sockaddr *sa) { ((struct SUpnpDiscovery *)p)->m_destAddr = *sa; } diff --git a/upnp/src/api/StateVarRequest.c b/upnp/src/api/StateVarRequest.c index 1dffc65..d3253d3 100644 --- a/upnp/src/api/StateVarRequest.c +++ b/upnp/src/api/StateVarRequest.c @@ -18,7 +18,7 @@ struct SUpnpStateVarRequest UpnpString *m_devUDN; UpnpString *m_serviceID; UpnpString *m_stateVarName; - struct in_addr m_ctrlPtIPAddr; + struct sockaddr_storage m_ctrlPtIPAddr; DOMString m_currentVal; }; @@ -36,7 +36,7 @@ UpnpStateVarRequest *UpnpStateVarRequest_new() p->m_serviceID = UpnpString_new(); p->m_stateVarName = UpnpString_new(); #if 0 - memset(&q->m_ctrlPtIPAddr, 0, sizeof (struct in_addr)); + memset(&q->m_ctrlPtIPAddr, 0, sizeof (struct sockaddr_storage)); p->m_currentVal = NULL; #endif @@ -64,7 +64,7 @@ void UpnpStateVarRequest_delete(UpnpStateVarRequest *p) UpnpString_delete(q->m_stateVarName); q->m_stateVarName = NULL; - memset(&q->m_ctrlPtIPAddr, 0, sizeof (struct in_addr)); + memset(&q->m_ctrlPtIPAddr, 0, sizeof (struct sockaddr_storage)); ixmlFreeDOMString(q->m_currentVal); q->m_currentVal = NULL; @@ -190,13 +190,13 @@ void UpnpStateVarRequest_strcpy_StateVarName(UpnpStateVarRequest *p, const char } -struct in_addr *UpnpStateVarRequest_get_CtrlPtIPAddr(const UpnpStateVarRequest *p) +struct sockaddr_storage *UpnpStateVarRequest_get_CtrlPtIPAddr(const UpnpStateVarRequest *p) { return &((struct SUpnpStateVarRequest *)p)->m_ctrlPtIPAddr; } -void UpnpStateVarRequest_set_CtrlPtIPAddr(UpnpStateVarRequest *p, struct in_addr *ia) +void UpnpStateVarRequest_set_CtrlPtIPAddr(UpnpStateVarRequest *p, struct sockaddr_storage *ia) { ((struct SUpnpStateVarRequest *)p)->m_ctrlPtIPAddr = *ia; } diff --git a/upnp/src/api/upnpapi.c b/upnp/src/api/upnpapi.c index 3b41011..a95d670 100644 --- a/upnp/src/api/upnpapi.c +++ b/upnp/src/api/upnpapi.c @@ -71,6 +71,8 @@ #include "ssdplib.h" #include "soaplib.h" #include "ThreadPool.h" +#include "sysdep.h" +#include "uuid.h" // Needed for GENA @@ -97,6 +99,8 @@ CLIENTONLY( ithread_mutex_t GlobalClientSubscribeMutex; ) // Mutex to synchronize the uuid creation process ithread_mutex_t gUUIDMutex; + ithread_mutex_t gSDKInitMutex = PTHREAD_MUTEX_INITIALIZER; + TimerThread gTimerThread; ThreadPool gSendThreadPool; @@ -106,11 +110,21 @@ CLIENTONLY( ithread_mutex_t GlobalClientSubscribeMutex; ) //Flag to indicate the state of web server WebServerState bWebServerState = WEB_SERVER_DISABLED; -// static buffer to store the local host ip address or host name - char LOCAL_HOST[LINE_SIZE]; +// Static buffer to contain interface name. (extern'ed in upnp.h) + char gIF_NAME[LINE_SIZE] = { '\0' }; -// local port for the mini-server - unsigned short LOCAL_PORT; +// Static buffer to contain interface IPv4 address. (extern'ed in upnp.h) + char gIF_IPV4[22]/* INET_ADDRSTRLEN*/ = { '\0' }; + +// Static buffer to contain interface IPv6 address. (extern'ed in upnp.h) + char gIF_IPV6[65]/* INET6_ADDRSTRLEN*/ = { '\0' }; + +// Contains interface index. (extern'ed in upnp.h) + int gIF_INDEX = -1; + +// local IPv4 and IPv6 ports for the mini-server + unsigned short LOCAL_PORT_V4; + unsigned short LOCAL_PORT_V6; // UPnP device and control point handle table void *HandleTable[NUM_HANDLE]; @@ -130,202 +144,169 @@ size_t g_maxContentLength = DEFAULT_SOAP_CONTENT_LENGTH; // in bytes // = 0 if uninitialized, = 1 if initialized. int UpnpSdkInit = 0; -// Global variable to denote the state of Upnp SDK device registration. -// = 0 if unregistered, = 1 if registered. - int UpnpSdkDeviceRegistered = 0; - // Global variable to denote the state of Upnp SDK client registration. // = 0 if unregistered, = 1 if registered. int UpnpSdkClientRegistered = 0; +// Global variable to denote the state of Upnp SDK IPv4 device registration. +// = 0 if unregistered, = 1 if registered. + int UpnpSdkDeviceRegisteredV4 = 0; + +// Global variable to denote the state of Upnp SDK IPv6 device registration. +// = 0 if unregistered, = 1 if registered. + int UpnpSdkDeviceregisteredV6 = 0; + +// Global variable used in discovery notifications. + Upnp_SID gUpnpSdkNLSuuid; + + +/**************************************************************************** + * Function: UpnpInit2 + * + * Parameters: + * IN const char * IfName: Name of local interface. + * IN short DestPort: Local Port to listen for incoming connections. + * + * Description: + * - Initializes the UPnP SDK. + * - Checks IfName interface. If NULL, we find a suitable interface for + * operation. + * + * Returns: + * UPNP_E_SUCCESS on success, nonzero on failure. + * UPNP_E_INIT_FAILED if Initialization fails. + * UPNP_E_INIT if UPnP is already initialized. + * UPNP_E_INVALID_INTERFACE if interface provided is not configured with at + * least one valid IP address. + *****************************************************************************/ +int UpnpInit2( IN const char *IfName, + IN unsigned short DestPort ) +{ + int retVal; + + ithread_mutex_lock( &gSDKInitMutex ); + + // Check if we're already initialized. + if( UpnpSdkInit == 1 ) { + ithread_mutex_unlock( &gSDKInitMutex ); + return UPNP_E_INIT; + } + + // Perform initialization preamble. + retVal = UpnpInitPreamble(); + if( retVal != UPNP_E_SUCCESS ) { + ithread_mutex_unlock( &gSDKInitMutex ); + return retVal; + } + + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "UpnpInit2 with IfName=%s, DestPort=%d.\n", + IfName ? IfName : "", DestPort ); + + // Retrieve interface information (Addresses, index, etc). + retVal = UpnpGetIfInfo( IfName ); + if( retVal != UPNP_E_SUCCESS ) { + ithread_mutex_unlock( &gSDKInitMutex ); + return retVal; + } + + // Set the UpnpSdkInit flag to 1 to indicate we're sucessfully initialized. + UpnpSdkInit = 1; + + // Finish initializing the SDK. + retVal = UpnpInitStartServers( DestPort ); + if( retVal != UPNP_E_SUCCESS ) { + UpnpSdkInit = 0; + ithread_mutex_unlock( &gSDKInitMutex ); + return retVal; + } + + ithread_mutex_unlock( &gSDKInitMutex ); + + return UPNP_E_SUCCESS; +} + + /**************************************************************************** * Function: UpnpInit * * Parameters: * IN const char * HostIP: Local IP Address - * IN short DestPort: Local Port to listen for incoming connections + * IN short DestPort: Local Port to listen for incoming connections. + * * Description: - * Initializes - * - Mutex objects, - * - Handle Table - * - Thread Pool and Thread Pool Attributes - * - MiniServer(starts listening for incoming requests) - * and WebServer (Sends request to the - * Upper Layer after HTTP Parsing) - * - Checks for IP Address passed as an argument. IF NULL, - * gets local host name - * - Sets GENA and SOAP Callbacks. - * - Starts the timer thread. + * ** DEPRECATED: Kept for backwards compatibility. ** + * Use UpnpInit2 for new implementations. + * - Initializes the UPnP SDK. + * - Checks HostIP address. If NULL, we find a suitable IP for operation. * * Returns: * UPNP_E_SUCCESS on success, nonzero on failure. * UPNP_E_INIT_FAILED if Initialization fails. - * UPNP_E_INIT if UPnP is already initialized + * UPNP_E_INIT if UPnP is already initialized. *****************************************************************************/ int UpnpInit( IN const char *HostIP, IN unsigned short DestPort ) { - int retVal = 0; - ThreadPoolAttr attr; -#ifdef WIN32 - WORD wVersionRequested; - WSADATA wsaData; - int err; -#endif + int retVal; + ithread_mutex_lock( &gSDKInitMutex ); + + // Check if we're already initialized. if( UpnpSdkInit == 1 ) { - // already initialized + ithread_mutex_unlock( &gSDKInitMutex ); return UPNP_E_INIT; } -#ifdef WIN32 - wVersionRequested = MAKEWORD( 2, 2 ); - - err = WSAStartup( wVersionRequested, &wsaData ); - if ( err != 0 ) { - /* Tell the user that we could not find a usable */ - /* WinSock DLL. */ - return UPNP_E_INIT_FAILED; - } - - /* Confirm that the WinSock DLL supports 2.2.*/ - /* Note that if the DLL supports versions greater */ - /* than 2.2 in addition to 2.2, it will still return */ - /* 2.2 in wVersion since that is the version we */ - /* requested. */ - - if ( LOBYTE( wsaData.wVersion ) != 2 || - HIBYTE( wsaData.wVersion ) != 2 ) { - /* Tell the user that we could not find a usable */ - /* WinSock DLL. */ - WSACleanup( ); - return UPNP_E_INIT_FAILED; - } - - /* The WinSock DLL is acceptable. Proceed. */ -#endif - - membuffer_init( &gDocumentRootDir ); - - srand( time( NULL ) ); // needed by SSDP or other parts - - if( UpnpInitLog() != UPNP_E_SUCCESS ) { - return UPNP_E_INIT_FAILED; + // Perform initialization preamble. + retVal = UpnpInitPreamble(); + if( retVal != UPNP_E_SUCCESS ) { + ithread_mutex_unlock( &gSDKInitMutex ); + return retVal; } - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpInit\n" ); - // initialize mutex -#ifdef __CYGWIN__ - /* On Cygwin, pthread_mutex_init() fails without this memset. */ - /* TODO: Fix Cygwin so we don't need this memset(). */ - memset(&GlobalHndRWLock, 0, sizeof(GlobalHndRWLock)); -#endif - if (ithread_rwlock_init(&GlobalHndRWLock, NULL) != 0) { - return UPNP_E_INIT_FAILED; - } + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "UpnpInit with HostIP=%s, DestPort=%d.\n", + HostIP ? HostIP : "", DestPort ); - if (ithread_mutex_init(&gUUIDMutex, NULL) != 0) { - return UPNP_E_INIT_FAILED; - } - // initialize subscribe mutex -#ifdef INCLUDE_CLIENT_APIS - if (ithread_mutex_init(&GlobalClientSubscribeMutex, NULL) != 0) { - return UPNP_E_INIT_FAILED; - } -#endif - - HandleLock(); + // Verify HostIP, if provided, or find it ourselves. if( HostIP != NULL ) { - strcpy( LOCAL_HOST, HostIP ); + strncpy( gIF_IPV4, HostIP, sizeof(gIF_IPV4) ); } else { - if( getlocalhostname( LOCAL_HOST ) != UPNP_E_SUCCESS ) { - HandleUnlock(); + if( getlocalhostname( gIF_IPV4, sizeof(gIF_IPV4) ) != UPNP_E_SUCCESS ) { return UPNP_E_INIT_FAILED; } } - if( UpnpSdkInit != 0 ) { - HandleUnlock(); - return UPNP_E_INIT; - } - - InitHandleList(); - HandleUnlock(); - - TPAttrInit( &attr ); - TPAttrSetMaxThreads( &attr, MAX_THREADS ); - TPAttrSetMinThreads( &attr, MIN_THREADS ); - TPAttrSetJobsPerThread( &attr, JOBS_PER_THREAD ); - TPAttrSetIdleTime( &attr, THREAD_IDLE_TIME ); - TPAttrSetMaxJobsTotal( &attr, MAX_JOBS_TOTAL ); - - if( ThreadPoolInit( &gSendThreadPool, &attr ) != UPNP_E_SUCCESS ) { - UpnpSdkInit = 0; - UpnpFinish(); - return UPNP_E_INIT_FAILED; - } - - if( ThreadPoolInit( &gRecvThreadPool, &attr ) != UPNP_E_SUCCESS ) { - UpnpSdkInit = 0; - UpnpFinish(); - return UPNP_E_INIT_FAILED; - } - - if( ThreadPoolInit( &gMiniServerThreadPool, &attr ) != UPNP_E_SUCCESS ) { - UpnpSdkInit = 0; - UpnpFinish(); - return UPNP_E_INIT_FAILED; - } - + // Set the UpnpSdkInit flag to 1 to indicate we're sucessfully initialized. UpnpSdkInit = 1; -#if EXCLUDE_SOAP == 0 - SetSoapCallback( soap_device_callback ); -#endif -#if EXCLUDE_GENA == 0 - SetGenaCallback( genaCallback ); -#endif - if( ( retVal = TimerThreadInit( &gTimerThread, - &gSendThreadPool ) ) != - UPNP_E_SUCCESS ) { + // Finish initializing the SDK. + retVal = UpnpInitStartServers( DestPort ); + if( retVal != UPNP_E_SUCCESS ) { UpnpSdkInit = 0; - UpnpFinish(); + ithread_mutex_unlock( &gSDKInitMutex ); return retVal; } -#if EXCLUDE_MINISERVER == 0 - if( ( retVal = StartMiniServer( DestPort ) ) <= 0 ) { - UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, - "Miniserver failed to start" ); - UpnpFinish(); - UpnpSdkInit = 0; - if( retVal != -1 ) - return retVal; - else // if miniserver is already running for unknown reasons! - return UPNP_E_INIT_FAILED; - } -#endif - DestPort = retVal; - LOCAL_PORT = DestPort; - -#if EXCLUDE_WEB_SERVER == 0 - if( ( retVal = - UpnpEnableWebserver( WEB_SERVER_ENABLED ) ) != UPNP_E_SUCCESS ) { - UpnpFinish(); - UpnpSdkInit = 0; - return retVal; - } -#endif UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, - "Host Ip: %s Host Port: %d\n", LOCAL_HOST, - LOCAL_PORT ); + "Host Ip: %s Host Port: %d\n", gIF_IPV4, + LOCAL_PORT_V4 ); - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Exiting UpnpInit\n" ); + ithread_mutex_unlock( &gSDKInitMutex ); return UPNP_E_SUCCESS; +} -} /***************** end of UpnpInit ******************/ - +/**************************************************************************** + * Function: PrintThreadPoolStats + * + * Parameters: + * + * Description: + * + * Return Values: (none) + *****************************************************************************/ #ifdef DEBUG static void PrintThreadPoolStats( @@ -425,7 +406,9 @@ UpnpFinish() PrintThreadPoolStats(&gMiniServerThreadPool, __FILE__, __LINE__, "MiniServer Thread Pool"); #ifdef INCLUDE_DEVICE_APIS - if( GetDeviceHandleInfo( &device_handle, &temp ) == HND_DEVICE ) + if( GetDeviceHandleInfo( AF_INET, &device_handle, &temp ) == HND_DEVICE ) + UpnpUnRegisterRootDevice( device_handle ); + if( GetDeviceHandleInfo( AF_INET6, &device_handle, &temp ) == HND_DEVICE ) UpnpUnRegisterRootDevice( device_handle ); #endif @@ -481,7 +464,7 @@ UpnpFinish() * Parameters: NONE * * Description: - * Gives back the miniserver port. + * Gives back the IPv4 listening miniserver port. * * Return Values: * local port on success, zero on failure. @@ -493,7 +476,28 @@ UpnpGetServerPort( void ) if( UpnpSdkInit != 1 ) return 0; - return LOCAL_PORT; + return LOCAL_PORT_V4; +} + +/****************************************************************************** + * Function: UpnpGetServerPort6 + * + * Parameters: NONE + * + * Description: + * Gives back the IPv6 listening miniserver port. + * + * Return Values: + * local port on success, zero on failure. + *****************************************************************************/ +unsigned short +UpnpGetServerPort6( void ) +{ + + if( UpnpSdkInit != 1 ) + return 0; + + return LOCAL_PORT_V6; } /*************************************************************************** @@ -502,10 +506,10 @@ UpnpGetServerPort( void ) * Parameters: NONE * * Description: - * Gives back the local ipaddress. + * Gives back the local IPv4 ipaddress. * * Return Values: char * - * return the IP address string on success else NULL of failure + * return the IPv4 address string on success else NULL of failure ***************************************************************************/ char * UpnpGetServerIpAddress( void ) @@ -514,7 +518,28 @@ UpnpGetServerIpAddress( void ) if( UpnpSdkInit != 1 ) return NULL; - return LOCAL_HOST; + return gIF_IPV4; +} + +/*************************************************************************** + * Function: UpnpGetServerIp6Address + * + * Parameters: NONE + * + * Description: + * Gives back the local IPv6 ipaddress. + * + * Return Values: char * + * return the IPv6 address string on success else NULL of failure + ***************************************************************************/ +char * +UpnpGetServerIp6Address( void ) +{ + + if( UpnpSdkInit != 1 ) + return NULL; + + return gIF_IPV6; } #ifdef INCLUDE_DEVICE_APIS @@ -619,19 +644,19 @@ UpnpRegisterRootDevice( IN const char *DescUrl, UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpRegisterRootDevice\n" ); - - HandleLock(); - if( UpnpSdkDeviceRegistered ) { - HandleUnlock(); - return UPNP_E_ALREADY_REGISTERED; - } + HandleLock(); if( Hnd == NULL || Fun == NULL || DescUrl == NULL || strlen( DescUrl ) == 0 ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } + if( UpnpSdkDeviceRegisteredV4 == 1 ) { + HandleUnlock(); + return UPNP_E_ALREADY_REGISTERED; + } + if( ( *Hnd = GetFreeHandle() ) == UPNP_E_OUTOF_HANDLE ) { HandleUnlock(); return UPNP_E_OUTOF_MEMORY; @@ -660,6 +685,7 @@ UpnpRegisterRootDevice( IN const char *DescUrl, CLIENTONLY( HInfo->ClientSubList = NULL; ) HInfo->MaxSubscriptions = UPNP_INFINITE; HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE; + HInfo->DeviceAf = AF_INET; if( ( retVal = UpnpDownloadXmlDoc( HInfo->DescURL, &( HInfo->DescDocument ) ) ) @@ -712,7 +738,8 @@ UpnpRegisterRootDevice( IN const char *DescUrl, "\nUpnpRegisterRootDevice2: Empty service table\n" ); } - UpnpSdkDeviceRegistered = 1; + UpnpSdkDeviceRegisteredV4 = 1; + HandleUnlock(); UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Exiting RegisterRootDevice Successfully\n" ); @@ -720,6 +747,7 @@ UpnpRegisterRootDevice( IN const char *DescUrl, return UPNP_E_SUCCESS; } + #endif // INCLUDE_DEVICE_APIS #ifdef INCLUDE_DEVICE_APIS @@ -818,13 +846,6 @@ UpnpUnRegisterRootDevice( IN UpnpDevice_Handle Hnd ) return UPNP_E_FINISH; } - HandleLock(); - if( !UpnpSdkDeviceRegistered ) { - HandleUnlock(); - return UPNP_E_INVALID_HANDLE; - } - HandleUnlock(); - UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpUnRegisterRootDevice \n" ); #if EXCLUDE_GENA == 0 @@ -840,7 +861,7 @@ UpnpUnRegisterRootDevice( IN UpnpDevice_Handle Hnd ) HandleUnlock(); #if EXCLUDE_SSDP == 0 - retVal = AdvertiseAndReply( -1, Hnd, 0, ( struct sockaddr_in * )NULL, + retVal = AdvertiseAndReply( -1, Hnd, 0, ( struct sockaddr * )NULL, ( char * )NULL, ( char * )NULL, ( char * )NULL, HInfo->MaxAge ); #endif @@ -863,8 +884,13 @@ UpnpUnRegisterRootDevice( IN UpnpDevice_Handle Hnd ) } #endif // INTERNAL_WEB_SERVER + if( HInfo->DeviceAf == AF_INET ) { + UpnpSdkDeviceRegisteredV4 = 0; + } else if( HInfo->DeviceAf == AF_INET6 ) { + UpnpSdkDeviceregisteredV6 = 0; + } + FreeHandle( Hnd ); - UpnpSdkDeviceRegistered = 0; HandleUnlock(); UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, @@ -920,24 +946,50 @@ GetNameForAlias( IN char *name, * Function: get_server_addr * * Parameters: - * OUT struct sockaddr_in* serverAddr: pointer to server address + * OUT struct sockaddr* serverAddr: pointer to server address * structure * * Description: - * This function fills the sockadr_in with miniserver information. + * This function fills the sockadr with IPv4 miniserver information. * * Return Values: VOID * ***************************************************************************/ static void -get_server_addr( OUT struct sockaddr_in *serverAddr ) +get_server_addr( OUT struct sockaddr *serverAddr ) { - memset( serverAddr, 0, sizeof( struct sockaddr_in ) ); + struct sockaddr_in* sa4 = (struct sockaddr_in*)serverAddr; - serverAddr->sin_family = AF_INET; - serverAddr->sin_port = htons( LOCAL_PORT ); - //inet_aton( LOCAL_HOST, &serverAddr->sin_addr ); - serverAddr->sin_addr.s_addr = inet_addr( LOCAL_HOST ); + memset( serverAddr, 0, sizeof(struct sockaddr_storage) ); + + sa4->sin_family = AF_INET; + inet_pton( AF_INET, gIF_IPV4, &sa4->sin_addr ); + sa4->sin_port = htons( LOCAL_PORT_V4 ); +} + +/************************************************************************** + * Function: get_server_addr6 + * + * Parameters: + * OUT struct sockaddr* serverAddr: pointer to server address + * structure + * + * Description: + * This function fills the sockadr with IPv6 miniserver information. + * + * Return Values: VOID + * + ***************************************************************************/ +static void +get_server_addr6( OUT struct sockaddr *serverAddr ) +{ + struct sockaddr_in6* sa6 = (struct sockaddr_in6*)serverAddr; + + memset( serverAddr, 0, sizeof(struct sockaddr_storage) ); + + sa6->sin6_family = AF_INET6; + inet_pton(AF_INET6, gIF_IPV6, &sa6->sin6_addr ); + sa6->sin6_port = htons( LOCAL_PORT_V6 ); } /************************************************************************** @@ -949,8 +1001,9 @@ get_server_addr( OUT struct sockaddr_in *serverAddr ) * IN char* description: * IN unsigned int bufferLen: * IN int config_baseURL: + * IN int AddressFamily: * OUT IXML_Document **xmlDoc: - * OUT char descURL[LINE_SIZE]: + * OUT char descURL[LINE_SIZE]: * * Description: * This function fills the sockadr_in with miniserver information. @@ -963,6 +1016,7 @@ GetDescDocumentAndURL( IN Upnp_DescType descriptionType, IN char *description, IN unsigned int bufferLen, IN int config_baseURL, + IN int AddressFamily, OUT IXML_Document ** xmlDoc, OUT char descURL[LINE_SIZE] ) { @@ -975,7 +1029,7 @@ GetDescDocumentAndURL( IN Upnp_DescType descriptionType, size_t num_read; time_t last_modified; struct stat file_info; - struct sockaddr_in serverAddr; + struct sockaddr_storage serverAddr; int rc = UPNP_E_SUCCESS; if( description == NULL ) { @@ -1054,10 +1108,13 @@ GetDescDocumentAndURL( IN Upnp_DescType descriptionType, strcpy( aliasStr, temp_str ); } - get_server_addr( &serverAddr ); + if(AddressFamily == AF_INET) + get_server_addr( (struct sockaddr*)&serverAddr ); + else + get_server_addr6( (struct sockaddr*)&serverAddr ); // config - retVal = configure_urlbase( *xmlDoc, &serverAddr, + retVal = configure_urlbase( *xmlDoc, (struct sockaddr*)&serverAddr, aliasStr, last_modified, descURL ); if( retVal != UPNP_E_SUCCESS ) { ixmlDocument_free( *xmlDoc ); @@ -1088,6 +1145,7 @@ GetDescDocumentAndURL( IN Upnp_DescType descriptionType, * IN char* description: * IN unsigned int bufferLen: * IN int config_baseURL: + * IN int AddressFamily: * OUT IXML_Document **xmlDoc: * OUT char *descURL: * @@ -1102,6 +1160,7 @@ GetDescDocumentAndURL( IN Upnp_DescType descriptionType, IN char *description, IN unsigned int bufferLen, IN int config_baseURL, + IN int AddressFamily, OUT IXML_Document ** xmlDoc, OUT char *descURL ) { @@ -1184,7 +1243,7 @@ UpnpRegisterRootDevice2( IN Upnp_DescType descriptionType, } HandleLock(); - if( UpnpSdkDeviceRegistered ) { + if( UpnpSdkDeviceRegisteredV4 == 1 ) { HandleUnlock(); return UPNP_E_ALREADY_REGISTERED; } @@ -1206,7 +1265,8 @@ UpnpRegisterRootDevice2( IN Upnp_DescType descriptionType, retVal = GetDescDocumentAndURL( descriptionType, description, bufferLen, - config_baseURL, &HInfo->DescDocument, HInfo->DescURL ); + config_baseURL, AF_INET, + &HInfo->DescDocument, HInfo->DescURL ); if( retVal != UPNP_E_SUCCESS ) { FreeHandle( *Hnd ); @@ -1227,6 +1287,7 @@ UpnpRegisterRootDevice2( IN Upnp_DescType descriptionType, CLIENTONLY( HInfo->ClientSubList = NULL; ) HInfo->MaxSubscriptions = UPNP_INFINITE; HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE; + HInfo->DeviceAf = AF_INET; UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice2: Valid Description\n" ); @@ -1271,7 +1332,8 @@ UpnpRegisterRootDevice2( IN Upnp_DescType descriptionType, "\nUpnpRegisterRootDevice2: Empty service table\n" ); } - UpnpSdkDeviceRegistered = 1; + UpnpSdkDeviceRegisteredV4 = 1; + HandleUnlock(); UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Exiting RegisterRootDevice2 Successfully\n" ); @@ -1279,6 +1341,155 @@ UpnpRegisterRootDevice2( IN Upnp_DescType descriptionType, return UPNP_E_SUCCESS; } + +/**************************************************************************** + * Function: UpnpRegisterRootDevice3 + * + * Parameters: + * IN const char *DescUrl:Pointer to a string containing the + * description URL for this root device instance. + * IN Upnp_FunPtr Callback: Pointer to the callback function for + * receiving asynchronous events. + * IN const void *Cookie: Pointer to user data returned with the + * callback function when invoked. + * OUT UpnpDevice_Handle *Hnd: Pointer to a variable to store the + * new device handle. + * IN const int AddressFamily: Registration address family. Can be AF_INET + * or AF_INET6. + * + * Description: + * This function registers a device application with + * the UPnP Library. A device application cannot make any other API + * calls until it registers using this function. + * + * Return Values: + * UPNP_E_SUCCESS on success, nonzero on failure. + *****************************************************************************/ +int +UpnpRegisterRootDevice3( IN const char *DescUrl, + IN Upnp_FunPtr Fun, + IN const void *Cookie, + OUT UpnpDevice_Handle * Hnd, + IN const int AddressFamily ) +{ + + struct Handle_Info *HInfo; + int retVal = 0; + + if( UpnpSdkInit != 1 ) { + return UPNP_E_FINISH; + } + + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "Inside UpnpRegisterRootDevice\n" ); + + HandleLock(); + if( Hnd == NULL || Fun == NULL || + DescUrl == NULL || strlen( DescUrl ) == 0 || + (AddressFamily != AF_INET && AddressFamily != AF_INET6) ) { + HandleUnlock(); + return UPNP_E_INVALID_PARAM; + } + + if( ( AddressFamily == AF_INET && UpnpSdkDeviceRegisteredV4 == 1 ) || + ( AddressFamily == AF_INET6 && UpnpSdkDeviceregisteredV6 == 1 ) ) { + HandleUnlock(); + return UPNP_E_ALREADY_REGISTERED; + } + + if( ( *Hnd = GetFreeHandle() ) == UPNP_E_OUTOF_HANDLE ) { + HandleUnlock(); + return UPNP_E_OUTOF_MEMORY; + } + + HInfo = ( struct Handle_Info * )malloc( sizeof( struct Handle_Info ) ); + if( HInfo == NULL ) { + HandleUnlock(); + return UPNP_E_OUTOF_MEMORY; + } + HandleTable[*Hnd] = HInfo; + + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "Root device URL is %s\n", DescUrl ); + + HInfo->aliasInstalled = 0; + HInfo->HType = HND_DEVICE; + strcpy( HInfo->DescURL, DescUrl ); + HInfo->Callback = Fun; + HInfo->Cookie = ( void * )Cookie; + HInfo->MaxAge = DEFAULT_MAXAGE; + HInfo->DeviceList = NULL; + HInfo->ServiceList = NULL; + HInfo->DescDocument = NULL; + CLIENTONLY( ListInit( &HInfo->SsdpSearchList, NULL, NULL ); ) + CLIENTONLY( HInfo->ClientSubList = NULL; ) + HInfo->MaxSubscriptions = UPNP_INFINITE; + HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE; + HInfo->DeviceAf = AddressFamily; + + if( ( retVal = + UpnpDownloadXmlDoc( HInfo->DescURL, &( HInfo->DescDocument ) ) ) + != UPNP_E_SUCCESS ) { + CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ) ); + FreeHandle( *Hnd ); + HandleUnlock(); + return retVal; + } + + UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice: Valid Description\n" ); + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice: DescURL : %s\n", + HInfo->DescURL ); + + HInfo->DeviceList = + ixmlDocument_getElementsByTagName( HInfo->DescDocument, "device" ); + if( !HInfo->DeviceList ) { + CLIENTONLY( ListDestroy( &HInfo->SsdpSearchList, 0 ) ); + ixmlDocument_free( HInfo->DescDocument ); + FreeHandle( *Hnd ); + HandleUnlock(); + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice: No devices found for RootDevice\n" ); + return UPNP_E_INVALID_DESC; + } + + HInfo->ServiceList = ixmlDocument_getElementsByTagName( + HInfo->DescDocument, "serviceList" ); + if( !HInfo->ServiceList ) { + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice: No services found for RootDevice\n" ); + } + + UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice: Gena Check\n" ); + //******************************* + // GENA SET UP + //******************************* + if( getServiceTable( ( IXML_Node * ) HInfo->DescDocument, + &HInfo->ServiceTable, HInfo->DescURL ) ) { + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "UpnpRegisterRootDevice: GENA Service Table \n" ); + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "Here are the known services: \n" ); + printServiceTable( &HInfo->ServiceTable, UPNP_INFO, API ); + } else { + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "\nUpnpRegisterRootDevice2: Empty service table\n" ); + } + + if( AddressFamily == AF_INET ) + UpnpSdkDeviceRegisteredV4 = 1; + else + UpnpSdkDeviceregisteredV6 = 1; + + HandleUnlock(); + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "Exiting RegisterRootDevice Successfully\n" ); + + return UPNP_E_SUCCESS; +} + #endif // INCLUDE_DEVICE_APIS #ifdef INCLUDE_CLIENT_APIS @@ -1476,7 +1687,7 @@ UpnpSendAdvertisement( IN UpnpDevice_Handle Hnd, Exp = DEFAULT_MAXAGE; SInfo->MaxAge = Exp; HandleUnlock(); - retVal = AdvertiseAndReply( 1, Hnd, 0, ( struct sockaddr_in * )NULL, + retVal = AdvertiseAndReply( 1, Hnd, 0, ( struct sockaddr * )NULL, ( char * )NULL, ( char * )NULL, ( char * )NULL, Exp ); @@ -3376,6 +3587,607 @@ UpnpDownloadXmlDoc( const char *url, // //---------------------------------------------------------------------------- +#ifdef WIN32 +/**************************************************************************** + * Function: WinsockInit + * + * Parameters: NONE + * + * Description: (Windows Only) + * Initializes the Windows Winsock library. + * + * Return Values: + * UPNP_E_SUCCESS on success, UPNP_E_INIT_FAILED on failure. + *****************************************************************************/ +int WinsockInit( void ) +{ + WORD wVersionRequested; + WSADATA wsaData; + int err; + + wVersionRequested = MAKEWORD( 2, 2 ); + + err = WSAStartup( wVersionRequested, &wsaData ); + if ( err != 0 ) { + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ + return UPNP_E_INIT_FAILED; + } + + /* Confirm that the WinSock DLL supports 2.2.*/ + /* Note that if the DLL supports versions greater */ + /* than 2.2 in addition to 2.2, it will still return */ + /* 2.2 in wVersion since that is the version we */ + /* requested. */ + + if ( LOBYTE( wsaData.wVersion ) != 2 || + HIBYTE( wsaData.wVersion ) != 2 ) { + /* Tell the user that we could not find a usable */ + /* WinSock DLL. */ + WSACleanup( ); + return UPNP_E_INIT_FAILED; + } + return UPNP_E_SUCCESS; +} +#endif + + +/**************************************************************************** + * Function: UpnpInitPreamble + * + * Parameters: (none) + * + * Description: + * This function performs the initial steps in initializing the UPnP SDK. + * - Winsock library is initialized for the process (Windows specific). + * - The logging (for debug messages) is initialized. + * - Mutexes, Handle table and thread pools are allocated and initialized. + * - Callback functions for SOAP and GENA are set, if they're enabled. + * - The SDK timer thread is initialized. + * + * Returns: + * UPNP_E_SUCCESS on success + *****************************************************************************/ +int UpnpInitPreamble() +{ + uuid_upnp nls_uuid; + int retVal = 0; + +#ifdef WIN32 + retVal = WinsockInit(); + if( retVal != UPNP_E_SUCCESS ){ + return retVal; + } + /* The WinSock DLL is acceptable. Proceed. */ +#endif + + srand( (unsigned int)time( NULL ) ); // needed by SSDP or other parts + + // Initialize debug output. + retVal = UpnpInitLog(); + if( retVal != UPNP_E_SUCCESS ) { + // UpnpInitLog does not return a valid UPNP_E_* + return UPNP_E_INIT_FAILED; + } + + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpInitPreamble\n" ); + + // Initialize SDK global mutexes. + retVal = UpnpInitMutexes(); + if( retVal != UPNP_E_SUCCESS ) { + return retVal; + } + + // Create the NLS uuid. + uuid_create(&nls_uuid); + uuid_unpack(&nls_uuid, gUpnpSdkNLSuuid); + + // Init the handle list. + HandleLock(); + InitHandleList(); + HandleUnlock(); + + // Initialize SDK global thread pools. + retVal = UpnpInitThreadPools(); + if( retVal != UPNP_E_SUCCESS ) { + return retVal; + } + +#if EXCLUDE_SOAP == 0 + SetSoapCallback( soap_device_callback ); +#endif + +#if EXCLUDE_GENA == 0 + SetGenaCallback( genaCallback ); +#endif + + // Initialize the SDK timer thread. + retVal = TimerThreadInit( &gTimerThread, &gSendThreadPool ); + if( retVal != UPNP_E_SUCCESS ) { + UpnpFinish(); + return retVal; + } + + return UPNP_E_SUCCESS; +} + + +/**************************************************************************** + * Function: UpnpInitMutexes + * + * Parameters: (none) + * + * Description: + * This function initializes the global mutexes used by the UPnP SDK. + * + * Returns: + * UPNP_E_SUCCESS on success + * UPNP_E_INIT_FAILED if a mutex could not be initialized. + *****************************************************************************/ +int UpnpInitMutexes( void ) +{ +#ifdef __CYGWIN__ + /* On Cygwin, pthread_mutex_init() fails without this memset. */ + /* TODO: Fix Cygwin so we don't need this memset(). */ + memset(&GlobalHndRWLock, 0, sizeof(GlobalHndRWLock)); +#endif + if (ithread_rwlock_init(&GlobalHndRWLock, NULL) != 0) { + return UPNP_E_INIT_FAILED; + } + + if (ithread_mutex_init(&gUUIDMutex, NULL) != 0) { + return UPNP_E_INIT_FAILED; + } + // initialize subscribe mutex +#ifdef INCLUDE_CLIENT_APIS + if (ithread_mutex_init(&GlobalClientSubscribeMutex, NULL) != 0) { + return UPNP_E_INIT_FAILED; + } +#endif + return UPNP_E_SUCCESS; +} + + +/**************************************************************************** + * Function: UpnpInitThreadPools + * + * Parameters: (none) + * + * Description: + * This function initializes the global threadm pools used by the UPnP SDK. + * + * Returns: + * UPNP_E_SUCCESS on success + * UPNP_E_INIT_FAILED if a mutex could not be initialized. + *****************************************************************************/ +int UpnpInitThreadPools( void ) +{ + ThreadPoolAttr attr; + + TPAttrInit( &attr ); + TPAttrSetMaxThreads( &attr, MAX_THREADS ); + TPAttrSetMinThreads( &attr, MIN_THREADS ); + TPAttrSetJobsPerThread( &attr, JOBS_PER_THREAD ); + TPAttrSetIdleTime( &attr, THREAD_IDLE_TIME ); + TPAttrSetMaxJobsTotal( &attr, MAX_JOBS_TOTAL ); + + if( ThreadPoolInit( &gSendThreadPool, &attr ) != UPNP_E_SUCCESS ) { + UpnpSdkInit = 0; + UpnpFinish(); + return UPNP_E_INIT_FAILED; + } + + if( ThreadPoolInit( &gRecvThreadPool, &attr ) != UPNP_E_SUCCESS ) { + UpnpSdkInit = 0; + UpnpFinish(); + return UPNP_E_INIT_FAILED; + } + + if( ThreadPoolInit( &gMiniServerThreadPool, &attr ) != UPNP_E_SUCCESS ) { + UpnpSdkInit = 0; + UpnpFinish(); + return UPNP_E_INIT_FAILED; + } + return UPNP_E_SUCCESS; +} + + +/**************************************************************************** + * Function: UpnpInitStartServers + * + * Parameters: + * IN short DestPort: Local Port to listen for incoming connections + * + * Description: + * This function finishes initializing the UPnP SDK. + * - The MiniServer is started, if enabled. + * - The WebServer is started, if enabled. + * + * Returns: + * UPNP_E_SUCCESS on success + * UPNP_E_INIT_FAILED if a mutex could not be initialized. + *****************************************************************************/ +int UpnpInitStartServers( IN unsigned short DestPort ) +{ + int retVal = 0; + + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Entering UpnpInitStartServers\n" ); + +#if EXCLUDE_MINISERVER == 0 + LOCAL_PORT_V4 = DestPort; + LOCAL_PORT_V6 = DestPort; + retVal = StartMiniServer( &LOCAL_PORT_V4, &LOCAL_PORT_V6 ); + if( retVal != UPNP_E_SUCCESS ) { + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "Miniserver failed to start" ); + UpnpFinish(); + return retVal; + } +#endif + +#if EXCLUDE_WEB_SERVER == 0 + membuffer_init( &gDocumentRootDir ); + retVal = UpnpEnableWebserver( WEB_SERVER_ENABLED ); + if( retVal != UPNP_E_SUCCESS ) { + UpnpFinish(); + return retVal; + } +#endif + + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Exiting UpnpInitStartServers\n" ); + + return UPNP_E_SUCCESS; +} + + +/************************************************************************** + * Function: UpnpGetIfInfo + * + * Parameters: + * char * IfName: Interface name (can be NULL). + * + * Description: + * This function will retrieve interface information and keep it in global + * variables. If NULL, we'll find the first suitable interface for + * operation. + * The interface must fulfill these requirements: + * - Be UP. + * - Not be LOOPBACK. + * - Support MULTICAST. + * - Have a valid IPv4 or IPv6 address. + * We'll retrieve the following information from the interface: + * - gIF_NAME -> Interface name (by input or found). + * - gIF_IPV4 -> IPv4 address (if any). + * - gIF_IPV6 -> IPv6 address (if any). + * - gIF_INDEX -> Interface index number. + * + * Return Values: + * UPNP_E_SUCCESS on success + * + ***************************************************************************/ +int UpnpGetIfInfo( const char * IfName ) +{ +#ifdef WIN32 + // ---------------------------------------------------- + // WIN32 implementation will use the IpHlpAPI library. + // ---------------------------------------------------- + PIP_ADAPTER_ADDRESSES adapts = NULL; + PIP_ADAPTER_ADDRESSES adapts_item; + PIP_ADAPTER_UNICAST_ADDRESS uni_addr; + SOCKADDR* ip_addr; + struct in_addr v4_addr; + struct in6_addr v6_addr; + ULONG adapts_sz = 0; + ULONG ret; + int ifname_found = 0; + int valid_addr_found = 0; + + // Get Adapters addresses required size. + ret = GetAdaptersAddresses( AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, adapts, &adapts_sz ); + if( ret != ERROR_BUFFER_OVERFLOW ) { + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "GetAdaptersAddresses failed to find list of adapters\n" ); + return UPNP_E_INIT; + } + + // Allocate enough memory. + adapts = (PIP_ADAPTER_ADDRESSES)malloc( adapts_sz ); + if( adapts == NULL ) { + return UPNP_E_OUTOF_MEMORY; + } + + // Do the call that will actually return the info. + ret = GetAdaptersAddresses( AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_DNS_SERVER, NULL, adapts, &adapts_sz ); + if( ret != ERROR_SUCCESS ) { + free( adapts ); + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "GetAdaptersAddresses failed to find list of adapters\n" ); + return UPNP_E_INIT; + } + + // Copy interface name, if it was provided. + if( IfName != NULL ) { + if( strlen(IfName) > sizeof(gIF_NAME) ) + return UPNP_E_INVALID_INTERFACE; + + strncpy( gIF_NAME, IfName, sizeof(gIF_NAME) ); + ifname_found = 1; + } + + adapts_item = adapts; + while( adapts_item != NULL ) { + + if( adapts_item->Flags & IP_ADAPTER_NO_MULTICAST ) { + continue; + } + + if( ifname_found == 0 ) { + // We have found a valid interface name. Keep it. + strncpy( gIF_NAME, adapts_item->FriendlyName, sizeof(gIF_NAME) ); + ifname_found = 1; + } else { + if( strncmp( gIF_NAME, adapts_item->FriendlyName, sizeof(gIF_NAME) ) != 0 ) { + // This is not the interface we're looking for. + continue; + } + } + + // Loop thru this adapter's unicast IP addresses. + uni_addr = adapts_item->FirstUnicastAddress; + while( uni_addr ) { + ip_addr = uni_addr->Address.lpSockaddr; + switch( ip_addr->sa_family ) { + case AF_INET: + memcpy( &v4_addr, &((struct sockaddr_in *)ip_addr)->sin_addr, sizeof(v4_addr) ); + valid_addr_found = 1; + break; + case AF_INET6: + // Only keep IPv6 link-local addresses. + if( IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)ip_addr)->sin6_addr) ) { + memcpy( &v6_addr, &((struct sockaddr_in6 *)ip_addr)->sin6_addr, sizeof(v6_addr) ); + valid_addr_found = 1; + } + break; + default: + if( valid_addr_found == 0 ) { + // Address is not IPv4 or IPv6 and no valid address has + // yet been found for this interface. Discard interface name. + ifname_found = 0; + } + break; + } + + // Next address. + uni_addr = uni_addr->Next; + } + + if( valid_addr_found == 1 ) { + gIF_INDEX = adapts_item->IfIndex; + break; + } + + // Next adapter. + adapts_item = adapts_item->Next; + } + + // Failed to find a valid interface, or valid address. + if( ifname_found == 0 || valid_addr_found == 0 ) { + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "Failed to find an adapter with valid IP addresses for use.\n" ); + return UPNP_E_INVALID_INTERFACE; + } + + inet_ntop(AF_INET, &v4_addr, gIF_IPV4, sizeof(gIF_IPV4)); + inet_ntop(AF_INET6, &v6_addr, gIF_IPV6, sizeof(gIF_IPV6)); +#elif (defined(BSD) && BSD >= 199306) + struct ifaddrs *ifap, *ifa; + struct in_addr v4_addr; + struct in6_addr v6_addr; + int ifname_found = 0; + int valid_addr_found = 0; + + // Copy interface name, if it was provided. + if( IfName != NULL ) { + if( strlen(IfName) > sizeof(gIF_NAME) ) + return UPNP_E_INVALID_INTERFACE; + + strncpy( gIF_NAME, IfName, sizeof(gIF_NAME) ); + ifname_found = 1; + } + + // Get system interface addresses. + if( getifaddrs(&ifap) != 0 ) { + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "getifaddrs failed to find list of addresses\n" ); + return UPNP_E_INIT; + } + + // cycle through available interfaces and their addresses. + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) + { + // Skip LOOPBACK interfaces, DOWN interfaces and interfaces that + // don't support MULTICAST. + if( ( ifa->ifa_flags & IFF_LOOPBACK ) + || ( !( ifa->ifa_flags & IFF_UP ) ) + || ( !( ifa->ifa_flags & IFF_MULTICAST ) ) ) { + continue; + } + + if( ifname_found == 0 ) { + // We have found a valid interface name. Keep it. + strncpy( gIF_NAME, ifa->ifa_name, sizeof(gIF_NAME) ); + ifname_found = 1; + } else { + if( strncmp( gIF_NAME, ifa->ifa_name, sizeof(gIF_NAME) ) != 0 ) { + // This is not the interface we're looking for. + continue; + } + } + + // Keep interface addresses for later. + switch( ifa->ifa_addr->sa_family ) + { + case AF_INET: + memcpy( &v4_addr, &((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr, sizeof(v4_addr) ); + valid_addr_found = 1; + break; + case AF_INET6: + // Only keep IPv6 link-local addresses. + if( IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_addr) ) { + memcpy( &v6_addr, &((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_addr, sizeof(v6_addr) ); + valid_addr_found = 1; + } + break; + default: + if( valid_addr_found == 0 ) { + // Address is not IPv4 or IPv6 and no valid address has + // yet been found for this interface. Discard interface name. + ifname_found = 0; + } + break; + } + } + freeifaddrs(ifap); + + // Failed to find a valid interface, or valid address. + if( ifname_found == 0 || valid_addr_found == 0 ) { + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "Failed to find an adapter with valid IP addresses for use.\n" ); + return UPNP_E_INVALID_INTERFACE; + } + + inet_ntop(AF_INET, &v4_addr, gIF_IPV4, sizeof(gIF_IPV4)); + inet_ntop(AF_INET6, &v6_addr, gIF_IPV6, sizeof(gIF_IPV6)); + gIF_INDEX = if_nametoindex(gIF_NAME); +#else + char szBuffer[MAX_INTERFACES * sizeof( struct ifreq )]; + struct ifconf ifConf; + struct ifreq ifReq; + FILE* inet6_procfd; + int i; + int LocalSock; + struct in6_addr v6_addr; + int if_idx; + char addr6[8][5]; + char buf[65]; // INET6_ADDRSTRLEN + int ifname_found = 0; + int valid_addr_found = 0; + + // Copy interface name, if it was provided. + if( IfName != NULL ) { + if( strlen(IfName) > sizeof(gIF_NAME) ) + return UPNP_E_INVALID_INTERFACE; + + strncpy( gIF_NAME, IfName, sizeof(gIF_NAME) ); + ifname_found = 1; + } + + // Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. + if( ( LocalSock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) < 0 ) { + UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, + "Can't create addrlist socket\n" ); + return UPNP_E_INIT; + } + + // Get the interface configuration information... + ifConf.ifc_len = sizeof szBuffer; + ifConf.ifc_ifcu.ifcu_buf = ( caddr_t ) szBuffer; + + if( ioctl( LocalSock, SIOCGIFCONF, &ifConf ) < 0 ) { + UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, + "DiscoverInterfaces: SIOCGIFCONF returned error\n" ); + return UPNP_E_INIT; + } + + // Cycle through the list of interfaces looking for IP addresses. + for( i = 0; i < ifConf.ifc_len ; ) { + struct ifreq *pifReq = + ( struct ifreq * )( ( caddr_t ) ifConf.ifc_req + i ); + i += sizeof *pifReq; + + // See if this is the sort of interface we want to deal with. + strcpy( ifReq.ifr_name, pifReq->ifr_name ); + if( ioctl( LocalSock, SIOCGIFFLAGS, &ifReq ) < 0 ) { + UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, + "Can't get interface flags for %s:\n", + ifReq.ifr_name ); + } + + // Skip LOOPBACK interfaces, DOWN interfaces and interfaces that + // don't support MULTICAST. + if( ( ifReq.ifr_flags & IFF_LOOPBACK ) + || ( !( ifReq.ifr_flags & IFF_UP ) ) + || ( !( ifReq.ifr_flags & IFF_MULTICAST ) ) ) { + continue; + } + + if( ifname_found == 0 ) { + // We have found a valid interface name. Keep it. + strncpy( gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) ); + ifname_found = 1; + } else { + if( strncmp( gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) ) != 0 ) { + // This is not the interface we're looking for. + continue; + } + } + + // Check address family. + if( pifReq->ifr_addr.sa_family == AF_INET ) { + // Copy interface name, IPv4 address and interface index. + strncpy( gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) ); + inet_ntop(AF_INET, &((struct sockaddr_in*)&pifReq->ifr_addr)->sin_addr, gIF_IPV4, sizeof(gIF_IPV4)); + gIF_INDEX = if_nametoindex(gIF_NAME); + + valid_addr_found = 1; + break; + } else { + // Address is not IPv4 + ifname_found = 0; + } + } + close( LocalSock ); + + // Failed to find a valid interface, or valid address. + if( ifname_found == 0 || valid_addr_found == 0 ) { + UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, + "Failed to find an adapter with valid IP addresses for use.\n" ); + return UPNP_E_INVALID_INTERFACE; + } + + // Try to get the IPv6 address for the same interface + // from "/proc/net/if_inet6", if possible. + inet6_procfd = fopen( "/proc/net/if_inet6", "r" ); + if( inet6_procfd != NULL ) { + while( fscanf(inet6_procfd, + "%4s%4s%4s%4s%4s%4s%4s%4s %02x %*02x %*02x %*02x %*20s\n", + addr6[0],addr6[1],addr6[2],addr6[3], + addr6[4],addr6[5],addr6[6],addr6[7], &if_idx) != EOF) { + // Get same interface as IPv4 address retrieved. + if( gIF_INDEX == if_idx ) { + snprintf(buf, sizeof(buf), "%s:%s:%s:%s:%s:%s:%s:%s", + addr6[0],addr6[1],addr6[2],addr6[3], + addr6[4],addr6[5],addr6[6],addr6[7]); + // Validate formed address and check for link-local. + if( inet_pton(AF_INET6, buf, &v6_addr) > 0 && + IN6_IS_ADDR_LINKLOCAL(&v6_addr) ) { + // Got valid IPv6 link-local adddress. + strncpy( gIF_IPV6, buf, sizeof(gIF_IPV6) ); + break; + } + } + } + fclose( inet6_procfd ); + } +#endif + + UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, + "Interface name=%s, index=%d, v4=%s, v6=%s\n", + gIF_NAME, gIF_INDEX, gIF_IPV4, gIF_IPV6 ); + + return UPNP_E_SUCCESS; +} + /************************************************************************** * Function: UpnpThreadDistribution @@ -3560,6 +4372,7 @@ int GetFreeHandle() * this function. * * Description: + * NOTE: The logic around the use of this function should be revised. * This function is to get client handle info * * Return Values: HND_CLIENT, HND_INVALID @@ -3587,38 +4400,45 @@ Upnp_Handle_Type GetClientHandleInfo( } /************************************************************************** - * Function: GetDeviceHandleInfo + * Function: GetDeviceHandleInfo + * Retrieves the device handle and information of the first device of the + * address family spcified. * - * Parameters: - * IN UpnpDevice_Handle *device_handle_out: - * device handle pointer (key for the client handle structure). + * Parameters: + * IN int AddressFamily: + * OUT UpnpDevice_Handle * device_handle_out: device handle pointer * OUT struct Handle_Info **HndInfo: * Device handle structure passed by this function. * * Description: * This function is to get device handle info. * - * Return Values: HND_DEVICE, HND_INVALID + * Return Values: HND_DEVICE or HND_INVALID * ***************************************************************************/ Upnp_Handle_Type GetDeviceHandleInfo( + const int AddressFamily, UpnpDevice_Handle *device_handle_out, struct Handle_Info **HndInfo) { - Upnp_Handle_Type ret = HND_DEVICE; - UpnpDevice_Handle device; + // Check if we've got a registered device of the address family specified. + if( (AddressFamily == AF_INET && UpnpSdkDeviceRegisteredV4 == 0) || + (AddressFamily == AF_INET6 && UpnpSdkDeviceregisteredV6 == 0) ) { + *device_handle_out = -1; + return HND_INVALID; + } - if (GetHandleInfo(1, HndInfo) == HND_DEVICE) { - device = 1; - } else if (GetHandleInfo(2, HndInfo) == HND_DEVICE) { - device = 2; - } else { - device = -1; - ret = HND_INVALID; - } + // Find it. + for( *device_handle_out=1; *device_handle_out < NUM_HANDLE; (*device_handle_out)++ ) { + if( GetHandleInfo( *device_handle_out, HndInfo ) == HND_DEVICE ) { + if( (*HndInfo)->DeviceAf == AddressFamily ) { + return HND_DEVICE; + } + } + } - *device_handle_out = device; - return ret; + *device_handle_out = -1; + return HND_INVALID; } /************************************************************************** @@ -3782,6 +4602,7 @@ void printNodes( IXML_Node * tmpRoot, int depth ) * * Parameters: * OUT char *out: IP address of the interface. + * IN int out_len: Length of the output buffer. * * Description: * This function is to get local IP address. It gets the ip address for @@ -3791,17 +4612,17 @@ void printNodes( IXML_Node * tmpRoot, int depth ) * Return Values: int * UPNP_E_SUCCESS if successful else return appropriate error ***************************************************************************/ - int getlocalhostname( OUT char *out ) { - +int getlocalhostname(OUT char *out, IN const int out_len) +{ #ifdef WIN32 - struct hostent *h=NULL; - struct sockaddr_in LocalAddr; + struct hostent *h=NULL; + struct sockaddr_in LocalAddr; - gethostname(out,LINE_SIZE); + gethostname(out, out_len); h=gethostbyname(out); if (h!=NULL){ memcpy(&LocalAddr.sin_addr,h->h_addr_list[0],4); - strcpy( out, inet_ntoa(LocalAddr.sin_addr)); + strncpy(out, inet_ntoa(LocalAddr.sin_addr), out_len); } return UPNP_E_SUCCESS; #elif (defined(BSD) && BSD >= 199306) @@ -3830,7 +4651,7 @@ void printNodes( IXML_Node * tmpRoot, int depth ) } strncpy( out, inet_ntoa( ((struct sockaddr_in *)(ifa->ifa_addr))-> - sin_addr ), LINE_SIZE ); + sin_addr ), out_len ); out[LINE_SIZE-1] = '\0'; UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Inside getlocalhostname : after strncpy %s\n", @@ -3907,7 +4728,7 @@ void printNodes( IXML_Node * tmpRoot, int depth ) } close( LocalSock ); - strncpy( out, inet_ntoa( LocalAddr.sin_addr ), LINE_SIZE ); + strncpy( out, inet_ntoa( LocalAddr.sin_addr ), out_len ); UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Inside getlocalhostname : after strncpy %s\n", diff --git a/upnp/src/gena/gena_ctrlpt.c b/upnp/src/gena/gena_ctrlpt.c index 6e5c2c4..2e956ec 100644 --- a/upnp/src/gena/gena_ctrlpt.c +++ b/upnp/src/gena/gena_ctrlpt.c @@ -325,13 +325,23 @@ static int gena_subscribe( "TIMEOUT: Second-", timeout_str ); } else { // subscribe - return_code = http_MakeMessage( - &request, 1, 1, - "q" "sssdsc" "sc" "sscc", - HTTPMETHOD_SUBSCRIBE, &dest_url, - "CALLBACK: ", - "NT: upnp:event", - "TIMEOUT: Second-", timeout_str); + if( dest_url.hostport.IPaddress.ss_family == AF_INET6 ) { + return_code = http_MakeMessage( + &request, 1, 1, + "q" "sssdsc" "sc" "sscc", + HTTPMETHOD_SUBSCRIBE, &dest_url, + "CALLBACK: ", + "NT: upnp:event", + "TIMEOUT: Second-", timeout_str ); + } else { + return_code = http_MakeMessage( + &request, 1, 1, + "q" "sssdsc" "sc" "sscc", + HTTPMETHOD_SUBSCRIBE, &dest_url, + "CALLBACK: ", + "NT: upnp:event", + "TIMEOUT: Second-", timeout_str); + } } if (return_code != 0) { return return_code; diff --git a/upnp/src/gena/gena_device.c b/upnp/src/gena/gena_device.c index 31ba797..c51031c 100644 --- a/upnp/src/gena/gena_device.c +++ b/upnp/src/gena/gena_device.c @@ -1352,7 +1352,8 @@ gena_process_subscription_request( IN SOCKINFO * info, HandleLock(); // CURRENTLY, ONLY ONE DEVICE - if( GetDeviceHandleInfo( &device_handle, &handle_info ) != HND_DEVICE ) { + if( GetDeviceHandleInfo( info->foreign_sockaddr.ss_family , + &device_handle, &handle_info ) != HND_DEVICE ) { free( event_url_path ); error_respond( info, HTTP_INTERNAL_SERVER_ERROR, request ); HandleUnlock(); @@ -1527,7 +1528,8 @@ gena_process_subscription_renewal_request( IN SOCKINFO * info, HandleLock(); // CURRENTLY, ONLY SUPPORT ONE DEVICE - if( GetDeviceHandleInfo( &device_handle, &handle_info ) != HND_DEVICE ) { + if( GetDeviceHandleInfo( info->foreign_sockaddr.ss_family, + &device_handle, &handle_info ) != HND_DEVICE ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); membuffer_destroy( &event_url_path ); return; @@ -1650,7 +1652,8 @@ gena_process_unsubscribe_request( IN SOCKINFO * info, HandleLock(); // CURRENTLY, ONLY SUPPORT ONE DEVICE - if( GetDeviceHandleInfo( &device_handle, &handle_info ) != HND_DEVICE ) { + if( GetDeviceHandleInfo( info->foreign_sockaddr.ss_family, + &device_handle, &handle_info ) != HND_DEVICE ) { error_respond( info, HTTP_PRECONDITION_FAILED, request ); membuffer_destroy( &event_url_path ); HandleUnlock(); diff --git a/upnp/src/genlib/miniserver/miniserver.c b/upnp/src/genlib/miniserver/miniserver.c index 80ec29c..72fba50 100644 --- a/upnp/src/genlib/miniserver/miniserver.c +++ b/upnp/src/genlib/miniserver/miniserver.c @@ -73,8 +73,7 @@ struct mserv_request_t { int connfd; // connection handle - struct in_addr foreign_ip_addr; - unsigned short foreign_ip_port; + struct sockaddr_storage foreign_sockaddr; }; typedef enum { MSERV_IDLE, MSERV_RUNNING, MSERV_STOPPING } MiniServerState; @@ -272,8 +271,8 @@ handle_request( void *args ) //parser_request_init( &parser ); ////LEAK_FIX_MK hmsg = &parser.msg; - if( sock_init_with_ip( &info, connfd, request->foreign_ip_addr, - request->foreign_ip_port ) != UPNP_E_SUCCESS ) { + if( sock_init_with_ip( &info, connfd, (struct sockaddr*)&request->foreign_sockaddr ) + != UPNP_E_SUCCESS ) { free( request ); httpmsg_destroy( hmsg ); return; @@ -317,7 +316,7 @@ handle_request( void *args ) * * Parameters: * IN int connfd - Socket Descriptor on which connection is accepted - * IN struct sockaddr_in* clientAddr - Clients Address information + * IN struct sockaddr* clientAddr - Clients Address information * * Description: * Initilize the thread pool to handle a request. @@ -327,7 +326,7 @@ handle_request( void *args ) ************************************************************************/ static UPNP_INLINE void schedule_request_job( IN int connfd, - IN struct sockaddr_in *clientAddr ) + IN struct sockaddr *clientAddr ) { struct mserv_request_t *request; ThreadPoolJob job; @@ -338,14 +337,13 @@ schedule_request_job( IN int connfd, if( request == NULL ) { UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, "mserv %d: out of memory\n", connfd ); - shutdown( request->connfd, SD_BOTH ); + shutdown( connfd, SD_BOTH ); UpnpCloseSocket( connfd ); return; } request->connfd = connfd; - request->foreign_ip_addr = clientAddr->sin_addr; - request->foreign_ip_port = ntohs( clientAddr->sin_port ); + memcpy( &request->foreign_sockaddr, clientAddr, sizeof(request->foreign_sockaddr) ); TPJobInit( &job, ( start_routine ) handle_request, ( void * )request ); TPJobSetFreeFunction( &job, free_handle_request_arg ); @@ -380,28 +378,41 @@ static void RunMiniServer( MiniServerSockArray *miniSock ) { char errorBuffer[ERROR_BUFFER_LEN]; - struct sockaddr_in clientAddr; + struct sockaddr_storage clientAddr; socklen_t clientLen; SOCKET connectHnd; - SOCKET miniServSock = miniSock->miniServerSock; + SOCKET miniServSock4 = miniSock->miniServerSock4; + SOCKET miniServSock6 = miniSock->miniServerSock6; SOCKET miniServStopSock = miniSock->miniServerStopSock; - SOCKET ssdpSock = miniSock->ssdpSock; + SOCKET ssdpSock4 = miniSock->ssdpSock4; + SOCKET ssdpSock6 = miniSock->ssdpSock6; #ifdef INCLUDE_CLIENT_APIS - SOCKET ssdpReqSock = miniSock->ssdpReqSock; + SOCKET ssdpReqSock4 = miniSock->ssdpReqSock4; + SOCKET ssdpReqSock6 = miniSock->ssdpReqSock6; #endif - + char buf_ntop[64]; fd_set expSet; fd_set rdSet; - unsigned int maxMiniSock; + unsigned int maxMiniSock = 0; int byteReceived; char requestBuf[256]; int ret = 0; - maxMiniSock = max( miniServSock, miniServStopSock) ; - maxMiniSock = max( maxMiniSock, (SOCKET)(ssdpSock) ); + if( miniServSock4 != INVALID_SOCKET ) + maxMiniSock = max( maxMiniSock, miniServSock4 ); + if( miniServSock6 != INVALID_SOCKET ) + maxMiniSock = max( maxMiniSock, miniServSock6 ); + if( ssdpSock4 != INVALID_SOCKET ) + maxMiniSock = max( maxMiniSock, ssdpSock4 ); + if( ssdpSock6 != INVALID_SOCKET ) + maxMiniSock = max( maxMiniSock, ssdpSock6 ); #ifdef INCLUDE_CLIENT_APIS - maxMiniSock = max( maxMiniSock, (SOCKET)(ssdpReqSock) ); + if( ssdpReqSock4 != INVALID_SOCKET ) + maxMiniSock = max( maxMiniSock, ssdpReqSock4 ); + if( ssdpReqSock6 != INVALID_SOCKET ) + maxMiniSock = max( maxMiniSock, ssdpReqSock6 ); #endif + maxMiniSock = max( maxMiniSock, miniServStopSock) ; ++maxMiniSock; gMServState = MSERV_RUNNING; @@ -410,11 +421,20 @@ RunMiniServer( MiniServerSockArray *miniSock ) FD_ZERO( &expSet ); FD_SET( miniServStopSock, &expSet ); - FD_SET( miniServSock, &rdSet ); FD_SET( miniServStopSock, &rdSet ); - FD_SET( ssdpSock, &rdSet ); + if( miniServSock4 != INVALID_SOCKET ) + FD_SET( miniServSock4, &rdSet ); + if( miniServSock6 != INVALID_SOCKET ) + FD_SET( miniServSock6, &rdSet ); + if( ssdpSock4 != INVALID_SOCKET ) + FD_SET( ssdpSock4, &rdSet ); + if( ssdpSock6 != INVALID_SOCKET ) + FD_SET( ssdpSock6, &rdSet ); #ifdef INCLUDE_CLIENT_APIS - FD_SET( ssdpReqSock, &rdSet ); + if( ssdpReqSock4 != INVALID_SOCKET ) + FD_SET( ssdpReqSock4, &rdSet ); + if( ssdpReqSock6 != INVALID_SOCKET ) + FD_SET( ssdpReqSock6, &rdSet ); #endif ret = select( maxMiniSock, &rdSet, NULL, &expSet, NULL ); @@ -426,9 +446,10 @@ RunMiniServer( MiniServerSockArray *miniSock ) isleep( 1 ); continue; } else { - if( FD_ISSET( miniServSock, &rdSet ) ) { - clientLen = sizeof( struct sockaddr_in ); - connectHnd = accept( miniServSock, + if( miniServSock6 != INVALID_SOCKET && + FD_ISSET( miniServSock6, &rdSet ) ) { + clientLen = sizeof( clientAddr ); + connectHnd = accept( miniServSock6, ( struct sockaddr * )&clientAddr, &clientLen ); if( connectHnd == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); @@ -436,29 +457,55 @@ RunMiniServer( MiniServerSockArray *miniSock ) "miniserver: Error in accept(): %s\n", errorBuffer ); continue; } - schedule_request_job( connectHnd, &clientAddr ); + schedule_request_job( connectHnd, (struct sockaddr*)&clientAddr ); + } + if( miniServSock4 != INVALID_SOCKET && + FD_ISSET( miniServSock4, &rdSet ) ) { + clientLen = sizeof( clientAddr ); + connectHnd = accept( miniServSock4, + ( struct sockaddr * )&clientAddr, &clientLen ); + if( connectHnd == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "miniserver: Error in accept(): %s\n", errorBuffer ); + continue; + } + schedule_request_job( connectHnd, (struct sockaddr*)&clientAddr ); } #ifdef INCLUDE_CLIENT_APIS // ssdp - if( FD_ISSET( ssdpReqSock, &rdSet ) ) { - readFromSSDPSocket( ssdpReqSock ); + if( ssdpReqSock6 != INVALID_SOCKET && + FD_ISSET( ssdpReqSock6, &rdSet ) ) { + readFromSSDPSocket( ssdpReqSock6 ); + } + if( ssdpReqSock4 != INVALID_SOCKET && + FD_ISSET( ssdpReqSock4, &rdSet ) ) { + readFromSSDPSocket( ssdpReqSock4 ); } #endif - if( FD_ISSET( ssdpSock, &rdSet ) ) { - readFromSSDPSocket( ssdpSock ); + if( ssdpSock6 != INVALID_SOCKET && + FD_ISSET( ssdpSock6, &rdSet ) ) { + readFromSSDPSocket( ssdpSock6 ); + } + if( ssdpSock4 != INVALID_SOCKET && + FD_ISSET( ssdpSock4, &rdSet ) ) { + readFromSSDPSocket( ssdpSock4 ); } if( FD_ISSET( miniServStopSock, &rdSet ) ) { - clientLen = sizeof( struct sockaddr_in ); - memset( (char *)&clientAddr, 0, sizeof (struct sockaddr_in) ); + clientLen = sizeof( clientAddr ); + memset( (char *)&clientAddr, 0, sizeof(clientAddr) ); byteReceived = recvfrom( miniServStopSock, requestBuf, 25, 0, ( struct sockaddr * )&clientAddr, &clientLen ); if( byteReceived > 0 ) { requestBuf[byteReceived] = '\0'; + inet_ntop(AF_INET, + &((struct sockaddr_in*)&clientAddr)->sin_addr, + buf_ntop, sizeof(buf_ntop) ); UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, "Received response: %s From host %s \n", - requestBuf, inet_ntoa( clientAddr.sin_addr ) ); + requestBuf, buf_ntop ); UpnpPrintf( UPNP_PACKET, MSERV, __FILE__, __LINE__, "Received multicast packet: \n %s\n", requestBuf ); @@ -470,15 +517,21 @@ RunMiniServer( MiniServerSockArray *miniSock ) } } - shutdown( miniServSock, SD_BOTH ); - UpnpCloseSocket( miniServSock ); + shutdown( miniServSock4, SD_BOTH ); + UpnpCloseSocket( miniServSock4 ); + shutdown( miniServSock6, SD_BOTH ); + UpnpCloseSocket( miniServSock6 ); shutdown( miniServStopSock, SD_BOTH ); UpnpCloseSocket( miniServStopSock ); - shutdown( ssdpSock, SD_BOTH ); - UpnpCloseSocket( ssdpSock ); + shutdown( ssdpSock4, SD_BOTH ); + UpnpCloseSocket( ssdpSock4 ); + shutdown( ssdpSock6, SD_BOTH ); + UpnpCloseSocket( ssdpSock6 ); #ifdef INCLUDE_CLIENT_APIS - shutdown( ssdpReqSock, SD_BOTH ); - UpnpCloseSocket( ssdpReqSock ); + shutdown( ssdpReqSock4, SD_BOTH ); + UpnpCloseSocket( ssdpReqSock4 ); + shutdown( ssdpReqSock6, SD_BOTH ); + UpnpCloseSocket( ssdpReqSock6 ); #endif free( miniSock ); @@ -503,18 +556,22 @@ RunMiniServer( MiniServerSockArray *miniSock ) static int get_port( int sockfd ) { - struct sockaddr_in sockinfo; + struct sockaddr_storage sockinfo; socklen_t len; int code; - int port; + int port = 0; - len = sizeof( struct sockaddr_in ); + len = sizeof( sockinfo ); code = getsockname( sockfd, ( struct sockaddr * )&sockinfo, &len ); if( code == -1 ) { return -1; } - port = ntohs( sockinfo.sin_port ); + if( sockinfo.ss_family == AF_INET ) { + port = ntohs( ((struct sockaddr_in*)&sockinfo)->sin_port ); + } else if( sockinfo.ss_family == AF_INET6 ) { + port = ntohs( ((struct sockaddr_in6*)&sockinfo)->sin6_port ); + } UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, "sockfd = %d, .... port = %d\n", sockfd, port ); @@ -526,8 +583,10 @@ get_port( int sockfd ) * * Parameters: * MiniServerSockArray *out - Socket Array - * unsigned short listen_port - port on which the server is - * listening for incoming connections + * unsigned short listen_port4 - port on which the server is + * listening for incoming IPv4 connections + * unsigned short listen_port6 - port on which the server is + * listening for incoming IPv6 connections * * Description: * Creates a STREAM socket, binds to INADDR_ANY and listens for @@ -546,31 +605,47 @@ get_port( int sockfd ) ************************************************************************/ int get_miniserver_sockets( MiniServerSockArray * out, - unsigned short listen_port ) + unsigned short listen_port4, + unsigned short listen_port6 ) { char errorBuffer[ERROR_BUFFER_LEN]; - struct sockaddr_in serverAddr; - int listenfd; - int success; - unsigned short actual_port; + struct sockaddr_storage __ss_v4; + struct sockaddr_storage __ss_v6; + struct sockaddr_in* serverAddr4 = (struct sockaddr_in*)&__ss_v4; + struct sockaddr_in6* serverAddr6 = (struct sockaddr_in6*)&__ss_v6; + SOCKET listenfd4, listenfd6; + int ret_code; + unsigned short actual_port4, actual_port6; int reuseaddr_on = 0; int sockError = UPNP_E_SUCCESS; int errCode = 0; int miniServerStopSock; int ret = 0; - listenfd = socket( AF_INET, SOCK_STREAM, 0 ); - if ( listenfd == -1 ) { - return UPNP_E_OUTOF_SOCKET; // error creating socket + // Create listen socket for IPv4/IPv6. An error here may indicate + // that we don't have an IPv4/IPv6 stack. + listenfd4 = socket( AF_INET, SOCK_STREAM, 0 ); + listenfd6 = socket( AF_INET6, SOCK_STREAM, 0 ); + if (listenfd4 == INVALID_SOCKET || listenfd6 == INVALID_SOCKET) { + return UPNP_E_OUTOF_SOCKET; } + // As per the IANA specifications for the use of ports by applications // override the listen port passed in with the first available - if( listen_port < APPLICATION_LISTENING_PORT ) - listen_port = APPLICATION_LISTENING_PORT; + if (listen_port4 < APPLICATION_LISTENING_PORT) { + listen_port4 = APPLICATION_LISTENING_PORT; + } + if (listen_port6 < APPLICATION_LISTENING_PORT) { + listen_port6 = APPLICATION_LISTENING_PORT; + } - memset( &serverAddr, 0, sizeof( serverAddr ) ); - serverAddr.sin_family = AF_INET; - serverAddr.sin_addr.s_addr = htonl( INADDR_ANY ); + memset( &__ss_v4, 0, sizeof( __ss_v4 ) ); + serverAddr4->sin_family = AF_INET; + serverAddr4->sin_addr.s_addr = htonl( INADDR_ANY ); + + memset( &__ss_v6, 0, sizeof( __ss_v6 ) ); + serverAddr6->sin6_family = AF_INET6; + serverAddr6->sin6_addr = in6addr_any; // Getting away with implementation of re-using address:port and instead // choosing to increment port numbers. @@ -583,95 +658,211 @@ get_miniserver_sockets( MiniServerSockArray * out, // THIS MAY CAUSE TCP TO BECOME LESS RELIABLE // HOWEVER IT HAS BEEN SUGESTED FOR TCP SERVERS UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "mserv start: resuseaddr set\n" ); - sockError = setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR, - (const char *)&reuseaddr_on, sizeof (int) ); - if ( sockError == -1 ) { - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); + "get_miniserver_sockets: resuseaddr set\n" ); - return UPNP_E_SOCKET_BIND; + if( listenfd4 != INVALID_SOCKET ) { + sockError = setsockopt( listenfd4, SOL_SOCKET, SO_REUSEADDR, + (const char *)&reuseaddr_on, sizeof (int) ); + if ( sockError == -1 ) { + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); + + return UPNP_E_SOCKET_BIND; + } + + sockError = bind( listenfd4, (struct sockaddr *)&__ss_v4, + sizeof(__ss_v4) ); + if ( sockError == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "get_miniserver_sockets: Error in IPv4 bind(): %s\n", + errorBuffer ); + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); + + return UPNP_E_SOCKET_BIND; // bind failed + } } - sockError = bind( listenfd, (struct sockaddr *)&serverAddr, - sizeof (struct sockaddr_in) ); - } else { - do { - serverAddr.sin_port = htons( listen_port++ ); - sockError = bind( listenfd, (struct sockaddr *)&serverAddr, - sizeof (struct sockaddr_in) ); + if( listenfd6 != INVALID_SOCKET ) { + sockError = setsockopt( listenfd6, SOL_SOCKET, SO_REUSEADDR, + (const char *)&reuseaddr_on, sizeof (int) ); if ( sockError == -1 ) { + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); + + return UPNP_E_SOCKET_BIND; + } + + sockError = bind( listenfd6, (struct sockaddr *)&__ss_v6, + sizeof(__ss_v6) ); + if ( sockError == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "get_miniserver_sockets: Error in IPv6 bind(): %s\n", + errorBuffer ); + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); + + return UPNP_E_SOCKET_BIND; // bind failed + } + } + } else { + if( listenfd4 != INVALID_SOCKET ) { + do { + serverAddr4->sin_port = htons( listen_port4++ ); + sockError = bind( listenfd4, (struct sockaddr *)&__ss_v4, + sizeof(__ss_v4) ); + if ( sockError == -1 ) { #ifdef WIN32 - errCode = WSAGetLastError(); + errCode = WSAGetLastError(); #else - errCode = errno; + errCode = errno; #endif - if( errno == EADDRINUSE ) { - errCode = 1; - } - } else - errCode = 0; + if( errno == EADDRINUSE ) { + errCode = 1; + } + } else + errCode = 0; + } while ( errCode != 0 ); + if ( sockError == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "get_miniserver_sockets: Error in IPv4 bind(): %s\n", + errorBuffer ); + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); - } while ( errCode != 0 ); - } + return UPNP_E_SOCKET_BIND; // bind failed + } + } - if ( sockError == -1 ) { - strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "mserv start: Error in bind(): %s\n", errorBuffer ); - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); + if( listenfd6 != INVALID_SOCKET ) { + do { + serverAddr4->sin_port = htons( listen_port6++ ); + sockError = bind( listenfd6, (struct sockaddr *)&__ss_v4, + sizeof(__ss_v4) ); + if ( sockError == -1 ) { +#ifdef WIN32 + errCode = WSAGetLastError(); +#else + errCode = errno; +#endif + if( errno == EADDRINUSE ) { + errCode = 1; + } + } else + errCode = 0; + } while ( errCode != 0 ); + if ( sockError == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "get_miniserver_sockets: Error in IPv6 bind(): %s\n", + errorBuffer ); + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); - return UPNP_E_SOCKET_BIND; // bind failed + return UPNP_E_SOCKET_BIND; // bind failed + } + } } UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "mserv start: bind success\n" ); + "get_miniserver_sockets: bind successful\n" ); - success = listen( listenfd, SOMAXCONN ); - if ( success == -1 ) { - strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); - UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, - "mserv start: Error in listen(): %s\n", errorBuffer ); - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); + if( listenfd4 != INVALID_SOCKET ) { + ret_code = listen( listenfd4, SOMAXCONN ); + if ( ret_code == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "mserv start: Error in IPv4 listen(): %s\n", errorBuffer ); + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); - return UPNP_E_LISTEN; + return UPNP_E_LISTEN; + } + + actual_port4 = get_port( listenfd4 ); + if( actual_port4 <= 0 ) { + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); + + return UPNP_E_INTERNAL_ERROR; + } + + out->miniServerPort4 = actual_port4; } - actual_port = get_port( listenfd ); - if( actual_port <= 0 ) { - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); + if( listenfd6 != INVALID_SOCKET ) { + ret_code = listen( listenfd6, SOMAXCONN ); + if ( ret_code == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__, + "mserv start: Error in IPv6 listen(): %s\n", errorBuffer ); + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); - return UPNP_E_INTERNAL_ERROR; + return UPNP_E_LISTEN; + } + + actual_port6 = get_port( listenfd6 ); + if( actual_port6 <= 0 ) { + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); + + return UPNP_E_INTERNAL_ERROR; + } + + out->miniServerPort6 = actual_port6; } - out->miniServerPort = actual_port; - miniServerStopSock = socket( AF_INET, SOCK_DGRAM, 0 ); if ( miniServerStopSock == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__, "Error in socket(): %s\n", errorBuffer ); - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); return UPNP_E_OUTOF_SOCKET; } // bind to local socket - memset( ( char * )&serverAddr, 0, sizeof( struct sockaddr_in ) ); - serverAddr.sin_family = AF_INET; - serverAddr.sin_addr.s_addr = inet_addr( "127.0.0.1" ); - ret = bind( miniServerStopSock, (struct sockaddr *)&serverAddr, - sizeof (serverAddr) ); + memset( &__ss_v4, 0, sizeof( __ss_v4 ) ); + serverAddr4->sin_family = AF_INET; + serverAddr4->sin_addr.s_addr = inet_addr( "127.0.0.1" ); + ret = bind( miniServerStopSock, (struct sockaddr *)&__ss_v4, + sizeof(__ss_v4) ); if ( ret == -1 ) { UpnpPrintf( UPNP_CRITICAL, MSERV, __FILE__, __LINE__, "Error in binding localhost!!!\n" ); - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); shutdown( miniServerStopSock, SD_BOTH ); UpnpCloseSocket( miniServerStopSock ); @@ -682,14 +873,17 @@ get_miniserver_sockets( MiniServerSockArray * out, if ( miniStopSockPort <= 0 ) { shutdown( miniServerStopSock, SD_BOTH ); UpnpCloseSocket( miniServerStopSock ); - shutdown( listenfd, SD_BOTH ); - UpnpCloseSocket( listenfd ); + shutdown( listenfd4, SD_BOTH ); + UpnpCloseSocket( listenfd4 ); + shutdown( listenfd6, SD_BOTH ); + UpnpCloseSocket( listenfd6 ); return UPNP_E_INTERNAL_ERROR; } out->stopPort = miniStopSockPort; - out->miniServerSock = listenfd; + out->miniServerSock4 = listenfd4; + out->miniServerSock6 = listenfd6; out->miniServerStopSock = miniServerStopSock; return UPNP_E_SUCCESS; @@ -698,27 +892,29 @@ get_miniserver_sockets( MiniServerSockArray * out, /************************************************************************ * Function: StartMiniServer * - * Parameters : - * unsigned short listen_port - Port on which the server listens for - * incoming connections + * Parameters: + * IN OUT unsigned short *listen_port4 ; Port on which the server + * listens for incoming IPv4 connections. + * IN OUT unsigned short *listen_port6 ; Port on which the server + * listens for incoming IPv6 connections. * - * Description: - * Initialize the sockets functionality for the + * Description: Initialize the sockets functionality for the * Miniserver. Initialize a thread pool job to run the MiniServer * and the job to the thread pool. If listen port is 0, port is * dynamically picked * - * Use timer mechanism to start the MiniServer, failure to meet the + * Use timer mechanism to start the MiniServer, failure to meet the * allowed delay aborts the attempt to launch the MiniServer. * - * Return: int - * Actual port socket is bound to - On Success - * A negative number UPNP_E_XXX - On Error + * Return: int; + * On success: UPNP_E_SUCCESS + * On error: PNP_E_XXX ************************************************************************/ int -StartMiniServer( unsigned short listen_port ) +StartMiniServer( unsigned short* listen_port4, + unsigned short* listen_port6 ) { - int success; + int ret_code; int count; int max_count = 10000; @@ -733,39 +929,48 @@ StartMiniServer( unsigned short listen_port ) if( miniSocket == NULL ) { return UPNP_E_OUTOF_MEMORY; } + memset( miniSocket, 0, sizeof(*miniSocket) ); - success = get_miniserver_sockets( miniSocket, listen_port ); - if( success != UPNP_E_SUCCESS ) { + ret_code = get_miniserver_sockets( miniSocket, *listen_port4, *listen_port6 ); + if( ret_code != UPNP_E_SUCCESS ) { free( miniSocket ); - return success; + return ret_code; } - success = get_ssdp_sockets( miniSocket ); - if( success != UPNP_E_SUCCESS ) { - shutdown( miniSocket->miniServerSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->miniServerSock ); + ret_code = get_ssdp_sockets( miniSocket ); + if( ret_code != UPNP_E_SUCCESS ) { + shutdown( miniSocket->miniServerSock4, SD_BOTH ); + UpnpCloseSocket( miniSocket->miniServerSock4 ); + shutdown( miniSocket->miniServerSock6, SD_BOTH ); + UpnpCloseSocket( miniSocket->miniServerSock6 ); shutdown( miniSocket->miniServerStopSock, SD_BOTH ); UpnpCloseSocket( miniSocket->miniServerStopSock ); free( miniSocket ); - return success; + return ret_code; } TPJobInit( &job, (start_routine)RunMiniServer, (void *)miniSocket ); TPJobSetPriority( &job, MED_PRIORITY ); TPJobSetFreeFunction( &job, ( free_routine ) free ); - success = ThreadPoolAddPersistent( &gMiniServerThreadPool, &job, NULL ); - if ( success < 0 ) { - shutdown( miniSocket->miniServerSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->miniServerSock ); + ret_code = ThreadPoolAddPersistent( &gMiniServerThreadPool, &job, NULL ); + if ( ret_code < 0 ) { + shutdown( miniSocket->miniServerSock4, SD_BOTH ); + UpnpCloseSocket( miniSocket->miniServerSock4 ); + shutdown( miniSocket->miniServerSock6, SD_BOTH ); + UpnpCloseSocket( miniSocket->miniServerSock6 ); shutdown( miniSocket->miniServerStopSock, SD_BOTH ); UpnpCloseSocket( miniSocket->miniServerStopSock ); - shutdown( miniSocket->ssdpSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->ssdpSock ); + shutdown( miniSocket->ssdpSock4, SD_BOTH ); + UpnpCloseSocket( miniSocket->ssdpSock4 ); + shutdown( miniSocket->ssdpSock6, SD_BOTH ); + UpnpCloseSocket( miniSocket->ssdpSock6 ); #ifdef INCLUDE_CLIENT_APIS - shutdown( miniSocket->ssdpReqSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->ssdpReqSock ); + shutdown( miniSocket->ssdpReqSock4, SD_BOTH ); + UpnpCloseSocket( miniSocket->ssdpReqSock4 ); + shutdown( miniSocket->ssdpReqSock6, SD_BOTH ); + UpnpCloseSocket( miniSocket->ssdpReqSock6 ); #endif return UPNP_E_OUTOF_MEMORY; @@ -779,21 +984,29 @@ StartMiniServer( unsigned short listen_port ) // taking too long to start that thread if ( count >= max_count ) { - shutdown( miniSocket->miniServerSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->miniServerSock ); + shutdown( miniSocket->miniServerSock4, SD_BOTH ); + UpnpCloseSocket( miniSocket->miniServerSock4 ); + shutdown( miniSocket->miniServerSock6, SD_BOTH ); + UpnpCloseSocket( miniSocket->miniServerSock6 ); shutdown( miniSocket->miniServerStopSock, SD_BOTH ); UpnpCloseSocket( miniSocket->miniServerStopSock ); - shutdown( miniSocket->ssdpSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->ssdpSock ); + shutdown( miniSocket->ssdpSock4, SD_BOTH ); + UpnpCloseSocket( miniSocket->ssdpSock4 ); + shutdown( miniSocket->ssdpSock6, SD_BOTH ); + UpnpCloseSocket( miniSocket->ssdpSock6 ); #ifdef INCLUDE_CLIENT_APIS - shutdown( miniSocket->ssdpReqSock, SD_BOTH ); - UpnpCloseSocket( miniSocket->ssdpReqSock ); + shutdown( miniSocket->ssdpReqSock4, SD_BOTH ); + UpnpCloseSocket( miniSocket->ssdpReqSock4 ); + shutdown( miniSocket->ssdpReqSock6, SD_BOTH ); + UpnpCloseSocket( miniSocket->ssdpReqSock6 ); #endif return UPNP_E_INTERNAL_ERROR; } + *listen_port4 = miniSocket->miniServerPort4; + *listen_port6 = miniSocket->miniServerPort6; - return miniSocket->miniServerPort; + return UPNP_E_SUCCESS; } /************************************************************************ @@ -814,7 +1027,7 @@ StopMiniServer() { char errorBuffer[ERROR_BUFFER_LEN]; int socklen = sizeof( struct sockaddr_in ); - int sock; + SOCKET sock; struct sockaddr_in ssdpAddr; char buf[256] = "ShutDown"; int bufLen = strlen( buf ); diff --git a/upnp/src/genlib/net/http/httpreadwrite.c b/upnp/src/genlib/net/http/httpreadwrite.c index 46f3c71..e3ca4a2 100644 --- a/upnp/src/genlib/net/http/httpreadwrite.c +++ b/upnp/src/genlib/net/http/httpreadwrite.c @@ -175,13 +175,13 @@ http_Connect( IN uri_type * destination_url, http_FixUrl( destination_url, url ); - connfd = socket( AF_INET, SOCK_STREAM, 0 ); + connfd = socket( url->hostport.IPaddress.ss_family, SOCK_STREAM, 0 ); if( connfd == -1 ) { return UPNP_E_OUTOF_SOCKET; } - if( connect( connfd, ( struct sockaddr * )&url->hostport.IPv4address, - sizeof( struct sockaddr_in ) ) == -1 ) { + if( connect( connfd, ( struct sockaddr * )&url->hostport.IPaddress, + sizeof( url->hostport.IPaddress ) ) == -1 ) { #ifdef WIN32 UpnpPrintf(UPNP_CRITICAL, HTTP, __FILE__, __LINE__, "connect error: %d\n", WSAGetLastError()); @@ -521,7 +521,7 @@ http_RequestAndResponse( IN uri_type * destination, int http_error_code; SOCKINFO info; - tcp_connection = socket( AF_INET, SOCK_STREAM, 0 ); + tcp_connection = socket( destination->hostport.IPaddress.ss_family, SOCK_STREAM, 0 ); if( tcp_connection == -1 ) { parser_response_init( response, req_method ); return UPNP_E_SOCKET_ERROR; @@ -535,7 +535,7 @@ http_RequestAndResponse( IN uri_type * destination, // connect ret_code = connect( info.socket, ( struct sockaddr * )&destination->hostport. - IPv4address, sizeof( struct sockaddr_in ) ); + IPaddress, sizeof( struct sockaddr_storage ) ); if( ret_code == -1 ) { sock_destroy( &info, SD_BOTH ); @@ -1005,7 +1005,7 @@ http_OpenHttpPost( IN const char *url_str, handle->contentLength = contentLength; - tcp_connection = socket( AF_INET, SOCK_STREAM, 0 ); + tcp_connection = socket( url.hostport.IPaddress.ss_family, SOCK_STREAM, 0 ); if( tcp_connection == -1 ) { ret_code = UPNP_E_SOCKET_ERROR; goto errorHandler; @@ -1019,8 +1019,8 @@ http_OpenHttpPost( IN const char *url_str, } ret_code = connect( handle->sock_info.socket, - ( struct sockaddr * )&url.hostport.IPv4address, - sizeof( struct sockaddr_in ) ); + ( struct sockaddr * )&url.hostport.IPaddress, + sizeof( struct sockaddr_storage ) ); if( ret_code == -1 ) { sock_destroy( &handle->sock_info, SD_BOTH ); @@ -1587,7 +1587,7 @@ http_OpenHttpGetProxy( IN const char *url_str, handle->cancel = 0; parser_response_init( &handle->response, HTTPMETHOD_GET ); - tcp_connection = socket( AF_INET, SOCK_STREAM, 0 ); + tcp_connection = socket( peer->hostport.IPaddress.ss_family, SOCK_STREAM, 0 ); if( tcp_connection == -1 ) { ret_code = UPNP_E_SOCKET_ERROR; goto errorHandler; @@ -1601,8 +1601,8 @@ http_OpenHttpGetProxy( IN const char *url_str, } ret_code = connect( handle->sock_info.socket, - ( struct sockaddr * )&peer->hostport.IPv4address, - sizeof( struct sockaddr_in ) ); + ( struct sockaddr * )&peer->hostport.IPaddress, + sizeof( struct sockaddr_storage ) ); if( ret_code == -1 ) { sock_destroy( &handle->sock_info, SD_BOTH ); @@ -2236,7 +2236,7 @@ http_OpenHttpGetEx( IN const char *url_str, handle->entity_offset = 0; parser_response_init( &handle->response, HTTPMETHOD_GET ); - tcp_connection = socket( AF_INET, SOCK_STREAM, 0 ); + tcp_connection = socket( url.hostport.IPaddress.ss_family, SOCK_STREAM, 0 ); if( tcp_connection == -1 ) { errCode = UPNP_E_SOCKET_ERROR; free( handle ); @@ -2252,8 +2252,8 @@ http_OpenHttpGetEx( IN const char *url_str, } errCode = connect( handle->sock_info.socket, - ( struct sockaddr * )&url.hostport.IPv4address, - sizeof( struct sockaddr_in ) ); + ( struct sockaddr * )&url.hostport.IPaddress, + sizeof( struct sockaddr_storage ) ); if( errCode == -1 ) { sock_destroy( &handle->sock_info, SD_BOTH ); errCode = UPNP_E_SOCKET_CONNECT; diff --git a/upnp/src/genlib/net/sock.c b/upnp/src/genlib/net/sock.c index 1af6ee8..58bdec7 100644 --- a/upnp/src/genlib/net/sock.c +++ b/upnp/src/genlib/net/sock.c @@ -62,7 +62,7 @@ * * Parameters : * OUT SOCKINFO* info ; Socket Information Object -* IN int sockfd ; Socket Descriptor +* IN SOCKET sockfd ; Socket Descriptor * * Description : Assign the passed in socket descriptor to socket * descriptor in the SOCKINFO structure. @@ -76,7 +76,7 @@ ************************************************************************/ int sock_init( OUT SOCKINFO * info, - IN int sockfd ) + IN SOCKET sockfd ) { assert( info ); @@ -91,10 +91,9 @@ sock_init( OUT SOCKINFO * info, * Function : sock_init_with_ip * * Parameters : -* OUT SOCKINFO* info ; Socket Information Object -* IN int sockfd ; Socket Descriptor -* IN struct in_addr foreign_ip_addr ; Remote IP Address -* IN unsigned short foreign_ip_port ; Remote Port number +* OUT SOCKINFO* info ; Socket Information Object +* IN SOCKET sockfd ; Socket Descriptor +* IN struct sockaddr* foreign_sockaddr; remote socket address. * * Description : Calls the sock_init function and assigns the passed in * IP address and port to the IP address and port in the SOCKINFO @@ -109,9 +108,8 @@ sock_init( OUT SOCKINFO * info, ************************************************************************/ int sock_init_with_ip( OUT SOCKINFO * info, - IN int sockfd, - IN struct in_addr foreign_ip_addr, - IN unsigned short foreign_ip_port ) + IN SOCKET sockfd, + IN struct sockaddr* foreign_sockaddr ) { int ret; @@ -120,8 +118,8 @@ sock_init_with_ip( OUT SOCKINFO * info, return ret; } - info->foreign_ip_addr = foreign_ip_addr; - info->foreign_ip_port = foreign_ip_port; + memcpy( &info->foreign_sockaddr, foreign_sockaddr, + sizeof( info->foreign_sockaddr) ); return UPNP_E_SUCCESS; } @@ -149,9 +147,11 @@ int sock_destroy( INOUT SOCKINFO * info, int ShutdownMethod ) { - shutdown( info->socket, ShutdownMethod ); - if( UpnpCloseSocket( info->socket ) == -1 ) { - return UPNP_E_SOCKET_ERROR; + if( info->socket != INVALID_SOCKET ) { + shutdown( info->socket, ShutdownMethod ); + if( UpnpCloseSocket( info->socket ) == -1 ) { + return UPNP_E_SOCKET_ERROR; + } } return UPNP_E_SUCCESS; @@ -190,7 +190,7 @@ sock_read_write( IN SOCKINFO * info, struct timeval timeout; int numBytes; time_t start_time = time( NULL ); - int sockfd = info->socket; + SOCKET sockfd = info->socket; long bytes_sent = 0, byte_left = 0, num_written; @@ -202,9 +202,9 @@ sock_read_write( IN SOCKINFO * info, FD_ZERO( &readSet ); FD_ZERO( &writeSet ); if( bRead ) { - FD_SET( ( unsigned )sockfd, &readSet ); + FD_SET( sockfd, &readSet ); } else { - FD_SET( ( unsigned )sockfd, &writeSet ); + FD_SET( sockfd, &writeSet ); } timeout.tv_sec = *timeoutSecs; diff --git a/upnp/src/genlib/net/uri/uri.c b/upnp/src/genlib/net/uri/uri.c index a11cf19..311f907 100644 --- a/upnp/src/genlib/net/uri/uri.c +++ b/upnp/src/genlib/net/uri/uri.c @@ -41,10 +41,7 @@ #endif #include "config.h" #include "uri.h" - -#ifdef WIN32 - #include "inet_pton.h" -#endif +#include "upnpapi.h" /************************************************************************ @@ -224,28 +221,6 @@ parse_uric( const char *in, return i; } -/************************************************************************ -* Function : copy_sockaddr_in -* -* Parameters : -* const struct sockaddr_in *in ; Source socket address object -* struct sockaddr_in *out ; Destination socket address object -* -* Description : Copies one socket address into another -* -* Return : void ; -* -* Note : -************************************************************************/ -void -copy_sockaddr_in( const struct sockaddr_in *in, - struct sockaddr_in *out ) -{ - memset( out->sin_zero, 0, 8 ); - out->sin_family = in->sin_family; - out->sin_port = in->sin_port; - out->sin_addr.s_addr = in->sin_addr.s_addr; -} /************************************************************************ * Function : copy_token @@ -328,8 +303,9 @@ copy_URL_list( URL_list * in, in->URLs, &out->parsedURLs[i].hostport.text, out->URLs ); - copy_sockaddr_in( &in->parsedURLs[i].hostport.IPv4address, - &out->parsedURLs[i].hostport.IPv4address ); + memcpy( &out->parsedURLs[i].hostport.IPaddress, + &in->parsedURLs[i].hostport.IPaddress, + sizeof(struct sockaddr_storage) ); } out->size = in->size; return HTTP_SUCCESS; @@ -490,48 +466,13 @@ token_cmp( token * in1, return memcmp( in1->buff, in2->buff, in1->size ); } -/************************************************************************ -* Function : parse_port -* -* Parameters : -* int max ; sets a maximum limit -* char * port ; port to be parsed. -* unsigned short * out ; out parameter where the port is parsed -* and converted into network format -* -* Description : parses a port (i.e. '4000') and converts it into a -* network ordered unsigned short int. -* -* Return : int ; -* -* Note : -************************************************************************/ -int -parse_port( int max, - const char *port, - unsigned short *out ) -{ - - const char *finger = port; - const char *max_ptr = finger + max; - unsigned short temp = 0; - - while( ( finger < max_ptr ) && ( isdigit( *finger ) ) ) { - temp = temp * 10; - temp += ( *finger ) - '0'; - finger++; - } - - *out = htons( temp ); - return finger - port; -} /************************************************************************ * Function : parse_hostport * * Parameters : * char *in ; string of characters representing host and port -* int max ; sets a maximum limit +* int max ; sets a maximum limit (not used). * hostport_type *out ; out parameter where the host and port * are represented as an internet address * @@ -540,7 +481,8 @@ parse_port( int max, * hostport_type struct with internet address and a token * representing the full host and port. uses gethostbyname. * -* Return : int ; +* Returns: The number of characters that form up the host and port. +* UPNP_E_INVALID_URL on error. * * Note : ************************************************************************/ @@ -549,165 +491,145 @@ parse_hostport( const char *in, int max, hostport_type * out ) { -#define BUFFER_SIZE 8192 + char workbuf[256]; + char* c; + struct sockaddr_in* sai4 = (struct sockaddr_in*)&out->IPaddress; + struct sockaddr_in6* sai6 = (struct sockaddr_in6*)&out->IPaddress; + char *srvname = NULL; + char *srvport = NULL; + char *last_dot = NULL; + unsigned short int port; + int af = AF_UNSPEC; + int hostport_size; + int has_port = 0; + int ret; - int i = 0; - int begin_port; - int hostport_size = 0; - int host_size = 0; -#if !defined(WIN32) && !(defined(__OSX__) || defined(__APPLE__)) - char temp_hostbyname_buff[BUFFER_SIZE]; - struct hostent h_buf; -#endif - struct hostent *h = NULL; - int errcode = 0; - char *temp_host_name = NULL; - int last_dot = -1; + memset( out, 0, sizeof(hostport_type) ); - out->text.size = 0; - out->text.buff = NULL; + // Work on a copy of the input string. + strncpy( workbuf, in, sizeof(workbuf) ); - out->IPv4address.sin_port = htons( 80 ); //default port is 80 - memset( &out->IPv4address.sin_zero, 0, 8 ); - - while( ( i < max ) && ( in[i] != ':' ) && ( in[i] != '/' ) - && ( ( isalnum( in[i] ) ) || ( in[i] == '.' ) - || ( in[i] == '-' ) ) ) { - i++; - if( in[i] == '.' ) { - last_dot = i; + c = workbuf; + if( *c == '[' ) { + // IPv6 addresses are enclosed in square brackets. + srvname = ++c; + while( *c != '\0' && *c != ']' ) { + c++; } + if( *c == '\0' ) { + // did not find closing bracket. + return UPNP_E_INVALID_URL; + } + // NULL terminate the srvname and then increment c. + *c++ = '\0'; // overwrite the ']' + if( *c == ':' ) { + has_port = 1; + c++; + } + af = AF_INET6; } - - host_size = i; - - if( ( i < max ) && ( in[i] == ':' ) ) { - begin_port = i + 1; - //convert port - if( !( hostport_size = parse_port( max - begin_port, - &in[begin_port], - &out->IPv4address.sin_port ) ) ) - { - return UPNP_E_INVALID_URL; + else { + // IPv4 address -OR- host name. + srvname = c; + while( (*c != ':') && (*c != '/') && ( (isalnum(*c)) || (*c == '.') || (*c == '-') ) ) { + if( *c == '.' ) + last_dot = c; + c++; } - hostport_size += begin_port; - } else - hostport_size = host_size; + has_port = (*c == ':') ? 1 : 0; + // NULL terminate the srvname + *c = '\0'; + if( has_port == 1 ) + c++; - //convert to temporary null terminated string - temp_host_name = ( char * )malloc( host_size + 1 ); - - if( temp_host_name == NULL ) - return UPNP_E_OUTOF_MEMORY; - - memcpy( temp_host_name, in, host_size ); - temp_host_name[host_size] = '\0'; - - //check to see if host name is an ipv4 address - if( ( last_dot != -1 ) && ( last_dot + 1 < host_size ) - && ( isdigit( temp_host_name[last_dot + 1] ) ) ) { - //must be ipv4 address - - errcode = inet_pton( AF_INET, - temp_host_name, &out->IPv4address.sin_addr ); - if( errcode == 1 ) { - out->IPv4address.sin_family = AF_INET; - } else { - out->IPv4address.sin_addr.s_addr = 0; - out->IPv4address.sin_family = AF_INET; - free( temp_host_name ); - temp_host_name = NULL; - return UPNP_E_INVALID_URL; + if( last_dot != NULL && isdigit(*(last_dot+1)) ) { + // Must be an IPv4 address. + af = AF_INET; } - } else { - int errCode = 0; + else { + // Must be a host name. + struct addrinfo hints, *res, *res0; - //call gethostbyname_r (reentrant form of gethostbyname) - // TODO: Use autoconf to discover this rather than the - // platform-specific stuff below -#if defined(WIN32) || defined(__CYGWIN__) - h = gethostbyname(temp_host_name); -#elif defined(SPARC_SOLARIS) - errCode = gethostbyname_r( - temp_host_name, - &h, - temp_hostbyname_buff, - BUFFER_SIZE, &errcode ); -#elif defined(__FreeBSD__) && __FreeBSD_version < 601103 - h = lwres_gethostbyname_r( - temp_host_name, - &h_buf, - temp_hostbyname_buff, - BUFFER_SIZE, &errcode ); - if ( h == NULL ) { - errCode = 1; - } -#elif defined(__OSX__) || defined(__APPLE__) - h = gethostbyname(temp_host_name); - if ( h == NULL ) { - errCode = 1; - } -#elif defined(__linux__) - errCode = gethostbyname_r( - temp_host_name, - &h_buf, - temp_hostbyname_buff, - BUFFER_SIZE, &h, &errcode ); -#else - { - struct addrinfo hints, *res, *res0; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; - h = NULL; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_INET; - hints.ai_socktype = SOCK_STREAM; - errCode = getaddrinfo(temp_host_name, "http", &hints, &res0); - - if (!errCode) { - for (res = res0; res; res = res->ai_next) { - if (res->ai_family == PF_INET && - res->ai_addr->sa_family == AF_INET) - { - h = &h_buf; - h->h_addrtype = res->ai_addr->sa_family; - h->h_length = 4; - h->h_addr = (void *) temp_hostbyname_buff; - *(struct in_addr *)h->h_addr = - ((struct sockaddr_in *)res->ai_addr)->sin_addr; + ret = getaddrinfo(srvname, NULL, &hints, &res0); + if( ret == 0 ) { + for (res = res0; res; res = res->ai_next) { + if( res->ai_family == AF_INET || + res->ai_family == AF_INET6 ) { + // Found a valid IPv4 or IPv6 address. + memcpy( &out->IPaddress, res->ai_addr, + res->ai_addrlen ); break; + } } - } - freeaddrinfo(res0); - } - } -#endif - if( errCode == 0 ) { - if( h ) { - if( ( h->h_addrtype == AF_INET ) && ( h->h_length == 4 ) ) { - out->IPv4address.sin_addr = - ( *( struct in_addr * )h->h_addr ); - out->IPv4address.sin_family = AF_INET; + freeaddrinfo(res0); + if( res == NULL ) { + // Didn't find an AF_INET or AF_INET6 address. + return UPNP_E_INVALID_URL; } } - } else { - out->IPv4address.sin_addr.s_addr = 0; - out->IPv4address.sin_family = AF_INET; - free( temp_host_name ); - temp_host_name = NULL; - return UPNP_E_INVALID_URL; + else { + // getaddrinfo failed. + return UPNP_E_INVALID_URL; + } } } - if( temp_host_name ) { - free( temp_host_name ); - temp_host_name = NULL; + // Check if a port is specified. + if( has_port == 1 ) { + // Port is specified. + srvport = c; + while( *c != '\0' && isdigit(*c) ) { + c++; + } + port = (unsigned short int)atoi(srvport); + if( port == 0 ) { + // Bad port number. + return UPNP_E_INVALID_URL; + } + } + else { + // Port was not specified, use default port. + port = 80; + } + + // The length of the host and port string can be calculated by + // subtracting pointers. + hostport_size = (int)(c - workbuf); + + // Fill in the 'out' information. + if( af == AF_INET ) { + sai4->sin_family = AF_INET; + sai4->sin_port = htons(port); + ret = inet_pton(AF_INET, srvname, &sai4->sin_addr); + } + else if( af == AF_INET6 ) { + sai6->sin6_family = AF_INET6; + sai6->sin6_port = htons(port); + sai6->sin6_scope_id = gIF_INDEX; + ret = inet_pton(AF_INET6, srvname, &sai6->sin6_addr); + } else { + // IP address was set by the hostname (getaddrinfo). + // Override port: + if( out->IPaddress.ss_family == AF_INET ) + sai4->sin_port = htons(port); + else + sai6->sin6_port = htons(port); + ret = 1; + } + + // Check if address was converted successfully. + if( ret <= 0 ) { + return UPNP_E_INVALID_URL; } out->text.size = hostport_size; out->text.buff = in; return hostport_size; - } /************************************************************************ @@ -1069,10 +991,7 @@ parse_uri( const char *in, return begin_path; } else { - out->hostport.IPv4address.sin_port = 0; - out->hostport.IPv4address.sin_addr.s_addr = 0; - out->hostport.text.size = 0; - out->hostport.text.buff = 0; + memset( &out->hostport, 0, sizeof(out->hostport) ); begin_path = begin_hostport; } diff --git a/upnp/src/inc/http_client.h b/upnp/src/inc/http_client.h index 1f45073..203770f 100644 --- a/upnp/src/inc/http_client.h +++ b/upnp/src/inc/http_client.h @@ -106,7 +106,7 @@ typedef struct TOKEN { //the full string representation typedef struct HOSTPORT { token text; //full host port - struct sockaddr_in IPv4address; //Network Byte Order + struct sockaddr_storage IPaddress; //Network Byte Order } hostport_type; //Represents a URI diff --git a/upnp/src/inc/miniserver.h b/upnp/src/inc/miniserver.h index ab1229a..2b82ba3 100644 --- a/upnp/src/inc/miniserver.h +++ b/upnp/src/inc/miniserver.h @@ -42,17 +42,21 @@ extern SOCKET gMiniServerStopSock; typedef struct MServerSockArray { /* socket for listening for miniserver requests */ - int miniServerSock; + SOCKET miniServerSock4; + SOCKET miniServerSock6; /* socket for stopping miniserver */ - int miniServerStopSock; + SOCKET miniServerStopSock; /* socket for incoming advertisments and search requests */ - int ssdpSock; + SOCKET ssdpSock4; + SOCKET ssdpSock6; - int stopPort; - int miniServerPort; + SOCKET stopPort; + SOCKET miniServerPort4; + SOCKET miniServerPort6; /* socket for sending search requests and receiving search replies */ - CLIENTONLY(int ssdpReqSock;) + CLIENTONLY(SOCKET ssdpReqSock4;) + CLIENTONLY(SOCKET ssdpReqSock6;) } MiniServerSockArray; @@ -110,8 +114,10 @@ void SetGenaCallback( MiniServerCallback callback ); * Function: StartMiniServer * * Parameters: - * unsigned short listen_port ; Port on which the server listens for - * incoming connections + * IN OUT unsigned short *listen_port4 ; Port on which the server + * listens for incoming IPv4 connections. + * IN OUT unsigned short *listen_port6 ; Port on which the server + * listens for incoming IPv6 connections. * * Description: Initialize the sockets functionality for the * Miniserver. Initialize a thread pool job to run the MiniServer @@ -122,10 +128,11 @@ void SetGenaCallback( MiniServerCallback callback ); * allowed delay aborts the attempt to launch the MiniServer. * * Return: int; - * Actual port socket is bound to - On Success: - * A negative number UPNP_E_XXX - On Error + * On success: UPNP_E_SUCCESS + * On error: UPNP_E_XXX ************************************************************************/ -int StartMiniServer( unsigned short listen_port ); +int StartMiniServer( IN OUT unsigned short* listen_port4, + IN OUT unsigned short* listen_port6 ); /************************************************************************ * Function: StopMiniServer diff --git a/upnp/src/inc/sock.h b/upnp/src/inc/sock.h index d7ee596..d83e3a1 100644 --- a/upnp/src/inc/sock.h +++ b/upnp/src/inc/sock.h @@ -48,11 +48,10 @@ typedef struct { - int socket; // handle/descriptor to a socket + SOCKET socket; // handle/descriptor to a socket // the following two fields are filled only in incoming requests; - struct in_addr foreign_ip_addr; - unsigned short foreign_ip_port; + struct sockaddr_storage foreign_sockaddr; } SOCKINFO; @@ -65,7 +64,7 @@ typedef struct * * Parameters : * OUT SOCKINFO* info ; Socket Information Object -* IN int sockfd ; Socket Descriptor +* IN SOCKET sockfd ; Socket Descriptor * * Description : Assign the passed in socket descriptor to socket * descriptor in the SOCKINFO structure. @@ -76,16 +75,15 @@ typedef struct * UPNP_E_SOCKET_ERROR * Note : ************************************************************************/ -int sock_init( OUT SOCKINFO* info, IN int sockfd ); +int sock_init(OUT SOCKINFO* info, IN SOCKET sockfd); /************************************************************************ * Function : sock_init_with_ip * * Parameters : -* OUT SOCKINFO* info ; Socket Information Object -* IN int sockfd ; Socket Descriptor -* IN struct in_addr foreign_ip_addr ; Remote IP Address -* IN unsigned short foreign_ip_port ; Remote Port number +* OUT SOCKINFO* info ; Socket Information Object +* IN SOCKET sockfd ; Socket Descriptor +* IN struct sockaddr* foreign_sockaddr; Remote socket address * * Description : Calls the sock_init function and assigns the passed in * IP address and port to the IP address and port in the SOCKINFO @@ -98,8 +96,10 @@ int sock_init( OUT SOCKINFO* info, IN int sockfd ); * * Note : ************************************************************************/ -int sock_init_with_ip( OUT SOCKINFO* info, IN int sockfd, - IN struct in_addr foreign_ip_addr, IN unsigned short foreign_ip_port ); +int sock_init_with_ip( + OUT SOCKINFO* info, + IN SOCKET sockfd, + IN struct sockaddr *foreign_sockaddr); /************************************************************************ * Function : sock_read @@ -162,7 +162,7 @@ int sock_write( IN SOCKINFO *info, IN char* buffer, IN size_t bufsize, * * Note : ************************************************************************/ -int sock_destroy( INOUT SOCKINFO* info,int ); +int sock_destroy(INOUT SOCKINFO* info, int); #ifdef __cplusplus } // #extern "C" diff --git a/upnp/src/inc/ssdplib.h b/upnp/src/inc/ssdplib.h index 4ef927a..8a017d3 100644 --- a/upnp/src/inc/ssdplib.h +++ b/upnp/src/inc/ssdplib.h @@ -78,6 +78,7 @@ typedef enum SsdpCmdType{SSDP_ERROR=-1, //Constant #define BUFSIZE 2500 #define SSDP_IP "239.255.255.250" +#define SSDP_IPV6_LINKLOCAL "FF02::C" #define SSDP_PORT 1900 #define NUM_TRY 3 #define NUM_COPY 1 @@ -121,7 +122,7 @@ typedef struct SsdpEventStruct char Os[LINE_SIZE]; char Ext[LINE_SIZE]; char Date[LINE_SIZE]; - struct sockaddr_in * DestAddr; + struct sockaddr *DestAddr; void * Cookie; } Event; @@ -134,7 +135,7 @@ typedef struct TData int Mx; void * Cookie; char * Data; - struct sockaddr_in DestAddr; + struct sockaddr_storage DestAddr; }ThreadData; @@ -142,7 +143,7 @@ typedef struct ssdpsearchreply { int MaxAge; UpnpDevice_Handle handle; - struct sockaddr_in dest_addr; + struct sockaddr_storage dest_addr; SsdpEvent event; }SsdpSearchReply; @@ -159,13 +160,14 @@ typedef struct ssdpsearcharg typedef struct { http_parser_t parser; - struct sockaddr_in dest_addr; + struct sockaddr_storage dest_addr; } ssdp_thread_data; /* globals */ -CLIENTONLY(extern SOCKET gSsdpReqSocket;); +CLIENTONLY(extern SOCKET gSsdpReqSocket4;); +CLIENTONLY(extern SOCKET gSsdpReqSocket6;); typedef int (*ParserFun)(char *, Event *); @@ -205,11 +207,11 @@ int Make_Socket_NoBlocking (int sock); #ifdef INCLUDE_DEVICE_APIS void ssdp_handle_device_request( IN http_message_t* hmsg, - IN struct sockaddr_in* dest_addr ); + IN struct sockaddr* dest_addr ); #else static inline void ssdp_handle_device_request( IN http_message_t* hmsg, - IN struct sockaddr_in* dest_addr ) {} + IN struct sockaddr* dest_addr ) {} #endif /************************************************************************ @@ -217,7 +219,7 @@ static inline void ssdp_handle_device_request( * * Parameters: * IN http_message_t* hmsg: SSDP message from the device -* IN struct sockaddr_in* dest_addr: Address of the device +* IN struct sockaddr* dest_addr: Address of the device * IN xboolean timeout: timeout kept by the control point while sending * search message * IN void* cookie: Cookie stored by the control point application. @@ -234,7 +236,7 @@ static inline void ssdp_handle_device_request( ***************************************************************************/ void ssdp_handle_ctrlpt_msg( IN http_message_t* hmsg, - IN struct sockaddr_in* dest_addr, + IN struct sockaddr* dest_addr, IN xboolean timeout, IN void* cookie ); @@ -347,6 +349,7 @@ int SearchByTarget(IN int Mx, IN char *St, IN void *Cookie); * IN char *Udn : * IN char *Location: Location URL. * IN int Duration : Service duration in sec. +* IN int AddressFamily: Device address family. * * Description: * This function creates the device advertisement request based on @@ -360,7 +363,8 @@ int DeviceAdvertisement( IN int RootDev, IN char *Udn, IN char *Location, - IN int Duration); + IN int Duration, + IN int AddressFamily); /************************************************************************ @@ -373,6 +377,7 @@ int DeviceAdvertisement( * IN char *_Server: * IN char *Location: Location URL * IN int Duration :Device duration in sec. +* IN int AddressFamily: Device address family. * * Description: * This function creates a HTTP device shutdown request packet @@ -387,13 +392,14 @@ int DeviceShutdown( IN char *Udn, IN char *_Server, IN char *Location, - IN int Duration); + IN int Duration, + IN int AddressFamily); /************************************************************************ * Function : DeviceReply * * Parameters: -* IN struct sockaddr_in * DestAddr:destination IP address. +* IN struct sockaddr *DestAddr: destination IP address. * IN char *DevType: Device type * IN int RootDev: 1 means root device 0 means embedded device. * IN char *Udn: Device UDN @@ -408,17 +414,18 @@ int DeviceShutdown( * UPNP_E_SUCCESS if successful else appropriate error ***************************************************************************/ int DeviceReply( - IN struct sockaddr_in * DestAddr, + IN struct sockaddr *DestAddr, IN char *DevType, IN int RootDev, IN char *Udn, - IN char *Location, IN int Duration); + IN char *Location, + IN int Duration); /************************************************************************ * Function : SendReply * * Parameters: -* IN struct sockaddr_in * DestAddr:destination IP address. +* IN struct sockaddr *DestAddr: destination IP address. * IN char *DevType: Device type * IN int RootDev: 1 means root device 0 means embedded device. * IN char * Udn: Device UDN @@ -435,7 +442,7 @@ int DeviceReply( * UPNP_E_SUCCESS if successful else appropriate error ***************************************************************************/ int SendReply( - IN struct sockaddr_in * DestAddr, + IN struct sockaddr *DestAddr, IN char *DevType, IN int RootDev, IN char *Udn, @@ -450,7 +457,8 @@ int SendReply( * IN char * Udn: Device UDN * IN char *ServType: Service Type. * IN char * Location: Location of Device description document. -* IN int Duration :Life time of this device. +* IN int Duration: Life time of this device. +* IN int AddressFamily: Device address family * * Description: * This function creates the advertisement packet based @@ -463,13 +471,14 @@ int ServiceAdvertisement( IN char *Udn, IN char *ServType, IN char *Location, - IN int Duration); + IN int Duration, + IN int AddressFamily); /************************************************************************ * Function : ServiceReply * * Parameters: -* IN struct sockaddr_in *DestAddr: +* IN struct sockaddr *DestAddr: * IN char *Udn: Device UDN * IN char *ServType: Service Type. * IN char *Server: Not used @@ -484,7 +493,7 @@ int ServiceAdvertisement( * UPNP_E_SUCCESS if successful else appropriate error ***************************************************************************/ int ServiceReply( - IN struct sockaddr_in *DestAddr, + IN struct sockaddr *DestAddr, IN char *ServType, IN char *Udn, IN char *Location, @@ -498,6 +507,7 @@ int ServiceReply( * IN char *ServType: Service Type. * IN char *Location: Location of Device description document. * IN int Duration :Service duration in sec. +* IN int AddressFamily: Device address family * * Description: * This function creates a HTTP service shutdown request packet @@ -510,7 +520,8 @@ int ServiceShutdown( IN char *Udn, IN char *ServType, IN char *Location, - IN int Duration); + IN int Duration, + IN int AddressFamily); /************************************************************************ @@ -537,7 +548,7 @@ void *advertiseAndReplyThread(IN void * data); * 1 = Send Advertisement * IN UpnpDevice_Handle Hnd: Device handle * IN enum SsdpSearchType SearchType:Search type for sending replies -* IN struct sockaddr_in *DestAddr:Destination address +* IN struct sockaddr *DestAddr:Destination address * IN char *DeviceType:Device type * IN char *DeviceUDN:Device UDN * IN char *ServiceType:Service type @@ -553,10 +564,9 @@ int AdvertiseAndReply( IN int AdFlag, IN UpnpDevice_Handle Hnd, IN enum SsdpSearchType SearchType, - IN struct sockaddr_in *DestAddr, + IN struct sockaddr *DestAddr, IN char *DeviceType, IN char *DeviceUDN, IN char *ServiceType, int Exp); #endif - diff --git a/upnp/src/inc/upnpapi.h b/upnp/src/inc/upnpapi.h index 9dc2f76..6f0f9c5 100644 --- a/upnp/src/inc/upnpapi.h +++ b/upnp/src/inc/upnpapi.h @@ -84,11 +84,12 @@ struct Handle_Info //URL information int MaxSubscriptions; int MaxSubscriptionTimeOut; + int DeviceAf; // Address family: AF_INET or AF_INET6 #endif // Client only #ifdef INCLUDE_CLIENT_APIS - ClientSubscription *ClientSubList; //client subscription list + ClientSubscription *ClientSubList; // client subscription list LinkedList SsdpSearchList; // active ssdp searches #endif int aliasInstalled; // 0 = not installed; otherwise installed @@ -116,13 +117,20 @@ Upnp_Handle_Type GetHandleInfo(int Hnd, struct Handle_Info **HndInfo); Upnp_Handle_Type GetClientHandleInfo(int *client_handle_out, struct Handle_Info **HndInfo); -Upnp_Handle_Type GetDeviceHandleInfo(int *device_handle_out, - struct Handle_Info **HndInfo); +Upnp_Handle_Type GetDeviceHandleInfo( const int AddressFamily, + int *device_handle_out, + struct Handle_Info **HndInfo); -extern char LOCAL_HOST[LINE_SIZE]; +extern char gIF_NAME[LINE_SIZE]; +extern char gIF_IPV4[22]; // INET_ADDRSTRLEN +extern char gIF_IPV6[65]; // INET6_ADDRSTRLEN +extern int gIF_INDEX; -extern unsigned short LOCAL_PORT; +extern unsigned short LOCAL_PORT_V4; +extern unsigned short LOCAL_PORT_V6; + +extern Upnp_SID gUpnpSdkNLSuuid; // NLS uuid. extern TimerThread gTimerThread; extern ThreadPool gRecvThreadPool; @@ -170,6 +178,14 @@ typedef enum { WEB_SERVER_DISABLED, WEB_SERVER_ENABLED } WebServerState; #define E_HTTP_SYNTAX -6 +#ifdef WIN32 +int WinsockInit(); +#endif +int UpnpInitPreamble(); +int UpnpInitMutexes(); +int UpnpInitThreadPools(); +int UpnpInitStartServers(unsigned short DestPort); +int UpnpGetIfInfo(const char *IfName); void InitHandleList(); int GetFreeHandle(); int FreeHandle(int Handle); @@ -177,7 +193,7 @@ void UpnpThreadDistribution(struct UpnpNonblockParam * Param); void AutoAdvertise(void *input); -int getlocalhostname(char *out); +int getlocalhostname(char *out, const int out_len); extern WebServerState bWebServerState; diff --git a/upnp/src/inc/uri.h b/upnp/src/inc/uri.h index 1c3847c..986b3fe 100644 --- a/upnp/src/inc/uri.h +++ b/upnp/src/inc/uri.h @@ -95,7 +95,7 @@ typedef struct TOKEN { * text is a token pointing to the full string representation */ typedef struct HOSTPORT { token text; //full host port - struct sockaddr_in IPv4address; //Network Byte Order + struct sockaddr_storage IPaddress; //Network Byte Order } hostport_type; /* Represents a URI used in parse_uri and elsewhere */ diff --git a/upnp/src/inc/urlconfig.h b/upnp/src/inc/urlconfig.h index 4683764..cea5763 100644 --- a/upnp/src/inc/urlconfig.h +++ b/upnp/src/inc/urlconfig.h @@ -50,13 +50,13 @@ extern "C" { * * Parameters : * INOUT IXML_Document *doc ; IXML Description document -* IN const struct sockaddr_in* serverAddr ; socket address object -* providing the IP address and port information -* IN const char* alias ; string containing the alias +* IN const struct sockaddr *serverAddr; socket address object +* providing the IP address and port information +* IN const char* alias ; string containing the alias * IN time_t last_modified ; time when the XML document was -* downloaded +* downloaded * OUT char docURL[LINE_SIZE] ; buffer to hold the URL of the -* document. +* document. * * Description : Configure the full URL for the description document. * Create the URL document and add alias, description information. @@ -70,10 +70,10 @@ extern "C" { * Note : ****************************************************************************/ int configure_urlbase( INOUT IXML_Document *doc, - IN const struct sockaddr_in* serverAddr, - IN const char* alias, + IN const struct sockaddr* serverAddr, + IN const char* alias, IN time_t last_modified, - OUT char docURL[LINE_SIZE] ); + OUT char docURL[LINE_SIZE]); #ifdef __cplusplus @@ -81,4 +81,3 @@ int configure_urlbase( INOUT IXML_Document *doc, #endif #endif /* URLCONFIG_H */ - diff --git a/upnp/src/soap/soap_device.c b/upnp/src/soap/soap_device.c index 19140ea..86af8ff 100644 --- a/upnp/src/soap/soap_device.c +++ b/upnp/src/soap/soap_device.c @@ -592,6 +592,7 @@ static int get_device_info( IN http_message_t *request, IN int isQuery, IN IXML_Document *actionDoc, + IN int AddressFamily, OUT UpnpString *device_udn, OUT UpnpString *service_id, OUT Upnp_FunPtr *callback, @@ -612,7 +613,8 @@ get_device_info( IN http_message_t *request, HandleLock(); - if( GetDeviceHandleInfo( &device_hnd, &device_info ) != HND_DEVICE ) { + if( GetDeviceHandleInfo( AddressFamily, + &device_hnd, &device_info ) != HND_DEVICE ) { goto error_handler; } @@ -843,10 +845,10 @@ error_handler: * * Note : ****************************************************************************/ -static UPNP_INLINE void -handle_query_variable( IN SOCKINFO * info, - IN http_message_t * request, - IN IXML_Document * xml_doc ) +static UPNP_INLINE void handle_query_variable( + IN SOCKINFO *info, + IN http_message_t *request, + IN IXML_Document *xml_doc ) { UpnpStateVarRequest *variable = UpnpStateVarRequest_new(); Upnp_FunPtr soap_event_callback; @@ -864,6 +866,7 @@ handle_query_variable( IN SOCKINFO * info, // get info for event err_code = get_device_info( request, 1, xml_doc, + info->foreign_sockaddr.ss_family, (UpnpString *)UpnpStateVarRequest_get_DevUDN(variable), (UpnpString *)UpnpStateVarRequest_get_ServiceID(variable), &soap_event_callback, @@ -876,7 +879,7 @@ handle_query_variable( IN SOCKINFO * info, UpnpStateVarRequest_set_ErrCode(variable, UPNP_E_SUCCESS); UpnpStateVarRequest_strcpy_StateVarName(variable, var_name); - UpnpStateVarRequest_set_CtrlPtIPAddr(variable, &info->foreign_ip_addr); + UpnpStateVarRequest_set_CtrlPtIPAddr(variable, &info->foreign_sockaddr); // send event soap_event_callback( UPNP_CONTROL_GET_VAR_REQUEST, variable, cookie ); @@ -960,6 +963,7 @@ handle_invoke_action( IN SOCKINFO * info, request, 0, xml_doc, + info->foreign_sockaddr.ss_family, devUDN, serviceID, &soap_event_callback, @@ -975,7 +979,7 @@ handle_invoke_action( IN SOCKINFO * info, UpnpActionRequest_set_DevUDN(action, devUDN); UpnpActionRequest_set_ServiceID(action, serviceID); UpnpActionRequest_set_ActionRequest(action, actionRequestDoc); - UpnpActionRequest_set_CtrlPtIPAddr(action, &info->foreign_ip_addr); + UpnpActionRequest_set_CtrlPtIPAddr(action, &info->foreign_sockaddr); UpnpPrintf(UPNP_INFO, SOAP, __FILE__, __LINE__, "Calling Callback\n"); diff --git a/upnp/src/ssdp/ssdp_ctrlpt.c b/upnp/src/ssdp/ssdp_ctrlpt.c index 1be5aec..c17542a 100644 --- a/upnp/src/ssdp/ssdp_ctrlpt.c +++ b/upnp/src/ssdp/ssdp_ctrlpt.c @@ -80,7 +80,7 @@ void send_search_result(IN void *data) * Parameters: * IN http_message_t *hmsg: * SSDP message from the device - * IN struct sockaddr_in *dest_addr: + * IN struct sockaddr *dest_addr: * Address of the device * IN xboolean timeout: * timeout kept by the control point while @@ -100,9 +100,9 @@ void send_search_result(IN void *data) ***************************************************************************/ void ssdp_handle_ctrlpt_msg( IN http_message_t *hmsg, - IN struct sockaddr_in *dest_addr, + IN struct sockaddr *dest_addr, IN xboolean timeout, // only in search reply - IN void *cookie ) // only in search reply + IN void *cookie) // only in search reply { int handle; struct Handle_Info *ctrlpt_info = NULL; @@ -336,50 +336,6 @@ end_ssdp_handle_ctrlpt_msg: UpnpDiscovery_delete(param); } -/************************************************************************ -* Function : process_reply -* -* Parameters: -* IN char* request_buf: the response came from the device -* IN int buf_len: The length of the response buffer -* IN struct sockaddr_in* dest_addr: The address of the device -* IN void *cookie : cookie passed by the control point application -* at the time of sending search message -* -* Description: -* This function processes reply recevied from a search -* -* Returns: void -* -***************************************************************************/ -#ifndef WIN32 -#warning There are currently no uses of the function 'process_reply()' in the code. -#warning 'process_reply()' is a candidate for removal. -#else -#pragma message("There are currently no uses of the function 'process_reply()' in the code.") -#pragma message("'process_reply()' is a candidate for removal.") -#endif -static UPNP_INLINE void -process_reply( IN char *request_buf, - IN int buf_len, - IN struct sockaddr_in *dest_addr, - IN void *cookie ) -{ - http_parser_t parser; - - parser_response_init( &parser, HTTPMETHOD_MSEARCH ); - - // parse - if( parser_append( &parser, request_buf, buf_len ) != PARSE_SUCCESS ) { - httpmsg_destroy( &parser.msg ); - return; - } - // handle reply - ssdp_handle_ctrlpt_msg( &parser.msg, dest_addr, FALSE, cookie ); - - // done - httpmsg_destroy( &parser.msg ); -} /************************************************************************ * Function : CreateClientRequestPacket @@ -389,6 +345,7 @@ process_reply( IN char *request_buf, * IN char *SearchTarget:Search Target * IN int Mx dest_addr: Number of seconds to wait to * collect all the responses +* IN int AddressFamily: search address family * * Description: * This function creates a HTTP search request packet @@ -400,13 +357,18 @@ process_reply( IN char *request_buf, static void CreateClientRequestPacket( IN char *RqstBuf, IN int Mx, - IN char *SearchTarget ) + IN char *SearchTarget, + IN int AddressFamily ) { char TempBuf[COMMAND_LEN]; strcpy( RqstBuf, "M-SEARCH * HTTP/1.1\r\n" ); - sprintf( TempBuf, "HOST: %s:%d\r\n", SSDP_IP, SSDP_PORT ); + if (AddressFamily == AF_INET) { + sprintf( TempBuf, "HOST: %s:%d\r\n", SSDP_IP, SSDP_PORT ); + } else if (AddressFamily == AF_INET6) { + sprintf( TempBuf, "HOST: [%s]:%d\r\n", SSDP_IPV6_LINKLOCAL, SSDP_PORT ); + } strcat( RqstBuf, TempBuf ); strcat( RqstBuf, "MAN: \"ssdp:discover\"\r\n" ); @@ -495,7 +457,17 @@ searchExpired( void *arg ) * This cokie will be returned to application in the callback. * * Description: -* This function creates and send the search request for a specific URL. +* This function implements the search request of the discovery phase. +* A M-SEARCH request is sent on the SSDP channel for both IPv4 and +* IPv6 addresses. The search target(ST) is required and must be one of +* the following: +* - "ssdp:all" : Search for all devices and services. +* - "ssdp:rootdevice" : Search for root devices only. +* - "uuid:" : Search for a particular device. +* - "urn:schemas-upnp-org:device:" +* - "urn:schemas-upnp-org:service:" +* - "urn::device:" +* - "urn::service:" * * Returns: int * 1 if successful else appropriate error @@ -506,18 +478,23 @@ SearchByTarget( IN int Mx, IN void *Cookie ) { char errorBuffer[ERROR_BUFFER_LEN]; - int socklen = sizeof( struct sockaddr_in ); + int socklen = sizeof( struct sockaddr_storage ); int *id = NULL; int ret = 0; - char *ReqBuf; - struct sockaddr_in destAddr; + char ReqBufv4[BUFSIZE]; + char ReqBufv6[BUFSIZE]; + struct sockaddr_storage __ss_v4; + struct sockaddr_storage __ss_v6; + struct sockaddr_in* destAddr4 = (struct sockaddr_in*)&__ss_v4; + struct sockaddr_in6* destAddr6 = (struct sockaddr_in6*)&__ss_v6; fd_set wrSet; SsdpSearchArg *newArg = NULL; int timeTillRead = 0; int handle; struct Handle_Info *ctrlpt_info = NULL; enum SsdpSearchType requestType; - unsigned long addr = inet_addr( LOCAL_HOST ); + unsigned long addrv4 = inet_addr( gIF_IPV4 ); + int max_fd = 0; //ThreadData *ThData; ThreadPoolJob job; @@ -527,12 +504,7 @@ SearchByTarget( IN int Mx, return UPNP_E_INVALID_PARAM; } - ReqBuf = (char *)malloc( BUFSIZE ); - if( ReqBuf == NULL ) { - return UPNP_E_OUTOF_MEMORY; - } - - UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, ">>> SSDP SEND >>>\n"); + UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, "Inside SearchByTarget\n"); timeTillRead = Mx; @@ -542,21 +514,24 @@ SearchByTarget( IN int Mx, timeTillRead = MAX_SEARCH_TIME; } - CreateClientRequestPacket( ReqBuf, timeTillRead, St ); - memset( ( char * )&destAddr, 0, sizeof( struct sockaddr_in ) ); + CreateClientRequestPacket( ReqBufv4, timeTillRead, St, AF_INET ); + CreateClientRequestPacket( ReqBufv6, timeTillRead, St, AF_INET6 ); - destAddr.sin_family = AF_INET; - destAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); - destAddr.sin_port = htons( SSDP_PORT ); + memset( &__ss_v4, 0, sizeof( __ss_v4 ) ); + destAddr4->sin_family = AF_INET; + inet_pton( AF_INET, SSDP_IP, &destAddr4->sin_addr ); + destAddr4->sin_port = htons( SSDP_PORT ); - FD_ZERO( &wrSet ); - FD_SET( gSsdpReqSocket, &wrSet ); + memset( &__ss_v6, 0, sizeof( __ss_v6 ) ); + destAddr6->sin6_family = AF_INET6; + inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &destAddr6->sin6_addr ); + destAddr6->sin6_port = htons( SSDP_PORT ); + destAddr6->sin6_scope_id = gIF_INDEX; // add search criteria to list HandleLock(); if( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) { HandleUnlock(); - free( ReqBuf ); return UPNP_E_INTERNAL_ERROR; } @@ -578,34 +553,56 @@ SearchByTarget( IN int Mx, ListAddTail( &ctrlpt_info->SsdpSearchList, newArg ); HandleUnlock(); - ret = setsockopt( gSsdpReqSocket, IPPROTO_IP, IP_MULTICAST_IF, - (char *)&addr, sizeof (addr) ); + FD_ZERO( &wrSet ); + if( gSsdpReqSocket4 != INVALID_SOCKET ) { + setsockopt( gSsdpReqSocket4, IPPROTO_IP, IP_MULTICAST_IF, + (char *)&addrv4, sizeof (addrv4) ); + FD_SET( gSsdpReqSocket4, &wrSet ); + max_fd = max(max_fd, gSsdpReqSocket4); + } + if( gSsdpReqSocket6 != INVALID_SOCKET ) { + setsockopt( gSsdpReqSocket6, IPPROTO_IPV6, IPV6_MULTICAST_IF, + (char *)&gIF_INDEX, sizeof(gIF_INDEX) ); + FD_SET( gSsdpReqSocket6, &wrSet ); + max_fd = max(max_fd, gSsdpReqSocket6); + } - ret = select( gSsdpReqSocket + 1, NULL, &wrSet, NULL, NULL ); + ret = select( max_fd + 1, NULL, &wrSet, NULL, NULL ); if( ret == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, "SSDP_LIB: Error in select(): %s\n", errorBuffer ); - shutdown( gSsdpReqSocket, SD_BOTH ); - UpnpCloseSocket( gSsdpReqSocket ); - free( ReqBuf ); + shutdown( gSsdpReqSocket4, SD_BOTH ); + UpnpCloseSocket( gSsdpReqSocket4 ); + shutdown( gSsdpReqSocket6, SD_BOTH ); + UpnpCloseSocket( gSsdpReqSocket6 ); return UPNP_E_INTERNAL_ERROR; - } else if( FD_ISSET( gSsdpReqSocket, &wrSet ) ) { + } + if( gSsdpReqSocket6 != INVALID_SOCKET && + FD_ISSET( gSsdpReqSocket6, &wrSet ) ) { int NumCopy = 0; while( NumCopy < NUM_SSDP_COPY ) { - sendto( gSsdpReqSocket, ReqBuf, strlen( ReqBuf ), 0, - (struct sockaddr *)&destAddr, socklen ); + sendto( gSsdpReqSocket6, ReqBufv6, strlen( ReqBufv6 ), 0, + (struct sockaddr *)&__ss_v6, socklen ); NumCopy++; imillisleep( SSDP_PAUSE ); } } + if( gSsdpReqSocket4 != INVALID_SOCKET && + FD_ISSET( gSsdpReqSocket4, &wrSet ) ) { + int NumCopy = 0; + while( NumCopy < NUM_SSDP_COPY ) { + sendto( gSsdpReqSocket4, ReqBufv4, strlen( ReqBufv4 ), 0, + (struct sockaddr *)&__ss_v4, socklen ); + NumCopy++; + imillisleep( SSDP_PAUSE ); + } + } - free( ReqBuf ); return 1; } #endif // EXCLUDE_SSDP #endif // INCLUDE_CLIENT_APIS - diff --git a/upnp/src/ssdp/ssdp_device.c b/upnp/src/ssdp/ssdp_device.c index 94af8aa..a7f5717 100644 --- a/upnp/src/ssdp/ssdp_device.c +++ b/upnp/src/ssdp/ssdp_device.c @@ -75,7 +75,7 @@ advertiseAndReplyThread( IN void *data ) AdvertiseAndReply( 0, arg->handle, arg->event.RequestType, - &arg->dest_addr, + (struct sockaddr*)&arg->dest_addr, arg->event.DeviceType, arg->event.UDN, arg->event.ServiceType, arg->MaxAge ); @@ -88,8 +88,8 @@ advertiseAndReplyThread( IN void *data ) * Function : ssdp_handle_device_request * * Parameters: -* IN http_message_t* hmsg: SSDP search request from the control point -* IN struct sockaddr_in* dest_addr: The address info of control point +* IN http_message_t *hmsg: SSDP search request from the control point +* IN struct sockaddr *dest_addr: The address info of control point * * Description: * This function handles the search request. It do the sanity checks of @@ -101,8 +101,8 @@ advertiseAndReplyThread( IN void *data ) ***************************************************************************/ #ifdef INCLUDE_DEVICE_APIS void -ssdp_handle_device_request( IN http_message_t * hmsg, - IN struct sockaddr_in *dest_addr ) +ssdp_handle_device_request( IN http_message_t *hmsg, + IN struct sockaddr *dest_addr ) { #define MX_FUDGE_FACTOR 10 @@ -142,7 +142,8 @@ ssdp_handle_device_request( IN http_message_t * hmsg, HandleLock(); // device info - if( GetDeviceHandleInfo( &handle, &dev_info ) != HND_DEVICE ) { + if( GetDeviceHandleInfo( dest_addr->sa_family, + &handle, &dev_info ) != HND_DEVICE ) { HandleUnlock(); return; // no info found } @@ -170,7 +171,7 @@ ssdp_handle_device_request( IN http_message_t * hmsg, return; } threadArg->handle = handle; - threadArg->dest_addr = ( *dest_addr ); + memcpy( &threadArg->dest_addr, dest_addr, sizeof(threadArg->dest_addr) ); threadArg->event = event; threadArg->MaxAge = maxAge; @@ -201,7 +202,7 @@ ssdp_handle_device_request( IN http_message_t * hmsg, * Function : NewRequestHandler * * Parameters: -* IN struct sockaddr_in * DestAddr: Ip address, to send the reply. +* IN struct sockaddr *DestAddr: Ip address, to send the reply. * IN int NumPacket: Number of packet to be sent. * IN char **RqPacket:Number of packet to be sent. * @@ -213,19 +214,21 @@ ssdp_handle_device_request( IN http_message_t * hmsg, * 1 if successful else appropriate error ***************************************************************************/ static int -NewRequestHandler( IN struct sockaddr_in *DestAddr, +NewRequestHandler( IN struct sockaddr *DestAddr, IN int NumPacket, IN char **RqPacket ) { char errorBuffer[ERROR_BUFFER_LEN]; - int ReplySock; - int socklen = sizeof( struct sockaddr_in ); + SOCKET ReplySock; + int socklen = sizeof( struct sockaddr_storage ); int NumCopy; int Index; - unsigned long replyAddr = inet_addr( LOCAL_HOST ); + unsigned long replyAddr = inet_addr( gIF_IPV4 ); int ttl = 4; // a/c to UPNP Spec + int hops = 1; + char buf_ntop[64]; - ReplySock = socket( AF_INET, SOCK_DGRAM, 0 ); + ReplySock = socket( DestAddr->sa_family, SOCK_DGRAM, 0 ); if ( ReplySock == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, @@ -234,11 +237,25 @@ NewRequestHandler( IN struct sockaddr_in *DestAddr, return UPNP_E_OUTOF_SOCKET; } - - setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_IF, - (char *)&replyAddr, sizeof (replyAddr) ); - setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_TTL, - (char *)&ttl, sizeof (int) ); + + if( DestAddr->sa_family == AF_INET ) { + inet_ntop(AF_INET, &((struct sockaddr_in*)DestAddr)->sin_addr, + buf_ntop, sizeof(buf_ntop)); + setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_IF, + (char *)&replyAddr, sizeof (replyAddr) ); + setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_TTL, + (char *)&ttl, sizeof (int) ); + } else if( DestAddr->sa_family == AF_INET6 ) { + inet_ntop(AF_INET6, &((struct sockaddr_in6*)DestAddr)->sin6_addr, + buf_ntop, sizeof(buf_ntop)); + setsockopt( ReplySock, IPPROTO_IPV6, IPV6_MULTICAST_IF, + (char *)&gIF_INDEX, sizeof(gIF_INDEX) ); + setsockopt( ReplySock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + (char *)&hops, sizeof(hops) ); + } else { + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Invalid destination address specified." ); + } for( Index = 0; Index < NumPacket; Index++ ) { int rc; @@ -256,11 +273,11 @@ NewRequestHandler( IN struct sockaddr_in *DestAddr, NumCopy = 0; while( NumCopy < NUM_COPY ) { UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, - ">>> SSDP SEND >>>\n%s\n", - *( RqPacket + Index ) ); + ">>> SSDP SEND to %s >>>\n%s\n", + buf_ntop, *( RqPacket + Index ) ); rc = sendto( ReplySock, *( RqPacket + Index ), strlen( *( RqPacket + Index ) ), - 0, ( struct sockaddr * )DestAddr, socklen ); + 0, DestAddr, socklen ); imillisleep( SSDP_PAUSE ); ++NumCopy; } @@ -283,6 +300,7 @@ NewRequestHandler( IN struct sockaddr_in *DestAddr, * IN char * location :Location URL. * IN int duration :Service duration in sec. * OUT char** packet :Output buffer filled with HTTP statement. +* IN int AddressFamily: Address family of the HTTP request. * * Description: * This function creates a HTTP request packet. Depending @@ -298,7 +316,8 @@ CreateServicePacket( IN int msg_type, IN char *usn, IN char *location, IN int duration, - OUT char **packet ) + OUT char **packet, + IN int AddressFamily) { int ret_code; char *nts; @@ -315,11 +334,13 @@ CreateServicePacket( IN int msg_type, if( msg_type == MSGTYPE_REPLY ) { ret_code = http_MakeMessage( &buf, 1, 1, - "R" "sdc" "D" "sc" "ssc" "S" "Xc" "ssc" "sscc", + "R" "sdc" "D" "sc" "ssc" "ssc" "ssc" "S" "Xc" "ssc" "sscc", HTTP_OK, "CACHE-CONTROL: max-age=", duration, "EXT:", "LOCATION: ", location, + "OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01", + "01-NLS: ", gUpnpSdkNLSuuid, X_USER_AGENT, "ST: ", nt, "USN: ", usn); @@ -337,14 +358,18 @@ CreateServicePacket( IN int msg_type, // NOTE: The CACHE-CONTROL and LOCATION headers are not present in // a shutdown msg, but are present here for MS WinMe interop. - + ret_code = http_MakeMessage( &buf, 1, 1, - "Q" "sssdc" "sdc" "ssc" "ssc" "ssc" "S" "Xc" "sscc", + "Q" "sssdc" "sdc" "ssc" "ssc" "ssc" "ssc" "ssc" "S" "Xc" "sscc", HTTPMETHOD_NOTIFY, "*", (size_t)1, - "HOST: ", SSDP_IP, ":", SSDP_PORT, + "HOST: ", + (AddressFamily==AF_INET) ? SSDP_IP : "[" SSDP_IPV6_LINKLOCAL "]", + ":", SSDP_PORT, "CACHE-CONTROL: max-age=", duration, "LOCATION: ", location, + "OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01", + "01-NLS: ", gUpnpSdkNLSuuid, "NT: ", nt, "NTS: ", nts, X_USER_AGENT, @@ -387,9 +412,12 @@ DeviceAdvertisement( IN char *DevType, int RootDev, char *Udn, IN char *Location, - IN int Duration ) + IN int Duration, + IN int AddressFamily) { - struct sockaddr_in DestAddr; + struct sockaddr_storage __ss; + struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss; + struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss; //char Mil_Nt[LINE_SIZE] char Mil_Usn[LINE_SIZE]; @@ -397,11 +425,22 @@ DeviceAdvertisement( IN char *DevType, int ret_code; UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, - "In function SendDeviceAdvertisemenrt\n" ); + "In function DeviceAdvertisement\n" ); - DestAddr.sin_family = AF_INET; - DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); - DestAddr.sin_port = htons( SSDP_PORT ); + memset( &__ss, 0, sizeof(__ss) ); + if( AddressFamily == AF_INET ) { + DestAddr4->sin_family = AF_INET; + inet_pton( AF_INET, SSDP_IP, &DestAddr4->sin_addr ); + DestAddr4->sin_port = htons( SSDP_PORT ); + } else if( AddressFamily == AF_INET6 ) { + DestAddr6->sin6_family = AF_INET6; + inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &DestAddr6->sin6_addr ); + DestAddr6->sin6_port = htons( SSDP_PORT ); + DestAddr6->sin6_scope_id = gIF_INDEX; + } else { + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Invalid device address family.\n" ); + } msgs[0] = NULL; msgs[1] = NULL; @@ -412,17 +451,17 @@ DeviceAdvertisement( IN char *DevType, if( RootDev ) { sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); CreateServicePacket( MSGTYPE_ADVERTISEMENT, "upnp:rootdevice", - Mil_Usn, Location, Duration, &msgs[0] ); + Mil_Usn, Location, Duration, &msgs[0], AddressFamily ); } // both root and sub-devices need to send these two messages // CreateServicePacket( MSGTYPE_ADVERTISEMENT, Udn, Udn, - Location, Duration, &msgs[1] ); + Location, Duration, &msgs[1], AddressFamily ); sprintf( Mil_Usn, "%s::%s", Udn, DevType ); CreateServicePacket( MSGTYPE_ADVERTISEMENT, DevType, Mil_Usn, - Location, Duration, &msgs[2] ); + Location, Duration, &msgs[2], AddressFamily ); // check error if( ( RootDev && msgs[0] == NULL ) || @@ -435,11 +474,11 @@ DeviceAdvertisement( IN char *DevType, // send packets if( RootDev ) { // send 3 msg types - ret_code = NewRequestHandler( &DestAddr, 3, &msgs[0] ); + ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 3, &msgs[0] ); } else // sub-device { // send 2 msg types - ret_code = NewRequestHandler( &DestAddr, 2, &msgs[1] ); + ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 2, &msgs[1] ); } // free msgs @@ -454,7 +493,7 @@ DeviceAdvertisement( IN char *DevType, * Function : SendReply * * Parameters: -* IN struct sockaddr_in * DestAddr:destination IP address. +* IN struct sockaddr * DestAddr:destination IP address. * IN char *DevType: Device type * IN int RootDev: 1 means root device 0 means embedded device. * IN char * Udn: Device UDN @@ -470,7 +509,7 @@ DeviceAdvertisement( IN char *DevType, * UPNP_E_SUCCESS if successful else appropriate error ***************************************************************************/ int -SendReply( IN struct sockaddr_in *DestAddr, +SendReply( IN struct sockaddr *DestAddr, IN char *DevType, IN int RootDev, IN char *Udn, @@ -493,7 +532,7 @@ SendReply( IN struct sockaddr_in *DestAddr, sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); CreateServicePacket( MSGTYPE_REPLY, "upnp:rootdevice", - Mil_Usn, Location, Duration, &msgs[0] ); + Mil_Usn, Location, Duration, &msgs[0], DestAddr->sa_family ); } else { // two msgs for embedded devices num_msgs = 1; @@ -501,11 +540,11 @@ SendReply( IN struct sockaddr_in *DestAddr, //NK: FIX for extra response when someone searches by udn if( !ByType ) { CreateServicePacket( MSGTYPE_REPLY, Udn, Udn, Location, - Duration, &msgs[0] ); + Duration, &msgs[0], DestAddr->sa_family ); } else { sprintf( Mil_Usn, "%s::%s", Udn, DevType ); CreateServicePacket( MSGTYPE_REPLY, DevType, Mil_Usn, - Location, Duration, &msgs[0] ); + Location, Duration, &msgs[0], DestAddr->sa_family ); } } @@ -531,7 +570,7 @@ SendReply( IN struct sockaddr_in *DestAddr, * Function : DeviceReply * * Parameters: -* IN struct sockaddr_in * DestAddr:destination IP address. +* IN struct sockaddr *DestAddr:destination IP address. * IN char *DevType: Device type * IN int RootDev: 1 means root device 0 means embedded device. * IN char * Udn: Device UDN @@ -545,12 +584,12 @@ SendReply( IN struct sockaddr_in *DestAddr, * UPNP_E_SUCCESS if successful else appropriate error ***************************************************************************/ int -DeviceReply( IN struct sockaddr_in *DestAddr, +DeviceReply( IN struct sockaddr *DestAddr, IN char *DevType, IN int RootDev, IN char *Udn, IN char *Location, - IN int Duration ) + IN int Duration) { char *szReq[3], Mil_Nt[LINE_SIZE], @@ -568,18 +607,18 @@ DeviceReply( IN struct sockaddr_in *DestAddr, strcpy( Mil_Nt, "upnp:rootdevice" ); sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn, - Location, Duration, &szReq[0] ); + Location, Duration, &szReq[0], DestAddr->sa_family ); } sprintf( Mil_Nt, "%s", Udn ); sprintf( Mil_Usn, "%s", Udn ); CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn, - Location, Duration, &szReq[1] ); + Location, Duration, &szReq[1], DestAddr->sa_family ); sprintf( Mil_Nt, "%s", DevType ); sprintf( Mil_Usn, "%s::%s", Udn, DevType ); CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn, - Location, Duration, &szReq[2] ); + Location, Duration, &szReq[2], DestAddr->sa_family ); // check error @@ -613,6 +652,7 @@ DeviceReply( IN struct sockaddr_in *DestAddr, * IN char *ServType: Service Type. * IN char * Location: Location of Device description document. * IN int Duration :Life time of this device. +* IN int AddressFamily: Device address family * Description: * This function creates the advertisement packet based * on the input parameter, and send it to the multicast channel. @@ -624,28 +664,42 @@ int ServiceAdvertisement( IN char *Udn, IN char *ServType, IN char *Location, - IN int Duration ) + IN int Duration, + IN int AddressFamily) { char Mil_Usn[LINE_SIZE]; char *szReq[1]; - struct sockaddr_in DestAddr; int RetVal; + struct sockaddr_storage __ss; + struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss; + struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss; - DestAddr.sin_family = AF_INET; - DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); - DestAddr.sin_port = htons( SSDP_PORT ); + memset( &__ss, 0, sizeof(__ss) ); + if( AddressFamily == AF_INET ) { + DestAddr4->sin_family = AF_INET; + inet_pton( AF_INET, SSDP_IP, &DestAddr4->sin_addr ); + DestAddr4->sin_port = htons( SSDP_PORT ); + } else if( AddressFamily == AF_INET6 ) { + DestAddr6->sin6_family = AF_INET6; + inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &DestAddr6->sin6_addr ); + DestAddr6->sin6_port = htons( SSDP_PORT ); + DestAddr6->sin6_scope_id = gIF_INDEX; + } else { + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Invalid device address family.\n" ); + } sprintf( Mil_Usn, "%s::%s", Udn, ServType ); //CreateServiceRequestPacket(1,szReq[0],Mil_Nt,Mil_Usn, //Server,Location,Duration); CreateServicePacket( MSGTYPE_ADVERTISEMENT, ServType, Mil_Usn, - Location, Duration, &szReq[0] ); + Location, Duration, &szReq[0], AddressFamily ); if( szReq[0] == NULL ) { return UPNP_E_OUTOF_MEMORY; } - RetVal = NewRequestHandler( &DestAddr, 1, szReq ); + RetVal = NewRequestHandler( (struct sockaddr*)&__ss, 1, szReq ); free( szReq[0] ); return RetVal; @@ -655,7 +709,7 @@ ServiceAdvertisement( IN char *Udn, * Function : ServiceReply * * Parameters: -* IN struct sockaddr_in *DestAddr: +* IN struct sockaddr *DestAddr: * IN char * Udn: Device UDN * IN char *ServType: Service Type. * IN char * Location: Location of Device description document. @@ -668,7 +722,7 @@ ServiceAdvertisement( IN char *Udn, * UPNP_E_SUCCESS if successful else appropriate error ***************************************************************************/ int -ServiceReply( IN struct sockaddr_in *DestAddr, +ServiceReply( IN struct sockaddr *DestAddr, IN char *ServType, IN char *Udn, IN char *Location, @@ -683,7 +737,7 @@ ServiceReply( IN struct sockaddr_in *DestAddr, sprintf( Mil_Usn, "%s::%s", Udn, ServType ); CreateServicePacket( MSGTYPE_REPLY, ServType, Mil_Usn, - Location, Duration, &szReq[0] ); + Location, Duration, &szReq[0], DestAddr->sa_family ); if( szReq[0] == NULL ) { return UPNP_E_OUTOF_MEMORY; } @@ -702,6 +756,7 @@ ServiceReply( IN struct sockaddr_in *DestAddr, * IN char *ServType: Service Type. * IN char * Location: Location of Device description document. * IN int Duration :Service duration in sec. +* IN int AddressFamily: Device address family * Description: * This function creates a HTTP service shutdown request packet * and sent it to the multicast channel through RequestHandler. @@ -713,27 +768,41 @@ int ServiceShutdown( IN char *Udn, IN char *ServType, IN char *Location, - IN int Duration ) + IN int Duration, + IN int AddressFamily) { char Mil_Usn[LINE_SIZE]; char *szReq[1]; - struct sockaddr_in DestAddr; + struct sockaddr_storage __ss; + struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss; + struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss; int RetVal; - DestAddr.sin_family = AF_INET; - DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); - DestAddr.sin_port = htons( SSDP_PORT ); + memset( &__ss, 0, sizeof(__ss) ); + if( AddressFamily == AF_INET ) { + DestAddr4->sin_family = AF_INET; + inet_pton( AF_INET, SSDP_IP, &DestAddr4->sin_addr ); + DestAddr4->sin_port = htons( SSDP_PORT ); + } else if( AddressFamily == AF_INET6 ) { + DestAddr6->sin6_family = AF_INET6; + inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &DestAddr6->sin6_addr ); + DestAddr6->sin6_port = htons( SSDP_PORT ); + DestAddr6->sin6_scope_id = gIF_INDEX; + } else { + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Invalid device address family.\n" ); + } //sprintf(Mil_Nt,"%s",ServType); sprintf( Mil_Usn, "%s::%s", Udn, ServType ); //CreateServiceRequestPacket(0,szReq[0],Mil_Nt,Mil_Usn, //Server,Location,Duration); CreateServicePacket( MSGTYPE_SHUTDOWN, ServType, Mil_Usn, - Location, Duration, &szReq[0] ); + Location, Duration, &szReq[0], AddressFamily ); if( szReq[0] == NULL ) { return UPNP_E_OUTOF_MEMORY; } - RetVal = NewRequestHandler( &DestAddr, 1, szReq ); + RetVal = NewRequestHandler( (struct sockaddr*)&__ss, 1, szReq ); free( szReq[0] ); return RetVal; @@ -748,6 +817,7 @@ ServiceShutdown( IN char *Udn, * IN char * Udn: Device UDN * IN char * Location: Location URL * IN int Duration :Device duration in sec. +* IN int AddressFamily: Device address family. * * Description: * This function creates a HTTP device shutdown request packet @@ -762,9 +832,12 @@ DeviceShutdown( IN char *DevType, IN char *Udn, IN char *_Server, IN char *Location, - IN int Duration ) + IN int Duration, + IN int AddressFamily) { - struct sockaddr_in DestAddr; + struct sockaddr_storage __ss; + struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss; + struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss; char *msgs[3]; char Mil_Usn[LINE_SIZE]; int ret_code; @@ -773,26 +846,37 @@ DeviceShutdown( IN char *DevType, msgs[1] = NULL; msgs[2] = NULL; - DestAddr.sin_family = AF_INET; - DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); - DestAddr.sin_port = htons( SSDP_PORT ); + memset( &__ss, 0, sizeof(__ss) ); + if( AddressFamily == AF_INET ) { + DestAddr4->sin_family = AF_INET; + inet_pton( AF_INET, SSDP_IP, &DestAddr4->sin_addr ); + DestAddr4->sin_port = htons( SSDP_PORT ); + } else if( AddressFamily == AF_INET6 ) { + DestAddr6->sin6_family = AF_INET6; + inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &DestAddr6->sin6_addr ); + DestAddr6->sin6_port = htons( SSDP_PORT ); + DestAddr6->sin6_scope_id = gIF_INDEX; + } else { + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Invalid device address family.\n" ); + } // root device has one extra msg if( RootDev ) { sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); CreateServicePacket( MSGTYPE_SHUTDOWN, "upnp:rootdevice", - Mil_Usn, Location, Duration, &msgs[0] ); + Mil_Usn, Location, Duration, &msgs[0], AddressFamily ); } UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, "In function DeviceShutdown\n" ); // both root and sub-devices need to send these two messages CreateServicePacket( MSGTYPE_SHUTDOWN, Udn, Udn, - Location, Duration, &msgs[1] ); + Location, Duration, &msgs[1], AddressFamily ); sprintf( Mil_Usn, "%s::%s", Udn, DevType ); CreateServicePacket( MSGTYPE_SHUTDOWN, DevType, Mil_Usn, - Location, Duration, &msgs[2] ); + Location, Duration, &msgs[2], AddressFamily ); // check error if( ( RootDev && msgs[0] == NULL ) || @@ -805,11 +889,11 @@ DeviceShutdown( IN char *DevType, // send packets if( RootDev ) { // send 3 msg types - ret_code = NewRequestHandler( &DestAddr, 3, &msgs[0] ); + ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 3, &msgs[0] ); } else // sub-device { // send 2 msg types - ret_code = NewRequestHandler( &DestAddr, 2, &msgs[1] ); + ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 2, &msgs[1] ); } // free msgs diff --git a/upnp/src/ssdp/ssdp_server.c b/upnp/src/ssdp/ssdp_server.c index c40d465..936e025 100644 --- a/upnp/src/ssdp/ssdp_server.c +++ b/upnp/src/ssdp/ssdp_server.c @@ -42,27 +42,25 @@ #include "httpparser.h" #include "httpreadwrite.h" -#ifdef WIN32 - #include - #include - #include - #include "unixutil.h" -#endif - #define MAX_TIME_TOREAD 45 -CLIENTONLY( SOCKET gSsdpReqSocket = 0; ) +CLIENTONLY( SOCKET gSsdpReqSocket4 = INVALID_SOCKET; ) +CLIENTONLY( SOCKET gSsdpReqSocket6 = INVALID_SOCKET; ) void RequestHandler(); +int create_ssdp_sock_v4( SOCKET* ssdpSock ); +int create_ssdp_sock_v6( SOCKET* ssdpSock ); +#if INCLUDE_CLIENT_APIS +int create_ssdp_sock_reqv4( SOCKET* ssdpReqSock ); +int create_ssdp_sock_reqv6( SOCKET* ssdpReqSock ); +#endif Event ErrotEvt; enum Listener { Idle, Stopping, Running }; -unsigned short ssdpStopPort; - struct SSDPSockArray { // socket for incoming advertisments and search requests - int ssdpSock; + SOCKET ssdpSock; // socket for sending search requests and receiving search replies CLIENTONLY( int ssdpReqSock; ) }; @@ -80,10 +78,10 @@ struct SSDPSockArray { * 1 = Send Advertisement * IN UpnpDevice_Handle Hnd: Device handle * IN enum SsdpSearchType SearchType:Search type for sending replies - * IN struct sockaddr_in *DestAddr:Destination address - * IN char *DeviceType:Device type + * IN struct sockaddr *DestAddr:Destination address + * IN char *DeviceType:Device type * IN char *DeviceUDN:Device UDN - * IN char *ServiceType:Service type + * IN char *ServiceType:Service type * IN int Exp:Advertisement age * * Description: @@ -95,7 +93,7 @@ struct SSDPSockArray { int AdvertiseAndReply( IN int AdFlag, IN UpnpDevice_Handle Hnd, IN enum SsdpSearchType SearchType, - IN struct sockaddr_in *DestAddr, + IN struct sockaddr *DestAddr, IN char *DeviceType, IN char *DeviceUDN, IN char *ServiceType, @@ -234,10 +232,10 @@ int AdvertiseAndReply( IN int AdFlag, // send the device advertisement if( AdFlag == 1 ) { DeviceAdvertisement( devType, i == 0, - UDNstr, SInfo->DescURL, Exp ); + UDNstr, SInfo->DescURL, Exp, SInfo->DeviceAf ); } else { // AdFlag == -1 DeviceShutdown( devType, i == 0, UDNstr, - SERVER, SInfo->DescURL, Exp ); + SERVER, SInfo->DescURL, Exp, SInfo->DeviceAf ); } } else { switch ( SearchType ) { @@ -353,10 +351,10 @@ int AdvertiseAndReply( IN int AdFlag, if( AdFlag ) { if( AdFlag == 1 ) { ServiceAdvertisement( UDNstr, servType, - SInfo->DescURL, Exp ); + SInfo->DescURL, Exp, SInfo->DeviceAf ); } else { // AdFlag == -1 ServiceShutdown( UDNstr, servType, - SInfo->DescURL, Exp ); + SInfo->DescURL, Exp, SInfo->DeviceAf ); } } else { switch ( SearchType ) { @@ -403,7 +401,7 @@ int AdvertiseAndReply( IN int AdFlag, * Function : Make_Socket_NoBlocking * * Parameters: - * IN int sock: socket + * IN SOCKET sock: socket * * Description: * This function makes socket non-blocking. @@ -412,7 +410,7 @@ int AdvertiseAndReply( IN int AdFlag, * 0 if successful else -1 ***************************************************************************/ int -Make_Socket_NoBlocking( int sock ) +Make_Socket_NoBlocking( SOCKET sock ) { #ifdef WIN32 u_long val=1; @@ -655,8 +653,11 @@ valid_ssdp_msg( IN http_message_t * hmsg ) } // check HOST header if( ( httpmsg_find_hdr( hmsg, HDR_HOST, &hdr_value ) == NULL ) || - ( memptr_cmp( &hdr_value, "239.255.255.250:1900" ) != 0 ) + ( ( memptr_cmp( &hdr_value, "239.255.255.250:1900" ) != 0 ) && + ( memptr_cmp( &hdr_value, "[FF02::C]:1900" ) != 0 ) ) ) { + UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, + "Invalid HOST header from SSDP message\n" ); return FALSE; } } @@ -705,7 +706,7 @@ start_event_handler( void *Data ) goto error_handler; } // check msg - if( !valid_ssdp_msg( &parser->msg ) ) { + if( valid_ssdp_msg( &parser->msg ) != TRUE ) { goto error_handler; } return 0; //////// done; thread will free 'data' @@ -740,9 +741,10 @@ ssdp_event_handler_thread( void *the_data ) // send msg to device or ctrlpt if( ( hmsg->method == HTTPMETHOD_NOTIFY ) || ( hmsg->request_method == HTTPMETHOD_MSEARCH ) ) { - CLIENTONLY( ssdp_handle_ctrlpt_msg( hmsg, &data->dest_addr, FALSE, NULL );) + CLIENTONLY( ssdp_handle_ctrlpt_msg( hmsg, + (struct sockaddr*)&data->dest_addr, FALSE, NULL );) } else { - ssdp_handle_device_request( hmsg, &data->dest_addr ); + ssdp_handle_device_request( hmsg, (struct sockaddr*)&data->dest_addr ); } // free data @@ -766,11 +768,12 @@ readFromSSDPSocket( SOCKET socket ) { char *requestBuf = NULL; char staticBuf[BUFSIZE]; - struct sockaddr_in clientAddr; + struct sockaddr_storage __ss; ThreadPoolJob job; ssdp_thread_data *data = NULL; - socklen_t socklen = 0; + socklen_t socklen = sizeof( __ss ); int byteReceived = 0; + char ntop_buf[64]; requestBuf = staticBuf; @@ -778,8 +781,6 @@ readFromSSDPSocket( SOCKET socket ) //can't be allocated, still drain the //socket using a static buffer - socklen = sizeof( struct sockaddr_in ); - data = ( ssdp_thread_data * ) malloc( sizeof( ssdp_thread_data ) ); @@ -787,7 +788,7 @@ readFromSSDPSocket( SOCKET socket ) //initialize parser #ifdef INCLUDE_CLIENT_APIS - if( socket == gSsdpReqSocket ) { + if( socket == gSsdpReqSocket4 || socket == gSsdpReqSocket6 ) { parser_response_init( &data->parser, HTTPMETHOD_MSEARCH ); } else { parser_request_init( &data->parser ); @@ -809,10 +810,18 @@ readFromSSDPSocket( SOCKET socket ) } byteReceived = recvfrom( socket, requestBuf, BUFSIZE - 1, 0, - ( struct sockaddr * )&clientAddr, &socklen ); + (struct sockaddr *)&__ss, &socklen ); if( byteReceived > 0 ) { requestBuf[byteReceived] = '\0'; + + if( __ss.ss_family == AF_INET ) + inet_ntop( AF_INET, &((struct sockaddr_in*)&__ss)->sin_addr, ntop_buf, sizeof(ntop_buf) ); + else if( __ss.ss_family == AF_INET6 ) + inet_ntop( AF_INET6, &((struct sockaddr_in6*)&__ss)->sin6_addr, ntop_buf, sizeof(ntop_buf) ); + else + strncpy( ntop_buf, "", sizeof(ntop_buf) ); + UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, "Start of received response ----------------------------------------------------\n" @@ -820,7 +829,7 @@ readFromSSDPSocket( SOCKET socket ) "End of received response ------------------------------------------------------\n" "From host %s\n", requestBuf, - inet_ntoa( clientAddr.sin_addr ) ); + ntop_buf ); UpnpPrintf( UPNP_PACKET, SSDP, __FILE__, __LINE__, "Start of received multicast packet --------------------------------------------\n" "%s\n" @@ -831,7 +840,7 @@ readFromSSDPSocket( SOCKET socket ) data->parser.msg.msg.length += byteReceived; // null-terminate data->parser.msg.msg.buf[byteReceived] = 0; - data->dest_addr = clientAddr; + memcpy( &data->dest_addr, &__ss, sizeof(__ss) ); TPJobInit( &job, ( start_routine ) ssdp_event_handler_thread, data ); TPJobSetFreeFunction( &job, free_ssdp_event_handler_data ); @@ -846,132 +855,261 @@ readFromSSDPSocket( SOCKET socket ) } } + /************************************************************************ * Function : get_ssdp_sockets * * Parameters: - * OUT MiniServerSockArray *out: Arrays of SSDP sockets + * OUT MiniServerSockArray *out: Array of SSDP sockets * * Description: - * This function creates the ssdp sockets. It set their option to listen - * for multicast traffic. + * This function creates the IPv4 and IPv6 ssdp sockets required by the + * control point and device operation. * * Returns: int * return UPNP_E_SUCCESS if successful else returns appropriate error ***************************************************************************/ -int -get_ssdp_sockets( MiniServerSockArray * out ) +int get_ssdp_sockets( MiniServerSockArray * out ) { - char errorBuffer[ERROR_BUFFER_LEN]; - int onOff = 1; - u_char ttl = 4; - struct ip_mreq ssdpMcastAddr; - struct sockaddr_in ssdpAddr; - int option = 1; - int ret = 0; - struct in_addr addr; - SOCKET ssdpSock; + int retVal; + #if INCLUDE_CLIENT_APIS - SOCKET ssdpReqSock; - - ssdpReqSock = socket( AF_INET, SOCK_DGRAM, 0 ); - if ( ssdpReqSock == -1 ) { - strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); - UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, - "Error in socket(): %s\n", errorBuffer ); - - return UPNP_E_OUTOF_SOCKET; + // Create the IPv4 socket for SSDP REQUESTS + if( strlen( gIF_IPV4 ) > 0 ) { + retVal = create_ssdp_sock_reqv4( &out->ssdpReqSock4 ); + if( retVal != UPNP_E_SUCCESS ) { + return retVal; + } + // For use by ssdp control point. + gSsdpReqSocket4 = out->ssdpReqSock4; + } else { + out->ssdpReqSock4 = INVALID_SOCKET; + } + + // Create the IPv6 socket for SSDP REQUESTS + if( strlen( gIF_IPV6 ) > 0 ) { + retVal = create_ssdp_sock_reqv6( &out->ssdpReqSock6 ); + if( retVal != UPNP_E_SUCCESS ) { + CLIENTONLY( shutdown( out->ssdpReqSock4, SD_BOTH ); ) + CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock4 ); ) + return retVal; + } + // For use by ssdp control point. + gSsdpReqSocket6 = out->ssdpReqSock6; + } else { + out->ssdpReqSock6 = INVALID_SOCKET; } - ret = setsockopt( ssdpReqSock, IPPROTO_IP, IP_MULTICAST_TTL, - &ttl, sizeof (ttl) ); - // just do it, regardless if fails or not. - Make_Socket_NoBlocking( ssdpReqSock ); - gSsdpReqSocket = ssdpReqSock; #endif /* INCLUDE_CLIENT_APIS */ - ssdpSock = socket( AF_INET, SOCK_DGRAM, 0 ); - if ( ssdpSock == -1 ) { + // Create the IPv4 socket for SSDP + if( strlen( gIF_IPV4 ) > 0 ) { + retVal = create_ssdp_sock_v4( &out->ssdpSock4 ); + if( retVal != UPNP_E_SUCCESS ) { + CLIENTONLY( shutdown( out->ssdpReqSock4, SD_BOTH ); ) + CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock4 ); ) + CLIENTONLY( shutdown( out->ssdpReqSock6, SD_BOTH ); ) + CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock6 ); ) + return retVal; + } + } else { + out->ssdpSock4 = INVALID_SOCKET; + } + + // Create the IPv6 socket for SSDP + if( strlen( gIF_IPV6 ) > 0 ) { + retVal = create_ssdp_sock_v6( &out->ssdpSock6 ); + if( retVal != UPNP_E_SUCCESS ) { + shutdown( out->ssdpSock4, SD_BOTH ); + UpnpCloseSocket( out->ssdpSock4 ); + CLIENTONLY( shutdown( out->ssdpReqSock4, SD_BOTH ); ) + CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock4 ); ) + CLIENTONLY( shutdown( out->ssdpReqSock6, SD_BOTH ); ) + CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock6 ); ) + return retVal; + } + } else { + out->ssdpSock6 = INVALID_SOCKET; + } + + return UPNP_E_SUCCESS; +} + + +#if INCLUDE_CLIENT_APIS +/************************************************************************ + * Function : create_ssdp_sock_reqv4 + * + * Parameters: + * IN SOCKET* ssdpReqSock: SSDP IPv4 request socket to be created + * + * Description: + * This function creates the SSDP IPv4 socket to be used by the control + * point. + * + * Returns: + * UPNP_E_SUCCESS on successful socket creation. + ***************************************************************************/ +int create_ssdp_sock_reqv4( SOCKET* ssdpReqSock ) +{ + char errorBuffer[ERROR_BUFFER_LEN]; + u_char ttl = 4; + + *ssdpReqSock = socket( AF_INET, SOCK_DGRAM, 0 ); + if ( *ssdpReqSock == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in socket(): %s\n", errorBuffer ); + return UPNP_E_OUTOF_SOCKET; + } + + setsockopt( *ssdpReqSock, IPPROTO_IP, IP_MULTICAST_TTL, + &ttl, sizeof (ttl) ); + + // just do it, regardless if fails or not. + Make_Socket_NoBlocking( *ssdpReqSock ); + + return UPNP_E_SUCCESS; +} + + +/************************************************************************ + * Function : create_ssdp_sock_reqv6 + * + * Parameters: + * IN SOCKET* ssdpReqSock: SSDP IPv6 request socket to be created + * + * Description: + * This function creates the SSDP IPv6 socket to be used by the control + * point. + * + * Returns: void + * + ***************************************************************************/ +int create_ssdp_sock_reqv6( SOCKET* ssdpReqSock ) +{ + char errorBuffer[ERROR_BUFFER_LEN]; + char hops = 1; + + *ssdpReqSock = socket( AF_INET6, SOCK_DGRAM, 0 ); + if ( *ssdpReqSock == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in socket(): %s\n", errorBuffer ); + return UPNP_E_OUTOF_SOCKET; + } + + // MUST use scoping of IPv6 addresses to control the propagation os SSDP + // messages instead of relying on the Hop Limit (Equivalent to the TTL + // limit in IPv4). + setsockopt( *ssdpReqSock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &hops, sizeof(hops) ); + + // just do it, regardless if fails or not. + Make_Socket_NoBlocking( *ssdpReqSock ); + + return UPNP_E_SUCCESS; +} +#endif /* INCLUDE_CLIENT_APIS */ + + +/************************************************************************ + * Function : create_ssdp_sock_v4 + * + * Parameters: + * IN SOCKET* ssdpSock: SSDP IPv4 socket to be created + * + * Description: + * This function ... + * + * Returns: void + * + ***************************************************************************/ +int create_ssdp_sock_v4( SOCKET* ssdpSock ) +{ + char errorBuffer[ERROR_BUFFER_LEN]; + int onOff; + u_char ttl = 4; + struct ip_mreq ssdpMcastAddr; + struct sockaddr_storage __ss; + struct sockaddr_in* ssdpAddr4 = (struct sockaddr_in*)&__ss; + int ret = 0; + struct in_addr addr; + + + *ssdpSock = socket( AF_INET, SOCK_DGRAM, 0 ); + if ( *ssdpSock == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in socket(): %s\n", errorBuffer ); - CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) - CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) return UPNP_E_OUTOF_SOCKET; } onOff = 1; - ret = setsockopt( ssdpSock, SOL_SOCKET, SO_REUSEADDR, - (char *)&onOff, sizeof(onOff) ); + ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_REUSEADDR, + (char*)&onOff, sizeof(onOff) ); if ( ret == -1) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in setsockopt() SO_REUSEADDR: %s\n", errorBuffer ); - CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) - CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) - shutdown( ssdpSock, SD_BOTH ); - UpnpCloseSocket( ssdpSock ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); return UPNP_E_SOCKET_ERROR; } #if defined(__FreeBSD__) || defined(__OSX__) || defined(__APPLE__) - ret = setsockopt( ssdpSock, SOL_SOCKET, SO_REUSEPORT, - (char *)&onOff, sizeof (onOff) ); + onOff = 1; + ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_REUSEPORT, + (char *)&onOff, sizeof(onOff) ); if ( ret == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in setsockopt() SO_REUSEPORT: %s\n", errorBuffer ); - CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) - CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) - shutdown( ssdpSock, SD_BOTH ); - UpnpCloseSocket( ssdpSock ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); return UPNP_E_SOCKET_ERROR; } #endif /* __FreeBSD__ */ - memset( (void *)&ssdpAddr, 0, sizeof( struct sockaddr_in ) ); - ssdpAddr.sin_family = AF_INET; - // ssdpAddr.sin_addr.s_addr = inet_addr(LOCAL_HOST); - ssdpAddr.sin_addr.s_addr = htonl( INADDR_ANY ); - ssdpAddr.sin_port = htons( SSDP_PORT ); - ret = bind( ssdpSock, (struct sockaddr *)&ssdpAddr, sizeof (ssdpAddr) ); + memset( &__ss, 0, sizeof( __ss ) ); + ssdpAddr4->sin_family = AF_INET; + // ssdpAddr.sin_addr.s_addr = inet_addr(gIF_IPV4); + ssdpAddr4->sin_addr.s_addr = htonl( INADDR_ANY ); + ssdpAddr4->sin_port = htons( SSDP_PORT ); + ret = bind( *ssdpSock, (struct sockaddr *)&__ss, sizeof(__ss) ); if ( ret == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in bind(), addr=0x%08X, port=%d: %s\n", INADDR_ANY, SSDP_PORT, errorBuffer ); - shutdown( ssdpSock, SD_BOTH ); - UpnpCloseSocket( ssdpSock ); - CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) - CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); return UPNP_E_SOCKET_BIND; } memset( (void *)&ssdpMcastAddr, 0, sizeof (struct ip_mreq) ); - ssdpMcastAddr.imr_interface.s_addr = inet_addr( LOCAL_HOST ); + ssdpMcastAddr.imr_interface.s_addr = inet_addr( gIF_IPV4 ); ssdpMcastAddr.imr_multiaddr.s_addr = inet_addr( SSDP_IP ); - ret = setsockopt( ssdpSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (char *)&ssdpMcastAddr, sizeof (struct ip_mreq) ); + ret = setsockopt( *ssdpSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *)&ssdpMcastAddr, sizeof(struct ip_mreq) ); if ( ret == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in setsockopt() IP_ADD_MEMBERSHIP (join multicast group): %s\n", errorBuffer ); - shutdown( ssdpSock, SD_BOTH ); - CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) - UpnpCloseSocket( ssdpSock ); - CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); return UPNP_E_SOCKET_ERROR; } /* Set multicast interface. */ memset( (void *)&addr, 0, sizeof (struct in_addr) ); - addr.s_addr = inet_addr(LOCAL_HOST); - ret = setsockopt(ssdpSock, IPPROTO_IP, IP_MULTICAST_IF, + addr.s_addr = inet_addr(gIF_IPV4); + ret = setsockopt(*ssdpSock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&addr, sizeof addr); if ( ret == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); @@ -982,26 +1120,132 @@ get_ssdp_sockets( MiniServerSockArray * out ) } /* result is not checked becuase it will fail in WinMe and Win9x. */ - ret = setsockopt( ssdpSock, IPPROTO_IP, + ret = setsockopt( *ssdpSock, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof (ttl) ); - ret = setsockopt( ssdpSock, SOL_SOCKET, SO_BROADCAST, - (char *)&option, sizeof (option) ); + onOff = 1; + ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_BROADCAST, + (char*)&onOff, sizeof(onOff) ); if( ret == -1) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, "Error in setsockopt() SO_BROADCAST (set broadcast): %s\n", errorBuffer ); - shutdown( ssdpSock, SD_BOTH ); - CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ); ) - UpnpCloseSocket( ssdpSock ); - CLIENTONLY( UpnpCloseSocket( ssdpReqSock ); ) + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); return UPNP_E_NETWORK_ERROR; } - CLIENTONLY( out->ssdpReqSock = ssdpReqSock; ) - out->ssdpSock = ssdpSock; + return UPNP_E_SUCCESS; +} + + +/************************************************************************ + * Function : create_ssdp_sock_v6 + * + * Parameters: + * IN SOCKET* ssdpSock: SSDP IPv6 socket to be created + * + * Description: + * This function ... + * + * Returns: void + * + ***************************************************************************/ +int create_ssdp_sock_v6( SOCKET* ssdpSock ) +{ + char errorBuffer[ERROR_BUFFER_LEN]; + struct ipv6_mreq ssdpMcastAddr; + struct sockaddr_storage __ss; + struct sockaddr_in6* ssdpAddr6 = (struct sockaddr_in6*)&__ss; + int onOff; + int ret = 0; + + *ssdpSock = socket( AF_INET6, SOCK_DGRAM, 0 ); + if ( *ssdpSock == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in socket(): %s\n", errorBuffer ); + + return UPNP_E_OUTOF_SOCKET; + } + + onOff = 1; + ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_REUSEADDR, + (char*)&onOff, sizeof(onOff) ); + if ( ret == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in setsockopt() SO_REUSEADDR: %s\n", errorBuffer ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); + + return UPNP_E_SOCKET_ERROR; + } + +#if defined(__FreeBSD__) || defined(__OSX__) || defined(__APPLE__) + onOff = 1; + ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_REUSEPORT, + (char*)&onOff, sizeof (onOff) ); + if ( ret == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in setsockopt() SO_REUSEPORT: %s\n", errorBuffer ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); + + return UPNP_E_SOCKET_ERROR; + } +#endif /* __FreeBSD__ */ + + memset( &__ss, 0, sizeof( __ss ) ); + ssdpAddr6->sin6_family = AF_INET6; + ssdpAddr6->sin6_addr = in6addr_any; + //inet_pton( AF_INET6, gIF_IPV6, &ssdpAddr6->sin6_addr ); + ssdpAddr6->sin6_scope_id = gIF_INDEX; + ssdpAddr6->sin6_port = htons( SSDP_PORT ); + ret = bind( *ssdpSock, (struct sockaddr *)&__ss, sizeof(__ss) ); + if ( ret == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in bind(), addr=0x%032lX, port=%d: %s\n", + 0lu, SSDP_PORT, errorBuffer ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); + + return UPNP_E_SOCKET_BIND; + } + + memset( (void *)&ssdpMcastAddr, 0, sizeof(ssdpMcastAddr) ); + ssdpMcastAddr.ipv6mr_interface = gIF_INDEX; + inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &ssdpMcastAddr.ipv6mr_multiaddr ); + ret = setsockopt( *ssdpSock, IPPROTO_IPV6, IPV6_JOIN_GROUP, + (char *)&ssdpMcastAddr, sizeof(ssdpMcastAddr) ); + if ( ret == -1 ) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in setsockopt() IPV6_JOIN_GROUP (join multicast group): %s\n", + errorBuffer ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); + + return UPNP_E_SOCKET_ERROR; + } + + onOff = 1; + ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_BROADCAST, + (char*)&onOff, sizeof(onOff) ); + if( ret == -1) { + strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); + UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__, + "Error in setsockopt() SO_BROADCAST (set broadcast): %s\n", + errorBuffer ); + shutdown( *ssdpSock, SD_BOTH ); + UpnpCloseSocket( *ssdpSock ); + + return UPNP_E_NETWORK_ERROR; + } return UPNP_E_SUCCESS; } diff --git a/upnp/src/urlconfig/urlconfig.c b/upnp/src/urlconfig/urlconfig.c index c2877d2..624e23b 100644 --- a/upnp/src/urlconfig/urlconfig.c +++ b/upnp/src/urlconfig/urlconfig.c @@ -51,7 +51,7 @@ * Function : addrToString * * Parameters : -* IN const struct sockaddr_in* addr ; socket address object with +* IN const struct sockaddr* addr ; socket address object with * the IP Address and port information * OUT char ipaddr_port[] ; character array which will hold the * IP Address in a string format. @@ -64,11 +64,20 @@ * Note : ************************************************************************/ static UPNP_INLINE void -addrToString( IN const struct sockaddr_in *addr, +addrToString( IN const struct sockaddr *addr, OUT char ipaddr_port[] ) { - sprintf( ipaddr_port, "%s:%d", inet_ntoa( addr->sin_addr ), - ntohs( addr->sin_port ) ); + char buf_ntop[64]; + + if( addr->sa_family == AF_INET ) { + struct sockaddr_in* sa4 = (struct sockaddr_in*)addr; + inet_ntop(AF_INET, &sa4->sin_addr, buf_ntop, sizeof(buf_ntop) ); + sprintf( ipaddr_port, "%s:%d", buf_ntop, ntohs( sa4->sin_port ) ); + } else if( addr->sa_family == AF_INET6 ) { + struct sockaddr_in6* sa6 = (struct sockaddr_in6*)addr; + inet_ntop(AF_INET6, &sa6->sin6_addr, buf_ntop, sizeof(buf_ntop) ); + sprintf( ipaddr_port, "[%s]:%d", buf_ntop, ntohs( sa6->sin6_port ) ); + } } /************************************************************************ @@ -344,7 +353,7 @@ config_description_doc( INOUT IXML_Document * doc, * * Parameters : * INOUT IXML_Document *doc ; IXML Description document -* IN const struct sockaddr_in* serverAddr ; socket address object +* IN const struct sockaddr* serverAddr ; socket address object * providing the IP address and port information * IN const char* alias ; string containing the alias * IN time_t last_modified ; time when the XML document was @@ -352,7 +361,7 @@ config_description_doc( INOUT IXML_Document * doc, * OUT char docURL[LINE_SIZE] ; buffer to hold the URL of the * document. * INOUT IXML_Document *doc:dom document whose urlbase is to be modified -* IN const struct sockaddr_in* serverAddr : ip address and port of +* IN const struct sockaddr* serverAddr : ip address and port of * the miniserver * IN const char* alias : a name to be used for the temp; e.g.:"foo.xml" * IN time_t last_modified : time @@ -371,7 +380,7 @@ config_description_doc( INOUT IXML_Document * doc, ************************************************************************/ int configure_urlbase( INOUT IXML_Document * doc, - IN const struct sockaddr_in *serverAddr, + IN const struct sockaddr *serverAddr, IN const char *alias, IN time_t last_modified, OUT char docURL[LINE_SIZE] )