4

I am trying to use the C++ IUPnPNAT interface to achieve automatic port forwarding in a P2P application under windows, and I can't make it work just because it returns allways a NULL object. I was not sure that my router was UPnP capable, because it doesn't show any option in the web interface, but if I install eMule or Skype, they open the ports inmediately and work fine, so the problem must be in my code or in the Microsoft interface. How eMule and Skype do it? Anobody can help me?

I paste my code:

WORD abre_puerto() {
WORD puerto, i; 
wchar_t buf_port[12], puerto_s[6]; 
char nombre[256], ip[16]; 
wchar_t ipw[16], descripcion[100];
struct addrinfo *resultado = NULL; 
struct addrinfo *ptr = NULL; 
struct addrinfo hints; 
struct sockaddr_in *sockaddr_ipv4;
IUPnPNAT *nat; 
IStaticPortMappingCollection *coleccion; 
IStaticPortMapping *mapeado; 
BSTR protocolo, ipb;

swprintf(buf_port, sizeof(buf_port), L"%d", time(NULL));
swprintf(puerto_s, sizeof(puerto_s), L"151%c%c", buf_port[wcslen(buf_port) - 2], buf_port[wcslen(buf_port) - 1]);
puerto = _wtoi(puerto_s);

if(gethostname(nombre, sizeof(nombre)) == SOCKET_ERROR) {return 0;}
ZeroMemory(&hints, sizeof(hints)); 
hints.ai_family = AF_INET; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_protocol = IPPROTO_TCP;
if(getaddrinfo(nombre, NULL, &hints, &resultado) != 0) {return 0;}

sockaddr_ipv4 = (struct sockaddr_in *)resultado->ai_addr;
strcpy(ip, inet_ntoa(sockaddr_ipv4->sin_addr));
MultiByteToWideChar(CP_UTF8, 0, ip, -1, ipw, sizeof(ipw));
ipb = SysAllocString(ipw);

nat = NULL; coleccion = NULL; mapeado = NULL;

if(CoInitialize(NULL) != S_OK) {return 0;}

if(CoCreateInstance(__uuidof(UPnPNAT), NULL, CLSCTX_ALL, __uuidof(IUPnPNAT), (void **)&nat) != S_OK) {return 0;}
else if(nat == NULL) {return 0;}

if(nat->get_StaticPortMappingCollection(&coleccion) != S_OK) {return 0;}
else if(coleccion == NULL) {return 0;} //fails here: coleccion is allways NULL!

protocolo = SysAllocString(L"TCP");
wcscpy(descripcion, TEXT("PROOF"));

for(i = 0; i < 250; i++) {
if(coleccion->get_Item(puerto, protocolo, &mapeado) != S_OK || mapeado == NULL) {break;}
puerto++; mapeado->Release(); mapeado = NULL;
}
if(i == 250) {return 0;}
if(coleccion->Add(puerto, protocolo, puerto, ipb, TRUE, descripcion, &mapeado) != S_OK) {return 0;}
else if(mapeado == NULL) {return 0;}
nat->Release(); coleccion->Release(); mapeado->Release();
CoUninitialize();

return puerto;
}

Thank you very much.

alnog
  • 41
  • 1
  • 4

2 Answers2

1

Apologies, but you're not explicit in the location of the received NULL pointer.

If the CoCreateInstance is returning null, then it indicates that the class in question isn't registered on the relevant machine with OLE/COM - the fact that Skype/eMule work is irrelevant, as they probably use a library that is built into the application, and not a COM object.

you should ensure that the COM object is registered on the system that is using it - search the registry for the UPnPNAT uuid.

if you want to have the application work on multiple systems, then you should consider linking directly to the .lib, and not using COM to connect to an object that may or may not be registered on the system at the time that it is being used.

Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122
  • it looks like the UPnp framework is an optional install on windows - so it is probable that it is just not installed on the system that you are testing on. – Anya Shenanigans Jan 06 '12 at 11:10
  • Sorry, I forgot to mention in my question where it comes the NULL object, but if you read the comment I left in my code, it's in the call to the method get_StaticPortMappingCollection of the IUPnPNAT interface, the NULL object is "IStaticPortMappingCollection *coleccion" and the method doesn't fail, returns S_OK, it's just the object that is allways empty. CoCreateInstance returns S_OK and fills the IUPnPNAT interface properly. The machine uses Windows 7 and in this same box with the same router, eMule works and opens the ports every time it starts up (probably uses the MiniUPnPc lib?). – alnog Jan 06 '12 at 12:27
0

Most probably you do not have Network Discovery turned on.

I have experienced the same issue while being connected to a Guest or Public network and doing some debug I have found out that upnpnat.dll was not loading at all at runtime when get_StaticPortMappingCollection(..) was called. This can happen due to security restrictions if you are not connected to a Private network. Can check this in Control Panel -> Network and Sharing Center -> Change advanced sharing settings.

Control Panel screen shot

Network discovery needs to be turned on in this case. For private networks it dose not matter.

Andrei
  • 3
  • 2