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