A simple NAT library












5












$begingroup$


I've created a simple NAT library, with four essential functions:




  1. Find the UNPN device (the router in my case).

  2. Get the external IP address.

  3. Add a port forwarding entry.

  4. Delete a port forwarding entry.


Currently, updating an entry in the NAT table will change only the internal client ip address or the internal port, so to update an external port you have to delete it first then insert a new one.



TODO:




  1. Add other functionality (listing mapping entries, number of entries ...).

  2. Add support for other platforms.

  3. more testing if possible.


An example is included; just un-comment the part that you want to test. The library compiled and tested against Visual Studio 2008.



Any suggestions: optimization, coding style, bugs.



main.c:



#pragma comment(lib, "ws2_32.lib")

#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdio.h>

#if (_MSC_VER >= 1500)
#include <Strsafe.h>
#endif


#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))

#define TCP_PROTOCOL 0
#define UDP_PROTOCOL 1

#define INVALID_ARGS 402
#define ACTION_FAILED 501
#define ENTRY_MAPPING_NOTEXIST 714
#define INVALID_REMOTEHOST_IP 715
#define INVALID_REMOTEHOST_PORT 716
#define ENTRY_CONFLICT 718
#define SAME_PORT_REQUIRED 724
#define ONLY_PERMANENT_LEASE 725
#define OWILDCARD_IP_REQUIRED 726
#define OWILDCARD_PORT_REQUIRED 727


int boradcastDiscovery(char *upnpDeviceIp);
int getExternalpAddress(char *upnpDeviceIp, char *localIp, char *externalIpAddress);
int addPortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int internalPort, int protocol, char *internalp, char *entryDescription);
int deletePortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int protocol);

int main() {
char buf[512],
ipAddress[16];
int errorCode = 0;

/*ZeroMemory(ipAddress, 16);
boradcastDiscovery(ipAddress);

printf("UPNP device IP: %sn", ipAddress);*/

/*ZeroMemory(ipAddress, 16);
errorCode = getExternalpAddress("192.168.1.1", "192.168.1.4", ipAddress);
switch(errorCode) {
case INVALID_ARGS:
printf("Invalid query arg's.n");
break;
case ACTION_FAILED:
printf("Query failed to get external IP.n");
break;
default:
printf("External IP address: %sn", ipAddress);
break;
}*/

/*ZeroMemory(ipAddress, 16);
errorCode = addPortForwardEntry("192.168.1.1", "192.168.1.4", 9000, 4000, TCP_PROTOCOL, "192.168.1.7", "TEST FROM LIBRARY");
switch(errorCode) {
case INVALID_ARGS:
printf("Invalid query arg's.n");
break;
case ACTION_FAILED:
printf("Query failed to add entry mapping.n");
break;
case INVALID_REMOTEHOST_IP:
printf("Invalid IP address.n");
break;
case INVALID_REMOTEHOST_PORT:
printf("Invalid Port number.n");
break;
case ENTRY_CONFLICT:
printf("Such entry already exist.n");
break;
case SAME_PORT_REQUIRED:
printf("External and internal port must be the same.n");
break;
case ONLY_PERMANENT_LEASE:
printf("External and internal port must be the same.n");
break;
case OWILDCARD_IP_REQUIRED:
printf("External and internal port must be the same.n");
break;
case OWILDCARD_PORT_REQUIRED:
printf("External and internal port must be the same.n");
break;
default:
printf("Port mapping entry added sussccefully.n");
break;
}*/

/*ZeroMemory(ipAddress, 16);
errorCode = deletePortForwardEntry("192.168.1.1", "192.168.1.2", 5000, TCP_PROTOCOL);
switch(errorCode) {
case INVALID_ARGS:
printf("Invalid query arg's.n");
break;
case ACTION_FAILED:
printf("Query failed to add entry mapping.n");
break;
case ENTRY_MAPPING_NOTEXIST:
printf("Entry mapping doesn't exist.n");
break;
default:
printf("Port mapping entry deleted sussccefully.n");
break;
}*/


while(1)
;
return 0;
}


UpNp discover:



int boradcastDiscovery(char *upnpDeviceIp) {
char *searchIGDevice = "M-SEARCH * HTTP/1.1rnHost:239.255.255.250:1900rnST:urn:schemas-upnp-org:device:InternetGatewayDevice:1rnMan:"ssdp:discover"rnMX:3rnrn",
buf[512];
int result = -1;
WSADATA wsaData;
struct sockaddr_in upnpControl,
broadcast_addr;

result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET)
return WSAGetLastError();

if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, searchIGDevice, sizeof(searchIGDevice)) == SOCKET_ERROR)
return WSAGetLastError();

upnpControl.sin_family = AF_INET;
upnpControl.sin_port = htons(0);
upnpControl.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR)
return WSAGetLastError();

broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_port = htons(1900);
broadcast_addr.sin_addr.s_addr = inet_addr("239.255.255.250");

if(sendto(sock, searchIGDevice, lstrlen(searchIGDevice)+1, 0, (sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) == SOCKET_ERROR)
return WSAGetLastError();

int bcLen = sizeof(broadcast_addr);
ZeroMemory(buf, 512);
if(recvfrom(sock, buf, 512, 0, (sockaddr *)&broadcast_addr, &bcLen) < 0)
return WSAGetLastError();
else {
closesocket(sock);
WSACleanup();
if(strstr(buf, "device:InternetGatewayDevice")) {
int i = 0;
char *deviceIp = strstr(buf, "http://") + 7;
while(*deviceIp != ':') {
upnpDeviceIp[i] = *deviceIp;
*deviceIp++;
++i;
}

return 0;
}
else
return -1;
}
}


Get external IP address:



int getExternalpAddress(char *upnpDeviceIp, char *localIp, char *externalIpAddress) {
WSADATA wsaData;
struct sockaddr_in upnpControl,
upnpDevice;
int i = 0,
j = 0,
result = -1,
bodyLen = 0;
char c,
*tmp = NULL,
*pLen = NULL,
*bodyResponse = NULL, // a pointer to HTTP body response
pBodyLen[5],
responseHeader[512],
getExternalIpRequest[622];
int reuseAddress = 1;

// A SOAP request to get external IP address
ZeroMemory(getExternalIpRequest, 622);
StringCbPrintf(getExternalIpRequest, 622,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: 303rn"
"Connection: Closern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn"
"<?xml version="1.0"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">"
"<SOAP-ENV:Body>"
"<m:GetExternalIPAddress xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1"/>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>rnrn", upnpDeviceIp);
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseAddress, sizeof(reuseAddress)) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(&upnpControl, sizeof(upnpControl));
upnpControl.sin_family = AF_INET;
if(localIp == NULL)
upnpControl.sin_addr.s_addr = INADDR_ANY;
else
upnpControl.sin_addr.s_addr = inet_addr(localIp);



ZeroMemory(&upnpDevice, sizeof(upnpDevice));
upnpDevice.sin_family = AF_INET;
upnpDevice.sin_port = htons(80);
upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(struct sockaddr)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, getExternalIpRequest, lstrlen(getExternalIpRequest), 0) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(responseHeader, 512);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
// We got the http header, extract the body length from it
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'r') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen);
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;

if(j == bodyLen) { // We got the HTTP body
closesocket(sock);
}
}
}

++i;
}

i = 0;
tmp = strstr(bodyResponse, "<NewExternalIPAddress>") + 22;
ZeroMemory(externalIpAddress, 16);
while(*tmp != '<') {
externalIpAddress[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
WSACleanup();
return 0;
}


Add port forward entry:



int addPortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int internalPort, 
int protocol, char *internalp, char *entryDescription) {
WSADATA wsaData;
struct sockaddr_in upnpControl, upnpDevice;
int i = 0,
j = 0,
result = -1,
bodyLen = 0,
numErrorCode = 0;
char c,
*pLen = NULL,
*proto = NULL,
*bodyResponse = NULL,
pBodyLen[5],
responseHeader[2000],
addForwardEntryRequest[1200],
addForwardEntryRequestHeader[1500];

proto = (char *)MALLOC(4);
ZeroMemory(proto, 4);
if(protocol == TCP_PROTOCOL)
StringCbPrintf(proto, 4, "TCP");
else
StringCbPrintf(proto, 4, "UDP");

// A SOAP request to insert a port forwarding entry
ZeroMemory(addForwardEntryRequest, 1200);
ZeroMemory(addForwardEntryRequestHeader, 1500);
StringCbPrintf(addForwardEntryRequest, 1200,
"<?xml version="1.0"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">"
"<SOAP-ENV:Body>"
"<m:AddPortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">"
"<NewRemoteHost>"
""
"</NewRemoteHost>"
"<NewExternalPort>"
"%d"
"</NewExternalPort>"
"<NewProtocol>"
"%s"
"</NewProtocol>"
"<NewInternalPort>"
"%d"
"</NewInternalPort>"
"<NewInternalClient>"
"%s"
"</NewInternalClient>"
"<NewEnabled>"
"1"
"</NewEnabled>"
"<NewPortMappingDescription>"
"%s"
"</NewPortMappingDescription>"
"<NewLeaseDuration>"
"0"
"</NewLeaseDuration>"
"</m:AddPortMapping>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>rnrn", externalPort, proto, internalPort, internalp, entryDescription);

StringCbPrintf(addForwardEntryRequestHeader, 1500,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: %drn"
"Connection: Closern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn", upnpDeviceIp, lstrlen(addForwardEntryRequest));
StringCchCat(addForwardEntryRequestHeader, 1500, addForwardEntryRequest);
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

ZeroMemory(&upnpControl, sizeof(upnpControl));
upnpControl.sin_family = AF_INET;
if(localIp == NULL)
upnpControl.sin_addr.s_addr = INADDR_ANY;
else
upnpControl.sin_addr.s_addr = inet_addr(localIp);

upnpControl.sin_port = 0;
ZeroMemory(&upnpDevice, sizeof(upnpDevice));
upnpDevice.sin_family = AF_INET;
upnpDevice.sin_port = htons(80);
upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(upnpDevice)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, addForwardEntryRequestHeader, lstrlen(addForwardEntryRequestHeader), 0) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(responseHeader, 2000);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'n') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen); // body length
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
ZeroMemory(bodyResponse, bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;
if(j == bodyLen) {
closesocket(sock);
}
}
}

++i;
}

// Check if uPnp reject our entry
i = 0;
if(strstr(bodyResponse, "<errorCode>")) {
char errorCode[3],
*tmp = strstr(bodyResponse, "<errorCode>") + 11;

while(*tmp != '<') {
errorCode[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
numErrorCode = atoi(errorCode);
return numErrorCode;
}

// Check the entry that we insert if is exist in the mapping table
ZeroMemory(addForwardEntryRequest, 1200);
ZeroMemory(addForwardEntryRequestHeader, 1500);
StringCbPrintf(addForwardEntryRequest, 1200,
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">rn"
"<SOAP-ENV:Body>rn"
"<m:GetSpecificPortMappingEntry xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">rn"
"<NewRemoteHost/>rn"
"<NewExternalPort>%d</NewExternalPort>rn"
"<NewProtocol>%s</NewProtocol>rn"
"</m:GetSpecificPortMappingEntry>rn"
"</SOAP-ENV:Body>rn"
"</SOAP-ENV:Envelope>rnrn", externalPort, proto);
StringCbPrintf(addForwardEntryRequestHeader, 1500,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#GetSpecificPortMappingEntry"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: %drn"
"Connection: Closern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn", upnpDeviceIp, lstrlen(addForwardEntryRequest));
StringCchCat(addForwardEntryRequestHeader, 1500, addForwardEntryRequest);
sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(upnpDevice)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, addForwardEntryRequestHeader, lstrlen(addForwardEntryRequestHeader), 0) == SOCKET_ERROR)
return WSAGetLastError();

i = 0;
ZeroMemory(responseHeader, 2000);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
j = 0;
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'n') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen);
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
ZeroMemory(bodyResponse, bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;
if(j == bodyLen) {
closesocket(sock);
WSACleanup();
}
}
}

++i;
}

// Check if the request rejected
i = 0;
if(strstr(bodyResponse, "<errorCode>")) {
char errorCode[3],
*tmp = strstr(bodyResponse, "<errorCode>") + 11;

while(*tmp != '<') {
errorCode[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
numErrorCode = atoi(errorCode);
return numErrorCode;
}

return 0;
}


Delete port forward entry:



int deletePortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int protocol) {
WSADATA wsaData;
struct sockaddr_in upnpControl, upnpDevice;
int i = 0,
j = 0,
result = -1,
bodyLen = 0,
numErrorCode = 0;
char c,
*pLen = NULL,
*proto = NULL,
*bodyResponse = NULL,
pBodyLen[5],
responseHeader[700],
deleteForwardEntryRequest[700],
deleteForwardEntryRequestHeader[1000];

proto = (char *)MALLOC(4);
ZeroMemory(proto, 4);
if(protocol == TCP_PROTOCOL)
StringCbPrintf(proto, 4, "TCP");
else
StringCbPrintf(proto, 4, "UDP");

// A SOAP request to delete a mapping entry
ZeroMemory(deleteForwardEntryRequest, 700);
ZeroMemory(deleteForwardEntryRequestHeader, 1000);
StringCbPrintf(deleteForwardEntryRequest, 1200,
"<?xml version="1.0"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">"
"<SOAP-ENV:Body>"
"<m:DeletePortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">"
"<NewRemoteHost>"
""
"</NewRemoteHost>"
"<NewExternalPort>"
"%d"
"</NewExternalPort>"
"<NewProtocol>"
"%s"
"</NewProtocol>"
"</m:DeletePortMapping>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>rnrn", externalPort, proto);

StringCbPrintf(deleteForwardEntryRequestHeader, 1500,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: %drn"
"Connection: Keep-Alivern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn", upnpDeviceIp, lstrlen(deleteForwardEntryRequest));
StringCchCat(deleteForwardEntryRequestHeader, 1500, deleteForwardEntryRequest);
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

ZeroMemory(&upnpControl, sizeof(upnpControl));
upnpControl.sin_family = AF_INET;
if(localIp == NULL)
upnpControl.sin_addr.s_addr = INADDR_ANY;
else
upnpControl.sin_addr.s_addr = inet_addr(localIp);

upnpControl.sin_port = 0;
ZeroMemory(&upnpDevice, sizeof(upnpDevice));
upnpDevice.sin_family = AF_INET;
upnpDevice.sin_port = htons(80);
upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(upnpDevice)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, deleteForwardEntryRequestHeader, lstrlen(deleteForwardEntryRequestHeader), 0) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(responseHeader, 700);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
j = 0;
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'n') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen);
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
ZeroMemory(bodyResponse, bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;
if(j == bodyLen) {
closesocket(sock);
WSACleanup();
}
}
}

++i;
}

// Check f our request rejected
i = 0;
if(strstr(bodyResponse, "<errorCode>")) {
char errorCode[3],
*tmp = strstr(bodyResponse, "<errorCode>") + 11;

while(*tmp != '<') {
errorCode[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
numErrorCode = atoi(errorCode);
return numErrorCode;
}
else
return 0;
}









share|improve this question











$endgroup$












  • $begingroup$
    I'd recommend splitting this code into separate blocks, or only include what's most necessary for review. Excessively-long code could discourage reviewing.
    $endgroup$
    – Jamal
    Nov 17 '13 at 21:49










  • $begingroup$
    @Jamal Do you mean splitting code by inserting each function in its own code tag?
    $endgroup$
    – SIFE
    Nov 17 '13 at 22:55










  • $begingroup$
    Only if this would work as separate questions. Otherwise, you could just have more than one block in this question, each with a short description of what's included.
    $endgroup$
    – Jamal
    Nov 17 '13 at 22:56






  • 1




    $begingroup$
    What's the point of main - it is just a while(1) loop with everything else commented out.
    $endgroup$
    – William Morris
    Nov 18 '13 at 1:06
















5












$begingroup$


I've created a simple NAT library, with four essential functions:




  1. Find the UNPN device (the router in my case).

  2. Get the external IP address.

  3. Add a port forwarding entry.

  4. Delete a port forwarding entry.


Currently, updating an entry in the NAT table will change only the internal client ip address or the internal port, so to update an external port you have to delete it first then insert a new one.



TODO:




  1. Add other functionality (listing mapping entries, number of entries ...).

  2. Add support for other platforms.

  3. more testing if possible.


An example is included; just un-comment the part that you want to test. The library compiled and tested against Visual Studio 2008.



Any suggestions: optimization, coding style, bugs.



main.c:



#pragma comment(lib, "ws2_32.lib")

#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdio.h>

#if (_MSC_VER >= 1500)
#include <Strsafe.h>
#endif


#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))

#define TCP_PROTOCOL 0
#define UDP_PROTOCOL 1

#define INVALID_ARGS 402
#define ACTION_FAILED 501
#define ENTRY_MAPPING_NOTEXIST 714
#define INVALID_REMOTEHOST_IP 715
#define INVALID_REMOTEHOST_PORT 716
#define ENTRY_CONFLICT 718
#define SAME_PORT_REQUIRED 724
#define ONLY_PERMANENT_LEASE 725
#define OWILDCARD_IP_REQUIRED 726
#define OWILDCARD_PORT_REQUIRED 727


int boradcastDiscovery(char *upnpDeviceIp);
int getExternalpAddress(char *upnpDeviceIp, char *localIp, char *externalIpAddress);
int addPortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int internalPort, int protocol, char *internalp, char *entryDescription);
int deletePortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int protocol);

int main() {
char buf[512],
ipAddress[16];
int errorCode = 0;

/*ZeroMemory(ipAddress, 16);
boradcastDiscovery(ipAddress);

printf("UPNP device IP: %sn", ipAddress);*/

/*ZeroMemory(ipAddress, 16);
errorCode = getExternalpAddress("192.168.1.1", "192.168.1.4", ipAddress);
switch(errorCode) {
case INVALID_ARGS:
printf("Invalid query arg's.n");
break;
case ACTION_FAILED:
printf("Query failed to get external IP.n");
break;
default:
printf("External IP address: %sn", ipAddress);
break;
}*/

/*ZeroMemory(ipAddress, 16);
errorCode = addPortForwardEntry("192.168.1.1", "192.168.1.4", 9000, 4000, TCP_PROTOCOL, "192.168.1.7", "TEST FROM LIBRARY");
switch(errorCode) {
case INVALID_ARGS:
printf("Invalid query arg's.n");
break;
case ACTION_FAILED:
printf("Query failed to add entry mapping.n");
break;
case INVALID_REMOTEHOST_IP:
printf("Invalid IP address.n");
break;
case INVALID_REMOTEHOST_PORT:
printf("Invalid Port number.n");
break;
case ENTRY_CONFLICT:
printf("Such entry already exist.n");
break;
case SAME_PORT_REQUIRED:
printf("External and internal port must be the same.n");
break;
case ONLY_PERMANENT_LEASE:
printf("External and internal port must be the same.n");
break;
case OWILDCARD_IP_REQUIRED:
printf("External and internal port must be the same.n");
break;
case OWILDCARD_PORT_REQUIRED:
printf("External and internal port must be the same.n");
break;
default:
printf("Port mapping entry added sussccefully.n");
break;
}*/

/*ZeroMemory(ipAddress, 16);
errorCode = deletePortForwardEntry("192.168.1.1", "192.168.1.2", 5000, TCP_PROTOCOL);
switch(errorCode) {
case INVALID_ARGS:
printf("Invalid query arg's.n");
break;
case ACTION_FAILED:
printf("Query failed to add entry mapping.n");
break;
case ENTRY_MAPPING_NOTEXIST:
printf("Entry mapping doesn't exist.n");
break;
default:
printf("Port mapping entry deleted sussccefully.n");
break;
}*/


while(1)
;
return 0;
}


UpNp discover:



int boradcastDiscovery(char *upnpDeviceIp) {
char *searchIGDevice = "M-SEARCH * HTTP/1.1rnHost:239.255.255.250:1900rnST:urn:schemas-upnp-org:device:InternetGatewayDevice:1rnMan:"ssdp:discover"rnMX:3rnrn",
buf[512];
int result = -1;
WSADATA wsaData;
struct sockaddr_in upnpControl,
broadcast_addr;

result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET)
return WSAGetLastError();

if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, searchIGDevice, sizeof(searchIGDevice)) == SOCKET_ERROR)
return WSAGetLastError();

upnpControl.sin_family = AF_INET;
upnpControl.sin_port = htons(0);
upnpControl.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR)
return WSAGetLastError();

broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_port = htons(1900);
broadcast_addr.sin_addr.s_addr = inet_addr("239.255.255.250");

if(sendto(sock, searchIGDevice, lstrlen(searchIGDevice)+1, 0, (sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) == SOCKET_ERROR)
return WSAGetLastError();

int bcLen = sizeof(broadcast_addr);
ZeroMemory(buf, 512);
if(recvfrom(sock, buf, 512, 0, (sockaddr *)&broadcast_addr, &bcLen) < 0)
return WSAGetLastError();
else {
closesocket(sock);
WSACleanup();
if(strstr(buf, "device:InternetGatewayDevice")) {
int i = 0;
char *deviceIp = strstr(buf, "http://") + 7;
while(*deviceIp != ':') {
upnpDeviceIp[i] = *deviceIp;
*deviceIp++;
++i;
}

return 0;
}
else
return -1;
}
}


Get external IP address:



int getExternalpAddress(char *upnpDeviceIp, char *localIp, char *externalIpAddress) {
WSADATA wsaData;
struct sockaddr_in upnpControl,
upnpDevice;
int i = 0,
j = 0,
result = -1,
bodyLen = 0;
char c,
*tmp = NULL,
*pLen = NULL,
*bodyResponse = NULL, // a pointer to HTTP body response
pBodyLen[5],
responseHeader[512],
getExternalIpRequest[622];
int reuseAddress = 1;

// A SOAP request to get external IP address
ZeroMemory(getExternalIpRequest, 622);
StringCbPrintf(getExternalIpRequest, 622,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: 303rn"
"Connection: Closern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn"
"<?xml version="1.0"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">"
"<SOAP-ENV:Body>"
"<m:GetExternalIPAddress xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1"/>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>rnrn", upnpDeviceIp);
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseAddress, sizeof(reuseAddress)) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(&upnpControl, sizeof(upnpControl));
upnpControl.sin_family = AF_INET;
if(localIp == NULL)
upnpControl.sin_addr.s_addr = INADDR_ANY;
else
upnpControl.sin_addr.s_addr = inet_addr(localIp);



ZeroMemory(&upnpDevice, sizeof(upnpDevice));
upnpDevice.sin_family = AF_INET;
upnpDevice.sin_port = htons(80);
upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(struct sockaddr)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, getExternalIpRequest, lstrlen(getExternalIpRequest), 0) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(responseHeader, 512);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
// We got the http header, extract the body length from it
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'r') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen);
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;

if(j == bodyLen) { // We got the HTTP body
closesocket(sock);
}
}
}

++i;
}

i = 0;
tmp = strstr(bodyResponse, "<NewExternalIPAddress>") + 22;
ZeroMemory(externalIpAddress, 16);
while(*tmp != '<') {
externalIpAddress[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
WSACleanup();
return 0;
}


Add port forward entry:



int addPortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int internalPort, 
int protocol, char *internalp, char *entryDescription) {
WSADATA wsaData;
struct sockaddr_in upnpControl, upnpDevice;
int i = 0,
j = 0,
result = -1,
bodyLen = 0,
numErrorCode = 0;
char c,
*pLen = NULL,
*proto = NULL,
*bodyResponse = NULL,
pBodyLen[5],
responseHeader[2000],
addForwardEntryRequest[1200],
addForwardEntryRequestHeader[1500];

proto = (char *)MALLOC(4);
ZeroMemory(proto, 4);
if(protocol == TCP_PROTOCOL)
StringCbPrintf(proto, 4, "TCP");
else
StringCbPrintf(proto, 4, "UDP");

// A SOAP request to insert a port forwarding entry
ZeroMemory(addForwardEntryRequest, 1200);
ZeroMemory(addForwardEntryRequestHeader, 1500);
StringCbPrintf(addForwardEntryRequest, 1200,
"<?xml version="1.0"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">"
"<SOAP-ENV:Body>"
"<m:AddPortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">"
"<NewRemoteHost>"
""
"</NewRemoteHost>"
"<NewExternalPort>"
"%d"
"</NewExternalPort>"
"<NewProtocol>"
"%s"
"</NewProtocol>"
"<NewInternalPort>"
"%d"
"</NewInternalPort>"
"<NewInternalClient>"
"%s"
"</NewInternalClient>"
"<NewEnabled>"
"1"
"</NewEnabled>"
"<NewPortMappingDescription>"
"%s"
"</NewPortMappingDescription>"
"<NewLeaseDuration>"
"0"
"</NewLeaseDuration>"
"</m:AddPortMapping>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>rnrn", externalPort, proto, internalPort, internalp, entryDescription);

StringCbPrintf(addForwardEntryRequestHeader, 1500,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: %drn"
"Connection: Closern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn", upnpDeviceIp, lstrlen(addForwardEntryRequest));
StringCchCat(addForwardEntryRequestHeader, 1500, addForwardEntryRequest);
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

ZeroMemory(&upnpControl, sizeof(upnpControl));
upnpControl.sin_family = AF_INET;
if(localIp == NULL)
upnpControl.sin_addr.s_addr = INADDR_ANY;
else
upnpControl.sin_addr.s_addr = inet_addr(localIp);

upnpControl.sin_port = 0;
ZeroMemory(&upnpDevice, sizeof(upnpDevice));
upnpDevice.sin_family = AF_INET;
upnpDevice.sin_port = htons(80);
upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(upnpDevice)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, addForwardEntryRequestHeader, lstrlen(addForwardEntryRequestHeader), 0) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(responseHeader, 2000);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'n') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen); // body length
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
ZeroMemory(bodyResponse, bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;
if(j == bodyLen) {
closesocket(sock);
}
}
}

++i;
}

// Check if uPnp reject our entry
i = 0;
if(strstr(bodyResponse, "<errorCode>")) {
char errorCode[3],
*tmp = strstr(bodyResponse, "<errorCode>") + 11;

while(*tmp != '<') {
errorCode[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
numErrorCode = atoi(errorCode);
return numErrorCode;
}

// Check the entry that we insert if is exist in the mapping table
ZeroMemory(addForwardEntryRequest, 1200);
ZeroMemory(addForwardEntryRequestHeader, 1500);
StringCbPrintf(addForwardEntryRequest, 1200,
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">rn"
"<SOAP-ENV:Body>rn"
"<m:GetSpecificPortMappingEntry xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">rn"
"<NewRemoteHost/>rn"
"<NewExternalPort>%d</NewExternalPort>rn"
"<NewProtocol>%s</NewProtocol>rn"
"</m:GetSpecificPortMappingEntry>rn"
"</SOAP-ENV:Body>rn"
"</SOAP-ENV:Envelope>rnrn", externalPort, proto);
StringCbPrintf(addForwardEntryRequestHeader, 1500,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#GetSpecificPortMappingEntry"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: %drn"
"Connection: Closern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn", upnpDeviceIp, lstrlen(addForwardEntryRequest));
StringCchCat(addForwardEntryRequestHeader, 1500, addForwardEntryRequest);
sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(upnpDevice)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, addForwardEntryRequestHeader, lstrlen(addForwardEntryRequestHeader), 0) == SOCKET_ERROR)
return WSAGetLastError();

i = 0;
ZeroMemory(responseHeader, 2000);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
j = 0;
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'n') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen);
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
ZeroMemory(bodyResponse, bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;
if(j == bodyLen) {
closesocket(sock);
WSACleanup();
}
}
}

++i;
}

// Check if the request rejected
i = 0;
if(strstr(bodyResponse, "<errorCode>")) {
char errorCode[3],
*tmp = strstr(bodyResponse, "<errorCode>") + 11;

while(*tmp != '<') {
errorCode[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
numErrorCode = atoi(errorCode);
return numErrorCode;
}

return 0;
}


Delete port forward entry:



int deletePortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int protocol) {
WSADATA wsaData;
struct sockaddr_in upnpControl, upnpDevice;
int i = 0,
j = 0,
result = -1,
bodyLen = 0,
numErrorCode = 0;
char c,
*pLen = NULL,
*proto = NULL,
*bodyResponse = NULL,
pBodyLen[5],
responseHeader[700],
deleteForwardEntryRequest[700],
deleteForwardEntryRequestHeader[1000];

proto = (char *)MALLOC(4);
ZeroMemory(proto, 4);
if(protocol == TCP_PROTOCOL)
StringCbPrintf(proto, 4, "TCP");
else
StringCbPrintf(proto, 4, "UDP");

// A SOAP request to delete a mapping entry
ZeroMemory(deleteForwardEntryRequest, 700);
ZeroMemory(deleteForwardEntryRequestHeader, 1000);
StringCbPrintf(deleteForwardEntryRequest, 1200,
"<?xml version="1.0"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">"
"<SOAP-ENV:Body>"
"<m:DeletePortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">"
"<NewRemoteHost>"
""
"</NewRemoteHost>"
"<NewExternalPort>"
"%d"
"</NewExternalPort>"
"<NewProtocol>"
"%s"
"</NewProtocol>"
"</m:DeletePortMapping>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>rnrn", externalPort, proto);

StringCbPrintf(deleteForwardEntryRequestHeader, 1500,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: %drn"
"Connection: Keep-Alivern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn", upnpDeviceIp, lstrlen(deleteForwardEntryRequest));
StringCchCat(deleteForwardEntryRequestHeader, 1500, deleteForwardEntryRequest);
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

ZeroMemory(&upnpControl, sizeof(upnpControl));
upnpControl.sin_family = AF_INET;
if(localIp == NULL)
upnpControl.sin_addr.s_addr = INADDR_ANY;
else
upnpControl.sin_addr.s_addr = inet_addr(localIp);

upnpControl.sin_port = 0;
ZeroMemory(&upnpDevice, sizeof(upnpDevice));
upnpDevice.sin_family = AF_INET;
upnpDevice.sin_port = htons(80);
upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(upnpDevice)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, deleteForwardEntryRequestHeader, lstrlen(deleteForwardEntryRequestHeader), 0) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(responseHeader, 700);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
j = 0;
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'n') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen);
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
ZeroMemory(bodyResponse, bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;
if(j == bodyLen) {
closesocket(sock);
WSACleanup();
}
}
}

++i;
}

// Check f our request rejected
i = 0;
if(strstr(bodyResponse, "<errorCode>")) {
char errorCode[3],
*tmp = strstr(bodyResponse, "<errorCode>") + 11;

while(*tmp != '<') {
errorCode[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
numErrorCode = atoi(errorCode);
return numErrorCode;
}
else
return 0;
}









share|improve this question











$endgroup$












  • $begingroup$
    I'd recommend splitting this code into separate blocks, or only include what's most necessary for review. Excessively-long code could discourage reviewing.
    $endgroup$
    – Jamal
    Nov 17 '13 at 21:49










  • $begingroup$
    @Jamal Do you mean splitting code by inserting each function in its own code tag?
    $endgroup$
    – SIFE
    Nov 17 '13 at 22:55










  • $begingroup$
    Only if this would work as separate questions. Otherwise, you could just have more than one block in this question, each with a short description of what's included.
    $endgroup$
    – Jamal
    Nov 17 '13 at 22:56






  • 1




    $begingroup$
    What's the point of main - it is just a while(1) loop with everything else commented out.
    $endgroup$
    – William Morris
    Nov 18 '13 at 1:06














5












5








5


1



$begingroup$


I've created a simple NAT library, with four essential functions:




  1. Find the UNPN device (the router in my case).

  2. Get the external IP address.

  3. Add a port forwarding entry.

  4. Delete a port forwarding entry.


Currently, updating an entry in the NAT table will change only the internal client ip address or the internal port, so to update an external port you have to delete it first then insert a new one.



TODO:




  1. Add other functionality (listing mapping entries, number of entries ...).

  2. Add support for other platforms.

  3. more testing if possible.


An example is included; just un-comment the part that you want to test. The library compiled and tested against Visual Studio 2008.



Any suggestions: optimization, coding style, bugs.



main.c:



#pragma comment(lib, "ws2_32.lib")

#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdio.h>

#if (_MSC_VER >= 1500)
#include <Strsafe.h>
#endif


#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))

#define TCP_PROTOCOL 0
#define UDP_PROTOCOL 1

#define INVALID_ARGS 402
#define ACTION_FAILED 501
#define ENTRY_MAPPING_NOTEXIST 714
#define INVALID_REMOTEHOST_IP 715
#define INVALID_REMOTEHOST_PORT 716
#define ENTRY_CONFLICT 718
#define SAME_PORT_REQUIRED 724
#define ONLY_PERMANENT_LEASE 725
#define OWILDCARD_IP_REQUIRED 726
#define OWILDCARD_PORT_REQUIRED 727


int boradcastDiscovery(char *upnpDeviceIp);
int getExternalpAddress(char *upnpDeviceIp, char *localIp, char *externalIpAddress);
int addPortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int internalPort, int protocol, char *internalp, char *entryDescription);
int deletePortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int protocol);

int main() {
char buf[512],
ipAddress[16];
int errorCode = 0;

/*ZeroMemory(ipAddress, 16);
boradcastDiscovery(ipAddress);

printf("UPNP device IP: %sn", ipAddress);*/

/*ZeroMemory(ipAddress, 16);
errorCode = getExternalpAddress("192.168.1.1", "192.168.1.4", ipAddress);
switch(errorCode) {
case INVALID_ARGS:
printf("Invalid query arg's.n");
break;
case ACTION_FAILED:
printf("Query failed to get external IP.n");
break;
default:
printf("External IP address: %sn", ipAddress);
break;
}*/

/*ZeroMemory(ipAddress, 16);
errorCode = addPortForwardEntry("192.168.1.1", "192.168.1.4", 9000, 4000, TCP_PROTOCOL, "192.168.1.7", "TEST FROM LIBRARY");
switch(errorCode) {
case INVALID_ARGS:
printf("Invalid query arg's.n");
break;
case ACTION_FAILED:
printf("Query failed to add entry mapping.n");
break;
case INVALID_REMOTEHOST_IP:
printf("Invalid IP address.n");
break;
case INVALID_REMOTEHOST_PORT:
printf("Invalid Port number.n");
break;
case ENTRY_CONFLICT:
printf("Such entry already exist.n");
break;
case SAME_PORT_REQUIRED:
printf("External and internal port must be the same.n");
break;
case ONLY_PERMANENT_LEASE:
printf("External and internal port must be the same.n");
break;
case OWILDCARD_IP_REQUIRED:
printf("External and internal port must be the same.n");
break;
case OWILDCARD_PORT_REQUIRED:
printf("External and internal port must be the same.n");
break;
default:
printf("Port mapping entry added sussccefully.n");
break;
}*/

/*ZeroMemory(ipAddress, 16);
errorCode = deletePortForwardEntry("192.168.1.1", "192.168.1.2", 5000, TCP_PROTOCOL);
switch(errorCode) {
case INVALID_ARGS:
printf("Invalid query arg's.n");
break;
case ACTION_FAILED:
printf("Query failed to add entry mapping.n");
break;
case ENTRY_MAPPING_NOTEXIST:
printf("Entry mapping doesn't exist.n");
break;
default:
printf("Port mapping entry deleted sussccefully.n");
break;
}*/


while(1)
;
return 0;
}


UpNp discover:



int boradcastDiscovery(char *upnpDeviceIp) {
char *searchIGDevice = "M-SEARCH * HTTP/1.1rnHost:239.255.255.250:1900rnST:urn:schemas-upnp-org:device:InternetGatewayDevice:1rnMan:"ssdp:discover"rnMX:3rnrn",
buf[512];
int result = -1;
WSADATA wsaData;
struct sockaddr_in upnpControl,
broadcast_addr;

result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET)
return WSAGetLastError();

if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, searchIGDevice, sizeof(searchIGDevice)) == SOCKET_ERROR)
return WSAGetLastError();

upnpControl.sin_family = AF_INET;
upnpControl.sin_port = htons(0);
upnpControl.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR)
return WSAGetLastError();

broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_port = htons(1900);
broadcast_addr.sin_addr.s_addr = inet_addr("239.255.255.250");

if(sendto(sock, searchIGDevice, lstrlen(searchIGDevice)+1, 0, (sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) == SOCKET_ERROR)
return WSAGetLastError();

int bcLen = sizeof(broadcast_addr);
ZeroMemory(buf, 512);
if(recvfrom(sock, buf, 512, 0, (sockaddr *)&broadcast_addr, &bcLen) < 0)
return WSAGetLastError();
else {
closesocket(sock);
WSACleanup();
if(strstr(buf, "device:InternetGatewayDevice")) {
int i = 0;
char *deviceIp = strstr(buf, "http://") + 7;
while(*deviceIp != ':') {
upnpDeviceIp[i] = *deviceIp;
*deviceIp++;
++i;
}

return 0;
}
else
return -1;
}
}


Get external IP address:



int getExternalpAddress(char *upnpDeviceIp, char *localIp, char *externalIpAddress) {
WSADATA wsaData;
struct sockaddr_in upnpControl,
upnpDevice;
int i = 0,
j = 0,
result = -1,
bodyLen = 0;
char c,
*tmp = NULL,
*pLen = NULL,
*bodyResponse = NULL, // a pointer to HTTP body response
pBodyLen[5],
responseHeader[512],
getExternalIpRequest[622];
int reuseAddress = 1;

// A SOAP request to get external IP address
ZeroMemory(getExternalIpRequest, 622);
StringCbPrintf(getExternalIpRequest, 622,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: 303rn"
"Connection: Closern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn"
"<?xml version="1.0"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">"
"<SOAP-ENV:Body>"
"<m:GetExternalIPAddress xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1"/>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>rnrn", upnpDeviceIp);
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseAddress, sizeof(reuseAddress)) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(&upnpControl, sizeof(upnpControl));
upnpControl.sin_family = AF_INET;
if(localIp == NULL)
upnpControl.sin_addr.s_addr = INADDR_ANY;
else
upnpControl.sin_addr.s_addr = inet_addr(localIp);



ZeroMemory(&upnpDevice, sizeof(upnpDevice));
upnpDevice.sin_family = AF_INET;
upnpDevice.sin_port = htons(80);
upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(struct sockaddr)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, getExternalIpRequest, lstrlen(getExternalIpRequest), 0) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(responseHeader, 512);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
// We got the http header, extract the body length from it
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'r') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen);
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;

if(j == bodyLen) { // We got the HTTP body
closesocket(sock);
}
}
}

++i;
}

i = 0;
tmp = strstr(bodyResponse, "<NewExternalIPAddress>") + 22;
ZeroMemory(externalIpAddress, 16);
while(*tmp != '<') {
externalIpAddress[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
WSACleanup();
return 0;
}


Add port forward entry:



int addPortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int internalPort, 
int protocol, char *internalp, char *entryDescription) {
WSADATA wsaData;
struct sockaddr_in upnpControl, upnpDevice;
int i = 0,
j = 0,
result = -1,
bodyLen = 0,
numErrorCode = 0;
char c,
*pLen = NULL,
*proto = NULL,
*bodyResponse = NULL,
pBodyLen[5],
responseHeader[2000],
addForwardEntryRequest[1200],
addForwardEntryRequestHeader[1500];

proto = (char *)MALLOC(4);
ZeroMemory(proto, 4);
if(protocol == TCP_PROTOCOL)
StringCbPrintf(proto, 4, "TCP");
else
StringCbPrintf(proto, 4, "UDP");

// A SOAP request to insert a port forwarding entry
ZeroMemory(addForwardEntryRequest, 1200);
ZeroMemory(addForwardEntryRequestHeader, 1500);
StringCbPrintf(addForwardEntryRequest, 1200,
"<?xml version="1.0"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">"
"<SOAP-ENV:Body>"
"<m:AddPortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">"
"<NewRemoteHost>"
""
"</NewRemoteHost>"
"<NewExternalPort>"
"%d"
"</NewExternalPort>"
"<NewProtocol>"
"%s"
"</NewProtocol>"
"<NewInternalPort>"
"%d"
"</NewInternalPort>"
"<NewInternalClient>"
"%s"
"</NewInternalClient>"
"<NewEnabled>"
"1"
"</NewEnabled>"
"<NewPortMappingDescription>"
"%s"
"</NewPortMappingDescription>"
"<NewLeaseDuration>"
"0"
"</NewLeaseDuration>"
"</m:AddPortMapping>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>rnrn", externalPort, proto, internalPort, internalp, entryDescription);

StringCbPrintf(addForwardEntryRequestHeader, 1500,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: %drn"
"Connection: Closern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn", upnpDeviceIp, lstrlen(addForwardEntryRequest));
StringCchCat(addForwardEntryRequestHeader, 1500, addForwardEntryRequest);
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

ZeroMemory(&upnpControl, sizeof(upnpControl));
upnpControl.sin_family = AF_INET;
if(localIp == NULL)
upnpControl.sin_addr.s_addr = INADDR_ANY;
else
upnpControl.sin_addr.s_addr = inet_addr(localIp);

upnpControl.sin_port = 0;
ZeroMemory(&upnpDevice, sizeof(upnpDevice));
upnpDevice.sin_family = AF_INET;
upnpDevice.sin_port = htons(80);
upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(upnpDevice)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, addForwardEntryRequestHeader, lstrlen(addForwardEntryRequestHeader), 0) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(responseHeader, 2000);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'n') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen); // body length
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
ZeroMemory(bodyResponse, bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;
if(j == bodyLen) {
closesocket(sock);
}
}
}

++i;
}

// Check if uPnp reject our entry
i = 0;
if(strstr(bodyResponse, "<errorCode>")) {
char errorCode[3],
*tmp = strstr(bodyResponse, "<errorCode>") + 11;

while(*tmp != '<') {
errorCode[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
numErrorCode = atoi(errorCode);
return numErrorCode;
}

// Check the entry that we insert if is exist in the mapping table
ZeroMemory(addForwardEntryRequest, 1200);
ZeroMemory(addForwardEntryRequestHeader, 1500);
StringCbPrintf(addForwardEntryRequest, 1200,
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">rn"
"<SOAP-ENV:Body>rn"
"<m:GetSpecificPortMappingEntry xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">rn"
"<NewRemoteHost/>rn"
"<NewExternalPort>%d</NewExternalPort>rn"
"<NewProtocol>%s</NewProtocol>rn"
"</m:GetSpecificPortMappingEntry>rn"
"</SOAP-ENV:Body>rn"
"</SOAP-ENV:Envelope>rnrn", externalPort, proto);
StringCbPrintf(addForwardEntryRequestHeader, 1500,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#GetSpecificPortMappingEntry"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: %drn"
"Connection: Closern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn", upnpDeviceIp, lstrlen(addForwardEntryRequest));
StringCchCat(addForwardEntryRequestHeader, 1500, addForwardEntryRequest);
sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(upnpDevice)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, addForwardEntryRequestHeader, lstrlen(addForwardEntryRequestHeader), 0) == SOCKET_ERROR)
return WSAGetLastError();

i = 0;
ZeroMemory(responseHeader, 2000);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
j = 0;
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'n') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen);
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
ZeroMemory(bodyResponse, bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;
if(j == bodyLen) {
closesocket(sock);
WSACleanup();
}
}
}

++i;
}

// Check if the request rejected
i = 0;
if(strstr(bodyResponse, "<errorCode>")) {
char errorCode[3],
*tmp = strstr(bodyResponse, "<errorCode>") + 11;

while(*tmp != '<') {
errorCode[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
numErrorCode = atoi(errorCode);
return numErrorCode;
}

return 0;
}


Delete port forward entry:



int deletePortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int protocol) {
WSADATA wsaData;
struct sockaddr_in upnpControl, upnpDevice;
int i = 0,
j = 0,
result = -1,
bodyLen = 0,
numErrorCode = 0;
char c,
*pLen = NULL,
*proto = NULL,
*bodyResponse = NULL,
pBodyLen[5],
responseHeader[700],
deleteForwardEntryRequest[700],
deleteForwardEntryRequestHeader[1000];

proto = (char *)MALLOC(4);
ZeroMemory(proto, 4);
if(protocol == TCP_PROTOCOL)
StringCbPrintf(proto, 4, "TCP");
else
StringCbPrintf(proto, 4, "UDP");

// A SOAP request to delete a mapping entry
ZeroMemory(deleteForwardEntryRequest, 700);
ZeroMemory(deleteForwardEntryRequestHeader, 1000);
StringCbPrintf(deleteForwardEntryRequest, 1200,
"<?xml version="1.0"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">"
"<SOAP-ENV:Body>"
"<m:DeletePortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">"
"<NewRemoteHost>"
""
"</NewRemoteHost>"
"<NewExternalPort>"
"%d"
"</NewExternalPort>"
"<NewProtocol>"
"%s"
"</NewProtocol>"
"</m:DeletePortMapping>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>rnrn", externalPort, proto);

StringCbPrintf(deleteForwardEntryRequestHeader, 1500,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: %drn"
"Connection: Keep-Alivern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn", upnpDeviceIp, lstrlen(deleteForwardEntryRequest));
StringCchCat(deleteForwardEntryRequestHeader, 1500, deleteForwardEntryRequest);
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

ZeroMemory(&upnpControl, sizeof(upnpControl));
upnpControl.sin_family = AF_INET;
if(localIp == NULL)
upnpControl.sin_addr.s_addr = INADDR_ANY;
else
upnpControl.sin_addr.s_addr = inet_addr(localIp);

upnpControl.sin_port = 0;
ZeroMemory(&upnpDevice, sizeof(upnpDevice));
upnpDevice.sin_family = AF_INET;
upnpDevice.sin_port = htons(80);
upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(upnpDevice)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, deleteForwardEntryRequestHeader, lstrlen(deleteForwardEntryRequestHeader), 0) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(responseHeader, 700);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
j = 0;
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'n') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen);
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
ZeroMemory(bodyResponse, bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;
if(j == bodyLen) {
closesocket(sock);
WSACleanup();
}
}
}

++i;
}

// Check f our request rejected
i = 0;
if(strstr(bodyResponse, "<errorCode>")) {
char errorCode[3],
*tmp = strstr(bodyResponse, "<errorCode>") + 11;

while(*tmp != '<') {
errorCode[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
numErrorCode = atoi(errorCode);
return numErrorCode;
}
else
return 0;
}









share|improve this question











$endgroup$




I've created a simple NAT library, with four essential functions:




  1. Find the UNPN device (the router in my case).

  2. Get the external IP address.

  3. Add a port forwarding entry.

  4. Delete a port forwarding entry.


Currently, updating an entry in the NAT table will change only the internal client ip address or the internal port, so to update an external port you have to delete it first then insert a new one.



TODO:




  1. Add other functionality (listing mapping entries, number of entries ...).

  2. Add support for other platforms.

  3. more testing if possible.


An example is included; just un-comment the part that you want to test. The library compiled and tested against Visual Studio 2008.



Any suggestions: optimization, coding style, bugs.



main.c:



#pragma comment(lib, "ws2_32.lib")

#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdio.h>

#if (_MSC_VER >= 1500)
#include <Strsafe.h>
#endif


#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))

#define TCP_PROTOCOL 0
#define UDP_PROTOCOL 1

#define INVALID_ARGS 402
#define ACTION_FAILED 501
#define ENTRY_MAPPING_NOTEXIST 714
#define INVALID_REMOTEHOST_IP 715
#define INVALID_REMOTEHOST_PORT 716
#define ENTRY_CONFLICT 718
#define SAME_PORT_REQUIRED 724
#define ONLY_PERMANENT_LEASE 725
#define OWILDCARD_IP_REQUIRED 726
#define OWILDCARD_PORT_REQUIRED 727


int boradcastDiscovery(char *upnpDeviceIp);
int getExternalpAddress(char *upnpDeviceIp, char *localIp, char *externalIpAddress);
int addPortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int internalPort, int protocol, char *internalp, char *entryDescription);
int deletePortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int protocol);

int main() {
char buf[512],
ipAddress[16];
int errorCode = 0;

/*ZeroMemory(ipAddress, 16);
boradcastDiscovery(ipAddress);

printf("UPNP device IP: %sn", ipAddress);*/

/*ZeroMemory(ipAddress, 16);
errorCode = getExternalpAddress("192.168.1.1", "192.168.1.4", ipAddress);
switch(errorCode) {
case INVALID_ARGS:
printf("Invalid query arg's.n");
break;
case ACTION_FAILED:
printf("Query failed to get external IP.n");
break;
default:
printf("External IP address: %sn", ipAddress);
break;
}*/

/*ZeroMemory(ipAddress, 16);
errorCode = addPortForwardEntry("192.168.1.1", "192.168.1.4", 9000, 4000, TCP_PROTOCOL, "192.168.1.7", "TEST FROM LIBRARY");
switch(errorCode) {
case INVALID_ARGS:
printf("Invalid query arg's.n");
break;
case ACTION_FAILED:
printf("Query failed to add entry mapping.n");
break;
case INVALID_REMOTEHOST_IP:
printf("Invalid IP address.n");
break;
case INVALID_REMOTEHOST_PORT:
printf("Invalid Port number.n");
break;
case ENTRY_CONFLICT:
printf("Such entry already exist.n");
break;
case SAME_PORT_REQUIRED:
printf("External and internal port must be the same.n");
break;
case ONLY_PERMANENT_LEASE:
printf("External and internal port must be the same.n");
break;
case OWILDCARD_IP_REQUIRED:
printf("External and internal port must be the same.n");
break;
case OWILDCARD_PORT_REQUIRED:
printf("External and internal port must be the same.n");
break;
default:
printf("Port mapping entry added sussccefully.n");
break;
}*/

/*ZeroMemory(ipAddress, 16);
errorCode = deletePortForwardEntry("192.168.1.1", "192.168.1.2", 5000, TCP_PROTOCOL);
switch(errorCode) {
case INVALID_ARGS:
printf("Invalid query arg's.n");
break;
case ACTION_FAILED:
printf("Query failed to add entry mapping.n");
break;
case ENTRY_MAPPING_NOTEXIST:
printf("Entry mapping doesn't exist.n");
break;
default:
printf("Port mapping entry deleted sussccefully.n");
break;
}*/


while(1)
;
return 0;
}


UpNp discover:



int boradcastDiscovery(char *upnpDeviceIp) {
char *searchIGDevice = "M-SEARCH * HTTP/1.1rnHost:239.255.255.250:1900rnST:urn:schemas-upnp-org:device:InternetGatewayDevice:1rnMan:"ssdp:discover"rnMX:3rnrn",
buf[512];
int result = -1;
WSADATA wsaData;
struct sockaddr_in upnpControl,
broadcast_addr;

result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET)
return WSAGetLastError();

if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, searchIGDevice, sizeof(searchIGDevice)) == SOCKET_ERROR)
return WSAGetLastError();

upnpControl.sin_family = AF_INET;
upnpControl.sin_port = htons(0);
upnpControl.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR)
return WSAGetLastError();

broadcast_addr.sin_family = AF_INET;
broadcast_addr.sin_port = htons(1900);
broadcast_addr.sin_addr.s_addr = inet_addr("239.255.255.250");

if(sendto(sock, searchIGDevice, lstrlen(searchIGDevice)+1, 0, (sockaddr *)&broadcast_addr, sizeof(broadcast_addr)) == SOCKET_ERROR)
return WSAGetLastError();

int bcLen = sizeof(broadcast_addr);
ZeroMemory(buf, 512);
if(recvfrom(sock, buf, 512, 0, (sockaddr *)&broadcast_addr, &bcLen) < 0)
return WSAGetLastError();
else {
closesocket(sock);
WSACleanup();
if(strstr(buf, "device:InternetGatewayDevice")) {
int i = 0;
char *deviceIp = strstr(buf, "http://") + 7;
while(*deviceIp != ':') {
upnpDeviceIp[i] = *deviceIp;
*deviceIp++;
++i;
}

return 0;
}
else
return -1;
}
}


Get external IP address:



int getExternalpAddress(char *upnpDeviceIp, char *localIp, char *externalIpAddress) {
WSADATA wsaData;
struct sockaddr_in upnpControl,
upnpDevice;
int i = 0,
j = 0,
result = -1,
bodyLen = 0;
char c,
*tmp = NULL,
*pLen = NULL,
*bodyResponse = NULL, // a pointer to HTTP body response
pBodyLen[5],
responseHeader[512],
getExternalIpRequest[622];
int reuseAddress = 1;

// A SOAP request to get external IP address
ZeroMemory(getExternalIpRequest, 622);
StringCbPrintf(getExternalIpRequest, 622,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#GetExternalIPAddress"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: 303rn"
"Connection: Closern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn"
"<?xml version="1.0"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">"
"<SOAP-ENV:Body>"
"<m:GetExternalIPAddress xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1"/>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>rnrn", upnpDeviceIp);
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuseAddress, sizeof(reuseAddress)) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(&upnpControl, sizeof(upnpControl));
upnpControl.sin_family = AF_INET;
if(localIp == NULL)
upnpControl.sin_addr.s_addr = INADDR_ANY;
else
upnpControl.sin_addr.s_addr = inet_addr(localIp);



ZeroMemory(&upnpDevice, sizeof(upnpDevice));
upnpDevice.sin_family = AF_INET;
upnpDevice.sin_port = htons(80);
upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(struct sockaddr)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, getExternalIpRequest, lstrlen(getExternalIpRequest), 0) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(responseHeader, 512);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
// We got the http header, extract the body length from it
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'r') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen);
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;

if(j == bodyLen) { // We got the HTTP body
closesocket(sock);
}
}
}

++i;
}

i = 0;
tmp = strstr(bodyResponse, "<NewExternalIPAddress>") + 22;
ZeroMemory(externalIpAddress, 16);
while(*tmp != '<') {
externalIpAddress[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
WSACleanup();
return 0;
}


Add port forward entry:



int addPortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int internalPort, 
int protocol, char *internalp, char *entryDescription) {
WSADATA wsaData;
struct sockaddr_in upnpControl, upnpDevice;
int i = 0,
j = 0,
result = -1,
bodyLen = 0,
numErrorCode = 0;
char c,
*pLen = NULL,
*proto = NULL,
*bodyResponse = NULL,
pBodyLen[5],
responseHeader[2000],
addForwardEntryRequest[1200],
addForwardEntryRequestHeader[1500];

proto = (char *)MALLOC(4);
ZeroMemory(proto, 4);
if(protocol == TCP_PROTOCOL)
StringCbPrintf(proto, 4, "TCP");
else
StringCbPrintf(proto, 4, "UDP");

// A SOAP request to insert a port forwarding entry
ZeroMemory(addForwardEntryRequest, 1200);
ZeroMemory(addForwardEntryRequestHeader, 1500);
StringCbPrintf(addForwardEntryRequest, 1200,
"<?xml version="1.0"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">"
"<SOAP-ENV:Body>"
"<m:AddPortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">"
"<NewRemoteHost>"
""
"</NewRemoteHost>"
"<NewExternalPort>"
"%d"
"</NewExternalPort>"
"<NewProtocol>"
"%s"
"</NewProtocol>"
"<NewInternalPort>"
"%d"
"</NewInternalPort>"
"<NewInternalClient>"
"%s"
"</NewInternalClient>"
"<NewEnabled>"
"1"
"</NewEnabled>"
"<NewPortMappingDescription>"
"%s"
"</NewPortMappingDescription>"
"<NewLeaseDuration>"
"0"
"</NewLeaseDuration>"
"</m:AddPortMapping>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>rnrn", externalPort, proto, internalPort, internalp, entryDescription);

StringCbPrintf(addForwardEntryRequestHeader, 1500,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: %drn"
"Connection: Closern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn", upnpDeviceIp, lstrlen(addForwardEntryRequest));
StringCchCat(addForwardEntryRequestHeader, 1500, addForwardEntryRequest);
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

ZeroMemory(&upnpControl, sizeof(upnpControl));
upnpControl.sin_family = AF_INET;
if(localIp == NULL)
upnpControl.sin_addr.s_addr = INADDR_ANY;
else
upnpControl.sin_addr.s_addr = inet_addr(localIp);

upnpControl.sin_port = 0;
ZeroMemory(&upnpDevice, sizeof(upnpDevice));
upnpDevice.sin_family = AF_INET;
upnpDevice.sin_port = htons(80);
upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(upnpDevice)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, addForwardEntryRequestHeader, lstrlen(addForwardEntryRequestHeader), 0) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(responseHeader, 2000);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'n') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen); // body length
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
ZeroMemory(bodyResponse, bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;
if(j == bodyLen) {
closesocket(sock);
}
}
}

++i;
}

// Check if uPnp reject our entry
i = 0;
if(strstr(bodyResponse, "<errorCode>")) {
char errorCode[3],
*tmp = strstr(bodyResponse, "<errorCode>") + 11;

while(*tmp != '<') {
errorCode[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
numErrorCode = atoi(errorCode);
return numErrorCode;
}

// Check the entry that we insert if is exist in the mapping table
ZeroMemory(addForwardEntryRequest, 1200);
ZeroMemory(addForwardEntryRequestHeader, 1500);
StringCbPrintf(addForwardEntryRequest, 1200,
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">rn"
"<SOAP-ENV:Body>rn"
"<m:GetSpecificPortMappingEntry xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">rn"
"<NewRemoteHost/>rn"
"<NewExternalPort>%d</NewExternalPort>rn"
"<NewProtocol>%s</NewProtocol>rn"
"</m:GetSpecificPortMappingEntry>rn"
"</SOAP-ENV:Body>rn"
"</SOAP-ENV:Envelope>rnrn", externalPort, proto);
StringCbPrintf(addForwardEntryRequestHeader, 1500,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#GetSpecificPortMappingEntry"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: %drn"
"Connection: Closern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn", upnpDeviceIp, lstrlen(addForwardEntryRequest));
StringCchCat(addForwardEntryRequestHeader, 1500, addForwardEntryRequest);
sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(upnpDevice)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, addForwardEntryRequestHeader, lstrlen(addForwardEntryRequestHeader), 0) == SOCKET_ERROR)
return WSAGetLastError();

i = 0;
ZeroMemory(responseHeader, 2000);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
j = 0;
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'n') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen);
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
ZeroMemory(bodyResponse, bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;
if(j == bodyLen) {
closesocket(sock);
WSACleanup();
}
}
}

++i;
}

// Check if the request rejected
i = 0;
if(strstr(bodyResponse, "<errorCode>")) {
char errorCode[3],
*tmp = strstr(bodyResponse, "<errorCode>") + 11;

while(*tmp != '<') {
errorCode[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
numErrorCode = atoi(errorCode);
return numErrorCode;
}

return 0;
}


Delete port forward entry:



int deletePortForwardEntry(char *upnpDeviceIp, char *localIp, int externalPort, int protocol) {
WSADATA wsaData;
struct sockaddr_in upnpControl, upnpDevice;
int i = 0,
j = 0,
result = -1,
bodyLen = 0,
numErrorCode = 0;
char c,
*pLen = NULL,
*proto = NULL,
*bodyResponse = NULL,
pBodyLen[5],
responseHeader[700],
deleteForwardEntryRequest[700],
deleteForwardEntryRequestHeader[1000];

proto = (char *)MALLOC(4);
ZeroMemory(proto, 4);
if(protocol == TCP_PROTOCOL)
StringCbPrintf(proto, 4, "TCP");
else
StringCbPrintf(proto, 4, "UDP");

// A SOAP request to delete a mapping entry
ZeroMemory(deleteForwardEntryRequest, 700);
ZeroMemory(deleteForwardEntryRequestHeader, 1000);
StringCbPrintf(deleteForwardEntryRequest, 1200,
"<?xml version="1.0"?>"
"<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">"
"<SOAP-ENV:Body>"
"<m:DeletePortMapping xmlns:m="urn:schemas-upnp-org:service:WANIPConnection:1">"
"<NewRemoteHost>"
""
"</NewRemoteHost>"
"<NewExternalPort>"
"%d"
"</NewExternalPort>"
"<NewProtocol>"
"%s"
"</NewProtocol>"
"</m:DeletePortMapping>"
"</SOAP-ENV:Body>"
"</SOAP-ENV:Envelope>rnrn", externalPort, proto);

StringCbPrintf(deleteForwardEntryRequestHeader, 1500,
"POST /UD/?3 HTTP/1.1rn"
"Content-Type: text/xml; charset="utf-8"rn"
"SOAPAction: "urn:schemas-upnp-org:service:WANIPConnection:1#DeletePortMapping"rn"
"User-Agent: Mozilla/4.0 (compatible; UPnP/1.0; Windows 9x)rn"
"Host: %srn"
"Content-Length: %drn"
"Connection: Keep-Alivern"
"Cache-Control: no-cachern"
"Pragma: no-cachernrn", upnpDeviceIp, lstrlen(deleteForwardEntryRequest));
StringCchCat(deleteForwardEntryRequestHeader, 1500, deleteForwardEntryRequest);
result = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(result != 0)
return WSAGetLastError();

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock == INVALID_SOCKET)
return WSAGetLastError();

ZeroMemory(&upnpControl, sizeof(upnpControl));
upnpControl.sin_family = AF_INET;
if(localIp == NULL)
upnpControl.sin_addr.s_addr = INADDR_ANY;
else
upnpControl.sin_addr.s_addr = inet_addr(localIp);

upnpControl.sin_port = 0;
ZeroMemory(&upnpDevice, sizeof(upnpDevice));
upnpDevice.sin_family = AF_INET;
upnpDevice.sin_port = htons(80);
upnpDevice.sin_addr.s_addr = inet_addr(upnpDeviceIp);
if(connect(sock, (struct sockaddr *)&upnpDevice, sizeof(upnpDevice)) == SOCKET_ERROR)
return WSAGetLastError();

if(send(sock, deleteForwardEntryRequestHeader, lstrlen(deleteForwardEntryRequestHeader), 0) == SOCKET_ERROR)
return WSAGetLastError();

ZeroMemory(responseHeader, 700);
while(recv(sock, &c, 1, 0) > 0) {
responseHeader[i] = c;
if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
j = 0;
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'n') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}

bodyLen = atoi(pBodyLen);
j = 0;
bodyResponse = (char *)MALLOC(bodyLen);
ZeroMemory(bodyResponse, bodyLen);
while(recv(sock, &c, 1, 0) > 0) {
bodyResponse[j] = c;
++j;
if(j == bodyLen) {
closesocket(sock);
WSACleanup();
}
}
}

++i;
}

// Check f our request rejected
i = 0;
if(strstr(bodyResponse, "<errorCode>")) {
char errorCode[3],
*tmp = strstr(bodyResponse, "<errorCode>") + 11;

while(*tmp != '<') {
errorCode[i] = *tmp;
*tmp++;
++i;
}

FREE(bodyResponse);
numErrorCode = atoi(errorCode);
return numErrorCode;
}
else
return 0;
}






c library networking windows






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Apr 15 '14 at 3:45









200_success

129k15152415




129k15152415










asked Nov 17 '13 at 20:46









SIFESIFE

12615




12615












  • $begingroup$
    I'd recommend splitting this code into separate blocks, or only include what's most necessary for review. Excessively-long code could discourage reviewing.
    $endgroup$
    – Jamal
    Nov 17 '13 at 21:49










  • $begingroup$
    @Jamal Do you mean splitting code by inserting each function in its own code tag?
    $endgroup$
    – SIFE
    Nov 17 '13 at 22:55










  • $begingroup$
    Only if this would work as separate questions. Otherwise, you could just have more than one block in this question, each with a short description of what's included.
    $endgroup$
    – Jamal
    Nov 17 '13 at 22:56






  • 1




    $begingroup$
    What's the point of main - it is just a while(1) loop with everything else commented out.
    $endgroup$
    – William Morris
    Nov 18 '13 at 1:06


















  • $begingroup$
    I'd recommend splitting this code into separate blocks, or only include what's most necessary for review. Excessively-long code could discourage reviewing.
    $endgroup$
    – Jamal
    Nov 17 '13 at 21:49










  • $begingroup$
    @Jamal Do you mean splitting code by inserting each function in its own code tag?
    $endgroup$
    – SIFE
    Nov 17 '13 at 22:55










  • $begingroup$
    Only if this would work as separate questions. Otherwise, you could just have more than one block in this question, each with a short description of what's included.
    $endgroup$
    – Jamal
    Nov 17 '13 at 22:56






  • 1




    $begingroup$
    What's the point of main - it is just a while(1) loop with everything else commented out.
    $endgroup$
    – William Morris
    Nov 18 '13 at 1:06
















$begingroup$
I'd recommend splitting this code into separate blocks, or only include what's most necessary for review. Excessively-long code could discourage reviewing.
$endgroup$
– Jamal
Nov 17 '13 at 21:49




$begingroup$
I'd recommend splitting this code into separate blocks, or only include what's most necessary for review. Excessively-long code could discourage reviewing.
$endgroup$
– Jamal
Nov 17 '13 at 21:49












$begingroup$
@Jamal Do you mean splitting code by inserting each function in its own code tag?
$endgroup$
– SIFE
Nov 17 '13 at 22:55




$begingroup$
@Jamal Do you mean splitting code by inserting each function in its own code tag?
$endgroup$
– SIFE
Nov 17 '13 at 22:55












$begingroup$
Only if this would work as separate questions. Otherwise, you could just have more than one block in this question, each with a short description of what's included.
$endgroup$
– Jamal
Nov 17 '13 at 22:56




$begingroup$
Only if this would work as separate questions. Otherwise, you could just have more than one block in this question, each with a short description of what's included.
$endgroup$
– Jamal
Nov 17 '13 at 22:56




1




1




$begingroup$
What's the point of main - it is just a while(1) loop with everything else commented out.
$endgroup$
– William Morris
Nov 18 '13 at 1:06




$begingroup$
What's the point of main - it is just a while(1) loop with everything else commented out.
$endgroup$
– William Morris
Nov 18 '13 at 1:06










2 Answers
2






active

oldest

votes


















9












$begingroup$

My main comment is that you need to concentrate on avoiding duplication of
code and on writing smaller functions. 50 lines or so is the sort of max length I use. You also use long names that are often
too long giving the code a very dense appearance and making it difficult ot
read. Smaller functions, reduced variable scope and hence shorter name sizes
will help here.



In function boradcastDiscovery, the name could be better as the current
(misspelt) name doesn't say what the function does. getGateway() perhaps?



In this function we have:



struct sockaddr_in upnpControl,
broadcast_addr;

SOCKET sock = INVALID_SOCKET;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET)
return WSAGetLastError();

if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, searchIGDevice, sizeof(searchIGDevice)) == SOCKET_ERROR)
return WSAGetLastError();

struct sockaddr_in upnpControl;
upnpControl.sin_family = AF_INET;
upnpControl.sin_port = htons(0);
upnpControl.sin_addr.s_addr = INADDR_ANY;
if (bind(sock, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR)
return WSAGetLastError();


This could easily be extracted to a function:



static int
getBroadcastSocket(char *device, size_t size)
{
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == INVALID_SOCKET) {
return -1;
}
int status = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, device, size);
if (status != SOCKET_ERROR) {
struct sockaddr_in s;
s.sin_family = AF_INET;
s.sin_port = htons(0);
s.sin_addr.s_addr = INADDR_ANY;
status = bind(sock, (sockaddr*)&s, sizeof s);
}
if (status == SOCKET_ERROR) {
close(sock);
return -1;
}
return sock;
}


Notice that sock is closed on error.



Another example is in code such as this which extracts a field from a string
and is repeated numerous times thoughout the whole code:



if(strstr(responseHeader, "rnrn")) {
// Move the pointer to the first digit
pLen = strstr(responseHeader, "Content-Length: ") + 16;
ZeroMemory(pBodyLen, 5);
// Get the body length
while(*pLen != 'r') {
pBodyLen[j] = *pLen;
*pLen++;
++j;
}


This should be extracted into a suitable function. Also of note in this code
are:




  • the use of explicit lengths (16 and 5 here), which is bad practice;

  • the lack of checks for target buffer overflow (often difficult);

  • the use of variable j which was initialize far away at the start of the
    function;

  • inappropriate loop type - a for would be better.





A few other comments:


  • The address "239.255.255.250" would be better if extracted to a #define at the top
    perhaps.



  • The code



    char *proto = NULL,
    ...
    proto = (char *)MALLOC(4);
    ZeroMemory(proto, 4);
    if(protocol == TCP_PROTOCOL)
    StringCbPrintf(proto, 4, "TCP");
    else
    StringCbPrintf(proto, 4, "UDP");



would be better as



    const char *proto = (protocol == TCP_PROTOCOL) ? "TCP" : "UDP";



  • Some of your calls to ZeroMemory often look redundant. The sizes in these
    calls and in calls to StringCbPrintf are often explicit numbers rather than
    using sizeof, which would be better.


  • The huge xml strings are distracting and would, I think, be better extracted
    into suitably named functions, passing in the target buffer and the parameters
    that need to be printed into the strings.



  • Variables should be defined close to their first point of use and initialised
    on use if possible. For example there is no benefit in writing:



    SOCKET sock = INVALID_SOCKET;
    sock = socket(AF_INET, SOCK_STREAM, 0);


    when you could write



    SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);



  • you are using TCP so you don't have to create a complete string before
    sending it. For example instead of writing



    createHeader(header, ...);
    createRequest(request, ...);
    concatenate(combined, header, request);
    send(combined);


    you can instead do:



    createHeader(header, ...);
    send(header);
    createRequest(request, ...);
    send(request);



Hopefully you will find something above that is of use :-)






share|improve this answer









$endgroup$





















    0












    $begingroup$

    Sorry for posting this in answer section, I really dont know how to contact someone on this thread, @William Morris. I badly need your help regarding with C++ NAT UPNP Implementation. Can you help me with this? I would really appreciate your effort. If you have time you can contact me through my gmail. veanhart@gmail.com . Thanks in advance. https://codereview.stackexchange.com/users/10269/william-morris





    share








    New contributor




    Techreator is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.






    $endgroup$













      Your Answer





      StackExchange.ifUsing("editor", function () {
      return StackExchange.using("mathjaxEditing", function () {
      StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
      StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
      });
      });
      }, "mathjax-editing");

      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "196"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f35549%2fa-simple-nat-library%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      9












      $begingroup$

      My main comment is that you need to concentrate on avoiding duplication of
      code and on writing smaller functions. 50 lines or so is the sort of max length I use. You also use long names that are often
      too long giving the code a very dense appearance and making it difficult ot
      read. Smaller functions, reduced variable scope and hence shorter name sizes
      will help here.



      In function boradcastDiscovery, the name could be better as the current
      (misspelt) name doesn't say what the function does. getGateway() perhaps?



      In this function we have:



      struct sockaddr_in upnpControl,
      broadcast_addr;

      SOCKET sock = INVALID_SOCKET;
      sock = socket(AF_INET, SOCK_DGRAM, 0);
      if (sock == INVALID_SOCKET)
      return WSAGetLastError();

      if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, searchIGDevice, sizeof(searchIGDevice)) == SOCKET_ERROR)
      return WSAGetLastError();

      struct sockaddr_in upnpControl;
      upnpControl.sin_family = AF_INET;
      upnpControl.sin_port = htons(0);
      upnpControl.sin_addr.s_addr = INADDR_ANY;
      if (bind(sock, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR)
      return WSAGetLastError();


      This could easily be extracted to a function:



      static int
      getBroadcastSocket(char *device, size_t size)
      {
      SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
      if (sock == INVALID_SOCKET) {
      return -1;
      }
      int status = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, device, size);
      if (status != SOCKET_ERROR) {
      struct sockaddr_in s;
      s.sin_family = AF_INET;
      s.sin_port = htons(0);
      s.sin_addr.s_addr = INADDR_ANY;
      status = bind(sock, (sockaddr*)&s, sizeof s);
      }
      if (status == SOCKET_ERROR) {
      close(sock);
      return -1;
      }
      return sock;
      }


      Notice that sock is closed on error.



      Another example is in code such as this which extracts a field from a string
      and is repeated numerous times thoughout the whole code:



      if(strstr(responseHeader, "rnrn")) {
      // Move the pointer to the first digit
      pLen = strstr(responseHeader, "Content-Length: ") + 16;
      ZeroMemory(pBodyLen, 5);
      // Get the body length
      while(*pLen != 'r') {
      pBodyLen[j] = *pLen;
      *pLen++;
      ++j;
      }


      This should be extracted into a suitable function. Also of note in this code
      are:




      • the use of explicit lengths (16 and 5 here), which is bad practice;

      • the lack of checks for target buffer overflow (often difficult);

      • the use of variable j which was initialize far away at the start of the
        function;

      • inappropriate loop type - a for would be better.





      A few other comments:


      • The address "239.255.255.250" would be better if extracted to a #define at the top
        perhaps.



      • The code



        char *proto = NULL,
        ...
        proto = (char *)MALLOC(4);
        ZeroMemory(proto, 4);
        if(protocol == TCP_PROTOCOL)
        StringCbPrintf(proto, 4, "TCP");
        else
        StringCbPrintf(proto, 4, "UDP");



      would be better as



          const char *proto = (protocol == TCP_PROTOCOL) ? "TCP" : "UDP";



      • Some of your calls to ZeroMemory often look redundant. The sizes in these
        calls and in calls to StringCbPrintf are often explicit numbers rather than
        using sizeof, which would be better.


      • The huge xml strings are distracting and would, I think, be better extracted
        into suitably named functions, passing in the target buffer and the parameters
        that need to be printed into the strings.



      • Variables should be defined close to their first point of use and initialised
        on use if possible. For example there is no benefit in writing:



        SOCKET sock = INVALID_SOCKET;
        sock = socket(AF_INET, SOCK_STREAM, 0);


        when you could write



        SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);



      • you are using TCP so you don't have to create a complete string before
        sending it. For example instead of writing



        createHeader(header, ...);
        createRequest(request, ...);
        concatenate(combined, header, request);
        send(combined);


        you can instead do:



        createHeader(header, ...);
        send(header);
        createRequest(request, ...);
        send(request);



      Hopefully you will find something above that is of use :-)






      share|improve this answer









      $endgroup$


















        9












        $begingroup$

        My main comment is that you need to concentrate on avoiding duplication of
        code and on writing smaller functions. 50 lines or so is the sort of max length I use. You also use long names that are often
        too long giving the code a very dense appearance and making it difficult ot
        read. Smaller functions, reduced variable scope and hence shorter name sizes
        will help here.



        In function boradcastDiscovery, the name could be better as the current
        (misspelt) name doesn't say what the function does. getGateway() perhaps?



        In this function we have:



        struct sockaddr_in upnpControl,
        broadcast_addr;

        SOCKET sock = INVALID_SOCKET;
        sock = socket(AF_INET, SOCK_DGRAM, 0);
        if (sock == INVALID_SOCKET)
        return WSAGetLastError();

        if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, searchIGDevice, sizeof(searchIGDevice)) == SOCKET_ERROR)
        return WSAGetLastError();

        struct sockaddr_in upnpControl;
        upnpControl.sin_family = AF_INET;
        upnpControl.sin_port = htons(0);
        upnpControl.sin_addr.s_addr = INADDR_ANY;
        if (bind(sock, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR)
        return WSAGetLastError();


        This could easily be extracted to a function:



        static int
        getBroadcastSocket(char *device, size_t size)
        {
        SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
        if (sock == INVALID_SOCKET) {
        return -1;
        }
        int status = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, device, size);
        if (status != SOCKET_ERROR) {
        struct sockaddr_in s;
        s.sin_family = AF_INET;
        s.sin_port = htons(0);
        s.sin_addr.s_addr = INADDR_ANY;
        status = bind(sock, (sockaddr*)&s, sizeof s);
        }
        if (status == SOCKET_ERROR) {
        close(sock);
        return -1;
        }
        return sock;
        }


        Notice that sock is closed on error.



        Another example is in code such as this which extracts a field from a string
        and is repeated numerous times thoughout the whole code:



        if(strstr(responseHeader, "rnrn")) {
        // Move the pointer to the first digit
        pLen = strstr(responseHeader, "Content-Length: ") + 16;
        ZeroMemory(pBodyLen, 5);
        // Get the body length
        while(*pLen != 'r') {
        pBodyLen[j] = *pLen;
        *pLen++;
        ++j;
        }


        This should be extracted into a suitable function. Also of note in this code
        are:




        • the use of explicit lengths (16 and 5 here), which is bad practice;

        • the lack of checks for target buffer overflow (often difficult);

        • the use of variable j which was initialize far away at the start of the
          function;

        • inappropriate loop type - a for would be better.





        A few other comments:


        • The address "239.255.255.250" would be better if extracted to a #define at the top
          perhaps.



        • The code



          char *proto = NULL,
          ...
          proto = (char *)MALLOC(4);
          ZeroMemory(proto, 4);
          if(protocol == TCP_PROTOCOL)
          StringCbPrintf(proto, 4, "TCP");
          else
          StringCbPrintf(proto, 4, "UDP");



        would be better as



            const char *proto = (protocol == TCP_PROTOCOL) ? "TCP" : "UDP";



        • Some of your calls to ZeroMemory often look redundant. The sizes in these
          calls and in calls to StringCbPrintf are often explicit numbers rather than
          using sizeof, which would be better.


        • The huge xml strings are distracting and would, I think, be better extracted
          into suitably named functions, passing in the target buffer and the parameters
          that need to be printed into the strings.



        • Variables should be defined close to their first point of use and initialised
          on use if possible. For example there is no benefit in writing:



          SOCKET sock = INVALID_SOCKET;
          sock = socket(AF_INET, SOCK_STREAM, 0);


          when you could write



          SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);



        • you are using TCP so you don't have to create a complete string before
          sending it. For example instead of writing



          createHeader(header, ...);
          createRequest(request, ...);
          concatenate(combined, header, request);
          send(combined);


          you can instead do:



          createHeader(header, ...);
          send(header);
          createRequest(request, ...);
          send(request);



        Hopefully you will find something above that is of use :-)






        share|improve this answer









        $endgroup$
















          9












          9








          9





          $begingroup$

          My main comment is that you need to concentrate on avoiding duplication of
          code and on writing smaller functions. 50 lines or so is the sort of max length I use. You also use long names that are often
          too long giving the code a very dense appearance and making it difficult ot
          read. Smaller functions, reduced variable scope and hence shorter name sizes
          will help here.



          In function boradcastDiscovery, the name could be better as the current
          (misspelt) name doesn't say what the function does. getGateway() perhaps?



          In this function we have:



          struct sockaddr_in upnpControl,
          broadcast_addr;

          SOCKET sock = INVALID_SOCKET;
          sock = socket(AF_INET, SOCK_DGRAM, 0);
          if (sock == INVALID_SOCKET)
          return WSAGetLastError();

          if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, searchIGDevice, sizeof(searchIGDevice)) == SOCKET_ERROR)
          return WSAGetLastError();

          struct sockaddr_in upnpControl;
          upnpControl.sin_family = AF_INET;
          upnpControl.sin_port = htons(0);
          upnpControl.sin_addr.s_addr = INADDR_ANY;
          if (bind(sock, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR)
          return WSAGetLastError();


          This could easily be extracted to a function:



          static int
          getBroadcastSocket(char *device, size_t size)
          {
          SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
          if (sock == INVALID_SOCKET) {
          return -1;
          }
          int status = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, device, size);
          if (status != SOCKET_ERROR) {
          struct sockaddr_in s;
          s.sin_family = AF_INET;
          s.sin_port = htons(0);
          s.sin_addr.s_addr = INADDR_ANY;
          status = bind(sock, (sockaddr*)&s, sizeof s);
          }
          if (status == SOCKET_ERROR) {
          close(sock);
          return -1;
          }
          return sock;
          }


          Notice that sock is closed on error.



          Another example is in code such as this which extracts a field from a string
          and is repeated numerous times thoughout the whole code:



          if(strstr(responseHeader, "rnrn")) {
          // Move the pointer to the first digit
          pLen = strstr(responseHeader, "Content-Length: ") + 16;
          ZeroMemory(pBodyLen, 5);
          // Get the body length
          while(*pLen != 'r') {
          pBodyLen[j] = *pLen;
          *pLen++;
          ++j;
          }


          This should be extracted into a suitable function. Also of note in this code
          are:




          • the use of explicit lengths (16 and 5 here), which is bad practice;

          • the lack of checks for target buffer overflow (often difficult);

          • the use of variable j which was initialize far away at the start of the
            function;

          • inappropriate loop type - a for would be better.





          A few other comments:


          • The address "239.255.255.250" would be better if extracted to a #define at the top
            perhaps.



          • The code



            char *proto = NULL,
            ...
            proto = (char *)MALLOC(4);
            ZeroMemory(proto, 4);
            if(protocol == TCP_PROTOCOL)
            StringCbPrintf(proto, 4, "TCP");
            else
            StringCbPrintf(proto, 4, "UDP");



          would be better as



              const char *proto = (protocol == TCP_PROTOCOL) ? "TCP" : "UDP";



          • Some of your calls to ZeroMemory often look redundant. The sizes in these
            calls and in calls to StringCbPrintf are often explicit numbers rather than
            using sizeof, which would be better.


          • The huge xml strings are distracting and would, I think, be better extracted
            into suitably named functions, passing in the target buffer and the parameters
            that need to be printed into the strings.



          • Variables should be defined close to their first point of use and initialised
            on use if possible. For example there is no benefit in writing:



            SOCKET sock = INVALID_SOCKET;
            sock = socket(AF_INET, SOCK_STREAM, 0);


            when you could write



            SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);



          • you are using TCP so you don't have to create a complete string before
            sending it. For example instead of writing



            createHeader(header, ...);
            createRequest(request, ...);
            concatenate(combined, header, request);
            send(combined);


            you can instead do:



            createHeader(header, ...);
            send(header);
            createRequest(request, ...);
            send(request);



          Hopefully you will find something above that is of use :-)






          share|improve this answer









          $endgroup$



          My main comment is that you need to concentrate on avoiding duplication of
          code and on writing smaller functions. 50 lines or so is the sort of max length I use. You also use long names that are often
          too long giving the code a very dense appearance and making it difficult ot
          read. Smaller functions, reduced variable scope and hence shorter name sizes
          will help here.



          In function boradcastDiscovery, the name could be better as the current
          (misspelt) name doesn't say what the function does. getGateway() perhaps?



          In this function we have:



          struct sockaddr_in upnpControl,
          broadcast_addr;

          SOCKET sock = INVALID_SOCKET;
          sock = socket(AF_INET, SOCK_DGRAM, 0);
          if (sock == INVALID_SOCKET)
          return WSAGetLastError();

          if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, searchIGDevice, sizeof(searchIGDevice)) == SOCKET_ERROR)
          return WSAGetLastError();

          struct sockaddr_in upnpControl;
          upnpControl.sin_family = AF_INET;
          upnpControl.sin_port = htons(0);
          upnpControl.sin_addr.s_addr = INADDR_ANY;
          if (bind(sock, (sockaddr*)&upnpControl, sizeof(upnpControl)) == SOCKET_ERROR)
          return WSAGetLastError();


          This could easily be extracted to a function:



          static int
          getBroadcastSocket(char *device, size_t size)
          {
          SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
          if (sock == INVALID_SOCKET) {
          return -1;
          }
          int status = setsockopt(sock, SOL_SOCKET, SO_BROADCAST, device, size);
          if (status != SOCKET_ERROR) {
          struct sockaddr_in s;
          s.sin_family = AF_INET;
          s.sin_port = htons(0);
          s.sin_addr.s_addr = INADDR_ANY;
          status = bind(sock, (sockaddr*)&s, sizeof s);
          }
          if (status == SOCKET_ERROR) {
          close(sock);
          return -1;
          }
          return sock;
          }


          Notice that sock is closed on error.



          Another example is in code such as this which extracts a field from a string
          and is repeated numerous times thoughout the whole code:



          if(strstr(responseHeader, "rnrn")) {
          // Move the pointer to the first digit
          pLen = strstr(responseHeader, "Content-Length: ") + 16;
          ZeroMemory(pBodyLen, 5);
          // Get the body length
          while(*pLen != 'r') {
          pBodyLen[j] = *pLen;
          *pLen++;
          ++j;
          }


          This should be extracted into a suitable function. Also of note in this code
          are:




          • the use of explicit lengths (16 and 5 here), which is bad practice;

          • the lack of checks for target buffer overflow (often difficult);

          • the use of variable j which was initialize far away at the start of the
            function;

          • inappropriate loop type - a for would be better.





          A few other comments:


          • The address "239.255.255.250" would be better if extracted to a #define at the top
            perhaps.



          • The code



            char *proto = NULL,
            ...
            proto = (char *)MALLOC(4);
            ZeroMemory(proto, 4);
            if(protocol == TCP_PROTOCOL)
            StringCbPrintf(proto, 4, "TCP");
            else
            StringCbPrintf(proto, 4, "UDP");



          would be better as



              const char *proto = (protocol == TCP_PROTOCOL) ? "TCP" : "UDP";



          • Some of your calls to ZeroMemory often look redundant. The sizes in these
            calls and in calls to StringCbPrintf are often explicit numbers rather than
            using sizeof, which would be better.


          • The huge xml strings are distracting and would, I think, be better extracted
            into suitably named functions, passing in the target buffer and the parameters
            that need to be printed into the strings.



          • Variables should be defined close to their first point of use and initialised
            on use if possible. For example there is no benefit in writing:



            SOCKET sock = INVALID_SOCKET;
            sock = socket(AF_INET, SOCK_STREAM, 0);


            when you could write



            SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);



          • you are using TCP so you don't have to create a complete string before
            sending it. For example instead of writing



            createHeader(header, ...);
            createRequest(request, ...);
            concatenate(combined, header, request);
            send(combined);


            you can instead do:



            createHeader(header, ...);
            send(header);
            createRequest(request, ...);
            send(request);



          Hopefully you will find something above that is of use :-)







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 18 '13 at 16:18









          William MorrisWilliam Morris

          8,7971241




          8,7971241

























              0












              $begingroup$

              Sorry for posting this in answer section, I really dont know how to contact someone on this thread, @William Morris. I badly need your help regarding with C++ NAT UPNP Implementation. Can you help me with this? I would really appreciate your effort. If you have time you can contact me through my gmail. veanhart@gmail.com . Thanks in advance. https://codereview.stackexchange.com/users/10269/william-morris





              share








              New contributor




              Techreator is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
              Check out our Code of Conduct.






              $endgroup$


















                0












                $begingroup$

                Sorry for posting this in answer section, I really dont know how to contact someone on this thread, @William Morris. I badly need your help regarding with C++ NAT UPNP Implementation. Can you help me with this? I would really appreciate your effort. If you have time you can contact me through my gmail. veanhart@gmail.com . Thanks in advance. https://codereview.stackexchange.com/users/10269/william-morris





                share








                New contributor




                Techreator is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                Check out our Code of Conduct.






                $endgroup$
















                  0












                  0








                  0





                  $begingroup$

                  Sorry for posting this in answer section, I really dont know how to contact someone on this thread, @William Morris. I badly need your help regarding with C++ NAT UPNP Implementation. Can you help me with this? I would really appreciate your effort. If you have time you can contact me through my gmail. veanhart@gmail.com . Thanks in advance. https://codereview.stackexchange.com/users/10269/william-morris





                  share








                  New contributor




                  Techreator is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.






                  $endgroup$



                  Sorry for posting this in answer section, I really dont know how to contact someone on this thread, @William Morris. I badly need your help regarding with C++ NAT UPNP Implementation. Can you help me with this? I would really appreciate your effort. If you have time you can contact me through my gmail. veanhart@gmail.com . Thanks in advance. https://codereview.stackexchange.com/users/10269/william-morris






                  share








                  New contributor




                  Techreator is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.








                  share


                  share






                  New contributor




                  Techreator is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.









                  answered 9 mins ago









                  TechreatorTechreator

                  1




                  1




                  New contributor




                  Techreator is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.





                  New contributor





                  Techreator is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.






                  Techreator is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
                  Check out our Code of Conduct.






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Code Review Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      Use MathJax to format equations. MathJax reference.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f35549%2fa-simple-nat-library%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      404 Error Contact Form 7 ajax form submitting

                      How to know if a Active Directory user can login interactively

                      TypeError: fit_transform() missing 1 required positional argument: 'X'