LegacyNATTraversal.c [plain text]
#include "mDNSEmbeddedAPI.h"
#include "mDNSMacOSX.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <fcntl.h>
#include <pthread.h>
#include <sched.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/sysctl.h>
#include <net/route.h>
#include "memory.h"
#include <ctype.h>
#include <arpa/inet.h>
#define MAX_SOAPMSGSIZE 65536
static int safe_close(int fd)
{
if (fd < 3) { return(-1); }
return(close(fd));
}
#define close safe_close
#define NA_E_SUCCESS (0)
#define NA_E_INTERNAL_ERROR (-1)
#define NA_E_INVALID_PARAMETER (-2)
#define NA_E_OPERATION_FAILED (-3)
#define NA_E_TIMEOUT (-4)
#define NA_E_THREAD_ERROR (-5)
#define NA_E_PARSE_ERROR (-6)
#define NA_E_NOT_READY (-7)
#define NA_E_NOT_FOUND (-8)
#define NA_E_NOT_AVAILABLE (-9)
#define NA_E_EXISTS (-10)
#define NA_E_AGAIN (-11)
#define NA_E_NOT_SUPPORTED (-12)
#define NA_E_ABORT (-14)
#define NA_E_NET (-15)
#define NALOG_ERROR (1UL)
#define NALOG_ALERT (2UL)
#define NALOG_INFO0 (4UL)
#define NALOG_INFO1 (8UL)
#define NALOG_DUMP (16UL)
#define NALOG_RSRV1 (32UL)
#define NALOG_RSRV2 (64UL)
#define NALOG_RSRV3 (128UL)
#define NALOG_UPNP (256)
#define NALOG_LEVEL0 (0)
#define NALOG_LEVEL1 (NALOG_UPNP | NALOG_ERROR)
#define NALOG_LEVEL2 (NALOG_LEVEL1 | NALOG_ALERT)
#define NALOG_LEVEL3 (NALOG_LEVEL2 | NALOG_INFO0)
#define NALOG_LEVEL4 (NALOG_LEVEL3 | NALOG_INFO1)
#define NALOG_LEVEL5 (NALOG_LEVEL4 | NALOG_DUMP)
#define NALOG_DEFAULT_LEVEL (NALOG_LEVEL2)
#define NA_DEFAULT_FUNCTION_TIMEOUT (50)
#define SSDP_IP "239.255.255.250"
#define SSDP_PORT 1900
#define SSDP_TTL 4
#define CRLF "\r\n"
#define H_CRLF "\r\n"
#define S_CRLF
#define HTTP200OK "HTTP/1.1 200 OK\r\n\r\n"
#define HTTP200OKLEN (sizeof(HTTP200OK) - 1)
#define MAX_EXPECTEVENTTIME (10000)
typedef struct tagProperty {
char *pszName;
char *pszValue;
char *pszType;
} Property, *PProperty;
typedef struct tagHTTPResponse {
char *pszStatus;
char *pszReason;
int iNumHeaders;
Property aHeaders[30]; char *pszBody;
int fFree;
char *buf;
} HTTPResponse, *PHTTPResponse, **PPHTTPResponse;
static const char szSSDPMsgDiscoverRoot[] =
"M-SEARCH * HTTP/1.1\r\n"
"Host:239.255.255.250:1900\r\n"
"ST:upnp:rootdevice\r\n"
"Man:\"ssdp:discover\"\r\n"
"MX:3\r\n"
"\r\n";
static const char szSSDPMsgDiscoverIGD[] =
"M-SEARCH * HTTP/1.1\r\n"
"Host:239.255.255.250:1900\r\n"
"ST:urn:schemas-upnp-org:device:InternetGatewayDevice:1\r\n"
"Man:\"ssdp:discover\"\r\n"
"MX:3\r\n"
"\r\n";
static const char szSSDPMsgDiscoverNAT[] =
"M-SEARCH * HTTP/1.1\r\n"
"Host:239.255.255.250:1900\r\n"
"ST:urn:schemas-upnp-org:service:WANIPConnection:1\r\n"
"Man:\"ssdp:discover\"\r\n"
"MX:3\r\n"
"\r\n";
static const char szEventMsgSubscribeFMT[] =
"SUBSCRIBE %1$s HTTP/1.1\r\n"
"NT: upnp:event\r\n"
"Callback: <http://%2$s/notify>\r\n"
"Timeout: Second-%4$d\r\n"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
"Host: %3$s\r\n"
"Content-Length: 0\r\n"
"Pragma: no-cache\r\n"
"\r\n";
#if 0
static const char szEventMsgUnsubscribeFMT[] =
"UNSUBSCRIBE %1$s HTTP/1.1\r\n"
"SID: %2$s\r\n"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
"Host: %3$s\r\n"
"Content-Length: 0\r\n"
"Pragma: no-cache\r\n"
"\r\n";
#endif
static const char szSOAPMsgControlAHeaderFMT[] =
"POST %1$s HTTP/1.1\r\n"
"Content-Type: text/xml; charset=\"utf-8\"\r\n"
"SOAPAction: \"urn:schemas-upnp-org:service:WANIPConnection:1#%3$s\"\r\n"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)\r\n"
"Host: %2$s\r\n"
"Content-Length: %4$d\r\n"
"Connection: close\r\n"
"Pragma: no-cache\r\n"
"\r\n";
static const char szSOAPMsgControlABodyFMT[] =
"<?xml version=\"1.0\"?>" CRLF
"<SOAP-ENV:Envelope" S_CRLF
" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\"" S_CRLF
" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" S_CRLF
"<SOAP-ENV:Body>" S_CRLF
"<m:%1$s" S_CRLF
" xmlns:m=\"urn:schemas-upnp-org:service:WANIPConnection:1\">" S_CRLF
"%2$s"
"</m:%1$s>" S_CRLF
"</SOAP-ENV:Body>" S_CRLF
"</SOAP-ENV:Envelope>" S_CRLF
CRLF;
static const char szSOAPMsgControlAArgumentFMT[] =
"<%1$s>%2$s</%1$s>" S_CRLF;
static const char szSOAPMsgControlAArgumentFMT_t[] =
"<%1$s"
" xmlns:dt=\"urn:schemas-microsoft-com:datatypes\""
" dt:dt=\"%3$s\">%2$s</%1$s>" S_CRLF;
#if 0
static const char szSOAPMsgControlQHeaderFMT[] =
"M-POST %1$s HTTP/1.1\r\n"
"Host: %2$s\r\n"
"Content-Length: %3$d\r\n"
"Content-Type: text/xml; charset-\"utf-8\"\r\n"
"01-SOAPAction: \"urn:schemas-upnp-org:control-1-0#QueryStateVariable\"\r\n"
"\r\n";
static const char szSOAPMsgControlQBodyFMT[] =
"<s:Envelope" S_CRLF
" xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\"" S_CRLF
" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" S_CRLF
"<s:Body>" S_CRLF
"<u:QueryStateVariable xmlns:u=\"urn:schemas-upnp-org:control-1-0\"" S_CRLF
"<u:varName>%s</u:varName>" S_CRLF
"</u:QueryStateVariable>" S_CRLF
"</s:Body>" S_CRLF
"</s:Envelope>" S_CRLF
"" S_CRLF;
#endif
static const char szSSDPMsgDescribeDeviceFMT[] =
"GET %s HTTP/1.1\r\n"
"Accept: text/xml, application/xml\r\n"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows NT/5.1)\r\n"
"Host: %s\r\n"
"Connection: close\r\n"
"\r\n";
static int g_fFirstInit = TRUE;
static int g_fQuit = FALSE;
static FILE *g_log;
static int g_fLogging;
static int g_sUDP = -1;
static int g_sUDPCancel = -1;
static int g_sTCP = -1;
static int g_sTCPCancel = -1;
static int g_fEventEnabled = FALSE;
static unsigned short g_wEventPort;
static struct sockaddr_in g_saddrRouterEvent;
static char g_szRouterHostPortEvent[1024];
static char g_szEventURL[1024];
static char g_szFriendlyName[1024];
static char g_szManufacturer[1024];
static char g_szModelName[1024];
static char g_szModelDescription[1024];
static struct sockaddr_in g_saddrRouterBase;
static char g_szRouterHostPortBase[1024];
static pthread_t g_UDPthread = NULL;
static pthread_t g_TCPthread = NULL;
static unsigned long g_dwLocalIP = 0;
static int g_fUPnPEnabled = FALSE;
static char g_szUSN[1024];
static struct sockaddr_in g_saddrRouterDesc;
static char g_szRouterHostPortDesc[1024];
static char g_szNATDevDescURL[1024];
static struct sockaddr_in g_saddrRouterSOAP;
static char g_szRouterHostPortSOAP[1024];
static char g_szControlURL[1024];
static int g_fControlURLSet = FALSE;
static pthread_mutex_t g_xUPnP;
static pthread_mutex_t g_xUPnPMsg;
static pthread_cond_t g_condUPnP;
static pthread_cond_t g_condUPnPControlURL;
static struct timeval g_tvUPnPInitTime;
static struct timeval g_tvLastUpdateTime;
static int g_iFunctionTimeout = NA_DEFAULT_FUNCTION_TIMEOUT;
static void GetDeviceDescription(void);
static void SetLocalIP(void);
#define ISIPV6 0x01
#define ISPPP 0x02
#define IFNAMELEN 16
#define IPLEN 16
typedef struct tagIPINFO
{
int iFlags;
char szIfName[IFNAMELEN];
unsigned char abIP[IPLEN];
unsigned short wPort;
} IPINFO, *PIPINFO, **PPIPINFO;
typedef struct hostent HOSTENT, *PHOSTENT;
static unsigned long GetNATIPNetmask(unsigned long dwIP)
{
if ((dwIP & 0xFF000000) == 0x0A000000) return 0xFF000000;
if ((dwIP & 0xFFF00000) == 0xAC100000) return 0xFFF00000;
if ((dwIP & 0xFFFF0000) == 0xC0a80000) return 0xFFFF0000;
return 0;
}
static int GetIPInfo(PPIPINFO ppIPInfo)
{
int fd;
int iLastLen, iLen, iNum = 0, iMax = 0;
unsigned long dwIP;
char *pcBuf, *pcTemp;
PIPINFO pIPInfo = NULL;
struct ifconf ifc;
struct ifreq *ifr, ifrcopy;
if (ppIPInfo == NULL) return 0;
fd = socket(AF_INET, SOCK_DGRAM, 0);
iLastLen = -1;
iLen = 100 * sizeof(struct ifreq);
for (;;)
{
pcBuf = (char *)malloc(iLen);
ifc.ifc_len = iLen;
ifc.ifc_buf = pcBuf;
if (ioctl(fd, SIOCGIFCONF, &ifc) < 0)
{
if (errno != EINVAL || iLastLen != -1)
{
free(pcBuf);
close(fd);
return 0;
}
}
else
{
if (ifc.ifc_len == iLastLen) break;
iLastLen = ifc.ifc_len;
}
iLen += 10 * sizeof(struct ifreq);
free(pcBuf);
}
for (pcTemp = pcBuf; pcTemp < pcBuf + ifc.ifc_len; )
{
if (iNum >= iMax)
{
PIPINFO pIPInfoNew;
iMax += 10;
pIPInfoNew = (PIPINFO)realloc(pIPInfo, sizeof(IPINFO) * iMax);
if (pIPInfoNew == NULL)
{
free(pIPInfo);
free(pcBuf);
close(fd);
return 0;
}
else pIPInfo = pIPInfoNew;
memset(pIPInfo + (iMax - 10), 0, sizeof(IPINFO) * 10);
}
ifr = (struct ifreq *)pcTemp;
pcTemp += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
if ((ifr->ifr_addr.sa_family != AF_INET &&
ifr->ifr_addr.sa_family != AF_INET6) ||
strncmp(ifr->ifr_name, "lo", 2) == 0) continue;
ifrcopy = *ifr;
ioctl(fd, SIOCGIFFLAGS, &ifrcopy);
if ((ifrcopy.ifr_flags & IFF_UP) == 0) continue;
switch (ifr->ifr_addr.sa_family)
{
case AF_INET:
memcpy(pIPInfo[iNum].szIfName, ifr->ifr_name, IFNAMELEN);
dwIP =
ntohl(((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr);
memcpy(pIPInfo[iNum].abIP, &dwIP, sizeof(unsigned long));
if (ifrcopy.ifr_flags & IFF_POINTOPOINT)
pIPInfo[iNum].iFlags |= ISPPP;
iNum++;
break;
case AF_INET6:
memcpy(pIPInfo[iNum].szIfName, ifr->ifr_name, IFNAMELEN);
memcpy(pIPInfo[iNum].abIP,
((struct sockaddr_in6 *)&(ifr->ifr_addr))-> sin6_addr.s6_addr,
16);
pIPInfo[iNum].iFlags |= ISIPV6;
if (ifrcopy.ifr_flags & IFF_POINTOPOINT)
pIPInfo[iNum].iFlags |= ISPPP;
iNum++;
break;
default:
break;
}
}
free(pcBuf);
close(fd);
*ppIPInfo = pIPInfo;
return iNum;
}
static void FreeIPInfo(PIPINFO pIPInfo)
{
if (pIPInfo != NULL) free(pIPInfo);
}
static void SendDiscoveryMsg();
static int SSDPListen()
{
char fLoop;
int iTTL;
struct ip_mreq mreq;
struct sockaddr_in saddr;
int sd;
sd = socket(AF_INET, SOCK_DGRAM, 0);
if (sd == -1) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "Can't create socket! SSDPListen exiting\n");
return NA_E_NET;
}
fLoop = 0; iTTL = SSDP_TTL;
bzero(&saddr, sizeof(saddr));
saddr.sin_len = sizeof(saddr);
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(g_dwLocalIP);
saddr.sin_port = 0;
bzero(&mreq, sizeof(mreq));
mreq.imr_interface.s_addr = g_dwLocalIP;
mreq.imr_multiaddr.s_addr = inet_addr(SSDP_IP);
if (
bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)) ) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log,
"bind/setsockopt for multicast failed... errno = %d\n", errno);
close(sd);
return NA_E_NET;
}
return sd;
}
static int EventListen()
{
struct sockaddr_in saddr;
int sd;
for (g_wEventPort = 5000; g_wEventPort < 5005; g_wEventPort++)
{
sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sd == -1) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "Can't create socket! EventListen exiting\n");
return NA_E_NET;
}
bzero(&saddr, sizeof(saddr));
saddr.sin_len = sizeof(saddr);
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(g_dwLocalIP);
saddr.sin_port = htons(g_wEventPort);
if (bind(sd, (struct sockaddr *)&saddr, sizeof(saddr)) == 0)
{
listen(sd, 128);
return sd;
}
if (g_fLogging & NALOG_ERROR)
fprintf(g_log,
"bind TCP port %u failed: errno = %d\n", g_wEventPort, errno);
close(sd);
}
return NA_E_NET;
}
static void *TCPProc(void *in);
static int EventInit()
{
int iRet;
pthread_attr_t attr;
if (g_fEventEnabled == FALSE)
{
g_sTCP = EventListen();
if (g_sTCP < 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "EventInit - Failed to init tcp socket.\n");
return NA_E_INTERNAL_ERROR;
}
pthread_attr_init(&attr);
iRet = pthread_create(&g_TCPthread, &attr, TCPProc, 0);
if (iRet != 0) {
close(g_sTCP);
g_sTCP = -1;
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "EventInit: TCPProc create failed(%d)\n", iRet);
return NA_E_THREAD_ERROR;
}
}
g_fEventEnabled = TRUE;
return NA_E_SUCCESS;
}
static void DumpHex(char *buf, int len)
{
int i;
int nexti;
int j;
int endj;
if (g_fLogging & NALOG_DUMP) {
if (buf == NULL) return;
if (len <= 0) return;
for (i = 0; i < len; i = nexti) {
fprintf(g_log, "%04x: ", i);
nexti = i + 16;
endj = (nexti > len) ? len : nexti;
for (j = i; j < endj; j++)
fprintf(g_log, "%02x ", buf[j] & 0xff);
if (j == len) {
if ((j % 16) != 0) {
char pad[3 * 16 + 1]; j = (16 - (j % 16)) * 3;
memset(pad, ' ', j);
pad[j] = '\0';
fputs(pad, g_log);
}
}
for (j = i; j < endj; j++)
isprint(buf[j]) ? fputc(buf[j], g_log) : fputc('.', g_log);
fputc('\n', g_log);
}
}
}
static char *FindHTTPHeaderNewLine(char *pbuf, int iBufSize, int *pfEOH)
{
char *result;
int i = 0;
if (pbuf == NULL) return NULL;
for (;;) {
result = memchr(pbuf, '\r', iBufSize);
if (result == NULL) {
if (g_fLogging & NALOG_INFO0) {
fprintf(g_log, "FindHTTPHeaderNewLine: er @(%d)\n", i);
fflush(g_log);
}
return NULL;
}
i++;
iBufSize -= (result - pbuf);
pbuf = result;
++pbuf; --iBufSize;
if (*pbuf == '\0') break;
if (*pbuf != '\n') continue;
++pbuf; --iBufSize;
if (*pbuf == '\0') break;
if ((*pbuf == ' ') || (*pbuf == '\t')) continue;
if ((pbuf[0] == '\r') && (pbuf[1] == '\n'))
*pfEOH = TRUE;
else
*pfEOH = FALSE;
return result;
}
return NULL;
}
static PHTTPResponse NewHTTPResponse_sz(
char *pszHTTPResponse,
int iBufferSize,
int fDestroyOriginal)
{
PHTTPResponse pResponse;
int fEOH;
char *pszEOL;
int iNumHeaders;
char *pBuf;
if ((pResponse = (PHTTPResponse)malloc(sizeof(HTTPResponse))) == NULL) {
if (g_fLogging & NALOG_INFO0) {
fprintf(g_log, "NewHTTPResponse_sz: er 1\n");
fflush(g_log);
}
return NULL;
}
if (fDestroyOriginal) {
pResponse->buf = NULL;
pBuf = pszHTTPResponse;
}
else {
int len = strlen(pszHTTPResponse);
if ((len+1) > iBufferSize) {
if (g_fLogging & NALOG_INFO0)
fprintf(g_log, "Length: %d > %d\n", len+1, iBufferSize);
iBufferSize = len+1;
}
if ((pResponse->buf = (char *)malloc(iBufferSize)) == NULL) {
free(pResponse);
if (g_fLogging & NALOG_INFO0) {
fprintf(g_log, "NewHTTPResponse_sz: er 2\n");
fflush(g_log);
}
return NULL;
}
memcpy(pResponse->buf, pszHTTPResponse, iBufferSize);
pBuf = pResponse->buf;
}
pszEOL = FindHTTPHeaderNewLine(pBuf, iBufferSize, &fEOH);
if (pszEOL == NULL) {
if (g_fLogging & NALOG_INFO0) {
fprintf(g_log, "NewHTTPResponse_sz: er 3\n");
fflush(g_log);
}
goto cleanup;
}
*pszEOL = '\0'; pszEOL += 2;
pResponse->pszStatus = strchr(pBuf, ' ');
if (pResponse->pszStatus == NULL) {
if (g_fLogging & NALOG_INFO0) {
fprintf(g_log, "NewHTTPResponse_sz: er 4\n");
fflush(g_log);
}
goto cleanup; }
pResponse->pszStatus++;
pResponse->pszReason = strchr(pResponse->pszStatus, ' ');
if (pResponse->pszReason == NULL) {
if (g_fLogging & NALOG_INFO0) {
fprintf(g_log, "NewHTTPResponse_sz: er 5\n");
fflush(g_log);
}
goto cleanup; }
pResponse->pszReason[0] = '\0'; pResponse->pszReason++;
iNumHeaders = 0;
while (!fEOH) {
PProperty pHeader = &(pResponse->aHeaders[iNumHeaders]);
pHeader->pszName = pszEOL;
pszEOL = FindHTTPHeaderNewLine(pszEOL,
iBufferSize - (pszEOL - pBuf), &fEOH);
if (pszEOL == NULL) goto cleanup;
*pszEOL = '\0'; pszEOL += 2;
pHeader->pszValue = strchr(pHeader->pszName, ':');
if (pHeader->pszValue == NULL) {
if (g_fLogging & NALOG_INFO0) {
fprintf(g_log, "NewHTTPResponse_sz: er 6\n");
fflush(g_log);
}
goto cleanup; }
pHeader->pszValue[0] = '\0'; pHeader->pszValue++; while (
(pHeader->pszValue[0] == ' ') ||
(pHeader->pszValue[0] == '\t') ||
(pHeader->pszValue[0] == '\r') ||
(pHeader->pszValue[0] == '\n')
) {
pHeader->pszValue++; }
iNumHeaders++; pHeader++; }
pResponse->iNumHeaders = iNumHeaders;
pResponse->pszBody = pszEOL + 2;
return pResponse;
cleanup:
if (pResponse->buf != NULL) free(pResponse->buf);
free(pResponse);
return NULL;
}
static void DeleteHTTPResponse(PHTTPResponse pResponse)
{
if (pResponse == NULL) return;
if (pResponse->buf != NULL)
free(pResponse->buf);
free(pResponse);
}
static void PrintHTTPResponse(PHTTPResponse pResponse)
{
int i;
if (g_fLogging & (NALOG_INFO1)) {
if (pResponse == NULL) return;
fprintf(g_log, " *** HTTP response begin *** \n");
fprintf(g_log, " * status = [%s], reason = [%s] *\n",
pResponse->pszStatus, pResponse->pszReason);
for (i = 0; i < pResponse->iNumHeaders; i++) {
fprintf(g_log, " * Header \"%s\" = [%s]\n",
pResponse->aHeaders[i].pszName,
pResponse->aHeaders[i].pszValue);
}
if (g_fLogging & NALOG_DUMP)
fprintf(g_log, " * body = [%s] *\n", pResponse->pszBody);
fprintf(g_log, " *** HTTP response end *** \n");
}
}
static int DiscoverRouter(PHTTPResponse pResponse)
{
int i;
int fLocation = FALSE;
int fUSN = FALSE;
int fIsNATDevice = FALSE;
#if 0
if (strcmp(pResponse->pszStatus, "200") != 0)
return -1;
#endif
if (pResponse == NULL) {
if (g_fLogging & NALOG_INFO0)
fprintf(g_log, "DiscoverRouter: pResponse == NULL\n");
return -1;
}
for (i = 0; i < pResponse->iNumHeaders; i++) {
PProperty pHeader = &(pResponse->aHeaders[i]);
if ((strcasecmp(pHeader->pszName, "ST") == 0) ||
(strcasecmp(pHeader->pszName, "NT") == 0)) {
if ((strcmp(pHeader->pszValue,
"urn:schemas-upnp-org:service:WANIPConnection:1") == 0) ||
(strcmp(pHeader->pszValue,
"urn:schemas-upnp-org:device:InternetGatewayDevice:1") == 0)) {
fIsNATDevice = TRUE;
}
}
}
if (!fIsNATDevice)
return -1;
pthread_mutex_lock(&g_xUPnP);
g_fUPnPEnabled = FALSE;
for (i = 0; i < pResponse->iNumHeaders; i++) {
PProperty pHeader = &(pResponse->aHeaders[i]);
if (strcasecmp(pHeader->pszName, "Location") == 0) {
char *p;
char *q;
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, "Checking Location...\n");
p = pHeader->pszValue;
if (strncmp(p, "http://", 7) != 0)
continue; p += 7; q = strchr(p, '/');
if (q == NULL) {
g_szNATDevDescURL[0] = '/';
g_szNATDevDescURL[1] = '\0';
}
else {
strncpy(g_szNATDevDescURL, q, sizeof(g_szNATDevDescURL) - 1);
g_szNATDevDescURL[sizeof(g_szNATDevDescURL) - 1] = '\0';
*q = '\0';
}
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, " Device Description URL set to[%s]...\n",
g_szNATDevDescURL);
q = strchr(p, ':');
if (q == NULL) {
sprintf(g_szRouterHostPortDesc, "%s", p);
g_saddrRouterDesc.sin_addr.s_addr = inet_addr(p);
g_saddrRouterDesc.sin_port = htons(80);
}
else {
if (atoi(q+1) == 80) *q = '\0';
strcpy(g_szRouterHostPortDesc, p);
*q = '\0';
q++;
g_saddrRouterDesc.sin_addr.s_addr = inet_addr(p);
g_saddrRouterDesc.sin_port = htons(atoi(q));
}
g_saddrRouterDesc.sin_family = AF_INET;
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, " Router Address set to[%s]...\n",
g_szRouterHostPortDesc);
fLocation = TRUE;
}
else if (strcasecmp(pHeader->pszName, "USN") == 0) {
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, "Checking USN...\n");
strncpy(g_szUSN, pHeader->pszValue, sizeof(g_szUSN) - 1);
g_szUSN[sizeof(g_szUSN) - 1] = '\0';
fUSN = TRUE;
}
else {
; }
}
if (fLocation && fUSN) {
if (g_fLogging & NALOG_INFO1) {
fprintf(g_log,
"Description Host/port string: [%s]\n"
"NATDevDescURL: [%s], USN: [%s]\n",
g_szRouterHostPortDesc,
g_szNATDevDescURL, g_szUSN);
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, "Got router information\n");
}
g_fUPnPEnabled = TRUE;
pthread_cond_broadcast(&g_condUPnP);
}
pthread_mutex_unlock(&g_xUPnP);
return 0;
}
#define UPNP_TIMEOUT_GRANULARITY (1000)
#define U_TOGRAN UPNP_TIMEOUT_GRANULARITY
static void TimevalSubtract(
struct timeval *result,
const struct timeval *a,
const struct timeval *b)
{
result->tv_sec = a->tv_sec - b->tv_sec;
if (b->tv_usec > a->tv_usec) {
result->tv_sec--;
result->tv_usec = 1000000 + a->tv_usec - b->tv_usec;
}
else
result->tv_usec = a->tv_usec - b->tv_usec;
}
static void GetTimeElapsed(
const struct timeval *tv_start,
const struct timeval *tv_end,
struct timeval *tv_elapsed)
{
TimevalSubtract(tv_elapsed, tv_end, tv_start);
#if 0
tv_elapsed->tv_sec = tv_end->tv_sec - tv_start->tv_sec;
if (tv_start->tv_usec > tv_end->tv_usec) {
tv_elapsed->tv_sec--;
tv_elapsed->tv_usec = 1000000 + tv_end->tv_usec - tv_start->tv_usec;
}
else
tv_elapsed->tv_usec = tv_end->tv_usec - tv_start->tv_usec;
#endif
}
static int CompareTime(
const struct timeval *a,
const struct timeval *b
)
{
if ((a->tv_sec == b->tv_sec) &&
(a->tv_usec == b->tv_usec)) return 0;
if (a->tv_sec > b->tv_sec) return 1;
else if (a->tv_sec < b->tv_sec) return -1;
if (a->tv_usec > b->tv_usec) return 1;
else return -1;
}
static int WaitControlURLSet(double timeout)
{
struct timespec ts;
struct timeval tv;
struct timeval tv_start;
int iRet;
long to_sec = (int) (timeout / U_TOGRAN);
long to_usec =
(int) (((timeout / U_TOGRAN) - to_sec) * 1000000.0);
struct timeval elapsed;
gettimeofday(&tv_start, NULL);
pthread_mutex_lock(&g_xUPnP);
#if 0
GetTimeElapsed(&g_tvLastUpdateTime, &tv_start, &elapsed);
if ((elapsed.tv_sec + (elapsed.tv_usec / 1000000.0)) >
(((double) g_iUPnPTimeout) / U_TOGRAN))
g_fControlURLSet = 0;
#endif
while (!g_fControlURLSet) {
gettimeofday(&tv, NULL);
#if 0
for now ignore device timeout
GetTimeElapsed(&g_tvUPnPInitTime, &tv, &elapsed);
if ((elapsed.tv_sec > g_timeout_sec) ||
( (elapsed.tv_sec == g_timeout_sec) &&
(elapsed.tv_usec > g_timeout_usec)
))
{
pthread_mutex_unlock(&g_xUPnP);
return FALSE;
}
#endif
ts.tv_sec = tv.tv_sec + to_sec;
ts.tv_nsec = (tv.tv_usec + to_usec) * 1000;
if (ts.tv_nsec > 1000000000) {
ts.tv_nsec -= 1000000000;
ts.tv_sec += 1;
}
GetTimeElapsed(&tv_start, &tv, &elapsed);
ts.tv_sec -= elapsed.tv_sec;
if (ts.tv_nsec < (elapsed.tv_usec * 1000)) {
ts.tv_sec--;
ts.tv_nsec = 1000000000 + ts.tv_nsec - (elapsed.tv_usec * 1000);
}
else {
ts.tv_nsec -= (elapsed.tv_usec * 1000);
}
iRet = pthread_cond_timedwait(&g_condUPnPControlURL, &g_xUPnP, &ts);
if (iRet != 0)
{
pthread_mutex_unlock(&g_xUPnP);
return FALSE;
}
}
pthread_mutex_unlock(&g_xUPnP);
return TRUE;
}
static int WaitUPnPFunction()
{
struct timeval start;
double wait2;
gettimeofday(&start, NULL);
wait2 = (double)g_iFunctionTimeout;
WaitControlURLSet(wait2);
return g_fControlURLSet;
}
static void SetLocalIP();
static int SendTCPMsg_saddr_parse(
char *msg, int iLen,
char *result, int resultSize,
struct sockaddr_in *saHost);
static void *TCPProc(void *in)
{
int iRet;
unsigned char buf[MAX_SOAPMSGSIZE];
int iBufLen;
(void)in; WaitUPnPFunction();
{
char callback[100];
char response[2000];
PHTTPResponse resp;
int n;
sprintf(callback, "%lu.%lu.%lu.%lu:%u",
(g_dwLocalIP >> 24) & 0xFF,
(g_dwLocalIP >> 16) & 0xFF,
(g_dwLocalIP >> 8) & 0xFF,
(g_dwLocalIP >> 0) & 0xFF,
g_wEventPort);
n = sprintf(buf,
szEventMsgSubscribeFMT,
g_szEventURL,
callback, g_szRouterHostPortEvent, 1800);
memset(response, 0, 2000);
n = SendTCPMsg_saddr_parse(
buf, n,
response, 2000,
&g_saddrRouterEvent);
if (n > 0)
{
response[n] = '\0';
resp = NewHTTPResponse_sz(buf, n, TRUE);
if (NULL != resp)
{
}
else
{
}
DeleteHTTPResponse(resp);
}
else
{
return NULL;
}
}
g_sTCPCancel = -1;
for (;;)
{
struct sockaddr_in recvaddr;
int recvaddrlen;
fd_set readfds;
struct timeval timeout;
int sEvent;
int fFirstRecv;
int sMax;
if (g_fQuit)
goto cleanup;
if (g_sTCPCancel != -1) close(g_sTCPCancel);
sMax = g_sTCPCancel = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sMax < g_sTCP) sMax = g_sTCP;
FD_ZERO(&readfds);
FD_SET(g_sTCP, &readfds);
FD_SET(g_sTCPCancel, &readfds);
iRet = select(sMax+1, &readfds, NULL, NULL, NULL);
if (iRet <= 0) {
if (EBADF == errno)
continue;
continue;
}
recvaddrlen = sizeof(recvaddr);
sEvent = accept(g_sTCP, (struct sockaddr *)&recvaddr, &recvaddrlen);
if (sEvent <= 0) continue;
fFirstRecv = 1;
iBufLen = 0;
for (;;)
{
FD_ZERO(&readfds);
FD_SET(sEvent, &readfds);
timeout.tv_sec = 0;
timeout.tv_usec = 400000; iRet = select(sEvent+1, &readfds, NULL, NULL, &timeout);
if (iRet <= 0) {
if (g_fQuit)
{
close(sEvent);
goto cleanup;
}
break;
}
iRet = recv(sEvent, buf + iBufLen, MAX_SOAPMSGSIZE - iBufLen, 0);
if (iRet < 0)
{
break;
}
else if (iRet == 0)
{
break;
}
iBufLen += iRet;
if (fFirstRecv)
{
int iTemp;
iTemp = send(sEvent, HTTP200OK, HTTP200OKLEN, 0);
shutdown(sEvent, 1);
fFirstRecv = 0;
}
}
close(sEvent);
if (iBufLen < MAX_SOAPMSGSIZE)
{
buf[iBufLen] = '\0';
}
else
{
buf[MAX_SOAPMSGSIZE - 1] = '\0';
}
}
cleanup:
close(g_sTCP);
g_sTCP = -1;
g_fEventEnabled = FALSE;
if (g_sTCPCancel != -1) close(g_sTCPCancel);
g_sTCPCancel = -1;
return NULL;
}
static void *UDPProc(void *in)
{
int iRet;
unsigned char buf[65536];
static time_t last_getdevicedesc_t = 0;
(void)in; pthread_mutex_lock(&g_xUPnP);
gettimeofday(&g_tvUPnPInitTime, NULL);
pthread_mutex_unlock(&g_xUPnP);
for (;;) {
ssize_t n;
struct sockaddr_in recvaddr;
int recvaddrlen;
fd_set readfds;
int sMax;
if (g_sUDPCancel < g_sUDP) sMax = g_sUDP;
else sMax = g_sUDPCancel;
FD_ZERO(&readfds);
FD_SET(g_sUDP, &readfds);
FD_SET(g_sUDPCancel, &readfds);
iRet = select(sMax+1, &readfds, NULL, NULL, NULL);
if (iRet <= 0) {
if (g_fQuit)
{
close(g_sUDP);
close(g_sUDPCancel);
g_sUDP = -1;
g_sUDPCancel = -1;
return NULL;
}
continue;
}
if (!FD_ISSET(g_sUDP, &readfds)) continue;
recvaddrlen = sizeof(recvaddr);
n = recvfrom(g_sUDP, buf, sizeof(buf), 0,
(struct sockaddr *)&recvaddr, &recvaddrlen);
if (n < 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "recv failed (%d)\n", errno);
close(g_sUDP);
close(g_sUDPCancel);
g_sUDP = -1;
g_sUDPCancel = -1;
return NULL;
}
buf[n] = '\0';
if (strncmp(buf, "HTTP/1.1", 8) == 0) {
PHTTPResponse pResponse = NewHTTPResponse_sz(buf, n, TRUE);
PrintHTTPResponse(pResponse);
if (DiscoverRouter(pResponse) == 0)
{
time_t now = time(NULL);
if (!g_fControlURLSet ||
((now - last_getdevicedesc_t) > 5))
{
GetDeviceDescription();
SetLocalIP();
last_getdevicedesc_t = now;
}
}
DeleteHTTPResponse(pResponse);
}
else if (strncmp(buf, "NOTIFY * HTTP/1.1", 7) == 0) {
PHTTPResponse pResponse = NewHTTPResponse_sz(buf, n, TRUE);
if (DiscoverRouter(pResponse) == 0)
{
time_t now = time(NULL);
if (!g_fControlURLSet ||
((now - last_getdevicedesc_t) > 5))
{
GetDeviceDescription();
SetLocalIP();
last_getdevicedesc_t = now;
}
}
DeleteHTTPResponse(pResponse);
}
else {
if (g_fLogging & NALOG_DUMP)
fprintf(g_log, "(%ld) Buffer: \n[%s]\n", time(NULL), buf);
fflush(g_log);
}
}
close(g_sUDP);
g_sUDP = -1;
}
static void SendUDPMsg(const char *msg) {
struct sockaddr_in saSendTo;
int iRet;
int iLen;
bzero(&saSendTo, sizeof(saSendTo));
saSendTo.sin_family = AF_INET;
saSendTo.sin_addr.s_addr = inet_addr(SSDP_IP);
saSendTo.sin_port = htons(SSDP_PORT);
iLen = strlen(msg);
if (g_fLogging & NALOG_DUMP)
fprintf(g_log, "SendUDP: [%s]\n", msg);
iRet = sendto(g_sUDP, msg, iLen, 0,
(struct sockaddr *)&saSendTo, sizeof(saSendTo));
if (iRet != iLen)
if (g_fLogging & NALOG_ALERT)
fprintf(g_log,
"SendUDPMsg: iRet(%d) != strlen(msg)(%d)! (errno %d)\n",
iRet, iLen, errno);
}
static char *strcasestr_n(const char *big, const char *little, int len)
{
int bigLen;
int littleLen;
int i;
int end;
if (little == NULL) return (char *)big;
if (big == NULL) return NULL;
bigLen = len;
littleLen = strlen(little);
if (bigLen < littleLen) return NULL;
end = bigLen - littleLen;
for (i = 0; i <= end; (i++), (big++)) {
if (strncasecmp(big, little, littleLen) == 0)
return (char *)big;
}
return NULL;
}
static char *strstr_n(const char *big, const char *little, int len)
{
int iBigLen;
int iLittleLen;
(void)len;
if ((big == NULL) || (little == NULL)) return NULL;
iBigLen = strlen(big);
iLittleLen = strlen(little);
for (;;) {
if (iBigLen < iLittleLen)
return NULL;
if (strncmp(big, little, iLittleLen) == 0)
return (char *)big;
++big;
--iBigLen;
}
}
static int FindContentLength(char *pbuf, int iLen)
{
char *p;
int iResult;
p = strcasestr_n(pbuf, "\r\nContent-Length:", iLen);
if (p == NULL) return -1;
p += sizeof("\r\nContent-Length:") - 1;
iResult = atoi(p);
return iResult;
}
static int FindBody(char *pbuf, int iLen)
{
char *p;
p = strstr_n(pbuf, "\r\n\r\n", iLen);
if (p == NULL) return -1;
p += sizeof("\r\n\r\n") - 1;
return (p - pbuf);
}
static int SendTCPMsg_saddr_2part(
char *msg, int iLen,
char *msg2, int iLen2,
char *result, int resultSize,
struct sockaddr_in *saHost)
{
int s;
struct sockaddr_in saSendTo;
int iRet;
int iBufLen;
int fND;
int fcntl_flags;
int iRetcode;
struct timeval tv;
fd_set writefds;
struct timeval tv_start;
struct timeval tv_end;
struct timeval tv_elapsed;
int iContentLength = -1;
int iBodyOffset = -1;
gettimeofday(&tv_start, NULL);
if (g_fUPnPEnabled != TRUE) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "UPnP not enabled (no UPnP device found yet)\n");
return NA_E_NOT_AVAILABLE;
}
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == -1) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "Can't get TCP socket (%d)\n", errno);
return NA_E_NET;
}
fND = 1;
if (setsockopt(s, IPPROTO_IP, TCP_NODELAY, &fND, sizeof(fND)) != 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "SendTCPMsg/2part: Can't set TCP_NODELAY option!\n");
iRetcode = NA_E_NET;
goto cleanup;
}
fcntl_flags = 0;
fcntl_flags = fcntl(s, F_GETFL, 0);
fcntl_flags |= O_NONBLOCK;
if (fcntl(s, F_SETFL, fcntl_flags) != 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "SendTCPMsg/2part: Can't set O_NONBLOCK option!\n");
iRetcode = NA_E_NET;
goto cleanup;
}
if (saHost == NULL)
memcpy(&saSendTo, &g_saddrRouterDesc, sizeof(saSendTo));
else
memcpy(&saSendTo, saHost, sizeof(saSendTo));
iRet = connect(s, (struct sockaddr *) &saSendTo, sizeof(saSendTo));
if ((iRet < 0) && (errno != EINPROGRESS)) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "SendTCPMsg/2part: connect failed (%d)\n", errno);
iRetcode = NA_E_NET;
goto cleanup;
}
if (g_fLogging & NALOG_INFO1)
fprintf(g_log,
"- Before Sending TCP Msg1: %d == %lu?\n", iLen, strlen(msg));
if (g_fLogging & NALOG_DUMP)
fprintf(g_log, "Sending TCP msg part 1:\n[%s]\n", msg);
tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY;
tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
FD_ZERO(&writefds);
FD_SET(s, &writefds);
iRet = select(s+1, 0, &writefds, 0, &tv);
if (iRet < 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "SendTCPMsg/2part: select failed (%d)\n", errno);
iRetcode = NA_E_NET;
goto cleanup;
}
if (iRet == 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "SendTCPMsg/2part: select timed out\n");
iRetcode = NA_E_TIMEOUT;
gettimeofday(&tv_end, NULL);
GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
goto cleanup;
}
iRet = send(s, msg, iLen, 0);
if (iRet != iLen)
if (g_fLogging & NALOG_ALERT)
fprintf(g_log, "SendTCPMsg/2part: iRet(%d) != strlen(msg)(%d)!\n",
iRet, iLen);
tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY;
tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
FD_ZERO(&writefds);
FD_SET(s, &writefds);
gettimeofday(&tv_end, NULL);
GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
if (CompareTime(&tv_elapsed, &tv) > 0) {
close(s);
return NA_E_TIMEOUT;
}
else {
tv.tv_sec -= tv_elapsed.tv_sec;
if (tv.tv_usec < tv_elapsed.tv_usec) {
tv.tv_sec--;
tv.tv_usec = 1000000 + tv.tv_usec - tv_elapsed.tv_usec;
}
else
tv.tv_usec = tv.tv_usec - tv_elapsed.tv_usec;
}
iRet = select(s+1, 0, &writefds, 0, &tv);
if (iRet < 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "SendTCPMsg/2part: select2 failed (%d)\n", errno);
iRetcode = NA_E_NET;
goto cleanup;
}
if (iRet == 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "SendTCPMsg/2part: select2 timed out\n");
iRetcode = NA_E_TIMEOUT;
gettimeofday(&tv_end, NULL);
GetTimeElapsed(&tv_start, &tv_end, &tv_elapsed);
goto cleanup;
}
iRet = send(s, msg2, iLen2, 0);
if (g_fLogging & NALOG_INFO1)
fprintf(g_log,
"SendTCPMsg/parse: Before Sending TCP Msg2: %d == %lu?\n",
iLen2, strlen(msg2));
if (g_fLogging & NALOG_DUMP)
fprintf(g_log, "Sending TCP msg part 2:\n[%s]\n", msg2);
if (iRet != iLen2)
if (g_fLogging & NALOG_ALERT)
fprintf(g_log, "SendTCPMsg/2part: iRet(%d) != strlen(msg2)(%d)!\n",
iRet, iLen2);
if (result == NULL) { if (g_fLogging & NALOG_DUMP)
fprintf(g_log, "TCP Buffer: [");
}
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, "start recv @%lu\n", time(NULL));
iBufLen = 0;
iContentLength = -1;
iBodyOffset = -1;
for (;;) {
fd_set readfds;
struct timeval timeout;
int i;
FD_ZERO(&readfds);
FD_SET(s, &readfds);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
iRet = select(s+1, &readfds, NULL, NULL, &timeout);
if (iRet <= 0)
{
break;
}
if (result == NULL) {
char t[1000];
i = recv(s, t, 1000-1, 0); if (i== 0) break;
if (g_fLogging & NALOG_DUMP) {
t[i] = '\0';
fprintf(g_log, "%s", t);
}
continue;
}
if (resultSize <= iBufLen) {
char t[1000];
i = recv(s, &t, 1000, 0);
if (i== 0) break;
continue;
}
i = recv(s, result + iBufLen, resultSize - iBufLen, 0);
if (i <= 0) {
break;
}
iBufLen += i;
iContentLength = FindContentLength(result, iBufLen);
iBodyOffset = FindBody(result, iBufLen);
if ((iBodyOffset >= 0) &&
(iContentLength >= 0) &&
((iBufLen - iBodyOffset) >= iContentLength))
{
break;
}
}
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, "done recv @%lu\n", time(NULL));
if (result == NULL) { if (g_fLogging & NALOG_DUMP)
fprintf(g_log, "]\n");
}
close(s);
return iBufLen;
cleanup:
close(s);
return iRetcode;
}
static int SendTCPMsg_saddr_parse(
char *msg, int iLen,
char *result, int resultSize,
struct sockaddr_in *saHost)
{
int s;
struct sockaddr_in saSendTo;
int iRet;
int iBufLen;
int fcntl_flags;
fd_set writefds;
struct timeval tv;
struct timeval tv_start;
char *pszCurHdr;
int iContentLength;
int iBodyOffset;
tv.tv_sec = 0;
tv.tv_usec = 25000;
select(0, NULL, NULL, NULL, &tv);
pthread_mutex_lock(&g_xUPnPMsg);
gettimeofday(&tv_start, NULL);
if (g_fUPnPEnabled != TRUE) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "UPnP not enabled (no UPnP device found yet)\n");
pthread_mutex_unlock(&g_xUPnPMsg);
return NA_E_NOT_AVAILABLE;
}
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == -1) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "Can't get TCP socket (%d)\n", errno);
pthread_mutex_unlock(&g_xUPnPMsg);
return NA_E_NET;
}
fcntl_flags = 0;
fcntl_flags = fcntl(s, F_GETFL, 0);
fcntl_flags |= O_NONBLOCK;
if (fcntl(s, F_SETFL, fcntl_flags) != 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "SendTCPMsg/parse: Can't set O_NONBLOCK option!\n");
close(s);
pthread_mutex_unlock(&g_xUPnPMsg);
return NA_E_NET;
}
if (saHost == NULL)
memcpy(&saSendTo, &g_saddrRouterDesc, sizeof(saSendTo));
else
memcpy(&saSendTo, saHost, sizeof(saSendTo));
iRet = connect(s, (struct sockaddr *) &saSendTo, sizeof(saSendTo));
if ((iRet < 0) && (errno != EINPROGRESS)) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "SendTCPMsg/parse: connect failed (%d)\n", errno);
close(s);
pthread_mutex_unlock(&g_xUPnPMsg);
return NA_E_NET;
}
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, "SendTCPMsg/parse: Before Sending TCP Msg: %d == %lu?\n",
iLen, strlen(msg));
if (g_fLogging & NALOG_DUMP)
fprintf(g_log,"Sending TCP msg:\n[%s]\n", msg);
tv.tv_sec = g_iFunctionTimeout / UPNP_TIMEOUT_GRANULARITY;
tv.tv_usec = (g_iFunctionTimeout % U_TOGRAN) * 1000000 / U_TOGRAN;
FD_ZERO(&writefds);
FD_SET(s, &writefds);
iRet = select(s+1, 0, &writefds, 0, &tv);
if (iRet < 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "SendTCPMsg/parse: select failed (%d)\n", errno);
close(s);
pthread_mutex_unlock(&g_xUPnPMsg);
return NA_E_NET;
}
if (iRet == 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "SendTCPMsg/parse: select timed out\n");
close(s);
pthread_mutex_unlock(&g_xUPnPMsg);
return NA_E_TIMEOUT;
}
iRet = send(s, msg, iLen, 0);
if (iRet != iLen)
if (g_fLogging & NALOG_ALERT)
fprintf(g_log, "SendTCPMsg: iRet (%d) != strlen(msg) (%d)!\n",
iRet, iLen);
if (result == NULL) { if (g_fLogging & NALOG_DUMP)
fprintf(g_log, "TCP Buffer: [");
}
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, "start recv @%lu\n", time(NULL));
iBufLen = 0;
pszCurHdr = result;
iContentLength = -1;
iBodyOffset = -1;
for (;;) {
fd_set readfds;
struct timeval timeout;
int i;
FD_ZERO(&readfds);
FD_SET(s, &readfds);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
iRet = select(s+1, &readfds, NULL, NULL, &timeout);
if (iRet <= 0) {
break;
}
if (result == NULL) {
char t[1000];
i = recv(s, t, 1000-1, 0); if (i== 0) break;
if (g_fLogging & NALOG_DUMP) {
t[i] = '\0';
fprintf(g_log, "%s", t);
}
continue;
}
if (resultSize <= iBufLen) {
char t[1000];
i = recv(s, &t, 1000, 0);
if (i== 0) break;
continue;
}
i = recv(s, result + iBufLen, resultSize - iBufLen, 0);
if (0 == i) {
break;
}
else if (i < 0) {
if (EAGAIN == errno) continue;
break;
}
iBufLen += i;
iContentLength = FindContentLength(result, iBufLen);
iBodyOffset = FindBody(result, iBufLen);
}
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, "done recv @%lu\n", time(NULL));
if (result == NULL) { if (g_fLogging & NALOG_DUMP)
fprintf(g_log, "]\n");
}
close(s);
pthread_mutex_unlock(&g_xUPnPMsg);
return iBufLen;
}
static PHTTPResponse SendSOAPMsgControlAction(
char *action,
int argc,
PProperty args,
int f2Part)
{
char *outBuffer = NULL;
char *outBufferBody = NULL;
char *outBufferArgs = NULL;
char *inBuffer = NULL;
int iLen;
int iHeaderLen;
int iBodyLen;
int iArgsLen;
int iResultLen;
int i;
int n;
PHTTPResponse pResponse = NULL;
if (!WaitUPnPFunction())
return NULL;
if ((outBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "can't malloc for outBuffer\n");
goto cleanup;
}
if ((outBufferBody = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "can't malloc for outBufferBody\n");
goto cleanup;
}
if ((outBufferArgs = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "can't malloc for outBufferArgs\n");
goto cleanup;
}
if ((inBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "can't malloc for inBuffer\n");
goto cleanup;
}
iArgsLen = 0;
if (args != NULL)
for (i=0; i<argc; i++) {
n = 0;
if (args[i].pszType == NULL) {
n = sprintf(outBufferArgs + iArgsLen,
szSOAPMsgControlAArgumentFMT,
args[i].pszName, args[i].pszValue);
}
else {
n = sprintf(outBufferArgs + iArgsLen,
szSOAPMsgControlAArgumentFMT_t,
args[i].pszName, args[i].pszValue, args[i].pszType);
}
iArgsLen += n;
}
outBufferArgs[iArgsLen] = '\0';
iBodyLen = sprintf(outBufferBody, szSOAPMsgControlABodyFMT,
action, outBufferArgs);
iHeaderLen = sprintf(outBuffer, szSOAPMsgControlAHeaderFMT,
g_szControlURL, g_szRouterHostPortSOAP, action, iBodyLen);
if (f2Part) {
DumpHex(outBuffer, iHeaderLen+1);
DumpHex(outBufferBody, iBodyLen+1);
iResultLen = SendTCPMsg_saddr_2part(
outBuffer, iHeaderLen,
outBufferBody, iBodyLen,
inBuffer, MAX_SOAPMSGSIZE,
&g_saddrRouterSOAP);
}
else {
strcpy(outBuffer + iHeaderLen, outBufferBody);
iLen = iHeaderLen + iBodyLen;
DumpHex(outBuffer, iLen+1);
iResultLen = SendTCPMsg_saddr_parse(
outBuffer, iLen,
inBuffer, MAX_SOAPMSGSIZE,
&g_saddrRouterSOAP);
}
if (iResultLen > 0) {
if (iResultLen > MAX_SOAPMSGSIZE) {
if (g_fLogging & NALOG_ALERT)
fprintf(g_log, "result truncated..\n");
iResultLen = MAX_SOAPMSGSIZE;
}
pResponse = NewHTTPResponse_sz(inBuffer, iResultLen, FALSE);
if (pResponse != NULL) {
PrintHTTPResponse(pResponse);
}
}
else {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "No TCP Response\n");
}
cleanup:
if (outBuffer != NULL) free(outBuffer);
if (outBufferBody != NULL) free(outBufferBody);
if (outBufferArgs != NULL) free(outBufferArgs);
if (inBuffer != NULL) free(inBuffer);
return pResponse;
}
static int FindURLBase(char *pbuf, int iLen, char *szURLBase)
{
char *p;
int i = 0;
p = strstr_n(pbuf, "<URLBase>", iLen);
if (p == NULL) return -1;
p += sizeof("<URLBase>") - 1;
while (isspace(*p))
p++;
while ((*p != '\0') && (*p != '<') && !isspace(*p)) {
if (i++ > 1000) break;
*szURLBase = *p;
szURLBase++;
p++;
}
*szURLBase = '\0';
return 0;
}
static int FindDescInfo(
char *pbuf,
int iLen,
const char *szParentName,
const char *szName,
char *szValue)
{
char *p;
char szSearch[100];
int iSearchLen;
int i = 0;
p = strstr_n(
pbuf,
szParentName,
iLen);
if (p == NULL)
return -1;
iLen -= (p - pbuf);
pbuf = p;
iSearchLen = sprintf(szSearch, "<%s>", szName);
p = strstr_n(pbuf, szSearch, iLen);
if (p == NULL) return -1;
p += iSearchLen;
while (isspace(*p))
p++;
while ((*p != '\0') && (*p != '<')) {
if (i++ > 1000) break;
*szValue = *p;
szValue++;
p++;
}
*szValue = '\0';
return 0;
}
static int FindIGDInfo(char *pbuf, int iLen, const char *szName, char *szValue)
{
return FindDescInfo(
pbuf, iLen,
"urn:schemas-upnp-org:device:InternetGatewayDevice:1",
szName, szValue);
}
static int FindManufacturer(char *pbuf, int iLen, char *szManuf)
{
return FindIGDInfo(pbuf, iLen, "manufacturer", szManuf);
}
static int FindFriendlyName(char *pbuf, int iLen, char *szValue)
{
return FindIGDInfo(pbuf, iLen, "friendlyName", szValue);
}
static int FindModelName(char *pbuf, int iLen, char *szValue)
{
return FindIGDInfo(pbuf, iLen, "modelName", szValue);
}
static int FindModelDescription(char *pbuf, int iLen, char *szValue)
{
return FindIGDInfo(pbuf, iLen, "modelDescription", szValue);
}
static int FindWANIPInfo(char *pbuf, int iLen, const char *szName, char *szValue)
{
return FindDescInfo(
pbuf, iLen,
"urn:schemas-upnp-org:service:WANIPConnection:1",
szName, szValue);
}
static int FindControlURL(char *pbuf, int iLen, char *szControlURL)
{
return FindWANIPInfo(pbuf, iLen, "controlURL", szControlURL);
}
static int FindEventURL(char *pbuf, int iLen, char *szEventURL)
{
return FindWANIPInfo(pbuf, iLen, "eventSubURL", szEventURL);
}
static int FindRouterInfo(char *inBuffer, int iLen)
{
if (FindManufacturer(inBuffer, iLen, g_szManufacturer) != 0)
g_szManufacturer[0] = '\0';
if (FindFriendlyName(inBuffer, iLen, g_szFriendlyName) != 0)
g_szFriendlyName[0] = '\0';
if (FindModelName(inBuffer, iLen, g_szModelName) != 0)
g_szModelName[0] = '\0';
if (FindModelDescription(inBuffer, iLen, g_szModelDescription) != 0)
g_szModelDescription[0] = '\0';
return 0;
}
static void ParseURL(
const char *szBuf, char *pszHostPort,
struct sockaddr_in *psaddr, char *pszPath)
{
char buf[1024];
char *p;
char *q;
unsigned short port;
strcpy(buf, szBuf);
p = buf;
if (0 == strncmp(p, "http://", 7))
p += 7;
q = strchr(p, '/');
if (pszPath) {
if (NULL == q) {
pszPath[0] = '/';
pszPath[1] = '\0';
}
else {
strcpy(pszPath, q);
*q = '\0';
}
}
q = strchr(p, ':');
if (NULL == q)
port = 80;
else {
port = atoi(q + 1);
if (80 == port) *q = '\0';
}
if (pszHostPort) strcpy(pszHostPort, p);
if (NULL != q) *q = '\0';
if (NULL != psaddr) {
psaddr->sin_family = AF_INET;
psaddr->sin_addr.s_addr = inet_addr(p);
psaddr->sin_port = htons(port);
}
#if 0
szBuf,
pszHostPort?pszHostPort:"",
pszPath?pszPath:"",
(psaddr->sin_addr.s_addr >> 24) & 0xff,
(psaddr->sin_addr.s_addr >> 16) & 0xff,
(psaddr->sin_addr.s_addr >> 8) & 0xff,
(psaddr->sin_addr.s_addr >> 0) & 0xff,
psaddr->sin_port);
#endif
}
static void GetDeviceDescription(void)
{
char *outBuffer = NULL;
char *inBuffer = NULL;
int iBufLen;
int iLen;
char szURLBase[1024];
char szControlURL[1024];
char szEventURL[1024];
if (!g_fUPnPEnabled) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "GetDeviceDescription: upnp not enabled\n");
return;
}
if ((outBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "can't malloc for outBuffer\n");
goto cleanup;
}
if ((inBuffer = (char *) malloc(MAX_SOAPMSGSIZE)) == NULL) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "can't malloc for inBuffer\n");
goto cleanup;
}
iBufLen = sprintf(outBuffer, szSSDPMsgDescribeDeviceFMT, g_szNATDevDescURL,
g_szRouterHostPortDesc);
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, "Describe Device: [%s]\n", outBuffer);
iLen = SendTCPMsg_saddr_parse(outBuffer, iBufLen, inBuffer, MAX_SOAPMSGSIZE,
&g_saddrRouterDesc);
g_fControlURLSet = FALSE;
if (FindControlURL(inBuffer, iLen, szControlURL) != 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(g_log, "GetDeviceDesc: can't find control URL\n");
goto cleanup;
}
pthread_mutex_lock(&g_xUPnP);
{
if (FindURLBase(inBuffer, iLen, szURLBase) != 0) {
memcpy(&g_saddrRouterBase, &g_saddrRouterDesc,
sizeof(g_saddrRouterBase));
strcpy(g_szRouterHostPortBase, g_szRouterHostPortDesc);
}
else {
ParseURL(szURLBase,
g_szRouterHostPortBase, &g_saddrRouterBase, NULL);
if ((strlen(g_szRouterHostPortBase) == 0) ||
(g_saddrRouterBase.sin_addr.s_addr == INADDR_NONE)) {
memcpy(&g_saddrRouterBase, &g_saddrRouterDesc,
sizeof(g_saddrRouterBase));
strcpy(g_szRouterHostPortBase, g_szRouterHostPortDesc);
}
}
}
ParseURL(szControlURL,
g_szRouterHostPortSOAP, &g_saddrRouterSOAP, g_szControlURL);
if ((strlen(g_szRouterHostPortSOAP) == 0) ||
(g_saddrRouterSOAP.sin_addr.s_addr == INADDR_NONE)) {
memcpy(&g_saddrRouterSOAP, &g_saddrRouterBase,
sizeof(g_saddrRouterSOAP));
strcpy(g_szRouterHostPortSOAP, g_szRouterHostPortBase);
}
g_fControlURLSet = TRUE;
gettimeofday(&g_tvLastUpdateTime, NULL);
pthread_cond_broadcast(&g_condUPnPControlURL);
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, "Got Device Description\n");
FindRouterInfo(inBuffer, iLen);
if (FindEventURL(inBuffer, iLen, szEventURL) != 0) {
szEventURL[0] = '\0';
}
else {
ParseURL(szEventURL,
g_szRouterHostPortEvent, &g_saddrRouterEvent, g_szEventURL);
if ((strlen(g_szRouterHostPortEvent) == 0) ||
(g_saddrRouterEvent.sin_addr.s_addr == INADDR_NONE)) {
memcpy(&g_saddrRouterEvent, &g_saddrRouterBase,
sizeof(g_saddrRouterEvent));
strcpy(g_szRouterHostPortEvent, g_szRouterHostPortBase);
}
EventInit();
}
cleanup:
if (outBuffer != NULL) free(outBuffer);
if (inBuffer != NULL) free(inBuffer);
pthread_mutex_unlock(&g_xUPnP);
}
static void GetIPByName(char *hostname, unsigned long *ip_ret)
{
unsigned long ip;
ip = inet_addr(hostname);
if (ip == INADDR_NONE) {
struct hostent *pHEnt;
pHEnt = gethostbyname(hostname);
if (pHEnt == NULL) {
if (g_fLogging & NALOG_ALERT)
fprintf(g_log, "Can't translate [%s] to IP...\n", hostname);
g_dwLocalIP = htonl(INADDR_ANY);
return;
}
ip = ntohl(*(unsigned long *)(pHEnt->h_addr));
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, "hostname [%s] to ip: %ld.%ld.%ld.%ld\n",
hostname,
(ip >> 24) & 0xff,
(ip >> 16) & 0xff,
(ip >> 8) & 0xff,
(ip >> 0) & 0xff);
}
*ip_ret = ip;
}
static void SetLocalIP()
{
PIPINFO pIPInfo = NULL;
int count = GetIPInfo(&pIPInfo);
if (NULL != pIPInfo)
{
int i;
unsigned long dwFirst = 0;
for(i = 0; i < count; i++)
{
if (!(pIPInfo[i].iFlags & ISIPV6) &&
(strncmp(pIPInfo[i].szIfName, "ppp", 3) != 0))
{
unsigned long dwTemp;
memcpy(&dwTemp, pIPInfo[i].abIP, sizeof(unsigned long));
if (0 != GetNATIPNetmask(dwTemp)) {
g_dwLocalIP = dwTemp;
break;
}
if (0 == dwFirst)
dwFirst = dwTemp;
}
}
if (i == count)
g_dwLocalIP = dwFirst;
FreeIPInfo(pIPInfo);
}
}
static int FindTagContent(const char *text, const char *tagname, char *buf)
{
char *p;
p = strstr(text, tagname);
if (p == NULL) {
if (g_fLogging & NALOG_INFO0)
fprintf(g_log, "FindTagContent: can't find %s\n", tagname);
return NA_E_PARSE_ERROR;
}
if (sscanf(p, "%*[^>]> %[^ <] <", buf) < 1) {
if (g_fLogging & NALOG_INFO0)
fprintf(g_log, "FindTagContent: Can't parse tag %s\n", tagname);
return NA_E_PARSE_ERROR;
}
return NA_E_SUCCESS;
}
mStatus LNT_UnmapPort(mDNSIPPort PubPort, mDNSBool tcp)
{
char szEPort[10];
Property propArgs[3];
PHTTPResponse resp;
unsigned short port = PubPort.NotAnInteger;
int protocol = tcp ? IPPROTO_TCP : IPPROTO_UDP;
sprintf(szEPort, "%u", port);
bzero(propArgs, sizeof(propArgs));
propArgs[0].pszName = "NewRemoteHost";
propArgs[0].pszValue = "";
propArgs[0].pszType = "string";
propArgs[1].pszName = "NewExternalPort";
propArgs[1].pszValue = szEPort;
propArgs[1].pszType = "ui2";
propArgs[2].pszName = "NewProtocol";
if (protocol == IPPROTO_TCP) {
propArgs[2].pszValue = "TCP";
}
else if (protocol == IPPROTO_UDP) {
propArgs[2].pszValue = "UDP";
}
else {
return -1;
}
propArgs[2].pszType = "string";
resp = SendSOAPMsgControlAction(
"DeletePortMapping", 3, propArgs, FALSE);
if (resp == NULL) {
return mStatus_NATTraversal;
}
if (strcmp(resp->pszStatus, "200") != 0) {
DeleteHTTPResponse(resp);
return mStatus_NATTraversal;
}
DeleteHTTPResponse(resp);
return mStatus_NoError;
}
static int GetMappingUnused(unsigned short eport, int protocol);
extern mStatus LNT_MapPort(mDNSIPPort priv, mDNSIPPort pub, mDNSBool tcp)
{
char szEPort[6];
char szIPort[6];
unsigned long dwIP;
char szLocalIP[30];
char descr[40];
Property propArgs[8];
PHTTPResponse resp;
unsigned short iport = priv.NotAnInteger;
unsigned short eport = pub.NotAnInteger;
int protocol = tcp ? IPPROTO_TCP : IPPROTO_UDP;
if (NA_E_EXISTS == GetMappingUnused(eport, protocol))
return mStatus_AlreadyRegistered;
sprintf(szEPort, "%u", eport);
sprintf(szIPort, "%u", iport);
dwIP = g_dwLocalIP;
sprintf(szLocalIP, "%u.%u.%u.%u",
(unsigned int)((dwIP >> 24) & 0xff),
(unsigned int)((dwIP >> 16) & 0xff),
(unsigned int)((dwIP >> 8) & 0xff),
(unsigned int)((dwIP >> 0) & 0xff));
bzero(propArgs, sizeof(propArgs));
propArgs[0].pszName = "NewRemoteHost";
propArgs[0].pszValue = "";
propArgs[0].pszType = "string";
propArgs[1].pszName = "NewExternalPort";
propArgs[1].pszValue = szEPort;
propArgs[1].pszType = "ui2";
propArgs[2].pszName = "NewProtocol";
if (protocol == IPPROTO_TCP) {
propArgs[2].pszValue = "TCP";
}
else if (protocol == IPPROTO_UDP) {
propArgs[2].pszValue = "UDP";
}
else {
return mStatus_BadParamErr;
}
propArgs[2].pszType = "string";
propArgs[3].pszName = "NewInternalPort";
propArgs[3].pszValue = szIPort;
propArgs[3].pszType = "ui2";
propArgs[4].pszName = "NewInternalClient";
propArgs[4].pszValue = szLocalIP;
propArgs[4].pszType = "string";
propArgs[5].pszName = "NewEnabled";
propArgs[5].pszValue = "1";
propArgs[5].pszType = "boolean";
propArgs[6].pszName = "NewPortMappingDescription";
sprintf(descr, "iC%u", eport);
propArgs[6].pszValue = descr;
propArgs[6].pszType = "string";
propArgs[7].pszName = "NewLeaseDuration";
propArgs[7].pszValue = "0";
propArgs[7].pszType = "ui4";
resp = SendSOAPMsgControlAction(
"AddPortMapping", 8, propArgs, FALSE);
if (resp == NULL) {
return mStatus_NATTraversal;
}
if (strcmp(resp->pszStatus, "200") != 0) {
DeleteHTTPResponse(resp);
return mStatus_NATTraversal;
}
DeleteHTTPResponse(resp);
return mStatus_NoError;
}
static int GetMappingUnused(unsigned short eport, int protocol)
{
char buf[1024];
char szPort[10];
Property propArgs[3];
PHTTPResponse resp;
unsigned long ip;
sprintf( szPort, "%u", eport);
bzero(&propArgs, sizeof(propArgs));
propArgs[0].pszName = "NewRemoteHost";
propArgs[0].pszValue = "";
propArgs[0].pszType = "string";
propArgs[1].pszName = "NewExternalPort";
propArgs[1].pszValue = szPort;
propArgs[1].pszType = "ui2";
propArgs[2].pszName = "NewProtocol";
if (protocol == IPPROTO_TCP) {
propArgs[2].pszValue = "TCP";
}
else if (protocol == IPPROTO_UDP) {
propArgs[2].pszValue = "UDP";
}
else {
return NA_E_INVALID_PARAMETER;
}
propArgs[2].pszType = "string";
resp = SendSOAPMsgControlAction(
"GetSpecificPortMappingEntry", 3, propArgs, FALSE);
if (resp != NULL) {
if ((strcmp(resp->pszStatus, "200") == 0) &&
(FindTagContent(resp->pszBody, "NewInternalClient", buf) == 0))
{
GetIPByName(buf, &ip);
if (ip == g_dwLocalIP) {
DeleteHTTPResponse(resp);
return NA_E_SUCCESS;
}
else {
DeleteHTTPResponse(resp);
return NA_E_EXISTS;
}
}
DeleteHTTPResponse(resp);
}
return NA_E_SUCCESS;
}
mStatus LNT_GetPublicIP(mDNSOpaque32 *IpPtr)
{
char buf[1024];
PHTTPResponse resp;
static struct timeval tvLastGoodIP = {0,0};
static unsigned long dwLastGoodIP;
struct timeval tv;
unsigned long *ip = (unsigned long *)IpPtr;
if (ip == NULL) return mStatus_BadParamErr;
gettimeofday(&tv, NULL);
GetTimeElapsed(&tvLastGoodIP, &tv, &tv);
if (tv.tv_sec < 4)
{
return dwLastGoodIP;
}
resp = SendSOAPMsgControlAction(
"GetExternalIPAddress", 0, NULL, FALSE);
if (resp == NULL)
return mStatus_NATTraversal;
if (FindTagContent(resp->pszBody, "NewExternalIPAddress", buf) == 0) {
if (g_fLogging & NALOG_INFO1)
fprintf(g_log, "Mapped remote host = %s\n", buf);
*ip = inet_addr(buf);
DeleteHTTPResponse(resp);
gettimeofday(&tvLastGoodIP, NULL);
dwLastGoodIP = *ip;
return mStatus_NoError;
}
DeleteHTTPResponse(resp);
return mStatus_NATTraversal;
}
static void SendDiscoveryMsg()
{
SendUDPMsg(szSSDPMsgDiscoverRoot);
SendUDPMsg(szSSDPMsgDiscoverIGD);
SendUDPMsg(szSSDPMsgDiscoverNAT);
}
int LegacyNATInit(void)
{
pthread_attr_t attr;
int iRet;
static int fFirstInitLocks = TRUE;
FILE *log = NULL;
g_fLogging = 0;
g_log = stderr;
SetLocalIP();
g_fQuit = FALSE;
if (fFirstInitLocks)
{
if (pthread_mutex_init(&g_xUPnP, NULL)) {
if (g_fLogging & NALOG_ERROR)
fprintf(log, "UpnpInit - mutex init failed\n");
return NA_E_INTERNAL_ERROR;
}
if (pthread_cond_init(&g_condUPnP, NULL)) {
pthread_mutex_destroy(&g_xUPnP);
if (g_fLogging & NALOG_ERROR)
fprintf(log, "UpnpInit - cond init failed\n");
return NA_E_INTERNAL_ERROR;
}
if (pthread_cond_init(&g_condUPnPControlURL, NULL)) {
pthread_mutex_destroy(&g_xUPnP);
pthread_cond_destroy(&g_condUPnP);
if (g_fLogging & NALOG_ERROR)
fprintf(log, "UpnpInit - cond init failed\n");
return NA_E_INTERNAL_ERROR;
}
if (pthread_mutex_init(&g_xUPnPMsg, NULL)) {
pthread_mutex_destroy(&g_xUPnP);
pthread_cond_destroy(&g_condUPnP);
pthread_cond_destroy(&g_condUPnPControlURL);
if (g_fLogging & NALOG_ERROR)
fprintf(log, "UpnpInit - mutex init failed\n");
return NA_E_INTERNAL_ERROR;
}
fFirstInitLocks = FALSE;
}
if (g_fFirstInit)
{
g_sUDP = SSDPListen();
g_sUDPCancel = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (g_sUDP < 0 || g_sUDPCancel < 0) {
if (g_fLogging & NALOG_ERROR)
fprintf(log, "UpnpInit - Failed to init multicast socket.\n");
return NA_E_INTERNAL_ERROR;
}
pthread_attr_init(&attr);
iRet = pthread_create(&g_UDPthread, &attr, UDPProc, log);
if (iRet != 0) {
g_fFirstInit = TRUE; close(g_sUDP);
g_sUDP = -1;
if (g_fLogging & NALOG_ERROR)
fprintf(log, "UpnpInit - pthread create failed (%d)\n", iRet);
return NA_E_THREAD_ERROR;
}
g_fFirstInit = FALSE;
}
SendDiscoveryMsg();
return NA_E_SUCCESS;
}
int LegacyNATDestroy()
{
void *UDPThreadRetVal;
g_fQuit = TRUE;
if (g_sTCPCancel >= 0) close(g_sTCPCancel);
if (g_sUDPCancel >= 0) close(g_sUDPCancel);
pthread_join(g_UDPthread, &UDPThreadRetVal);
g_sTCPCancel = -1;
g_sUDPCancel = -1;
g_fFirstInit = TRUE;
g_fUPnPEnabled = FALSE;
g_fControlURLSet = FALSE;
return NA_E_SUCCESS;
}