/* $Id: miniwget.c,v 1.31 2009/12/04 11:29:19 nanard Exp $ */ /* Project : miniupnp * Author : Thomas Bernard * Copyright (c) 2005-2009 Thomas Bernard * This software is subject to the conditions detailed in the * LICENCE file provided in this distribution. * */ #include #include #include #include "miniupnpc.h" #ifdef WIN32 #include #include #define MAXHOSTNAMELEN 64 #define MIN(x,y) (((x)<(y))?(x):(y)) #define snprintf _snprintf #define herror #define socklen_t int #else #include #include #if defined(__amigaos__) && !defined(__amigaos4__) #define socklen_t int #else #include #endif #include #include #include #include #include #include #define closesocket close #define MINIUPNPC_IGNORE_EINTR #endif #if defined(__sun) || defined(sun) #define MIN(x,y) (((x)<(y))?(x):(y)) #endif #if defined(__amigaos__) || defined(__amigaos4__) #define herror(A) printf("%s\n", A) #endif #include "miniupnpcstrings.h" #include "miniwget.h" /* miniwget2() : * */ static void * miniwget2(const char * url, const char * host, unsigned short port, const char * path, int * size, char * addr_str, int addr_str_len) { char buf[2048]; int s; struct sockaddr_in dest; struct hostent *hp; int n; int len; int sent; #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT struct timeval timeout; #endif *size = 0; hp = gethostbyname(host); if(hp==NULL) { herror(host); return NULL; } /* memcpy((char *)&dest.sin_addr, hp->h_addr, hp->h_length); */ memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr)); memset(dest.sin_zero, 0, sizeof(dest.sin_zero)); s = socket(PF_INET, SOCK_STREAM, 0); if(s < 0) { perror("socket"); return NULL; } #ifdef MINIUPNPC_SET_SOCKET_TIMEOUT /* setting a 3 seconds timeout for the connect() call */ timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0) { perror("setsockopt"); } timeout.tv_sec = 3; timeout.tv_usec = 0; if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0) { perror("setsockopt"); } #endif dest.sin_family = AF_INET; dest.sin_port = htons(port); n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in)); #ifdef MINIUPNPC_IGNORE_EINTR while(n < 0 && errno == EINTR) { socklen_t len; fd_set wset; int err; FD_ZERO(&wset); FD_SET(s, &wset); if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR) continue; /*len = 0;*/ /*n = getpeername(s, NULL, &len);*/ len = sizeof(err); if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { perror("getsockopt"); closesocket(s); return NULL; } if(err != 0) { errno = err; n = -1; } } #endif if(n<0) { perror("connect"); closesocket(s); return NULL; } /* get address for caller ! */ if(addr_str) { struct sockaddr_in saddr; socklen_t saddrlen; saddrlen = sizeof(saddr); if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0) { perror("getsockname"); } else { #if defined(WIN32) || (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()); }*/ strncpy(addr_str, inet_ntoa(saddr.sin_addr), addr_str_len); #else inet_ntop(AF_INET, &saddr.sin_addr, addr_str, addr_str_len); #endif } #ifdef DEBUG printf("address miniwget : %s\n", addr_str); #endif } len = snprintf(buf, sizeof(buf), "GET %s HTTP/1.0\r\n" "Host: %s:%d\r\n" "Connection: Close\r\n" "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n" "\r\n", path, host, port); 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; } } { /* TODO : in order to support HTTP/1.1, chunked transfer encoding * must be supported. That means parsing of headers must be * added. */ int headers=1; char * respbuffer = NULL; int allreadyread = 0; /*while((n = recv(s, buf, 2048, 0)) > 0)*/ while((n = ReceiveData(s, buf, 2048, 5000)) > 0) { if(headers) { int i=0; while(ip3)) { strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1))); *port = 80; } else { strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1))); *port = 0; p2++; while( (*p2 >= '0') && (*p2 <= '9')) { *port *= 10; *port += (unsigned short)(*p2 - '0'); p2++; } } *path = p3; return 1; } void * miniwget(const char * url, int * size) { unsigned short port; char * path; /* protocol://host:port/chemin */ char hostname[MAXHOSTNAMELEN+1]; *size = 0; if(!parseURL(url, hostname, &port, &path)) return NULL; return miniwget2(url, hostname, port, path, size, 0, 0); } void * miniwget_getaddr(const char * url, int * size, char * addr, int addrlen) { unsigned short port; char * path; /* protocol://host:port/chemin */ char hostname[MAXHOSTNAMELEN+1]; *size = 0; if(addr) addr[0] = '\0'; if(!parseURL(url, hostname, &port, &path)) return NULL; return miniwget2(url, hostname, port, path, size, addr, addrlen); }