/* simpleUPnPcommand2 : * not so simple ! * return values : * pointer - OK * NULL - error */ static char * simpleUPnPcommand2(SOCKET s, const char * url, const char * service, const char * action, struct UPNParg * args, int * bufsize, const char * httpversion) { char hostname[MAXHOSTNAMELEN+1]; unsigned short port = 0; char * path; char soapact[128]; char soapbody[2048]; int soapbodylen; char * buf; int n; int status_code; *bufsize = 0; snprintf(soapact, sizeof(soapact), "%s#%s", service, action); if(args==NULL) { soapbodylen = snprintf(soapbody, sizeof(soapbody), "<?xml version=\"1.0\"?>\r\n" "<" SOAPPREFIX ":Envelope " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" "</" SERVICEPREFIX ":%s>" "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>" "\r\n", action, service, action); if ((unsigned int)soapbodylen >= sizeof(soapbody)) return NULL; } else { char * p; const char * pe, * pv; const char * const pend = soapbody + sizeof(soapbody); soapbodylen = snprintf(soapbody, sizeof(soapbody), "<?xml version=\"1.0\"?>\r\n" "<" SOAPPREFIX ":Envelope " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", action, service); if ((unsigned int)soapbodylen >= sizeof(soapbody)) return NULL; p = soapbody + soapbodylen; while(args->elt) { if(p >= pend) /* check for space to write next byte */ return NULL; *(p++) = '<'; pe = args->elt; while(p < pend && *pe) *(p++) = *(pe++); if(p >= pend) /* check for space to write next byte */ return NULL; *(p++) = '>'; if((pv = args->val)) { while(p < pend && *pv) *(p++) = *(pv++); } if((p+2) > pend) /* check for space to write next 2 bytes */ return NULL; *(p++) = '<'; *(p++) = '/'; pe = args->elt; while(p < pend && *pe) *(p++) = *(pe++); if(p >= pend) /* check for space to write next byte */ return NULL; *(p++) = '>'; args++; } if((p+4) > pend) /* check for space to write next 4 bytes */ return NULL; *(p++) = '<'; *(p++) = '/'; *(p++) = SERVICEPREFIX2; *(p++) = ':'; pe = action; while(p < pend && *pe) *(p++) = *(pe++); strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n", pend - p); if(soapbody[sizeof(soapbody)-1]) /* strncpy pads buffer with 0s, so if it doesn't end in 0, could not fit full string */ return NULL; } if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; if(ISINVALID(s)) { s = connecthostport(hostname, port, 0); if(ISINVALID(s)) { /* failed to connect */ return NULL; } } n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); if(n<=0) { #ifdef DEBUG printf("Error sending SOAP request\n"); #endif closesocket(s); return NULL; } buf = getHTTPResponse(s, bufsize, &status_code); #ifdef DEBUG if(*bufsize > 0 && buf) { printf("HTTP %d SOAP Response :\n%.*s\n", status_code, *bufsize, buf); } else { printf("HTTP %d, empty SOAP response. size=%d\n", status_code, *bufsize); } #endif closesocket(s); return buf; }
/* simpleUPnPcommand2 : * not so simple ! * return values : * pointer - OK * NULL - error */ char * simpleUPnPcommand2(int s, const char * url, const char * service, const char * action, struct UPNParg * args, int * bufsize, const char * httpversion) { char hostname[MAXHOSTNAMELEN+1]; unsigned short port = 0; char * path; char soapact[128]; char soapbody[2048]; char * buf; int n; *bufsize = 0; snprintf(soapact, sizeof(soapact), "%s#%s", service, action); if(args==NULL) { /*soapbodylen = */snprintf(soapbody, sizeof(soapbody), "<?xml version=\"1.0\"?>\r\n" "<" SOAPPREFIX ":Envelope " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">" "</" SERVICEPREFIX ":%s>" "</" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>" "\r\n", action, service, action); } else { char * p; const char * pe, * pv; int soapbodylen; soapbodylen = snprintf(soapbody, sizeof(soapbody), "<?xml version=\"1.0\"?>\r\n" "<" SOAPPREFIX ":Envelope " "xmlns:" SOAPPREFIX "=\"http://schemas.xmlsoap.org/soap/envelope/\" " SOAPPREFIX ":encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" "<" SOAPPREFIX ":Body>" "<" SERVICEPREFIX ":%s xmlns:" SERVICEPREFIX "=\"%s\">", action, service); p = soapbody + soapbodylen; while(args->elt) { /* check that we are never overflowing the string... */ if(soapbody + sizeof(soapbody) <= p + 100) { /* we keep a margin of at least 100 bytes */ return NULL; } *(p++) = '<'; pe = args->elt; while(*pe) *(p++) = *(pe++); *(p++) = '>'; if((pv = args->val)) { while(*pv) *(p++) = *(pv++); } *(p++) = '<'; *(p++) = '/'; pe = args->elt; while(*pe) *(p++) = *(pe++); *(p++) = '>'; args++; } *(p++) = '<'; *(p++) = '/'; *(p++) = SERVICEPREFIX2; *(p++) = ':'; pe = action; while(*pe) *(p++) = *(pe++); strncpy(p, "></" SOAPPREFIX ":Body></" SOAPPREFIX ":Envelope>\r\n", soapbody + sizeof(soapbody) - p); } if(!parseURL(url, hostname, &port, &path, NULL)) return NULL; if(s < 0) { s = connecthostport(hostname, port, 0); if(s < 0) { /* failed to connect */ return NULL; } } n = soapPostSubmit(s, path, hostname, port, soapact, soapbody, httpversion); if(n<=0) { #ifdef DEBUG printf("Error sending SOAP request\n"); #endif closesocket(s); return NULL; } buf = getHTTPResponse(s, bufsize); #ifdef DEBUG if(*bufsize > 0 && buf) { printf("SOAP Response :\n%.*s\n", *bufsize, buf); } #endif closesocket(s); return buf; }
/* miniwget3() : * do all the work. * Return NULL if something failed. */ static void * miniwget3(const char * host, unsigned short port, const char * path, int * size, char * addr_str, int addr_str_len, const char * httpversion, unsigned int scope_id, int * status_code) { char buf[2048]; int s; int n; int len; int sent; void * content; *size = 0; s = connecthostport(host, port, scope_id); if(s < 0) return NULL; /* get address for caller ! */ if(addr_str) { struct sockaddr_storage saddr; socklen_t saddrlen; saddrlen = sizeof(saddr); if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0) { perror("getsockname"); } else { #if defined(__amigaos__) && !defined(__amigaos4__) /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD); * But his function make a string with the port : nn.nn.nn.nn:port */ /* if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr), NULL, addr_str, (DWORD *)&addr_str_len)) { printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError()); }*/ /* the following code is only compatible with ip v4 addresses */ strncpy(addr_str, inet_ntoa(((struct sockaddr_in *)&saddr)->sin_addr), addr_str_len); #else #if 0 if(saddr.sa_family == AF_INET6) { inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)&saddr)->sin6_addr), addr_str, addr_str_len); } else { inet_ntop(AF_INET, &(((struct sockaddr_in *)&saddr)->sin_addr), addr_str, addr_str_len); } #endif /* getnameinfo return ip v6 address with the scope identifier * such as : 2a01:e35:8b2b:7330::%4281128194 */ n = getnameinfo((const struct sockaddr *)&saddr, saddrlen, addr_str, addr_str_len, NULL, 0, NI_NUMERICHOST | NI_NUMERICSERV); if(n != 0) { #ifdef _WIN32 fprintf(stderr, "getnameinfo() failed : %d\n", n); #else fprintf(stderr, "getnameinfo() failed : %s\n", gai_strerror(n)); #endif } #endif } #ifdef DEBUG printf("address miniwget : %s\n", addr_str); #endif } len = snprintf(buf, sizeof(buf), "GET %s HTTP/%s\r\n" "Host: %s:%d\r\n" "Connection: Close\r\n" "User-Agent: " OS_STRING ", " UPNP_VERSION_STRING ", MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" "\r\n", path, httpversion, host, port); if ((unsigned int)len >= sizeof(buf)) { closesocket(s); return NULL; } sent = 0; /* sending the HTTP request */ while(sent < len) { n = send(s, buf+sent, len-sent, 0); if(n < 0) { perror("send"); closesocket(s); return NULL; } else { sent += n; } } content = getHTTPResponse(s, size, status_code); closesocket(s); return content; }