static int init_upnp(void) { struct UPNPDev *devlist; struct UPNPDev *dev = NULL; struct UPNPDev *trydev = NULL; char *descXML; int descXMLsize = 0; const char *multicastif = 0; const char *minissdpdpath = 0; memset(&nat_globals.urls, 0, sizeof(struct UPNPUrls)); memset(&nat_globals.data, 0, sizeof(struct IGDdatas)); devlist = upnpDiscover(3000, multicastif, minissdpdpath, 0); if (devlist) { dev = devlist; while (dev) { if (strstr(dev->st, "InternetGatewayDevice")) { break; } if (!trydev && !switch_stristr("printer", dev->descURL)) { trydev = dev; } dev = dev->pNext; } } if (!dev && trydev) { dev = trydev; /* defaulting to first device */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No InternetGatewayDevice, using first entry as default (%s).\n", dev->descURL); } else if (devlist && !dev && !trydev) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "No InternetGatewayDevice found and I am NOT going to try your printer because printers should not route to the internet, that would be DAFT\n"); } if (dev) { descXML = miniwget(dev->descURL, &descXMLsize); nat_globals.descURL = strdup(dev->descURL); if (descXML) { parserootdesc(descXML, descXMLsize, &nat_globals.data); free(descXML); descXML = 0; GetUPNPUrls(&nat_globals.urls, &nat_globals.data, dev->descURL); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unable to retrieve device description XML (%s).\n", dev->descURL); } freeUPNPDevlist(devlist); } if (get_upnp_pubaddr(nat_globals.pub_addr) == SWITCH_STATUS_SUCCESS) { nat_globals.nat_type = SWITCH_NAT_TYPE_UPNP; return 0; } return -2; }
// called from ---UPnP--- thread // discovers the IGD bool NetPlayServer::initUPnP() { UPNPDev *devlist; std::vector<UPNPDev *> igds; int descXMLsize = 0, upnperror = 0; char *descXML; // Don't init if already inited if (m_upnp_inited) return true; // Don't init if it failed before if (m_upnp_error) return false; memset(&m_upnp_urls, 0, sizeof(UPNPUrls)); memset(&m_upnp_data, 0, sizeof(IGDdatas)); // Find all UPnP devices devlist = upnpDiscover(2000, NULL, NULL, 0, 0, &upnperror); if (!devlist) { WARN_LOG(NETPLAY, "An error occured trying to discover UPnP devices."); m_upnp_error = true; m_upnp_inited = false; return false; } // Look for the IGD for (UPNPDev* dev = devlist; dev; dev = dev->pNext) { if (strstr(dev->st, "InternetGatewayDevice")) igds.push_back(dev); } for (const UPNPDev* dev : igds) { descXML = (char *) miniwget(dev->descURL, &descXMLsize, 0); if (descXML) { parserootdesc(descXML, descXMLsize, &m_upnp_data); free(descXML); descXML = 0; GetUPNPUrls(&m_upnp_urls, &m_upnp_data, dev->descURL, 0); NOTICE_LOG(NETPLAY, "Got info from IGD at %s.", dev->descURL); break; } else { WARN_LOG(NETPLAY, "Error getting info from IGD at %s.", dev->descURL); } } freeUPNPDevlist(devlist); return true; }
bool Portfwd::init(unsigned int timeout) { #ifdef WIN32 WSADATA wsaData; int nResult = WSAStartup(MAKEWORD(2,2), &wsaData); if(nResult != NO_ERROR) { fprintf(stderr, "WSAStartup() failed.\n"); return -1; } #endif struct UPNPDev * devlist; struct UPNPDev * dev; char * descXML; int descXMLsize = 0; printf("Portfwd::init()\n"); urls = (UPNPUrls*)malloc(sizeof(struct UPNPUrls)); data = (IGDdatas*)malloc(sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); memset(data, 0, sizeof(struct IGDdatas)); devlist = upnpDiscover(timeout, NULL, NULL, 0); if (devlist) { dev = devlist; while (dev) { if (strstr (dev->st, "InternetGatewayDevice")) break; dev = dev->pNext; } if (!dev) dev = devlist; /* defaulting to first device */ printf("UPnP device :\n" " desc: %s\n st: %s\n", dev->descURL, dev->st); descXML = (char*)miniwget(dev->descURL, &descXMLsize); if (descXML) { parserootdesc (descXML, descXMLsize, data); free (descXML); descXML = 0; GetUPNPUrls (urls, data, dev->descURL); } // get lan IP: char lanaddr[16]; int i; i = UPNP_GetValidIGD(devlist, urls, data, (char*)&lanaddr, 16); m_lanip = std::string(lanaddr); freeUPNPDevlist(devlist); get_status(); return true; } return false; }
static inline void I_InitUPnP(void) { struct UPNPDev * devlist = NULL; int upnp_error = -2; CONS_Printf(M_GetText("Looking for UPnP Internet Gateway Device\n")); devlist = upnpDiscover(2000, NULL, NULL, 0, false, &upnp_error); if (devlist) { struct UPNPDev *dev = devlist; char * descXML; int descXMLsize = 0; while (dev) { if (strstr (dev->st, "InternetGatewayDevice")) break; dev = dev->pNext; } if (!dev) dev = devlist; /* defaulting to first device */ CONS_Printf(M_GetText("Found UPnP device:\n desc: %s\n st: %s\n"), dev->descURL, dev->st); UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); CONS_Printf(M_GetText("Local LAN IP address: %s\n"), lanaddr); descXML = miniwget(dev->descURL, &descXMLsize); if (descXML) { parserootdesc(descXML, descXMLsize, &data); free(descXML); descXML = NULL; memset(&urls, 0, sizeof(struct UPNPUrls)); memset(&data, 0, sizeof(struct IGDdatas)); GetUPNPUrls(&urls, &data, dev->descURL); I_AddExitFunc(I_ShutdownUPnP); } freeUPNPDevlist(devlist); } else if (upnp_error == UPNPDISCOVER_SOCKET_ERROR) { CONS_Printf(M_GetText("No UPnP devices discovered\n")); } }
/* UPNP_GetIGDFromUrl() * Used when skipping the discovery process. * return value : * 0 - Not ok * 1 - OK */ int UPNP_GetIGDFromUrl(const char * rootdescurl, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { char * descXML; int descXMLsize = 0; descXML = miniwget_getaddr(rootdescurl, &descXMLsize, lanaddr, lanaddrlen, 0); if(descXML) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(descXML, descXMLsize, data); free(descXML); descXML = NULL; GetUPNPUrls(urls, data, rootdescurl, 0); return 1; } else { return 0; } }
void natt_init(void) { #ifndef HAVE_SOCKET_LEGACY #if HAVE_MINIUPNPC struct UPNPDev * devlist; struct UPNPDev * dev; char * descXML; int descXMLsize = 0; int upnperror = 0; memset(&urls, 0, sizeof(struct UPNPUrls)); memset(&data, 0, sizeof(struct IGDdatas)); devlist = upnpDiscover(2000, NULL, NULL, 0, 0, 2, &upnperror); if (devlist) { dev = devlist; while (dev) { if (strstr (dev->st, "InternetGatewayDevice")) break; dev = dev->pNext; } if (!dev) dev = devlist; descXML = (char *) miniwget(dev->descURL, &descXMLsize, 0, NULL); if (descXML) { parserootdesc(descXML, descXMLsize, &data); free (descXML); descXML = 0; GetUPNPUrls (&urls, &data, dev->descURL, 0); } freeUPNPDevlist(devlist); } #endif #endif }
/* UPNP_GetValidIGD() : * return values : * -1 = Internal error * 0 = NO IGD found * 1 = A valid connected IGD has been found * 2 = A valid IGD has been found but it reported as * not connected * 3 = an UPnP device has been found but was not recognized as an IGD * * In any non zero return case, the urls and data structures * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to * free allocated memory. */ LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { struct xml_desc { char * xml; int size; } * desc = NULL; struct UPNPDev * dev; int ndev = 0; int i; int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ if(!devlist) { #ifdef DEBUG printf("Empty devlist\n"); #endif return 0; } for(dev = devlist; dev; dev = dev->pNext) ndev++; if(ndev > 0) { desc = calloc(ndev, sizeof(struct xml_desc)); if(!desc) return -1; /* memory allocation error */ } for(state = 1; state <= 3; state++) { for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { /* we should choose an internet gateway device. * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ if(state == 1) { desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), lanaddr, lanaddrlen, dev->scope_id); #ifdef DEBUG if(!desc[i].xml) { printf("error getting XML description %s\n", dev->descURL); } #endif } if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(desc[i].xml, desc[i].size, data); if(0==strcmp(data->CIF.servicetype, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1") || state >= 3 ) { GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, UPNPIGD_IsConnected(urls, data)); #endif if((state >= 2) || UPNPIGD_IsConnected(urls, data)) goto free_and_return; FreeUPNPUrls(urls); if(data->second.servicetype[0] != '\0') { #ifdef DEBUG printf("We tried %s, now we try %s !\n", data->first.servicetype, data->second.servicetype); #endif /* swaping WANPPPConnection and WANIPConnection ! */ memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, UPNPIGD_IsConnected(urls, data)); #endif if((state >= 2) || UPNPIGD_IsConnected(urls, data)) goto free_and_return; FreeUPNPUrls(urls); } } memset(data, 0, sizeof(struct IGDdatas)); } } } state = 0; free_and_return: if(desc) { for(i = 0; i < ndev; i++) { if(desc[i].xml) { free(desc[i].xml); } } free(desc); } return state; }
/* UPNP_GetValidIGD() : * return values : * 0 = NO IGD found * 1 = A valid connected IGD has been found * 2 = A valid IGD has been found but it reported as * not connected * 3 = an UPnP device has been found but was not recognized as an IGD * * In any non zero return case, the urls and data structures * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to * free allocated memory. */ int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { char * descXML; int descXMLsize = 0; struct UPNPDev * dev; int ndev = 0; int state; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ if(!devlist) { #ifdef DEBUG printf("Empty devlist\n"); #endif return 0; } for(state = 1; state <= 3; state++) { for(dev = devlist; dev; dev = dev->pNext) { /* we should choose an internet gateway device. * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ descXML = miniwget_getaddr(dev->descURL, &descXMLsize, lanaddr, lanaddrlen); if(descXML) { ndev++; memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(descXML, descXMLsize, data); free(descXML); descXML = NULL; if(0==strcmp(data->servicetype_CIF, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1") || state >= 3 ) { GetUPNPUrls(urls, data, dev->descURL); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, UPNPIGD_IsConnected(urls, data)); #endif if((state >= 2) || UPNPIGD_IsConnected(urls, data)) return state; FreeUPNPUrls(urls); } memset(data, 0, sizeof(struct IGDdatas)); } #ifdef DEBUG else { printf("error getting XML description %s\n", dev->descURL); } #endif } } return 0; }
/* UPNP_GetValidIGD() : * return values : * -1 = Internal error * 0 = NO IGD found * 1 = A valid connected IGD has been found * 2 = A valid IGD has been found but it reported as * not connected * 3 = an UPnP device has been found but was not recognized as an IGD * * In any positive non zero return case, the urls and data structures * passed as parameters are set. Don't forget to call FreeUPNPUrls(urls) to * free allocated memory. */ MINIUPNP_LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { struct xml_desc { char * xml; int size; int is_igd; } * desc = NULL; struct UPNPDev * dev; int ndev = 0; int i; int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ char extIpAddr[16]; char myLanAddr[40]; int status_code = -1; if(!devlist) { #ifdef DEBUG printf("Empty devlist\n"); #endif return 0; } /* counting total number of devices in the list */ for(dev = devlist; dev; dev = dev->pNext) ndev++; /* ndev is always > 0 */ desc = calloc(ndev, sizeof(struct xml_desc)); if(!desc) return -1; /* memory allocation error */ /* Step 1 : downloading descriptions and testing type */ for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { /* we should choose an internet gateway device. * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), myLanAddr, sizeof(myLanAddr), dev->scope_id, &status_code); #ifdef DEBUG if(!desc[i].xml) { printf("error getting XML description %s\n", dev->descURL); } #endif if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(desc[i].xml, desc[i].size, data); if(COMPARE(data->CIF.servicetype, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) { desc[i].is_igd = 1; if(lanaddr) strncpy(lanaddr, myLanAddr, lanaddrlen); } } } /* iterate the list to find a device depending on state */ for(state = 1; state <= 3; state++) { for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(desc[i].xml, desc[i].size, data); if(desc[i].is_igd || state >= 3 ) { int is_connected; GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); /* in state 2 and 3 we don't test if device is connected ! */ if(state >= 2) goto free_and_return; is_connected = UPNPIGD_IsConnected(urls, data); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, is_connected); #endif /* checks that status is connected AND there is a external IP address assigned */ if(is_connected && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) { if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0') && (0 != strcmp(extIpAddr, "0.0.0.0"))) goto free_and_return; } FreeUPNPUrls(urls); if(data->second.servicetype[0] != '\0') { #ifdef DEBUG printf("We tried %s, now we try %s !\n", data->first.servicetype, data->second.servicetype); #endif /* swaping WANPPPConnection and WANIPConnection ! */ memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); is_connected = UPNPIGD_IsConnected(urls, data); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, is_connected); #endif if(is_connected && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) { if(!is_rfc1918addr(extIpAddr) && (extIpAddr[0] != '\0') && (0 != strcmp(extIpAddr, "0.0.0.0"))) goto free_and_return; } FreeUPNPUrls(urls); } } memset(data, 0, sizeof(struct IGDdatas)); } } } state = 0; free_and_return: for(i = 0; i < ndev; i++) free(desc[i].xml); free(desc); return state; }
int main(int argc, char ** argv) { char * descURL = NULL; int option_index = 0; int c; int devid = -1; char arguments[1025]; arguments[0]='\0'; char action[129]; action[0]='\0'; char verbose = 0; unsigned int operation = OP_NONE; if(argc == 1) { printUsage(argv[0]); return -1; } while(1){ c = getopt_long(argc,argv,"dlva:p:",long_options,&option_index); if(c == -1) break; switch(c){ case 'd': operation = OP_DISCOVER; break; case 'l': operation = OP_LIST; break; case 'a': operation = OP_CALLOP; if(optarg) strncpy(action,optarg,128); break; case 'p': if(optarg) strncpy(arguments,optarg,1024); break; case 'v': verbose = 1; break; default: printUsage(argv[0]); return 0; } } if(verbose) printf("Universal Plug and Play IGD Tool v0.1\n João Paulo Barraca <*****@*****.**>\n\n"); if(operation == OP_NONE) return 0; descURL = upnpDiscover(5000); // timeout = 5secs if(descURL) { struct IGDdatas *data = (struct IGDdatas*) malloc(sizeof(struct IGDdatas)); struct UPNPUrls urls; memset(data, 0, sizeof(struct IGDdatas)); memset(&urls, 0, sizeof(struct UPNPUrls)); char * descXML; int descXMLsize = 0; descXML = miniwget(descURL, &descXMLsize); parserootdesc(descXML, descXMLsize, data); if(descXML) { switch(operation) { case OP_CALLOP: callUPNPVariable(data,action,arguments, verbose); break; case OP_LIST: listServices(data,devid,verbose); break; case OP_DISCOVER: listDevices(data); break; default: printf("Error: Action not implemented (yet)!\n"); break; } free(descXML); } else { printf("Error: Cannot get XML description of the device.\n"); } freeIGD(data); free(descURL); } else { fprintf(stderr, "Error: No IGD UPnP Device found on the network !\n"); } return 0; }
/* UPNP_GetValidIGDe) : * return values : * -1 = Internal error * 0 = NO IGD found * 1 = A valid connected IGD has been found * 2 = A valid IGD has been found but it reported as * not connected * 3 = an UPnP device has been found but was not recognized as an IGD * * In any positive non zero return case, the urls and data structures * passed as parameters are set. Donc forget to call FreeUPNPUrls(urls) to * free allocated memory. */ MINIUPNP_LIBSPEC int UPNP_GetValidIGD(struct UPNPDev * devlist, struct UPNPUrls * urls, struct IGDdatas * data, char * lanaddr, int lanaddrlen) { struct xml_desc { char * xml; int size; int is_igd; } * desc = NULL; struct UPNPDev * dev; int ndev = 0; int i; int state = -1; /* state 1 : IGD connected. State 2 : IGD. State 3 : anything */ int n_igd = 0; char extIpAddr[16]; struct UPNPDevInfo IGDInfo; char *dut_lanaddr; char IGDDescURL[256]; if(!devlist) { #ifdef DEBUG printf("Empty devlist\n"); #endif return 0; } /* counting total number of devices in the list */ for(dev = devlist; dev; dev = dev->pNext) ndev++; if(ndev > 0) { desc = calloc(ndev, sizeof(struct xml_desc)); if(!desc) return -1; /* memory allocation error */ } dut_lanaddr = get_lan_ipaddr(); /* Step 1 : downloading descriptions and testing type */ for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { memset(&IGDInfo, 0, sizeof(struct UPNPDevInfo)); /* we should choose an internet gateway device. * with st == urn:schemas-upnp-org:device:InternetGatewayDevice:1 */ strcpy(IGDDescURL, dev->descURL); desc[i].xml = miniwget_getaddr(dev->descURL, &(desc[i].size), lanaddr, lanaddrlen, dev->scope_id, &IGDInfo, dut_lanaddr); #ifdef DEBUG if(!desc[i].xml) { printf("error getting XML description %s\n", dev->descURL); } #endif if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); /* parserootdesc(desc[i].xml, desc[i].size, data); */ #ifdef DEBUG FILE *xml_fd; xml_fd = fopen("/tmp/upnpc_xml.log", "w"); fprintf(xml_fd, "============= XML ==============\n"); fprintf(xml_fd, "%s\n", desc[i].xml); parsedescxml(desc[i].xml, &IGDInfo.friendlyName, &IGDInfo.iconUrl); fprintf(xml_fd, " HostName: %s\n", IGDInfo.hostname); fprintf(xml_fd, " type: %s\n", IGDInfo.type); fprintf(xml_fd, " F Name: %s\n", IGDInfo.friendlyName); fprintf(xml_fd, " Icon URL: %s\n", IGDInfo.iconUrl); fprintf(xml_fd, "================================\n\n"); syslog(LOG_NOTICE, "parse icon url: %s", IGDInfo.iconUrl); #endif strcpy(dev->DevInfo.hostname, IGDInfo.hostname); strcpy(dev->DevInfo.type, IGDInfo.type); strcpy(dev->DevInfo.friendlyName, IGDInfo.friendlyName); strcpy(dev->DevInfo.iconUrl, IGDInfo.iconUrl); #ifdef RTCONFIG_JFFS2USERICON if(strcmp(IGDInfo.iconUrl, "") != NULL) { char realIconUrl[158], iconFile[32], iconBuf[512]; char *ico_head, *ico_end; char *icon, *p, *q; int iconSize, i = 0, iconCheck = 0; FILE *ico_fd; memset(realIconUrl, 0, 158); if(strstr(IGDInfo.iconUrl, "http://")) { strcpy(realIconUrl, IGDInfo.iconUrl); } else { q = IGDDescURL; while(q = strchr(q, '/')) { i++; if(i == 3) { p = IGDDescURL; i = 0; while ( p < q ) { realIconUrl[i++] = *p++; } strcat(realIconUrl, IGDInfo.iconUrl); #ifdef DEBUG printf("\n*** Real URL=%s=\n\n", realIconUrl); #endif break; } q++; } } get_icon: #ifdef DEBUG syslog(LOG_NOTICE, "Real icon url: %s", realIconUrl); fprintf(xml_fd, "Real icon url: %s\n", realIconUrl); #endif sprintf(iconFile, "/tmp/upnpicon/%s.ico", IGDInfo.hostname); icon = miniwget_getaddr(realIconUrl, &iconSize, lanaddr, lanaddrlen, 0, &IGDInfo, dut_lanaddr); if( iconSize > 512 ) { ico_fd = fopen(iconFile, "w"); if(ico_fd) { fwrite(icon, sizeof(char), iconSize, ico_fd); fclose(ico_fd); } } else if(iconSize > 0) { ico_head = strstr(icon, "<a href="); if(ico_head) { ico_head = ico_head+9; ico_end = strstr(icon, "\">"); if(ico_end) { *ico_end = '\0'; strcpy(realIconUrl, ico_head); goto get_icon; } } } } #endif if(COMPARE(data->CIF.servicetype, "urn:schemas-upnp-org:service:WANCommonInterfaceConfig:")) { desc[i].is_igd = 1; n_igd++; } #ifdef DEBUG fclose(xml_fd); #endif } else memset(dev->DevInfo.hostname, 0, 65); } /* iterate the list to find a device depending on state */ for(state = 1; state <= 3; state++) /*if(0)*/ { for(dev = devlist, i = 0; dev; dev = dev->pNext, i++) { if(desc[i].xml) { memset(data, 0, sizeof(struct IGDdatas)); memset(urls, 0, sizeof(struct UPNPUrls)); parserootdesc(desc[i].xml, desc[i].size, data); if(desc[i].is_igd || state >= 3 ) { GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); /* in state 2 and 3 we dont test if device is connected ! */ if(state >= 2) goto free_and_return; #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, UPNPIGD_IsConnected(urls, data)); #endif /* checks that status is connected AND there is a external IP address assigned */ if(UPNPIGD_IsConnected(urls, data) && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) goto free_and_return; FreeUPNPUrls(urls); if(data->second.servicetype[0] != '\0') { #ifdef DEBUG printf("We tried %s, now we try %s !\n", data->first.servicetype, data->second.servicetype); #endif /* swaping WANPPPConnection and WANIPConnection ! */ memcpy(&data->tmp, &data->first, sizeof(struct IGDdatas_service)); memcpy(&data->first, &data->second, sizeof(struct IGDdatas_service)); memcpy(&data->second, &data->tmp, sizeof(struct IGDdatas_service)); GetUPNPUrls(urls, data, dev->descURL, dev->scope_id); #ifdef DEBUG printf("UPNPIGD_IsConnected(%s) = %d\n", urls->controlURL, UPNPIGD_IsConnected(urls, data)); #endif if(UPNPIGD_IsConnected(urls, data) && (UPNP_GetExternalIPAddress(urls->controlURL, data->first.servicetype, extIpAddr) == 0)) goto free_and_return; FreeUPNPUrls(urls); } } memset(data, 0, sizeof(struct IGDdatas)); } } } state = 0; free_and_return: if(desc) { for(i = 0; i < ndev; i++) { if(desc[i].xml) { free(desc[i].xml); } } free(desc); } return state; }
// called from ---UPnP--- thread // discovers the IGD static bool InitUPnP() { static bool s_inited = false; static bool s_error = false; // Don't init if already inited if (s_inited) return true; // Don't init if it failed before if (s_error) return false; s_urls = {}; s_data = {}; // Find all UPnP devices int upnperror = 0; std::unique_ptr<UPNPDev, decltype(&freeUPNPDevlist)> devlist(nullptr, freeUPNPDevlist); #if MINIUPNPC_API_VERSION >= 14 devlist.reset(upnpDiscover(2000, nullptr, nullptr, 0, 0, 2, &upnperror)); #else devlist.reset(upnpDiscover(2000, nullptr, nullptr, 0, 0, &upnperror)); #endif if (!devlist) { WARN_LOG(NETPLAY, "An error occurred trying to discover UPnP devices."); s_error = true; return false; } // Look for the IGD for (UPNPDev* dev = devlist.get(); dev; dev = dev->pNext) { if (!std::strstr(dev->st, "InternetGatewayDevice")) continue; int desc_xml_size = 0; std::unique_ptr<char, decltype(&std::free)> desc_xml(nullptr, std::free); int statusCode = 200; #if MINIUPNPC_API_VERSION >= 16 desc_xml.reset( static_cast<char*>(miniwget_getaddr(dev->descURL, &desc_xml_size, s_our_ip.data(), static_cast<int>(s_our_ip.size()), 0, &statusCode))); #else desc_xml.reset(static_cast<char*>(miniwget_getaddr( dev->descURL, &desc_xml_size, s_our_ip.data(), static_cast<int>(s_our_ip.size()), 0))); #endif if (desc_xml && statusCode == 200) { parserootdesc(desc_xml.get(), desc_xml_size, &s_data); GetUPNPUrls(&s_urls, &s_data, dev->descURL, 0); NOTICE_LOG(NETPLAY, "Got info from IGD at %s.", dev->descURL); break; } else { WARN_LOG(NETPLAY, "Error getting info from IGD at %s.", dev->descURL); } } s_inited = true; return true; }
void init_upnp (void) { struct UPNPDev * devlist; struct UPNPDev * dev; char * descXML; int descXMLsize = 0; int res = 0; char IPAddress[40]; int r; if (!sv_upnp) return; memset(&urls, 0, sizeof(struct UPNPUrls)); memset(&data, 0, sizeof(struct IGDdatas)); Printf(PRINT_HIGH, "UPnP: Discovering router (max 1 unit supported)\n"); devlist = upnpDiscover(sv_upnp_discovertimeout.asInt(), NULL, NULL, 0, 0, &res); if (!devlist || res != UPNPDISCOVER_SUCCESS) { Printf(PRINT_HIGH, "UPnP: Router not found or timed out, error %d\n", res); is_upnp_ok = false; return; } dev = devlist; while (dev) { if (strstr (dev->st, "InternetGatewayDevice")) break; dev = dev->pNext; } if (!dev) dev = devlist; /* defaulting to first device */ //Printf(PRINT_HIGH, "UPnP device :\n" // " desc: %s\n st: %s\n", // dev->descURL, dev->st); descXML = (char *)miniwget(dev->descURL, &descXMLsize, 0); if (descXML) { parserootdesc (descXML, descXMLsize, &data); free (descXML); descXML = NULL; GetUPNPUrls (&urls, &data, dev->descURL, 0); } freeUPNPDevlist(devlist); r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, IPAddress); if (r != 0) { Printf(PRINT_HIGH, "UPnP: Router found but unable to get external IP address\n"); is_upnp_ok = false; } else { Printf(PRINT_HIGH, "UPnP: Router found, external IP address is: %s\n", IPAddress); // Store ip address just in case admin wants it sv_upnp_externalip.ForceSet(IPAddress); is_upnp_ok = true; } }