* 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 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> 2010-08-21 Marcelo Jimenez <mroberto(at)users.sourceforge.net>
* upnp/src/genlib/miniserver/miniserver.c: Fix for IPV6 ULA/GUA issues. * 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" ); 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 * Function : searchExpired
* *
@ -475,136 +504,152 @@ searchExpired( void *arg )
* Returns: int * Returns: int
* 1 if successful else appropriate error * 1 if successful else appropriate error
***************************************************************************/ ***************************************************************************/
int int SearchByTarget(
SearchByTarget( IN int Mx, IN int Mx,
IN char *St, IN char *St,
IN void *Cookie ) IN void *Cookie)
{ {
char errorBuffer[ERROR_BUFFER_LEN]; char errorBuffer[ERROR_BUFFER_LEN];
int socklen = sizeof( struct sockaddr_storage ); int socklen = sizeof( struct sockaddr_storage );
int *id = NULL; int *id = NULL;
int ret = 0; int ret = 0;
char ReqBufv4[BUFSIZE]; char ReqBufv4[BUFSIZE];
char ReqBufv6[BUFSIZE]; char ReqBufv6[BUFSIZE];
struct sockaddr_storage __ss_v4; char ReqBufv6UlaGua[BUFSIZE];
struct sockaddr_storage __ss_v6; struct sockaddr_storage __ss_v4;
struct sockaddr_in* destAddr4 = (struct sockaddr_in*)&__ss_v4; struct sockaddr_storage __ss_v6;
struct sockaddr_in6* destAddr6 = (struct sockaddr_in6*)&__ss_v6; struct sockaddr_in* destAddr4 = (struct sockaddr_in*)&__ss_v4;
fd_set wrSet; struct sockaddr_in6* destAddr6 = (struct sockaddr_in6*)&__ss_v6;
SsdpSearchArg *newArg = NULL; fd_set wrSet;
int timeTillRead = 0; SsdpSearchArg *newArg = NULL;
int handle; int timeTillRead = 0;
struct Handle_Info *ctrlpt_info = NULL; int handle;
enum SsdpSearchType requestType; struct Handle_Info *ctrlpt_info = NULL;
unsigned long addrv4 = inet_addr( gIF_IPV4 ); enum SsdpSearchType requestType;
int max_fd = 0; unsigned long addrv4 = inet_addr(gIF_IPV4);
int max_fd = 0;
//ThreadData *ThData; //ThreadData *ThData;
ThreadPoolJob job; ThreadPoolJob job;
requestType = ssdp_request_type1( St ); requestType = ssdp_request_type1(St);
if( requestType == SSDP_SERROR ) { if (requestType == SSDP_SERROR) {
return UPNP_E_INVALID_PARAM; 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 ) { CreateClientRequestPacket(ReqBufv4, timeTillRead, St, AF_INET);
timeTillRead = MIN_SEARCH_TIME; CreateClientRequestPacket(ReqBufv6, timeTillRead, St, AF_INET6);
} else if( timeTillRead > MAX_SEARCH_TIME ) { CreateClientRequestPacketUlaGua(ReqBufv6UlaGua, timeTillRead, St, AF_INET6);
timeTillRead = MAX_SEARCH_TIME;
}
CreateClientRequestPacket( ReqBufv4, timeTillRead, St, AF_INET ); memset(&__ss_v4, 0, sizeof(__ss_v4));
CreateClientRequestPacket( ReqBufv6, timeTillRead, St, AF_INET6 ); 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 ) ); memset(&__ss_v6, 0, sizeof(__ss_v6));
destAddr4->sin_family = AF_INET; destAddr6->sin6_family = AF_INET6;
inet_pton( AF_INET, SSDP_IP, &destAddr4->sin_addr ); inet_pton(AF_INET6, SSDP_IPV6_SITELOCAL, &destAddr6->sin6_addr);
destAddr4->sin_port = htons( SSDP_PORT ); destAddr6->sin6_port = htons(SSDP_PORT);
destAddr6->sin6_scope_id = gIF_INDEX;
memset( &__ss_v6, 0, sizeof( __ss_v6 ) ); /* add search criteria to list */
destAddr6->sin6_family = AF_INET6; HandleLock();
inet_pton( AF_INET6, SSDP_IPV6_LINKLOCAL, &destAddr6->sin6_addr ); if (GetClientHandleInfo(&handle, &ctrlpt_info) != HND_CLIENT) {
destAddr6->sin6_port = htons( SSDP_PORT ); HandleUnlock();
destAddr6->sin6_scope_id = gIF_INDEX;
// add search criteria to list return UPNP_E_INTERNAL_ERROR;
HandleLock(); }
if( GetClientHandleInfo( &handle, &ctrlpt_info ) != HND_CLIENT ) {
HandleUnlock();
return UPNP_E_INTERNAL_ERROR;
}
newArg = ( SsdpSearchArg * ) malloc( sizeof( SsdpSearchArg ) ); newArg = (SsdpSearchArg *)malloc(sizeof(SsdpSearchArg));
newArg->searchTarget = strdup( St ); newArg->searchTarget = strdup(St);
newArg->cookie = Cookie; newArg->cookie = Cookie;
newArg->requestType = requestType; newArg->requestType = requestType;
id = ( int * )malloc( sizeof( int ) ); id = (int *)malloc(sizeof(int));
TPJobInit( &job, ( start_routine ) searchExpired, id ); TPJobInit(&job, (start_routine)searchExpired, id);
TPJobSetPriority( &job, MED_PRIORITY ); TPJobSetPriority(&job, MED_PRIORITY);
TPJobSetFreeFunction( &job, ( free_routine ) free ); TPJobSetFreeFunction(&job, (free_routine)free);
// Schedule a timeout event to remove search Arg /* Schedule a timeout event to remove search Arg */
TimerThreadSchedule( &gTimerThread, timeTillRead, TimerThreadSchedule(&gTimerThread, timeTillRead,
REL_SEC, &job, SHORT_TERM, id ); REL_SEC, &job, SHORT_TERM, id);
newArg->timeoutEventId = ( *id ); newArg->timeoutEventId = *id;
ListAddTail( &ctrlpt_info->SsdpSearchList, newArg ); ListAddTail(&ctrlpt_info->SsdpSearchList, newArg);
HandleUnlock(); HandleUnlock();
/* End of lock */
FD_ZERO( &wrSet ); FD_ZERO(&wrSet);
if( gSsdpReqSocket4 != INVALID_SOCKET ) { if (gSsdpReqSocket4 != INVALID_SOCKET) {
setsockopt( gSsdpReqSocket4, IPPROTO_IP, IP_MULTICAST_IF, setsockopt(gSsdpReqSocket4, IPPROTO_IP, IP_MULTICAST_IF,
(char *)&addrv4, sizeof (addrv4) ); (char *)&addrv4, sizeof (addrv4));
FD_SET( gSsdpReqSocket4, &wrSet ); FD_SET(gSsdpReqSocket4, &wrSet);
max_fd = max(max_fd, gSsdpReqSocket4); max_fd = max(max_fd, gSsdpReqSocket4);
} }
if( gSsdpReqSocket6 != INVALID_SOCKET ) { if (gSsdpReqSocket6 != INVALID_SOCKET) {
setsockopt( gSsdpReqSocket6, IPPROTO_IPV6, IPV6_MULTICAST_IF, setsockopt(gSsdpReqSocket6, IPPROTO_IPV6, IPV6_MULTICAST_IF,
(char *)&gIF_INDEX, sizeof(gIF_INDEX) ); (char *)&gIF_INDEX, sizeof (gIF_INDEX));
FD_SET( gSsdpReqSocket6, &wrSet ); FD_SET(gSsdpReqSocket6, &wrSet);
max_fd = max(max_fd, gSsdpReqSocket6); max_fd = max(max_fd, gSsdpReqSocket6);
} }
ret = select( max_fd + 1, NULL, &wrSet, NULL, NULL ); ret = select(max_fd + 1, NULL, &wrSet, NULL, NULL);
if( ret == -1 ) { if (ret == -1) {
strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN); strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
"SSDP_LIB: Error in select(): %s\n", "SSDP_LIB: Error in select(): %s\n",
errorBuffer ); errorBuffer);
shutdown( gSsdpReqSocket4, SD_BOTH ); shutdown(gSsdpReqSocket4, SD_BOTH);
UpnpCloseSocket( gSsdpReqSocket4 ); UpnpCloseSocket(gSsdpReqSocket4);
shutdown( gSsdpReqSocket6, SD_BOTH ); shutdown(gSsdpReqSocket6, SD_BOTH);
UpnpCloseSocket( gSsdpReqSocket6 ); UpnpCloseSocket(gSsdpReqSocket6);
return UPNP_E_INTERNAL_ERROR; return UPNP_E_INTERNAL_ERROR;
} }
if( gSsdpReqSocket6 != INVALID_SOCKET && if (gSsdpReqSocket6 != INVALID_SOCKET &&
FD_ISSET( gSsdpReqSocket6, &wrSet ) ) { FD_ISSET(gSsdpReqSocket6, &wrSet)) {
int NumCopy = 0; 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 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 #endif // EXCLUDE_SSDP

View File

@ -291,6 +291,61 @@ NewRequestHandler( IN struct sockaddr *DestAddr,
return UPNP_E_SUCCESS; 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 * Function : CreateServiceRequestPacket
* *
@ -312,85 +367,92 @@ NewRequestHandler( IN struct sockaddr *DestAddr,
* Returns: void * Returns: void
* *
***************************************************************************/ ***************************************************************************/
void void CreateServicePacket(
CreateServicePacket( IN int msg_type, IN int msg_type,
IN char *nt, IN char *nt,
IN char *usn, IN char *usn,
IN char *location, IN char *location,
IN int duration, IN int duration,
OUT char **packet, OUT char **packet,
IN int AddressFamily) IN int AddressFamily)
{ {
int ret_code; int ret_code;
char *nts; char *nts;
membuffer buf; membuffer buf;
//Notf=0 means service shutdown, /* Notf == 0 means service shutdown,
//Notf=1 means service advertisement, Notf =2 means reply * Notf == 1 means service advertisement,
* Notf == 2 means reply */
membuffer_init(&buf);
buf.size_inc = 30;
*packet = NULL;
membuffer_init( &buf ); if (msg_type == MSGTYPE_REPLY) {
buf.size_inc = 30; 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 ) { return;
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;
} }
/************************************************************************ /************************************************************************
* Function : DeviceAdvertisement * Function : DeviceAdvertisement
* *
@ -436,7 +498,9 @@ DeviceAdvertisement( IN char *DevType,
DestAddr4->sin_port = htons( SSDP_PORT ); DestAddr4->sin_port = htons( SSDP_PORT );
} else if( AddressFamily == AF_INET6 ) { } else if( AddressFamily == AF_INET6 ) {
DestAddr6->sin6_family = 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_port = htons( SSDP_PORT );
DestAddr6->sin6_scope_id = gIF_INDEX; DestAddr6->sin6_scope_id = gIF_INDEX;
} else { } else {
@ -683,7 +747,9 @@ ServiceAdvertisement( IN char *Udn,
DestAddr4->sin_port = htons( SSDP_PORT ); DestAddr4->sin_port = htons( SSDP_PORT );
} else if( AddressFamily == AF_INET6 ) { } else if( AddressFamily == AF_INET6 ) {
DestAddr6->sin6_family = 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_port = htons( SSDP_PORT );
DestAddr6->sin6_scope_id = gIF_INDEX; DestAddr6->sin6_scope_id = gIF_INDEX;
} else { } else {
@ -787,7 +853,9 @@ ServiceShutdown( IN char *Udn,
DestAddr4->sin_port = htons( SSDP_PORT ); DestAddr4->sin_port = htons( SSDP_PORT );
} else if( AddressFamily == AF_INET6 ) { } else if( AddressFamily == AF_INET6 ) {
DestAddr6->sin6_family = 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_port = htons( SSDP_PORT );
DestAddr6->sin6_scope_id = gIF_INDEX; DestAddr6->sin6_scope_id = gIF_INDEX;
} else { } else {
@ -855,7 +923,9 @@ DeviceShutdown( IN char *DevType,
DestAddr4->sin_port = htons( SSDP_PORT ); DestAddr4->sin_port = htons( SSDP_PORT );
} else if( AddressFamily == AF_INET6 ) { } else if( AddressFamily == AF_INET6 ) {
DestAddr6->sin6_family = 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_port = htons( SSDP_PORT );
DestAddr6->sin6_scope_id = gIF_INDEX; DestAddr6->sin6_scope_id = gIF_INDEX;
} else { } else {

View File

@ -56,6 +56,7 @@ CLIENTONLY( SOCKET gSsdpReqSocket6 = INVALID_SOCKET; )
void RequestHandler(); void RequestHandler();
int create_ssdp_sock_v4( SOCKET* ssdpSock ); int create_ssdp_sock_v4( SOCKET* ssdpSock );
int create_ssdp_sock_v6( SOCKET* ssdpSock ); int create_ssdp_sock_v6( SOCKET* ssdpSock );
int create_ssdp_sock_v6_ula_gua( SOCKET* ssdpSock );
#if INCLUDE_CLIENT_APIS #if INCLUDE_CLIENT_APIS
int create_ssdp_sock_reqv4( SOCKET* ssdpReqSock ); int create_ssdp_sock_reqv4( SOCKET* ssdpReqSock );
int create_ssdp_sock_reqv6( SOCKET* ssdpReqSock ); int create_ssdp_sock_reqv6( SOCKET* ssdpReqSock );
@ -260,15 +261,31 @@ int AdvertiseAndReply(
} }
case SSDP_DEVICETYPE: { case SSDP_DEVICETYPE: {
if (!strncasecmp(DeviceType, devType, strlen(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__, UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"DeviceType=%s and search devType=%s MATCH\n", "DeviceType=%s and search devType=%s MATCH\n",
devType, DeviceType); devType, DeviceType);
SendReply(DestAddr, devType, 0, UDNstr, SendReply(DestAddr, devType, 0, UDNstr, SInfo->DescURL, defaultExp, 1);
SInfo->DescURL, defaultExp, 1); #endif
} else { } else {
UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
"DeviceType=%s and search devType=%s" "DeviceType=%s and search devType=%s DID NOT MATCH\n",
" DID NOT MATCH\n",
devType, DeviceType); devType, DeviceType);
} }
break; break;
@ -346,9 +363,33 @@ int AdvertiseAndReply(
break; break;
case SSDP_SERVICE: case SSDP_SERVICE:
if (ServiceType) { 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))) { if (!strncasecmp(ServiceType, servType, strlen(ServiceType))) {
ServiceReply(DestAddr, servType, UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__,
UDNstr, SInfo->DescURL, defaultExp); "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; break;
@ -614,35 +655,38 @@ free_ssdp_event_handler_data( void *the_data )
* Returns: xboolean * Returns: xboolean
* returns TRUE if msg is valid else FALSE * returns TRUE if msg is valid else FALSE
***************************************************************************/ ***************************************************************************/
static UPNP_INLINE xboolean static UPNP_INLINE xboolean valid_ssdp_msg(IN http_message_t *hmsg)
valid_ssdp_msg( IN http_message_t * hmsg )
{ {
memptr hdr_value; memptr hdr_value;
// check for valid methods - NOTIFY or M-SEARCH /* check for valid methods - NOTIFY or M-SEARCH */
if( hmsg->method != HTTPMETHOD_NOTIFY && if (hmsg->method != HTTPMETHOD_NOTIFY &&
hmsg->method != HTTPMETHOD_MSEARCH hmsg->method != HTTPMETHOD_MSEARCH &&
&& hmsg->request_method != HTTPMETHOD_MSEARCH ) { hmsg->request_method != HTTPMETHOD_MSEARCH) {
return FALSE; return FALSE;
} }
if( hmsg->request_method != HTTPMETHOD_MSEARCH ) { if (hmsg->request_method != HTTPMETHOD_MSEARCH) {
// check PATH == * /* check PATH == "*" */
if( hmsg->uri.type != RELATIVE || if (hmsg->uri.type != RELATIVE ||
strncmp( "*", hmsg->uri.pathquery.buff, strncmp("*", hmsg->uri.pathquery.buff, hmsg->uri.pathquery.size) != 0) {
hmsg->uri.pathquery.size ) != 0 ) { return FALSE;
return FALSE; }
} /* check HOST header */
// check HOST header if (httpmsg_find_hdr(hmsg, HDR_HOST, &hdr_value) == NULL ||
if( ( httpmsg_find_hdr( hmsg, HDR_HOST, &hdr_value ) == NULL ) || (memptr_cmp(&hdr_value, "239.255.255.250:1900") != 0 &&
( ( 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, "[ff02::c]:1900") != 0 &&
) { memptr_cmp(&hdr_value, "[FF05::C]:1900") != 0 &&
UpnpPrintf( UPNP_INFO, SSDP, __FILE__, __LINE__, memptr_cmp(&hdr_value, "[ff05::c]:1900") != 0)) {
"Invalid HOST header from SSDP message\n" ); UpnpPrintf(UPNP_INFO, SSDP, __FILE__, __LINE__,
return FALSE; "Invalid HOST header from SSDP message\n");
}
} return FALSE;
return TRUE; // passed quick check }
}
/* passed quick check */
return TRUE;
} }
/************************************************************************ /************************************************************************
@ -850,69 +894,92 @@ readFromSSDPSocket( SOCKET socket )
* Returns: int * Returns: int
* return UPNP_E_SUCCESS if successful else returns appropriate error * 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 #if INCLUDE_CLIENT_APIS
// Create the IPv4 socket for SSDP REQUESTS /* Create the IPv4 socket for SSDP REQUESTS */
if( strlen( gIF_IPV4 ) > 0 ) { if(strlen(gIF_IPV4) > 0) {
retVal = create_ssdp_sock_reqv4( &out->ssdpReqSock4 ); retVal = create_ssdp_sock_reqv4(&out->ssdpReqSock4);
if( retVal != UPNP_E_SUCCESS ) { if(retVal != UPNP_E_SUCCESS) {
return retVal; return retVal;
} }
// For use by ssdp control point. /* For use by ssdp control point. */
gSsdpReqSocket4 = out->ssdpReqSock4; gSsdpReqSocket4 = out->ssdpReqSock4;
} else { } else {
out->ssdpReqSock4 = INVALID_SOCKET; out->ssdpReqSock4 = INVALID_SOCKET;
} }
// Create the IPv6 socket for SSDP REQUESTS /* Create the IPv6 socket for SSDP REQUESTS */
if( strlen( gIF_IPV6 ) > 0 ) { if (strlen(gIF_IPV6) > 0) {
retVal = create_ssdp_sock_reqv6( &out->ssdpReqSock6 ); retVal = create_ssdp_sock_reqv6(&out->ssdpReqSock6);
if( retVal != UPNP_E_SUCCESS ) { if (retVal != UPNP_E_SUCCESS) {
CLIENTONLY( shutdown( out->ssdpReqSock4, SD_BOTH ); ) shutdown(out->ssdpReqSock4, SD_BOTH);
CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock4 ); ) UpnpCloseSocket(out->ssdpReqSock4);
return retVal; return retVal;
} }
// For use by ssdp control point. /* For use by ssdp control point. */
gSsdpReqSocket6 = out->ssdpReqSock6; gSsdpReqSocket6 = out->ssdpReqSock6;
} else { } else {
out->ssdpReqSock6 = INVALID_SOCKET; out->ssdpReqSock6 = INVALID_SOCKET;
} }
#endif /* INCLUDE_CLIENT_APIS */ #endif /* INCLUDE_CLIENT_APIS */
// Create the IPv4 socket for SSDP /* Create the IPv4 socket for SSDP */
if( strlen( gIF_IPV4 ) > 0 ) { if (strlen(gIF_IPV4) > 0) {
retVal = create_ssdp_sock_v4( &out->ssdpSock4 ); retVal = create_ssdp_sock_v4(&out->ssdpSock4);
if( retVal != UPNP_E_SUCCESS ) { if (retVal != UPNP_E_SUCCESS) {
CLIENTONLY( shutdown( out->ssdpReqSock4, SD_BOTH ); ) #ifdef INCLUDE_CLIENT_APIS
CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock4 ); ) shutdown(out->ssdpReqSock4, SD_BOTH);
CLIENTONLY( shutdown( out->ssdpReqSock6, SD_BOTH ); ) UpnpCloseSocket(out->ssdpReqSock4);
CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock6 ); ) shutdown(out->ssdpReqSock6, SD_BOTH);
return retVal; UpnpCloseSocket(out->ssdpReqSock6);
} #endif
} else { return retVal;
out->ssdpSock4 = INVALID_SOCKET; }
} } else {
out->ssdpSock4 = INVALID_SOCKET;
}
// Create the IPv6 socket for SSDP /* Create the IPv6 socket for SSDP */
if( strlen( gIF_IPV6 ) > 0 ) { if (strlen(gIF_IPV6) > 0) {
retVal = create_ssdp_sock_v6( &out->ssdpSock6 ); retVal = create_ssdp_sock_v6(&out->ssdpSock6);
if( retVal != UPNP_E_SUCCESS ) { if (retVal != UPNP_E_SUCCESS) {
shutdown( out->ssdpSock4, SD_BOTH ); shutdown(out->ssdpSock4, SD_BOTH);
UpnpCloseSocket( out->ssdpSock4 ); UpnpCloseSocket(out->ssdpSock4);
CLIENTONLY( shutdown( out->ssdpReqSock4, SD_BOTH ); ) #ifdef INCLUDE_CLIENT_APIS
CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock4 ); ) shutdown(out->ssdpReqSock4, SD_BOTH);
CLIENTONLY( shutdown( out->ssdpReqSock6, SD_BOTH ); ) UpnpCloseSocket(out->ssdpReqSock4);
CLIENTONLY( UpnpCloseSocket( out->ssdpReqSock6 ); ) shutdown(out->ssdpReqSock6, SD_BOTH);
return retVal; UpnpCloseSocket(out->ssdpReqSock6);
} #endif
} else { return retVal;
out->ssdpSock6 = INVALID_SOCKET; }
} } 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; 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 */ #endif /* EXCLUDE_SSDP */