📄 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.
//
///////////////////////////////////////////////////////////////////////////
//File upnpapi.c
#include <assert.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include "config.h"
#include "upnpapi.h"
#include "httpreadwrite.h"
#include "ssdplib.h"
#include "soaplib.h"
#include "ThreadPool.h"
#include "membuffer.h"
#ifndef _WIN32
#include <sys/ioctl.h>
#include <linux/if.h>
#include <sys/utsname.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#else
#include <winsock2.h>
#include <Ws2tcpip.h>
#endif
#include "httpreadwrite.h"
//************************************
//Needed for GENA
#include "gena.h"
#include "gena_device.h"
#include "service_table.h"
#include "miniserver.h"
//*******************************************
/*
********************* */
#ifdef INTERNAL_WEB_SERVER
#include "webserver.h"
#include "urlconfig.h"
#endif // INTERNAL_WEB_SERVER
/*
****************** */
//Mutex to synchronize the subscription handling at the client side
CLIENTONLY( ithread_mutex_t GlobalClientSubscribeMutex;
)
//Mutex to synchronize handles ( root device or control point handle)
ithread_mutex_t GlobalHndMutex;
//Mutex to synchronize the uuid creation process
ithread_mutex_t gUUIDMutex;
TimerThread gTimerThread;
ThreadPool gRecvThreadPool;
ThreadPool gSendThreadPool;
//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.
int 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 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
DBGONLY( if( InitLog( ) != UPNP_E_SUCCESS )
return UPNP_E_INIT_FAILED; );
DBGONLY( UpnpPrintf
( UPNP_INFO, API, __FILE__, __LINE__, "Inside UpnpInit \n" );
)
//initialize mutex
if( ithread_mutex_init( &GlobalHndMutex, NULL ) != 0 ) {
return UPNP_E_INIT_FAILED;
}
if( ithread_mutex_init( &gUUIDMutex, NULL ) != 0 ) {
return UPNP_E_INIT_FAILED;
}
//initialize subscribe mutex
CLIENTONLY( if
( ithread_mutex_init( &GlobalClientSubscribeMutex, NULL )
!= 0 ) {
return UPNP_E_INIT_FAILED;}
)
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 );
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;
}
UpnpSdkInit = 1;
#if EXCLUDE_SOAP == 0
DEVICEONLY( 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 ) {
DBGONLY( 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
DBGONLY( UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
"Host Ip: %s Host Port: %d\n", LOCAL_HOST,
LOCAL_PORT ) );
DBGONLY( UpnpPrintf
( UPNP_INFO, API, __FILE__, __LINE__, "Exiting UpnpInit \n" );
)
return UPNP_E_SUCCESS;
} /***************** end of UpnpInit ******************/
/****************************************************************************
* 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.
*****************************************************************************/
int
UpnpFinish( )
{
DEVICEONLY( UpnpDevice_Handle device_handle;
)
CLIENTONLY( UpnpClient_Handle client_handle;
)
struct Handle_Info *temp;
DBGONLY( ThreadPoolStats stats;
)
#ifdef _WIN32
// WSACleanup( );
#endif
if( UpnpSdkInit != 1 )
return UPNP_E_FINISH;
DBGONLY( 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" );}
ThreadPoolGetStats( &gRecvThreadPool, &stats );
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
"Recv Thread Pool \n High Jobs pending = %d"
" \nMed Jobs Pending = %d\n Low Jobs Pending = %d \nWorker Threads"
" = %d\nIdle Threads = %d\nPersistent Threads = %d\nAverage Time "
"spent in High Q = %lf\nAverage Time spent in Med Q = %lf\nAverage"
" Time spent in Low Q = %lf\nMax Threads Used: %d\nTotal Work Time"
"= %lf\nTotal Idle Time = %lf\n",
stats.currentJobsHQ, stats.currentJobsMQ,
stats.currentJobsLQ, stats.persistentThreads,
stats.avgWaitHQ, stats.avgWaitMQ, stats.avgWaitLQ,
stats.maxThreads, stats.totalWorkTime,
stats.totalIdleTime );
ThreadPoolGetStats( &gSendThreadPool, &stats );
UpnpPrintf( UPNP_INFO, API, __FILE__, __LINE__,
"Send Thread Pool \n High Jobs pending = %d"
" \nMed Jobs Pending = %d\n Low Jobs Pending = %d \nWorker Threads"
" = %d\nIdle Threads = %d\nPersistent Threads = %d\nAverage Time "
"spent in High Q = %lf\nAverage Time spent in Med Q = %lf\nAverage"
" Time spent in Low Q = %lf\nMax Threads Used: %d\nTotal Work Time"
"= %lf\nTotal Idle Time = %lf\n",
stats.currentJobsHQ, stats.currentJobsMQ,
stats.currentJobsLQ, stats.persistentThreads,
stats.avgWaitHQ, stats.avgWaitMQ, stats.avgWaitLQ,
stats.maxThreads, stats.totalWorkTime,
stats.totalIdleTime ); )
#ifdef INCLUDE_DEVICE_APIS
if( GetDeviceHandleInfo( &device_handle, &temp ) == HND_DEVICE )
UpnpUnRegisterRootDevice( device_handle );
#endif
#ifdef INCLUDE_CLIENT_APIS
if( GetClientHandleInfo( &client_handle, &temp ) == HND_CLIENT )
UpnpUnRegisterClient( client_handle );
#endif
TimerThreadShutdown( &gTimerThread );
StopMiniServer( );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -