X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Ftcpip.c;h=1c5f78047892eb6bc15830337b5172f627fb5e50;hp=66dbd09bf4502cc424b30176f273dc86d9e3b779;hb=02b6a809f17f142071384ffac8e406b6e9fbd2fb;hpb=b335dcd534287a207ef75b35e486df21293feddb diff --git a/src/tcpip.c b/src/tcpip.c index 66dbd09..1c5f780 100644 --- a/src/tcpip.c +++ b/src/tcpip.c @@ -1,8 +1,6 @@ -/* - * Copyright (C) 1995-2006, Index Data ApS +/* This file is part of the YAZ toolkit. + * Copyright (C) 1995-2008 Index Data * See the file LICENSE for details. - * - * $Id: tcpip.c,v 1.23 2006-08-30 18:58:59 adam Exp $ */ /** * \file tcpip.c @@ -26,7 +24,16 @@ #endif #ifdef WIN32 -#include + +/* VS 2003 or later has getaddrinfo; older versions do not */ +#include +#if _MSC_VER >= 1300 +#include +#define HAVE_GETADDRINFO 1 +#else +#define HAVE_GETADDRINFO 0 +#endif + #else #include #include @@ -37,16 +44,19 @@ #if HAVE_SYS_SOCKET_H #include #endif -#if HAVE_SYS_SELECT_H -#include -#endif #if HAVE_SYS_WAIT_H #include #endif +#if HAVE_GNUTLS_H +#include +#define ENABLE_SSL 1 +#endif + #if HAVE_OPENSSL_SSL_H #include #include +#define ENABLE_SSL 1 #endif #include @@ -56,6 +66,8 @@ static int tcpip_close(COMSTACK h); static int tcpip_put(COMSTACK h, char *buf, int size); static int tcpip_get(COMSTACK h, char **buf, int *bufsize); +static int tcpip_put_connect(COMSTACK h, char *buf, int size); +static int tcpip_get_connect(COMSTACK h, char **buf, int *bufsize); static int tcpip_connect(COMSTACK h, void *address); static int tcpip_more(COMSTACK h); static int tcpip_rcvconnect(COMSTACK h); @@ -65,7 +77,7 @@ static int tcpip_listen(COMSTACK h, char *raddr, int *addrlen, void *cd); static int tcpip_set_blocking(COMSTACK p, int blocking); -#if HAVE_OPENSSL_SSL_H +#if ENABLE_SSL static int ssl_get(COMSTACK h, char **buf, int *bufsize); static int ssl_put(COMSTACK h, char *buf, int size); #endif @@ -93,23 +105,27 @@ typedef struct tcpip_state int written; /* -1 if we aren't writing */ int towrite; /* to verify against user input */ - int (*complete)(const unsigned char *buf, int len); /* length/comple. */ + int (*complete)(const char *buf, int len); /* length/complete. */ #if HAVE_GETADDRINFO - struct addrinfo *res; + struct addrinfo *ai; #else struct sockaddr_in addr; /* returned by cs_straddr */ #endif char buf[128]; /* returned by cs_addrstr */ -#if HAVE_OPENSSL_SSL_H +#if ENABLE_SSL SSL_CTX *ctx; /* current CTX. */ SSL_CTX *ctx_alloc; /* If =ctx it is owned by CS. If 0 it is not owned */ SSL *ssl; char cert_fname[256]; #endif + char *connect_request_buf; + int connect_request_len; + char *connect_response_buf; + int connect_response_len; } tcpip_state; #ifdef WIN32 -static int tcpip_init (void) +static int tcpip_init(void) { static int initialized = 0; if (!initialized) @@ -125,7 +141,7 @@ static int tcpip_init (void) return 1; } #else -static int tcpip_init (void) +static int tcpip_init(void) { return 1; } @@ -135,44 +151,20 @@ static int tcpip_init (void) * This function is always called through the cs_create() macro. * s >= 0: socket has already been established for us. */ -COMSTACK tcpip_type(int s, int blocking, int protocol, void *vp) +COMSTACK tcpip_type(int s, int flags, int protocol, void *vp) { COMSTACK p; tcpip_state *sp; - int new_socket; -#ifdef WIN32 - unsigned long tru = 1; -#endif - if (!tcpip_init ()) + if (!tcpip_init()) return 0; - if (s < 0) - { - if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) - return 0; - new_socket = 1; - } - else - new_socket = 0; if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack)))) return 0; if (!(sp = (struct tcpip_state *)(p->cprivate = xmalloc(sizeof(tcpip_state))))) return 0; - if (!((p->blocking = blocking)&1)) - { -#ifdef WIN32 - if (ioctlsocket(s, FIONBIO, &tru) < 0) - return 0; -#else - if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) - return 0; -#ifndef MSG_NOSIGNAL - signal (SIGPIPE, SIG_IGN); -#endif -#endif - } + p->flags = flags; p->io_pending = 0; p->iofile = s; @@ -193,20 +185,20 @@ COMSTACK tcpip_type(int s, int blocking, int protocol, void *vp) p->f_set_blocking = tcpip_set_blocking; p->max_recv_bytes = 5000000; - p->state = new_socket ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */ + p->state = s < 0 ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */ p->event = CS_NONE; p->cerrno = 0; p->stackerr = 0; p->user = 0; -#if HAVE_OPENSSL_SSL_H +#if ENABLE_SSL sp->ctx = sp->ctx_alloc = 0; sp->ssl = 0; strcpy(sp->cert_fname, "yaz.pem"); #endif #if HAVE_GETADDRINFO - sp->res = 0; + sp->ai = 0; #endif sp->altbuf = 0; sp->altsize = sp->altlen = 0; @@ -216,20 +208,46 @@ COMSTACK tcpip_type(int s, int blocking, int protocol, void *vp) else sp->complete = cs_complete_auto; + sp->connect_request_buf = 0; + sp->connect_request_len = 0; + sp->connect_response_buf = 0; + sp->connect_response_len = 0; + p->timeout = COMSTACK_DEFAULT_TIMEOUT; TRC(fprintf(stderr, "Created new TCPIP comstack\n")); return p; } -#if HAVE_OPENSSL_SSL_H +COMSTACK yaz_tcpip_create(int s, int flags, int protocol, + const char *connect_host) +{ + COMSTACK p = tcpip_type(s, flags, protocol, 0); + if (!p) + return 0; + if (connect_host) + { + tcpip_state *sp = (tcpip_state *) p->cprivate; + sp->connect_request_buf = (char *) xmalloc(strlen(connect_host) + 30); + sprintf(sp->connect_request_buf, "CONNECT %s HTTP/1.0\r\n\r\n", + connect_host); + sp->connect_request_len = strlen(sp->connect_request_buf); + p->f_put = tcpip_put_connect; + p->f_get = tcpip_get_connect; + sp->complete = cs_complete_auto_head; /* only want HTTP header */ + } + return p; +} -COMSTACK ssl_type(int s, int blocking, int protocol, void *vp) + +#if ENABLE_SSL + +COMSTACK ssl_type(int s, int flags, int protocol, void *vp) { tcpip_state *sp; COMSTACK p; - p = tcpip_type (s, blocking, protocol, 0); + p = tcpip_type(s, flags, protocol, 0); if (!p) return 0; p->f_get = ssl_get; @@ -242,6 +260,41 @@ COMSTACK ssl_type(int s, int blocking, int protocol, void *vp) /* note: we don't handle already opened socket in SSL mode - yet */ return p; } + +int ssl_check_error(COMSTACK h, tcpip_state *sp, int res) +{ +#if HAVE_OPENSSL_SSL_H + int err = SSL_get_error(sp->ssl, res); + TRC(fprintf(stderr, "got err=%d\n", err)); + if (err == SSL_ERROR_WANT_READ) + { + TRC(fprintf(stderr, " -> SSL_ERROR_WANT_READ\n")); + h->io_pending = CS_WANT_READ; + return 1; + } + if (err == SSL_ERROR_WANT_WRITE) + { + TRC(fprintf(stderr, " -> SSL_ERROR_WANT_WRITE\n")); + h->io_pending = CS_WANT_WRITE; + return 1; + } +#else + int tls_error = sp->ssl->last_error; + TRC(fprintf(stderr, "ssl_check_error error=%d fatal=%d msg=%s\n", + sp->ssl->last_error, + gnutls_error_is_fatal(tls_error), + gnutls_strerror(tls_error))); + if (tls_error == GNUTLS_E_AGAIN || tls_error == GNUTLS_E_INTERRUPTED) + { + int dir = gnutls_record_get_direction(sp->ssl->gnutls_state); + TRC(fprintf(stderr, " -> incomplete dir=%d\n", dir)); + h->io_pending = dir ? CS_WANT_WRITE : CS_WANT_READ; + return 1; + } +#endif + h->cerrno = CSERRORSSL; + return 0; +} #endif #if HAVE_GETADDRINFO @@ -265,7 +318,7 @@ struct addrinfo *tcpip_getaddrinfo(const char *str, const char *port) host[sizeof(host)-1] = 0; if ((p = strchr(host, '/'))) *p = 0; - if ((p = strchr(host, ':'))) + if ((p = strrchr(host, ':'))) { *p = '\0'; port = p+1; @@ -304,7 +357,7 @@ int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add, buf[sizeof(buf)-1] = 0; if ((p = strchr(buf, '/'))) *p = 0; - if ((p = strchr(buf, ':'))) + if ((p = strrchr(buf, ':'))) { *p = 0; port = atoi(p + 1); @@ -336,13 +389,30 @@ void *tcpip_straddr(COMSTACK h, const char *str) const char *port = "210"; if (h->protocol == PROTO_HTTP) port = "80"; - if (!tcpip_init ()) + if (!tcpip_init()) return 0; - if (sp->res) - freeaddrinfo(sp->res); - sp->res = tcpip_getaddrinfo(str, port); - return sp->res; + if (sp->ai) + freeaddrinfo(sp->ai); + sp->ai = tcpip_getaddrinfo(str, port); + if (sp->ai && h->state == CS_ST_UNBND) + { + int s = -1; + struct addrinfo *ai = sp->ai; + for (; ai; ai = ai->ai_next) + { + s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); + if (s != -1) + break; + } + if (s == -1) + return 0; + h->iofile = s; + + if (!tcpip_set_blocking(h, h->flags)) + return 0; + } + return sp->ai; } #else void *tcpip_straddr(COMSTACK h, const char *str) @@ -352,10 +422,21 @@ void *tcpip_straddr(COMSTACK h, const char *str) if (h->protocol == PROTO_HTTP) port = 80; - if (!tcpip_init ()) + if (!tcpip_init()) return 0; - if (!tcpip_strtoaddr_ex (str, &sp->addr, port)) + if (!tcpip_strtoaddr_ex(str, &sp->addr, port)) return 0; + if (h->state == CS_ST_UNBND) + { + int s; + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + return 0; + h->iofile = s; + + if (!tcpip_set_blocking(h, h->flags)) + return 0; + } return &sp->addr; } #endif @@ -364,8 +445,7 @@ int tcpip_more(COMSTACK h) { tcpip_state *sp = (tcpip_state *)h->cprivate; - return sp->altlen && (*sp->complete)((unsigned char *) sp->altbuf, - sp->altlen); + return sp->altlen && (*sp->complete)(sp->altbuf, sp->altlen); } /* @@ -376,7 +456,7 @@ int tcpip_more(COMSTACK h) int tcpip_connect(COMSTACK h, void *address) { #if HAVE_GETADDRINFO - struct addrinfo *ai = (struct addrinfo *) address; + tcpip_state *sp = (tcpip_state *)h->cprivate; #else struct sockaddr_in *add = (struct sockaddr_in *) address; #endif @@ -392,12 +472,19 @@ int tcpip_connect(COMSTACK h, void *address) h->cerrno = CSOUTSTATE; return -1; } +#if HAVE_GETADDRINFO + if (sp->ai != (struct addrinfo *) address) + { + h->cerrno = CSOUTSTATE; + return -1; + } +#endif #ifdef __sun__ /* On Suns, you must set a bigger Receive Buffer BEFORE a call to connect * This gives the connect a chance to negotiate with the other side * (see 'man tcp') */ - if ( getsockopt(h->iofile, SOL_SOCKET, SO_RCVBUF, (void *)&recbuflen, &rbufsize ) < 0 ) + if (getsockopt(h->iofile, SOL_SOCKET, SO_RCVBUF, (void *)&recbuflen, &rbufsize ) < 0 ) { h->cerrno = CSYSERR; return -1; @@ -405,22 +492,24 @@ int tcpip_connect(COMSTACK h, void *address) TRC(fprintf( stderr, "Current Size of TCP Receive Buffer= %d\n", recbuflen )); recbuflen *= 10; /* lets be optimistic */ - if ( setsockopt(h->iofile, SOL_SOCKET, SO_RCVBUF, (void *)&recbuflen, rbufsize ) < 0 ) + if (setsockopt(h->iofile, SOL_SOCKET, SO_RCVBUF, (void *)&recbuflen, rbufsize ) < 0 ) { h->cerrno = CSYSERR; return -1; } - if ( getsockopt(h->iofile, SOL_SOCKET, SO_RCVBUF, (void *)&recbuflen, &rbufsize ) ) + if (getsockopt(h->iofile, SOL_SOCKET, SO_RCVBUF, (void *)&recbuflen, &rbufsize ) ) { h->cerrno = CSYSERR; return -1; } - TRC(fprintf( stderr, "New Size of TCP Receive Buffer = %d\n", - recbuflen )); + TRC(fprintf(stderr, "New Size of TCP Receive Buffer = %d\n", + recbuflen )); #endif #if HAVE_GETADDRINFO - r = connect(h->iofile, ai->ai_addr, ai->ai_addrlen); + r = connect(h->iofile, sp->ai->ai_addr, sp->ai->ai_addrlen); + freeaddrinfo(sp->ai); + sp->ai = 0; #else r = connect(h->iofile, (struct sockaddr *) add, sizeof(*add)); #endif @@ -449,7 +538,7 @@ int tcpip_connect(COMSTACK h, void *address) h->event = CS_CONNECT; h->state = CS_ST_CONNECTING; - return tcpip_rcvconnect (h); + return tcpip_rcvconnect(h); } /* @@ -457,7 +546,7 @@ int tcpip_connect(COMSTACK h, void *address) */ int tcpip_rcvconnect(COMSTACK h) { -#if HAVE_OPENSSL_SSL_H +#if ENABLE_SSL tcpip_state *sp = (tcpip_state *)h->cprivate; #endif TRC(fprintf(stderr, "tcpip_rcvconnect\n")); @@ -469,13 +558,13 @@ int tcpip_rcvconnect(COMSTACK h) h->cerrno = CSOUTSTATE; return -1; } -#if HAVE_OPENSSL_SSL_H +#if ENABLE_SSL if (h->type == ssl_type && !sp->ctx) { + SSL_library_init(); SSL_load_error_strings(); - SSLeay_add_all_algorithms(); - sp->ctx = sp->ctx_alloc = SSL_CTX_new (SSLv23_method()); + sp->ctx = sp->ctx_alloc = SSL_CTX_new(SSLv23_client_method()); if (!sp->ctx) { h->cerrno = CSERRORSSL; @@ -488,24 +577,14 @@ int tcpip_rcvconnect(COMSTACK h) if (!sp->ssl) { - sp->ssl = SSL_new (sp->ctx); - SSL_set_fd (sp->ssl, h->iofile); + sp->ssl = SSL_new(sp->ctx); + SSL_set_fd(sp->ssl, h->iofile); } - res = SSL_connect (sp->ssl); + res = SSL_connect(sp->ssl); if (res <= 0) { - int err = SSL_get_error(sp->ssl, res); - if (err == SSL_ERROR_WANT_READ) - { - h->io_pending = CS_WANT_READ; - return 1; - } - if (err == SSL_ERROR_WANT_WRITE) - { - h->io_pending = CS_WANT_WRITE; + if (ssl_check_error(h, sp, res)) return 1; - } - h->cerrno = CSERRORSSL; return -1; } } @@ -518,7 +597,7 @@ int tcpip_rcvconnect(COMSTACK h) #define CERTF "ztest.pem" #define KEYF "ztest.pem" -static void tcpip_setsockopt (int fd) +static void tcpip_setsockopt(int fd) { #if 0 int len = 4096; @@ -542,25 +621,32 @@ static void tcpip_setsockopt (int fd) static int tcpip_bind(COMSTACK h, void *address, int mode) { int r; + tcpip_state *sp = (tcpip_state *)h->cprivate; #if HAVE_GETADDRINFO - struct addrinfo *ai = (struct addrinfo *)address; #else struct sockaddr *addr = (struct sockaddr *)address; #endif #ifdef WIN32 BOOL one = 1; #else - unsigned long one = 1; + int one = 1; #endif -#if HAVE_OPENSSL_SSL_H - tcpip_state *sp = (tcpip_state *)h->cprivate; +#if HAVE_GETADDRINFO + if (sp->ai != (struct addrinfo *) address) + { + h->cerrno = CSOUTSTATE; + return -1; + } +#endif + +#if ENABLE_SSL if (h->type == ssl_type && !sp->ctx) { + SSL_library_init(); SSL_load_error_strings(); - SSLeay_add_all_algorithms(); - sp->ctx = sp->ctx_alloc = SSL_CTX_new (SSLv23_method()); + sp->ctx = sp->ctx_alloc = SSL_CTX_new(SSLv23_server_method()); if (!sp->ctx) { h->cerrno = CSERRORSSL; @@ -572,34 +658,47 @@ static int tcpip_bind(COMSTACK h, void *address, int mode) if (sp->ctx_alloc) { int res; - res = SSL_CTX_use_certificate_chain_file(sp->ctx, sp->cert_fname); + res = SSL_CTX_use_certificate_file(sp->ctx, sp->cert_fname, + SSL_FILETYPE_PEM); if (res <= 0) { +#if HAVE_OPENSSL_SSL_H ERR_print_errors_fp(stderr); - exit (2); +#else + fprintf(stderr, " SSL_CTX_use_certificate_file %s failed\n", + sp->cert_fname); +#endif + exit(2); } - res = SSL_CTX_use_PrivateKey_file (sp->ctx, sp->cert_fname, + res = SSL_CTX_use_PrivateKey_file(sp->ctx, sp->cert_fname, SSL_FILETYPE_PEM); if (res <= 0) { +#if HAVE_OPENSSL_SSL_H ERR_print_errors_fp(stderr); - exit (3); +#else + fprintf(stderr, " SSL_CTX_use_certificate_file %s failed\n", + sp->cert_fname); +#endif + exit(3); } - res = SSL_CTX_check_private_key (sp->ctx); +#if HAVE_OPENSSL_SSL_H + res = SSL_CTX_check_private_key(sp->ctx); if (res <= 0) { ERR_print_errors_fp(stderr); exit(5); } +#endif } - TRC (fprintf (stderr, "ssl_bind\n")); + TRC(fprintf(stderr, "ssl_bind\n")); } else { - TRC (fprintf (stderr, "tcpip_bind\n")); + TRC(fprintf(stderr, "tcpip_bind\n")); } #else - TRC (fprintf (stderr, "tcpip_bind\n")); + TRC(fprintf(stderr, "tcpip_bind\n")); #endif #ifndef WIN32 if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, (char*) @@ -611,7 +710,9 @@ static int tcpip_bind(COMSTACK h, void *address, int mode) #endif tcpip_setsockopt(h->iofile); #if HAVE_GETADDRINFO - r = bind(h->iofile, ai->ai_addr, ai->ai_addrlen); + r = bind(h->iofile, sp->ai->ai_addr, sp->ai->ai_addrlen); + freeaddrinfo(sp->ai); + sp->ai = 0; #else r = bind(h->iofile, addr, sizeof(struct sockaddr_in)); #endif @@ -661,7 +762,15 @@ int tcpip_listen(COMSTACK h, char *raddr, int *addrlen, ) h->cerrno = CSNODATA; else + { +#ifdef WIN32 + shutdown(h->iofile, SD_RECEIVE); +#else + shutdown(h->iofile, SHUT_RD); +#endif + listen(h->iofile, SOMAXCONN); h->cerrno = CSYSERR; + } return -1; } if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_in)) @@ -681,7 +790,7 @@ int tcpip_listen(COMSTACK h, char *raddr, int *addrlen, return -1; } h->state = CS_ST_INCON; - tcpip_setsockopt (h->newfd); + tcpip_setsockopt(h->newfd); return 0; } @@ -725,13 +834,7 @@ COMSTACK tcpip_accept(COMSTACK h) } return 0; } - if (!(cnew->blocking&1) && -#ifdef WIN32 - (ioctlsocket(cnew->iofile, FIONBIO, &tru) < 0) -#else - (fcntl(cnew->iofile, F_SETFL, O_NONBLOCK) < 0) -#endif - ) + if (!tcpip_set_blocking(cnew, cnew->flags)) { h->cerrno = CSYSERR; if (h->newfd != -1) @@ -743,8 +846,8 @@ COMSTACK tcpip_accept(COMSTACK h) #endif h->newfd = -1; } - xfree (cnew); - xfree (state); + xfree(cnew); + xfree(state); return 0; } h->newfd = -1; @@ -752,45 +855,47 @@ COMSTACK tcpip_accept(COMSTACK h) state->altsize = state->altlen = 0; state->towrite = state->written = -1; state->complete = st->complete; +#if HAVE_GETADDRINFO + state->ai = 0; +#endif cnew->state = CS_ST_ACCEPT; h->state = CS_ST_IDLE; -#if HAVE_OPENSSL_SSL_H +#if ENABLE_SSL state->ctx = st->ctx; state->ctx_alloc = 0; state->ssl = st->ssl; if (state->ctx) { - state->ssl = SSL_new (state->ctx); - SSL_set_fd (state->ssl, cnew->iofile); + state->ssl = SSL_new(state->ctx); + SSL_set_fd(state->ssl, cnew->iofile); } #endif + state->connect_request_buf = 0; + state->connect_response_buf = 0; h = cnew; } if (h->state == CS_ST_ACCEPT) { -#if HAVE_OPENSSL_SSL_H + +#if ENABLE_SSL tcpip_state *state = (tcpip_state *)h->cprivate; if (state->ctx) { - int res = SSL_accept (state->ssl); - TRC(fprintf(stderr, "SSL_accept\n")); + int res; + errno = 0; + res = SSL_accept(state->ssl); + TRC(fprintf(stderr, "SSL_accept res=%d\n", res)); if (res <= 0) { - int err = SSL_get_error(state->ssl, res); - if (err == SSL_ERROR_WANT_READ) + if (ssl_check_error(h, state, res)) { - h->io_pending = CS_WANT_READ; return h; } - if (err == SSL_ERROR_WANT_WRITE) - { - h->io_pending = CS_WANT_WRITE; - return h; - } - cs_close (h); + cs_close(h); return 0; } + TRC(fprintf(stderr, "SSL_accept complete\n")); } #endif } @@ -833,7 +938,7 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) sp->altsize = tmpi; } h->io_pending = 0; - while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread))) + while (!(berlen = (*sp->complete)(*buf, hasread))) { if (!*bufsize) { @@ -858,7 +963,7 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) TRC(fprintf(stderr, " recv res=%d, hasread=%d\n", res, hasread)); if (res < 0) { - TRC(fprintf(stderr, " recv errno=%d, (%s)\n", yaz_errno(), + TRC(fprintf(stderr, " recv errno=%d, (%s)\n", yaz_errno(), strerror(yaz_errno()))); #ifdef WIN32 if (WSAGetLastError() == WSAEWOULDBLOCK) @@ -867,7 +972,10 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) break; } else + { + h->cerrno = CSYSERR; return -1; + } #else if (yaz_errno() == EWOULDBLOCK #ifdef EAGAIN @@ -887,7 +995,10 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) else if (yaz_errno() == 0) continue; else + { + h->cerrno = CSYSERR; return -1; + } #endif } else if (!res) @@ -899,8 +1010,8 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) return -1; } } - TRC (fprintf (stderr, " Out of read loop with hasread=%d, berlen=%d\n", - hasread, berlen)); + TRC(fprintf(stderr, " Out of read loop with hasread=%d, berlen=%d\n", + hasread, berlen)); /* move surplus buffer (or everything if we didn't get a BER rec.) */ if (hasread > berlen) { @@ -911,10 +1022,16 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) if (!sp->altbuf) { if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req))) + { + h->cerrno = CSYSERR; return -1; + } } else if (sp->altsize < req) if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req))) + { + h->cerrno = CSYSERR; return -1; + } TRC(fprintf(stderr, " Moving %d bytes to altbuf(0x%x)\n", tomove, (unsigned) sp->altbuf)); memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove); @@ -925,7 +1042,7 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) } -#if HAVE_OPENSSL_SSL_H +#if ENABLE_SSL /* * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer, * 0=connection closed. @@ -952,7 +1069,7 @@ int ssl_get(COMSTACK h, char **buf, int *bufsize) sp->altsize = tmpi; } h->io_pending = 0; - while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread))) + while (!(berlen = (*sp->complete)(*buf, hasread))) { if (!*bufsize) { @@ -962,24 +1079,12 @@ int ssl_get(COMSTACK h, char **buf, int *bufsize) else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK) if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2))) return -1; - res = SSL_read (sp->ssl, *buf + hasread, CS_TCPIP_BUFCHUNK); + res = SSL_read(sp->ssl, *buf + hasread, CS_TCPIP_BUFCHUNK); TRC(fprintf(stderr, " SSL_read res=%d, hasread=%d\n", res, hasread)); if (res <= 0) { - int ssl_err = SSL_get_error(sp->ssl, res); - if (ssl_err == SSL_ERROR_WANT_READ) - { - h->io_pending = CS_WANT_READ; - break; - } - if (ssl_err == SSL_ERROR_WANT_WRITE) - { - h->io_pending = CS_WANT_WRITE; + if (ssl_check_error(h, sp, res)) break; - } - if (res == 0) - return 0; - h->cerrno = CSERRORSSL; return -1; } hasread += res; @@ -1079,7 +1184,7 @@ int tcpip_put(COMSTACK h, char *buf, int size) } -#if HAVE_OPENSSL_SSL_H +#if ENABLE_SSL /* * Returns 1, 0 or -1 * In nonblocking mode, you must call again with same buffer while @@ -1105,22 +1210,12 @@ int ssl_put(COMSTACK h, char *buf, int size) } while (state->towrite > state->written) { - res = SSL_write (state->ssl, buf + state->written, - size - state->written); + res = SSL_write(state->ssl, buf + state->written, + size - state->written); if (res <= 0) { - int ssl_err = SSL_get_error(state->ssl, res); - if (ssl_err == SSL_ERROR_WANT_READ) - { - h->io_pending = CS_WANT_READ; - return 1; - } - if (ssl_err == SSL_ERROR_WANT_WRITE) - { - h->io_pending = CS_WANT_WRITE; + if (ssl_check_error(h, state, res)) return 1; - } - h->cerrno = CSERRORSSL; return -1; } state->written += res; @@ -1140,10 +1235,10 @@ int tcpip_close(COMSTACK h) TRC(fprintf(stderr, "tcpip_close\n")); if (h->iofile != -1) { -#if HAVE_OPENSSL_SSL_H +#if ENABLE_SSL if (sp->ssl) { - SSL_shutdown (sp->ssl); + SSL_shutdown(sp->ssl); } #endif #ifdef WIN32 @@ -1154,20 +1249,22 @@ int tcpip_close(COMSTACK h) } if (sp->altbuf) xfree(sp->altbuf); -#if HAVE_OPENSSL_SSL_H +#if ENABLE_SSL if (sp->ssl) { - TRC (fprintf(stderr, "SSL_free\n")); - SSL_free (sp->ssl); + TRC(fprintf(stderr, "SSL_free\n")); + SSL_free(sp->ssl); } sp->ssl = 0; if (sp->ctx_alloc) - SSL_CTX_free (sp->ctx_alloc); + SSL_CTX_free(sp->ctx_alloc); #endif #if HAVE_GETADDRINFO - if (sp->res) - freeaddrinfo(sp->res); + if (sp->ai) + freeaddrinfo(sp->ai); #endif + xfree(sp->connect_request_buf); + xfree(sp->connect_response_buf); xfree(sp); xfree(h); return 0; @@ -1175,30 +1272,55 @@ int tcpip_close(COMSTACK h) char *tcpip_addrstr(COMSTACK h) { - struct sockaddr_in addr; tcpip_state *sp = (struct tcpip_state *)h->cprivate; char *r = 0, *buf = sp->buf; - YAZ_SOCKLEN_T len; + +#if HAVE_GETADDRINFO + char host[120]; + struct sockaddr_storage addr; + YAZ_SOCKLEN_T len = sizeof(addr); + + if (getpeername(h->iofile, (struct sockaddr *)&addr, &len) < 0) + { + h->cerrno = CSYSERR; + return 0; + } + if (getnameinfo((struct sockaddr *) &addr, len, host, sizeof(host)-1, + 0, 0, + (h->flags & CS_FLAGS_NUMERICHOST) ? NI_NUMERICHOST : 0)) + { + r = "unknown"; + } + else + r = host; + +#else + + struct sockaddr_in addr; + YAZ_SOCKLEN_T len = sizeof(addr); struct hostent *host; - len = sizeof(addr); if (getpeername(h->iofile, (struct sockaddr*) &addr, &len) < 0) { h->cerrno = CSYSERR; return 0; } - if (!(h->blocking&2)) { - if ((host = gethostbyaddr((char*)&addr.sin_addr, sizeof(addr.sin_addr), - AF_INET))) + if (!(h->flags & CS_FLAGS_NUMERICHOST)) + { + if ((host = gethostbyaddr((char*)&addr.sin_addr, + sizeof(addr.sin_addr), + AF_INET))) r = (char*) host->h_name; } if (!r) - r = inet_ntoa(addr.sin_addr); + r = inet_ntoa(addr.sin_addr); +#endif + if (h->protocol == PROTO_HTTP) sprintf(buf, "http:%s", r); else sprintf(buf, "tcp:%s", r); -#if HAVE_OPENSSL_SSL_H +#if ENABLE_SSL if (sp->ctx) { if (h->protocol == PROTO_HTTP) @@ -1210,30 +1332,31 @@ char *tcpip_addrstr(COMSTACK h) return buf; } -int static tcpip_set_blocking(COMSTACK p, int blocking) +int static tcpip_set_blocking(COMSTACK p, int flags) { unsigned long flag; - if (p->blocking == blocking) - return 1; #ifdef WIN32 - flag = 1; + flag = (flags & CS_FLAGS_BLOCKING) ? 0 : 1; if (ioctlsocket(p->iofile, FIONBIO, &flag) < 0) return 0; #else flag = fcntl(p->iofile, F_GETFL, 0); - if(!(blocking&1)) - flag = flag & ~O_NONBLOCK; + if (flags & CS_FLAGS_BLOCKING) + flag = flag & ~O_NONBLOCK; /* blocking */ else - flag = flag | O_NONBLOCK; + { + flag = flag | O_NONBLOCK; /* non-blocking */ + signal(SIGPIPE, SIG_IGN); + } if (fcntl(p->iofile, F_SETFL, flag) < 0) return 0; #endif - p->blocking = blocking; + p->flags = flags; return 1; } -#if HAVE_OPENSSL_SSL_H +#if ENABLE_SSL int cs_set_ssl_ctx(COMSTACK cs, void *ctx) { struct tcpip_state *sp; @@ -1271,7 +1394,8 @@ int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len) SSL *ssl = (SSL *) cs_get_ssl(cs); if (ssl) { - X509 *server_cert = SSL_get_peer_certificate (ssl); +#if HAVE_OPENSSL_SSL_H + X509 *server_cert = SSL_get_peer_certificate(ssl); if (server_cert) { BIO *bio = BIO_new(BIO_s_mem()); @@ -1284,6 +1408,7 @@ int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len) BIO_free(bio); return 1; } +#endif } return 0; } @@ -1309,6 +1434,38 @@ int cs_set_ssl_certificate_file(COMSTACK cs, const char *fname) } #endif + +static int tcpip_put_connect(COMSTACK h, char *buf, int size) +{ + struct tcpip_state *state = (struct tcpip_state *)h->cprivate; + + int r = tcpip_put(h, state->connect_request_buf, + state->connect_request_len); + if (r == 0) + { + /* it's sent */ + h->f_put = tcpip_put; /* switch to normal tcpip put */ + r = tcpip_put(h, buf, size); + } + return r; +} + +static int tcpip_get_connect(COMSTACK h, char **buf, int *bufsize) +{ + struct tcpip_state *state = (struct tcpip_state *)h->cprivate; + int r; + + r = tcpip_get(h, &state->connect_response_buf, + &state->connect_response_len); + if (r < 1) + return r; + /* got the connect response completely */ + state->complete = cs_complete_auto; /* switch to normal tcpip get */ + h->f_get = tcpip_get; + return tcpip_get(h, buf, bufsize); +} + + /* * Local variables: * c-basic-offset: 4