⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ssdp_device.c

📁 电驴下载工具eMule0.47aVeryCD的源代码,可作分析测试也可用于P2P软件的开发研究.
💻 C
📖 第 1 页 / 共 2 页
字号:
///////////////////////////////////////////////////////////////////////////
//
// 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.
//
///////////////////////////////////////////////////////////////////////////

#ifdef INCLUDE_DEVICE_APIS
#if EXCLUDE_SSDP == 0
#include <assert.h>
#include <stdio.h>
#include "config.h"
#include "ssdplib.h"
#include "upnpapi.h"
#include "ThreadPool.h"
#include "httpparser.h"
#include "httpreadwrite.h"
#include "statcodes.h"
#include "unixutil.h"
#ifdef _WIN32
#include <winsock2.h>
#include <Ws2tcpip.h>
#endif

#define MSGTYPE_SHUTDOWN		0
#define MSGTYPE_ADVERTISEMENT	1
#define MSGTYPE_REPLY			2

/************************************************************************
* Function : advertiseAndReplyThread									
*																	
* Parameters:														
*		IN void *data: Structure containing the search request
*
* Description:														
*	This function is a wrapper function to reply the search request 
*	coming from the control point.
*
* Returns: void *
*	always return NULL
***************************************************************************/
void *
advertiseAndReplyThread( IN void *data )
{
    SsdpSearchReply *arg = ( SsdpSearchReply * ) data;

    AdvertiseAndReply( 0, arg->handle,
                       arg->event.RequestType,
                       &arg->dest_addr,
                       arg->event.DeviceType,
                       arg->event.UDN,
                       arg->event.ServiceType, arg->MaxAge );
    free( arg );

    return NULL;
}

/************************************************************************
* Function : ssdp_handle_device_request									
*																	
* Parameters:														
*		IN http_message_t* hmsg: SSDP search request from the control point
*		IN struct sockaddr_in* dest_addr: The address info of control point
*
* Description:														
*	This function handles the search request. It do the sanity checks of
*	the request and then schedules a thread to send a random time reply (
*	random within maximum time given by the control point to reply).
*
* Returns: void *
*	1 if successful else appropriate error
***************************************************************************/
void
ssdp_handle_device_request( IN http_message_t * hmsg,
                            IN struct sockaddr_in *dest_addr )
{
#define MX_FUDGE_FACTOR 10

    int handle;
    struct Handle_Info *dev_info = NULL;
    memptr hdr_value;
    int mx;
    char save_char;
    SsdpEvent event;
    int ret_code;
    SsdpSearchReply *threadArg = NULL;
    ThreadPoolJob job;
    int replyTime;
    int maxAge;

    // check man hdr
    if( httpmsg_find_hdr( hmsg, HDR_MAN, &hdr_value ) == NULL ||
        memptr_cmp( &hdr_value, "\"ssdp:discover\"" ) != 0 ) {
        return;                 // bad or missing hdr
    }
    // MX header
    if( httpmsg_find_hdr( hmsg, HDR_MX, &hdr_value ) == NULL ||
        ( mx = raw_to_int( &hdr_value, 10 ) ) < 0 ) {
        return;
    }
    // ST header
    if( httpmsg_find_hdr( hmsg, HDR_ST, &hdr_value ) == NULL ) {
        return;
    }
    save_char = hdr_value.buf[hdr_value.length];
    hdr_value.buf[hdr_value.length] = '\0';
    ret_code = ssdp_request_type( hdr_value.buf, &event );
    hdr_value.buf[hdr_value.length] = save_char;    // restore
    if( ret_code == -1 ) {
        return;                 // bad ST header
    }

    HandleLock(  );
    // device info
    if( GetDeviceHandleInfo( &handle, &dev_info ) != HND_DEVICE ) {
        HandleUnlock(  );
        return;                 // no info found
    }
    maxAge = dev_info->MaxAge;
    HandleUnlock(  );

    DBGONLY( UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "ssdp_handle_device_request with Cmd %d SEARCH\n",
                         event.Cmd );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "MAX-AGE     =  %d\n", maxAge );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "MX     =  %d\n", event.Mx );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "DeviceType   =  %s\n", event.DeviceType );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "DeviceUuid   =  %s\n", event.UDN );
             UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__,
                         "ServiceType =  %s\n", event.ServiceType ); )

        threadArg =
        ( SsdpSearchReply * ) malloc( sizeof( SsdpSearchReply ) );

    if( threadArg == NULL ) {
        return;
    }
    threadArg->handle = handle;
    threadArg->dest_addr = ( *dest_addr );
    threadArg->event = event;
    threadArg->MaxAge = maxAge;

    TPJobInit( &job, advertiseAndReplyThread, threadArg );
    TPJobSetFreeFunction( &job, ( free_routine ) free );

    //Subtract a percentage from the mx
    //to allow for network and processing delays
    // (i.e. if search is for 30 seconds, 
    //       respond withing 0 - 27 seconds)

    if( mx >= 2 ) {
        mx -= MAXVAL( 1, mx / MX_FUDGE_FACTOR );
    }

    if( mx < 1 ) {
        mx = 1;
    }

    replyTime = rand(  ) % mx;

    TimerThreadSchedule( &gTimerThread, replyTime, REL_SEC, &job,
                         SHORT_TERM, NULL );
}

#ifdef _WIN32
static
void _genaGetIP(char * addr, char * ipAddr, int * portAddr)
{
    int curChar;
    char * charPtr;
    char buf[80];

    curChar = 0;
    while (addr[curChar] != ':') {
	curChar++;
    }
    strncpy(ipAddr, addr, curChar);
    ipAddr[curChar] = 0;
    charPtr = addr + curChar + 1;
    strcpy(buf, charPtr);
    *portAddr = atoi(buf);
}
#endif

/************************************************************************
* Function : NewRequestHandler									
*																	
* Parameters:														
*		IN struct sockaddr_in * DestAddr: Ip address, to send the reply.
*		IN int NumPacket: Number of packet to be sent.
*		IN char **RqPacket:Number of packet to be sent.
*
* Description:														
*	This function works as a request handler which passes the HTTP 
*	request string to multicast channel then
*
* Returns: void *
*	1 if successful else appropriate error
***************************************************************************/
static int
NewRequestHandler( IN struct sockaddr_in *DestAddr,
                   IN int NumPacket,
                   IN char **RqPacket )
{
/*#ifdef _WIN32
    struct ip_mreq genaMcastAddr;
    int option = 1;
	//char ipAddr[80];
    //int portAddr;
#endif*/
    int socklen = sizeof( struct sockaddr_in );
	SOCKET ReplySock;
    int NumCopy, Index;
    unsigned long replyAddr = inet_addr( LOCAL_HOST );
    int ttl = 4;                //a/c to UPNP Spec

    ReplySock = socket( AF_INET, SOCK_DGRAM, 0 );
    if( ReplySock == UPNP_INVALID_SOCKET ) {
        DBGONLY( UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
                             "SSDP_LIB: New Request Handler:"
                             "Error in socket operation !!!\n" ) );

        return UPNP_E_OUTOF_SOCKET;
    }

/*#ifdef _WIN32
	memset( ( void * )&genaMcastAddr, 0, sizeof( struct ip_mreq ) );
    genaMcastAddr.imr_interface.s_addr = htonl( INADDR_ANY );
    genaMcastAddr.imr_multiaddr.s_addr = inet_addr( LOCAL_HOST );
    if( setsockopt( ReplySock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                    ( char * )&genaMcastAddr,
                    sizeof( struct ip_mreq ) ) != 0 ) {
		    shutdown( ReplySock, SD_BOTH );
		    UpnpCloseSocket( ReplySock );
		    return UPNP_E_SOCKET_ERROR;
    }
    // result is not checked becuase it will fail in WinMe and Win9x.
    setsockopt( ReplySock, IPPROTO_IP,
                IP_MULTICAST_TTL, &ttl, sizeof( ttl ) );
    if( setsockopt( ReplySock, SOL_SOCKET, SO_BROADCAST,
                    ( const char * )&option, sizeof( option ) ) != 0 ) {
		    shutdown( ReplySock, SD_BOTH );
		    UpnpCloseSocket( ReplySock );
		    return UPNP_E_NETWORK_ERROR;
    }
#else*/
    setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_IF,
                ( char * )&replyAddr, sizeof( replyAddr ) );
    setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_TTL,
                ( char * )&ttl, sizeof( int ) );
//#endif

    for( Index = 0; Index < NumPacket; Index++ ) {
        int rc;

        NumCopy = 0;
        while( NumCopy < NUM_COPY ) {
            DBGONLY( UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
                                 ">>> SSDP SEND >>>\n%s\n",
                                 *( RqPacket + Index ) );
                 )
                rc = sendto( ReplySock, *( RqPacket + Index ),
                             strlen( *( RqPacket + Index ) ),
                             0, ( struct sockaddr * )DestAddr, socklen );
            imillisleep( SSDP_PAUSE );
            ++NumCopy;
        }
    }

    shutdown( ReplySock, SD_BOTH );
    UpnpCloseSocket( ReplySock );
    return UPNP_E_SUCCESS;
}

/************************************************************************
* Function : CreateServiceRequestPacket									
*																	
* Parameters:														
*	IN int msg_type : type of the message ( Search Reply, Advertisement 
*												or Shutdown )
*	IN char * nt : ssdp type
*	IN char * usn : unique service name ( go in the HTTP Header)
*	IN char * location :Location URL.
*	IN int  duration :Service duration in sec.
*	OUT char** packet :Output buffer filled with HTTP statement.
*
* Description:														
*	This function creates a HTTP request packet.  Depending 
*	on the input parameter it either creates a service advertisement
*   request or service shutdown request etc.
*
* Returns: void
*	
***************************************************************************/
void
CreateServicePacket( IN int msg_type,
                     IN char *nt,
                     IN char *usn,
                     IN char *location,
                     IN int duration,
                     OUT char **packet )
{
    int ret_code;
    char *nts;
    membuffer buf;

    //Notf=0 means service shutdown, 
    //Notf=1 means service advertisement, Notf =2 means reply   

    membuffer_init( &buf );
    buf.size_inc = 30;

    *packet = NULL;

    if( msg_type == MSGTYPE_REPLY ) {
        ret_code = http_MakeMessage( &buf, 1, 1,
                                     "R" "sdc" "D" "s" "ssc" "S" "ssc"
                                     "ssc" "c", HTTP_OK,
                                     "CACHE-CONTROL: max-age=", duration,
                                     "EXT:\r\n", "LOCATION: ", location,
                                     "ST: ", nt, "USN: ", usn );
        if( ret_code != 0 ) {
            return;
        }
    } else if( msg_type == MSGTYPE_ADVERTISEMENT ||
               msg_type == MSGTYPE_SHUTDOWN ) {
        if( msg_type == MSGTYPE_ADVERTISEMENT ) {
            nts = "ssdp:alive";
        } else                  // shutdown
        {
            nts = "ssdp:byebye";
        }

        // NOTE: The CACHE-CONTROL and LOCATION headers are not present in
        //  a shutdown msg, but are present here for MS WinMe interop.

        ret_code = http_MakeMessage( &buf, 1, 1,
                                     "Q" "sssdc" "sdc" "ssc" "ssc" "ssc"
                                     "S" "ssc" "c", HTTPMETHOD_NOTIFY, "*",
                                     1, "HOST: ", SSDP_IP, ":", SSDP_PORT,
                                     "CACHE-CONTROL: max-age=", duration,
                                     "LOCATION: ", location, "NT: ", nt,
                                     "NTS: ", nts, "USN: ", usn );
        if( ret_code != 0 ) {
            return;
        }

    } else {
        assert( 0 );            // unknown msg
    }

    *packet = membuffer_detach( &buf ); // return msg

    membuffer_destroy( &buf );

    return;
}

/************************************************************************
* Function : DeviceAdvertisement									
*																	
* Parameters:														
*	IN char * DevType : type of the device
*	IN int RootDev: flag to indicate if the device is root device
*	IN char * nt : ssdp type
*	IN char * usn : unique service name
*	IN char * location :Location URL.
*	IN int  duration :Service duration in sec.
*
* Description:														
*	This function creates the device advertisement request based on 
*	the input parameter, and send it to the multicast channel.
*
* Returns: int
*	UPNP_E_SUCCESS if successful else appropriate error
***************************************************************************/
int
DeviceAdvertisement( IN char *DevType,
                     int RootDev,
                     char *Udn,
                     IN char *Location,
                     IN int Duration )
{
    struct sockaddr_in DestAddr;

    //char Mil_Nt[LINE_SIZE]
    char Mil_Usn[LINE_SIZE];
    char *msgs[3];
    int ret_code;


    DBGONLY( UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
                         "In function SendDeviceAdvertisemenrt\n" );
         )

        DestAddr.sin_family = AF_INET;
    DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP );
    DestAddr.sin_port = htons( SSDP_PORT );

⌨️ 快捷键说明

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