From f78b96e6645bb3309719a234ff68699d8fccb975 Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Tue, 4 Jun 2002 11:36:10 +0000 Subject: [PATCH] New COMSTACK: UNIX socket --- CHANGELOG | 2 + client/client.c | 30 ++- comstack/Makefile.am | 4 +- comstack/comstack.c | 15 +- comstack/unix.c | 603 +++++++++++++++++++++++++++++++++++++++++++++++ include/yaz/Makefile.am | 4 +- include/yaz/unix.h | 49 ++++ 7 files changed, 691 insertions(+), 16 deletions(-) create mode 100644 comstack/unix.c create mode 100644 include/yaz/unix.h diff --git a/CHANGELOG b/CHANGELOG index 2160276..338d5c9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,6 +2,8 @@ Possible compatibility problems with earlier versions marked with '*'. --- 1.8.8 2002/MM/DD +New COMSTACK of type UNIX Socket. Use "unix:/path" as address for +both client and server. Code by Morten Bøgeskov. --- 1.8.7 2002/05/22 diff --git a/client/client.c b/client/client.c index 0c67a87..1da6fe9 100644 --- a/client/client.c +++ b/client/client.c @@ -2,7 +2,7 @@ * Copyright (c) 1995-2002, Index Data * See the file LICENSE for details. * - * $Id: client.c,v 1.156 2002-06-02 21:34:45 adam Exp $ + * $Id: client.c,v 1.157 2002-06-04 11:36:10 adam Exp $ */ #include @@ -364,16 +364,24 @@ int cmd_open(char *arg) session_mem = NULL; } } - t = tcpip_type; - base[0] = '\0'; - if (sscanf (arg, "%100[^/]/%100s", type_and_host, base) < 1) - return 0; - - if(yazProxy) - conn = cs_create_host(yazProxy, 1, &add); - else - conn = cs_create_host(type_and_host, 1, &add); - + if (strncmp (arg, "unix:", 5) == 0) + { + base[0] = '\0'; + conn = cs_create_host(arg, 1, &add); + } + else + { + t = tcpip_type; + base[0] = '\0'; + if (sscanf (arg, "%100[^/]/%100s", type_and_host, base) < 1) + return 0; + + if(yazProxy) + conn = cs_create_host(yazProxy, 1, &add); + else + conn = cs_create_host(type_and_host, 1, &add); + + } if (!conn) { printf ("Couldn't create comstack\n"); diff --git a/comstack/Makefile.am b/comstack/Makefile.am index 2594dd8..d0a876e 100644 --- a/comstack/Makefile.am +++ b/comstack/Makefile.am @@ -1,4 +1,4 @@ -## $Id: Makefile.am,v 1.5 2002-04-15 09:44:42 adam Exp $ +## $Id: Makefile.am,v 1.6 2002-06-04 11:36:10 adam Exp $ noinst_LTLIBRARIES=libcomstack.la @@ -6,5 +6,5 @@ AM_CPPFLAGS=-I$(top_srcdir)/include LIBS = -libcomstack_la_SOURCES=comstack.c tcpip.c waislen.c +libcomstack_la_SOURCES=comstack.c tcpip.c waislen.c unix.c diff --git a/comstack/comstack.c b/comstack/comstack.c index b15eb5f..121d143 100644 --- a/comstack/comstack.c +++ b/comstack/comstack.c @@ -3,7 +3,10 @@ * See the file LICENSE for details. * * $Log: comstack.c,v $ - * Revision 1.9 2001-10-22 13:57:24 adam + * Revision 1.10 2002-06-04 11:36:10 adam + * New COMSTACK: UNIX socket + * + * Revision 1.9 2001/10/22 13:57:24 adam * Implemented cs_rcvconnect and cs_look as described in the documentation. * * Revision 1.8 2001/07/19 19:49:02 adam @@ -42,6 +45,7 @@ #include #include #include +#include static const char *cs_errlist[] = { @@ -86,6 +90,15 @@ COMSTACK cs_create_host(const char *type_and_host, int blocking, void **vp) return 0; #endif } + else if (strncmp (type_and_host, "unix:", 5) == 0) + { +#ifndef WIN32 + t = unix_type; + host = type_and_host + 5; +#else + return 0; +#endif + } else { t = tcpip_type; diff --git a/comstack/unix.c b/comstack/unix.c new file mode 100644 index 0000000..a3d4e58 --- /dev/null +++ b/comstack/unix.c @@ -0,0 +1,603 @@ +/* + * Copyright (c) 1995-2002, Index Data + * See the file LICENSE for details. + * + * $Id: unix.c,v 1.1 2002-06-04 11:36:10 adam Exp $ + * UNIX socket COMSTACK. By Morten Bøgeskov. + */ +#ifndef WIN32 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +/* Chas added the following, so we get the definition of completeBER */ +#include + +int unix_close(COMSTACK h); +int unix_put(COMSTACK h, char *buf, int size); +int unix_get(COMSTACK h, char **buf, int *bufsize); +int unix_connect(COMSTACK h, void *address); +int unix_more(COMSTACK h); +int unix_rcvconnect(COMSTACK h); +int unix_bind(COMSTACK h, void *address, int mode); +int unix_listen(COMSTACK h, char *raddr, int *addrlen, + int (*check_ip)(void *cd, const char *a, int len, int type), + void *cd); +int static unix_set_blocking(COMSTACK p, int blocking); + + +COMSTACK unix_accept(COMSTACK h); +char *unix_addrstr(COMSTACK h); +void *unix_straddr(COMSTACK h, const char *str); + +#if 0 +#define TRC(x) x +#else +#define TRC(X) +#endif + +/* this state is used for both SSL and straight TCP/IP */ +typedef struct unix_state +{ + char *altbuf; /* alternate buffer for surplus data */ + int altsize; /* size as xmalloced */ + int altlen; /* length of data or 0 if none */ + + 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. */ + struct sockaddr_un addr; /* returned by cs_straddr */ + char buf[128]; /* returned by cs_addrstr */ +} unix_state; + +static int unix_init (void) +{ + return 1; +} + +/* + * This function is always called through the cs_create() macro. + * s >= 0: socket has already been established for us. + */ +COMSTACK unix_type(int s, int blocking, int protocol, void *vp) +{ + COMSTACK p; + unix_state *state; + int new_socket; + + if (!unix_init ()) + return 0; + if (s < 0) + { + if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) + return 0; + new_socket = 1; + } + else + new_socket = 0; + if (!(p = (struct comstack *)xmalloc(sizeof(struct comstack)))) + return 0; + if (!(state = (struct unix_state *)(p->cprivate = + xmalloc(sizeof(unix_state))))) + return 0; + + if (!(p->blocking = blocking)) + { + if (fcntl(s, F_SETFL, O_NONBLOCK) < 0) + return 0; +#ifndef MSG_NOSIGNAL + signal (SIGPIPE, SIG_IGN); +#endif + } + + p->io_pending = 0; + p->iofile = s; + p->type = unix_type; + p->protocol = (enum oid_proto) protocol; + + p->f_connect = unix_connect; + p->f_rcvconnect = unix_rcvconnect; + p->f_get = unix_get; + p->f_put = unix_put; + p->f_close = unix_close; + p->f_more = unix_more; + p->f_bind = unix_bind; + p->f_listen = unix_listen; + p->f_accept = unix_accept; + p->f_addrstr = unix_addrstr; + p->f_straddr = unix_straddr; + p->f_set_blocking = unix_set_blocking; + + p->state = new_socket ? CS_ST_UNBND : CS_ST_IDLE; /* state of line */ + p->event = CS_NONE; + p->cerrno = 0; + p->stackerr = 0; + + state->altbuf = 0; + state->altsize = state->altlen = 0; + state->towrite = state->written = -1; + if (protocol == PROTO_WAIS) + state->complete = completeWAIS; + else + state->complete = completeBER; + + p->timeout = COMSTACK_DEFAULT_TIMEOUT; + TRC(fprintf(stderr, "Created new UNIX comstack\n")); + + return p; +} + + +int unix_strtoaddr_ex(const char *str, struct sockaddr_un *add) +{ + struct hostent *hp; + char *p, buf[512]; + short int port = 210; + unsigned tmpadd; + + if (!unix_init ()) + return 0; + TRC(fprintf(stderr, "unix_strtoaddress: %s\n", str ? str : "NULL")); + add->sun_family = AF_UNIX; + strncpy(add->sun_path, str, sizeof(add->sun_path)); + return 1; +} + +void *unix_straddr(COMSTACK h, const char *str) +{ + unix_state *sp = (unix_state *)h->cprivate; + + TRC(fprintf(stderr, "unix_straddr: %s\n", str ? str : "NULL")); + + if (!unix_strtoaddr_ex (str, &sp->addr)) + return 0; + return &sp->addr; +} + +struct sockaddr_un *unix_strtoaddr(const char *str) +{ + static struct sockaddr_un add; + + TRC(fprintf(stderr, "unix_strtoaddr: %s\n", str ? str : "NULL")); + + if (!unix_strtoaddr_ex (str, &add)) + return 0; + return &add; +} + +int unix_more(COMSTACK h) +{ + unix_state *sp = (unix_state *)h->cprivate; + + return sp->altlen && (*sp->complete)((unsigned char *) sp->altbuf, + sp->altlen); +} + +/* + * connect(2) will block (sometimes) - nothing we can do short of doing + * weird things like spawning subprocesses or threading or some weird junk + * like that. + */ +int unix_connect(COMSTACK h, void *address) +{ + struct sockaddr_un *add = (struct sockaddr_un *)address; + int r; + + TRC(fprintf(stderr, "unix_connect\n")); + h->io_pending = 0; + if (h->state != CS_ST_UNBND) + { + h->cerrno = CSOUTSTATE; + return -1; + } + r = connect(h->iofile, (struct sockaddr *) add, SUN_LEN(add)); + if (r < 0) + { + if (errno == EINPROGRESS) + { + h->event = CS_CONNECT; + h->state = CS_ST_CONNECTING; + h->io_pending = CS_WANT_WRITE|CS_WANT_READ; + return 1; + } + h->cerrno = CSYSERR; + return -1; + } + h->event = CS_CONNECT; + h->state = CS_ST_CONNECTING; + + return unix_rcvconnect (h); +} + +/* + * nop + */ +int unix_rcvconnect(COMSTACK h) +{ + unix_state *sp = (unix_state *)h->cprivate; + TRC(fprintf(stderr, "unix_rcvconnect\n")); + + if (h->state == CS_ST_DATAXFER) + return 0; + if (h->state != CS_ST_CONNECTING) + { + h->cerrno = CSOUTSTATE; + return -1; + } + h->event = CS_DATA; + h->state = CS_ST_DATAXFER; + return 0; +} + +#define CERTF "ztest.pem" +#define KEYF "ztest.pem" + +int unix_bind(COMSTACK h, void *address, int mode) +{ + struct sockaddr *addr = (struct sockaddr *)address; + unsigned long one = 1; + const char * path = ((struct sockaddr_un *)addr)->sun_path; + struct stat stat_buf; + + TRC (fprintf (stderr, "unix_bind\n")); + + if(stat(path, &stat_buf) != -1) { + struct sockaddr_un socket_unix; + int socket_out = -1; + if(! S_ISSOCK(stat_buf.st_mode)) { + h->cerrno = CSYSERR; + errno = EEXIST; /* Not a socket (File exists) */ + return -1; + } + if((socket_out = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + h->cerrno = CSYSERR; + return -1; + } + socket_unix.sun_family = AF_UNIX; + strncpy(socket_unix.sun_path, path, sizeof(socket_unix.sun_path)); + if(connect(socket_out, (struct sockaddr *) &socket_unix, SUN_LEN(&socket_unix)) < 0) { + if(errno == ECONNREFUSED) { + TRC (fprintf (stderr, "Socket exists but nobody is listening\n")); + } else { + h->cerrno = CSYSERR; + return -1; + } + } else { + close(socket_out); + h->cerrno = CSYSERR; + errno = EADDRINUSE; + return -1; + } + unlink(path); + } + + if (bind(h->iofile, (struct sockaddr *) addr, SUN_LEN((struct sockaddr_un *)addr))) + { + h->cerrno = CSYSERR; + return -1; + } + if (mode == CS_SERVER && listen(h->iofile, 3) < 0) + { + h->cerrno = CSYSERR; + return -1; + } + h->state = CS_ST_IDLE; + h->event = CS_LISTEN; + return 0; +} + +int unix_listen(COMSTACK h, char *raddr, int *addrlen, + int (*check_ip)(void *cd, const char *a, int len, int t), + void *cd) +{ + struct sockaddr_un addr; +#ifdef __cplusplus + socklen_t len = SUN_LEN(&addr); +#else + int len = SUN_LEN(&addr); +#endif + + TRC(fprintf(stderr, "unix_listen pid=%d\n", getpid())); + if (h->state != CS_ST_IDLE) + { + h->cerrno = CSOUTSTATE; + return -1; + } + h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len); + if (h->newfd < 0) + { + if ( + errno == EWOULDBLOCK +#ifdef EAGAIN +#if EAGAIN != EWOULDBLOCK + || errno == EAGAIN +#endif +#endif + ) + h->cerrno = CSNODATA; + else + h->cerrno = CSYSERR; + return -1; + } + if (addrlen && (size_t) (*addrlen) >= sizeof(struct sockaddr_un)) + memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_un)); + else if (addrlen) + *addrlen = 0; + h->state = CS_ST_INCON; + return 0; +} + +COMSTACK unix_accept(COMSTACK h) +{ + COMSTACK cnew; + unix_state *state, *st = (unix_state *)h->cprivate; + + TRC(fprintf(stderr, "unix_accept\n")); + if (h->state == CS_ST_INCON) + { + if (!(cnew = (COMSTACK)xmalloc(sizeof(*cnew)))) + { + h->cerrno = CSYSERR; + close(h->newfd); + h->newfd = -1; + return 0; + } + memcpy(cnew, h, sizeof(*h)); + cnew->iofile = h->newfd; + cnew->io_pending = 0; + if (!(state = (unix_state *) + (cnew->cprivate = xmalloc(sizeof(unix_state))))) + { + h->cerrno = CSYSERR; + if (h->newfd != -1) + { + close(h->newfd); + h->newfd = -1; + } + return 0; + } + if (!cnew->blocking && + (!cnew->blocking && fcntl(cnew->iofile, F_SETFL, O_NONBLOCK) < 0) + ) + { + h->cerrno = CSYSERR; + if (h->newfd != -1) + { + close(h->newfd); + h->newfd = -1; + } + xfree (cnew); + xfree (state); + return 0; + } + h->newfd = -1; + state->altbuf = 0; + state->altsize = state->altlen = 0; + state->towrite = state->written = -1; + state->complete = st->complete; + cnew->state = CS_ST_ACCEPT; + cnew->event = CS_NONE; + h->state = CS_ST_IDLE; + + h = cnew; + } + if (h->state == CS_ST_ACCEPT) + { + } + else + { + h->cerrno = CSOUTSTATE; + return 0; + } + h->io_pending = 0; + h->state = CS_ST_DATAXFER; + h->event = CS_DATA; + return h; +} + +#define CS_UNIX_BUFCHUNK 4096 + +/* + * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer, + * 0=connection closed. + */ +int unix_get(COMSTACK h, char **buf, int *bufsize) +{ + unix_state *sp = (unix_state *)h->cprivate; + char *tmpc; + int tmpi, berlen, rest, req, tomove; + int hasread = 0, res; + + TRC(fprintf(stderr, "unix_get: bufsize=%d\n", *bufsize)); + if (sp->altlen) /* switch buffers */ + { + TRC(fprintf(stderr, " %d bytes in altbuf (0x%x)\n", sp->altlen, + (unsigned) 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)((unsigned char *)*buf, hasread))) + { + if (!*bufsize) + { + if (!(*buf = (char *)xmalloc(*bufsize = CS_UNIX_BUFCHUNK))) + return -1; + } + else if (*bufsize - hasread < CS_UNIX_BUFCHUNK) + if (!(*buf =(char *)xrealloc(*buf, *bufsize *= 2))) + return -1; + res = recv(h->iofile, *buf + hasread, CS_UNIX_BUFCHUNK, 0); + TRC(fprintf(stderr, " recv res=%d, hasread=%d\n", res, hasread)); + if (res < 0) + { + if (errno == EWOULDBLOCK +#ifdef EAGAIN +#if EAGAIN != EWOULDBLOCK + || errno == EAGAIN +#endif +#endif + || errno == EINPROGRESS + ) + { + h->io_pending = CS_WANT_READ; + break; + } + else if (errno == 0) + continue; + else + return -1; + } + else if (!res) + return 0; + 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_UNIX_BUFCHUNK; + if (rest) + req += CS_UNIX_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(0x%x)\n", tomove, + (unsigned) sp->altbuf)); + memcpy(sp->altbuf, *buf + berlen, sp->altlen = tomove); + } + if (berlen < CS_UNIX_BUFCHUNK - 1) + *(*buf + berlen) = '\0'; + return berlen ? berlen : 1; +} + + + +/* + * Returns 1, 0 or -1 + * In nonblocking mode, you must call again with same buffer while + * return value is 1. + */ +int unix_put(COMSTACK h, char *buf, int size) +{ + int res; + struct unix_state *state = (struct unix_state *)h->cprivate; + + TRC(fprintf(stderr, "unix_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) + { + if ((res = + send(h->iofile, buf + state->written, size - + state->written, +#ifdef MSG_NOSIGNAL + MSG_NOSIGNAL +#else + 0 +#endif + )) < 0) + { + if ( + errno == EWOULDBLOCK +#ifdef EAGAIN +#if EAGAIN != EWOULDBLOCK + || errno == EAGAIN +#endif +#endif + ) + { + TRC(fprintf(stderr, " Flow control stop\n")); + h->io_pending = CS_WANT_WRITE; + return 1; + } + h->cerrno = CSYSERR; + 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; +} + + + +int unix_close(COMSTACK h) +{ + unix_state *sp = (struct unix_state *)h->cprivate; + + TRC(fprintf(stderr, "unix_close\n")); + if (h->iofile != -1) + { + close(h->iofile); + } + if (sp->altbuf) + xfree(sp->altbuf); + xfree(sp); + xfree(h); + return 0; +} + +char *unix_addrstr(COMSTACK h) +{ + unix_state *sp = (struct unix_state *)h->cprivate; + char *buf = sp->buf; + sprintf(buf, "unix:%s", sp->addr.sun_path); + return buf; +} + +int static unix_set_blocking(COMSTACK p, int blocking) +{ + unsigned long flag; + + if (p->blocking == blocking) + return 1; + flag = fcntl(p->iofile, F_GETFL, 0); + if(!blocking) + flag = flag & ~O_NONBLOCK; + else + flag = flag | O_NONBLOCK; + if (fcntl(p->iofile, F_SETFL, flag) < 0) + return 0; + p->blocking = blocking; + return 1; +} +#endif diff --git a/include/yaz/Makefile.am b/include/yaz/Makefile.am index a063372..c9ffa49 100644 --- a/include/yaz/Makefile.am +++ b/include/yaz/Makefile.am @@ -1,9 +1,9 @@ -## $Id: Makefile.am,v 1.15 2002-05-18 09:52:37 oleg Exp $ +## $Id: Makefile.am,v 1.16 2002-06-04 11:36:11 adam Exp $ pkginclude_HEADERS= backend.h ccl.h comstack.h \ d1_attset.h d1_map.h data1.h diagbib1.h sortspec.h \ log.h logrpn.h marcdisp.h nmem.h odr.h oid.h options.h otherinfo.h \ - pquery.h prt-ext.h readconf.h statserv.h tcpip.h tpath.h wrbuf.h xmalloc.h \ + pquery.h prt-ext.h readconf.h statserv.h tcpip.h unix.h tpath.h wrbuf.h xmalloc.h \ yaz-ccl.h yaz-util.h yaz-version.h yconfig.h proto.h \ \ ill.h ill-core.h item-req.h z-accdes1.h z-accform1.h \ diff --git a/include/yaz/unix.h b/include/yaz/unix.h new file mode 100644 index 0000000..93998af --- /dev/null +++ b/include/yaz/unix.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1995-2002, Index Data. + * + * Permission to use, copy, modify, distribute, and sell this software and + * its documentation, in whole or in part, for any purpose, is hereby granted, + * provided that: + * + * 1. This copyright and permission notice appear in all copies of the + * software and its documentation. Notices of copyright or attribution + * which appear at the beginning of any file must remain unchanged. + * + * 2. The name of Index Data or the individual authors may not be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND, + * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY + * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + * IN NO EVENT SHALL INDEX DATA BE LIABLE FOR ANY SPECIAL, INCIDENTAL, + * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR + * NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF + * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * $Id: unix.h,v 1.1 2002-06-04 11:36:11 adam Exp $ + * UNIX socket COMSTACK. By Morten Bøgeskov. + * + */ + +#ifndef UNIX_H +#define UNIX_H + +#ifndef WIN32 + +#include +#include + +YAZ_BEGIN_CDECL + +YAZ_EXPORT int completeWAIS(const unsigned char *buf, int len); +YAZ_EXPORT struct sockaddr_un *unix_strtoaddr(const char *str); +YAZ_EXPORT COMSTACK unix_type(int s, int blocking, int protocol, void *vp); + +YAZ_END_CDECL + +#endif + +#endif -- 1.7.10.4