* g10.c (main): Enhance the version-specific config file code to try for
[gnupg.git] / util / http.c
1 /* http.c  -  HTTP protocol handler
2  *      Copyright (C) 1999, 2001, 2002, 2003 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
6  * GnuPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GnuPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <errno.h>
28
29 #ifdef _WIN32
30 #include <windows.h>
31 #else
32 #include <unistd.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/time.h>
36 #include <time.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <netdb.h>
40 #endif
41
42 #include "util.h"
43 #include "iobuf.h"
44 #include "i18n.h"
45 #include "http.h"
46 #include "srv.h"
47
48 #ifdef __riscos__
49 #define HTTP_PROXY_ENV           "GnuPG$HttpProxy"
50 #define HTTP_PROXY_ENV_PRINTABLE "<GnuPG$HttpProxy>"
51 #else
52 #define HTTP_PROXY_ENV           "http_proxy"
53 #define HTTP_PROXY_ENV_PRINTABLE "$http_proxy"
54 #endif
55
56 #ifdef _WIN32
57 #define sock_close(a)  closesocket(a)
58 #else
59 #define sock_close(a)  close(a)
60 #endif
61
62 #define MAX_LINELEN 20000  /* max. length of a HTTP line */
63 #define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz"   \
64                         "ABCDEFGHIJKLMNOPQRSTUVWXYZ"   \
65                         "01234567890@"                 \
66                         "!\"#$%&'()*+,-./:;<=>?[\\]^_{|}~"
67
68 #ifndef EAGAIN
69 #define EAGAIN  EWOULDBLOCK
70 #endif
71
72 static int parse_uri( PARSED_URI *ret_uri, const char *uri );
73 static void release_parsed_uri( PARSED_URI uri );
74 static int do_parse_uri( PARSED_URI uri, int only_local_part );
75 static int remove_escapes( byte *string );
76 static int insert_escapes( byte *buffer, const byte *string,
77                                          const byte *special );
78 static URI_TUPLE parse_tuple( byte *string );
79 static int send_request( HTTP_HD hd );
80 static byte *build_rel_path( PARSED_URI uri );
81 static int parse_response( HTTP_HD hd );
82
83 static int connect_server(const char *server, ushort port, unsigned int flags);
84 static int write_server( int sock, const char *data, size_t length );
85
86 #ifdef _WIN32
87 static void
88 deinit_sockets (void)
89 {
90     WSACleanup();
91 }
92
93 static void
94 init_sockets (void)
95 {
96     static int initialized;
97     static WSADATA wsdata;
98
99     if (initialized)
100         return;
101
102     if( WSAStartup( 0x0101, &wsdata ) ) {
103         log_error ("error initializing socket library: ec=%d\n", 
104                     (int)WSAGetLastError () );
105         return;
106     }
107     if( wsdata.wVersion < 0x0001 ) {
108         log_error ("socket library version is %x.%x - but 1.1 needed\n",
109                    LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion));
110         WSACleanup();
111         return;
112     }
113     atexit ( deinit_sockets );
114     initialized = 1;
115 }
116 #endif /*_WIN32*/
117
118
119 int
120 http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url,
121                                               unsigned int flags )
122 {
123     int rc;
124
125     if( !(reqtype == HTTP_REQ_GET || reqtype == HTTP_REQ_POST) )
126         return G10ERR_INV_ARG;
127
128     /* initialize the handle */
129     memset( hd, 0, sizeof *hd );
130     hd->sock = -1;
131     hd->initialized = 1;
132     hd->req_type = reqtype;
133     hd->flags = flags;
134
135     rc = parse_uri( &hd->uri, url );
136     if( !rc ) {
137         rc = send_request( hd );
138         if( !rc ) {
139             hd->fp_write = iobuf_sockopen( hd->sock , "w" );
140             if( hd->fp_write )
141                 return 0;
142             rc = G10ERR_GENERAL;
143         }
144     }
145
146     if( !hd->fp_read && !hd->fp_write && hd->sock != -1 )
147         sock_close( hd->sock );
148     iobuf_close( hd->fp_read );
149     iobuf_close( hd->fp_write);
150     release_parsed_uri( hd->uri );
151     hd->initialized = 0;
152
153     return rc;
154 }
155
156
157 void
158 http_start_data( HTTP_HD hd )
159 {
160     iobuf_flush ( hd->fp_write );
161     if( !hd->in_data ) {
162         write_server (hd->sock, "\r\n", 2);
163         hd->in_data = 1;
164     }
165 }
166
167
168 int
169 http_wait_response( HTTP_HD hd, unsigned int *ret_status )
170 {
171     int rc;
172
173     http_start_data( hd ); /* make sure that we are in the data */
174
175 #if 0
176     hd->sock = dup( hd->sock ); 
177     if( hd->sock == -1 )
178         return G10ERR_GENERAL;
179 #endif
180     iobuf_ioctl (hd->fp_write, 1, 1, NULL); /* keep the socket open */
181     iobuf_close (hd->fp_write);
182     hd->fp_write = NULL;
183     if ( !(hd->flags & HTTP_FLAG_NO_SHUTDOWN) )
184         shutdown( hd->sock, 1 );
185     hd->in_data = 0;
186
187     hd->fp_read = iobuf_sockopen( hd->sock , "r" );
188     if( !hd->fp_read )
189         return G10ERR_GENERAL;
190
191     rc = parse_response( hd );
192     if( !rc && ret_status )
193         *ret_status = hd->status_code;
194
195     return rc;
196 }
197
198
199 int
200 http_open_document( HTTP_HD hd, const char *document, unsigned int flags )
201 {
202     int rc;
203
204     rc = http_open( hd, HTTP_REQ_GET, document, flags );
205     if( rc )
206         return rc;
207
208     rc = http_wait_response( hd, NULL );
209     if( rc )
210         http_close( hd );
211
212     return rc;
213 }
214
215
216
217
218 void
219 http_close( HTTP_HD hd )
220 {
221     if( !hd || !hd->initialized )
222         return;
223     if( !hd->fp_read && !hd->fp_write && hd->sock != -1 )
224         sock_close( hd->sock );
225     iobuf_close( hd->fp_read );
226     iobuf_close( hd->fp_write );
227     release_parsed_uri( hd->uri );
228     m_free( hd->buffer );
229     hd->initialized = 0;
230 }
231
232
233
234 /****************
235  * Parse an URI and put the result into the newly allocated ret_uri.
236  * The caller must always use release_parsed_uri to releases the
237  * resources (even on an error).
238  */
239 static int
240 parse_uri( PARSED_URI *ret_uri, const char *uri )
241 {
242    *ret_uri = m_alloc_clear( sizeof(**ret_uri) + strlen(uri) );
243    strcpy( (*ret_uri)->buffer, uri );
244    return do_parse_uri( *ret_uri, 0 );
245 }
246
247 static void
248 release_parsed_uri( PARSED_URI uri )
249 {
250     if( uri )
251     {
252         URI_TUPLE r, r2;
253
254         for( r = uri->query; r; r = r2 ) {
255             r2 = r->next;
256             m_free( r );
257         }
258         m_free( uri );
259     }
260 }
261
262 static int
263 do_parse_uri( PARSED_URI uri, int only_local_part )
264 {
265     URI_TUPLE *tail;
266     char *p, *p2, *p3;
267     int n;
268
269     p = uri->buffer;
270     n = strlen( uri->buffer );
271     /* initialize all fields to an empty string or an empty list */
272     uri->scheme = uri->host = uri->path = p + n;
273     uri->port = 0;
274     uri->params = uri->query = NULL;
275
276     /* a quick validity check */
277     if( strspn( p, VALID_URI_CHARS) != n )
278         return G10ERR_BAD_URI; /* invalid characters found */
279
280     if( !only_local_part ) {
281         /* find the scheme */
282         if( !(p2 = strchr( p, ':' ) ) || p2 == p )
283            return G10ERR_BAD_URI; /* No scheme */
284         *p2++ = 0;
285         strlwr( p );
286         uri->scheme = p;
287         uri->port = 80;
288         if( !strcmp( uri->scheme, "http" ) )
289             ;
290         else if( !strcmp( uri->scheme, "x-hkp" ) ) /* same as HTTP */
291             uri->port = 11371;
292         else
293             return G10ERR_INVALID_URI; /* Unsupported scheme */
294
295         p = p2;
296
297         /* find the hostname */
298         if( *p != '/' )
299             return G10ERR_INVALID_URI; /* does not start with a slash */
300
301         p++;
302         if( *p == '/' ) {  /* there seems to be a hostname */
303             p++;
304             if( (p2 = strchr(p, '/')) )
305                 *p2++ = 0;
306             strlwr( p );
307             uri->host = p;
308             if( (p3=strchr( p, ':' )) ) {
309                 *p3++ = 0;
310                 uri->port = atoi( p3 );
311             }
312
313             uri->host = p;
314             if( (n = remove_escapes( uri->host )) < 0 )
315                 return G10ERR_BAD_URI;
316             if( n != strlen( p ) )
317                 return G10ERR_BAD_URI; /* hostname with a Nul in it */
318             p = p2 ? p2 : NULL;
319         }
320     } /* end global URI part */
321
322     /* parse the pathname part */
323     if( !p || !*p ) /* we don't have a path */
324         return 0; /* and this is okay */
325
326     /* todo: here we have to check params */
327
328     /* do we have a query part */
329     if( (p2 = strchr( p, '?' )) )
330         *p2++ = 0;
331
332     uri->path = p;
333     if( (n = remove_escapes( p )) < 0 )
334         return G10ERR_BAD_URI;
335     if( n != strlen( p ) )
336         return G10ERR_BAD_URI; /* path with a Nul in it */
337     p = p2 ? p2 : NULL;
338
339     if( !p || !*p ) /* we don't have a query string */
340         return 0;   /* okay */
341
342     /* now parse the query string */
343     tail = &uri->query;
344     for(;;) {
345         URI_TUPLE elem;
346
347         if( (p2 = strchr( p, '&' )) )
348             *p2++ = 0;
349         if( !(elem = parse_tuple( p )) )
350             return G10ERR_BAD_URI;
351         *tail = elem;
352         tail = &elem->next;
353
354         if( !p2 )
355            break; /* ready */
356         p = p2;
357     }
358
359     return 0;
360 }
361
362
363
364 /****************
365  * Remove all %xx escapes; this is done inplace.
366  * Returns: new length of the string.
367  */
368 static int
369 remove_escapes( byte *string )
370 {
371     int n = 0;
372     byte *p, *s;
373
374     for(p=s=string; *s ; s++ ) {
375         if( *s == '%' ) {
376             if( s[1] && s[2] && isxdigit(s[1]) && isxdigit(s[2]) ) {
377                 s++;
378                 *p  = *s >= '0' && *s <= '9' ? *s - '0' :
379                       *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10 ;
380                 *p <<= 4;
381                 s++;
382                 *p |= *s >= '0' && *s <= '9' ? *s - '0' :
383                       *s >= 'A' && *s <= 'F' ? *s - 'A' + 10 : *s - 'a' + 10 ;
384                 p++;
385                 n++;
386             }
387             else {
388                 *p++ = *s++;
389                 if( *s )
390                    *p++ = *s++;
391                 if( *s )
392                    *p++ = *s++;
393                 if( *s )
394                    *p = 0;
395                 return -1; /* bad URI */
396             }
397         }
398         else
399         {
400             *p++ = *s;
401             n++;
402         }
403     }
404     *p = 0; /* always keep a string terminator */
405     return n;
406 }
407
408
409 static int
410 insert_escapes( byte *buffer, const byte *string, const byte *special )
411 {
412     int n = 0;
413
414     for( ; *string; string++ ) {
415         if( strchr( VALID_URI_CHARS, *string )
416             && !strchr( special, *string ) )  {
417             if( buffer )
418                 *buffer++ = *string;
419             n++;
420         }
421         else {
422             if( buffer ) {
423                 sprintf( buffer, "%02X", *string );
424                 buffer += 3;
425             }
426             n += 3;
427         }
428     }
429     return n;
430 }
431
432
433
434
435
436 static URI_TUPLE
437 parse_tuple( byte *string )
438 {
439     byte *p = string;
440     byte *p2;
441     int n;
442     URI_TUPLE tuple;
443
444     if( (p2 = strchr( p, '=' )) )
445         *p2++ = 0;
446     if( (n = remove_escapes( p )) < 0 )
447         return NULL; /* bad URI */
448     if( n != strlen( p ) )
449        return NULL; /* name with a Nul in it */
450     tuple = m_alloc_clear( sizeof *tuple );
451     tuple->name = p;
452     if( !p2 )  {
453         /* we have only the name, so we assume an empty value string */
454         tuple->value = p + strlen(p);
455         tuple->valuelen = 0;
456     }
457     else { /* name and value */
458         if( (n = remove_escapes( p2 )) < 0 ) {
459             m_free( tuple );
460             return NULL; /* bad URI */
461         }
462         tuple->value = p2;
463         tuple->valuelen = n;
464     }
465     return tuple;
466 }
467
468
469 /****************
470  * Send a HTTP request to the server
471  * Returns 0 if the request was successful
472  */
473 static int
474 send_request( HTTP_HD hd )
475 {
476     const byte *server;
477     byte *request, *p;
478     ushort port;
479     int rc;
480     const char *http_proxy = NULL;
481
482     server = *hd->uri->host? hd->uri->host : "localhost";
483     port   = hd->uri->port?  hd->uri->port : 80;
484
485     if( (hd->flags & HTTP_FLAG_TRY_PROXY)
486         && (http_proxy = getenv( HTTP_PROXY_ENV )) ) {
487         PARSED_URI uri;
488
489         rc = parse_uri( &uri, http_proxy );
490         if (rc) {
491             log_error("invalid " HTTP_PROXY_ENV_PRINTABLE ": %s\n",
492                       g10_errstr(rc));
493             release_parsed_uri( uri );
494             return G10ERR_NETWORK;
495         }
496         hd->sock = connect_server( *uri->host? uri->host : "localhost",
497                                    uri->port? uri->port : 80, 0 );
498         release_parsed_uri( uri );
499     }
500     else
501       hd->sock = connect_server( server, port, hd->flags );
502
503     if( hd->sock == -1 )
504         return G10ERR_NETWORK;
505
506     p = build_rel_path( hd->uri );
507     request = m_alloc( strlen(server) + strlen(p) + 50 );
508     if( http_proxy ) {
509         sprintf( request, "%s http://%s:%hu%s%s HTTP/1.0\r\n",
510                           hd->req_type == HTTP_REQ_GET ? "GET" :
511                           hd->req_type == HTTP_REQ_HEAD? "HEAD":
512                           hd->req_type == HTTP_REQ_POST? "POST": "OOPS",
513                           server, port,  *p == '/'? "":"/", p );
514     }
515     else {
516         sprintf( request, "%s %s%s HTTP/1.0\r\n",
517                           hd->req_type == HTTP_REQ_GET ? "GET" :
518                           hd->req_type == HTTP_REQ_HEAD? "HEAD":
519                           hd->req_type == HTTP_REQ_POST? "POST": "OOPS",
520                                                   *p == '/'? "":"/", p );
521     }
522     m_free(p);
523
524     rc = write_server( hd->sock, request, strlen(request) );
525     m_free( request );
526
527     return rc;
528 }
529
530
531
532
533 /****************
534  * Build the relative path from the parsed URI.
535  * Minimal implementation.
536  */
537 static byte*
538 build_rel_path( PARSED_URI uri )
539 {
540     URI_TUPLE r;
541     byte *rel_path, *p;
542     int n;
543
544     /* count the needed space */
545     n = insert_escapes( NULL, uri->path, "%;?&" );
546     /* todo: build params */
547     for( r=uri->query; r; r = r->next ) {
548         n++; /* '?'/'&' */
549         n += insert_escapes( NULL, r->name, "%;?&=" );
550         n++; /* '='*/
551         n += insert_escapes( NULL, r->value, "%;?&=" );
552     }
553     n++;
554
555     /* now  allocate and copy */
556     p = rel_path = m_alloc( n );
557     n = insert_escapes( p, uri->path, "%;?&" );
558     p += n;
559     /* todo: add params */
560     for( r=uri->query; r; r = r->next ) {
561         *p++ = r == uri->query? '?':'&';
562         n = insert_escapes( p, r->name, "%;?&=" );
563         p += n;
564         *p++ = '=';
565         /* todo: use valuelen */
566         n = insert_escapes( p, r->value, "%;?&=" );
567         p += n;
568     }
569     *p = 0;
570     return rel_path;
571 }
572
573
574
575 /***********************
576  * Parse the response from a server.
577  * Returns: errorcode and sets some fileds in the handle
578  */
579 static int
580 parse_response( HTTP_HD hd )
581 {
582     byte *line, *p, *p2;
583     unsigned maxlen, len;
584
585     /* Wait for the status line */
586     do {
587         maxlen = MAX_LINELEN;
588         len = iobuf_read_line( hd->fp_read, &hd->buffer,
589                                             &hd->buffer_size, &maxlen );
590         line = hd->buffer;
591         if( !maxlen )
592             return -1; /* line has been truncated */
593         if( !len )
594             return -1; /* eof */
595     } while( !*line  );
596
597     if( (p = strchr( line, '/')) )
598         *p++ = 0;
599     if( !p || strcmp( line, "HTTP" ) )
600         return 0; /* assume http 0.9 */
601
602     if( (p2 = strpbrk( p, " \t" ) ) ) {
603         *p2++ = 0;
604         p2 += strspn( p2, " \t" );
605     }
606     if( !p2 )
607         return 0; /* assume http 0.9 */
608     p = p2;
609     /* todo: add HTTP version number check here */
610     if( (p2 = strpbrk( p, " \t" ) ) )
611         *p2++ = 0;
612     if( !isdigit(p[0]) || !isdigit(p[1]) || !isdigit(p[2]) || p[3] ) {
613          /* malformed HTTP statuscode - assume HTTP 0.9 */
614         hd->is_http_0_9 = 1;
615         hd->status_code = 200;
616         return 0;
617     }
618     hd->status_code = atoi( p );
619
620     /* skip all the header lines and wait for the empty line */
621     do {
622         maxlen = MAX_LINELEN;
623         len = iobuf_read_line( hd->fp_read, &hd->buffer,
624                                &hd->buffer_size, &maxlen );
625         line = hd->buffer;
626         /* we ignore truncated lines */
627         if( !len )
628             return -1; /* eof */
629         /* time lineendings */
630         if( (*line == '\r' && line[1] == '\n') || *line == '\n' )
631             *line = 0;
632     } while( len && *line  );
633
634     return 0;
635 }
636
637 #if 0
638 static int
639 start_server()
640 {
641     struct sockaddr_in mya;
642     struct sockaddr_in peer;
643     int fd, client;
644     fd_set rfds;
645     int addrlen;
646     int i;
647
648     if( (fd=socket(AF_INET,SOCK_STREAM, 0)) == -1 ) {
649         log_error("socket() failed: %s\n", strerror(errno));
650         return -1;
651     }
652     i = 1;
653     if( setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, (byte*)&i, sizeof(i) ) )
654         log_info("setsockopt(SO_REUSEADDR) failed: %s\n", strerror(errno) );
655
656     mya.sin_family=AF_INET;
657     memset(&mya.sin_addr, 0, sizeof(mya.sin_addr));
658     mya.sin_port=htons(11371);
659
660     if( bind( fd, (struct sockaddr *)&mya, sizeof(mya)) ) {
661         log_error("bind to port 11371 failed: %s\n", strerror(errno) );
662         sock_close( fd );
663         return -1;
664     }
665
666     if( listen( fd, 5 ) ) {
667         log_error("listen failed: %s\n", strerror(errno) );
668         sock_close( fd );
669         return -1;
670     }
671
672     for(;;) {
673         FD_ZERO(&rfds);
674         FD_SET( fd, &rfds );
675
676         if( select( fd+1, &rfds, NULL, NULL, NULL) <= 0 )
677             continue; /* ignore any errors */
678
679         if( !FD_ISSET( fd, &rfds ) )
680             continue;
681
682         addrlen = sizeof peer;
683         client = accept( fd, (struct sockaddr *)&peer, &addrlen);
684         if( client == -1 )
685             continue; /* oops */
686
687         log_info("connect from %s\n", inet_ntoa( peer.sin_addr ) );
688
689         fflush(stdout);
690         fflush(stderr);
691         if( !fork() ) {
692             int c;
693             FILE *fp;
694
695             fp = fdopen( client , "r" );
696             while( (c=getc(fp)) != EOF )
697                 putchar(c);
698             fclose(fp);
699             exit(0);
700         }
701         sock_close( client );
702     }
703
704
705     return 0;
706 }
707 #endif
708
709
710 static int
711 connect_server( const char *server, ushort port, unsigned int flags )
712 {
713   int sock=-1,srv,srvcount=0,connected=0;
714   struct srventry *srvlist=NULL;
715
716 #ifdef _WIN32
717   unsigned long inaddr;
718
719   init_sockets();
720   /* Win32 gethostbyname doesn't handle IP addresses internally, so we
721      try inet_addr first on that platform only. */
722   if((inaddr=inet_addr(server))!=SOCKET_ERROR)
723     {
724       struct sockaddr_in addr;
725
726       memset(&addr,0,sizeof(addr));
727
728       if((sock=socket(AF_INET,SOCK_STREAM,0))==INVALID_SOCKET)
729         {
730           log_error("error creating socket: ec=%d\n",(int)WSAGetLastError());
731           return -1;
732         }
733
734       addr.sin_family=AF_INET; 
735       addr.sin_port=htons(port);
736
737       if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
738         return sock;
739       else
740         {
741           sock_close(sock);
742           return -1;
743         }
744     }
745 #endif
746
747 #ifdef USE_DNS_SRV
748   /* Do the SRV thing */
749   if(flags&HTTP_FLAG_TRY_SRV)
750     {
751       /* We're using SRV, so append the tags */
752       char srvname[MAXDNAME];
753
754       strcpy(srvname,"_hkp._tcp.");
755       strncat(srvname,server,MAXDNAME-11);
756       srvname[MAXDNAME-1]='\0';
757       srvcount=getsrv(srvname,&srvlist);
758     }
759 #endif
760
761   if(srvlist==NULL)
762     {
763       /* Either we're not using SRV, or the SRV lookup failed.  Make
764          up a fake SRV record. */
765       srvlist=m_alloc_clear(sizeof(struct srventry));
766       srvlist->port=port;
767       strncpy(srvlist->target,server,MAXDNAME);
768       srvcount=1;
769     }
770
771 #ifdef HAVE_GETADDRINFO
772
773   for(srv=0;srv<srvcount;srv++)
774     {
775       struct addrinfo hints,*res,*ai;
776       char portstr[6];
777
778       sprintf(portstr,"%u",srvlist[srv].port);
779       memset(&hints,0,sizeof(hints));
780       hints.ai_socktype=SOCK_STREAM;
781       if(getaddrinfo(srvlist[srv].target,portstr,&hints,&res)!=0)
782         continue;
783
784       for(ai=res;ai;ai=ai->ai_next)
785         {
786           if((sock=socket(ai->ai_family,ai->ai_socktype,ai->ai_protocol))==-1)
787             {
788               log_error("error creating socket: %s\n",strerror(errno));
789               freeaddrinfo(res);
790               return -1;
791             }
792
793           if(connect(sock,ai->ai_addr,ai->ai_addrlen)==0)
794             {
795               connected=1;
796               break;
797             }
798         }
799
800       freeaddrinfo(res);
801
802       if(ai)
803         break;
804     }
805
806 #else /* !HAVE_GETADDRINFO */
807
808   for(srv=0;srv<srvcount;srv++)
809     {
810       int i=0;
811       struct hostent *host=NULL;
812       struct sockaddr_in addr;
813
814       memset(&addr,0,sizeof(addr));
815
816       if((host=gethostbyname(srvlist[srv].target))==NULL)
817         continue;
818
819       if((sock=socket(host->h_addrtype,SOCK_STREAM,0))==-1)
820         {
821           log_error("error creating socket: %s\n",strerror(errno));
822           return -1;
823         }
824
825       addr.sin_family=host->h_addrtype;
826       addr.sin_port=htons(srvlist[srv].port);
827
828       /* Try all A records until one responds. */
829       while(host->h_addr_list[i])
830         {
831           memcpy(&addr.sin_addr,host->h_addr_list[i],host->h_length);
832
833           if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0)
834             {
835               connected=1;
836               break;
837             }
838
839           i++;
840         }
841
842       if(host->h_addr_list[i])
843         break;
844     }
845 #endif /* !HAVE_GETADDRINFO */
846
847   m_free(srvlist);
848
849   if(!connected)
850     {
851 #ifdef _WIN32
852       log_error("%s: host not found: ec=%d\n",server,(int)WSAGetLastError());
853 #else
854       log_error("%s: host not found\n",server);
855 #endif
856       if(sock!=-1)
857         sock_close(sock);
858       return -1;
859     }
860
861   return sock;
862 }
863
864
865 static int
866 write_server( int sock, const char *data, size_t length )
867 {
868     int nleft;
869
870     nleft = length;
871     while( nleft > 0 ) {
872 #ifdef _WIN32  
873         int nwritten;
874
875         nwritten = send (sock, data, nleft, 0);
876         if ( nwritten == SOCKET_ERROR ) {
877             log_info ("write failed: ec=%d\n", (int)WSAGetLastError ());
878             return G10ERR_NETWORK;
879         }
880 #else
881         int nwritten = write( sock, data, nleft );
882         if( nwritten == -1 ) {
883             if( errno == EINTR )
884                 continue;
885             if( errno == EAGAIN ) {
886                 struct timeval tv;
887
888                 tv.tv_sec =  0;
889                 tv.tv_usec = 50000;
890                 select(0, NULL, NULL, NULL, &tv);
891                 continue;
892             }
893             log_info("write failed: %s\n", strerror(errno));
894             return G10ERR_NETWORK;
895         }
896 #endif
897         nleft -=nwritten;
898         data += nwritten;
899     }
900
901     return 0;
902 }
903
904 /**** Test code ****/
905 #ifdef TEST
906
907 int
908 main(int argc, char **argv)
909 {
910     int rc;
911     PARSED_URI uri;
912     URI_TUPLE r;
913     struct http_context hd;
914     int c;
915
916     log_set_name("http-test");
917     if( argc == 1 ) {
918         start_server();
919         return 0;
920     }
921
922     if( argc != 2 ) {
923         fprintf(stderr,"usage: http-test uri\n");
924         return 1;
925     }
926     argc--; argv++;
927
928     rc = parse_uri( &uri, *argv );
929     if( rc ) {
930         log_error("`%s': %s\n", *argv, g10_errstr(rc));
931         release_parsed_uri( uri );
932         return 1;
933     }
934
935     printf("Scheme: %s\n", uri->scheme );
936     printf("Host  : %s\n", uri->host );
937     printf("Port  : %u\n", uri->port );
938     printf("Path  : %s\n", uri->path );
939     for( r=uri->params; r; r = r->next ) {
940         printf("Params: %s=%s", r->name, r->value );
941         if( strlen( r->value ) != r->valuelen )
942             printf(" [real length=%d]", (int)r->valuelen );
943         putchar('\n');
944     }
945     for( r=uri->query; r; r = r->next ) {
946         printf("Query : %s=%s", r->name, r->value );
947         if( strlen( r->value ) != r->valuelen )
948             printf(" [real length=%d]", (int)r->valuelen );
949         putchar('\n');
950     }
951     release_parsed_uri( uri ); uri = NULL;
952
953     rc = http_open_document( &hd, *argv, 0 );
954     if( rc ) {
955         log_error("can't get `%s': %s\n", *argv, g10_errstr(rc));
956         return 1;
957     }
958     log_info("open_http_document succeeded; status=%u\n", hd.status_code );
959     while( (c=iobuf_get( hd.fp_read)) != -1 )
960         putchar(c);
961     http_close( &hd );
962     return 0;
963 }
964 #endif /*TEST*/