📄 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 <string.h>#include "ssdplib.h"#include "upnpapi.h"#include "ThreadPool.h"#include "httpparser.h"#include "httpreadwrite.h"#include "statcodes.h"#include "unixutil.h"#ifdef WIN32 #include <ws2tcpip.h> #include <winsock2.h>#endif /* WIN32 */#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***************************************************************************/#ifdef INCLUDE_DEVICE_APISvoidssdp_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(); 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 );}#endif/************************************************************************* 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 ){ char errorBuffer[ERROR_BUFFER_LEN]; int ReplySock; int socklen = sizeof( struct sockaddr_in ); int NumCopy; int 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 == -1 ) { strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, "SSDP_LIB: New Request Handler:" "Error in socket(): %s\n", errorBuffer ); 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; // The reason to keep this loop is purely historical/documentation, // according to section 9.2 of HTTPU spec: // // "If a multicast resource would send a response(s) to any copy of the // request, it SHOULD send its response(s) to each copy of the request // it receives. It MUST NOT repeat its response(s) per copy of the // request." // // http://www.upnp.org/download/draft-goland-http-udp-04.txt // // So, NUM_COPY has been changed from 2 to 1. NumCopy = 0; while( NumCopy < NUM_COPY ) { 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" "sc" "ssc" "S" "Xc" "ssc" "sscc", HTTP_OK, "CACHE-CONTROL: max-age=", duration, "EXT:", "LOCATION: ", location, X_USER_AGENT, "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" "Xc" "sscc", HTTPMETHOD_NOTIFY, "*", (size_t)1, "HOST: ", SSDP_IP, ":", SSDP_PORT, "CACHE-CONTROL: max-age=", duration, "LOCATION: ", location, "NT: ", nt, "NTS: ", nts, X_USER_AGENT, "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; 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 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -