diff options
Diffstat (limited to 'util')
-rw-r--r-- | util/ChangeLog | 11 | ||||
-rw-r--r-- | util/http.c | 144 | ||||
-rw-r--r-- | util/iobuf.c | 153 |
3 files changed, 277 insertions, 31 deletions
diff --git a/util/ChangeLog b/util/ChangeLog index 422159306..ff85c9235 100644 --- a/util/ChangeLog +++ b/util/ChangeLog @@ -1,3 +1,14 @@ +2001-03-13 Werner Koch <[email protected]> + + * iobuf.c (iobuf_sockopen): New. + (sock_filter) [__MINGW32__]: New. + (iobuf_ioctl): New. + (file_filter): Implemented keep_open mode. + * http.c (http_open, http_wait_response): Replaced iobuf_fdopen by + iobuf_sockopen and use an iobuf_ioctl to avoid the dup(). + (deinit_sockets, init_sockets) [__MINGW32__]: New. + (connect_server, write_server): Add code to work with W32 sockets. + 2001-03-12 Werner Koch <[email protected]> * strgutil.c (check_trailing_chars,check_trailing_ws): New. diff --git a/util/http.c b/util/http.c index d3bc44fe3..269e9238d 100644 --- a/util/http.c +++ b/util/http.c @@ -26,16 +26,18 @@ #include <ctype.h> #include <errno.h> -#ifndef HAVE_DOSISH_SYSTEM - -#include <unistd.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/time.h> -#include <time.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#include <netdb.h> +#ifdef __MINGW32__ + #include <windows.h> +#else + #include <unistd.h> + #include <sys/types.h> + #include <sys/socket.h> + #include <sys/time.h> + #include <time.h> + #include <netinet/in.h> + #include <arpa/inet.h> + #include <netdb.h> +#endif #include "util.h" #include "iobuf.h" @@ -43,6 +45,12 @@ #include "http.h" +#ifdef __MINGW32__ +#define sock_close(a) closesocket(a) +#else +#define sock_close(a) close(a) +#endif + #define MAX_LINELEN 20000 /* max. length of a HTTP line */ #define VALID_URI_CHARS "abcdefghijklmnopqrstuvwxyz" \ "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ @@ -67,6 +75,38 @@ static int parse_response( HTTP_HD hd ); static int connect_server( const char *server, ushort port ); static int write_server( int sock, const char *data, size_t length ); +#ifdef __MINGW32__ +static void +deinit_sockets (void) +{ + WSACleanup(); +} + +static void +init_sockets (void) +{ + static int initialized; + static WSADATA wsdata; + + if (initialized) + return; + + if( WSAStartup( 0x0101, &wsdata ) ) { + log_error ("error initializing socket library: ec=%d\n", + (int)WSAGetLastError () ); + return; + } + if( wsdata.wVersion < 0x0001 ) { + log_error ("socket library version is %x.%x - but 1.1 needed\n", + LOBYTE(wsdata.wVersion), HIBYTE(wsdata.wVersion)); + WSACleanup(); + return; + } + atexit ( deinit_sockets ); + initialized = 1; +} +#endif /*__MINGW32__*/ + int http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url, @@ -88,7 +128,7 @@ http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url, if( !rc ) { rc = send_request( hd ); if( !rc ) { - hd->fp_write = iobuf_fdopen( hd->sock , "w" ); + hd->fp_write = iobuf_sockopen( hd->sock , "w" ); if( hd->fp_write ) return 0; rc = G10ERR_GENERAL; @@ -96,7 +136,7 @@ http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url, } if( !hd->fp_read && !hd->fp_write && hd->sock != -1 ) - close( hd->sock ); + sock_close( hd->sock ); iobuf_close( hd->fp_read ); iobuf_close( hd->fp_write); release_parsed_uri( hd->uri ); @@ -124,15 +164,18 @@ http_wait_response( HTTP_HD hd, unsigned int *ret_status ) http_start_data( hd ); /* make sure that we are in the data */ iobuf_flush( hd->fp_write ); - hd->sock = dup( hd->sock ); + #if 0 + hd->sock = dup( hd->sock ); if( hd->sock == -1 ) return G10ERR_GENERAL; - iobuf_close( hd->fp_write ); + #endif + iobuf_ioctl (hd->fp_write, 1, 1, NULL); /* keep the socket open */ + iobuf_close (hd->fp_write); hd->fp_write = NULL; shutdown( hd->sock, 1 ); hd->in_data = 0; - hd->fp_read = iobuf_fdopen( hd->sock , "r" ); + hd->fp_read = iobuf_sockopen( hd->sock , "r" ); if( !hd->fp_read ) return G10ERR_GENERAL; @@ -169,7 +212,7 @@ http_close( HTTP_HD hd ) if( !hd || !hd->initialized ) return; if( !hd->fp_read && !hd->fp_write && hd->sock != -1 ) - close( hd->sock ); + sock_close( hd->sock ); iobuf_close( hd->fp_read ); iobuf_close( hd->fp_write ); release_parsed_uri( hd->uri ); @@ -606,13 +649,13 @@ start_server() if( bind( fd, (struct sockaddr *)&mya, sizeof(mya)) ) { log_error("bind to port 11371 failed: %s\n", strerror(errno) ); - close( fd ); + sock_close( fd ); return -1; } if( listen( fd, 5 ) ) { log_error("listen failed: %s\n", strerror(errno) ); - close( fd ); + sock_close( fd ); return -1; } @@ -645,7 +688,7 @@ start_server() fclose(fp); exit(0); } - close( client ); + sock_close( client ); } @@ -658,9 +701,51 @@ start_server() static int connect_server( const char *server, ushort port ) { + int sd; +#ifdef __MINGW32__ + struct hostent *hp; + struct sockaddr_in ad; + unsigned long l; + + init_sockets (); + + memset (&ad, 0, sizeof(ad)); + ad.sin_family = AF_INET; + ad.sin_port = htons(port); + + if( (l = inet_addr (server)) != SOCKET_ERROR ) { + memcpy (&ad.sin_addr, &l, sizeof(l)); + } + else if( (hp = gethostbyname (server)) ) { + if( hp->h_addrtype != AF_INET ) { + log_error ("%s: unknown address family\n", server); + return -1; + } + if ( hp->h_length != 4 ) { + log_error ("%s: illegal address length\n", server); + return -1; + } + memcpy (&ad.sin_addr, hp->h_addr, hp->h_length); + } + else { + log_error ("%s: host not found: ec=%d\n", + server, (int)WSAGetLastError ()); + return -1; + } + + if ((sd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + log_error ("error creating socket: ex=%d\n", + (int)WSAGetLastError ()); + return -1; + } + + if( connect (sd, (struct sockaddr *)&ad, sizeof (ad) ) ) { + sock_close (sd); + return -1; + } +#else struct sockaddr_in addr; struct hostent *host; - int sd; addr.sin_family = AF_INET; addr.sin_port = htons(port); @@ -675,10 +760,10 @@ connect_server( const char *server, ushort port ) return -1; if( connect( sd, (struct sockaddr *)&addr, sizeof addr) == -1 ) { - close(sd); + sock_close(sd); return -1; } - +#endif return sd; } @@ -686,11 +771,19 @@ connect_server( const char *server, ushort port ) static int write_server( int sock, const char *data, size_t length ) { - int nleft, nwritten; + int nleft; nleft = length; while( nleft > 0 ) { - nwritten = write( sock, data, nleft ); + #ifdef __MINGW32__ + unsigned long nwritten; + + if ( !WriteFile ( sock, data, nleft, &nwritten, NULL)) { + log_info ("write failed: ec=%d\n", (int)GetLastError ()); + return G10ERR_NETWORK; + } + #else + int nwritten = write( sock, data, nleft ); if( nwritten == -1 ) { if( errno == EINTR ) continue; @@ -705,6 +798,7 @@ write_server( int sock, const char *data, size_t length ) log_info("write failed: %s\n", strerror(errno)); return G10ERR_NETWORK; } + #endif nleft -=nwritten; data += nwritten; } @@ -712,8 +806,6 @@ write_server( int sock, const char *data, size_t length ) return 0; } -#endif /* HAVE_DOSISH_SYSTEM */ - /**** Test code ****/ #ifdef TEST diff --git a/util/iobuf.c b/util/iobuf.c index ce4f93645..67e44de9f 100644 --- a/util/iobuf.c +++ b/util/iobuf.c @@ -53,6 +53,7 @@ #define FILEP_OR_FD_FOR_STDOUT (stdout) typedef struct { FILE *fp; /* open file handle */ + int keep_open; int print_only_name; /* flags indicating that fname is not a real file*/ char fname[1]; /* name of the file */ } file_filter_ctx_t ; @@ -74,6 +75,7 @@ #endif typedef struct { FILEP_OR_FD fp; /* open file handle */ + int keep_open; int eof_seen; int print_only_name; /* flags indicating that fname is not a real file*/ char fname[1]; /* name of the file */ @@ -88,6 +90,15 @@ static CLOSE_CACHE close_cache; #endif +#ifdef __MINGW32__ +typedef struct { + int sock; + int keep_open; + int eof_seen; + int print_only_name; /* flags indicating that fname is not a real file*/ + char fname[1]; /* name of the file */ +} sock_filter_ctx_t ; +#endif /*__MINGW32__*/ /* The first partial length header block must be of size 512 * to make it easier (and efficienter) we use a min. block size of 512 @@ -216,6 +227,7 @@ fd_cache_close (const char *fname, FILEP_OR_FD fp) for (cc=close_cache; cc; cc = cc->next ) { if ( cc->fp == INVALID_FP && !strcmp (cc->fname, fname) ) { cc->fp = fp; + return; } } /* add a new one */ @@ -333,6 +345,7 @@ file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) *ret_len = nbytes; } else if( control == IOBUFCTRL_INIT ) { + a->keep_open = 0; } else if( control == IOBUFCTRL_DESC ) { *(char**)buf = "file_filter"; @@ -341,7 +354,8 @@ file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) if( f != stdin && f != stdout ) { if( DBG_IOBUF ) log_debug("%s: close fd %d\n", a->fname, fileno(f) ); - fclose(f); + if (!a->keep_open) + fclose(f); } f = NULL; m_free(a); /* we can free our context now */ @@ -443,6 +457,7 @@ file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) } else if ( control == IOBUFCTRL_INIT ) { a->eof_seen = 0; + a->keep_open = 0; } else if ( control == IOBUFCTRL_DESC ) { *(char**)buf = "file_filter(fd)"; @@ -452,13 +467,15 @@ file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) if ( f != FILEP_OR_FD_FOR_STDIN && f != FILEP_OR_FD_FOR_STDOUT ) { if( DBG_IOBUF ) log_debug("%s: close handle %p\n", a->fname, f ); - fd_cache_close (a->fname, f); + if (!a->keep_open) + fd_cache_close (a->fname, f); } #else if ( (int)f != 0 && (int)f != 1 ) { if( DBG_IOBUF ) log_debug("%s: close fd %d\n", a->fname, f ); - fd_cache_close (a->fname, f); + if (!a->keep_open) + fd_cache_close (a->fname, f); } f = INVALID_FP; #endif @@ -468,6 +485,78 @@ file_filter(void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) return rc; } +#ifdef __MINGW32__ +/* Becuase sockets are an special object under Lose32 we have to + * use a special filter */ +static int +sock_filter (void *opaque, int control, IOBUF chain, byte *buf, size_t *ret_len) +{ + sock_filter_ctx_t *a = opaque; + size_t size = *ret_len; + size_t nbytes = 0; + int rc = 0; + + if( control == IOBUFCTRL_UNDERFLOW ) { + assert( size ); /* need a buffer */ + if ( a->eof_seen) { + rc = -1; + *ret_len = 0; + } + else { + int nread; + + nread = recv ( a->sock, buf, size, 0 ); + if ( nread == SOCKET_ERROR ) { + int ec = (int)WSAGetLastError (); + log_error("socket read error: ec=%d\n", ec); + rc = G10ERR_READ_FILE; + } + else if ( !nread ) { + a->eof_seen = 1; + rc = -1; + } + else { + nbytes = nread; + } + *ret_len = nbytes; + } + } + else if( control == IOBUFCTRL_FLUSH ) { + if( size ) { + byte *p = buf; + int n; + + nbytes = size; + do { + n = send (a->sock, p, nbytes, 0); + if ( n == SOCKET_ERROR ) { + int ec = (int)WSAGetLastError (); + log_error("socket write error: ec=%d\n", ec); + rc = G10ERR_WRITE_FILE; + break; + } + p += n; + nbytes -= n; + } while ( nbytes ); + nbytes = p - buf; + } + *ret_len = nbytes; + } + else if ( control == IOBUFCTRL_INIT ) { + a->eof_seen = 0; + a->keep_open = 0; + } + else if ( control == IOBUFCTRL_DESC ) { + *(char**)buf = "sock_filter"; + } + else if ( control == IOBUFCTRL_FREE ) { + if (!a->keep_open) + closesocket (a->sock); + m_free (a); /* we can free our context now */ + } + return rc; +} +#endif /*__MINGW32__*/ /**************** * This is used to implement the block write mode. @@ -790,9 +879,8 @@ iobuf_alloc(int use, size_t bufsize) return a; } - int -iobuf_close( IOBUF a ) +iobuf_close ( IOBUF a ) { IOBUF a2; size_t dummy_len=0; @@ -996,6 +1084,32 @@ iobuf_fdopen( int fd, const char *mode ) return a; } + +IOBUF +iobuf_sockopen ( int fd, const char *mode ) +{ +#ifdef __MINGW32__ + IOBUF a; + sock_filter_ctx_t *scx; + size_t len; + + a = iobuf_alloc( strchr( mode, 'w')? 2:1, 8192 ); + scx = m_alloc( sizeof *scx + 25 ); + scx->sock = fd; + scx->print_only_name = 1; + sprintf(scx->fname, "[sock %d]", fd ); + a->filter = sock_filter; + a->filter_ov = scx; + sock_filter( scx, IOBUFCTRL_DESC, NULL, (byte*)&a->desc, &len ); + sock_filter( scx, IOBUFCTRL_INIT, NULL, NULL, &len ); + if( DBG_IOBUF ) + log_debug("iobuf-%d.%d: sockopen `%s'\n", a->no, a->subno, scx->fname); + return a; +#else + return iobuf_fdopen (fd, mode); +#endif +} + /**************** * create an iobuf for writing to a file; the file will be created. */ @@ -1133,6 +1247,35 @@ iobuf_fopen( const char *fname, const char *mode ) return a; } +int +iobuf_ioctl ( IOBUF a, int cmd, int intval, void *ptrval ) +{ + if ( cmd == 1 ) { /* keep system filepointer/descriptor open */ + for( ; a; a = a->chain ) + if( !a->chain && a->filter == file_filter ) { + file_filter_ctx_t *b = a->filter_ov; + b->keep_open = intval; + return 0; + } + #ifdef __MINGW32__ + else if( !a->chain && a->filter == sock_filter ) { + sock_filter_ctx_t *b = a->filter_ov; + b->keep_open = intval; + return 0; + } + #endif + } + else if ( cmd == 2 ) { /* invalidate cache */ + if ( !a && !intval && ptrval ) { + #ifndef FILE_FILTER_USES_STDIO + fd_cache_invalidate (ptrval); + #endif + return 0; + } + } + + return -1; +} /**************** |