📄 ssdp_server.c
字号:
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 + -