libupnp/upnp/src/ssdp/ssdp_device.c
Fabrice Fontaine 4b82bb7baf UPnP Low Power support
Adding two new functions (UpnpSendAdvertisementLowPower and
UpnpUnRegisterRootDeviceLowPower) which can be used to specify values
for the three SSDP headers defined by UPnP Low Power. Those headers are
Powerstate, SleepPeriod and RegistrationState.
(cherry picked from commit 98e4f938d63226bcb623dd7d9cd1855482318534)
2011-11-04 20:34:00 -02:00

793 lines
23 KiB
C

/**************************************************************************
*
* Copyright (c) 2000-2003 Intel Corporation
* All rights reserved.
* Copyright (C) 2011 France Telecom 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.
*
**************************************************************************/
/*!
* \addtogroup SSDPlib
*
* @{
*
* \file
*/
#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
void *advertiseAndReplyThread(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;
}
#ifdef INCLUDE_DEVICE_APIS
void ssdp_handle_device_request(http_message_t *hmsg, struct sockaddr_storage *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)
/* bad or missing hdr. */
return;
/* 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);
/* restore. */
hdr_value.buf[hdr_value.length] = save_char;
if (ret_code == -1)
/* bad ST header. */
return;
HandleLock();
/* device info. */
if (GetDeviceHandleInfo(dest_addr->ss_family,
&handle, &dev_info) != HND_DEVICE) {
HandleUnlock();
/* no info found. */
return;
}
maxAge = dev_info->MaxAge;
HandleUnlock();
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
* within 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
/*!
* \brief Works as a request handler which passes the HTTP request string
* to multicast channel.
*
* \return 1 if successful else appropriate error.
*/
static int NewRequestHandler(
/*! [in] Ip address, to send the reply. */
struct sockaddr *DestAddr,
/*! [in] Number of packet to be sent. */
int NumPacket,
/*! [in] . */
char **RqPacket)
{
char errorBuffer[ERROR_BUFFER_LEN];
SOCKET ReplySock;
socklen_t socklen = sizeof(struct sockaddr_storage);
int Index;
unsigned long replyAddr = inet_addr(gIF_IPV4);
/* a/c to UPNP Spec */
int ttl = 4;
int hops = 1;
char buf_ntop[64];
int ret = UPNP_E_SUCCESS;
ReplySock = socket(DestAddr->sa_family, SOCK_DGRAM, 0);
if (ReplySock == INVALID_SOCKET) {
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++) {
ssize_t 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;
}
/*!
* \brief
*
* \return 1 if an inet6 @ has been found.
*/
static 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;
}
/*!
* \brief
*
* \return 1 if the Url contains an ULA or GUA IPv6 address, 0 otherwise.
*/
static 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;
}
/*!
* \brief Creates a HTTP request packet. Depending on the input parameter,
* it either creates a service advertisement request or service shutdown
* request etc.
*/
static void CreateServicePacket(
/*! [in] type of the message (Search Reply, Advertisement
* or Shutdown). */
int msg_type,
/*! [in] ssdp type. */
const char *nt,
/*! [in] unique service name ( go in the HTTP Header). */
char *usn,
/*! [in] Location URL. */
char *location,
/*! [in] Service duration in sec. */
int duration,
/*! [out] Output buffer filled with HTTP statement. */
char **packet,
/*! [in] Address family of the HTTP request. */
int AddressFamily,
/*! [in] PowerState as defined by UPnP Low Power. */
int PowerState,
/*! [in] SleepPeriod as defined by UPnP Low Power. */
int SleepPeriod,
/*! [in] RegistrationState as defined by UPnP Low Power. */
int RegistrationState)
{
int ret_code;
const 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) {
if (PowerState > 0) {
ret_code = http_MakeMessage(&buf, 1, 1,
"R" "sdc" "D" "sc" "ssc" "ssc" "ssc"
"S" "Xc" "ssc" "ssc"
"sdc" "sdc" "sdcc", 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, "Powerstate: ", PowerState,
"SleepPeriod: ", SleepPeriod,
"RegistrationState: ",
RegistrationState);
} else {
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) {
const 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 "]";
}
if (PowerState > 0) {
ret_code = http_MakeMessage(&buf, 1, 1,
"Q" "sssdc" "sdc" "ssc" "ssc" "ssc"
"ssc" "ssc" "S" "Xc" "ssc"
"sdc" "sdc" "sdcc",
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, "Powerstate: ",
PowerState, "SleepPeriod: ",
SleepPeriod, "RegistrationState: ",
RegistrationState);
} else {
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)
return;
} else
/* unknown msg */
assert(0);
/* return msg */
*packet = membuffer_detach(&buf);
membuffer_destroy(&buf);
return;
}
int DeviceAdvertisement(char *DevType, int RootDev, char *Udn, char *Location,
int Duration, int AddressFamily, int PowerState,
int SleepPeriod, int RegistrationState)
{
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, PowerState, SleepPeriod,
RegistrationState);
}
/* both root and sub-devices need to send these two messages */
CreateServicePacket(MSGTYPE_ADVERTISEMENT, Udn, Udn,
Location, Duration, &msgs[1], AddressFamily,
PowerState, SleepPeriod, RegistrationState);
sprintf(Mil_Usn, "%s::%s", Udn, DevType);
CreateServicePacket(MSGTYPE_ADVERTISEMENT, DevType, Mil_Usn,
Location, Duration, &msgs[2], AddressFamily,
PowerState, SleepPeriod, RegistrationState);
/* 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;
}
int SendReply(struct sockaddr *DestAddr, char *DevType, int RootDev,
char *Udn, char *Location, int Duration, int ByType,
int PowerState, int SleepPeriod, int RegistrationState)
{
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, PowerState,
SleepPeriod, RegistrationState);
} 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, PowerState,
SleepPeriod, RegistrationState);
} else {
sprintf(Mil_Usn, "%s::%s", Udn, DevType);
CreateServicePacket(MSGTYPE_REPLY, DevType, Mil_Usn,
Location, Duration, &msgs[0],
DestAddr->sa_family, PowerState,
SleepPeriod, RegistrationState);
}
}
/* 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;
}
int DeviceReply(struct sockaddr *DestAddr, char *DevType, int RootDev,
char *Udn, char *Location, int Duration, int PowerState,
int SleepPeriod, int RegistrationState)
{
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, PowerState,
SleepPeriod, RegistrationState);
}
sprintf(Mil_Nt, "%s", Udn);
sprintf(Mil_Usn, "%s", Udn);
CreateServicePacket(MSGTYPE_REPLY, Mil_Nt, Mil_Usn,
Location, Duration, &szReq[1], DestAddr->sa_family,
PowerState, SleepPeriod, RegistrationState);
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,
PowerState, SleepPeriod, RegistrationState);
/* 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;
}
int ServiceAdvertisement(char *Udn, char *ServType, char *Location,
int Duration, int AddressFamily, int PowerState,
int SleepPeriod, int RegistrationState)
{
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,
PowerState, SleepPeriod, RegistrationState);
if (szReq[0] == NULL) {
return UPNP_E_OUTOF_MEMORY;
}
RetVal = NewRequestHandler((struct sockaddr *)&__ss, 1, szReq);
free(szReq[0]);
return RetVal;
}
int ServiceReply(struct sockaddr *DestAddr, char *ServType, char *Udn,
char *Location, int Duration, int PowerState, int SleepPeriod,
int RegistrationState)
{
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,
PowerState, SleepPeriod, RegistrationState);
if (szReq[0] == NULL)
return UPNP_E_OUTOF_MEMORY;
RetVal = NewRequestHandler(DestAddr, 1, szReq);
free(szReq[0]);
return RetVal;
}
int ServiceShutdown(char *Udn, char *ServType, char *Location, int Duration,
int AddressFamily, int PowerState, int SleepPeriod,
int RegistrationState)
{
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,
PowerState, SleepPeriod, RegistrationState);
if (szReq[0] == NULL)
return UPNP_E_OUTOF_MEMORY;
RetVal = NewRequestHandler((struct sockaddr *)&__ss, 1, szReq);
free(szReq[0]);
return RetVal;
}
int DeviceShutdown(char *DevType, int RootDev, char *Udn, char *_Server,
char *Location, int Duration, int AddressFamily,
int PowerState, int SleepPeriod, int RegistrationState)
{
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, PowerState, SleepPeriod,
RegistrationState);
}
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,
PowerState, SleepPeriod, RegistrationState);
sprintf(Mil_Usn, "%s::%s", Udn, DevType);
CreateServicePacket(MSGTYPE_SHUTDOWN, DevType, Mil_Usn,
Location, Duration, &msgs[2], AddressFamily,
PowerState, SleepPeriod, RegistrationState);
/* 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;
_Server = _Server;
}
#endif /* EXCLUDE_SSDP */
#endif /* INCLUDE_DEVICE_APIS */
/* @} SSDPlib */