/******************************************************************************* * * Copyright (c) 2000-2003 Intel Corporation * All rights reserved. * Copyright (C) 2011-2012 France Telecom All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither name of Intel Corporation nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ******************************************************************************/ /*! * \addtogroup UPnPAPI * * @{ * * \file */ #include "config.h" #include "upnpapi.h" #include "httpreadwrite.h" #include "membuffer.h" #include "ssdplib.h" #include "soaplib.h" #include "sysdep.h" #include "ThreadPool.h" #include "UpnpStdInt.h" #include "UpnpUniStd.h" /* for close() */ #include "uuid.h" /* Needed for GENA */ #include "gena.h" #include "miniserver.h" #include "service_table.h" #ifdef INTERNAL_WEB_SERVER #include "urlconfig.h" #include "VirtualDir.h" #include "webserver.h" #endif /* INTERNAL_WEB_SERVER */ #include #include #include #include #include #ifdef WIN32 /* Do not include these files */ #else #include #include #include #endif #ifndef IN6_IS_ADDR_GLOBAL #define IN6_IS_ADDR_GLOBAL(a) \ ((((__const uint32_t *) (a))[0] & htonl(0x70000000)) \ == htonl (0x20000000)) #endif /* IS ADDR GLOBAL */ #ifndef IN6_IS_ADDR_ULA #define IN6_IS_ADDR_ULA(a) \ ((((__const uint32_t *) (a))[0] & htonl(0xfe000000)) \ == htonl (0xfc000000)) #endif /* IS ADDR ULA */ /*! This structure is for virtual directory callbacks */ struct VirtualDirCallbacks virtualDirCallback; /*! Pointer to the virtual directory list. */ virtualDirList *pVirtualDirList; #ifdef INCLUDE_CLIENT_APIS /*! Mutex to synchronize the subscription handling at the client side. */ ithread_mutex_t GlobalClientSubscribeMutex; #endif /* INCLUDE_CLIENT_APIS */ /*! rwlock to synchronize handles (root device or control point handle). */ ithread_rwlock_t GlobalHndRWLock; /*! Mutex to synchronize the uuid creation process. */ ithread_mutex_t gUUIDMutex; /*! Initialization mutex. */ ithread_mutex_t gSDKInitMutex = PTHREAD_MUTEX_INITIALIZER; /*! Global timer thread. */ TimerThread gTimerThread; /*! Send thread pool. */ ThreadPool gSendThreadPool; /*! Receive thread pool. */ ThreadPool gRecvThreadPool; /*! Mini server thread pool. */ ThreadPool gMiniServerThreadPool; /*! Flag to indicate the state of web server */ WebServerState bWebServerState = WEB_SERVER_DISABLED; /*! Static buffer to contain interface name. (extern'ed in upnp.h) */ char gIF_NAME[LINE_SIZE] = { '\0' }; /*! Static buffer to contain interface IPv4 address. (extern'ed in upnp.h) */ char gIF_IPV4[INET_ADDRSTRLEN] = { '\0' }; /*! Static buffer to contain interface IPv6 address. (extern'ed in upnp.h) */ char gIF_IPV6[INET6_ADDRSTRLEN] = { '\0' }; /*! Static buffer to contain interface ULA or GUA IPv6 address. (extern'ed in upnp.h) */ char gIF_IPV6_ULA_GUA[INET6_ADDRSTRLEN] = { '\0' }; /*! Contains interface index. (extern'ed in upnp.h) */ unsigned gIF_INDEX = (unsigned)-1; /*! local IPv4 port for the mini-server */ unsigned short LOCAL_PORT_V4; /*! local IPv6 port for the mini-server */ unsigned short LOCAL_PORT_V6; /*! UPnP device and control point handle table */ #define NUM_HANDLE 200 static void *HandleTable[NUM_HANDLE]; /*! a local dir which serves as webserver root */ extern membuffer gDocumentRootDir; /*! Maximum content-length (in bytes) that the SDK will process on an incoming * packet. Content-Length exceeding this size will be not processed and * error 413 (HTTP Error Code) will be returned to the remote end point. */ size_t g_maxContentLength = DEFAULT_SOAP_CONTENT_LENGTH; /*! Global variable to denote the state of Upnp SDK == 0 if uninitialized, * == 1 if initialized. */ int UpnpSdkInit = 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; #ifdef UPNP_HAVE_OPTSSDP /*! Global variable used in discovery notifications. */ Upnp_SID gUpnpSdkNLSuuid; #endif /* UPNP_HAVE_OPTSSDP */ /*! * \brief (Windows Only) Initializes the Windows Winsock library. * * \return UPNP_E_SUCCESS on success, UPNP_E_INIT_FAILED on failure. */ static int WinsockInit(void) { int retVal = UPNP_E_SUCCESS; #ifdef WIN32 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. */ retVal = UPNP_E_INIT_FAILED; goto exit_function; } /* 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(); retVal = UPNP_E_INIT_FAILED; goto exit_function; } /* The WinSock DLL is acceptable. Proceed. */ exit_function: #else #endif return retVal; } /*! * \brief Initializes the global mutexes used by the UPnP SDK. * * \return UPNP_E_SUCCESS on success or UPNP_E_INIT_FAILED if a mutex could not * be initialized. */ static 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; } /*! * \brief Initializes the global threadm pools used by the UPnP SDK. * * \return UPNP_E_SUCCESS on success or UPNP_E_INIT_FAILED if a mutex could not * be initialized. */ static int UpnpInitThreadPools(void) { int ret = UPNP_E_SUCCESS; ThreadPoolAttr attr; TPAttrInit(&attr); TPAttrSetMaxThreads(&attr, MAX_THREADS); TPAttrSetMinThreads(&attr, MIN_THREADS); TPAttrSetStackSize(&attr, THREAD_STACK_SIZE); TPAttrSetJobsPerThread(&attr, JOBS_PER_THREAD); TPAttrSetIdleTime(&attr, THREAD_IDLE_TIME); TPAttrSetMaxJobsTotal(&attr, MAX_JOBS_TOTAL); if (ThreadPoolInit(&gSendThreadPool, &attr) != UPNP_E_SUCCESS) { ret = UPNP_E_INIT_FAILED; goto exit_function; } if (ThreadPoolInit(&gRecvThreadPool, &attr) != UPNP_E_SUCCESS) { ret = UPNP_E_INIT_FAILED; goto exit_function; } if (ThreadPoolInit(&gMiniServerThreadPool, &attr) != UPNP_E_SUCCESS) { ret = UPNP_E_INIT_FAILED; goto exit_function; } exit_function: if (ret != UPNP_E_SUCCESS) { UpnpSdkInit = 0; UpnpFinish(); } return ret; } /*! * \brief Performs the initial steps in initializing the UPnP SDK. * * \li Winsock library is initialized for the process (Windows specific). * \li The logging (for debug messages) is initialized. * \li Mutexes, Handle table and thread pools are allocated and initialized. * \li Callback functions for SOAP and GENA are set, if they're enabled. * \li The SDK timer thread is initialized. * * \return UPNP_E_SUCCESS on success. */ static int UpnpInitPreamble(void) { int retVal = UPNP_E_SUCCESS; int i; #ifdef UPNP_HAVE_OPTSSDP uuid_upnp nls_uuid; #endif /* UPNP_HAVE_OPTSSDP */ retVal = WinsockInit(); if (retVal != UPNP_E_SUCCESS) { return retVal; } /* needed by SSDP or other parts. */ srand((unsigned int)time(NULL)); /* 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; } #ifdef UPNP_HAVE_OPTSSDP /* Create the NLS uuid. */ uuid_create(&nls_uuid); uuid_unpack(&nls_uuid, gUpnpSdkNLSuuid); #endif /* UPNP_HAVE_OPTSSDP */ /* Initializes the handle list. */ HandleLock(); for (i = 0; i < NUM_HANDLE; ++i) { HandleTable[i] = NULL; } 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; } /*! * \brief Finishes initializing the UPnP SDK. * \li The MiniServer is started, if enabled. * \li The WebServer is started, if enabled. * * \return UPNP_E_SUCCESS on success or UPNP_E_INIT_FAILED if a mutex could not * be initialized. */ static int UpnpInitStartServers( /*! [in] Local Port to listen for incoming connections. */ unsigned short DestPort) { #if EXCLUDE_MINISERVER == 0 || EXCLUDE_WEB_SERVER == 0 int retVal = 0; #endif 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; } int UpnpInit(const char *HostIP, unsigned short DestPort) { int retVal = UPNP_E_SUCCESS; /* Initializes the ithread library */ ithread_initialize_library(); ithread_mutex_lock(&gSDKInitMutex); /* Check if we're already initialized. */ if (UpnpSdkInit == 1) { retVal = UPNP_E_INIT; goto exit_function; } /* Perform initialization preamble. */ retVal = UpnpInitPreamble(); if (retVal != UPNP_E_SUCCESS) { goto exit_function; } UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "UpnpInit with HostIP=%s, DestPort=%d.\n", HostIP ? HostIP : "", (int)DestPort); /* Verify HostIP, if provided, or find it ourselves. */ memset(gIF_IPV4, 0, sizeof(gIF_IPV4)); if (HostIP != NULL) { strncpy(gIF_IPV4, HostIP, sizeof(gIF_IPV4) - 1); } else { if( getlocalhostname( gIF_IPV4, sizeof(gIF_IPV4) - 1 ) != UPNP_E_SUCCESS ) { retVal = UPNP_E_INIT_FAILED; goto exit_function; } } /* Set the UpnpSdkInit flag to 1 to indicate we're successfully initialized. */ UpnpSdkInit = 1; /* Finish initializing the SDK. */ retVal = UpnpInitStartServers(DestPort); if (retVal != UPNP_E_SUCCESS) { UpnpSdkInit = 0; goto exit_function; } UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Host Ip: %s Host Port: %d\n", gIF_IPV4, (int)LOCAL_PORT_V4); exit_function: ithread_mutex_unlock(&gSDKInitMutex); return retVal; } #ifdef UPNP_ENABLE_IPV6 int UpnpInit2(const char *IfName, unsigned short DestPort) { int retVal; /* Initializes the ithread library */ ithread_initialize_library(); ithread_mutex_lock(&gSDKInitMutex); /* Check if we're already initialized. */ if (UpnpSdkInit == 1) { retVal = UPNP_E_INIT; goto exit_function; } /* Perform initialization preamble. */ retVal = UpnpInitPreamble(); if (retVal != UPNP_E_SUCCESS) { goto exit_function; } 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) { goto exit_function; } /* Set the UpnpSdkInit flag to 1 to indicate we're successfully initialized. */ UpnpSdkInit = 1; /* Finish initializing the SDK. */ retVal = UpnpInitStartServers(DestPort); if (retVal != UPNP_E_SUCCESS) { UpnpSdkInit = 0; goto exit_function; } exit_function: ithread_mutex_unlock(&gSDKInitMutex); return retVal; } #endif #ifdef DEBUG /*! * \brief Prints thread pool statistics. */ void PrintThreadPoolStats( /*! [in] The thread pool. */ ThreadPool *tp, /*! [in] The file name that called this function, use the macro * __FILE__. */ const char *DbgFileName, /*! [in] The line number that the function was called, use the macro * __LINE__. */ int DbgLineNo, /*! [in] The message. */ const char *msg) { ThreadPoolStats stats; ThreadPoolGetStats(tp, &stats); UpnpPrintf(UPNP_INFO, API, DbgFileName, DbgLineNo, "%s\n" "High Jobs pending: %d\n" "Med Jobs Pending: %d\n" "Low Jobs Pending: %d\n" "Average wait in High Q in milliseconds: %lf\n" "Average wait in Med Q in milliseconds: %lf\n" "Average wait in Low Q in milliseconds: %lf\n" "Max Threads Used: %d\n" "Worker Threads: %d\n" "Persistent Threads: %d\n" "Idle Threads: %d\n" "Total Threads: %d\n" "Total Work Time: %lf\n" "Total Idle Time: %lf\n", msg, stats.currentJobsHQ, stats.currentJobsMQ, stats.currentJobsLQ, stats.avgWaitHQ, stats.avgWaitMQ, stats.avgWaitLQ, stats.maxThreads, stats.workerThreads, stats.persistentThreads, stats.idleThreads, stats.totalThreads, stats.totalWorkTime, stats.totalIdleTime); } #else static UPNP_INLINE void PrintThreadPoolStats(ThreadPool *tp, const char *DbgFileName, int DbgLineNo, const char *msg) { return; tp = tp; DbgFileName = DbgFileName; DbgLineNo = DbgLineNo; msg = msg; } #endif /* DEBUG */ int UpnpFinish(void) { #ifdef INCLUDE_DEVICE_APIS UpnpDevice_Handle device_handle; #endif #ifdef INCLUDE_CLIENT_APIS UpnpClient_Handle client_handle; #endif struct Handle_Info *temp; if (UpnpSdkInit != 1) return UPNP_E_FINISH; UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpFinish: UpnpSdkInit is %d\n", UpnpSdkInit); if (UpnpSdkInit == 1) UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "UpnpFinish: UpnpSdkInit is ONE\n"); PrintThreadPoolStats(&gSendThreadPool, __FILE__, __LINE__, "Send Thread Pool"); PrintThreadPoolStats(&gRecvThreadPool, __FILE__, __LINE__, "Recv Thread Pool"); PrintThreadPoolStats(&gMiniServerThreadPool, __FILE__, __LINE__, "MiniServer Thread Pool"); #ifdef INCLUDE_DEVICE_APIS switch (GetDeviceHandleInfo(AF_INET, &device_handle, &temp)) { case HND_DEVICE: UpnpUnRegisterRootDevice(device_handle); break; default: break; } switch (GetDeviceHandleInfo(AF_INET6, &device_handle, &temp)) { case HND_DEVICE: UpnpUnRegisterRootDevice(device_handle); break; default: break; } #endif #ifdef INCLUDE_CLIENT_APIS switch (GetClientHandleInfo(&client_handle, &temp)) { case HND_CLIENT: UpnpUnRegisterClient(client_handle); break; default: break; } #endif TimerThreadShutdown(&gTimerThread); #if EXCLUDE_MINISERVER == 0 StopMiniServer(); #endif #if EXCLUDE_WEB_SERVER == 0 web_server_destroy(); #endif ThreadPoolShutdown(&gMiniServerThreadPool); PrintThreadPoolStats(&gMiniServerThreadPool, __FILE__, __LINE__, "MiniServer Thread Pool"); ThreadPoolShutdown(&gRecvThreadPool); PrintThreadPoolStats(&gSendThreadPool, __FILE__, __LINE__, "Send Thread Pool"); ThreadPoolShutdown(&gSendThreadPool); PrintThreadPoolStats(&gRecvThreadPool, __FILE__, __LINE__, "Recv Thread Pool"); #ifdef INCLUDE_CLIENT_APIS ithread_mutex_destroy(&GlobalClientSubscribeMutex); #endif ithread_rwlock_destroy(&GlobalHndRWLock); ithread_mutex_destroy(&gUUIDMutex); /* remove all virtual dirs */ UpnpRemoveAllVirtualDirs(); UpnpSdkInit = 0; UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Exiting UpnpFinish: UpnpSdkInit is :%d:\n", UpnpSdkInit); UpnpCloseLog(); /* Clean-up ithread library resources */ ithread_cleanup_library(); return UPNP_E_SUCCESS; } unsigned short UpnpGetServerPort(void) { if (UpnpSdkInit != 1) return 0u; return LOCAL_PORT_V4; } #ifdef UPNP_ENABLE_IPV6 unsigned short UpnpGetServerPort6(void) { if (UpnpSdkInit != 1) return 0u; return LOCAL_PORT_V6; } #endif char *UpnpGetServerIpAddress(void) { if (UpnpSdkInit != 1) return NULL; return gIF_IPV4; } char *UpnpGetServerIp6Address(void) { if (UpnpSdkInit != 1) return NULL; return gIF_IPV6; } char *UpnpGetServerUlaGuaIp6Address(void) { if (UpnpSdkInit != 1) return NULL; return gIF_IPV6_ULA_GUA; } /*! * \brief Get a free handle. * * \return On success, an integer greater than zero or UPNP_E_OUTOF_HANDLE on * failure. */ static int GetFreeHandle() { /* Handle 0 is not used as NULL translates to 0 when passed as a handle */ int i = 1; while (i < NUM_HANDLE && HandleTable[i] != NULL) ++i; if (i == NUM_HANDLE) return UPNP_E_OUTOF_HANDLE; else return i; } /*! * \brief Free handle. * * \return UPNP_E_SUCCESS if successful or UPNP_E_INVALID_HANDLE if not */ static int FreeHandle( /*! [in] Handle index. */ int Upnp_Handle) { int ret = UPNP_E_INVALID_HANDLE; UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "FreeHandle: entering, Handle is %d\n", Upnp_Handle); if (Upnp_Handle < 1 || Upnp_Handle >= NUM_HANDLE) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "FreeHandle: Handle %d is out of range\n", Upnp_Handle); } else if (HandleTable[Upnp_Handle] == NULL) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "FreeHandle: HandleTable[%d] is NULL\n", Upnp_Handle); } else { free( HandleTable[Upnp_Handle] ); HandleTable[Upnp_Handle] = NULL; ret = UPNP_E_SUCCESS; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "FreeHandle: exiting, ret = %d.\n", ret); return ret; } #ifdef INCLUDE_DEVICE_APIS int UpnpRegisterRootDevice( const char *DescUrl, Upnp_FunPtr Fun, const void *Cookie, UpnpDevice_Handle *Hnd) { struct Handle_Info *HInfo = NULL; int retVal = 0; #if EXCLUDE_GENA == 0 int hasServiceTable = 0; #endif /* EXCLUDE_GENA */ HandleLock(); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpRegisterRootDevice\n"); if (UpnpSdkInit != 1) { retVal = UPNP_E_FINISH; goto exit_function; } if (Hnd == NULL || Fun == NULL || DescUrl == NULL || strlen(DescUrl) == (size_t)0) { retVal = UPNP_E_INVALID_PARAM; goto exit_function; } if (UpnpSdkDeviceRegisteredV4 == 1) { retVal = UPNP_E_ALREADY_REGISTERED; goto exit_function; } *Hnd = GetFreeHandle(); if (*Hnd == UPNP_E_OUTOF_HANDLE) { retVal = UPNP_E_OUTOF_MEMORY; goto exit_function; } HInfo = (struct Handle_Info *)malloc(sizeof (struct Handle_Info)); if (HInfo == NULL) { retVal = UPNP_E_OUTOF_MEMORY; goto exit_function; } memset(HInfo, 0, sizeof(struct Handle_Info)); HandleTable[*Hnd] = HInfo; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Root device URL is %s\n", DescUrl ); HInfo->aliasInstalled = 0; HInfo->HType = HND_DEVICE; strncpy(HInfo->DescURL, DescUrl, sizeof(HInfo->DescURL) - 1); strncpy(HInfo->LowerDescURL, DescUrl, sizeof(HInfo->LowerDescURL) - 1); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Following Root Device URL will be used when answering to legacy CPs %s\n", HInfo->LowerDescURL); HInfo->Callback = Fun; HInfo->Cookie = (void *)Cookie; HInfo->MaxAge = DEFAULT_MAXAGE; HInfo->DeviceList = NULL; HInfo->ServiceList = NULL; HInfo->DescDocument = NULL; #ifdef INCLUDE_CLIENT_APIS ListInit(&HInfo->SsdpSearchList, NULL, NULL); HInfo->ClientSubList = NULL; #endif /* INCLUDE_CLIENT_APIS */ HInfo->MaxSubscriptions = UPNP_INFINITE; HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE; HInfo->DeviceAf = AF_INET; retVal = UpnpDownloadXmlDoc(HInfo->DescURL, &(HInfo->DescDocument)); if (retVal != UPNP_E_SUCCESS) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice: error downloading Document: %d\n", retVal); #ifdef INCLUDE_CLIENT_APIS ListDestroy(&HInfo->SsdpSearchList, 0); #endif /* INCLUDE_CLIENT_APIS */ FreeHandle(*Hnd); goto exit_function; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice: Valid Description\n" "UpnpRegisterRootDevice: DescURL : %s\n", HInfo->DescURL); HInfo->DeviceList = ixmlDocument_getElementsByTagName(HInfo->DescDocument, "device"); if (!HInfo->DeviceList) { #ifdef INCLUDE_CLIENT_APIS ListDestroy(&HInfo->SsdpSearchList, 0); #endif /* INCLUDE_CLIENT_APIS */ ixmlDocument_free(HInfo->DescDocument); FreeHandle(*Hnd); UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice: No devices found for RootDevice\n"); retVal = UPNP_E_INVALID_DESC; goto exit_function; } HInfo->ServiceList = ixmlDocument_getElementsByTagName( HInfo->DescDocument, "serviceList"); if (!HInfo->ServiceList) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice: No services found for RootDevice\n"); } #if EXCLUDE_GENA == 0 /* * GENA SET UP */ UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice: Gena Check\n"); memset(&HInfo->ServiceTable, 0, sizeof(HInfo->ServiceTable)); hasServiceTable = getServiceTable( (IXML_Node *)HInfo->DescDocument, &HInfo->ServiceTable, HInfo->DescURL); if (hasServiceTable) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice: GENA Service Table\n" "Here are the known services:\n"); printServiceTable( &HInfo->ServiceTable, UPNP_ALL, API ); } else { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "\nUpnpRegisterRootDevice: Empty service table\n"); } #endif /* EXCLUDE_GENA */ UpnpSdkDeviceRegisteredV4 = 1; retVal = UPNP_E_SUCCESS; exit_function: UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting RegisterRootDevice, return value == %d\n", retVal); HandleUnlock(); return retVal; } #endif /* INCLUDE_DEVICE_APIS */ /*! * \brief Fills the sockadr_in with miniserver information. */ static int GetDescDocumentAndURL( /* [in] pointer to server address structure. */ Upnp_DescType descriptionType, /* [in] . */ char *description, /* [in] . */ int config_baseURL, /* [in] . */ int AddressFamily, /* [out] . */ IXML_Document **xmlDoc, /* [out] . */ char descURL[LINE_SIZE]); #ifdef INCLUDE_DEVICE_APIS int UpnpRegisterRootDevice2( Upnp_DescType descriptionType, const char *description_const, size_t bufferLen, /* ignored */ int config_baseURL, Upnp_FunPtr Fun, const void *Cookie, UpnpDevice_Handle *Hnd) { struct Handle_Info *HInfo = NULL; int retVal = 0; #if EXCLUDE_GENA == 0 int hasServiceTable = 0; #endif /* EXCLUDE_GENA */ char *description = (char *)description_const; HandleLock(); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpRegisterRootDevice2\n"); if (UpnpSdkInit != 1) { retVal = UPNP_E_FINISH; goto exit_function; } if (Hnd == NULL || Fun == NULL) { retVal = UPNP_E_INVALID_PARAM; goto exit_function; } if (UpnpSdkDeviceRegisteredV4 == 1) { retVal = UPNP_E_ALREADY_REGISTERED; goto exit_function; } *Hnd = GetFreeHandle(); if (*Hnd == UPNP_E_OUTOF_HANDLE) { retVal = UPNP_E_OUTOF_MEMORY; goto exit_function; } HInfo = (struct Handle_Info *)malloc(sizeof (struct Handle_Info)); if (HInfo == NULL) { retVal = UPNP_E_OUTOF_MEMORY; goto exit_function; } memset(HInfo, 0, sizeof(struct Handle_Info)); HandleTable[*Hnd] = HInfo; /* prevent accidental removal of a non-existent alias */ HInfo->aliasInstalled = 0; retVal = GetDescDocumentAndURL( descriptionType, description, config_baseURL, AF_INET, &HInfo->DescDocument, HInfo->DescURL); if (retVal != UPNP_E_SUCCESS) { FreeHandle(*Hnd); goto exit_function; } strncpy(HInfo->LowerDescURL, HInfo->DescURL, sizeof(HInfo->LowerDescURL) - 1); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Following Root Device URL will be used when answering to legacy CPs %s\n", HInfo->LowerDescURL); HInfo->aliasInstalled = config_baseURL != 0; HInfo->HType = HND_DEVICE; HInfo->Callback = Fun; HInfo->Cookie = (void *)Cookie; HInfo->MaxAge = DEFAULT_MAXAGE; HInfo->DeviceList = NULL; HInfo->ServiceList = NULL; #ifdef INCLUDE_CLIENT_APIS ListInit(&HInfo->SsdpSearchList, NULL, NULL); HInfo->ClientSubList = NULL; #endif /* INCLUDE_CLIENT_APIS */ HInfo->MaxSubscriptions = UPNP_INFINITE; HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE; HInfo->DeviceAf = AF_INET; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice2: Valid Description\n" "UpnpRegisterRootDevice2: DescURL : %s\n", HInfo->DescURL); HInfo->DeviceList = ixmlDocument_getElementsByTagName( HInfo->DescDocument, "device" ); if (!HInfo->DeviceList) { #ifdef INCLUDE_CLIENT_APIS ListDestroy(&HInfo->SsdpSearchList, 0); #endif /* INCLUDE_CLIENT_APIS */ ixmlDocument_free(HInfo->DescDocument); FreeHandle(*Hnd); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice2: No devices found for RootDevice\n" ); retVal = UPNP_E_INVALID_DESC; goto exit_function; } HInfo->ServiceList = ixmlDocument_getElementsByTagName( HInfo->DescDocument, "serviceList" ); if (!HInfo->ServiceList) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice2: No services found for RootDevice\n"); } #if EXCLUDE_GENA == 0 /* * GENA SET UP */ UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice2: Gena Check\n" ); memset(&HInfo->ServiceTable, 0, sizeof(HInfo->ServiceTable)); hasServiceTable = getServiceTable( (IXML_Node *)HInfo->DescDocument, &HInfo->ServiceTable, HInfo->DescURL); if (hasServiceTable) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice2: GENA Service Table\n" "Here are the known services: \n"); printServiceTable(&HInfo->ServiceTable, UPNP_ALL, API); } else { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "\nUpnpRegisterRootDevice2: Empty service table\n"); } #endif /* EXCLUDE_GENA */ UpnpSdkDeviceRegisteredV4 = 1; retVal = UPNP_E_SUCCESS; exit_function: UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting RegisterRootDevice2, return value == %d\n", retVal); HandleUnlock(); return retVal; bufferLen = bufferLen; } #endif /* INCLUDE_DEVICE_APIS */ #ifdef INCLUDE_DEVICE_APIS int UpnpRegisterRootDevice3( const char *DescUrl, Upnp_FunPtr Fun, const void *Cookie, UpnpDevice_Handle *Hnd, int AddressFamily) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpRegisterRootDevice3\n"); return UpnpRegisterRootDevice4(DescUrl, Fun, Cookie, Hnd, AddressFamily, NULL); } #endif /* INCLUDE_DEVICE_APIS */ #ifdef INCLUDE_DEVICE_APIS int UpnpRegisterRootDevice4( const char *DescUrl, Upnp_FunPtr Fun, const void *Cookie, UpnpDevice_Handle *Hnd, int AddressFamily, const char *LowerDescUrl) { struct Handle_Info *HInfo; int retVal = 0; #if EXCLUDE_GENA == 0 int hasServiceTable = 0; #endif /* EXCLUDE_GENA */ int handler_index = 0; HandleLock(); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpRegisterRootDevice4\n"); if (UpnpSdkInit != 1) { retVal = UPNP_E_FINISH; goto exit_function; } if (Hnd == NULL || Fun == NULL || DescUrl == NULL || strlen(DescUrl) == (size_t)0 || (AddressFamily != AF_INET && AddressFamily != AF_INET6)) { retVal = UPNP_E_INVALID_PARAM; goto exit_function; } /* Test for already regsitered IPV4. */ if (AddressFamily == AF_INET && UpnpSdkDeviceRegisteredV4 == 1) { retVal = UPNP_E_ALREADY_REGISTERED; goto exit_function; } /* Test for already registered IPV6. IPV6 devices might register on multiple * IPv6 addresses (link local and GUA or ULA), so we must to check the * description URL in the HandleTable. */ while (handler_index < NUM_HANDLE && HandleTable[handler_index] != NULL) { if (strcmp(((struct Handle_Info *)HandleTable[handler_index])->DescURL, DescUrl)) { retVal = UPNP_E_ALREADY_REGISTERED; goto exit_function; } handler_index++; } *Hnd = GetFreeHandle(); if (*Hnd == UPNP_E_OUTOF_HANDLE) { retVal = UPNP_E_OUTOF_MEMORY; goto exit_function; } HInfo = (struct Handle_Info *)malloc(sizeof (struct Handle_Info)); if (HInfo == NULL) { retVal = UPNP_E_OUTOF_MEMORY; goto exit_function; } memset(HInfo, 0, sizeof(struct Handle_Info)); HandleTable[*Hnd] = HInfo; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Root device URL is %s\n", DescUrl); HInfo->aliasInstalled = 0; HInfo->HType = HND_DEVICE; strncpy(HInfo->DescURL, DescUrl, sizeof(HInfo->DescURL) - 1); if (LowerDescUrl == NULL) strncpy(HInfo->LowerDescURL, DescUrl, sizeof(HInfo->LowerDescURL) - 1); else strncpy(HInfo->LowerDescURL, LowerDescUrl, sizeof(HInfo->LowerDescURL) - 1); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Following Root Device URL will be used when answering to legacy CPs %s\n", HInfo->LowerDescURL); HInfo->Callback = Fun; HInfo->Cookie = (void *)Cookie; HInfo->MaxAge = DEFAULT_MAXAGE; HInfo->DeviceList = NULL; HInfo->ServiceList = NULL; HInfo->DescDocument = NULL; #ifdef INCLUDE_CLIENT_APIS ListInit(&HInfo->SsdpSearchList, NULL, NULL); HInfo->ClientSubList = NULL; #endif /* INCLUDE_CLIENT_APIS */ HInfo->MaxSubscriptions = UPNP_INFINITE; HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE; HInfo->DeviceAf = AddressFamily; retVal = UpnpDownloadXmlDoc(HInfo->DescURL, &(HInfo->DescDocument)); if (retVal != UPNP_E_SUCCESS) { #ifdef INCLUDE_CLIENT_APIS ListDestroy(&HInfo->SsdpSearchList, 0); #endif /* INCLUDE_CLIENT_APIS */ FreeHandle(*Hnd); goto exit_function; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice4: Valid Description\n" "UpnpRegisterRootDevice4: DescURL : %s\n", HInfo->DescURL); HInfo->DeviceList = ixmlDocument_getElementsByTagName( HInfo->DescDocument, "device"); if (!HInfo->DeviceList) { #ifdef INCLUDE_CLIENT_APIS ListDestroy(&HInfo->SsdpSearchList, 0); #endif /* INCLUDE_CLIENT_APIS */ ixmlDocument_free(HInfo->DescDocument); FreeHandle(*Hnd); UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice4: No devices found for RootDevice\n"); retVal = UPNP_E_INVALID_DESC; goto exit_function; } HInfo->ServiceList = ixmlDocument_getElementsByTagName( HInfo->DescDocument, "serviceList" ); if (!HInfo->ServiceList) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice4: No services found for RootDevice\n"); } #if EXCLUDE_GENA == 0 /* * GENA SET UP */ UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice4: Gena Check\n" ); memset(&HInfo->ServiceTable, 0, sizeof(HInfo->ServiceTable)); hasServiceTable = getServiceTable( (IXML_Node *)HInfo->DescDocument, &HInfo->ServiceTable, HInfo->DescURL); if (hasServiceTable) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "UpnpRegisterRootDevice4: GENA Service Table \n" "Here are the known services: \n" ); printServiceTable(&HInfo->ServiceTable, UPNP_ALL, API); } else { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "\nUpnpRegisterRootDevice4: Empty service table\n"); } #endif /* EXCLUDE_GENA */ switch (AddressFamily) { case AF_INET: UpnpSdkDeviceRegisteredV4 = 1; break; default: UpnpSdkDeviceregisteredV6 = 1; } retVal = UPNP_E_SUCCESS; exit_function: UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting RegisterRootDevice4, return value == %d\n", retVal); HandleUnlock(); return retVal; } #endif /* INCLUDE_DEVICE_APIS */ #ifdef INCLUDE_DEVICE_APIS int UpnpUnRegisterRootDevice(UpnpDevice_Handle Hnd) { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpUnRegisterRootDevice\n"); return UpnpUnRegisterRootDeviceLowPower(Hnd, -1, -1, -1); } int UpnpUnRegisterRootDeviceLowPower(UpnpDevice_Handle Hnd, int PowerState, int SleepPeriod, int RegistrationState) { int retVal = 0; struct Handle_Info *HInfo = NULL; if (UpnpSdkInit != 1) return UPNP_E_FINISH; UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpUnRegisterRootDeviceLowPower\n"); #if EXCLUDE_GENA == 0 if (genaUnregisterDevice(Hnd) != UPNP_E_SUCCESS) return UPNP_E_INVALID_HANDLE; #endif HandleLock(); switch (GetHandleInfo(Hnd, &HInfo)) { case HND_INVALID: HandleUnlock(); return UPNP_E_INVALID_HANDLE; default: break; } HInfo->PowerState = PowerState; if( SleepPeriod < 0 ) SleepPeriod = -1; HInfo->SleepPeriod = SleepPeriod; HInfo->RegistrationState = RegistrationState; HandleUnlock(); #if EXCLUDE_SSDP == 0 retVal = AdvertiseAndReply(-1, Hnd, (enum SsdpSearchType)0, (struct sockaddr *)NULL, (char *)NULL, (char *)NULL, (char *)NULL, HInfo->MaxAge); #endif HandleLock(); switch (GetHandleInfo(Hnd, &HInfo)) { case HND_INVALID: HandleUnlock(); return UPNP_E_INVALID_HANDLE; default: break; } ixmlNodeList_free(HInfo->DeviceList); ixmlNodeList_free(HInfo->ServiceList); ixmlDocument_free(HInfo->DescDocument); #ifdef INCLUDE_CLIENT_APIS ListDestroy(&HInfo->SsdpSearchList, 0); #endif /* INCLUDE_CLIENT_APIS */ #ifdef INTERNAL_WEB_SERVER if (HInfo->aliasInstalled) web_server_set_alias(NULL, NULL, 0, 0); #endif /* INTERNAL_WEB_SERVER */ switch (HInfo->DeviceAf) { case AF_INET: UpnpSdkDeviceRegisteredV4 = 0; break; case AF_INET6: UpnpSdkDeviceregisteredV6 = 0; break; default: break; } FreeHandle(Hnd); HandleUnlock(); UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Exiting UpnpUnRegisterRootDeviceLowPower\n"); return retVal; } #endif /* INCLUDE_DEVICE_APIS */ #ifdef INCLUDE_CLIENT_APIS int UpnpRegisterClient(Upnp_FunPtr Fun, const void *Cookie, UpnpClient_Handle *Hnd) { struct Handle_Info *HInfo; if (UpnpSdkInit != 1) return UPNP_E_FINISH; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpRegisterClient \n"); if (Fun == NULL || Hnd == NULL) return UPNP_E_INVALID_PARAM; HandleLock(); if (UpnpSdkClientRegistered) { 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; } HInfo->HType = HND_CLIENT; HInfo->Callback = Fun; HInfo->Cookie = (void *)Cookie; HInfo->ClientSubList = NULL; ListInit(&HInfo->SsdpSearchList, NULL, NULL); #ifdef INCLUDE_DEVICE_APIS HInfo->MaxAge = 0; HInfo->MaxSubscriptions = UPNP_INFINITE; HInfo->MaxSubscriptionTimeOut = UPNP_INFINITE; #endif HandleTable[*Hnd] = HInfo; UpnpSdkClientRegistered = 1; HandleUnlock(); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpRegisterClient \n"); return UPNP_E_SUCCESS; } #endif /* INCLUDE_CLIENT_APIS */ #ifdef INCLUDE_CLIENT_APIS int UpnpUnRegisterClient(UpnpClient_Handle Hnd) { struct Handle_Info *HInfo; ListNode *node = NULL; SsdpSearchArg *searchArg = NULL; if (UpnpSdkInit != 1) return UPNP_E_FINISH; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpUnRegisterClient \n"); HandleLock(); if (!UpnpSdkClientRegistered) { HandleUnlock(); return UPNP_E_INVALID_HANDLE; } HandleUnlock(); #if EXCLUDE_GENA == 0 if (genaUnregisterClient(Hnd) != UPNP_E_SUCCESS) return UPNP_E_INVALID_HANDLE; #endif HandleLock(); switch (GetHandleInfo(Hnd, &HInfo)) { case HND_INVALID: HandleUnlock(); return UPNP_E_INVALID_HANDLE; default: break; } /* clean up search list */ node = ListHead(&HInfo->SsdpSearchList); while (node != NULL) { searchArg = (SsdpSearchArg *) node->item; if (searchArg) { free(searchArg->searchTarget); free(searchArg); } ListDelNode(&HInfo->SsdpSearchList, node, 0); node = ListHead(&HInfo->SsdpSearchList); } ListDestroy(&HInfo->SsdpSearchList, 0); FreeHandle(Hnd); UpnpSdkClientRegistered = 0; HandleUnlock(); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpUnRegisterClient \n"); return UPNP_E_SUCCESS; } #endif /* INCLUDE_CLIENT_APIS */ #ifdef INCLUDE_DEVICE_APIS #ifdef INTERNAL_WEB_SERVER /*! * \brief Determines alias for given name which is a file name or URL. * * \return UPNP_E_SUCCESS on success, nonzero on failure. */ static int GetNameForAlias( /*! [in] Name of the file. */ char *name, /*! [out] Pointer to alias string. */ char **alias) { char *ext; char *al; ext = strrchr( name, '.' ); if( ext == NULL || strcasecmp( ext, ".xml" ) != 0 ) { return UPNP_E_EXT_NOT_XML; } al = strrchr( name, '/' ); if( al == NULL ) { *alias = name; } else { *alias = al; } return UPNP_E_SUCCESS; } /*! * \brief Fill the sockadr with IPv4 miniserver information. */ static void get_server_addr( /*! [out] pointer to server address structure. */ struct sockaddr *serverAddr) { struct sockaddr_in* sa4 = (struct sockaddr_in*)serverAddr; 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 ); } /*! * \brief Fill the sockadr with IPv6 miniserver information. */ static void get_server_addr6( /*! [out] pointer to server address structure. */ 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 ); } static int GetDescDocumentAndURL( Upnp_DescType descriptionType, char *description, int config_baseURL, int AddressFamily, IXML_Document **xmlDoc, char descURL[LINE_SIZE]) { int retVal = 0; char *membuf = NULL; char aliasStr[LINE_SIZE]; char *temp_str = NULL; FILE *fp = NULL; size_t fileLen; size_t num_read; time_t last_modified; struct stat file_info; struct sockaddr_storage serverAddr; int rc = UPNP_E_SUCCESS; memset(aliasStr, 0, sizeof(aliasStr)); if (description == NULL) return UPNP_E_INVALID_PARAM; /* non-URL description must have configuration specified */ if (descriptionType != (enum Upnp_DescType_e)UPNPREG_URL_DESC && !config_baseURL) return UPNP_E_INVALID_PARAM; /* Get XML doc and last modified time */ if (descriptionType == (enum Upnp_DescType_e)UPNPREG_URL_DESC) { retVal = UpnpDownloadXmlDoc(description, xmlDoc); if (retVal != UPNP_E_SUCCESS) return retVal; last_modified = time(NULL); } else if (descriptionType == (enum Upnp_DescType_e)UPNPREG_FILENAME_DESC) { retVal = stat(description, &file_info); if (retVal == -1) return UPNP_E_FILE_NOT_FOUND; fileLen = (size_t)file_info.st_size; last_modified = file_info.st_mtime; fp = fopen(description, "rb"); if (fp == NULL) return UPNP_E_FILE_NOT_FOUND; membuf = (char *)malloc(fileLen + (size_t)1); if (membuf == NULL) { fclose(fp); return UPNP_E_OUTOF_MEMORY; } num_read = fread(membuf, (size_t)1, fileLen, fp); if (num_read != fileLen) { fclose(fp); free(membuf); return UPNP_E_FILE_READ_ERROR; } membuf[fileLen] = 0; fclose(fp); rc = ixmlParseBufferEx(membuf, xmlDoc); free(membuf); } else if (descriptionType == (enum Upnp_DescType_e)UPNPREG_BUF_DESC) { last_modified = time(NULL); rc = ixmlParseBufferEx(description, xmlDoc); } else { return UPNP_E_INVALID_PARAM; } if (rc != IXML_SUCCESS && descriptionType != (enum Upnp_DescType_e)UPNPREG_URL_DESC) { if (rc == IXML_INSUFFICIENT_MEMORY) return UPNP_E_OUTOF_MEMORY; else return UPNP_E_INVALID_DESC; } /* Determine alias */ if (config_baseURL) { if (descriptionType == (enum Upnp_DescType_e)UPNPREG_BUF_DESC) { strncpy(aliasStr, "description.xml", sizeof(aliasStr) - 1); } else { /* URL or filename */ retVal = GetNameForAlias(description, &temp_str); if (retVal != UPNP_E_SUCCESS) { ixmlDocument_free(*xmlDoc); return retVal; } if (strlen(temp_str) > (LINE_SIZE - 1)) { ixmlDocument_free(*xmlDoc); free(temp_str); return UPNP_E_URL_TOO_BIG; } strncpy(aliasStr, temp_str, sizeof(aliasStr) - 1); } if (AddressFamily == AF_INET) { get_server_addr((struct sockaddr *)&serverAddr); } else { get_server_addr6((struct sockaddr *)&serverAddr); } /* config */ retVal = configure_urlbase(*xmlDoc, (struct sockaddr *)&serverAddr, aliasStr, last_modified, descURL); if (retVal != UPNP_E_SUCCESS) { ixmlDocument_free(*xmlDoc); return retVal; } } else { /* Manual */ if (strlen(description) > LINE_SIZE - 1) { ixmlDocument_free(*xmlDoc); return UPNP_E_URL_TOO_BIG; } strncpy(descURL, description, LINE_SIZE - 1); descURL[LINE_SIZE - 1] = '\0'; } assert(*xmlDoc != NULL); return UPNP_E_SUCCESS; } #else /* INTERNAL_WEB_SERVER */ /* no web server */ static int GetDescDocumentAndURL( Upnp_DescType descriptionType, char *description, int config_baseURL, int AddressFamily, IXML_Document **xmlDoc, char descURL[LINE_SIZE]) { int retVal = 0; if (descriptionType != (enum Upnp_DescType_e)UPNPREG_URL_DESC || config_baseURL) { return UPNP_E_NO_WEB_SERVER; } if (description == NULL) { return UPNP_E_INVALID_PARAM; } if (strlen(description) > LINE_SIZE - (size_t)1) { return UPNP_E_URL_TOO_BIG; } strncpy(descURL, description, LINE_SIZE - 1); descURL[LINE_SIZE - 1] = '\0'; retVal = UpnpDownloadXmlDoc(description, xmlDoc); if (retVal != UPNP_E_SUCCESS) { return retVal; } return UPNP_E_SUCCESS; } #endif /* INTERNAL_WEB_SERVER */ #endif /* INCLUDE_DEVICE_APIS */ /******************************************************************************* * * SSDP interface * ******************************************************************************/ #ifdef INCLUDE_DEVICE_APIS #if EXCLUDE_SSDP == 0 int UpnpSendAdvertisement(UpnpDevice_Handle Hnd, int Exp) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSendAdvertisement \n"); return UpnpSendAdvertisementLowPower (Hnd, Exp, -1, -1, -1); } int UpnpSendAdvertisementLowPower(UpnpDevice_Handle Hnd, int Exp, int PowerState, int SleepPeriod, int RegistrationState) { struct Handle_Info *SInfo = NULL; int retVal = 0, *ptrMx; upnp_timeout *adEvent; ThreadPoolJob job; memset(&job, 0, sizeof(job)); if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSendAdvertisementLowPower \n" ); HandleLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_DEVICE: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } if( Exp < 1 ) Exp = DEFAULT_MAXAGE; SInfo->MaxAge = Exp; SInfo->PowerState = PowerState; if( SleepPeriod < 0 ) SleepPeriod = -1; SInfo->SleepPeriod = SleepPeriod; SInfo->RegistrationState = RegistrationState; HandleUnlock(); retVal = AdvertiseAndReply( 1, Hnd, ( enum SsdpSearchType )0, ( struct sockaddr * )NULL, ( char * )NULL, ( char * )NULL, ( char * )NULL, Exp ); if( retVal != UPNP_E_SUCCESS ) return retVal; ptrMx = ( int * )malloc( sizeof( int ) ); if( ptrMx == NULL ) return UPNP_E_OUTOF_MEMORY; adEvent = ( upnp_timeout * ) malloc( sizeof( upnp_timeout ) ); if( adEvent == NULL ) { free( ptrMx ); return UPNP_E_OUTOF_MEMORY; } *ptrMx = Exp; adEvent->handle = Hnd; adEvent->Event = ptrMx; HandleLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_DEVICE: break; default: HandleUnlock(); free( adEvent ); free( ptrMx ); return UPNP_E_INVALID_HANDLE; } #ifdef SSDP_PACKET_DISTRIBUTE TPJobInit( &job, ( start_routine ) AutoAdvertise, adEvent ); TPJobSetFreeFunction( &job, ( free_routine ) free_upnp_timeout ); TPJobSetPriority( &job, MED_PRIORITY ); if( ( retVal = TimerThreadSchedule( &gTimerThread, ( ( Exp / 2 ) - ( AUTO_ADVERTISEMENT_TIME ) ), REL_SEC, &job, SHORT_TERM, &( adEvent->eventId ) ) ) != UPNP_E_SUCCESS ) { HandleUnlock(); free( adEvent ); free( ptrMx ); return retVal; } #else TPJobInit( &job, ( start_routine ) AutoAdvertise, adEvent ); TPJobSetFreeFunction( &job, ( free_routine ) free_upnp_timeout ); TPJobSetPriority( &job, MED_PRIORITY ); if( ( retVal = TimerThreadSchedule( &gTimerThread, Exp - AUTO_ADVERTISEMENT_TIME, REL_SEC, &job, SHORT_TERM, &( adEvent->eventId ) ) ) != UPNP_E_SUCCESS ) { HandleUnlock(); free( adEvent ); free( ptrMx ); return retVal; } #endif HandleUnlock(); UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpSendAdvertisementLowPower \n" ); return retVal; } #endif /* EXCLUDE_SSDP == 0 */ #endif /* INCLUDE_DEVICE_APIS */ #if EXCLUDE_SSDP == 0 #ifdef INCLUDE_CLIENT_APIS int UpnpSearchAsync( UpnpClient_Handle Hnd, int Mx, const char *Target_const, const void *Cookie_const ) { struct Handle_Info *SInfo = NULL; char *Target = ( char * )Target_const; int retVal; if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSearchAsync\n" ); HandleReadLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_CLIENT: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } if( Mx < 1 ) Mx = DEFAULT_MX; if( Target == NULL ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } HandleUnlock(); retVal = SearchByTarget( Mx, Target, ( void * )Cookie_const ); if (retVal != 1) return retVal; UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpSearchAsync \n" ); return UPNP_E_SUCCESS; } #endif /* INCLUDE_CLIENT_APIS */ #endif /******************************************************************************* * * GENA interface * ******************************************************************************/ #if EXCLUDE_GENA == 0 #ifdef INCLUDE_DEVICE_APIS int UpnpSetMaxSubscriptions(UpnpDevice_Handle Hnd, int MaxSubscriptions) { struct Handle_Info *SInfo = NULL; if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSetMaxSubscriptions \n" ); HandleLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_DEVICE: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } if( ( MaxSubscriptions != UPNP_INFINITE ) && ( MaxSubscriptions < 0 ) ) { HandleUnlock(); return UPNP_E_INVALID_HANDLE; } SInfo->MaxSubscriptions = MaxSubscriptions; HandleUnlock(); UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpSetMaxSubscriptions \n" ); return UPNP_E_SUCCESS; } #endif /* INCLUDE_DEVICE_APIS */ #ifdef INCLUDE_DEVICE_APIS int UpnpSetMaxSubscriptionTimeOut(UpnpDevice_Handle Hnd, int MaxSubscriptionTimeOut) { struct Handle_Info *SInfo = NULL; if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSetMaxSubscriptionTimeOut\n" ); HandleLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_DEVICE: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } if( ( MaxSubscriptionTimeOut != UPNP_INFINITE ) && ( MaxSubscriptionTimeOut < 0 ) ) { HandleUnlock(); return UPNP_E_INVALID_HANDLE; } SInfo->MaxSubscriptionTimeOut = MaxSubscriptionTimeOut; HandleUnlock(); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpSetMaxSubscriptionTimeOut\n"); return UPNP_E_SUCCESS; } #endif /* INCLUDE_DEVICE_APIS */ #ifdef INCLUDE_CLIENT_APIS int UpnpSubscribeAsync( UpnpClient_Handle Hnd, const char *EvtUrl_const, int TimeOut, Upnp_FunPtr Fun, const void *Cookie_const) { struct Handle_Info *SInfo = NULL; struct UpnpNonblockParam *Param; char *EvtUrl = ( char * )EvtUrl_const; ThreadPoolJob job; memset(&job, 0, sizeof(job)); if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSubscribeAsync\n"); HandleReadLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_CLIENT: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } if( EvtUrl == NULL ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } if( TimeOut != UPNP_INFINITE && TimeOut < 1 ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } if( Fun == NULL ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } HandleUnlock(); Param = (struct UpnpNonblockParam *) malloc(sizeof (struct UpnpNonblockParam)); if( Param == NULL ) { return UPNP_E_OUTOF_MEMORY; } memset( Param, 0, sizeof( struct UpnpNonblockParam ) ); Param->FunName = SUBSCRIBE; Param->Handle = Hnd; strncpy( Param->Url, EvtUrl, sizeof( Param->Url ) - 1 ); Param->TimeOut = TimeOut; Param->Fun = Fun; Param->Cookie = (void *)Cookie_const; TPJobInit(&job, (start_routine)UpnpThreadDistribution, Param); TPJobSetFreeFunction(&job, (free_routine)free); TPJobSetPriority(&job, MED_PRIORITY); ThreadPoolAdd(&gSendThreadPool, &job, NULL); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpSubscribeAsync\n"); return UPNP_E_SUCCESS; } #endif /* INCLUDE_CLIENT_APIS */ #ifdef INCLUDE_CLIENT_APIS int UpnpSubscribe( UpnpClient_Handle Hnd, const char *EvtUrl_const, int *TimeOut, Upnp_SID SubsId) { int retVal; struct Handle_Info *SInfo = NULL; UpnpString *EvtUrl = UpnpString_new(); UpnpString *SubsIdTmp = UpnpString_new(); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSubscribe\n"); if (UpnpSdkInit != 1) { retVal = UPNP_E_FINISH; goto exit_function; } if (EvtUrl == NULL) { retVal = UPNP_E_OUTOF_MEMORY; goto exit_function; } if (EvtUrl_const == NULL) { retVal = UPNP_E_INVALID_PARAM; goto exit_function; } UpnpString_set_String(EvtUrl, EvtUrl_const); if (SubsIdTmp == NULL) { retVal = UPNP_E_OUTOF_MEMORY; goto exit_function; } if (SubsId == NULL) { retVal = UPNP_E_INVALID_PARAM; goto exit_function; } UpnpString_set_String(SubsIdTmp, SubsId); if (TimeOut == NULL) { retVal = UPNP_E_INVALID_PARAM; goto exit_function; } HandleReadLock(); switch (GetHandleInfo(Hnd, &SInfo)) { case HND_CLIENT: break; default: HandleUnlock(); retVal = UPNP_E_INVALID_HANDLE; goto exit_function; } HandleUnlock(); retVal = genaSubscribe(Hnd, EvtUrl, TimeOut, SubsIdTmp); memset(SubsId, 0, sizeof(Upnp_SID)); strncpy(SubsId, UpnpString_get_String(SubsIdTmp), sizeof(Upnp_SID) - 1); exit_function: UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpSubscribe, retVal=%d\n", retVal); UpnpString_delete(SubsIdTmp); UpnpString_delete(EvtUrl); return retVal; } #endif /* INCLUDE_CLIENT_APIS */ #ifdef INCLUDE_CLIENT_APIS int UpnpUnSubscribe(UpnpClient_Handle Hnd, const Upnp_SID SubsId) { struct Handle_Info *SInfo = NULL; int retVal; UpnpString *SubsIdTmp = UpnpString_new(); UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpUnSubscribe\n"); if (UpnpSdkInit != 1) { retVal = UPNP_E_FINISH; goto exit_function; } if (SubsIdTmp == NULL) { retVal = UPNP_E_OUTOF_MEMORY; goto exit_function; } if (SubsId == NULL) { retVal = UPNP_E_INVALID_PARAM; goto exit_function; } UpnpString_set_String(SubsIdTmp, SubsId); HandleReadLock(); switch (GetHandleInfo(Hnd, &SInfo)) { case HND_CLIENT: break; default: HandleUnlock(); retVal = UPNP_E_INVALID_HANDLE; goto exit_function; } HandleUnlock(); retVal = genaUnSubscribe(Hnd, SubsIdTmp); exit_function: UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpUnSubscribe, retVal=%d\n", retVal); UpnpString_delete(SubsIdTmp); return retVal; } #endif /* INCLUDE_CLIENT_APIS */ #ifdef INCLUDE_CLIENT_APIS int UpnpUnSubscribeAsync( UpnpClient_Handle Hnd, Upnp_SID SubsId, Upnp_FunPtr Fun, const void *Cookie_const) { int retVal = UPNP_E_SUCCESS; ThreadPoolJob job; struct Handle_Info *SInfo = NULL; struct UpnpNonblockParam *Param; memset(&job, 0, sizeof(job)); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpUnSubscribeAsync\n"); if (UpnpSdkInit != 1) { retVal = UPNP_E_FINISH; goto exit_function; } if (SubsId == NULL) { retVal = UPNP_E_INVALID_PARAM; goto exit_function; } if (Fun == NULL) { retVal = UPNP_E_INVALID_PARAM; goto exit_function; } HandleReadLock(); switch (GetHandleInfo(Hnd, &SInfo)) { case HND_CLIENT: break; default: HandleUnlock(); retVal = UPNP_E_INVALID_HANDLE; goto exit_function; } HandleUnlock(); Param = (struct UpnpNonblockParam *)malloc(sizeof(struct UpnpNonblockParam)); if (Param == NULL) { retVal = UPNP_E_OUTOF_MEMORY; goto exit_function; } memset( Param, 0, sizeof( struct UpnpNonblockParam ) ); Param->FunName = UNSUBSCRIBE; Param->Handle = Hnd; strncpy( Param->SubsId, SubsId, sizeof( Param->SubsId ) - 1 ); Param->Fun = Fun; Param->Cookie = (void *)Cookie_const; TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param ); TPJobSetFreeFunction( &job, ( free_routine ) free ); TPJobSetPriority( &job, MED_PRIORITY ); ThreadPoolAdd( &gSendThreadPool, &job, NULL ); exit_function: UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpUnSubscribeAsync\n"); return retVal; } #endif /* INCLUDE_CLIENT_APIS */ #ifdef INCLUDE_CLIENT_APIS int UpnpRenewSubscription( UpnpClient_Handle Hnd, int *TimeOut, const Upnp_SID SubsId) { struct Handle_Info *SInfo = NULL; int retVal; UpnpString *SubsIdTmp = UpnpString_new(); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpRenewSubscription\n"); if (UpnpSdkInit != 1) { retVal = UPNP_E_FINISH; goto exit_function; } if (SubsIdTmp == NULL) { retVal = UPNP_E_OUTOF_MEMORY; goto exit_function; } if (SubsId == NULL) { retVal = UPNP_E_INVALID_PARAM; goto exit_function; } UpnpString_set_String(SubsIdTmp, SubsId); if (TimeOut == NULL) { retVal = UPNP_E_INVALID_PARAM; goto exit_function; } HandleReadLock(); switch (GetHandleInfo(Hnd, &SInfo)) { case HND_CLIENT: break; default: HandleUnlock(); retVal = UPNP_E_INVALID_HANDLE; goto exit_function; } HandleUnlock(); retVal = genaRenewSubscription(Hnd, SubsIdTmp, TimeOut); exit_function: UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpRenewSubscription, retVal=%d\n", retVal); UpnpString_delete(SubsIdTmp); return retVal; } #endif /* INCLUDE_CLIENT_APIS */ #ifdef INCLUDE_CLIENT_APIS int UpnpRenewSubscriptionAsync( UpnpClient_Handle Hnd, int TimeOut, Upnp_SID SubsId, Upnp_FunPtr Fun, const void *Cookie_const) { ThreadPoolJob job; struct Handle_Info *SInfo = NULL; struct UpnpNonblockParam *Param; memset(&job, 0, sizeof(job)); if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpRenewSubscriptionAsync\n"); HandleReadLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_CLIENT: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } if( TimeOut != UPNP_INFINITE && TimeOut < 1 ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } if( SubsId == NULL ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } if( Fun == NULL ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } HandleUnlock(); Param = ( struct UpnpNonblockParam * ) malloc( sizeof( struct UpnpNonblockParam ) ); if( Param == NULL ) { return UPNP_E_OUTOF_MEMORY; } memset(Param, 0, sizeof( struct UpnpNonblockParam ) ); Param->FunName = RENEW; Param->Handle = Hnd; strncpy( Param->SubsId, SubsId, sizeof( Param->SubsId ) - 1 ); Param->Fun = Fun; Param->Cookie = ( void * )Cookie_const; Param->TimeOut = TimeOut; TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param ); TPJobSetFreeFunction( &job, ( free_routine ) free ); TPJobSetPriority( &job, MED_PRIORITY ); ThreadPoolAdd( &gSendThreadPool, &job, NULL ); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpRenewSubscriptionAsync\n"); return UPNP_E_SUCCESS; } #endif /* INCLUDE_CLIENT_APIS */ #ifdef INCLUDE_DEVICE_APIS int UpnpNotify( UpnpDevice_Handle Hnd, const char *DevID_const, const char *ServName_const, const char **VarName_const, const char **NewVal_const, int cVariables) { struct Handle_Info *SInfo = NULL; int retVal; char *DevID = (char *)DevID_const; char *ServName = (char *)ServName_const; char **VarName = (char **)VarName_const; char **NewVal = (char **)NewVal_const; if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpNotify\n"); HandleReadLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_DEVICE: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } if( DevID == NULL ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } if( ServName == NULL ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } if( VarName == NULL || NewVal == NULL || cVariables < 0 ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } HandleUnlock(); retVal = genaNotifyAll( Hnd, DevID, ServName, VarName, NewVal, cVariables ); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpNotify\n"); return retVal; } int UpnpNotifyExt( UpnpDevice_Handle Hnd, const char *DevID_const, const char *ServName_const, IXML_Document *PropSet) { struct Handle_Info *SInfo = NULL; int retVal; char *DevID = (char *)DevID_const; char *ServName = (char *)ServName_const; if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpNotify \n" ); HandleReadLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_DEVICE: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } if( DevID == NULL ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } if( ServName == NULL ) { HandleUnlock(); return UPNP_E_INVALID_PARAM; } HandleUnlock(); retVal = genaNotifyAllExt( Hnd, DevID, ServName, PropSet ); UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpNotify \n" ); return retVal; } #endif /* INCLUDE_DEVICE_APIS */ #ifdef INCLUDE_DEVICE_APIS int UpnpAcceptSubscription( UpnpDevice_Handle Hnd, const char *DevID_const, const char *ServName_const, const char **VarName_const, const char **NewVal_const, int cVariables, const Upnp_SID SubsId) { int ret = 0; int line = 0; struct Handle_Info *SInfo = NULL; char *DevID = (char *)DevID_const; char *ServName = (char *)ServName_const; char **VarName = (char **)VarName_const; char **NewVal = (char **)NewVal_const; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpAcceptSubscription\n"); if (UpnpSdkInit != 1) { line = __LINE__; ret = UPNP_E_FINISH; goto exit_function; } HandleReadLock(); switch (GetHandleInfo(Hnd, &SInfo)) { case HND_DEVICE: break; default: HandleUnlock(); line = __LINE__; ret = UPNP_E_INVALID_HANDLE; goto exit_function; } if (DevID == NULL) { HandleUnlock(); line = __LINE__; ret = UPNP_E_INVALID_PARAM; goto exit_function; } if (ServName == NULL) { HandleUnlock(); line = __LINE__; ret = UPNP_E_INVALID_PARAM; goto exit_function; } if (SubsId == NULL) { HandleUnlock(); line = __LINE__; ret = UPNP_E_INVALID_PARAM; goto exit_function; } /* Now accepts an empty state list, so the code below is commented out */ #if 0 if (VarName == NULL || NewVal == NULL || cVariables < 0) { HandleUnlock(); line = __LINE__; ret = UPNP_E_INVALID_PARAM; goto exit_function; } #endif HandleUnlock(); line = __LINE__; ret = genaInitNotify( Hnd, DevID, ServName, VarName, NewVal, cVariables, SubsId); exit_function: UpnpPrintf(UPNP_ALL, API, __FILE__, line, "Exiting UpnpAcceptSubscription, ret = %d\n", ret); return ret; } int UpnpAcceptSubscriptionExt( UpnpDevice_Handle Hnd, const char *DevID_const, const char *ServName_const, IXML_Document *PropSet, Upnp_SID SubsId) { int ret = 0; int line = 0; struct Handle_Info *SInfo = NULL; char *DevID = (char *)DevID_const; char *ServName = (char *)ServName_const; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpAcceptSubscription\n"); if (UpnpSdkInit != 1) { line = __LINE__; ret = UPNP_E_FINISH; goto exit_function; } HandleReadLock(); switch (GetHandleInfo(Hnd, &SInfo)) { case HND_DEVICE: break; default: HandleUnlock(); line = __LINE__; ret = UPNP_E_INVALID_HANDLE; goto exit_function; } if (DevID == NULL) { HandleUnlock(); line = __LINE__; ret = UPNP_E_INVALID_PARAM; goto exit_function; } if (ServName == NULL) { HandleUnlock(); line = __LINE__; ret = UPNP_E_INVALID_PARAM; goto exit_function; } if (SubsId == NULL) { HandleUnlock(); line = __LINE__; ret = UPNP_E_INVALID_PARAM; goto exit_function; } /* Now accepts an empty state list, so the code below is commented out */ #if 0 if (PropSet == NULL) { HandleUnlock(); line = __LINE__; ret = UPNP_E_INVALID_PARAM; goto exit_function; } #endif HandleUnlock(); line = __LINE__; ret = genaInitNotifyExt(Hnd, DevID, ServName, PropSet, SubsId); exit_function: UpnpPrintf(UPNP_ALL, API, __FILE__, line, "Exiting UpnpAcceptSubscription, ret = %d.\n", ret); return ret; } #endif /* INCLUDE_DEVICE_APIS */ #endif /* EXCLUDE_GENA == 0 */ /******************************************************************************* * * SOAP interface * ******************************************************************************/ #if EXCLUDE_SOAP == 0 #ifdef INCLUDE_CLIENT_APIS int UpnpSendAction( UpnpClient_Handle Hnd, const char *ActionURL_const, const char *ServiceType_const, const char *DevUDN_const, IXML_Document *Action, IXML_Document **RespNodePtr) { struct Handle_Info *SInfo = NULL; int retVal = 0; char *ActionURL = (char *)ActionURL_const; char *ServiceType = (char *)ServiceType_const; /* udn not used? */ /*char *DevUDN = (char *)DevUDN_const;*/ if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSendAction\n"); if (DevUDN_const !=NULL) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "non NULL DevUDN is ignored\n"); } DevUDN_const = NULL; HandleReadLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_CLIENT: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } HandleUnlock(); if( ActionURL == NULL ) { return UPNP_E_INVALID_PARAM; } if( ServiceType == NULL || Action == NULL || RespNodePtr == NULL || DevUDN_const != NULL ) { return UPNP_E_INVALID_PARAM; } retVal = SoapSendAction( ActionURL, ServiceType, Action, RespNodePtr ); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpSendAction\n"); return retVal; } int UpnpSendActionEx( UpnpClient_Handle Hnd, const char *ActionURL_const, const char *ServiceType_const, const char *DevUDN_const, IXML_Document *Header, IXML_Document *Action, IXML_Document **RespNodePtr) { struct Handle_Info *SInfo = NULL; int retVal = 0; char *ActionURL = (char *)ActionURL_const; char *ServiceType = (char *)ServiceType_const; /* udn not used? */ /*char *DevUDN = (char *)DevUDN_const;*/ if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSendActionEx\n"); if( Header == NULL ) { retVal = UpnpSendAction( Hnd, ActionURL_const, ServiceType_const, DevUDN_const, Action, RespNodePtr ); return retVal; } HandleReadLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_CLIENT: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } HandleUnlock(); if( ActionURL == NULL ) { return UPNP_E_INVALID_PARAM; } if( ServiceType == NULL || Action == NULL || RespNodePtr == NULL ) { return UPNP_E_INVALID_PARAM; } retVal = SoapSendActionEx( ActionURL, ServiceType, Header, Action, RespNodePtr ); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpSendAction \n"); return retVal; } int UpnpSendActionAsync( UpnpClient_Handle Hnd, const char *ActionURL_const, const char *ServiceType_const, const char *DevUDN_const, IXML_Document *Act, Upnp_FunPtr Fun, const void *Cookie_const) { int rc; ThreadPoolJob job; struct Handle_Info *SInfo = NULL; struct UpnpNonblockParam *Param; DOMString tmpStr; char *ActionURL = (char *)ActionURL_const; char *ServiceType = (char *)ServiceType_const; /* udn not used? */ /*char *DevUDN = (char *)DevUDN_const;*/ memset(&job, 0, sizeof(job)); if(UpnpSdkInit != 1) { return UPNP_E_FINISH; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSendActionAsync\n"); HandleReadLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_CLIENT: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } HandleUnlock(); if( ActionURL == NULL ) { return UPNP_E_INVALID_PARAM; } if( ServiceType == NULL || Act == NULL || Fun == NULL || DevUDN_const != NULL ) { return UPNP_E_INVALID_PARAM; } tmpStr = ixmlPrintNode( ( IXML_Node * ) Act ); if( tmpStr == NULL ) { return UPNP_E_INVALID_ACTION; } Param = ( struct UpnpNonblockParam * ) malloc( sizeof( struct UpnpNonblockParam ) ); if( Param == NULL ) { return UPNP_E_OUTOF_MEMORY; } memset( Param, 0, sizeof( struct UpnpNonblockParam ) ); Param->FunName = ACTION; Param->Handle = Hnd; strncpy( Param->Url, ActionURL, sizeof ( Param->Url ) - 1 ); strncpy( Param->ServiceType, ServiceType, sizeof ( Param->ServiceType ) - 1 ); rc = ixmlParseBufferEx( tmpStr, &( Param->Act ) ); if( rc != IXML_SUCCESS ) { free( Param ); ixmlFreeDOMString( tmpStr ); if( rc == IXML_INSUFFICIENT_MEMORY ) { return UPNP_E_OUTOF_MEMORY; } else { return UPNP_E_INVALID_ACTION; } } ixmlFreeDOMString( tmpStr ); Param->Cookie = ( void * )Cookie_const; Param->Fun = Fun; TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param ); TPJobSetFreeFunction( &job, ( free_routine ) free ); TPJobSetPriority( &job, MED_PRIORITY ); ThreadPoolAdd( &gSendThreadPool, &job, NULL ); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpSendActionAsync \n"); return UPNP_E_SUCCESS; } int UpnpSendActionExAsync( UpnpClient_Handle Hnd, const char *ActionURL_const, const char *ServiceType_const, const char *DevUDN_const, IXML_Document *Header, IXML_Document *Act, Upnp_FunPtr Fun, const void *Cookie_const) { struct Handle_Info *SInfo = NULL; struct UpnpNonblockParam *Param; DOMString tmpStr; DOMString headerStr = NULL; char *ActionURL = ( char * )ActionURL_const; char *ServiceType = ( char * )ServiceType_const; ThreadPoolJob job; int retVal = 0; memset(&job, 0, sizeof(job)); if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpSendActionExAsync\n"); if( Header == NULL ) { retVal = UpnpSendActionAsync( Hnd, ActionURL_const, ServiceType_const, DevUDN_const, Act, Fun, Cookie_const ); return retVal; } HandleReadLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_CLIENT: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } HandleUnlock(); if( ActionURL == NULL ) { return UPNP_E_INVALID_PARAM; } if( ServiceType == NULL || Act == NULL || Fun == NULL ) { return UPNP_E_INVALID_PARAM; } headerStr = ixmlPrintNode( ( IXML_Node * ) Header ); tmpStr = ixmlPrintNode( ( IXML_Node * ) Act ); if( tmpStr == NULL ) { return UPNP_E_INVALID_ACTION; } Param = ( struct UpnpNonblockParam * ) malloc( sizeof( struct UpnpNonblockParam ) ); if( Param == NULL ) { return UPNP_E_OUTOF_MEMORY; } memset( Param, 0, sizeof( struct UpnpNonblockParam ) ); Param->FunName = ACTION; Param->Handle = Hnd; strncpy( Param->Url, ActionURL, sizeof( Param->Url ) - 1 ); strncpy( Param->ServiceType, ServiceType, sizeof ( Param->ServiceType ) - 1 ); retVal = ixmlParseBufferEx( headerStr, &( Param->Header ) ); if( retVal != IXML_SUCCESS ) { free( Param ); ixmlFreeDOMString( tmpStr ); ixmlFreeDOMString( headerStr ); if( retVal == IXML_INSUFFICIENT_MEMORY ) { return UPNP_E_OUTOF_MEMORY; } else { return UPNP_E_INVALID_ACTION; } } retVal = ixmlParseBufferEx( tmpStr, &( Param->Act ) ); if( retVal != IXML_SUCCESS ) { free( Param ); ixmlFreeDOMString( tmpStr ); ixmlFreeDOMString( headerStr ); ixmlDocument_free( Param->Header ); if( retVal == IXML_INSUFFICIENT_MEMORY ) { return UPNP_E_OUTOF_MEMORY; } else { return UPNP_E_INVALID_ACTION; } } ixmlFreeDOMString( tmpStr ); ixmlFreeDOMString( headerStr ); Param->Cookie = ( void * )Cookie_const; Param->Fun = Fun; TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param ); TPJobSetFreeFunction( &job, ( free_routine ) free ); TPJobSetPriority( &job, MED_PRIORITY ); ThreadPoolAdd( &gSendThreadPool, &job, NULL ); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpSendActionAsync\n"); return UPNP_E_SUCCESS; } int UpnpGetServiceVarStatusAsync( UpnpClient_Handle Hnd, const char *ActionURL_const, const char *VarName_const, Upnp_FunPtr Fun, const void *Cookie_const) { ThreadPoolJob job; struct Handle_Info *SInfo = NULL; struct UpnpNonblockParam *Param; char *ActionURL = (char *)ActionURL_const; char *VarName = (char *)VarName_const; memset(&job, 0, sizeof(job)); if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpGetServiceVarStatusAsync\n"); HandleReadLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_CLIENT: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } HandleUnlock(); if( ActionURL == NULL ) { return UPNP_E_INVALID_PARAM; } if( VarName == NULL || Fun == NULL ) return UPNP_E_INVALID_PARAM; Param = ( struct UpnpNonblockParam * ) malloc( sizeof( struct UpnpNonblockParam ) ); if( Param == NULL ) { return UPNP_E_OUTOF_MEMORY; } memset( Param, 0, sizeof( struct UpnpNonblockParam ) ); Param->FunName = STATUS; Param->Handle = Hnd; strncpy( Param->Url, ActionURL, sizeof( Param->Url ) - 1); strncpy( Param->VarName, VarName, sizeof( Param->VarName ) - 1 ); Param->Fun = Fun; Param->Cookie = ( void * )Cookie_const; TPJobInit( &job, ( start_routine ) UpnpThreadDistribution, Param ); TPJobSetFreeFunction( &job, ( free_routine ) free ); TPJobSetPriority( &job, MED_PRIORITY ); ThreadPoolAdd( &gSendThreadPool, &job, NULL ); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpGetServiceVarStatusAsync\n"); return UPNP_E_SUCCESS; } int UpnpGetServiceVarStatus( UpnpClient_Handle Hnd, const char *ActionURL_const, const char *VarName_const, DOMString *StVar) { struct Handle_Info *SInfo = NULL; int retVal = 0; char *StVarPtr; char *ActionURL = (char *)ActionURL_const; char *VarName = (char *)VarName_const; if(UpnpSdkInit != 1) { return UPNP_E_FINISH; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpGetServiceVarStatus\n"); HandleReadLock(); switch( GetHandleInfo( Hnd, &SInfo ) ) { case HND_CLIENT: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } HandleUnlock(); if( ActionURL == NULL ) { return UPNP_E_INVALID_PARAM; } if( VarName == NULL || StVar == NULL ) { return UPNP_E_INVALID_PARAM; } retVal = SoapGetServiceVarStatus( ActionURL, VarName, &StVarPtr ); *StVar = StVarPtr; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpGetServiceVarStatus \n"); return retVal; } #endif /* INCLUDE_CLIENT_APIS */ #endif /* EXCLUDE_SOAP */ /******************************************************************************* * * Client API * ******************************************************************************/ int UpnpOpenHttpPost( const char *url, void **handle, const char *contentType, int contentLength, int timeout) { return http_OpenHttpPost( url, handle, contentType, contentLength, timeout); } int UpnpWriteHttpPost( void *handle, char *buf, size_t *size, int timeout) { return http_WriteHttpPost(handle, buf, size, timeout); } int UpnpCloseHttpPost( void *handle, int *httpStatus, int timeout) { return http_CloseHttpPost(handle, httpStatus, timeout); } int UpnpOpenHttpGet( const char *url_str, void **Handle, char **contentType, int *contentLength, int *httpStatus, int timeout) { return http_OpenHttpGet( url_str, Handle, contentType, contentLength, httpStatus, timeout); } int UpnpOpenHttpGetProxy( const char *url_str, const char *proxy_str, void **Handle, char **contentType, int *contentLength, int *httpStatus, int timeout) { return http_OpenHttpGetProxy( url_str, proxy_str, Handle, contentType, contentLength, httpStatus, timeout); } int UpnpOpenHttpGetEx( const char *url_str, void **Handle, char **contentType, int *contentLength, int *httpStatus, int lowRange, int highRange, int timeout) { return http_OpenHttpGetEx( url_str, Handle, contentType, contentLength, httpStatus, lowRange, highRange, timeout); } int UpnpCancelHttpGet(void *Handle) { return http_CancelHttpGet(Handle); } int UpnpCloseHttpGet(void *Handle) { return http_CloseHttpGet(Handle); } int UpnpReadHttpGet(void *Handle, char *buf, size_t *size, int timeout) { return http_ReadHttpGet(Handle, buf, size, timeout); } int UpnpHttpGetProgress(void *Handle, size_t *length, size_t *total) { return http_HttpGetProgress(Handle, length, total); } int UpnpDownloadUrlItem(const char *url, char **outBuf, char *contentType) { int ret_code; size_t dummy; if (url == NULL || outBuf == NULL || contentType == NULL) return UPNP_E_INVALID_PARAM; ret_code = http_Download(url, HTTP_DEFAULT_TIMEOUT, outBuf, &dummy, contentType); if (ret_code > 0) /* error reply was received */ ret_code = UPNP_E_INVALID_URL; return ret_code; } int UpnpDownloadXmlDoc(const char *url, IXML_Document **xmlDoc) { int ret_code; char *xml_buf; char content_type[LINE_SIZE]; if (url == NULL || xmlDoc == NULL) { return UPNP_E_INVALID_PARAM; } ret_code = UpnpDownloadUrlItem(url, &xml_buf, content_type); if (ret_code != UPNP_E_SUCCESS) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "Error downloading document, retCode: %d\n", ret_code); return ret_code; } if (strncasecmp(content_type, "text/xml", strlen("text/xml"))) { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Not text/xml\n"); /* Linksys WRT54G router returns * "CONTENT-TYPE: application/octet-stream". * Let's be nice to Linksys and try to parse document anyway. * If the data sended is not a xml file, ixmlParseBufferEx * will fail and the function will return UPNP_E_INVALID_DESC too. */ #if 0 free(xml_buf); return UPNP_E_INVALID_DESC; #endif } ret_code = ixmlParseBufferEx(xml_buf, xmlDoc); free(xml_buf); if (ret_code != IXML_SUCCESS) { if (ret_code == IXML_INSUFFICIENT_MEMORY) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "Out of memory, ixml error code: %d\n", ret_code); return UPNP_E_OUTOF_MEMORY; } else { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "Invalid Description, ixml error code: %d\n", ret_code); return UPNP_E_INVALID_DESC; } } else { #ifdef DEBUG xml_buf = ixmlPrintNode((IXML_Node *)*xmlDoc); UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Printing the Parsed xml document \n %s\n", xml_buf); UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "****************** END OF Parsed XML Doc *****************\n"); ixmlFreeDOMString(xml_buf); #endif UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpDownloadXmlDoc\n"); return UPNP_E_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; memset(gIF_NAME, 0, sizeof(gIF_NAME)); strncpy(gIF_NAME, IfName, sizeof(gIF_NAME) - 1); 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. */ #ifdef UPNP_USE_MSVCPP /* * Partial fix for VC - friendly name is wchar string, * but currently gIF_NAME is char string. For now try * to convert it, which will work with many (but not * all) adapters. A full fix would require a lot of * big changes (gIF_NAME to wchar string?). */ wcstombs(gIF_NAME, adapts_item->FriendlyName, sizeof(gIF_NAME)); #else memset(gIF_NAME, 0, sizeof(gIF_NAME)); strncpy(gIF_NAME, adapts_item->FriendlyName, sizeof(gIF_NAME) - 1); #endif ifname_found = 1; } else { #ifdef UPNP_USE_MSVCPP /* * Partial fix for VC - friendly name is wchar string, * but currently gIF_NAME is char string. For now try * to convert it, which will work with many (but not * all) adapters. A full fix would require a lot of * big changes (gIF_NAME to wchar string?). */ char tmpIfName[LINE_SIZE] = { 0 }; wcstombs(tmpIfName, adapts_item->FriendlyName, sizeof(tmpIfName)); if (strncmp (gIF_NAME, tmpIfName, sizeof(gIF_NAME)) != 0) { /* This is not the interface we're looking for. */ continue; } #else if (strncmp (gIF_NAME, adapts_item->FriendlyName, sizeof(gIF_NAME)) != 0) { /* This is not the interface we're looking for. */ continue; } #endif } /* 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) || defined(__FreeBSD_kernel__) 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; memset(gIF_NAME, 0, sizeof(gIF_NAME)); strncpy(gIF_NAME, IfName, sizeof(gIF_NAME) - 1); 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. */ memset(gIF_NAME, 0, sizeof(gIF_NAME)); strncpy(gIF_NAME, ifa->ifa_name, sizeof(gIF_NAME) - 1); 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; size_t i; int LocalSock; struct in6_addr v6_addr; unsigned if_idx; char addr6[8][5]; char buf[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; memset(gIF_NAME, 0, sizeof(gIF_NAME)); strncpy(gIF_NAME, IfName, sizeof(gIF_NAME) - 1); ifname_found = 1; } /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */ if ((LocalSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Can't create addrlist socket\n"); return UPNP_E_INIT; } /* Get the interface configuration information... */ ifConf.ifc_len = (int)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"); close(LocalSock); return UPNP_E_INIT; } /* Cycle through the list of interfaces looking for IP addresses. */ for (i = (size_t)0; i < (size_t)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. */ memset(ifReq.ifr_name, 0, sizeof(ifReq.ifr_name)); strncpy(ifReq.ifr_name, pifReq->ifr_name, sizeof(ifReq.ifr_name) - 1); 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. */ memset(gIF_NAME, 0, sizeof(gIF_NAME)); strncpy(gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) - 1); 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. */ memset(gIF_NAME, 0, sizeof(gIF_NAME)); strncpy(gIF_NAME, pifReq->ifr_name, sizeof(gIF_NAME) - 1); 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) { 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) { if (IN6_IS_ADDR_ULA(&v6_addr)) { /* Got valid IPv6 ula. */ memset(gIF_IPV6_ULA_GUA, 0, sizeof(gIF_IPV6_ULA_GUA)); strncpy(gIF_IPV6_ULA_GUA, buf, sizeof (gIF_IPV6_ULA_GUA) - 1); } else if (IN6_IS_ADDR_GLOBAL(&v6_addr) && strlen(gIF_IPV6_ULA_GUA) == (size_t)0) { /* got a GUA, should store it while no ULA is found */ memset(gIF_IPV6_ULA_GUA, 0, sizeof(gIF_IPV6_ULA_GUA)); strncpy(gIF_IPV6_ULA_GUA, buf, sizeof (gIF_IPV6_ULA_GUA) - 1); } else if (IN6_IS_ADDR_LINKLOCAL(&v6_addr) && strlen(gIF_IPV6) == (size_t)0) { /* got a Link local IPv6 address. */ memset(gIF_IPV6, 0, sizeof(gIF_IPV6)); strncpy(gIF_IPV6, buf, sizeof(gIF_IPV6) - 1); } } } } fclose(inet6_procfd); } #endif UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "Interface name=%s, index=%d, v4=%s, v6=%s, ULA or GUA v6=%s\n", gIF_NAME, gIF_INDEX, gIF_IPV4, gIF_IPV6, gIF_IPV6_ULA_GUA); return UPNP_E_SUCCESS; } /*! * \brief Schedule async functions in threadpool. */ #ifdef INCLUDE_CLIENT_APIS void UpnpThreadDistribution(struct UpnpNonblockParam *Param) { /*int errCode = 0;*/ UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside UpnpThreadDistribution \n"); switch (Param->FunName) { #if EXCLUDE_GENA == 0 case SUBSCRIBE: { struct Upnp_Event_Subscribe Evt; UpnpString *Sid = UpnpString_new(); UpnpString *Url = UpnpString_new(); UpnpString_set_String(Url, Param->Url); memset(&Evt, 0, sizeof(Evt)); Evt.ErrCode = genaSubscribe( Param->Handle, Url, (int *)&Param->TimeOut, Sid); strncpy(Evt.PublisherUrl, Param->Url, sizeof(Evt.PublisherUrl) - 1); Evt.TimeOut = Param->TimeOut; strncpy((char *)Evt.Sid, UpnpString_get_String(Sid), sizeof(Evt.Sid) - 1); Param->Fun(UPNP_EVENT_SUBSCRIBE_COMPLETE, &Evt, Param->Cookie); UpnpString_delete(Sid); UpnpString_delete(Url); free(Param); break; } case UNSUBSCRIBE: { struct Upnp_Event_Subscribe Evt; UpnpString *Sid = UpnpString_new(); UpnpString_set_String(Sid, Param->SubsId); memset(&Evt, 0, sizeof(Evt)); Evt.ErrCode = genaUnSubscribe( Param->Handle, Sid); strncpy((char *)Evt.Sid, UpnpString_get_String(Sid), sizeof(Evt.Sid) - 1); strncpy(Evt.PublisherUrl, "", sizeof(Evt.PublisherUrl) - 1); Evt.TimeOut = 0; Param->Fun(UPNP_EVENT_UNSUBSCRIBE_COMPLETE, &Evt, Param->Cookie); UpnpString_delete(Sid); free(Param); break; } case RENEW: { struct Upnp_Event_Subscribe Evt; UpnpString *Sid = UpnpString_new(); UpnpString_set_String(Sid, Param->SubsId); memset(&Evt, 0, sizeof(Evt)); Evt.ErrCode = genaRenewSubscription( Param->Handle, Sid, &Param->TimeOut); Evt.TimeOut = Param->TimeOut; strncpy((char *)Evt.Sid, UpnpString_get_String(Sid), sizeof(Evt.Sid) - 1); Param->Fun(UPNP_EVENT_RENEWAL_COMPLETE, &Evt, Param->Cookie); UpnpString_delete(Sid); free(Param); break; } #endif /* EXCLUDE_GENA == 0 */ #if EXCLUDE_SOAP == 0 case ACTION: { struct Upnp_Action_Complete Evt; memset(&Evt, 0, sizeof(Evt)); Evt.ActionResult = NULL; Evt.ErrCode = SoapSendAction( Param->Url, Param->ServiceType, Param->Act, &Evt.ActionResult); Evt.ActionRequest = Param->Act; strncpy(Evt.CtrlUrl, Param->Url, sizeof(Evt.CtrlUrl) - 1); Param->Fun(UPNP_CONTROL_ACTION_COMPLETE, &Evt, Param->Cookie); ixmlDocument_free(Evt.ActionRequest); ixmlDocument_free(Evt.ActionResult); free(Param); break; } case STATUS: { struct Upnp_State_Var_Complete Evt; memset(&Evt, 0, sizeof(Evt)); Evt.ErrCode = SoapGetServiceVarStatus( Param->Url, Param->VarName, &Evt.CurrentVal); strncpy(Evt.StateVarName, Param->VarName, sizeof(Evt.StateVarName) - 1); strncpy(Evt.CtrlUrl, Param->Url, sizeof(Evt.CtrlUrl) - 1); Param->Fun(UPNP_CONTROL_GET_VAR_COMPLETE, &Evt, Param->Cookie); free(Evt.CurrentVal); free(Param); break; } #endif /* EXCLUDE_SOAP == 0 */ default: break; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Exiting UpnpThreadDistribution\n"); } #endif /* INCLUDE_CLIENT_APIS */ /*! * \brief Get callback function ptr from a handle. * * \return Upnp_FunPtr */ Upnp_FunPtr GetCallBackFn(UpnpClient_Handle Hnd) { return ((struct Handle_Info *)HandleTable[Hnd])->Callback; } /* Assumes at most one client */ Upnp_Handle_Type GetClientHandleInfo( UpnpClient_Handle *client_handle_out, struct Handle_Info **HndInfo) { Upnp_Handle_Type ret = HND_CLIENT; UpnpClient_Handle client; switch (GetHandleInfo(1, HndInfo)) { case HND_CLIENT: client = 1; break; default: switch (GetHandleInfo(2, HndInfo)) { case HND_CLIENT: client = 2; break; default: client = -1; ret = HND_INVALID; } } *client_handle_out = client; return ret; } Upnp_Handle_Type GetDeviceHandleInfo( int AddressFamily, UpnpDevice_Handle *device_handle_out, struct Handle_Info **HndInfo) { /* 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; } /* Find it. */ for (*device_handle_out=1; *device_handle_out < NUM_HANDLE; (*device_handle_out)++) { switch (GetHandleInfo(*device_handle_out, HndInfo)) { case HND_DEVICE: if ((*HndInfo)->DeviceAf == AddressFamily) { return HND_DEVICE; } break; default: break; } } *device_handle_out = -1; return HND_INVALID; } Upnp_Handle_Type GetHandleInfo( UpnpClient_Handle Hnd, struct Handle_Info **HndInfo) { Upnp_Handle_Type ret = HND_INVALID; UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "GetHandleInfo: entering, Handle is %d\n", Hnd); if (Hnd < 1 || Hnd >= NUM_HANDLE) { UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, "GetHandleInfo: Handle out of range\n"); } else if (HandleTable[Hnd] == NULL) { UpnpPrintf(UPNP_CRITICAL, API, __FILE__, __LINE__, "GetHandleInfo: HandleTable[%d] is NULL\n", Hnd); } else if (HandleTable[Hnd] != NULL) { *HndInfo = (struct Handle_Info *)HandleTable[Hnd]; ret = ((struct Handle_Info *)*HndInfo)->HType; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "GetHandleInfo: exiting\n"); return ret; } int PrintHandleInfo(UpnpClient_Handle Hnd) { struct Handle_Info * HndInfo; if (HandleTable[Hnd] != NULL) { HndInfo = HandleTable[Hnd]; UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Printing information for Handle_%d\n", Hnd); UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "HType_%d\n", HndInfo->HType); #ifdef INCLUDE_DEVICE_APIS switch(HndInfo->HType) { case HND_CLIENT: break; default: UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "DescURL_%s\n", HndInfo->DescURL); } #endif /* INCLUDE_DEVICE_APIS */ } else { return UPNP_E_INVALID_HANDLE; } return UPNP_E_SUCCESS; } int getlocalhostname(char *out, size_t out_len) { int ret = UPNP_E_SUCCESS; char tempstr[INET_ADDRSTRLEN]; const char *p = NULL; #ifdef WIN32 struct hostent *h = NULL; struct sockaddr_in LocalAddr; memset(&LocalAddr, 0, sizeof(LocalAddr)); gethostname(out, out_len); h = gethostbyname(out); if (h != NULL) { memcpy(&LocalAddr.sin_addr, h->h_addr_list[0], 4); p = inet_ntop(AF_INET, &LocalAddr.sin_addr, tempstr, sizeof(tempstr)); if (p) { strncpy(out, p, out_len); } else { UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "getlocalhostname: inet_ntop returned error\n" ); ret = UPNP_E_INIT; } } else { UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "getlocalhostname: gethostbyname returned error\n" ); ret = UPNP_E_INIT; } #elif (defined(BSD) && BSD >= 199306) || defined(__FreeBSD_kernel__) struct ifaddrs *ifap, *ifa; if (getifaddrs(&ifap) != 0) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "DiscoverInterfaces: getifaddrs() returned error\n"); return UPNP_E_INIT; } /* cycle through available interfaces */ for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { /* Skip loopback, point-to-point and down interfaces, * except don't skip down interfaces * if we're trying to get a list of configurable interfaces. */ if ((ifa->ifa_flags & IFF_LOOPBACK) || (!( ifa->ifa_flags & IFF_UP))) { continue; } if (ifa->ifa_addr->sa_family == AF_INET) { /* We don't want the loopback interface. */ if (((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { continue; } p = inet_ntop(AF_INET, &((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr, tempstr, sizeof(tempstr)); if (p) { strncpy(out, p, out_len); } else { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "getlocalhostname: inet_ntop returned error\n"); ret = UPNP_E_INIT; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside getlocalhostname: after strncpy %s\n", out); break; } } freeifaddrs(ifap); ret = ifa ? UPNP_E_SUCCESS : UPNP_E_INIT; #else char szBuffer[MAX_INTERFACES * sizeof (struct ifreq)]; struct ifconf ifConf; struct ifreq ifReq; int nResult; long unsigned int i; int LocalSock; struct sockaddr_in LocalAddr; int j = 0; /* purify */ memset(&ifConf, 0, sizeof(ifConf)); memset(&ifReq, 0, sizeof(ifReq)); memset(szBuffer, 0, sizeof(szBuffer)); memset(&LocalAddr, 0, sizeof(LocalAddr)); /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */ LocalSock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (LocalSock == INVALID_SOCKET) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Can't create addrlist socket\n"); return UPNP_E_INIT; } /* Get the interface configuration information... */ ifConf.ifc_len = (int)sizeof szBuffer; ifConf.ifc_ifcu.ifcu_buf = (caddr_t) szBuffer; nResult = ioctl(LocalSock, SIOCGIFCONF, &ifConf); if (nResult < 0) { UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "DiscoverInterfaces: SIOCGIFCONF returned error\n"); close(LocalSock); return UPNP_E_INIT; } /* Cycle through the list of interfaces looking for IP addresses. */ for (i = 0lu; i < (long unsigned int)ifConf.ifc_len && j < DEFAULT_INTERFACE; ) { 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. */ memset(ifReq.ifr_name, 0, sizeof(ifReq.ifr_name)); strncpy(ifReq.ifr_name, pifReq->ifr_name, sizeof(ifReq.ifr_name) - 1); 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, point-to-point and down interfaces, * except don't skip down interfaces * if we're trying to get a list of configurable interfaces. */ if ((ifReq.ifr_flags & IFF_LOOPBACK) || (!(ifReq.ifr_flags & IFF_UP))) { continue; } if (pifReq->ifr_addr.sa_family == AF_INET) { /* Get a pointer to the address...*/ memcpy(&LocalAddr, &pifReq->ifr_addr, sizeof pifReq->ifr_addr); /* We don't want the loopback interface. */ if (LocalAddr.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) { continue; } } /* increment j if we found an address which is not loopback * and is up */ j++; } close(LocalSock); p = inet_ntop(AF_INET, &LocalAddr.sin_addr, tempstr, sizeof(tempstr)); if (p) { strncpy(out, p, out_len); } else { UpnpPrintf( UPNP_ALL, API, __FILE__, __LINE__, "getlocalhostname: inet_ntop returned error\n" ); ret = UPNP_E_INIT; } UpnpPrintf(UPNP_ALL, API, __FILE__, __LINE__, "Inside getlocalhostname: after strncpy %s\n", out); #endif return ret; } #ifdef INCLUDE_DEVICE_APIS #if EXCLUDE_SSDP == 0 void AutoAdvertise(void *input) { upnp_timeout *event = (upnp_timeout *)input; UpnpSendAdvertisement(event->handle, *((int *)event->Event)); free_upnp_timeout(event); } #endif /* EXCLUDE_SSDP == 0 */ #endif /* INCLUDE_DEVICE_APIS */ #ifdef INTERNAL_WEB_SERVER int UpnpSetWebServerRootDir(const char *rootDir) { if( UpnpSdkInit == 0 ) return UPNP_E_FINISH; if( ( rootDir == NULL ) || ( strlen( rootDir ) == 0 ) ) { return UPNP_E_INVALID_PARAM; } membuffer_destroy( &gDocumentRootDir ); return web_server_set_root_dir(rootDir); } #endif /* INTERNAL_WEB_SERVER */ int UpnpAddVirtualDir(const char *newDirName) { virtualDirList *pNewVirtualDir; virtualDirList *pLast; virtualDirList *pCurVirtualDir; char dirName[NAME_SIZE]; memset( dirName, 0, sizeof( dirName ) ); if( UpnpSdkInit != 1 ) { /* SDK is not initialized */ return UPNP_E_FINISH; } if( ( newDirName == NULL ) || ( strlen( newDirName ) == ( size_t ) 0 ) ) { return UPNP_E_INVALID_PARAM; } if( *newDirName != '/' ) { if (strlen(newDirName) > sizeof(dirName) - 2) return UPNP_E_INVALID_PARAM; dirName[0] = '/'; strncpy( dirName + 1, newDirName, sizeof( dirName ) - 2 ); } else { if (strlen(newDirName) > sizeof(dirName) - 1) return UPNP_E_INVALID_PARAM; strncpy( dirName, newDirName, sizeof( dirName ) - 1 ); } pCurVirtualDir = pVirtualDirList; while( pCurVirtualDir != NULL ) { /* already has this entry */ if( strcmp( pCurVirtualDir->dirName, dirName ) == 0 ) { return UPNP_E_SUCCESS; } pCurVirtualDir = pCurVirtualDir->next; } pNewVirtualDir = ( virtualDirList * ) malloc( sizeof( virtualDirList ) ); if( pNewVirtualDir == NULL ) { return UPNP_E_OUTOF_MEMORY; } pNewVirtualDir->next = NULL; memset( pNewVirtualDir->dirName, 0, sizeof( pNewVirtualDir->dirName ) ); strncpy( pNewVirtualDir->dirName, dirName, sizeof( pNewVirtualDir->dirName ) - 1); *( pNewVirtualDir->dirName + strlen( dirName ) ) = 0; if( pVirtualDirList == NULL ) { /* first virtual dir */ pVirtualDirList = pNewVirtualDir; } else { pLast = pVirtualDirList; while( pLast->next != NULL ) { pLast = pLast->next; } pLast->next = pNewVirtualDir; } return UPNP_E_SUCCESS; } int UpnpRemoveVirtualDir(const char *dirName) { virtualDirList *pPrev; virtualDirList *pCur; int found = 0; if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } if( dirName == NULL ) { return UPNP_E_INVALID_PARAM; } if( pVirtualDirList == NULL ) { return UPNP_E_INVALID_PARAM; } /* Handle the special case where the directory that we are */ /* removing is the first and only one in the list. */ if( ( pVirtualDirList->next == NULL ) && ( strcmp( pVirtualDirList->dirName, dirName ) == 0 ) ) { free( pVirtualDirList ); pVirtualDirList = NULL; return UPNP_E_SUCCESS; } pCur = pVirtualDirList; pPrev = pCur; while( pCur != NULL ) { if( strcmp( pCur->dirName, dirName ) == 0 ) { pPrev->next = pCur->next; free( pCur ); found = 1; break; } else { pPrev = pCur; pCur = pCur->next; } } if( found == 1 ) return UPNP_E_SUCCESS; else return UPNP_E_INVALID_PARAM; } void UpnpRemoveAllVirtualDirs(void) { virtualDirList *pCur; virtualDirList *pNext; if( UpnpSdkInit != 1 ) { return; } pCur = pVirtualDirList; while( pCur != NULL ) { pNext = pCur->next; free( pCur ); pCur = pNext; } pVirtualDirList = NULL; } int UpnpEnableWebserver(int enable) { int retVal = UPNP_E_SUCCESS; if( UpnpSdkInit != 1 ) { return UPNP_E_FINISH; } switch ( enable ) { #ifdef INTERNAL_WEB_SERVER case TRUE: if( ( retVal = web_server_init() ) != UPNP_E_SUCCESS ) { return retVal; } bWebServerState = WEB_SERVER_ENABLED; SetHTTPGetCallback( web_server_callback ); break; case FALSE: web_server_destroy(); bWebServerState = WEB_SERVER_DISABLED; SetHTTPGetCallback( NULL ); break; #endif /* INTERNAL_WEB_SERVER */ default: retVal = UPNP_E_INVALID_PARAM; } return retVal; } /*! * \brief Checks if the webserver is enabled or disabled. * * \return 1, if webserver is enabled or 0, if webserver is disabled. */ int UpnpIsWebserverEnabled(void) { if (UpnpSdkInit != 1) { return 0; } return bWebServerState == (WebServerState)WEB_SERVER_ENABLED; } int UpnpSetVirtualDirCallbacks(struct UpnpVirtualDirCallbacks *callbacks) { int ret = 0; if( UpnpSdkInit != 1 ) { /* SDK is not initialized */ return UPNP_E_FINISH; } if( callbacks == NULL ) return UPNP_E_INVALID_PARAM; ret = UpnpVirtualDir_set_GetInfoCallback(callbacks->get_info) == UPNP_E_SUCCESS && UpnpVirtualDir_set_OpenCallback(callbacks->open) == UPNP_E_SUCCESS && UpnpVirtualDir_set_ReadCallback(callbacks->read) == UPNP_E_SUCCESS && UpnpVirtualDir_set_WriteCallback(callbacks->write) == UPNP_E_SUCCESS && UpnpVirtualDir_set_SeekCallback(callbacks->seek) == UPNP_E_SUCCESS && UpnpVirtualDir_set_CloseCallback(callbacks->close) == UPNP_E_SUCCESS; return ret ? UPNP_E_SUCCESS : UPNP_E_INVALID_PARAM; } int UpnpVirtualDir_set_GetInfoCallback(VDCallback_GetInfo callback) { int ret = UPNP_E_SUCCESS; if (!callback) { ret = UPNP_E_INVALID_PARAM; } else { virtualDirCallback.get_info = callback; } return ret; } int UpnpVirtualDir_set_OpenCallback(VDCallback_Open callback) { int ret = UPNP_E_SUCCESS; if (!callback) { ret = UPNP_E_INVALID_PARAM; } else { virtualDirCallback.open = callback; } return ret; } int UpnpVirtualDir_set_ReadCallback(VDCallback_Read callback) { int ret = UPNP_E_SUCCESS; if (!callback) { ret = UPNP_E_INVALID_PARAM; } else { virtualDirCallback.read = callback; } return ret; } int UpnpVirtualDir_set_WriteCallback(VDCallback_Write callback) { int ret = UPNP_E_SUCCESS; if (!callback) { ret = UPNP_E_INVALID_PARAM; } else { virtualDirCallback.write = callback; } return ret; } int UpnpVirtualDir_set_SeekCallback(VDCallback_Seek callback) { int ret = UPNP_E_SUCCESS; if (!callback) { ret = UPNP_E_INVALID_PARAM; } else { virtualDirCallback.seek = callback; } return ret; } int UpnpVirtualDir_set_CloseCallback(VDCallback_Close callback) { int ret = UPNP_E_SUCCESS; if (!callback) { ret = UPNP_E_INVALID_PARAM; } else { virtualDirCallback.close = callback; } return ret; } int UpnpSetContentLength(UpnpClient_Handle Hnd, size_t contentLength) { int errCode = UPNP_E_SUCCESS; struct Handle_Info *HInfo = NULL; do { if (UpnpSdkInit != 1) { errCode = UPNP_E_FINISH; break; } HandleLock(); switch (GetHandleInfo(Hnd, &HInfo)) { case HND_DEVICE: break; default: HandleUnlock(); return UPNP_E_INVALID_HANDLE; } if (contentLength > MAX_SOAP_CONTENT_LENGTH) { errCode = UPNP_E_OUTOF_BOUNDS; break; } g_maxContentLength = contentLength; } while (0); HandleUnlock(); return errCode; } int UpnpSetMaxContentLength(size_t contentLength) { int errCode = UPNP_E_SUCCESS; do { if (UpnpSdkInit != 1) { errCode = UPNP_E_FINISH; break; } g_maxContentLength = contentLength; } while(0); return errCode; } /* @} UPnPAPI */