Files
libupnp/upnp/src/ssdp/ssdp_device.c
Fabrice Fontaine c65ec8a720 Make multiple SSDP advertisements faster.
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.
2010-11-05 23:52:17 -02:00

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