/*
- * Copyright (c) 1995-2001, Index Data
+ * Copyright (c) 1995-2003, Index Data
* See the file LICENSE for details.
*
- * $Id: tcpip.c,v 1.44 2001-11-06 17:01:25 adam Exp $
+ * $Id: tcpip.c,v 1.57 2003-05-13 14:21:13 adam Exp $
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
-#ifndef WIN32
+
+#ifdef WIN32
+#else
#include <unistd.h>
#endif
+
#include <errno.h>
#include <fcntl.h>
+#include <signal.h>
#if HAVE_OPENSSL_SSL_H
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <yaz/comstack.h>
#include <yaz/tcpip.h>
#include <yaz/log.h>
+#include <yaz/nmem.h>
-/* Chas added the following, so we get the definition of completeBER */
-#include <yaz/odr.h>
+#ifdef WIN32
+#else
+#include <netinet/tcp.h>
+#endif
-int tcpip_close(COMSTACK h);
-int tcpip_put(COMSTACK h, char *buf, int size);
-int tcpip_get(COMSTACK h, char **buf, int *bufsize);
-int tcpip_connect(COMSTACK h, void *address);
-int tcpip_more(COMSTACK h);
-int tcpip_rcvconnect(COMSTACK h);
-int tcpip_bind(COMSTACK h, void *address, int mode);
-int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
+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_connect(COMSTACK h, void *address);
+static int tcpip_more(COMSTACK h);
+static int tcpip_rcvconnect(COMSTACK h);
+static int tcpip_bind(COMSTACK h, void *address, int mode);
+static int tcpip_listen(COMSTACK h, char *raddr, int *addrlen,
int (*check_ip)(void *cd, const char *a, int len, int type),
void *cd);
-int static tcpip_set_blocking(COMSTACK p, int blocking);
+static int tcpip_set_blocking(COMSTACK p, int blocking);
#if HAVE_OPENSSL_SSL_H
-int ssl_get(COMSTACK h, char **buf, int *bufsize);
-int ssl_put(COMSTACK h, char *buf, int size);
+static int ssl_get(COMSTACK h, char **buf, int *bufsize);
+static int ssl_put(COMSTACK h, char *buf, int size);
#endif
-COMSTACK tcpip_accept(COMSTACK h);
-char *tcpip_addrstr(COMSTACK h);
-void *tcpip_straddr(COMSTACK h, const char *str);
+static COMSTACK tcpip_accept(COMSTACK h);
+static char *tcpip_addrstr(COMSTACK h);
+static void *tcpip_straddr(COMSTACK h, const char *str);
#if 0
#define TRC(x) x
#define TRC(X)
#endif
+#ifndef YAZ_SOCKLEN_T
+#define YAZ_SOCKLEN_T int
+#endif
+
/* this state is used for both SSL and straight TCP/IP */
typedef struct tcpip_state
{
#ifdef WIN32
if (!(p->blocking = blocking) && ioctlsocket(s, FIONBIO, &tru) < 0)
+ return 0;
#else
- if (!(p->blocking = blocking) && fcntl(s, F_SETFL, O_NONBLOCK) < 0)
+ if (!(p->blocking = blocking))
+ {
+ if (fcntl(s, F_SETFL, O_NONBLOCK) < 0)
+ return 0;
+#ifndef MSG_NOSIGNAL
+ signal (SIGPIPE, SIG_IGN);
+#endif
+ }
#endif
- return 0;
p->io_pending = 0;
p->iofile = s;
if (protocol == PROTO_WAIS)
state->complete = completeWAIS;
else
- state->complete = completeBER;
+ state->complete = cs_complete_auto;
p->timeout = COMSTACK_DEFAULT_TIMEOUT;
TRC(fprintf(stderr, "Created new TCPIP comstack\n"));
}
#endif
-int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add)
+int tcpip_strtoaddr_ex(const char *str, struct sockaddr_in *add,
+ int default_port)
{
struct hostent *hp;
char *p, buf[512];
- short int port = 210;
+ short int port = default_port;
unsigned tmpadd;
if (!tcpip_init ())
void *tcpip_straddr(COMSTACK h, const char *str)
{
tcpip_state *sp = (tcpip_state *)h->cprivate;
+ int port = 210;
+
+ if (h->protocol == PROTO_HTTP)
+ port = 80;
- if (!tcpip_strtoaddr_ex (str, &sp->addr))
+ if (!tcpip_strtoaddr_ex (str, &sp->addr, port))
return 0;
return &sp->addr;
}
{
static struct sockaddr_in add;
- if (!tcpip_strtoaddr_ex (str, &add))
+ if (!tcpip_strtoaddr_ex (str, &add, 210))
return 0;
return &add;
}
{
struct sockaddr_in *add = (struct sockaddr_in *)address;
#if HAVE_OPENSSL_SSL_H
- tcpip_state *sp = (tcpip_state *)h->cprivate;
+ tcpip_state *sp = (tcpip_state *)h->cprivate;
#endif
int r;
-
+#ifdef __sun__
+ int recbuflen;
+ YAZ_SOCKLEN_T rbufsize = sizeof(recbuflen);
+#endif
TRC(fprintf(stderr, "tcpip_connect\n"));
h->io_pending = 0;
- if (h->state == CS_ST_UNBND)
+ if (h->state != CS_ST_UNBND)
+ {
+ h->cerrno = CSOUTSTATE;
+ return -1;
+ }
+#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 )
+ {
+ h->cerrno = CSYSERR;
+ return -1;
+ }
+ 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 )
+ {
+ h->cerrno = CSYSERR;
+ return -1;
+ }
+ 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 ));
+#endif
+ r = connect(h->iofile, (struct sockaddr *) add, sizeof(*add));
+ if (r < 0)
{
- r = connect(h->iofile, (struct sockaddr *) add, sizeof(*add));
- if (r < 0)
- {
#ifdef WIN32
- if (WSAGetLastError() == WSAEWOULDBLOCK)
- {
- h->event = CS_CONNECT;
- h->state = CS_ST_CONNECTING;
- h->io_pending = CS_WANT_WRITE;
- return 1;
- }
+ if (WSAGetLastError() == WSAEWOULDBLOCK)
+ {
+ h->event = CS_CONNECT;
+ h->state = CS_ST_CONNECTING;
+ h->io_pending = CS_WANT_WRITE;
+ return 1;
+ }
#else
- if (errno == EINPROGRESS)
- {
- h->event = CS_CONNECT;
- h->state = CS_ST_CONNECTING;
- h->io_pending = CS_WANT_WRITE|CS_WANT_READ;
- return 1;
- }
+ if (yaz_errno() == EINPROGRESS)
+ {
+ h->event = CS_CONNECT;
+ h->state = CS_ST_CONNECTING;
+ h->io_pending = CS_WANT_WRITE|CS_WANT_READ;
+ return 1;
+ }
#endif
- h->cerrno = CSYSERR;
- return -1;
- }
- h->event = CS_CONNECT;
- h->state = CS_ST_CONNECTING;
+ h->cerrno = CSYSERR;
+ return -1;
}
+ h->event = CS_CONNECT;
+ h->state = CS_ST_CONNECTING;
+
+ return tcpip_rcvconnect (h);
+}
+
+/*
+ * nop
+ */
+int tcpip_rcvconnect(COMSTACK h)
+{
+#if HAVE_OPENSSL_SSL_H
+ tcpip_state *sp = (tcpip_state *)h->cprivate;
+#endif
+ TRC(fprintf(stderr, "tcpip_rcvconnect\n"));
+
+ if (h->state == CS_ST_DATAXFER)
+ return 0;
if (h->state != CS_ST_CONNECTING)
{
h->cerrno = CSOUTSTATE;
int err = SSL_get_error(sp->ssl, res);
if (err == SSL_ERROR_WANT_READ)
{
- yaz_log (LOG_LOG, "SSL_connect. want_read");
h->io_pending = CS_WANT_READ;
return 1;
}
if (err == SSL_ERROR_WANT_WRITE)
{
- yaz_log (LOG_LOG, "SSL_connect. want_write");
h->io_pending = CS_WANT_WRITE;
return 1;
}
return 0;
}
-/*
- * nop
- */
-int tcpip_rcvconnect(COMSTACK cs)
-{
- TRC(fprintf(stderr, "tcpip_rcvconnect\n"));
+#define CERTF "ztest.pem"
+#define KEYF "ztest.pem"
- if (cs->event == CS_CONNECT)
+static void tcpip_setsockopt (int fd)
+{
+#if 0
+ int len = 4096;
+ int set = 1;
+
+ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&set, sizeof(int)))
{
- int fd = cs->iofile;
- fd_set input, output;
- struct timeval tv;
- int r;
-
- tv.tv_sec = 0;
- tv.tv_usec = 1;
-
- FD_ZERO(&input);
- FD_ZERO(&output);
- FD_SET (fd, &input);
- FD_SET (fd, &output);
-
- r = select (fd+1, &input, &output, 0, &tv);
- if (r > 0)
- {
- if (FD_ISSET(cs->iofile, &output))
- {
- cs->event = CS_DATA;
- return 0; /* write OK, we're OK */
- }
- else
- return -1; /* an error, for sure */
- }
- else if (r == 0)
- return 0; /* timeout - incomplete */
+ yaz_log(LOG_WARN|LOG_ERRNO, "setsockopt TCP_NODELAY");
+ }
+ if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (char*)&len, sizeof(int)))
+ {
+ yaz_log(LOG_WARN|LOG_ERRNO, "setsockopt SNDBUF");
}
- return -1; /* wrong state or bad select */
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (char*)&len, sizeof(int)))
+ {
+ yaz_log(LOG_WARN|LOG_ERRNO, "setsockopt RCVBUF");
+ }
+#endif
}
-#define CERTF "ztest.pem"
-#define KEYF "ztest.pem"
-
-int tcpip_bind(COMSTACK h, void *address, int mode)
+static int tcpip_bind(COMSTACK h, void *address, int mode)
{
struct sockaddr *addr = (struct sockaddr *)address;
#ifdef WIN32
return -1;
}
#endif
+ tcpip_setsockopt(h->iofile);
if (bind(h->iofile, addr, sizeof(struct sockaddr_in)))
{
h->cerrno = CSYSERR;
void *cd)
{
struct sockaddr_in addr;
-#ifdef __cplusplus
- socklen_t len = sizeof(addr);
-#else
- int len = sizeof(addr);
-#endif
+ YAZ_SOCKLEN_T len = sizeof(addr);
TRC(fprintf(stderr, "tcpip_listen pid=%d\n", getpid()));
if (h->state != CS_ST_IDLE)
#ifdef WIN32
WSAGetLastError() == WSAEWOULDBLOCK
#else
- errno == EWOULDBLOCK
+ yaz_errno() == EWOULDBLOCK
#ifdef EAGAIN
#if EAGAIN != EWOULDBLOCK
- || errno == EAGAIN
+ || yaz_errno() == EAGAIN
#endif
#endif
#endif
return -1;
}
h->state = CS_ST_INCON;
+ tcpip_setsockopt (h->newfd);
return 0;
}
if (err == SSL_ERROR_WANT_READ)
{
h->io_pending = CS_WANT_READ;
- yaz_log (LOG_LOG, "SSL_accept. want_read");
return h;
}
if (err == SSL_ERROR_WANT_WRITE)
{
h->io_pending = CS_WANT_WRITE;
- yaz_log (LOG_LOG, "SSL_accept. want_write");
return h;
}
cs_close (h);
else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2)))
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)
{
+ TRC(fprintf(stderr, " recv errno=%d, (%s)\n", yaz_errno(),
+ strerror(yaz_errno())));
#ifdef WIN32
if (WSAGetLastError() == WSAEWOULDBLOCK)
{
else
return -1;
#else
- if (errno == EWOULDBLOCK
+ if (yaz_errno() == EWOULDBLOCK
#ifdef EAGAIN
#if EAGAIN != EWOULDBLOCK
- || errno == EAGAIN
+ || yaz_errno() == EAGAIN
#endif
#endif
- || errno == EINPROGRESS
+ || yaz_errno() == EINPROGRESS
+#ifdef __sun__
+ || yaz_errno() == ENOENT /* Sun's sometimes set errno to this */
+#endif
)
{
h->io_pending = CS_WANT_READ;
break;
}
- else if (errno == 0)
+ else if (yaz_errno() == 0)
continue;
else
- return -1;
+ return -1;
#endif
}
else if (!res)
if (ssl_err == SSL_ERROR_WANT_READ)
{
h->io_pending = CS_WANT_READ;
- yaz_log (LOG_LOG, "SSL_read. want_read");
break;
}
if (ssl_err == SSL_ERROR_WANT_WRITE)
{
h->io_pending = CS_WANT_WRITE;
- yaz_log (LOG_LOG, "SSL_read. want_write");
break;
}
if (res == 0)
#ifdef WIN32
WSAGetLastError() == WSAEWOULDBLOCK
#else
- errno == EWOULDBLOCK
+ yaz_errno() == EWOULDBLOCK
#ifdef EAGAIN
#if EAGAIN != EWOULDBLOCK
- || errno == EAGAIN
+ || yaz_errno() == EAGAIN
+#endif
#endif
+#ifdef __sun__
+ || yaz_errno() == ENOENT /* Sun's sometimes set errno to this value! */
#endif
+ || yaz_errno() == EINPROGRESS
#endif
)
{
if (ssl_err == SSL_ERROR_WANT_READ)
{
h->io_pending = CS_WANT_READ;
- yaz_log (LOG_LOG, "SSL_write. want_read");
return 1;
}
if (ssl_err == SSL_ERROR_WANT_WRITE)
{
h->io_pending = CS_WANT_WRITE;
- yaz_log (LOG_LOG, "SSL_write. want_write");
return 1;
}
h->cerrno = CSERRORSSL;
struct sockaddr_in addr;
tcpip_state *sp = (struct tcpip_state *)h->cprivate;
char *r, *buf = sp->buf;
- size_t len;
+ YAZ_SOCKLEN_T len;
struct hostent *host;
len = sizeof(addr);
r = (char*) host->h_name;
else
r = inet_ntoa(addr.sin_addr);
- sprintf(buf, "tcp:%s", r);
+ if (h->protocol == PROTO_HTTP)
+ sprintf(buf, "http:%s", r);
+ else
+ sprintf(buf, "tcp:%s", r);
#if HAVE_OPENSSL_SSL_H
if (sp->ctx)
- sprintf(buf, "ssl:%s", r);
+ {
+ if (h->protocol == PROTO_HTTP)
+ sprintf(buf, "https:%s", r);
+ else
+ sprintf(buf, "ssl:%s", r);
+ }
#endif
return buf;
}