📄 gena_device.c
字号:
/////////////////////////////////////////////////////////////////////////////// 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./////////////////////////////////////////////////////////////////////////////#include "config.h"#if EXCLUDE_GENA == 0#ifdef INCLUDE_DEVICE_APIS#include "gena.h"#include "sysdep.h"#include "uuid.h"#include "upnpapi.h"#include "parsetools.h"#include "statcodes.h"#include "httpparser.h"#include "httpreadwrite.h"#include "unixutil.h"/************************************************************************* Function : genaUnregisterDevice* * Parameters: * IN UpnpDevice_Handle device_handle: Handle of the root device** Description: * This function cleans the service table of the device. ** Returns: int* returns UPNP_E_SUCCESS if successful else returns GENA_E_BAD_HANDLE****************************************************************************/intgenaUnregisterDevice( IN UpnpDevice_Handle device_handle ){ struct Handle_Info *handle_info; HandleLock( ); if( GetHandleInfo( device_handle, &handle_info ) != HND_DEVICE ) { DBGONLY( UpnpPrintf( UPNP_CRITICAL, GENA, __FILE__, __LINE__, "genaUnregisterDevice : BAD Handle : %d\n", device_handle ) ); HandleUnlock( ); return GENA_E_BAD_HANDLE; } freeServiceTable( &handle_info->ServiceTable ); HandleUnlock( ); return UPNP_E_SUCCESS;}/************************************************************************* Function : GeneratePropertySet* * Parameters: * IN char **names : Array of variable names (go in the event notify)* IN char ** values : Array of variable values (go in the event notify)* IN int count : number of variables* OUT DOMString *out: PropertySet node in the string format** Description: * This function to generate XML propery Set for notifications ** Returns: int* returns UPNP_E_SUCCESS if successful else returns GENA_E_BAD_HANDLE** Note: XML_VERSION comment is NOT sent due to interop issues with other * UPnP vendors****************************************************************************/static intGeneratePropertySet( IN char **names, IN char **values, IN int count, OUT DOMString * out ){ char *buffer; int counter = 0; int size = 0; int temp_counter = 0; //size+=strlen(XML_VERSION); the XML_VERSION is not interopeable with //other vendors size += strlen( XML_PROPERTYSET_HEADER ); size += strlen( "</e:propertyset>\n\n" ); for( temp_counter = 0, counter = 0; counter < count; counter++ ) { size += strlen( "<e:property>\n</e:property>\n" ); size += ( 2 * strlen( names[counter] ) + strlen( values[counter] ) + ( strlen( "<></>\n" ) ) ); } buffer = ( char * )malloc( size + 1 ); if( buffer == NULL ) { return UPNP_E_OUTOF_MEMORY; } memset( buffer, 0, size + 1 ); //strcpy(buffer,XML_VERSION); the XML_VERSION is not interopeable with //other vendors strcpy( buffer, XML_PROPERTYSET_HEADER ); for( counter = 0; counter < count; counter++ ) { strcat( buffer, "<e:property>\n" ); sprintf( &buffer[strlen( buffer )], "<%s>%s</%s>\n</e:property>\n", names[counter], values[counter], names[counter] ); } strcat( buffer, "</e:propertyset>\n\n" ); ( *out ) = ixmlCloneDOMString( buffer ); free( buffer ); return XML_SUCCESS;}/************************************************************************* Function : free_notify_struct* * Parameters: * IN notify_thread_struct * input : Notify structure** Description: * This function frees memory used in notify_threads if the reference * count is 0 otherwise decrements the refrence count** Returns: VOID* ****************************************************************************/static voidfree_notify_struct( IN notify_thread_struct * input ){ ( *input->reference_count )--; if( ( *input->reference_count ) == 0 ) { free( input->headers ); ixmlFreeDOMString( input->propertySet ); free( input->servId ); free( input->UDN ); free( input->reference_count ); } free( input );}/***************************************************************************** Function : notify_send_and_recv** Parameters :* IN uri_type* destination_url : subscription callback URL * (URL of the control point)* IN membuffer* mid_msg : Common HTTP headers * IN char* propertySet : The evented XML * OUT http_parser_t* response : The response from the control point.** Description : This function sends the notify message and returns a * reply.** Return : int* on success: returns UPNP_E_SUCCESS; else returns a UPNP error** Note : called by genaNotify****************************************************************************/static XINLINE intnotify_send_and_recv( IN uri_type * destination_url, IN membuffer * mid_msg, IN char *propertySet, OUT http_parser_t * response ){ uri_type url; int conn_fd; membuffer start_msg; int ret_code; int err_code; int timeout; SOCKINFO info; // connect DBGONLY( UpnpPrintf( UPNP_ALL, GENA, __FILE__, __LINE__, "gena notify to: %.*s\n", destination_url->hostport.text.size, destination_url->hostport.text.buff ); ) conn_fd = http_Connect( destination_url, &url ); if( conn_fd < 0 ) { return conn_fd; // return UPNP error } if( ( ret_code = sock_init( &info, conn_fd ) ) != 0 ) { sock_destroy( &info, SD_BOTH ); return ret_code; } // make start line and HOST header membuffer_init( &start_msg ); if( http_MakeMessage( &start_msg, 1, 1, "q" "s", HTTPMETHOD_NOTIFY, &url, mid_msg->buf ) != 0 ) { membuffer_destroy( &start_msg ); sock_destroy( &info, SD_BOTH ); return UPNP_E_OUTOF_MEMORY; } timeout = HTTP_DEFAULT_TIMEOUT; // send msg (note +1 for propertyset; null-terminator is also sent) if( ( ret_code = http_SendMessage( &info, &timeout, "bb", start_msg.buf, start_msg.length, propertySet, strlen( propertySet ) + 1 ) ) != 0 ) { membuffer_destroy( &start_msg ); sock_destroy( &info, SD_BOTH ); return ret_code; } if( ( ret_code = http_RecvMessage( &info, response, HTTPMETHOD_NOTIFY, &timeout, &err_code ) ) != 0 ) { membuffer_destroy( &start_msg ); sock_destroy( &info, SD_BOTH ); httpmsg_destroy( &response->msg ); return ret_code; } sock_destroy( &info, SD_BOTH ); //should shutdown completely //when closing socket // sock_destroy( &info,SD_RECEIVE); membuffer_destroy( &start_msg ); return UPNP_E_SUCCESS;}/***************************************************************************** Function : genaNotify** Parameters :* IN char *headers : (null terminated) (includes all headers * (including \r\n) except SID and SEQ)* IN char *propertySet : The evented XML * IN subscription* sub : subscription to be Notified, * Assumes this is valid for life of function)** Description : Function to Notify a particular subscription of a * particular event. In general the service should NOT be * blocked around this call. (this may cause deadlock * with a client) NOTIFY http request is sent and the * reply is processed.** Return : int* GENA_SUCCESS if the event was delivered else returns appropriate * error** Note :****************************************************************************/intgenaNotify( IN char *headers, IN char *propertySet, IN subscription * sub ){ int i; membuffer mid_msg; membuffer endmsg; uri_type *url; http_parser_t response; int return_code = -1; membuffer_init( &mid_msg ); // make 'end' msg (the part that won't vary with the destination) endmsg.size_inc = 30; if( http_MakeMessage( &mid_msg, 1, 1, "s" "ssc" "sdcc", headers, "SID: ", sub->sid, "SEQ: ", sub->ToSendEventKey ) != 0 ) { membuffer_destroy( &mid_msg ); return UPNP_E_OUTOF_MEMORY; } // send a notify to each url until one goes thru for( i = 0; i < sub->DeliveryURLs.size; i++ ) { url = &sub->DeliveryURLs.parsedURLs[i]; if( ( return_code = notify_send_and_recv( url, &mid_msg, propertySet, &response ) ) == UPNP_E_SUCCESS ) { break; } } membuffer_destroy( &mid_msg ); if( return_code == UPNP_E_SUCCESS ) { if( response.msg.status_code == HTTP_OK ) { return_code = GENA_SUCCESS; } else { if( response.msg.status_code == HTTP_PRECONDITION_FAILED ) { //Invalid SID gets removed return_code = GENA_E_NOTIFY_UNACCEPTED_REMOVE_SUB; } else { return_code = GENA_E_NOTIFY_UNACCEPTED; } } httpmsg_destroy( &response.msg ); } return return_code;}/***************************************************************************** Function : genaNotifyThread** Parameters :* IN void * input : notify thread structure containing all the * headers and property set info** Description : Thread job to Notify a control point. It validates the* subscription and copies the subscription. Also make sure that * events are sent in order. ** Return : void** Note : calls the genaNotify to do the actual work****************************************************************************/static voidgenaNotifyThread( IN void *input ){ subscription *sub; service_info *service; subscription sub_copy; notify_thread_struct *in = ( notify_thread_struct * ) input; int return_code; struct Handle_Info *handle_info; ThreadPoolJob job; HandleLock( ); //validate context if( GetHandleInfo( in->device_handle, &handle_info ) != HND_DEVICE ) { free_notify_struct( in ); HandleUnlock( ); return; } if( ( ( service = FindServiceId( &handle_info->ServiceTable, in->servId, in->UDN ) ) == NULL ) || ( !service->active ) || ( ( sub = GetSubscriptionSID( in->sid, service ) ) == NULL ) || ( ( copy_subscription( sub, &sub_copy ) != HTTP_SUCCESS ) ) ) { free_notify_struct( in ); HandleUnlock( ); return; } //If the event is out of order push it back to the job queue if( in->eventKey != sub->ToSendEventKey ) { TPJobInit( &job, ( start_routine ) genaNotifyThread, input ); TPJobSetFreeFunction( &job, ( free_function ) free_notify_struct ); TPJobSetPriority( &job, MED_PRIORITY ); ThreadPoolAdd( &gSendThreadPool, &job, NULL ); freeSubscription( &sub_copy ); HandleUnlock( ); return; } HandleUnlock( ); //send the notify return_code = genaNotify( in->headers, in->propertySet, &sub_copy ); freeSubscription( &sub_copy ); HandleLock( ); if( GetHandleInfo( in->device_handle, &handle_info ) != HND_DEVICE ) { free_notify_struct( in ); HandleUnlock( ); return; } //validate context if( ( ( service = FindServiceId( &handle_info->ServiceTable, in->servId, in->UDN ) ) == NULL ) || ( !service->active ) || ( ( sub = GetSubscriptionSID( in->sid, service ) ) == NULL ) ) { free_notify_struct( in ); HandleUnlock( ); return; } sub->ToSendEventKey++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -