source: trunk/third-party/miniupnp/miniwget.c @ 10285

Last change on this file since 10285 was 10285, checked in by livings124, 11 years ago

update miniupnp to 1.4

File size: 7.0 KB
Line 
1/* $Id: miniwget.c,v 1.31 2009/12/04 11:29:19 nanard Exp $ */
2/* Project : miniupnp
3 * Author : Thomas Bernard
4 * Copyright (c) 2005-2009 Thomas Bernard
5 * This software is subject to the conditions detailed in the
6 * LICENCE file provided in this distribution.
7 * */
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include "miniupnpc.h"
12#ifdef WIN32
13#include <winsock2.h>
14#include <io.h>
15#define MAXHOSTNAMELEN 64
16#define MIN(x,y) (((x)<(y))?(x):(y))
17#define snprintf _snprintf
18#define herror
19#define socklen_t int
20#else
21#include <unistd.h>
22#include <sys/param.h>
23#if defined(__amigaos__) && !defined(__amigaos4__)
24#define socklen_t int
25#else
26#include <sys/select.h>
27#endif
28#include <sys/socket.h>
29#include <netdb.h>
30#include <netinet/in.h>
31#include <arpa/inet.h>
32#include <errno.h>
33#include <time.h>
34#define closesocket close
35#define MINIUPNPC_IGNORE_EINTR
36#endif
37#if defined(__sun) || defined(sun)
38#define MIN(x,y) (((x)<(y))?(x):(y))
39#endif
40#if defined(__amigaos__) || defined(__amigaos4__)
41#define herror(A) printf("%s\n", A)
42#endif
43
44#include "miniupnpcstrings.h"
45#include "miniwget.h"
46
47/* miniwget2() :
48 * */
49static void *
50miniwget2(const char * url, const char * host,
51                  unsigned short port, const char * path,
52                  int * size, char * addr_str, int addr_str_len)
53{
54        char buf[2048];
55    int s;
56        struct sockaddr_in dest;
57        struct hostent *hp;
58        int n;
59        int len;
60        int sent;
61#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
62        struct timeval timeout;
63#endif
64        *size = 0;
65        hp = gethostbyname(host);
66        if(hp==NULL)
67        {
68                herror(host);
69                return NULL;
70        }
71        /*  memcpy((char *)&dest.sin_addr, hp->h_addr, hp->h_length);  */
72        memcpy(&dest.sin_addr, hp->h_addr, sizeof(dest.sin_addr));
73        memset(dest.sin_zero, 0, sizeof(dest.sin_zero));
74        s = socket(PF_INET, SOCK_STREAM, 0);
75        if(s < 0)
76        {
77                perror("socket");
78                return NULL;
79        }
80#ifdef MINIUPNPC_SET_SOCKET_TIMEOUT
81        /* setting a 3 seconds timeout for the connect() call */
82        timeout.tv_sec = 3;
83        timeout.tv_usec = 0;
84        if(setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval)) < 0)
85        {
86                perror("setsockopt");
87        }
88        timeout.tv_sec = 3;
89        timeout.tv_usec = 0;
90        if(setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
91        {
92                perror("setsockopt");
93        }
94#endif
95        dest.sin_family = AF_INET;
96        dest.sin_port = htons(port);
97        n = connect(s, (struct sockaddr *)&dest, sizeof(struct sockaddr_in));
98#ifdef MINIUPNPC_IGNORE_EINTR
99        while(n < 0 && errno == EINTR)
100        {
101                socklen_t len;
102                fd_set wset;
103                int err;
104                FD_ZERO(&wset);
105                FD_SET(s, &wset);
106                if((n = select(s + 1, NULL, &wset, NULL, NULL)) == -1 && errno == EINTR)
107                        continue;
108                /*len = 0;*/
109                /*n = getpeername(s, NULL, &len);*/
110                len = sizeof(err);
111                if(getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
112                        perror("getsockopt");
113                        closesocket(s);
114                        return NULL;
115                }
116                if(err != 0) {
117                        errno = err;
118                        n = -1;
119                }
120        }
121#endif
122        if(n<0)
123        {
124                perror("connect");
125                closesocket(s);
126                return NULL;
127        }
128
129        /* get address for caller ! */
130        if(addr_str)
131        {
132                struct sockaddr_in saddr;
133                socklen_t saddrlen;
134
135                saddrlen = sizeof(saddr);
136                if(getsockname(s, (struct sockaddr *)&saddr, &saddrlen) < 0)
137                {
138                        perror("getsockname");
139                }
140                else
141                {
142#if defined(WIN32) || (defined(__amigaos__) && !defined(__amigaos4__))
143        /* using INT WINAPI WSAAddressToStringA(LPSOCKADDR, DWORD, LPWSAPROTOCOL_INFOA, LPSTR, LPDWORD);
144     * But his function make a string with the port :  nn.nn.nn.nn:port */
145/*              if(WSAAddressToStringA((SOCKADDR *)&saddr, sizeof(saddr),
146                            NULL, addr_str, (DWORD *)&addr_str_len))
147                {
148                    printf("WSAAddressToStringA() failed : %d\n", WSAGetLastError());
149                }*/
150                        strncpy(addr_str, inet_ntoa(saddr.sin_addr), addr_str_len);
151#else
152                        inet_ntop(AF_INET, &saddr.sin_addr, addr_str, addr_str_len);
153#endif
154                }
155#ifdef DEBUG
156                printf("address miniwget : %s\n", addr_str);
157#endif
158        }
159
160        len = snprintf(buf, sizeof(buf),
161                 "GET %s HTTP/1.0\r\n"
162                             "Host: %s:%d\r\n"
163                                 "Connection: Close\r\n"
164                                 "User-Agent: " OS_STRING ", UPnP/1.0, MiniUPnPc/" MINIUPNPC_VERSION_STRING "\r\n"
165
166                                 "\r\n",
167                    path, host, port);
168        sent = 0;
169        /* sending the HTTP request */
170        while(sent < len)
171        {
172                n = send(s, buf+sent, len-sent, 0);
173                if(n < 0)
174                {
175                        perror("send");
176                        closesocket(s);
177                        return NULL;
178                }
179                else
180                {
181                        sent += n;
182                }
183        }
184        {
185                /* TODO : in order to support HTTP/1.1, chunked transfer encoding
186                 *        must be supported. That means parsing of headers must be
187                 *        added.                                                   */
188                int headers=1;
189                char * respbuffer = NULL;
190                int allreadyread = 0;
191                /*while((n = recv(s, buf, 2048, 0)) > 0)*/
192                while((n = ReceiveData(s, buf, 2048, 5000)) > 0)
193                {
194                        if(headers)
195                        {
196                                int i=0;
197                                while(i<n-3)
198                                {
199                                        /* searching for the end of the HTTP headers */
200                                        if(buf[i]=='\r' && buf[i+1]=='\n'
201                                           && buf[i+2]=='\r' && buf[i+3]=='\n')
202                                        {
203                                                headers = 0;    /* end */
204                                                if(i<n-4)
205                                                {
206                                                        /* Copy the content into respbuffet */
207                                                        respbuffer = (char *)realloc((void *)respbuffer, 
208                                                                                                                 allreadyread+(n-i-4));
209                                                        memcpy(respbuffer+allreadyread, buf + i + 4, n-i-4);
210                                                        allreadyread += (n-i-4);
211                                                }
212                                                break;
213                                        }
214                                        i++;
215                                }
216                        }
217                        else
218                        {
219                                respbuffer = (char *)realloc((void *)respbuffer, 
220                                                                 allreadyread+n);
221                                memcpy(respbuffer+allreadyread, buf, n);
222                                allreadyread += n;
223                        }
224                }
225                *size = allreadyread;
226#ifdef DEBUG
227                printf("%d bytes read\n", *size);
228#endif
229                closesocket(s);
230                return respbuffer;
231        }
232}
233
234/* parseURL()
235 * arguments :
236 *   url :              source string not modified
237 *   hostname : hostname destination string (size of MAXHOSTNAMELEN+1)
238 *   port :             port (destination)
239 *   path :             pointer to the path part of the URL
240 *
241 * Return values :
242 *    0 - Failure
243 *    1 - Success         */
244int parseURL(const char * url, char * hostname, unsigned short * port, char * * path)
245{
246        char * p1, *p2, *p3;
247        p1 = strstr(url, "://");
248        if(!p1)
249                return 0;
250        p1 += 3;
251        if(  (url[0]!='h') || (url[1]!='t')
252           ||(url[2]!='t') || (url[3]!='p'))
253                return 0;
254        p2 = strchr(p1, ':');
255        p3 = strchr(p1, '/');
256        if(!p3)
257                return 0;
258        memset(hostname, 0, MAXHOSTNAMELEN + 1);
259        if(!p2 || (p2>p3))
260        {
261                strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p3-p1)));
262                *port = 80;
263        }
264        else
265        {
266                strncpy(hostname, p1, MIN(MAXHOSTNAMELEN, (int)(p2-p1)));
267                *port = 0;
268                p2++;
269                while( (*p2 >= '0') && (*p2 <= '9'))
270                {
271                        *port *= 10;
272                        *port += (unsigned short)(*p2 - '0');
273                        p2++;
274                }
275        }
276        *path = p3;
277        return 1;
278}
279
280void * miniwget(const char * url, int * size)
281{
282        unsigned short port;
283        char * path;
284        /* protocol://host:port/chemin */
285        char hostname[MAXHOSTNAMELEN+1];
286        *size = 0;
287        if(!parseURL(url, hostname, &port, &path))
288                return NULL;
289        return miniwget2(url, hostname, port, path, size, 0, 0);
290}
291
292void * miniwget_getaddr(const char * url, int * size, char * addr, int addrlen)
293{
294        unsigned short port;
295        char * path;
296        /* protocol://host:port/chemin */
297        char hostname[MAXHOSTNAMELEN+1];
298        *size = 0;
299        if(addr)
300                addr[0] = '\0';
301        if(!parseURL(url, hostname, &port, &path))
302                return NULL;
303        return miniwget2(url, hostname, port, path, size, addr, addrlen);
304}
305
Note: See TracBrowser for help on using the repository browser.