X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=blobdiff_plain;f=src%2Ftcpip.c;h=a8f03bad70fc1714b36abc84c7c08e6f29bf3642;hp=3ade82b428689ec4deea7c6acd257bce911be280;hb=04aeb72237a5ed1b57b21c9b3610e7a68950ce83;hpb=b822082114c8d580461eb58ff90de9a92e397b90 diff --git a/src/tcpip.c b/src/tcpip.c index 3ade82b..a8f03ba 100644 --- a/src/tcpip.c +++ b/src/tcpip.c @@ -17,6 +17,7 @@ #include #include #include +#include #if HAVE_SYS_TYPES_H #include #endif @@ -74,8 +75,6 @@ static void 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); @@ -85,12 +84,6 @@ static int tcpip_listen(COMSTACK h, char *raddr, int *addrlen, void *cd); static int tcpip_set_blocking(COMSTACK p, int blocking); -#if HAVE_GNUTLS_H -static int ssl_get(COMSTACK h, char **buf, int *bufsize); -static int ssl_put(COMSTACK h, char *buf, int size); -#endif - - #if HAVE_GETADDRINFO struct addrinfo *tcpip_getaddrinfo(const char *str, const char *port, int *ipv6_only); @@ -251,13 +244,10 @@ COMSTACK tcpip_type(int s, int flags, int protocol, void *vp) return p; } -COMSTACK yaz_tcpip_create2(int s, int flags, int protocol, - const char *connect_host, - const char *bind_host) +static void connect_and_bind(COMSTACK p, + const char *connect_host, const char *connect_auth, + const char *bind_host) { - COMSTACK p = tcpip_type(s, flags, protocol, 0); - if (!p) - return 0; if (bind_host) { tcpip_state *sp = (tcpip_state *) p->cprivate; @@ -274,17 +264,45 @@ COMSTACK yaz_tcpip_create2(int s, int flags, int protocol, 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); + char *cp; + sp->connect_request_buf = (char *) xmalloc(strlen(connect_host) + 130); + strcpy(sp->connect_request_buf, "CONNECT "); + strcat(sp->connect_request_buf, connect_host); + cp = strchr(sp->connect_request_buf, '/'); + if (cp) + *cp = '\0'; + strcat(sp->connect_request_buf, " HTTP/1.0\r\n"); + if (connect_auth && strlen(connect_auth) < 40) + { + strcat(sp->connect_request_buf, "Proxy-Authorization: Basic "); + yaz_base64encode(connect_auth, sp->connect_request_buf + + strlen(sp->connect_request_buf)); + strcat(sp->connect_request_buf, "\r\n"); + } + strcat(sp->connect_request_buf, "\r\n"); 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 */ } +} + +COMSTACK yaz_tcpip_create3(int s, int flags, int protocol, + const char *connect_host, + const char *connect_auth, + const char *bind_host) +{ + COMSTACK p = tcpip_type(s, flags, protocol, 0); + if (!p) + return 0; + connect_and_bind(p, connect_host, 0, bind_host); return p; } +COMSTACK yaz_tcpip_create2(int s, int flags, int protocol, + const char *connect_host, + const char *bind_host) +{ + return yaz_tcpip_create3(s, flags, protocol, connect_host, 0, bind_host); +} + COMSTACK yaz_tcpip_create(int s, int flags, int protocol, const char *connect_host) { @@ -311,8 +329,6 @@ COMSTACK ssl_type(int s, int flags, int protocol, void *vp) p = tcpip_type(s, flags, protocol, 0); if (!p) return 0; - p->f_get = ssl_get; - p->f_put = ssl_put; p->type = ssl_type; sp = (tcpip_state *) p->cprivate; @@ -324,6 +340,18 @@ COMSTACK ssl_type(int s, int flags, int protocol, void *vp) #endif } +COMSTACK yaz_ssl_create(int s, int flags, int protocol, + const char *connect_host, + const char *connect_auth, + const char *bind_host) +{ + COMSTACK p = ssl_type(s, flags, protocol, 0); + if (!p) + return 0; + connect_and_bind(p, connect_host, connect_auth, bind_host); + return p; +} + #if HAVE_GNUTLS_H static int ssl_check_error(COMSTACK h, tcpip_state *sp, int res) { @@ -772,6 +800,35 @@ int tcpip_rcvconnect(COMSTACK h) h->cerrno = CSOUTSTATE; return -1; } + if (sp->connect_request_buf) + { + int r; + + sp->complete = cs_complete_auto_head; + if (sp->connect_request_len > 0) + { + r = tcpip_put(h, sp->connect_request_buf, + sp->connect_request_len); + TRC(fprintf(stderr, "tcpip_put CONNECT r=%d\n", r)); + h->event = CS_CONNECT; /* because tcpip_put sets it */ + if (r) /* < 0 is error, 1 is in-complete */ + return r; + TRC(fprintf(stderr, "tcpip_put CONNECT complete\n")); + TRC(fwrite(sp->connect_request_buf, 1, sp->connect_request_len, stderr)); + } + sp->connect_request_len = 0; + + r = tcpip_get(h, &sp->connect_response_buf, &sp->connect_response_len); + TRC(fprintf(stderr, "tcpip_get CONNECT r=%d\n", r)); + if (r == 1) + return r; + if (r <= 0) + return -1; + TRC(fwrite(sp->connect_response_buf, 1, r, stderr)); + xfree(sp->connect_request_buf); + sp->connect_request_buf = 0; + sp->complete = cs_complete_auto; + } #if HAVE_GNUTLS_H if (h->type == ssl_type && !sp->session) { @@ -962,7 +1019,9 @@ COMSTACK tcpip_accept(COMSTACK h) TRC(fprintf(stderr, "tcpip_accept h=%p pid=%d\n", h, getpid())); if (h->state == CS_ST_INCON) { +#if HAVE_GNUTLS_H tcpip_state *st = (tcpip_state *)h->cprivate; +#endif tcpip_state *state = tcpip_state_create(); cnew = (COMSTACK) xmalloc(sizeof(*cnew)); @@ -1106,55 +1165,76 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) h->cerrno = CSYSERR; return -1; } -#ifdef __sun__ - yaz_set_errno( 0 ); - /* unfortunatly, sun sometimes forgets to set errno in recv - when EWOULDBLOCK etc. would be required (res = -1) */ -#endif - res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0); - TRC(fprintf(stderr, " recv res=%d, hasread=%d\n", res, hasread)); - if (res < 0) +#if HAVE_GNUTLS_H + if (sp->session) { - TRC(fprintf(stderr, " recv errno=%d, (%s)\n", yaz_errno(), - strerror(yaz_errno()))); -#ifdef WIN32 - if (WSAGetLastError() == WSAEWOULDBLOCK) + res = gnutls_record_recv(sp->session, *buf + hasread, + CS_TCPIP_BUFCHUNK); + if (res == 0) { - h->io_pending = CS_WANT_READ; - break; + TRC(fprintf(stderr, "gnutls_record_recv returned 0\n")); + return 0; } - else + else if (res < 0) { - h->cerrno = CSYSERR; + if (ssl_check_error(h, sp, res)) + break; return -1; } + } + else +#endif + { +#ifdef __sun__ + yaz_set_errno( 0 ); + /* unfortunatly, sun sometimes forgets to set errno in recv + when EWOULDBLOCK etc. would be required (res = -1) */ +#endif + res = recv(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK, 0); + TRC(fprintf(stderr, " recv res=%d, hasread=%d\n", res, hasread)); + if (res < 0) + { + TRC(fprintf(stderr, " recv errno=%d, (%s)\n", yaz_errno(), + strerror(yaz_errno()))); +#ifdef WIN32 + if (WSAGetLastError() == WSAEWOULDBLOCK) + { + h->io_pending = CS_WANT_READ; + break; + } + else + { + h->cerrno = CSYSERR; + return -1; + } #else - if (yaz_errno() == EWOULDBLOCK + if (yaz_errno() == EWOULDBLOCK #ifdef EAGAIN #if EAGAIN != EWOULDBLOCK - || yaz_errno() == EAGAIN + || yaz_errno() == EAGAIN #endif #endif - || yaz_errno() == EINPROGRESS + || yaz_errno() == EINPROGRESS #ifdef __sun__ - || yaz_errno() == ENOENT /* Sun's sometimes set errno to this */ + || yaz_errno() == ENOENT /* Sun's sometimes set errno to this */ #endif - ) - { - h->io_pending = CS_WANT_READ; - break; - } - else if (yaz_errno() == 0) - continue; - else - { - h->cerrno = CSYSERR; - return -1; - } + ) + { + h->io_pending = CS_WANT_READ; + break; + } + else if (yaz_errno() == 0) + continue; + else + { + h->cerrno = CSYSERR; + return -1; + } #endif + } + else if (!res) + return hasread; } - else if (!res) - return hasread; hasread += res; if (hasread > h->max_recv_bytes) { @@ -1194,84 +1274,6 @@ int tcpip_get(COMSTACK h, char **buf, int *bufsize) } -#if HAVE_GNUTLS_H -/* - * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer, - * 0=connection closed. - */ -int ssl_get(COMSTACK h, char **buf, int *bufsize) -{ - tcpip_state *sp = (tcpip_state *)h->cprivate; - char *tmpc; - int tmpi, berlen, rest, req, tomove; - int hasread = 0, res; - - TRC(fprintf(stderr, "ssl_get: bufsize=%d\n", *bufsize)); - if (sp->altlen) /* switch buffers */ - { - TRC(fprintf(stderr, " %d bytes in altbuf (%p)\n", sp->altlen, - sp->altbuf)); - tmpc = *buf; - tmpi = *bufsize; - *buf = sp->altbuf; - *bufsize = sp->altsize; - hasread = sp->altlen; - sp->altlen = 0; - sp->altbuf = tmpc; - sp->altsize = tmpi; - } - h->io_pending = 0; - while (!(berlen = (*sp->complete)(*buf, hasread))) - { - if (!*bufsize) - { - if (!(*buf = (char *)xmalloc(*bufsize = CS_TCPIP_BUFCHUNK))) - return -1; - } - else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK) - if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2))) - return -1; - res = gnutls_record_recv(sp->session, *buf + hasread, - CS_TCPIP_BUFCHUNK); - if (res == 0) - { - TRC(fprintf(stderr, "gnutls_record_recv returned 0\n")); - return 0; - } - else if (res < 0) - { - if (ssl_check_error(h, sp, res)) - break; - return -1; - } - hasread += res; - } - 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) - { - tomove = req = hasread - berlen; - rest = tomove % CS_TCPIP_BUFCHUNK; - if (rest) - req += CS_TCPIP_BUFCHUNK - rest; - if (!sp->altbuf) - { - if (!(sp->altbuf = (char *)xmalloc(sp->altsize = req))) - return -1; - } else if (sp->altsize < req) - if (!(sp->altbuf =(char *)xrealloc(sp->altbuf, sp->altsize = req))) - return -1; - TRC(fprintf(stderr, " Moving %d bytes to altbuf(%p)\n", tomove, - sp->altbuf)); - memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove); - } - if (berlen < CS_TCPIP_BUFCHUNK - 1) - *(*buf + berlen) = '\0'; - return berlen ? berlen : 1; -} -#endif - /* * Returns 1, 0 or -1 * In nonblocking mode, you must call again with same buffer while @@ -1297,38 +1299,60 @@ int tcpip_put(COMSTACK h, char *buf, int size) } while (state->towrite > state->written) { - if ((res = - send(h->iofile, buf + state->written, size - - state->written, +#if HAVE_GNUTLS_H + if (state->session) + { + res = gnutls_record_send(state->session, buf + state->written, + size - state->written); + if (res <= 0) + { + if (ssl_check_error(h, state, res)) + return 1; + return -1; + } + } + else +#endif + { + if ((res = + send(h->iofile, buf + state->written, size - + state->written, #ifdef MSG_NOSIGNAL - MSG_NOSIGNAL + MSG_NOSIGNAL #else - 0 + 0 #endif - )) < 0) - { - if ( + )) < 0) + { + if ( #ifdef WIN32 - WSAGetLastError() == WSAEWOULDBLOCK + WSAGetLastError() == WSAEWOULDBLOCK #else - yaz_errno() == EWOULDBLOCK + yaz_errno() == EWOULDBLOCK #ifdef EAGAIN #if EAGAIN != EWOULDBLOCK - || yaz_errno() == EAGAIN + || yaz_errno() == EAGAIN #endif #endif #ifdef __sun__ - || yaz_errno() == ENOENT /* Sun's sometimes set errno to this value! */ + || yaz_errno() == ENOENT /* Sun's sometimes set errno to this value! */ #endif - || yaz_errno() == EINPROGRESS + || yaz_errno() == EINPROGRESS #endif - ) - { - TRC(fprintf(stderr, " Flow control stop\n")); - h->io_pending = CS_WANT_WRITE; - return 1; + ) + { + TRC(fprintf(stderr, " Flow control stop\n")); + h->io_pending = CS_WANT_WRITE; + return 1; + } + if (h->flags & CS_FLAGS_BLOCKING) + { + h->cerrno = CSYSERR; + return -1; + } + else + return cont_connect(h); } - return cont_connect(h); } state->written += res; TRC(fprintf(stderr, " Wrote %d, written=%d, nbytes=%d\n", @@ -1339,51 +1363,6 @@ int tcpip_put(COMSTACK h, char *buf, int size) return 0; } - -#if HAVE_GNUTLS_H -/* - * Returns 1, 0 or -1 - * In nonblocking mode, you must call again with same buffer while - * return value is 1. - */ -int ssl_put(COMSTACK h, char *buf, int size) -{ - int res; - struct tcpip_state *state = (struct tcpip_state *)h->cprivate; - - TRC(fprintf(stderr, "ssl_put: size=%d\n", size)); - h->io_pending = 0; - h->event = CS_DATA; - if (state->towrite < 0) - { - state->towrite = size; - state->written = 0; - } - else if (state->towrite != size) - { - h->cerrno = CSWRONGBUF; - return -1; - } - while (state->towrite > state->written) - { - res = gnutls_record_send(state->session, buf + state->written, - size - state->written); - if (res <= 0) - { - if (ssl_check_error(h, state, res)) - return 1; - return -1; - } - state->written += res; - TRC(fprintf(stderr, " Wrote %d, written=%d, nbytes=%d\n", - res, state->written, size)); - } - state->towrite = state->written = -1; - TRC(fprintf(stderr, " Ok\n")); - return 0; -} -#endif - void tcpip_close(COMSTACK h) { tcpip_state *sp = (struct tcpip_state *)h->cprivate; @@ -1716,37 +1695,6 @@ int cs_get_peer_certificate_x509(COMSTACK cs, char **buf, int *len) return 0; } -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