/*
- * Copyright (C) 1995-2006, Index Data ApS
+ * Copyright (C) 1995-2007, Index Data ApS
* See the file LICENSE for details.
*
- * $Id: tcpip.c,v 1.26 2006-09-01 11:27:20 adam Exp $
+ * $Id: tcpip.c,v 1.36 2007-10-09 06:00:56 adam Exp $
*/
/**
* \file tcpip.c
#endif
#ifdef WIN32
+
+/* VS 2003 or later has getaddrinfo; older versions do not */
#include <winsock2.h>
+#if _MSC_VER >= 1300
#include <ws2tcpip.h>
#define HAVE_GETADDRINFO 1
#else
+#define HAVE_GETADDRINFO 0
+#endif
+
+#else
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
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);
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 *ai;
#else
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
* 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;
xmalloc(sizeof(tcpip_state)))))
return 0;
- p->blocking = blocking;
+ p->flags = flags;
p->io_pending = 0;
p->iofile = s;
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;
}
+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 = 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;
+}
+
+
#if HAVE_OPENSSL_SSL_H
-COMSTACK ssl_type(int s, int blocking, int protocol, void *vp)
+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;
sp->ai = tcpip_getaddrinfo(str, port);
if (sp->ai && h->state == CS_ST_UNBND)
{
- int s;
+ int s = -1;
struct addrinfo *ai = sp->ai;
- s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
- if (s < 0)
+ 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->blocking))
+ if (!tcpip_set_blocking(h, h->flags))
return 0;
}
return sp->ai;
return 0;
h->iofile = s;
- if (!tcpip_set_blocking(h, h->blocking))
+ if (!tcpip_set_blocking(h, h->flags))
return 0;
}
return &sp->addr;
{
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);
}
/*
#if HAVE_OPENSSL_SSL_H
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());
if (!sp->ctx)
#ifdef WIN32
BOOL one = 1;
#else
- unsigned long one = 1;
+ int one = 1;
#endif
#if HAVE_GETADDRINFO
#if HAVE_OPENSSL_SSL_H
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());
if (!sp->ctx)
}
return 0;
}
- if (!tcpip_set_blocking(cnew, cnew->blocking))
+ if (!tcpip_set_blocking(cnew, cnew->flags))
{
h->cerrno = CSYSERR;
if (h->newfd != -1)
state->ssl = SSL_new (state->ctx);
SSL_set_fd (state->ssl, cnew->iofile);
}
+ state->connect_request_buf = 0;
+ state->connect_response_buf = 0;
#endif
h = cnew;
}
sp->altsize = tmpi;
}
h->io_pending = 0;
- while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
+ while (!(berlen = (*sp->complete)(*buf, hasread)))
{
if (!*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)
break;
}
else
+ {
+ h->cerrno = CSYSERR;
return -1;
+ }
#else
if (yaz_errno() == EWOULDBLOCK
#ifdef EAGAIN
else if (yaz_errno() == 0)
continue;
else
+ {
+ h->cerrno = CSYSERR;
return -1;
+ }
#endif
}
else if (!res)
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);
sp->altsize = tmpi;
}
h->io_pending = 0;
- while (!(berlen = (*sp->complete)((unsigned char *)*buf, hasread)))
+ while (!(berlen = (*sp->complete)(*buf, hasread)))
{
if (!*bufsize)
{
if (sp->ai)
freeaddrinfo(sp->ai);
#endif
+ xfree(sp->connect_request_buf);
+ xfree(sp->connect_response_buf);
xfree(sp);
xfree(h);
return 0;
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
return buf;
}
-int static tcpip_set_blocking(COMSTACK p, int blocking)
+int static tcpip_set_blocking(COMSTACK p, int flags)
{
unsigned long flag;
#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)
+ if (flags & CS_FLAGS_BLOCKING)
flag = flag & ~O_NONBLOCK; /* blocking */
else
{
if (fcntl(p->iofile, F_SETFL, flag) < 0)
return 0;
#endif
- p->blocking = blocking;
+ p->flags = flags;
return 1;
}
}
#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