source: branches/1.9x/third-party/miniupnp/miniwget.c @ 10578

Last change on this file since 10578 was 10578, checked in by charles, 11 years ago

(1.9x third-party) upgrade our miniupnp snapshot for #3125 "UPnP fails on Linksys AM300 modem/router"

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