miniserver.c

来自「原来由英特尔制定的UPnP SDK的」· C语言 代码 · 共 853 行 · 第 1/2 页

C
853
字号
/////////////////////////////////////////////////////////////////////////////// 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.//////////////////////////////////////////////////////////////////////////////************************************************************************* Purpose: This file implements the functionality and utility functions* used by the Miniserver module.************************************************************************/#include "config.h"#ifndef WIN32	#include <arpa/inet.h>	#include <netinet/in.h>	#include <sys/socket.h>	#include <sys/wait.h>	#include <unistd.h>	#include <sys/time.h>#else /* WIN32 */	#include <winsock2.h>	typedef int socklen_t;	#define EAFNOSUPPORT 97#endif /* WIN32 */#include "unixutil.h"#include "ithread.h"#include <assert.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include "ssdplib.h"#include "util.h"#include "miniserver.h"#include "ThreadPool.h"#include "httpreadwrite.h"#include "statcodes.h"#include "upnpapi.h"#define APPLICATION_LISTENING_PORT 49152struct mserv_request_t {    int connfd;                 // connection handle    struct in_addr foreign_ip_addr;    unsigned short foreign_ip_port;};typedef enum { MSERV_IDLE, MSERV_RUNNING, MSERV_STOPPING } MiniServerState;unsigned short miniStopSockPort;////////////////////////////////////////////////////////////////////////////// module varsstatic MiniServerCallback gGetCallback = NULL;static MiniServerCallback gSoapCallback = NULL;static MiniServerCallback gGenaCallback = NULL;static MiniServerState gMServState = MSERV_IDLE;/************************************************************************ * Function: SetHTTPGetCallback * * Parameters : * 	MiniServerCallback callback - HTTP Callback to be invoked  * * Description: * 	Set HTTP Get Callback * * Return: void ************************************************************************/voidSetHTTPGetCallback( MiniServerCallback callback ){    gGetCallback = callback;}/************************************************************************ * Function: SetSoapCallback * * Parameters: *	MiniServerCallback callback - SOAP Callback to be invoked  * * Description: * 	Set SOAP Callback * * Return: void ************************************************************************/#ifdef INCLUDE_DEVICE_APISvoidSetSoapCallback( MiniServerCallback callback ){    gSoapCallback = callback;}#endif /* INCLUDE_DEVICE_APIS *//************************************************************************ * Function: SetGenaCallback * * Parameters: *	MiniServerCallback callback - GENA Callback to be invoked * * Description: * 	Set GENA Callback * * Return: void ************************************************************************/voidSetGenaCallback( MiniServerCallback callback ){    gGenaCallback = callback;}/************************************************************************ * Function :	dispatch_request * * Parameters : *	IN SOCKINFO *info	- Socket Information object. *	http_parser_t* hparser	- HTTP parser object. * * Description : *	Based on the type pf message, appropriate callback is issued * * Return: int *	0 - On Success *	HTTP_INTERNAL_SERVER_ERROR - Callback is NULL ************************************************************************/static intdispatch_request( IN SOCKINFO * info,                  http_parser_t * hparser ){    MiniServerCallback callback;    switch ( hparser->msg.method ) {            //Soap Call        case SOAPMETHOD_POST:        case HTTPMETHOD_MPOST:            callback = gSoapCallback;            break;            //Gena Call        case HTTPMETHOD_NOTIFY:        case HTTPMETHOD_SUBSCRIBE:        case HTTPMETHOD_UNSUBSCRIBE:            UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,                "miniserver %d: got GENA msg\n", info->socket );            callback = gGenaCallback;            break;            //HTTP server call        case HTTPMETHOD_GET:        case HTTPMETHOD_POST:        case HTTPMETHOD_HEAD:        case HTTPMETHOD_SIMPLEGET:            callback = gGetCallback;            break;        default:            callback = NULL;    }    if( callback == NULL ) {        return HTTP_INTERNAL_SERVER_ERROR;    }    callback( hparser, &hparser->msg, info );    return 0;}/************************************************************************ * Function: handle_error * * Parameters: * 	IN SOCKINFO *info	- Socket Inforamtion Object * 	int http_error_code	- HTTP Error Code * 	int major		- Major Version Number * 	int minor		- Minor Version Number * * Description: * 	Send Error Message * * Return: void ************************************************************************/static UPNP_INLINE voidhandle_error( IN SOCKINFO * info,              int http_error_code,              int major,              int minor ){    http_SendStatusResponse( info, http_error_code, major, minor );}/************************************************************************ * Function: free_handle_request_arg * * Parameters: *	void *args ; Request Message to be freed * * Description: * 	Free memory assigned for handling request and unitialize socket * 	functionality * * Return: void ************************************************************************/static voidfree_handle_request_arg( void *args ){    struct mserv_request_t *request = ( struct mserv_request_t * )args;    shutdown( request->connfd, SD_BOTH );    UpnpCloseSocket( request->connfd );    free( request );}/************************************************************************ * Function: handle_request * * Parameters: *	void *args - Request Message to be handled * * Description: * 	Receive the request and dispatch it for handling * * Return: void ************************************************************************/static voidhandle_request( void *args ){    SOCKINFO info;    int http_error_code;    int ret_code;    int major = 1;    int minor = 1;    http_parser_t parser;    http_message_t *hmsg = NULL;    int timeout = HTTP_DEFAULT_TIMEOUT;    struct mserv_request_t *request = ( struct mserv_request_t * )args;    int connfd = request->connfd;    UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,        "miniserver %d: READING\n", connfd );    //parser_request_init( &parser ); ////LEAK_FIX_MK    hmsg = &parser.msg;    if( sock_init_with_ip( &info, connfd, request->foreign_ip_addr,                           request->foreign_ip_port ) != UPNP_E_SUCCESS ) {        free( request );        httpmsg_destroy( hmsg );        return;    }    // read    ret_code = http_RecvMessage( &info, &parser, HTTPMETHOD_UNKNOWN,                                 &timeout, &http_error_code );    if( ret_code != 0 ) {        goto error_handler;    }    UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,        "miniserver %d: PROCESSING...\n", connfd );    // dispatch    http_error_code = dispatch_request( &info, &parser );    if( http_error_code != 0 ) {        goto error_handler;    }    http_error_code = 0;  error_handler:    if( http_error_code > 0 ) {        if( hmsg ) {            major = hmsg->major_version;            minor = hmsg->minor_version;        }        handle_error( &info, http_error_code, major, minor );    }    UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,        "miniserver %d: COMPLETE\n", connfd );    sock_destroy( &info, SD_BOTH ); //should shutdown completely    httpmsg_destroy( hmsg );    free( request );}/************************************************************************ * Function: schedule_request_job * * Parameters: *	IN int connfd - Socket Descriptor on which connection is accepted *	IN struct sockaddr_in* clientAddr - Clients Address information * * Description: * 	Initilize the thread pool to handle a request. *	Sets priority for the job and adds the job to the thread pool * * Return: void ************************************************************************/static UPNP_INLINE voidschedule_request_job( IN int connfd,                      IN struct sockaddr_in *clientAddr ){    struct mserv_request_t *request;    ThreadPoolJob job;    request =        ( struct mserv_request_t * )        malloc( sizeof( struct mserv_request_t ) );    if( request == NULL ) {        UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,            "mserv %d: out of memory\n", connfd );        shutdown( request->connfd, SD_BOTH );        UpnpCloseSocket( connfd );        return;    }    request->connfd = connfd;    request->foreign_ip_addr = clientAddr->sin_addr;    request->foreign_ip_port = ntohs( clientAddr->sin_port );    TPJobInit( &job, ( start_routine ) handle_request, ( void * )request );    TPJobSetFreeFunction( &job, free_handle_request_arg );    TPJobSetPriority( &job, MED_PRIORITY );    if( ThreadPoolAdd( &gMiniServerThreadPool, &job, NULL ) != 0 ) {        UpnpPrintf( UPNP_INFO, MSERV, __FILE__, __LINE__,            "mserv %d: cannot schedule request\n", connfd );            free( request );        shutdown( connfd, SD_BOTH );        UpnpCloseSocket( connfd );        return;    }}/************************************************************************ * Function: RunMiniServer * * Parameters: *	MiniServerSockArray *miniSock - Socket Array * * Description: * 	Function runs the miniserver. The MiniServer accepts a  *	new request and schedules a thread to handle the new request. *	Checks for socket state and invokes appropriate read and shutdown  *	actions for the Miniserver and SSDP sockets  * * Return: void ************************************************************************/static voidRunMiniServer( MiniServerSockArray *miniSock ){    char errorBuffer[ERROR_BUFFER_LEN];    struct sockaddr_in clientAddr;    socklen_t clientLen;    SOCKET connectHnd;    SOCKET miniServSock = miniSock->miniServerSock;    SOCKET miniServStopSock =  miniSock->miniServerStopSock;    SOCKET ssdpSock = miniSock->ssdpSock;#ifdef INCLUDE_CLIENT_APIS    SOCKET ssdpReqSock = miniSock->ssdpReqSock;#endif    fd_set expSet;    fd_set rdSet;    unsigned int maxMiniSock;    int byteReceived;    char requestBuf[256];    int ret = 0;    maxMiniSock = max( miniServSock, miniServStopSock) ;    maxMiniSock = max( maxMiniSock, (SOCKET)(ssdpSock) );#ifdef INCLUDE_CLIENT_APIS    maxMiniSock = max( maxMiniSock, (SOCKET)(ssdpReqSock) );#endif    ++maxMiniSock;    gMServState = MSERV_RUNNING;    while( TRUE ) {        FD_ZERO( &rdSet );        FD_ZERO( &expSet );        FD_SET( miniServStopSock, &expSet );        FD_SET( miniServSock, &rdSet );        FD_SET( miniServStopSock, &rdSet );        FD_SET( ssdpSock, &rdSet );#ifdef INCLUDE_CLIENT_APIS        FD_SET( ssdpReqSock, &rdSet );#endif        ret = select( maxMiniSock, &rdSet, NULL, &expSet, NULL );        if ( ret == -1 ) {            strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);            UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,                "Error in select(): %s\n", errorBuffer );	    /* Avoid 100% CPU in case of repeated error in select() */	    isleep( 1 );            continue;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?