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

📄 ssdp_server.c

📁 电驴下载工具eMule0.47aVeryCD的源代码,可作分析测试也可用于P2P软件的开发研究.
💻 C
📖 第 1 页 / 共 3 页
字号:
static XINLINE xboolean
valid_ssdp_msg( IN http_message_t * hmsg )
{
    memptr hdr_value;

    // check for valid methods - NOTIFY or M-SEARCH
    if( hmsg->method != HTTPMETHOD_NOTIFY &&
        hmsg->method != HTTPMETHOD_MSEARCH
        && hmsg->request_method != HTTPMETHOD_MSEARCH ) {
        return FALSE;
    }
    if( hmsg->request_method != HTTPMETHOD_MSEARCH ) {
        // check PATH == *
        if( hmsg->uri.type != RELATIVE ||
            strncmp( "*", hmsg->uri.pathquery.buff,
                     hmsg->uri.pathquery.size ) != 0 ) {
            return FALSE;
        }
        // check HOST header
        if( ( httpmsg_find_hdr( hmsg, HDR_HOST, &hdr_value ) == NULL ) ||
            ( memptr_cmp( &hdr_value, "239.255.255.250:1900" ) != 0 )
             ) {
            return FALSE;
        }
    }
    return TRUE;                // passed quick check
}

/************************************************************************
* Function : start_event_handler								
*																	
* Parameters:														
*	IN void *the_data: ssdp_thread_data structure. This structure contains
*			SSDP request message.
*
* Description:														
*	This function parses the message and dispatches it to a handler 
*	which handles the ssdp request msg
*
* Returns: int
*	0 if successful -1 if error
***************************************************************************/
static XINLINE int
start_event_handler( void *Data )
{

    http_parser_t *parser = NULL;
    parse_status_t status;
    ssdp_thread_data *data = ( ssdp_thread_data * ) Data;

    parser = &data->parser;

    status = parser_parse( parser );
    if( status == PARSE_FAILURE ) {
        if( parser->msg.method != HTTPMETHOD_NOTIFY ||
            !parser->valid_ssdp_notify_hack ) {
            DBGONLY( UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
                                 "SSDP recvd bad msg code = %d\n",
                                 status );
                 )
                // ignore bad msg, or not enuf mem
                goto error_handler;
        }
        // valid notify msg
    } else if( status != PARSE_SUCCESS ) {
        DBGONLY( UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
                             "SSDP recvd bad msg code = %d\n", status );
             )

            goto error_handler;
    }
    // check msg
    if( !valid_ssdp_msg( &parser->msg ) ) {
        goto error_handler;
    }
    return 0;                   //////// done; thread will free 'data'

  error_handler:
    free_ssdp_event_handler_data( data );
    return -1;
}

/************************************************************************
* Function : ssdp_event_handler_thread								
*																	
* Parameters:														
*	IN void *the_data: ssdp_thread_data structure. This structure contains
*			SSDP request message.
*
* Description:														
*	This function is a thread that handles SSDP requests.
*
* Returns: void
*	
***************************************************************************/
static void
ssdp_event_handler_thread( void *the_data )
{
    ssdp_thread_data *data = ( ssdp_thread_data * ) the_data;
    http_message_t *hmsg = &data->parser.msg;

    if( start_event_handler( the_data ) != 0 ) {
        return;
    }
    // send msg to device or ctrlpt
    if( ( hmsg->method == HTTPMETHOD_NOTIFY ) ||
        ( hmsg->request_method == HTTPMETHOD_MSEARCH ) ) {

        CLIENTONLY( ssdp_handle_ctrlpt_msg( hmsg, &data->dest_addr,
                                            FALSE, NULL );
             );
    } else {
        DEVICEONLY( ssdp_handle_device_request( hmsg, &data->dest_addr );
             );
    }

    // free data
    free_ssdp_event_handler_data( data );
}

/************************************************************************
* Function : readFromSSDPSocket								
*																	
* Parameters:														
*	IN SOCKET socket: SSDP socket
*
* Description:														
*	This function reads the data from the ssdp socket.
*
* Returns: void
*	
***************************************************************************/
void
readFromSSDPSocket( SOCKET socket )
{
    char *requestBuf = NULL;
    char staticBuf[BUFSIZE];
    struct sockaddr_in clientAddr;
    ThreadPoolJob job;
    ssdp_thread_data *data = NULL;
    int socklen = 0;
    int byteReceived = 0;

    requestBuf = staticBuf;

    //in case memory
    //can't be allocated, still drain the 
    //socket using a static buffer

    socklen = sizeof( struct sockaddr_in );

    data = ( ssdp_thread_data * )
        malloc( sizeof( ssdp_thread_data ) );

    if( data != NULL ) {
        //initialize parser

#ifdef INCLUDE_CLIENT_APIS
        if( socket == gSsdpReqSocket ) {
            parser_response_init( &data->parser, HTTPMETHOD_MSEARCH );
        } else {
            parser_request_init( &data->parser );
        }
#else
        parser_request_init( &data->parser );
#endif

        //set size of parser buffer

        if( membuffer_set_size( &data->parser.msg.msg, BUFSIZE ) == 0 ) {
            //use this as the buffer for recv
            requestBuf = data->parser.msg.msg.buf;

        } else {
            free( data );
            data = NULL;
        }
    }
    byteReceived = recvfrom( socket, requestBuf,
                             BUFSIZE - 1, 0,
                             ( struct sockaddr * )&clientAddr, &socklen );

    if( byteReceived > 0 ) {

        requestBuf[byteReceived] = '\0';
        DBGONLY( UpnpPrintf( UPNP_INFO, SSDP,
                             __FILE__, __LINE__,
                             "Received response !!!  "
                             "%s From host %s \n",
                             requestBuf,
                             inet_ntoa( clientAddr.sin_addr ) );
             )

            DBGONLY( UpnpPrintf( UPNP_PACKET, SSDP,
                                 __FILE__, __LINE__,
                                 "Received multicast packet:"
                                 "\n %s\n", requestBuf );
             )
            //add thread pool job to handle request
            if( data != NULL ) {
            data->parser.msg.msg.length += byteReceived;
            // null-terminate
            data->parser.msg.msg.buf[byteReceived] = 0;
            data->dest_addr = clientAddr;
            TPJobInit( &job, ( start_routine )
                       ssdp_event_handler_thread, data );
            TPJobSetFreeFunction( &job, free_ssdp_event_handler_data );
            TPJobSetPriority( &job, MED_PRIORITY );

            if( ThreadPoolAdd( &gRecvThreadPool, &job, NULL ) != 0 ) {
                free_ssdp_event_handler_data( data );
            }
        }

    } else {
        free_ssdp_event_handler_data( data );
    }
}

/************************************************************************
* Function : get_ssdp_sockets								
*																	
* Parameters:														
*	OUT MiniServerSockArray *out: Arrays of SSDP sockets
*
* Description:														
*	This function creates the ssdp sockets. It set their option to listen 
*	for multicast traffic.
*
* Returns: int
*	return UPNP_E_SUCCESS if successful else returns appropriate error
***************************************************************************/
int
get_ssdp_sockets( MiniServerSockArray * out )
{
    SOCKET ssdpSock;

    CLIENTONLY( SOCKET ssdpReqSock;
         )
    int onOff = 1;
    u_char ttl = 4;
    struct ip_mreq ssdpMcastAddr;
    struct sockaddr_in ssdpAddr;
    int option = 1;

    CLIENTONLY( if( ( ssdpReqSock = socket( AF_INET, SOCK_DGRAM, 0 ) )
                    == UPNP_INVALID_SOCKET ) {
                DBGONLY( UpnpPrintf( UPNP_CRITICAL,
                                     SSDP, __FILE__, __LINE__,
                                     "Error in socket operation !!!\n" ); )
                return UPNP_E_OUTOF_SOCKET;}
                setsockopt( ssdpReqSock,
                            IPPROTO_IP,
                            IP_MULTICAST_TTL, &ttl, sizeof( ttl ) );
                // just do it, regardless if fails or not.
                Make_Socket_NoBlocking( ssdpReqSock ); gSsdpReqSocket = ssdpReqSock; )  //CLIENTONLY

        if( ( ssdpSock = socket( AF_INET, SOCK_DGRAM, 0 ) )
            == UPNP_INVALID_SOCKET ) {
            DBGONLY( UpnpPrintf( UPNP_CRITICAL,
                                 SSDP, __FILE__, __LINE__,
                                 "Error in socket operation !!!\n" );
                 )
                CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ) );
            CLIENTONLY( UpnpCloseSocket( ssdpReqSock ) );
            return UPNP_E_OUTOF_SOCKET;
        }

    onOff = 1;
    if( setsockopt( ssdpSock, SOL_SOCKET, SO_REUSEADDR,
                    ( char * )&onOff, sizeof( onOff ) ) != 0 ) {

        DBGONLY( UpnpPrintf( UPNP_CRITICAL,
                             SSDP, __FILE__, __LINE__,
                             "Error in set reuse addr !!!\n" );
             )
            CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ) );
        CLIENTONLY( UpnpCloseSocket( ssdpReqSock ) );
        shutdown( ssdpSock, SD_BOTH );
        UpnpCloseSocket( ssdpSock );
        return UPNP_E_SOCKET_ERROR;
    }

    memset( ( void * )&ssdpAddr, 0, sizeof( struct sockaddr_in ) );
    ssdpAddr.sin_family = AF_INET;
    //  ssdpAddr.sin_addr.s_addr = inet_addr(LOCAL_HOST);
    ssdpAddr.sin_addr.s_addr = htonl( INADDR_ANY );
    ssdpAddr.sin_port = htons( SSDP_PORT );
    if( bind
        ( ssdpSock, ( struct sockaddr * )&ssdpAddr,
          sizeof( ssdpAddr ) ) != 0 ) {
        DBGONLY( UpnpPrintf
                 ( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
                   "Error in binding !!!\n" );
             )
            shutdown( ssdpSock, SD_BOTH );
        UpnpCloseSocket( ssdpSock );
        CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ) );
        CLIENTONLY( UpnpCloseSocket( ssdpReqSock ) );
        return UPNP_E_SOCKET_BIND;
    }

    memset( ( void * )&ssdpMcastAddr, 0, sizeof( struct ip_mreq ) );
    ssdpMcastAddr.imr_interface.s_addr = htonl( INADDR_ANY );
    ssdpMcastAddr.imr_multiaddr.s_addr = inet_addr( SSDP_IP );
    if( setsockopt( ssdpSock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                    ( char * )&ssdpMcastAddr,
                    sizeof( struct ip_mreq ) ) != 0 ) {
        DBGONLY( UpnpPrintf
                 ( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
                   "Error in joining" " multicast group !!!\n" );
             )
            shutdown( ssdpSock, SD_BOTH );
        CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ) );
        UpnpCloseSocket( ssdpSock );
        CLIENTONLY( UpnpCloseSocket( ssdpReqSock ) );
        return UPNP_E_SOCKET_ERROR;
    }
    // result is not checked becuase it will fail in WinMe and Win9x.
    setsockopt( ssdpSock, IPPROTO_IP,
                IP_MULTICAST_TTL, &ttl, sizeof( ttl ) );
    if( setsockopt( ssdpSock, SOL_SOCKET, SO_BROADCAST,
                    ( char * )&option, sizeof( option ) ) != 0 ) {
        DBGONLY( UpnpPrintf( UPNP_CRITICAL,
                             SSDP, __FILE__, __LINE__,
                             "Error in setting broadcast !!!\n" );
             )
            shutdown( ssdpSock, SD_BOTH );
        CLIENTONLY( shutdown( ssdpReqSock, SD_BOTH ) );
        UpnpCloseSocket( ssdpSock );
        CLIENTONLY( UpnpCloseSocket( ssdpReqSock ) );
        return UPNP_E_NETWORK_ERROR;
    }

    CLIENTONLY( out->ssdpReqSock = ssdpReqSock;
         );
    out->ssdpSock = ssdpSock;
    return UPNP_E_SUCCESS;
}

#endif // EXCLUDE_SSDP

⌨️ 快捷键说明

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