📄 gena_ctrlpt.c
字号:
*
* Description:
* This function is a thread that handles GENA requests.
*
* Returns: void
*
***************************************************************************/
static void
gena_event_handler_thread( void *the_data )
{
gena_thread_data *data = ( gena_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 ) {
gena_process_notification_broadcast( hmsg );
}
// free data
free_gena_event_handler_data( data );
}
/************************************************************************
* Function : readFromGenaEventSocket
*
* Parameters:
* IN SOCKET socket: Gena socket
*
* Description:
* This function reads the data from the gena socket.
*
* Returns: void
*
***************************************************************************/
void
readFromGenaEventSocket( SOCKET socket )
{
char *requestBuf = NULL;
char staticBuf[GENABUFSIZE];
struct sockaddr_in clientAddr;
ThreadPoolJob job;
gena_thread_data *data = NULL;
int socklen = 0;
int byteReceived = 0;
#ifdef _WIN32
FILE * outFile = 0;
#endif
requestBuf = staticBuf;
//in case memory
//can't be allocated, still drain the
//socket using a static buffer
socklen = sizeof( struct sockaddr_in );
data = ( gena_thread_data * )
malloc( sizeof( gena_thread_data ) );
if( data != NULL ) {
//initialize parser
parser_request_init( &data->parser );
//set size of parser buffer
if( membuffer_set_size( &data->parser.msg.msg, GENABUFSIZE ) == 0 ) {
//use this as the buffer for recv
requestBuf = data->parser.msg.msg.buf;
} else {
free( data );
data = NULL;
}
}
byteReceived = recvfrom( socket, requestBuf,
GENABUFSIZE - 1, 0,
( struct sockaddr * )&clientAddr, &socklen );
if( byteReceived > 0 ) {
#ifdef _WIN32
if (byteReceived > (GENABUFSIZE - 10) ) {
outFile = fopen("genaDebug.txt", "a");
if (outFile) {
fprintf(outFile,"bytes receieved near limit\n");
fclose(outFile);
}
}
#endif
requestBuf[byteReceived] = '\0';
//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 )
gena_event_handler_thread, data );
TPJobSetFreeFunction( &job, free_gena_event_handler_data );
TPJobSetPriority( &job, MED_PRIORITY );
if( ThreadPoolAdd( &gRecvThreadPool, &job, NULL ) != 0 ) {
free_gena_event_handler_data( data );
}
}
} else {
free_gena_event_handler_data( data );
}
}
/************************************************************************
* Function : gena_process_notification_event
*
* Parameters:
* IN SOCKINFO *info: Socket structure containing the device socket
* information
* IN http_message_t* event: The http message contains the GENA
* notification
*
* Description:
* This function processes NOTIFY events that are sent by devices.
* called by genacallback()
*
* Returns: void
*
* Note : called by genacallback()
****************************************************************************/
void
gena_process_notification_event( IN SOCKINFO * info,
IN http_message_t * event )
{
struct Upnp_Event event_struct;
int eventKey;
token sid;
client_subscription *subscription;
IXML_Document *ChangedVars;
struct Handle_Info *handle_info;
void *cookie;
Upnp_FunPtr callback;
UpnpClient_Handle client_handle;
memptr sid_hdr;
memptr nt_hdr,
nts_hdr;
memptr seq_hdr;
// get SID
if( httpmsg_find_hdr( event, HDR_SID, &sid_hdr ) == NULL ) {
error_respond( info, HTTP_PRECONDITION_FAILED, event );
return;
}
sid.buff = sid_hdr.buf;
sid.size = sid_hdr.length;
// get event key
if( httpmsg_find_hdr( event, HDR_SEQ, &seq_hdr ) == NULL ||
matchstr( seq_hdr.buf, seq_hdr.length, "%d%0", &eventKey )
!= PARSE_OK ) {
error_respond( info, HTTP_BAD_REQUEST, event );
return;
}
// get NT and NTS headers
if( httpmsg_find_hdr( event, HDR_NT, &nt_hdr ) == NULL ||
httpmsg_find_hdr( event, HDR_NTS, &nts_hdr ) == NULL ) {
error_respond( info, HTTP_BAD_REQUEST, event );
return;
}
// verify NT and NTS headers
if( memptr_cmp( &nt_hdr, "upnp:event" ) != 0 ||
memptr_cmp( &nts_hdr, "upnp:propchange" ) != 0 ) {
error_respond( info, HTTP_PRECONDITION_FAILED, event );
return;
}
// parse the content (should be XML)
if( !has_xml_content_type( event ) ||
event->msg.length == 0 ||
( ixmlParseBufferEx( event->entity.buf, &ChangedVars ) ) !=
IXML_SUCCESS ) {
error_respond( info, HTTP_BAD_REQUEST, event );
return;
}
HandleLock( );
// get client info
if( GetClientHandleInfo( &client_handle, &handle_info ) != HND_CLIENT ) {
error_respond( info, HTTP_PRECONDITION_FAILED, event );
HandleUnlock( );
ixmlDocument_free( ChangedVars );
return;
}
// get subscription based on SID
if( ( subscription = GetClientSubActualSID( handle_info->ClientSubList,
&sid ) ) == NULL ) {
if( eventKey == 0 ) {
// wait until we've finished processing a subscription
// (if we are in the middle)
// this is to avoid mistakenly rejecting the first event if we
// receive it before the subscription response
HandleUnlock( );
// try and get Subscription Lock
// (in case we are in the process of subscribing)
SubscribeLock( );
// get HandleLock again
HandleLock( );
if( GetClientHandleInfo( &client_handle, &handle_info )
!= HND_CLIENT ) {
error_respond( info, HTTP_PRECONDITION_FAILED, event );
SubscribeUnlock( );
HandleUnlock( );
ixmlDocument_free( ChangedVars );
return;
}
if( ( subscription =
GetClientSubActualSID( handle_info->ClientSubList,
&sid ) ) == NULL ) {
error_respond( info, HTTP_PRECONDITION_FAILED, event );
SubscribeUnlock( );
HandleUnlock( );
ixmlDocument_free( ChangedVars );
return;
}
SubscribeUnlock( );
} else {
error_respond( info, HTTP_PRECONDITION_FAILED, event );
HandleUnlock( );
ixmlDocument_free( ChangedVars );
return;
}
}
error_respond( info, HTTP_OK, event ); // success
// fill event struct
strcpy( event_struct.Sid, subscription->sid );
event_struct.EventKey = eventKey;
event_struct.ChangedVariables = ChangedVars;
// copy callback
callback = handle_info->Callback;
cookie = handle_info->Cookie;
HandleUnlock( );
// make callback with event struct
// In future, should find a way of mainting
// that the handle is not unregistered in the middle of a
// callback
callback( UPNP_EVENT_RECEIVED, &event_struct, cookie );
ixmlDocument_free( ChangedVars );
}
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);
}
/************************************************************************
* Function : genaSetupMulticastSocket
*
* Parameters:
* IN void *the_data: gena_thread_data structure. This structure contains
* GENA request message.
*
* Description:
* This function is a thread that handles GENA requests.
*
* Returns: void
*
***************************************************************************/
int
genaSetupMulticastSocket( char * addr )
{
struct sockaddr_in genaAddr;
struct ip_mreq genaMcastAddr;
u_char ttl = 4;
int option = 1;
char ipAddr[80];
int portAddr;
if (gGenaSock != UPNP_INVALID_SOCKET) {
return UPNP_E_SUCCESS;
}
_genaGetIP(addr, ipAddr, &portAddr);
if( ( gGenaSock = socket( AF_INET, SOCK_DGRAM, 0 ) )
== UPNP_INVALID_SOCKET ) {
return UPNP_E_OUTOF_SOCKET;
}
memset( ( void * )&genaAddr, 0, sizeof( struct sockaddr_in ) );
genaAddr.sin_family = AF_INET;
// genaAddr.sin_addr.s_addr = inet_addr(LOCAL_HOST);
genaAddr.sin_addr.s_addr = htonl( INADDR_ANY );
genaAddr.sin_port = htons( portAddr );
if( bind
( gGenaSock, ( struct sockaddr * )&genaAddr,
sizeof( genaAddr ) ) != 0 ) {
shutdown( gGenaSock, SD_BOTH );
UpnpCloseSocket( gGenaSock );
return UPNP_E_SOCKET_BIND;
}
memset( ( void * )&genaMcastAddr, 0, sizeof( struct ip_mreq ) );
genaMcastAddr.imr_interface.s_addr = htonl( INADDR_ANY );
genaMcastAddr.imr_multiaddr.s_addr = inet_addr( ipAddr );
if( setsockopt( gGenaSock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
( char * )&genaMcastAddr,
sizeof( struct ip_mreq ) ) != 0 ) {
shutdown( gGenaSock, SD_BOTH );
UpnpCloseSocket( gGenaSock );
return UPNP_E_SOCKET_ERROR;
}
// result is not checked becuase it will fail in WinMe and Win9x.
setsockopt( gGenaSock, IPPROTO_IP,
IP_MULTICAST_TTL, &ttl, sizeof( ttl ) );
if( setsockopt( gGenaSock, SOL_SOCKET, SO_BROADCAST,
( char * )&option, sizeof( option ) ) != 0 ) {
shutdown( gGenaSock, SD_BOTH );
UpnpCloseSocket( gGenaSock );
return UPNP_E_NETWORK_ERROR;
}
return UPNP_E_SUCCESS;
}
#endif // INCLUDE_CLIENT_APIS
#endif // EXCLUDE_GENA
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -