* upnp/src/ssdp/ssdp_device.c: Fix for IPV6 ULA/GUA issues.

* upnp/src/ssdp/ssdp_ctrlpt.c: Fix for IPV6 ULA/GUA issues.
* upnp/src/ssdp/ssdp_server.c: Fix for IPV6 ULA/GUA issues.

Patch submitted by Ronan Menard.



git-svn-id: https://pupnp.svn.sourceforge.net/svnroot/pupnp/branches/branch-1.6.x@578 119443c7-1b9e-41f8-b6fc-b9c35fce742c
This commit is contained in:
Marcelo Roberto Jimenez 2010-08-22 01:34:35 +00:00
parent a362d06dff
commit 5a2cc884c1
4 changed files with 577 additions and 275 deletions

View File

@ -2,6 +2,13 @@
Version 1.6.7
*******************************************************************************
2010-08-21 Marcelo Jimenez <mroberto(at)users.sourceforge.net>
* upnp/src/ssdp/ssdp_device.c: Fix for IPV6 ULA/GUA issues.
* upnp/src/ssdp/ssdp_ctrlpt.c: Fix for IPV6 ULA/GUA issues.
* upnp/src/ssdp/ssdp_server.c: Fix for IPV6 ULA/GUA issues.
Patch submitted by Ronan Menard.
2010-08-21 Marcelo Jimenez <mroberto(at)users.sourceforge.net>
* upnp/src/genlib/miniserver/miniserver.c: Fix for IPV6 ULA/GUA issues.

View File

@ -387,6 +387,35 @@ CreateClientRequestPacket( IN char *RqstBuf,
strcat( RqstBuf, "\r\n" );
}
static void CreateClientRequestPacketUlaGua(
IN char *RqstBuf,
IN int Mx,
IN char *SearchTarget,
IN int AddressFamily)
{
char TempBuf[COMMAND_LEN];
strcpy(RqstBuf, "M-SEARCH * HTTP/1.1\r\n");
if (AddressFamily == AF_INET) {
sprintf(TempBuf, "HOST: %s:%d\r\n", SSDP_IP, SSDP_PORT);
} else if (AddressFamily == AF_INET6) {
sprintf(TempBuf, "HOST: [%s]:%d\r\n", SSDP_IPV6_SITELOCAL, SSDP_PORT);
}
strcat(RqstBuf, TempBuf);
strcat(RqstBuf, "MAN: \"ssdp:discover\"\r\n");
if (Mx > 0) {
sprintf(TempBuf, "MX: %d\r\n", Mx);
strcat(RqstBuf, TempBuf);
}
if (SearchTarget) {
sprintf(TempBuf, "ST: %s\r\n", SearchTarget);
strcat(RqstBuf, TempBuf);
}
strcat(RqstBuf, "\r\n");
}
/************************************************************************
* Function : searchExpired
*
@ -475,136 +504,152 @@ searchExpired( void *arg )
* Returns: int
* 1 if successful else appropriate error
***************************************************************************/
int
SearchByTarget( IN int Mx,
IN char *St,
IN void *Cookie )
int SearchByTarget(
IN int Mx,
IN char *St,
IN void *Cookie)
{
char errorBuffer[ERROR_BUFFER_LEN];
int socklen = sizeof( struct sockaddr_storage );
int *id = NULL;
int ret = 0;
char ReqBufv4[BUFSIZE];
char ReqBufv6[BUFSIZE];
struct sockaddr_storage __ss_v4;
struct sockaddr_storage __ss_v6;
struct sockaddr_in* destAddr4 = (struct sockaddr_in*)&__ss_v4;
struct sockaddr_in6* destAddr6 = (struct sockaddr_in6*)&__ss_v6;
fd_set wrSet;
SsdpSearchArg *newArg = NULL;
int timeTillRead = 0;
int handle;
struct Handle_Info *ctrlpt_info = NULL;
enum SsdpSearchType requestType;
unsigned long addrv4 = inet_addr( gIF_IPV4 );
int max_fd = 0;
char errorBuffer[ERROR_BUFFER_LEN];
int socklen = sizeof( struct sockaddr_storage );
int *id = NULL;
int ret = 0;
char ReqBufv4[BUFSIZE];
char ReqBufv6[BUFSIZE];
char ReqBufv6UlaGua[BUFSIZE];
struct sockaddr_storage __ss_v4;
struct sockaddr_storage __ss_v6;
struct sockaddr_in* destAddr4 = (struct sockaddr_in*)&__ss_v4;
struct sockaddr_in6* destAddr6 = (struct sockaddr_in6*)&__ss_v6;
fd_set wrSet;
SsdpSearchArg *newArg = NULL;
int timeTillRead = 0;
int handle;
struct Handle_Info *ctrlpt_info = NULL;
enum SsdpSearchType requestType;
unsigned long addrv4 = inet_addr(gIF_IPV4);
int max_fd = 0;
//ThreadData *ThData;
ThreadPoolJob job;
//ThreadData *ThData;
ThreadPoolJob job;
requestType = ssdp_request_type1( St );
if( requestType == SSDP_SERROR ) {
return UPNP_E_INVALID_PARAM;
}
requestType = ssdp_request_type1(St);
if (requestType == SSDP_SERROR) {
return UPNP_E_INVALID_PARAM;
}
UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, "Inside SearchByTarget\n");
UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__, "Inside SearchByTarget\n");
timeTillRead = Mx;
timeTillRead = Mx;
if (timeTillRead < MIN_SEARCH_TIME) {
timeTillRead = MIN_SEARCH_TIME;
} else if (timeTillRead > MAX_SEARCH_TIME) {
timeTillRead = MAX_SEARCH_TIME;
}
if( timeTillRead < MIN_SEARCH_TIME ) {
timeTillRead = MIN_SEARCH_TIME;
} else if( timeTillRead > MAX_SEARCH_TIME ) {
timeTillRead = MAX_SEARCH_TIME;
}
CreateClientRequestPacket(ReqBufv4, timeTillRead, St, AF_INET);
CreateClientRequestPacket(ReqBufv6, timeTillRead, St, AF_INET6);
CreateClientRequestPacketUlaGua(ReqBufv6UlaGua, timeTillRead, St, AF_INET6);
CreateClientRequestPacket( ReqBufv4, timeTillRead, St, AF_INET );
CreateClientRequestPacket( ReqBufv6, timeTillRead, St, AF_INET6 );
memset(&__ss_v4, 0, sizeof(__ss_v4));
destAddr4->sin_family = AF_INET;
inet_pton(AF_INET, SSDP_IP, &destAddr4->sin_addr);
destAddr4->sin_port = htons(SSDP_PORT);
memset( &__ss_v4, 0, sizeof( __ss_v4 ) );
destAddr4->sin_family = AF_INET;
inet_pton( AF_INET, SSDP_IP, &destAddr4->sin_addr );
destAddr4->sin_port = htons( SSDP_PORT );
memset(&__ss_v6, 0, sizeof(__ss_v6));
destAddr6->sin6_family = AF_INET6;
inet_pton(AF_INET6, SSDP_IPV6_SITELOCAL, &destAddr6->sin6_addr);
destAddr6->sin6_port = htons(SSDP_PORT);
destAddr6->sin6_scope_id = gIF_INDEX;
memset( &__ss_v6, 0, sizeof( __ss_v6 ) );
destAddr6->sin6_family = AF_INET6;
inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &destAddr6->sin6_addr );
destAddr6->sin6_port = htons( SSDP_PORT );
destAddr6->sin6_scope_id = gIF_INDEX;
/* add search criteria to list */
HandleLock();
if (GetClientHandleInfo(&handle, &ctrlpt_info) != HND_CLIENT) {
HandleUnlock();
// add search criteria to list
HandleLock();
if( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) {
HandleUnlock();
return UPNP_E_INTERNAL_ERROR;
}
return UPNP_E_INTERNAL_ERROR;
}
newArg = ( SsdpSearchArg * ) malloc( sizeof( SsdpSearchArg ) );
newArg->searchTarget = strdup( St );
newArg->cookie = Cookie;
newArg->requestType = requestType;
newArg = (SsdpSearchArg *)malloc(sizeof(SsdpSearchArg));
newArg->searchTarget = strdup(St);
newArg->cookie = Cookie;
newArg->requestType = requestType;
id = ( int * )malloc( sizeof( int ) );
TPJobInit( &job, ( start_routine ) searchExpired, id );
TPJobSetPriority( &job, MED_PRIORITY );
TPJobSetFreeFunction( &job, ( free_routine ) free );
id = (int *)malloc(sizeof(int));
TPJobInit(&job, (start_routine)searchExpired, id);
TPJobSetPriority(&job, MED_PRIORITY);
TPJobSetFreeFunction(&job, (free_routine)free);
// Schedule a timeout event to remove search Arg
TimerThreadSchedule( &gTimerThread, timeTillRead,
REL_SEC, &job, SHORT_TERM, id );
newArg->timeoutEventId = ( *id );
/* Schedule a timeout event to remove search Arg */
TimerThreadSchedule(&gTimerThread, timeTillRead,
REL_SEC, &job, SHORT_TERM, id);
newArg->timeoutEventId = *id;
ListAddTail( &ctrlpt_info->SsdpSearchList, newArg );
HandleUnlock();
ListAddTail(&ctrlpt_info->SsdpSearchList, newArg);
HandleUnlock();
/* End of lock */
FD_ZERO( &wrSet );
if( gSsdpReqSocket4 != INVALID_SOCKET ) {
setsockopt( gSsdpReqSocket4, IPPROTO_IP, IP_MULTICAST_IF,
(char *)&addrv4, sizeof (addrv4) );
FD_SET( gSsdpReqSocket4, &wrSet );
max_fd = max(max_fd, gSsdpReqSocket4);
}
if( gSsdpReqSocket6 != INVALID_SOCKET ) {
setsockopt( gSsdpReqSocket6, IPPROTO_IPV6, IPV6_MULTICAST_IF,
(char *)&gIF_INDEX, sizeof(gIF_INDEX) );
FD_SET( gSsdpReqSocket6, &wrSet );
max_fd = max(max_fd, gSsdpReqSocket6);
}
FD_ZERO(&wrSet);
if (gSsdpReqSocket4 != INVALID_SOCKET) {
setsockopt(gSsdpReqSocket4, IPPROTO_IP, IP_MULTICAST_IF,
(char *)&addrv4, sizeof (addrv4));
FD_SET(gSsdpReqSocket4, &wrSet);
max_fd = max(max_fd, gSsdpReqSocket4);
}
if (gSsdpReqSocket6 != INVALID_SOCKET) {
setsockopt(gSsdpReqSocket6, IPPROTO_IPV6, IPV6_MULTICAST_IF,
(char *)&gIF_INDEX, sizeof (gIF_INDEX));
FD_SET(gSsdpReqSocket6, &wrSet);
max_fd = max(max_fd, gSsdpReqSocket6);
}
ret = select( max_fd + 1, NULL, &wrSet, NULL, NULL );
if( ret == -1 ) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
"SSDP_LIB: Error in select(): %s\n",
errorBuffer );
shutdown( gSsdpReqSocket4, SD_BOTH );
UpnpCloseSocket( gSsdpReqSocket4 );
shutdown( gSsdpReqSocket6, SD_BOTH );
UpnpCloseSocket( gSsdpReqSocket6 );
ret = select(max_fd + 1, NULL, &wrSet, NULL, NULL);
if (ret == -1) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
"SSDP_LIB: Error in select(): %s\n",
errorBuffer);
shutdown(gSsdpReqSocket4, SD_BOTH);
UpnpCloseSocket(gSsdpReqSocket4);
shutdown(gSsdpReqSocket6, SD_BOTH);
UpnpCloseSocket(gSsdpReqSocket6);
return UPNP_E_INTERNAL_ERROR;
}
if( gSsdpReqSocket6 != INVALID_SOCKET &&
FD_ISSET( gSsdpReqSocket6, &wrSet ) ) {
int NumCopy = 0;
while( NumCopy < NUM_SSDP_COPY ) {
sendto( gSsdpReqSocket6, ReqBufv6, strlen( ReqBufv6 ), 0,
(struct sockaddr *)&__ss_v6, socklen );
NumCopy++;
imillisleep( SSDP_PAUSE );
}
}
if( gSsdpReqSocket4 != INVALID_SOCKET &&
FD_ISSET( gSsdpReqSocket4, &wrSet ) ) {
int NumCopy = 0;
while( NumCopy < NUM_SSDP_COPY ) {
sendto( gSsdpReqSocket4, ReqBufv4, strlen( ReqBufv4 ), 0,
(struct sockaddr *)&__ss_v4, socklen );
NumCopy++;
imillisleep( SSDP_PAUSE );
}
}
return UPNP_E_INTERNAL_ERROR;
}
if (gSsdpReqSocket6 != INVALID_SOCKET &&
FD_ISSET(gSsdpReqSocket6, &wrSet)) {
int NumCopy = 0;
return 1;
while (NumCopy < NUM_SSDP_COPY) {
sendto(gSsdpReqSocket6,
ReqBufv6UlaGua, strlen(ReqBufv6UlaGua), 0,
(struct sockaddr *)&__ss_v6, socklen);
NumCopy++;
imillisleep(SSDP_PAUSE);
}
NumCopy = 0;
inet_pton(AF_INET6, SSDP_IPV6_LINKLOCAL, &destAddr6->sin6_addr);
while (NumCopy < NUM_SSDP_COPY) {
sendto(gSsdpReqSocket6,
ReqBufv6, strlen(ReqBufv6), 0,
(struct sockaddr *)&__ss_v6, socklen);
NumCopy++;
imillisleep(SSDP_PAUSE);
}
}
if (gSsdpReqSocket4 != INVALID_SOCKET &&
FD_ISSET(gSsdpReqSocket4, &wrSet)) {
int NumCopy = 0;
while (NumCopy < NUM_SSDP_COPY) {
sendto(gSsdpReqSocket4,
ReqBufv4, strlen(ReqBufv4), 0,
(struct sockaddr *)&__ss_v4, socklen);
NumCopy++;
imillisleep(SSDP_PAUSE);
}
}
return 1;
}
#endif // EXCLUDE_SSDP

View File

@ -291,6 +291,61 @@ NewRequestHandler( IN struct sockaddr *DestAddr,
return UPNP_E_SUCCESS;
}
/**
* 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
*
@ -312,85 +367,92 @@ NewRequestHandler( IN struct sockaddr *DestAddr,
* 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)
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;
int ret_code;
char *nts;
membuffer buf;
//Notf=0 means service shutdown,
//Notf=1 means service advertisement, Notf =2 means reply
/* Notf == 0 means service shutdown,
* Notf == 1 means service advertisement,
* Notf == 2 means reply */
membuffer_init(&buf);
buf.size_inc = 30;
*packet = NULL;
membuffer_init( &buf );
buf.size_inc = 30;
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) {
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. */
char *host = NULL;
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);
}
*packet = NULL;
/* return msg */
*packet = membuffer_detach(&buf);
membuffer_destroy(&buf);
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 ) {
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" "ssc" "ssc" "S" "Xc" "sscc",
HTTPMETHOD_NOTIFY, "*", (size_t)1,
"HOST: ",
(AddressFamily==AF_INET) ? SSDP_IP : "[" SSDP_IPV6_LINKLOCAL "]",
":", 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 {
assert( 0 ); // unknown msg
}
*packet = membuffer_detach( &buf ); // return msg
membuffer_destroy( &buf );
return;
return;
}
/************************************************************************
* Function : DeviceAdvertisement
*
@ -436,7 +498,9 @@ DeviceAdvertisement( IN char *DevType,
DestAddr4->sin_port = htons( SSDP_PORT );
} else if( AddressFamily == AF_INET6 ) {
DestAddr6->sin6_family = AF_INET6;
inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &DestAddr6->sin6_addr );
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 {
@ -683,7 +747,9 @@ ServiceAdvertisement( IN char *Udn,
DestAddr4->sin_port = htons( SSDP_PORT );
} else if( AddressFamily == AF_INET6 ) {
DestAddr6->sin6_family = AF_INET6;
inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &DestAddr6->sin6_addr );
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 {
@ -787,7 +853,9 @@ ServiceShutdown( IN char *Udn,
DestAddr4->sin_port = htons( SSDP_PORT );
} else if( AddressFamily == AF_INET6 ) {
DestAddr6->sin6_family = AF_INET6;
inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &DestAddr6->sin6_addr );
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 {
@ -855,7 +923,9 @@ DeviceShutdown( IN char *DevType,
DestAddr4->sin_port = htons( SSDP_PORT );
} else if( AddressFamily == AF_INET6 ) {
DestAddr6->sin6_family = AF_INET6;
inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &DestAddr6->sin6_addr );
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 {

View File

@ -56,6 +56,7 @@ CLIENTONLY( SOCKET gSsdpReqSocket6 = INVALID_SOCKET; )
void RequestHandler();
int create_ssdp_sock_v4( SOCKET* ssdpSock );
int create_ssdp_sock_v6( SOCKET* ssdpSock );
int create_ssdp_sock_v6_ula_gua( SOCKET* ssdpSock );
#if INCLUDE_CLIENT_APIS
int create_ssdp_sock_reqv4( SOCKET* ssdpReqSock );
int create_ssdp_sock_reqv6( SOCKET* ssdpReqSock );
@ -260,15 +261,31 @@ int AdvertiseAndReply(
}
case SSDP_DEVICETYPE: {
if (!strncasecmp(DeviceType, devType, strlen(DeviceType))) {
/* (char *) support for atoi */
/* TODO: Patch pending. */
#if 0
if (atoi(&DeviceType[strlen(DeviceType)-1]) <= atoi(&devType[strlen(devType)-1])) {
/* the requested version is lower than the device version
* must reply with the lower version number */
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"DeviceType=%s and search devType=%s MATCH\n",
devType, DeviceType);
SendReply(DestAddr, DeviceType, 0, UDNstr, SInfo->DescURL, defaultExp, 1);
} else {
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"DeviceType=%s and search devType=%s"
" DID NOT MATCH\n",
devType, DeviceType);
}
#else
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"DeviceType=%s and search devType=%s MATCH\n",
devType, DeviceType);
SendReply(DestAddr, devType, 0, UDNstr,
SInfo->DescURL, defaultExp, 1);
SendReply(DestAddr, devType, 0, UDNstr, SInfo->DescURL, defaultExp, 1);
#endif
} else {
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"DeviceType=%s and search devType=%s"
" DID NOT MATCH\n",
"DeviceType=%s and search devType=%s DID NOT MATCH\n",
devType, DeviceType);
}
break;
@ -346,9 +363,33 @@ int AdvertiseAndReply(
break;
case SSDP_SERVICE:
if (ServiceType) {
/* TODO: Patch pending. */
#if 0
if (!strncasecmp(ServiceType, servType, strlen(ServiceType) - 2)) {
/*ServiceReply(DestAddr, servType, UDNstr, SInfo->DescURL, defaultExp);*/
if (atoi(&ServiceType[strlen(ServiceType)-1]) <= atoi(&servType[strlen(servType)-1])) {
/* the requested version is lower than the service version
* must reply with the lower version number */
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"ServiceType=%s and search servType=%s MATCH\n",
ServiceType, servType);
SendReply(DestAddr, ServiceType, 0, UDNstr, SInfo->DescURL, defaultExp, 1);
} else {
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"ServiceType=%s and search servType=%s DID NOT MATCH\n",
ServiceType, servType);
}
#else
if (!strncasecmp(ServiceType, servType, strlen(ServiceType))) {
ServiceReply(DestAddr, servType,
UDNstr, SInfo->DescURL, defaultExp);
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"ServiceType=%s and search servType=%s MATCH\n",
ServiceType, servType);
ServiceReply(DestAddr, servType, UDNstr, SInfo->DescURL, defaultExp);
#endif
} else {
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"ServiceType=%s and search servType=%s DID NOT MATCH\n",
ServiceType, servType);
}
}
break;
@ -614,35 +655,38 @@ free_ssdp_event_handler_data( void *the_data )
* Returns: xboolean
* returns TRUE if msg is valid else FALSE
***************************************************************************/
static UPNP_INLINE xboolean
valid_ssdp_msg( IN http_message_t * hmsg )
static UPNP_INLINE xboolean valid_ssdp_msg(IN http_message_t *hmsg)
{
memptr hdr_value;
// check for valid methods - NOTIFY or M-SEARCH
if( hmsg->method != HTTPMETHOD_NOTIFY &&
hmsg->method != HTTPMETHOD_MSEARCH
&& hmsg->request_method != HTTPMETHOD_MSEARCH ) {
return FALSE;
}
if( hmsg->request_method != HTTPMETHOD_MSEARCH ) {
// check PATH == *
if( hmsg->uri.type != RELATIVE ||
strncmp( "*", hmsg->uri.pathquery.buff,
hmsg->uri.pathquery.size ) != 0 ) {
return FALSE;
}
// check HOST header
if( ( httpmsg_find_hdr( hmsg, HDR_HOST, &hdr_value ) == NULL ) ||
( ( memptr_cmp( &hdr_value, "239.255.255.250:1900" ) != 0 ) &&
( memptr_cmp( &hdr_value, "[FF02::C]:1900" ) != 0 ) )
) {
UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__,
"Invalid HOST header from SSDP message\n" );
return FALSE;
}
}
return TRUE; // passed quick check
/* check for valid methods - NOTIFY or M-SEARCH */
if (hmsg->method != HTTPMETHOD_NOTIFY &&
hmsg->method != HTTPMETHOD_MSEARCH &&
hmsg->request_method != HTTPMETHOD_MSEARCH) {
return FALSE;
}
if (hmsg->request_method != HTTPMETHOD_MSEARCH) {
/* check PATH == "*" */
if (hmsg->uri.type != RELATIVE ||
strncmp("*", hmsg->uri.pathquery.buff, hmsg->uri.pathquery.size) != 0) {
return FALSE;
}
/* check HOST header */
if (httpmsg_find_hdr(hmsg, HDR_HOST, &hdr_value) == NULL ||
(memptr_cmp(&hdr_value, "239.255.255.250:1900") != 0 &&
memptr_cmp(&hdr_value, "[FF02::C]:1900") != 0 &&
memptr_cmp(&hdr_value, "[ff02::c]:1900") != 0 &&
memptr_cmp(&hdr_value, "[FF05::C]:1900") != 0 &&
memptr_cmp(&hdr_value, "[ff05::c]:1900") != 0)) {
UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
"Invalid HOST header from SSDP message\n");
return FALSE;
}
}
/* passed quick check */
return TRUE;
}
/************************************************************************
@ -850,69 +894,92 @@ readFromSSDPSocket( SOCKET socket )
* Returns: int
* return UPNP_E_SUCCESS if successful else returns appropriate error
***************************************************************************/
int get_ssdp_sockets( MiniServerSockArray * out )
int get_ssdp_sockets(MiniServerSockArray *out)
{
int retVal;
int retVal;
#if INCLUDE_CLIENT_APIS
// Create the IPv4 socket for SSDP REQUESTS
if( strlen( gIF_IPV4 ) > 0 ) {
retVal = create_ssdp_sock_reqv4( &out->ssdpReqSock4 );
if( retVal != UPNP_E_SUCCESS ) {
return retVal;
}
// For use by ssdp control point.
gSsdpReqSocket4 = out->ssdpReqSock4;
} else {
out->ssdpReqSock4 = INVALID_SOCKET;
}
/* Create the IPv4 socket for SSDP REQUESTS */
if(strlen(gIF_IPV4) > 0) {
retVal = create_ssdp_sock_reqv4(&out->ssdpReqSock4);
if(retVal != UPNP_E_SUCCESS) {
return retVal;
}
/* For use by ssdp control point. */
gSsdpReqSocket4 = out->ssdpReqSock4;
} else {
out->ssdpReqSock4 = INVALID_SOCKET;
}
// Create the IPv6 socket for SSDP REQUESTS
if( strlen( gIF_IPV6 ) > 0 ) {
retVal = create_ssdp_sock_reqv6( &out->ssdpReqSock6 );
if( retVal != UPNP_E_SUCCESS ) {
CLIENTONLY( shutdown( out->ssdpReqSock4, SD_BOTH ); )
CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock4 ); )
return retVal;
}
// For use by ssdp control point.
gSsdpReqSocket6 = out->ssdpReqSock6;
} else {
out->ssdpReqSock6 = INVALID_SOCKET;
}
/* Create the IPv6 socket for SSDP REQUESTS */
if (strlen(gIF_IPV6) > 0) {
retVal = create_ssdp_sock_reqv6(&out->ssdpReqSock6);
if (retVal != UPNP_E_SUCCESS) {
shutdown(out->ssdpReqSock4, SD_BOTH);
UpnpCloseSocket(out->ssdpReqSock4);
return retVal;
}
/* For use by ssdp control point. */
gSsdpReqSocket6 = out->ssdpReqSock6;
} else {
out->ssdpReqSock6 = INVALID_SOCKET;
}
#endif /* INCLUDE_CLIENT_APIS */
// Create the IPv4 socket for SSDP
if( strlen( gIF_IPV4 ) > 0 ) {
retVal = create_ssdp_sock_v4( &out->ssdpSock4 );
if( retVal != UPNP_E_SUCCESS ) {
CLIENTONLY( shutdown( out->ssdpReqSock4, SD_BOTH ); )
CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock4 ); )
CLIENTONLY( shutdown( out->ssdpReqSock6, SD_BOTH ); )
CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock6 ); )
return retVal;
}
} else {
out->ssdpSock4 = INVALID_SOCKET;
}
/* Create the IPv4 socket for SSDP */
if (strlen(gIF_IPV4) > 0) {
retVal = create_ssdp_sock_v4(&out->ssdpSock4);
if (retVal != UPNP_E_SUCCESS) {
#ifdef INCLUDE_CLIENT_APIS
shutdown(out->ssdpReqSock4, SD_BOTH);
UpnpCloseSocket(out->ssdpReqSock4);
shutdown(out->ssdpReqSock6, SD_BOTH);
UpnpCloseSocket(out->ssdpReqSock6);
#endif
return retVal;
}
} else {
out->ssdpSock4 = INVALID_SOCKET;
}
// Create the IPv6 socket for SSDP
if( strlen( gIF_IPV6 ) > 0 ) {
retVal = create_ssdp_sock_v6( &out->ssdpSock6 );
if( retVal != UPNP_E_SUCCESS ) {
shutdown( out->ssdpSock4, SD_BOTH );
UpnpCloseSocket( out->ssdpSock4 );
CLIENTONLY( shutdown( out->ssdpReqSock4, SD_BOTH ); )
CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock4 ); )
CLIENTONLY( shutdown( out->ssdpReqSock6, SD_BOTH ); )
CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock6 ); )
return retVal;
}
} else {
out->ssdpSock6 = INVALID_SOCKET;
}
/* Create the IPv6 socket for SSDP */
if (strlen(gIF_IPV6) > 0) {
retVal = create_ssdp_sock_v6(&out->ssdpSock6);
if (retVal != UPNP_E_SUCCESS) {
shutdown(out->ssdpSock4, SD_BOTH);
UpnpCloseSocket(out->ssdpSock4);
#ifdef INCLUDE_CLIENT_APIS
shutdown(out->ssdpReqSock4, SD_BOTH);
UpnpCloseSocket(out->ssdpReqSock4);
shutdown(out->ssdpReqSock6, SD_BOTH);
UpnpCloseSocket(out->ssdpReqSock6);
#endif
return retVal;
}
} else {
out->ssdpSock6 = INVALID_SOCKET;
}
return UPNP_E_SUCCESS;
if (strlen(gIF_IPV6_ULA_GUA) > 0) {
retVal = create_ssdp_sock_v6_ula_gua(&out->ssdpSock6UlaGua);
if (retVal != UPNP_E_SUCCESS) {
shutdown(out->ssdpSock4, SD_BOTH);
UpnpCloseSocket(out->ssdpSock4);
shutdown(out->ssdpSock6, SD_BOTH);
UpnpCloseSocket(out->ssdpSock6);
#ifdef INCLUDE_CLIENT_APIS
shutdown(out->ssdpReqSock4, SD_BOTH);
UpnpCloseSocket(out->ssdpReqSock4);
shutdown(out->ssdpReqSock6, SD_BOTH);
UpnpCloseSocket(out->ssdpReqSock6);
#endif
return retVal;
}
} else {
out->ssdpSock6UlaGua = INVALID_SOCKET;
}
return UPNP_E_SUCCESS;
}
@ -1229,5 +1296,118 @@ int create_ssdp_sock_v6( SOCKET* ssdpSock )
return UPNP_E_SUCCESS;
}
/************************************************************************
* Function : create_ssdp_sock_v6_ula_gua
*
* Parameters:
* IN SOCKET* ssdpSock: SSDP IPv6 socket to be created
*
* Description:
* This function ...
*
* Returns: void
*
***************************************************************************/
int create_ssdp_sock_v6_ula_gua(SOCKET *ssdpSock)
{
char errorBuffer[ERROR_BUFFER_LEN];
struct ipv6_mreq ssdpMcastAddr;
struct sockaddr_storage __ss;
struct sockaddr_in6 *ssdpAddr6 = (struct sockaddr_in6 *)&__ss;
int onOff;
int ret = 0;
*ssdpSock = socket(AF_INET6, SOCK_DGRAM, 0);
if (*ssdpSock == -1) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
"Error in socket(): %s\n", errorBuffer);
return UPNP_E_OUTOF_SOCKET;
}
onOff = 1;
ret = setsockopt(*ssdpSock, SOL_SOCKET, SO_REUSEADDR,
(char*)&onOff, sizeof(onOff) );
if (ret == -1) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf(UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
"Error in setsockopt() SO_REUSEADDR: %s\n", errorBuffer);
shutdown(*ssdpSock, SD_BOTH);
UpnpCloseSocket(*ssdpSock);
return UPNP_E_SOCKET_ERROR;
}
#if defined(BSD) || defined(__OSX__) || defined(__APPLE__)
onOff = 1;
ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_REUSEPORT,
(char*)&onOff, sizeof (onOff) );
if ( ret == -1 ) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
"Error in setsockopt() SO_REUSEPORT: %s\n", errorBuffer );
shutdown( *ssdpSock, SD_BOTH );
UpnpCloseSocket( *ssdpSock );
return UPNP_E_SOCKET_ERROR;
}
#endif /* BSD */
memset( &__ss, 0, sizeof( __ss ) );
ssdpAddr6->sin6_family = AF_INET6;
ssdpAddr6->sin6_addr = in6addr_any;
ssdpAddr6->sin6_scope_id = gIF_INDEX;
ssdpAddr6->sin6_port = htons( SSDP_PORT );
ret = bind( *ssdpSock, (struct sockaddr *)ssdpAddr6, sizeof(*ssdpAddr6) );
if ( ret == -1 ) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
"Error in bind(), addr=0x%032lX, port=%d: %s\n",
0lu, SSDP_PORT, errorBuffer );
shutdown( *ssdpSock, SD_BOTH );
UpnpCloseSocket( *ssdpSock );
return UPNP_E_SOCKET_BIND;
}
memset( (void *)&ssdpMcastAddr, 0, sizeof(ssdpMcastAddr) );
ssdpMcastAddr.ipv6mr_interface = gIF_INDEX;
/* SITE LOCAL */
inet_pton( AF_INET6, SSDP_IPV6_SITELOCAL, &ssdpMcastAddr.ipv6mr_multiaddr );
ret = setsockopt( *ssdpSock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
(char *)&ssdpMcastAddr, sizeof(ssdpMcastAddr) );
if ( ret == -1 ) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
"Error in setsockopt() IPV6_JOIN_GROUP (join multicast group): %s\n",
errorBuffer );
shutdown( *ssdpSock, SD_BOTH );
UpnpCloseSocket( *ssdpSock );
return UPNP_E_SOCKET_ERROR;
}
onOff = 1;
ret = setsockopt( *ssdpSock, SOL_SOCKET, SO_BROADCAST,
(char*)&onOff, sizeof(onOff) );
if( ret == -1) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_CRITICAL, SSDP, __FILE__, __LINE__,
"Error in setsockopt() SO_BROADCAST (set broadcast): %s\n",
errorBuffer );
shutdown( *ssdpSock, SD_BOTH );
UpnpCloseSocket( *ssdpSock );
return UPNP_E_NETWORK_ERROR;
}
return UPNP_E_SUCCESS;
}
#endif /* EXCLUDE_SSDP */