
Put the loop to send multiple copies of each SSDP advertisements in ssdp_server.c instead of ssdp_device.c so we have only one call to imillisleep ( SSDP_PAUSE ) to speed up advertisements.
979 lines
29 KiB
C
979 lines
29 KiB
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 "httpparser.h"
|
|
#include "httpreadwrite.h"
|
|
#include "ssdplib.h"
|
|
#include "statcodes.h"
|
|
#include "ThreadPool.h"
|
|
#include "unixutil.h"
|
|
#include "upnpapi.h"
|
|
#include "UpnpInet.h"
|
|
|
|
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.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,
|
|
(struct sockaddr*)&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 *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_APIS
|
|
void ssdp_handle_device_request(
|
|
IN http_message_t *hmsg,
|
|
IN struct sockaddr *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( dest_addr->sa_family,
|
|
&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;
|
|
memcpy( &threadArg->dest_addr, dest_addr, sizeof(threadArg->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 *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 int
|
|
NewRequestHandler( IN struct sockaddr *DestAddr,
|
|
IN int NumPacket,
|
|
IN char **RqPacket )
|
|
{
|
|
char errorBuffer[ERROR_BUFFER_LEN];
|
|
SOCKET ReplySock;
|
|
int socklen = sizeof( struct sockaddr_storage );
|
|
int Index;
|
|
unsigned long replyAddr = inet_addr( gIF_IPV4 );
|
|
int ttl = 4; // a/c to UPNP Spec
|
|
int hops = 1;
|
|
char buf_ntop[64];
|
|
int ret = UPNP_E_SUCCESS;
|
|
|
|
ReplySock = socket( DestAddr->sa_family, 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;
|
|
}
|
|
|
|
if( DestAddr->sa_family == AF_INET ) {
|
|
inet_ntop(AF_INET, &((struct sockaddr_in*)DestAddr)->sin_addr,
|
|
buf_ntop, sizeof(buf_ntop));
|
|
setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_IF,
|
|
(char *)&replyAddr, sizeof (replyAddr) );
|
|
setsockopt( ReplySock, IPPROTO_IP, IP_MULTICAST_TTL,
|
|
(char *)&ttl, sizeof (int) );
|
|
socklen = sizeof(struct sockaddr_in);
|
|
} else if( DestAddr->sa_family == AF_INET6 ) {
|
|
inet_ntop(AF_INET6, &((struct sockaddr_in6*)DestAddr)->sin6_addr,
|
|
buf_ntop, sizeof(buf_ntop));
|
|
setsockopt( ReplySock, IPPROTO_IPV6, IPV6_MULTICAST_IF,
|
|
(char *)&gIF_INDEX, sizeof(gIF_INDEX) );
|
|
setsockopt( ReplySock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
|
|
(char *)&hops, sizeof(hops) );
|
|
} else {
|
|
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
|
|
"Invalid destination address specified." );
|
|
ret = UPNP_E_NETWORK_ERROR;
|
|
goto end_NewRequestHandler;
|
|
}
|
|
|
|
for( Index = 0; Index < NumPacket; Index++ ) {
|
|
int rc;
|
|
UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
|
|
">>> SSDP SEND to %s >>>\n%s\n",
|
|
buf_ntop, *( RqPacket + Index ) );
|
|
rc = sendto( ReplySock, *( RqPacket + Index ),
|
|
strlen( *( RqPacket + Index ) ),
|
|
0, DestAddr, socklen );
|
|
|
|
if (rc == -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 );
|
|
ret = UPNP_E_SOCKET_WRITE;
|
|
goto end_NewRequestHandler;
|
|
}
|
|
}
|
|
|
|
end_NewRequestHandler:
|
|
shutdown( ReplySock, SD_BOTH );
|
|
UpnpCloseSocket( ReplySock );
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* return 1 if an inet6 @ has been found
|
|
*/
|
|
int extractIPv6address(char *url, char *address)
|
|
{
|
|
int i = 0;
|
|
int j = 0;
|
|
int ret = 0;
|
|
|
|
while (url[i] != '[' && url[i] != '\0') {
|
|
i++;
|
|
}
|
|
if( url[i] == '\0') {
|
|
goto exit_function;
|
|
}
|
|
|
|
/* bracket has been found, we deal with an IPv6 address */
|
|
i++;
|
|
while (url[i] != '\0' && url[i] != ']' ) {
|
|
address[j] = url[i];
|
|
i++;
|
|
j++;
|
|
}
|
|
if (url[i] == '\0') {
|
|
goto exit_function;
|
|
}
|
|
|
|
if (url[i] == ']') {
|
|
address[j] = '\0';
|
|
ret = 1;
|
|
}
|
|
|
|
exit_function:
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* return 1 if the Url contains an ULA or GUA IPv6 address
|
|
* 0 otherwise
|
|
*/
|
|
int isUrlV6UlaGua(char *descdocUrl)
|
|
{
|
|
char address[INET6_ADDRSTRLEN];
|
|
struct in6_addr v6_addr;
|
|
|
|
if (extractIPv6address(descdocUrl, address)) {
|
|
inet_pton(AF_INET6, address, &v6_addr);
|
|
return !IN6_IS_ADDR_LINKLOCAL(&v6_addr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/************************************************************************
|
|
* 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.
|
|
* IN int AddressFamily: Address family of the HTTP request.
|
|
*
|
|
* 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
|
|
*
|
|
***************************************************************************/
|
|
void CreateServicePacket(
|
|
IN int msg_type,
|
|
IN char *nt,
|
|
IN char *usn,
|
|
IN char *location,
|
|
IN int duration,
|
|
OUT char **packet,
|
|
IN int AddressFamily)
|
|
{
|
|
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" "ssc" "ssc" "S" "Xc" "ssc" "sscc",
|
|
HTTP_OK,
|
|
"CACHE-CONTROL: max-age=", duration,
|
|
"EXT:",
|
|
"LOCATION: ", location,
|
|
"OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01",
|
|
"01-NLS: ", gUpnpSdkNLSuuid,
|
|
X_USER_AGENT,
|
|
"ST: ", nt,
|
|
"USN: ", usn);
|
|
if (ret_code != 0) {
|
|
return;
|
|
}
|
|
} else if (msg_type == MSGTYPE_ADVERTISEMENT ||
|
|
msg_type == MSGTYPE_SHUTDOWN) {
|
|
char *host = NULL;
|
|
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. */
|
|
if (AddressFamily == AF_INET) {
|
|
host = SSDP_IP;
|
|
} else {
|
|
if (isUrlV6UlaGua(location)) {
|
|
host = "[" SSDP_IPV6_SITELOCAL "]";
|
|
} else {
|
|
host = "[" SSDP_IPV6_LINKLOCAL "]";
|
|
}
|
|
}
|
|
ret_code = http_MakeMessage(
|
|
&buf, 1, 1,
|
|
"Q" "sssdc" "sdc" "ssc" "ssc" "ssc" "ssc" "ssc" "S" "Xc" "sscc",
|
|
HTTPMETHOD_NOTIFY, "*", (size_t)1,
|
|
"HOST: ", host,
|
|
":", SSDP_PORT,
|
|
"CACHE-CONTROL: max-age=", duration,
|
|
"LOCATION: ", location,
|
|
"OPT: ", "\"http://schemas.upnp.org/upnp/1/0/\"; ns=01",
|
|
"01-NLS: ", gUpnpSdkNLSuuid,
|
|
"NT: ", nt,
|
|
"NTS: ", nts,
|
|
X_USER_AGENT,
|
|
"USN: ", usn );
|
|
if (ret_code != 0) {
|
|
return;
|
|
}
|
|
} else {
|
|
/* unknown msg */
|
|
assert(0);
|
|
}
|
|
|
|
/* return msg */
|
|
*packet = membuffer_detach(&buf);
|
|
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
|
|
***************************************************************************/
|
|
int
|
|
DeviceAdvertisement( IN char *DevType,
|
|
int RootDev,
|
|
char *Udn,
|
|
IN char *Location,
|
|
IN int Duration,
|
|
IN int AddressFamily)
|
|
{
|
|
struct sockaddr_storage __ss;
|
|
struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss;
|
|
struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss;
|
|
|
|
//char Mil_Nt[LINE_SIZE]
|
|
char Mil_Usn[LINE_SIZE];
|
|
char *msgs[3];
|
|
int ret_code = UPNP_E_SUCCESS;
|
|
|
|
UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
|
|
"In function DeviceAdvertisement\n" );
|
|
|
|
memset( &__ss, 0, sizeof(__ss) );
|
|
if( AddressFamily == AF_INET ) {
|
|
DestAddr4->sin_family = AF_INET;
|
|
inet_pton( AF_INET, SSDP_IP, &DestAddr4->sin_addr );
|
|
DestAddr4->sin_port = htons( SSDP_PORT );
|
|
} else if( AddressFamily == AF_INET6 ) {
|
|
DestAddr6->sin6_family = AF_INET6;
|
|
inet_pton(AF_INET6,
|
|
(isUrlV6UlaGua(Location)) ? SSDP_IPV6_SITELOCAL : SSDP_IPV6_LINKLOCAL,
|
|
&DestAddr6->sin6_addr );
|
|
DestAddr6->sin6_port = htons( SSDP_PORT );
|
|
DestAddr6->sin6_scope_id = gIF_INDEX;
|
|
} else {
|
|
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
|
|
"Invalid device address family.\n" );
|
|
}
|
|
|
|
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], AddressFamily );
|
|
}
|
|
// both root and sub-devices need to send these two messages
|
|
//
|
|
|
|
CreateServicePacket( MSGTYPE_ADVERTISEMENT, Udn, Udn,
|
|
Location, Duration, &msgs[1], AddressFamily );
|
|
|
|
sprintf( Mil_Usn, "%s::%s", Udn, DevType );
|
|
CreateServicePacket( MSGTYPE_ADVERTISEMENT, DevType, Mil_Usn,
|
|
Location, Duration, &msgs[2], AddressFamily );
|
|
|
|
// check error
|
|
if( ( RootDev && msgs[0] == NULL ) ||
|
|
msgs[1] == NULL || msgs[2] == NULL ) {
|
|
free( msgs[0] );
|
|
free( msgs[1] );
|
|
free( msgs[2] );
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
// send packets
|
|
if( RootDev ) {
|
|
// send 3 msg types
|
|
ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 3, &msgs[0] );
|
|
} else // sub-device
|
|
{
|
|
// send 2 msg types
|
|
ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 2, &msgs[1] );
|
|
}
|
|
|
|
// free msgs
|
|
free( msgs[0] );
|
|
free( msgs[1] );
|
|
free( msgs[2] );
|
|
|
|
return ret_code;
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : SendReply
|
|
*
|
|
* Parameters:
|
|
* IN struct sockaddr * DestAddr:destination IP address.
|
|
* IN char *DevType: Device type
|
|
* IN int RootDev: 1 means root device 0 means embedded device.
|
|
* IN char * Udn: Device UDN
|
|
* IN char * Location: Location of Device description document.
|
|
* IN int Duration :Life time of this device.
|
|
* IN int ByType:
|
|
*
|
|
* Description:
|
|
* This function creates the reply packet based on the input parameter,
|
|
* and send it to the client addesss given in its input parameter DestAddr.
|
|
*
|
|
* Returns: int
|
|
* UPNP_E_SUCCESS if successful else appropriate error
|
|
***************************************************************************/
|
|
int
|
|
SendReply( IN struct sockaddr *DestAddr,
|
|
IN char *DevType,
|
|
IN int RootDev,
|
|
IN char *Udn,
|
|
IN char *Location,
|
|
IN int Duration,
|
|
IN int ByType )
|
|
{
|
|
int ret_code;
|
|
char *msgs[2];
|
|
int num_msgs;
|
|
char Mil_Usn[LINE_SIZE];
|
|
int i;
|
|
|
|
msgs[0] = NULL;
|
|
msgs[1] = NULL;
|
|
|
|
if( RootDev ) {
|
|
// one msg for root device
|
|
num_msgs = 1;
|
|
|
|
sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn );
|
|
CreateServicePacket( MSGTYPE_REPLY, "upnp:rootdevice",
|
|
Mil_Usn, Location, Duration, &msgs[0], DestAddr->sa_family );
|
|
} else {
|
|
// two msgs for embedded devices
|
|
num_msgs = 1;
|
|
|
|
//NK: FIX for extra response when someone searches by udn
|
|
if( !ByType ) {
|
|
CreateServicePacket( MSGTYPE_REPLY, Udn, Udn, Location,
|
|
Duration, &msgs[0], DestAddr->sa_family );
|
|
} else {
|
|
sprintf( Mil_Usn, "%s::%s", Udn, DevType );
|
|
CreateServicePacket( MSGTYPE_REPLY, DevType, Mil_Usn,
|
|
Location, Duration, &msgs[0], DestAddr->sa_family );
|
|
}
|
|
}
|
|
|
|
// check error
|
|
for( i = 0; i < num_msgs; i++ ) {
|
|
if( msgs[i] == NULL ) {
|
|
free( msgs[0] );
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
}
|
|
|
|
// send msgs
|
|
ret_code = NewRequestHandler( DestAddr, num_msgs, msgs );
|
|
for( i = 0; i < num_msgs; i++ ) {
|
|
if( msgs[i] != NULL )
|
|
free( msgs[i] );
|
|
}
|
|
|
|
return ret_code;
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : DeviceReply
|
|
*
|
|
* Parameters:
|
|
* IN struct sockaddr *DestAddr:destination IP address.
|
|
* IN char *DevType: Device type
|
|
* IN int RootDev: 1 means root device 0 means embedded device.
|
|
* IN char * Udn: Device UDN
|
|
* IN char * Location: Location of Device description document.
|
|
* IN int Duration :Life time of this device.
|
|
* Description:
|
|
* This function creates the reply packet based on the input parameter,
|
|
* and send it to the client address given in its input parameter DestAddr.
|
|
*
|
|
* Returns: int
|
|
* UPNP_E_SUCCESS if successful else appropriate error
|
|
***************************************************************************/
|
|
int
|
|
DeviceReply( IN struct sockaddr *DestAddr,
|
|
IN char *DevType,
|
|
IN int RootDev,
|
|
IN char *Udn,
|
|
IN char *Location,
|
|
IN int Duration)
|
|
{
|
|
char *szReq[3],
|
|
Mil_Nt[LINE_SIZE],
|
|
Mil_Usn[LINE_SIZE];
|
|
int RetVal;
|
|
|
|
szReq[0] = NULL;
|
|
szReq[1] = NULL;
|
|
szReq[2] = NULL;
|
|
|
|
// create 2 or 3 msgs
|
|
|
|
if( RootDev ) {
|
|
// 3 replies for root device
|
|
strcpy( Mil_Nt, "upnp:rootdevice" );
|
|
sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn );
|
|
CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn,
|
|
Location, Duration, &szReq[0], DestAddr->sa_family );
|
|
}
|
|
|
|
sprintf( Mil_Nt, "%s", Udn );
|
|
sprintf( Mil_Usn, "%s", Udn );
|
|
CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn,
|
|
Location, Duration, &szReq[1], DestAddr->sa_family );
|
|
|
|
sprintf( Mil_Nt, "%s", DevType );
|
|
sprintf( Mil_Usn, "%s::%s", Udn, DevType );
|
|
CreateServicePacket( MSGTYPE_REPLY, Mil_Nt, Mil_Usn,
|
|
Location, Duration, &szReq[2], DestAddr->sa_family );
|
|
|
|
// check error
|
|
|
|
if( ( RootDev && szReq[0] == NULL ) ||
|
|
szReq[1] == NULL || szReq[2] == NULL ) {
|
|
free( szReq[0] );
|
|
free( szReq[1] );
|
|
free( szReq[2] );
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
// send replies
|
|
if( RootDev ) {
|
|
RetVal = NewRequestHandler( DestAddr, 3, szReq );
|
|
} else {
|
|
RetVal = NewRequestHandler( DestAddr, 2, &szReq[1] );
|
|
}
|
|
|
|
// free
|
|
free( szReq[0] );
|
|
free( szReq[1] );
|
|
free( szReq[2] );
|
|
|
|
return RetVal;
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : ServiceAdvertisement
|
|
*
|
|
* Parameters:
|
|
* IN char * Udn: Device UDN
|
|
* IN char *ServType: Service Type.
|
|
* IN char * Location: Location of Device description document.
|
|
* IN int Duration :Life time of this device.
|
|
* IN int AddressFamily: Device address family
|
|
* Description:
|
|
* This function creates the advertisement packet based
|
|
* on the input parameter, and send it to the multicast channel.
|
|
*
|
|
* Returns: int
|
|
* UPNP_E_SUCCESS if successful else appropriate error
|
|
***************************************************************************/
|
|
int
|
|
ServiceAdvertisement( IN char *Udn,
|
|
IN char *ServType,
|
|
IN char *Location,
|
|
IN int Duration,
|
|
IN int AddressFamily)
|
|
{
|
|
char Mil_Usn[LINE_SIZE];
|
|
char *szReq[1];
|
|
int RetVal = UPNP_E_SUCCESS;
|
|
struct sockaddr_storage __ss;
|
|
struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss;
|
|
struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss;
|
|
|
|
memset( &__ss, 0, sizeof(__ss) );
|
|
if( AddressFamily == AF_INET ) {
|
|
DestAddr4->sin_family = AF_INET;
|
|
inet_pton( AF_INET, SSDP_IP, &DestAddr4->sin_addr );
|
|
DestAddr4->sin_port = htons( SSDP_PORT );
|
|
} else if( AddressFamily == AF_INET6 ) {
|
|
DestAddr6->sin6_family = AF_INET6;
|
|
inet_pton(AF_INET6,
|
|
(isUrlV6UlaGua(Location)) ? SSDP_IPV6_SITELOCAL : SSDP_IPV6_LINKLOCAL,
|
|
&DestAddr6->sin6_addr );
|
|
DestAddr6->sin6_port = htons( SSDP_PORT );
|
|
DestAddr6->sin6_scope_id = gIF_INDEX;
|
|
} else {
|
|
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
|
|
"Invalid device address family.\n" );
|
|
}
|
|
|
|
sprintf( Mil_Usn, "%s::%s", Udn, ServType );
|
|
|
|
//CreateServiceRequestPacket(1,szReq[0],Mil_Nt,Mil_Usn,
|
|
//Server,Location,Duration);
|
|
CreateServicePacket( MSGTYPE_ADVERTISEMENT, ServType, Mil_Usn,
|
|
Location, Duration, &szReq[0], AddressFamily );
|
|
if( szReq[0] == NULL ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
RetVal = NewRequestHandler( (struct sockaddr*)&__ss, 1, szReq );
|
|
|
|
free( szReq[0] );
|
|
return RetVal;
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : ServiceReply
|
|
*
|
|
* Parameters:
|
|
* IN struct sockaddr *DestAddr:
|
|
* IN char * Udn: Device UDN
|
|
* IN char *ServType: Service Type.
|
|
* IN char * Location: Location of Device description document.
|
|
* IN int Duration :Life time of this device.
|
|
* Description:
|
|
* This function creates the advertisement packet based
|
|
* on the input parameter, and send it to the multicast channel.
|
|
*
|
|
* Returns: int
|
|
* UPNP_E_SUCCESS if successful else appropriate error
|
|
***************************************************************************/
|
|
int
|
|
ServiceReply( IN struct sockaddr *DestAddr,
|
|
IN char *ServType,
|
|
IN char *Udn,
|
|
IN char *Location,
|
|
IN int Duration )
|
|
{
|
|
char Mil_Usn[LINE_SIZE];
|
|
char *szReq[1];
|
|
int RetVal;
|
|
|
|
szReq[0] = NULL;
|
|
|
|
sprintf( Mil_Usn, "%s::%s", Udn, ServType );
|
|
|
|
CreateServicePacket( MSGTYPE_REPLY, ServType, Mil_Usn,
|
|
Location, Duration, &szReq[0], DestAddr->sa_family );
|
|
if( szReq[0] == NULL ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
|
|
RetVal = NewRequestHandler( DestAddr, 1, szReq );
|
|
|
|
free( szReq[0] );
|
|
return RetVal;
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : ServiceShutdown
|
|
*
|
|
* Parameters:
|
|
* IN char * Udn: Device UDN
|
|
* IN char *ServType: Service Type.
|
|
* IN char * Location: Location of Device description document.
|
|
* IN int Duration :Service duration in sec.
|
|
* IN int AddressFamily: Device address family
|
|
* Description:
|
|
* This function creates a HTTP service shutdown request packet
|
|
* and sent it to the multicast channel through RequestHandler.
|
|
*
|
|
* Returns: int
|
|
* UPNP_E_SUCCESS if successful else appropriate error
|
|
***************************************************************************/
|
|
int
|
|
ServiceShutdown( IN char *Udn,
|
|
IN char *ServType,
|
|
IN char *Location,
|
|
IN int Duration,
|
|
IN int AddressFamily)
|
|
{
|
|
char Mil_Usn[LINE_SIZE];
|
|
char *szReq[1];
|
|
struct sockaddr_storage __ss;
|
|
struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss;
|
|
struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss;
|
|
int RetVal = UPNP_E_SUCCESS;
|
|
|
|
memset( &__ss, 0, sizeof(__ss) );
|
|
if( AddressFamily == AF_INET ) {
|
|
DestAddr4->sin_family = AF_INET;
|
|
inet_pton( AF_INET, SSDP_IP, &DestAddr4->sin_addr );
|
|
DestAddr4->sin_port = htons( SSDP_PORT );
|
|
} else if( AddressFamily == AF_INET6 ) {
|
|
DestAddr6->sin6_family = AF_INET6;
|
|
inet_pton(AF_INET6,
|
|
(isUrlV6UlaGua(Location)) ? SSDP_IPV6_SITELOCAL : SSDP_IPV6_LINKLOCAL,
|
|
&DestAddr6->sin6_addr );
|
|
DestAddr6->sin6_port = htons( SSDP_PORT );
|
|
DestAddr6->sin6_scope_id = gIF_INDEX;
|
|
} else {
|
|
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
|
|
"Invalid device address family.\n" );
|
|
}
|
|
|
|
//sprintf(Mil_Nt,"%s",ServType);
|
|
sprintf( Mil_Usn, "%s::%s", Udn, ServType );
|
|
//CreateServiceRequestPacket(0,szReq[0],Mil_Nt,Mil_Usn,
|
|
//Server,Location,Duration);
|
|
CreateServicePacket( MSGTYPE_SHUTDOWN, ServType, Mil_Usn,
|
|
Location, Duration, &szReq[0], AddressFamily );
|
|
if( szReq[0] == NULL ) {
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
RetVal = NewRequestHandler( (struct sockaddr*)&__ss, 1, szReq );
|
|
|
|
free( szReq[0] );
|
|
return RetVal;
|
|
}
|
|
|
|
/************************************************************************
|
|
* Function : DeviceShutdown
|
|
*
|
|
* Parameters:
|
|
* IN char *DevType: Device Type.
|
|
* IN int RootDev:1 means root device.
|
|
* IN char * Udn: Device UDN
|
|
* IN char * Location: Location URL
|
|
* IN int Duration :Device duration in sec.
|
|
* IN int AddressFamily: Device address family.
|
|
*
|
|
* Description:
|
|
* This function creates a HTTP device shutdown request packet
|
|
* and sent it to the multicast channel through RequestHandler.
|
|
*
|
|
* Returns: int
|
|
* UPNP_E_SUCCESS if successful else appropriate error
|
|
***************************************************************************/
|
|
int
|
|
DeviceShutdown( IN char *DevType,
|
|
IN int RootDev,
|
|
IN char *Udn,
|
|
IN char *_Server,
|
|
IN char *Location,
|
|
IN int Duration,
|
|
IN int AddressFamily)
|
|
{
|
|
struct sockaddr_storage __ss;
|
|
struct sockaddr_in* DestAddr4 = (struct sockaddr_in*)&__ss;
|
|
struct sockaddr_in6* DestAddr6 = (struct sockaddr_in6*)&__ss;
|
|
char *msgs[3];
|
|
char Mil_Usn[LINE_SIZE];
|
|
int ret_code = UPNP_E_SUCCESS;
|
|
|
|
msgs[0] = NULL;
|
|
msgs[1] = NULL;
|
|
msgs[2] = NULL;
|
|
|
|
memset( &__ss, 0, sizeof(__ss) );
|
|
if( AddressFamily == AF_INET ) {
|
|
DestAddr4->sin_family = AF_INET;
|
|
inet_pton( AF_INET, SSDP_IP, &DestAddr4->sin_addr );
|
|
DestAddr4->sin_port = htons( SSDP_PORT );
|
|
} else if( AddressFamily == AF_INET6 ) {
|
|
DestAddr6->sin6_family = AF_INET6;
|
|
inet_pton(AF_INET6,
|
|
(isUrlV6UlaGua(Location)) ? SSDP_IPV6_SITELOCAL : SSDP_IPV6_LINKLOCAL,
|
|
&DestAddr6->sin6_addr );
|
|
DestAddr6->sin6_port = htons( SSDP_PORT );
|
|
DestAddr6->sin6_scope_id = gIF_INDEX;
|
|
} else {
|
|
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
|
|
"Invalid device address family.\n" );
|
|
}
|
|
|
|
// root device has one extra msg
|
|
if( RootDev ) {
|
|
sprintf( Mil_Usn, "%s::upnp:rootdevice", Udn );
|
|
CreateServicePacket( MSGTYPE_SHUTDOWN, "upnp:rootdevice",
|
|
Mil_Usn, Location, Duration, &msgs[0], AddressFamily );
|
|
}
|
|
|
|
UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
|
|
"In function DeviceShutdown\n" );
|
|
// both root and sub-devices need to send these two messages
|
|
CreateServicePacket( MSGTYPE_SHUTDOWN, Udn, Udn,
|
|
Location, Duration, &msgs[1], AddressFamily );
|
|
|
|
sprintf( Mil_Usn, "%s::%s", Udn, DevType );
|
|
CreateServicePacket( MSGTYPE_SHUTDOWN, DevType, Mil_Usn,
|
|
Location, Duration, &msgs[2], AddressFamily );
|
|
|
|
// check error
|
|
if( ( RootDev && msgs[0] == NULL ) ||
|
|
msgs[1] == NULL || msgs[2] == NULL ) {
|
|
free( msgs[0] );
|
|
free( msgs[1] );
|
|
free( msgs[2] );
|
|
return UPNP_E_OUTOF_MEMORY;
|
|
}
|
|
// send packets
|
|
if( RootDev ) {
|
|
// send 3 msg types
|
|
ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 3, &msgs[0] );
|
|
} else // sub-device
|
|
{
|
|
// send 2 msg types
|
|
ret_code = NewRequestHandler( (struct sockaddr*)&__ss, 2, &msgs[1] );
|
|
}
|
|
|
|
// free msgs
|
|
free( msgs[0] );
|
|
free( msgs[1] );
|
|
free( msgs[2] );
|
|
|
|
return ret_code;
|
|
}
|
|
|
|
#endif // EXCLUDE_SSDP
|
|
#endif // INCLUDE_DEVICE_APIS
|
|
|