📄 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"
#ifdef _WIN32
#include <winsock2.h>
#include <Ws2tcpip.h>
#endif
#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
****************************************************************************/
int
genaUnregisterDevice( 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 int
GeneratePropertySet( 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 void
free_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 );
}
static void
free_notifyMulticast_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 int
notify_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 : GenaBroadcastNotifyHandler
*
* 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
*
*
*
* Returns: void *
* 1 if successful else appropriate error
***************************************************************************/
#define GENA_IP "239.255.255.250"
#define GENA_PORT 1901
int
GenaBroadcastNotifyHandler( IN char *RqPacket )
{
// need to know destination address
// need to have the packet to send out
/*#ifdef _WIN32
struct ip_mreq genaMcastAddr;
int option = 1;
#endif*/
struct sockaddr_in DestAddr;
SOCKET ReplySock;
int socklen = sizeof( struct sockaddr_in );
unsigned long replyAddr = inet_addr( LOCAL_HOST );
int ttl = 4; //a/c to UPNP Spec
int rc;
int retVal = UPNP_E_SUCCESS;
DestAddr.sin_family = AF_INET;
DestAddr.sin_addr.s_addr = inet_addr( GENA_IP );
DestAddr.sin_port = htons( GENA_PORT );
ReplySock = socket( AF_INET, SOCK_DGRAM, 0 );
if( ReplySock == UPNP_INVALID_SOCKET ) {
return UPNP_E_OUTOF_SOCKET;
}
//#ifndef _WIN32
setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_IF,
( char * )&replyAddr, sizeof( replyAddr ) );
setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_TTL,
( char * )&ttl, sizeof( int ) );
/*#else
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 );
printf("Socket Error\n");
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;
}
#endif*/
rc = sendto( ReplySock, RqPacket ,
strlen( RqPacket ),
0, ( struct sockaddr * )&DestAddr, socklen );
if (rc < strlen(RqPacket)) {
printf("sendto failed, rc = %d\n", rc);
retVal = UPNP_E_SUCCESS;
}
shutdown( ReplySock, SD_BOTH );
UpnpCloseSocket( ReplySock );
return retVal;
}
/****************************************************************************
* 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 :
****************************************************************************/
int
genaNotify( IN char *headers,
IN char *propertySet,
IN subscription * sub )
{
int i;
membuffer mid_msg;
membuffer endmsg;
uri_type * url;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -