📄 ssdp_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"#ifdef INCLUDE_DEVICE_APIS#if EXCLUDE_SSDP == 0#include <assert.h>#include <stdio.h>#include "ssdplib.h"#include "upnpapi.h"#include "ThreadPool.h"#include "httpparser.h"#include "httpreadwrite.h"#include "statcodes.h"#include "unixutil.h"#define MSGTYPE_SHUTDOWN 0#define MSGTYPE_ADVERTISEMENT 1#define MSGTYPE_REPLY 2/************************************************************************* Function : advertiseAndReplyThread * * Parameters: * IN void *data: Structure containing the search request** Description: * This function is a wrapper function to reply the search request * coming from the control point.** Returns: void ** always return NULL***************************************************************************/void *advertiseAndReplyThread( IN void *data ){ SsdpSearchReply *arg = ( SsdpSearchReply * ) data; AdvertiseAndReply( 0, arg->handle, arg->event.RequestType, &arg->dest_addr, arg->event.DeviceType, arg->event.UDN, arg->event.ServiceType, arg->MaxAge ); free( arg ); return NULL;}/************************************************************************* Function : ssdp_handle_device_request * * Parameters: * IN http_message_t* hmsg: SSDP search request from the control point* IN struct sockaddr_in* dest_addr: The address info of control point** Description: * This function handles the search request. It do the sanity checks of* the request and then schedules a thread to send a random time reply (* random within maximum time given by the control point to reply).** Returns: void ** 1 if successful else appropriate error***************************************************************************/voidssdp_handle_device_request( IN http_message_t * hmsg, IN struct sockaddr_in *dest_addr ){#define MX_FUDGE_FACTOR 10 int handle; struct Handle_Info *dev_info = NULL; memptr hdr_value; int mx; char save_char; SsdpEvent event; int ret_code; SsdpSearchReply *threadArg = NULL; ThreadPoolJob job; int replyTime; int maxAge; // check man hdr if( httpmsg_find_hdr( hmsg, HDR_MAN, &hdr_value ) == NULL || memptr_cmp( &hdr_value, "\"ssdp:discover\"" ) != 0 ) { return; // bad or missing hdr } // MX header if( httpmsg_find_hdr( hmsg, HDR_MX, &hdr_value ) == NULL || ( mx = raw_to_int( &hdr_value, 10 ) ) < 0 ) { return; } // ST header if( httpmsg_find_hdr( hmsg, HDR_ST, &hdr_value ) == NULL ) { return; } save_char = hdr_value.buf[hdr_value.length]; hdr_value.buf[hdr_value.length] = '\0'; ret_code = ssdp_request_type( hdr_value.buf, &event ); hdr_value.buf[hdr_value.length] = save_char; // restore if( ret_code == -1 ) { return; // bad ST header } HandleLock( ); // device info if( GetDeviceHandleInfo( &handle, &dev_info ) != HND_DEVICE ) { HandleUnlock( ); return; // no info found } maxAge = dev_info->MaxAge; HandleUnlock( ); DBGONLY( UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__, "ssdp_handle_device_request with Cmd %d SEARCH\n", event.Cmd ); UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__, "MAX-AGE = %d\n", maxAge ); UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__, "MX = %d\n", event.Mx ); UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__, "DeviceType = %s\n", event.DeviceType ); UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__, "DeviceUuid = %s\n", event.UDN ); UpnpPrintf( UPNP_PACKET, API, __FILE__, __LINE__, "ServiceType = %s\n", event.ServiceType ); ) threadArg = ( SsdpSearchReply * ) malloc( sizeof( SsdpSearchReply ) ); if( threadArg == NULL ) { return; } threadArg->handle = handle; threadArg->dest_addr = ( *dest_addr ); threadArg->event = event; threadArg->MaxAge = maxAge; TPJobInit( &job, advertiseAndReplyThread, threadArg ); TPJobSetFreeFunction( &job, ( free_routine ) free ); //Subtract a percentage from the mx //to allow for network and processing delays // (i.e. if search is for 30 seconds, // respond withing 0 - 27 seconds) if( mx >= 2 ) { mx -= MAXVAL( 1, mx / MX_FUDGE_FACTOR ); } if( mx < 1 ) { mx = 1; } replyTime = rand( ) % mx; TimerThreadSchedule( &gTimerThread, replyTime, REL_SEC, &job, SHORT_TERM, NULL );}/************************************************************************* Function : NewRequestHandler * * 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 then** Returns: void ** 1 if successful else appropriate error***************************************************************************/static intNewRequestHandler( IN struct sockaddr_in *DestAddr, IN int NumPacket, IN char **RqPacket ){ int ReplySock, socklen = sizeof( struct sockaddr_in ); int NumCopy, Index; unsigned long replyAddr = inet_addr( LOCAL_HOST ); int ttl = 4; //a/c to UPNP Spec ReplySock = socket( AF_INET, SOCK_DGRAM, 0 ); if( ReplySock == UPNP_INVALID_SOCKET ) { DBGONLY( UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, "SSDP_LIB: New Request Handler:" "Error in socket operation !!!\n" ) ); return UPNP_E_OUTOF_SOCKET; } setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_IF, ( char * )&replyAddr, sizeof( replyAddr ) ); setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_TTL, ( char * )&ttl, sizeof( int ) ); for( Index = 0; Index < NumPacket; Index++ ) { int rc; NumCopy = 0; while( NumCopy < NUM_COPY ) { DBGONLY( UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, ">>> SSDP SEND >>>\n%s\n", *( RqPacket + Index ) ); ) rc = sendto( ReplySock, *( RqPacket + Index ), strlen( *( RqPacket + Index ) ), 0, ( struct sockaddr * )DestAddr, socklen ); imillisleep( SSDP_PAUSE ); ++NumCopy; } } shutdown( ReplySock, SD_BOTH ); UpnpCloseSocket( ReplySock ); return UPNP_E_SUCCESS;}/************************************************************************* Function : CreateServiceRequestPacket * * Parameters: * IN int msg_type : type of the message ( Search Reply, Advertisement * or Shutdown )* IN char * nt : ssdp type* IN char * usn : unique service name ( go in the HTTP Header)* IN char * location :Location URL.* IN int duration :Service duration in sec.* OUT char** packet :Output buffer filled with HTTP statement.** Description: * This function creates a HTTP request packet. Depending * on the input parameter it either creates a service advertisement* request or service shutdown request etc.** Returns: void* ***************************************************************************/voidCreateServicePacket( IN int msg_type, IN char *nt, IN char *usn, IN char *location, IN int duration, OUT char **packet ){ int ret_code; char *nts; membuffer buf; //Notf=0 means service shutdown, //Notf=1 means service advertisement, Notf =2 means reply membuffer_init( &buf ); buf.size_inc = 30; *packet = NULL; if( msg_type == MSGTYPE_REPLY ) { ret_code = http_MakeMessage( &buf, 1, 1, "R" "sdc" "D" "s" "ssc" "S" "ssc" "ssc" "c", HTTP_OK, "CACHE-CONTROL: max-age=", duration, "EXT:\r\n", "LOCATION: ", location, "ST: ", nt, "USN: ", usn ); if( ret_code != 0 ) { return; } } else if( msg_type == MSGTYPE_ADVERTISEMENT || msg_type == MSGTYPE_SHUTDOWN ) { if( msg_type == MSGTYPE_ADVERTISEMENT ) { nts = "ssdp:alive"; } else // shutdown { nts = "ssdp:byebye"; } // NOTE: The CACHE-CONTROL and LOCATION headers are not present in // a shutdown msg, but are present here for MS WinMe interop. ret_code = http_MakeMessage( &buf, 1, 1, "Q" "sssdc" "sdc" "ssc" "ssc" "ssc" "S" "ssc" "c", HTTPMETHOD_NOTIFY, "*", 1, "HOST: ", SSDP_IP, ":", SSDP_PORT, "CACHE-CONTROL: max-age=", duration, "LOCATION: ", location, "NT: ", nt, "NTS: ", nts, "USN: ", usn ); if( ret_code != 0 ) { return; } } else { assert( 0 ); // unknown msg } *packet = membuffer_detach( &buf ); // return msg membuffer_destroy( &buf ); return;}/************************************************************************* Function : DeviceAdvertisement * * Parameters: * IN char * DevType : type of the device* IN int RootDev: flag to indicate if the device is root device* IN char * nt : ssdp type* IN char * usn : unique service name* IN char * location :Location URL.* IN int duration :Service duration in sec.** Description: * This function creates the device advertisement request based on * the input parameter, and send it to the multicast channel.** Returns: int* UPNP_E_SUCCESS if successful else appropriate error***************************************************************************/intDeviceAdvertisement( IN char *DevType, int RootDev, char *Udn, IN char *Location, IN int Duration ){ struct sockaddr_in DestAddr; //char Mil_Nt[LINE_SIZE] char Mil_Usn[LINE_SIZE]; char *msgs[3]; int ret_code; DBGONLY( UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, "In function SendDeviceAdvertisemenrt\n" ); ) DestAddr.sin_family = AF_INET; DestAddr.sin_addr.s_addr = inet_addr( SSDP_IP ); DestAddr.sin_port = htons( SSDP_PORT ); msgs[0] = NULL; msgs[1] = NULL; msgs[2] = NULL; //If deviceis a root device , here we need to //send 3 advertisement or reply if( RootDev ) { sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn ); CreateServicePacket( MSGTYPE_ADVERTISEMENT, "upnp:rootdevice", Mil_Usn, Location, Duration, &msgs[0] ); } // both root and sub-devices need to send these two messages // CreateServicePacket( MSGTYPE_ADVERTISEMENT, Udn, Udn, Location, Duration, &msgs[1] ); sprintf( Mil_Usn, "%s::%s", Udn, DevType ); CreateServicePacket( MSGTYPE_ADVERTISEMENT, DevType, Mil_Usn, Location, Duration, &msgs[2] ); // check error if( ( RootDev && msgs[0] == NULL ) || msgs[1] == NULL || msgs[2] == NULL ) { free( msgs[0] ); free( msgs[1] );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -