📄 upnpapi.c
字号:
/////////////////////////////////////////////////////////////////////////////// Copyright (c) 2000-2003 Intel Corporation // 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./////////////////////////////////////////////////////////////////////////////#include "config.h"#include <sys/stat.h>#include <assert.h>#include <signal.h>#include <stdlib.h>#include <string.h>#ifndef WIN32 #include <arpa/inet.h> #include <net/if.h> #include <netinet/in.h> #include <sys/ioctl.h> #include <sys/param.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/utsname.h> #include <unistd.h> #if defined(_sun) #include <sys/sockio.h> #include <fcntl.h> #elif defined(BSD) && BSD >= 199306 #include <ifaddrs.h> #endif#endif /* WIN32 */#include "upnpapi.h"#include "httpreadwrite.h"#include "membuffer.h"#include "ssdplib.h"#include "soaplib.h"#include "ThreadPool.h"// Needed for GENA#include "gena.h"#include "miniserver.h"#include "service_table.h"#ifdef INTERNAL_WEB_SERVER #include "webserver.h" #include "urlconfig.h"#endif // INTERNAL_WEB_SERVER//virtualDirList *pVirtualDirList;// Mutex to synchronize the subscription handling at the client sideCLIENTONLY( ithread_mutex_t GlobalClientSubscribeMutex; )// 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; TimerThread gTimerThread; ThreadPool gSendThreadPool; ThreadPool gRecvThreadPool; ThreadPool gMiniServerThreadPool;//Flag to indicate the state of web server WebServerState bWebServerState = WEB_SERVER_DISABLED;// static buffer to store the local host ip address or host name char LOCAL_HOST[LINE_SIZE];// local port for the mini-server unsigned short LOCAL_PORT;// UPnP device and control point handle table void *HandleTable[NUM_HANDLE];//This structure is for virtual directory callbacks struct UpnpVirtualDirCallbacks virtualDirCallback;// a local dir which serves as webserver root extern membuffer gDocumentRootDir;// Maximum content-length 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; // in bytes// 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 device registration.// = 0 if unregistered, = 1 if registered. int UpnpSdkDeviceRegistered = 0;// Global variable to denote the state of Upnp SDK client registration.// = 0 if unregistered, = 1 if registered. int UpnpSdkClientRegistered = 0;/**************************************************************************** * Function: UpnpInit * * Parameters: * IN const char * HostIP: Local IP Address * IN short DestPort: Local Port to listen for incoming connections * Description: * Initializes * - Mutex objects, * - Handle Table * - Thread Pool and Thread Pool Attributes * - MiniServer(starts listening for incoming requests) * and WebServer (Sends request to the * Upper Layer after HTTP Parsing) * - Checks for IP Address passed as an argument. IF NULL, * gets local host name * - Sets GENA and SOAP Callbacks. * - Starts the timer thread. * * Returns: * UPNP_E_SUCCESS on success, nonzero on failure. * UPNP_E_INIT_FAILED if Initialization fails. * UPNP_E_INIT if UPnP is already initialized *****************************************************************************/int UpnpInit( IN const char *HostIP, IN unsigned short DestPort ){ int retVal = 0; ThreadPoolAttr attr;#ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; int err;#endif if( UpnpSdkInit == 1 ) { // already initialized return UPNP_E_INIT; }#ifdef WIN32 wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ return UPNP_E_INIT_FAILED; } /* Confirm that the WinSock DLL supports 2.2.*/ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ WSACleanup( ); return UPNP_E_INIT_FAILED; } /* The WinSock DLL is acceptable. Proceed. */#endif membuffer_init( &gDocumentRootDir ); srand( time( NULL ) ); // needed by SSDP or other parts if( UpnpInitLog() != UPNP_E_SUCCESS ) { return UPNP_E_INIT_FAILED; } UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpInit\n" ); // initialize mutex#ifdef __CYGWIN__ /* On Cygwin, pthread_mutex_init() fails without this memset. */ /* TODO: Fix Cygwin so we don't need this memset(). */ memset(&GlobalHndRWLock, 0, sizeof(GlobalHndRWLock));#endif if (ithread_rwlock_init(&GlobalHndRWLock, NULL) != 0) { return UPNP_E_INIT_FAILED; } if (ithread_mutex_init(&gUUIDMutex, NULL) != 0) { return UPNP_E_INIT_FAILED; } // initialize subscribe mutex#ifdef INCLUDE_CLIENT_APIS if (ithread_mutex_init(&GlobalClientSubscribeMutex, NULL) != 0) { return UPNP_E_INIT_FAILED; }#endif HandleLock(); if( HostIP != NULL ) { strcpy( LOCAL_HOST, HostIP ); } else { if( getlocalhostname( LOCAL_HOST ) != UPNP_E_SUCCESS ) { HandleUnlock(); return UPNP_E_INIT_FAILED; } } if( UpnpSdkInit != 0 ) { HandleUnlock(); return UPNP_E_INIT; } InitHandleList(); HandleUnlock(); TPAttrInit( &attr ); TPAttrSetMaxThreads( &attr, MAX_THREADS ); TPAttrSetMinThreads( &attr, MIN_THREADS ); TPAttrSetJobsPerThread( &attr, JOBS_PER_THREAD ); TPAttrSetIdleTime( &attr, THREAD_IDLE_TIME ); TPAttrSetMaxJobsTotal( &attr, MAX_JOBS_TOTAL ); if( ThreadPoolInit( &gSendThreadPool, &attr ) != UPNP_E_SUCCESS ) { UpnpSdkInit = 0; UpnpFinish(); return UPNP_E_INIT_FAILED; } if( ThreadPoolInit( &gRecvThreadPool, &attr ) != UPNP_E_SUCCESS ) { UpnpSdkInit = 0; UpnpFinish(); return UPNP_E_INIT_FAILED; } if( ThreadPoolInit( &gMiniServerThreadPool, &attr ) != UPNP_E_SUCCESS ) { UpnpSdkInit = 0; UpnpFinish(); return UPNP_E_INIT_FAILED; } UpnpSdkInit = 1;#if EXCLUDE_SOAP == 0 SetSoapCallback( soap_device_callback );#endif#if EXCLUDE_GENA == 0 SetGenaCallback( genaCallback );#endif if( ( retVal = TimerThreadInit( &gTimerThread, &gSendThreadPool ) ) != UPNP_E_SUCCESS ) { UpnpSdkInit = 0; UpnpFinish(); return retVal; }#if EXCLUDE_MINISERVER == 0 if( ( retVal = StartMiniServer( DestPort ) ) <= 0 ) { UpnpPrintf( UPNP_CRITICAL, API, __FILE__, __LINE__, "Miniserver failed to start" ); UpnpFinish(); UpnpSdkInit = 0; if( retVal != -1 ) return retVal; else // if miniserver is already running for unknown reasons! return UPNP_E_INIT_FAILED; }#endif DestPort = retVal; LOCAL_PORT = DestPort;#if EXCLUDE_WEB_SERVER == 0 if( ( retVal = UpnpEnableWebserver( WEB_SERVER_ENABLED ) ) != UPNP_E_SUCCESS ) { UpnpFinish(); UpnpSdkInit = 0; return retVal; }#endif UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Host Ip: %s Host Port: %d\n", LOCAL_HOST, LOCAL_PORT ); UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__, "Exiting UpnpInit\n" ); return UPNP_E_SUCCESS;} /***************** end of UpnpInit ******************/#ifdef DEBUGstatic void PrintThreadPoolStats( ThreadPool *tp, const char *DbgFileName, int DbgLineNo, 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 /* DEBUG */static UPNP_INLINE void PrintThreadPoolStats( ThreadPool *tp, const char *DbgFileName, int DbgLineNo, const char *msg){}#endif /* DEBUG *//**************************************************************************** * Function: UpnpFinish * * Parameters: NONE * * Description: * Checks for pending jobs and threads * Unregisters either the client or device * Shuts down the Timer Thread * Stops the Mini Server * Uninitializes the Thread Pool * For Win32 cleans up Winsock Interface * Cleans up mutex objects * * Return Values: * UPNP_E_SUCCESS on success, nonzero on failure. *****************************************************************************/intUpnpFinish(){#ifdef INCLUDE_DEVICE_APIS UpnpDevice_Handle device_handle;#endif#ifdef INCLUDE_CLIENT_APIS UpnpClient_Handle client_handle;#endif struct Handle_Info *temp;#ifdef WIN32// WSACleanup();#endif 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 if( GetDeviceHandleInfo( &device_handle, &temp ) == HND_DEVICE ) UpnpUnRegisterRootDevice( device_handle );#endif#ifdef INCLUDE_CLIENT_APIS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -