Renamed yazlib to comstack.
authorSebastian Hammer <quinn@indexdata.com>
Wed, 14 Jun 1995 09:58:19 +0000 (09:58 +0000)
committerSebastian Hammer <quinn@indexdata.com>
Wed, 14 Jun 1995 09:58:19 +0000 (09:58 +0000)
comstack/Makefile [new file with mode: 0644]
comstack/comstack.c [new file with mode: 0644]
comstack/tcpip.c [new file with mode: 0644]
comstack/xmosi.c [new file with mode: 0644]

diff --git a/comstack/Makefile b/comstack/Makefile
new file mode 100644 (file)
index 0000000..46f9770
--- /dev/null
@@ -0,0 +1,59 @@
+# Copyright (C) 1994, Index Data I/S 
+# All rights reserved.
+# Sebastian Hammer, Adam Dickmeiss
+# $Id: Makefile,v 1.1 1995-06-14 09:58:19 quinn Exp $
+
+
+LIBDIR=../lib
+
+#LIBOSI=../../xtimosi/src/libmosi.a $(LIBDIR)/librfc.a
+#XMOSI=xmosi.o
+
+SHELL=/bin/sh
+INCLUDE=-I../include -I. -I../../xtimosi/src
+LIBINCLUDE=-L$(LIBDIR) -L../../xtimosi/src
+#CFLAGS=-Wall -pedantic -g
+#CFLAGS=-g
+DEFS=$(INCLUDE) -DRPN_QUERY # -DTRACE_TCPIP
+LIB= $(LIBDIR)/libcomstack.a 
+LIBS=$(LIBDIR)/libasn.a $(LIBDIR)/libodr.a $(LIBDIR)/libcomstack.a \
+        ../lib/ccl.a $(LIBDIR)/libutil.a $(LIBMOSI)
+PO = comstack.o tcpip.o $(XMOSI)
+CPP=$(CC) -E
+#CC=checkergcc
+
+all: $(LIBDIR) $(LIB)
+
+cli: tst.o $(LIB)
+       $(CC) $(CFLAGS) $(LIBINCLUDE) -o cli tst.o $(LIBINCLUDE) $(LIBS)
+
+alll:
+
+$(LIB): $(PO)
+       rm -f $(LIB)
+       ar qc $(LIB) $(PO)
+       ranlib $(LIB)
+
+$(LIBDIR):
+       mkdir $(LIBDIR)
+.c.o:
+       $(CC) -c $(DEFS) $(CFLAGS) $<
+
+clean:
+       rm -f *.[oa] test core mon.out gmon.out errlist tst cli
+
+depend: depend2
+
+depend1:
+       sed '/^#Depend/q' <Makefile >Makefile.tmp
+       $(CPP) $(DEFS) -M *.c >>Makefile.tmp
+       mv -f Makefile.tmp Makefile
+
+depend2:
+       $(CPP) $(INCLUDE) -M *.c >.depend       
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+#Depend --- DOT NOT DELETE THIS LINE
diff --git a/comstack/comstack.c b/comstack/comstack.c
new file mode 100644 (file)
index 0000000..2912d35
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 1995, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log: comstack.c,v $
+ * Revision 1.1  1995-06-14 09:58:20  quinn
+ * Renamed yazlib to comstack.
+ *
+ * Revision 1.2  1995/05/16  08:51:15  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.1  1995/03/14  10:28:34  quinn
+ * Adding server-side support to tcpip.c and fixing bugs in nonblocking I/O
+ *
+ *
+ */
+
+const char *cs_errlist[] =
+{
+    "No error or unspecified error",
+    "System (lower-layer) error",
+    "Operation out of state",
+    "No data (operation would block)",
+    "New data while half of old buffer is on the line (flow control)"
+};
diff --git a/comstack/tcpip.c b/comstack/tcpip.c
new file mode 100644 (file)
index 0000000..d816123
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ * Copyright (c) 1995, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log: tcpip.c,v $
+ * Revision 1.1  1995-06-14 09:58:20  quinn
+ * Renamed yazlib to comstack.
+ *
+ * Revision 1.20  1995/05/16  08:51:16  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.19  1995/04/10  10:24:08  quinn
+ * Some bug-fixes.
+ *
+ * Revision 1.18  1995/03/30  13:29:27  quinn
+ * Added REUSEADDR in tcpip_bind
+ *
+ * Revision 1.17  1995/03/27  08:36:10  quinn
+ * Some work on nonblocking operation in xmosi.c and rfct.c.
+ * Added protocol parameter to cs_create()
+ *
+ * Revision 1.16  1995/03/21  15:53:41  quinn
+ * Added rcvconnect
+ *
+ * Revision 1.15  1995/03/21  12:31:27  quinn
+ * Added check for EINPROGRESS on connect.
+ *
+ * Revision 1.14  1995/03/20  09:47:21  quinn
+ * Added server-side support to xmosi.c
+ * Fixed possible problems in rfct
+ * Other little mods
+ *
+ * Revision 1.13  1995/03/15  16:15:13  adam
+ * Removed p_write.
+ *
+ * Revision 1.12  1995/03/15  15:36:27  quinn
+ * Mods to support nonblocking I/O
+ *
+ * Revision 1.11  1995/03/15  08:37:57  quinn
+ * Now we're pretty much set for nonblocking I/O.
+ *
+ * Revision 1.10  1995/03/14  17:00:07  quinn
+ * Bug-fixes - added tracing info to tcpip.c
+ *
+ * Revision 1.9  1995/03/14  10:28:42  quinn
+ * Adding server-side support to tcpip.c and fixing bugs in nonblocking I/O
+ *
+ * Revision 1.8  1995/03/10  14:22:50  quinn
+ * Removed debug output.
+ *
+ * Revision 1.7  1995/03/10  11:44:59  quinn
+ * Fixes and debugging
+ *
+ * Revision 1.6  1995/03/07  10:26:55  quinn
+ * Initialized type field in the comstacks.
+ *
+ * Revision 1.5  1995/02/14  20:40:07  quinn
+ * Various stuff.
+ *
+ * Revision 1.4  1995/02/14  11:54:49  quinn
+ * Beginning to add full CCL.
+ *
+ * Revision 1.3  1995/02/10  18:58:10  quinn
+ * Fixed tcpip_get (formerly tcpip_read).
+ * Turned tst (cli) into a proper, event-driven thingy.
+ *
+ * Revision 1.2  1995/02/10  15:55:47  quinn
+ * Small things.
+ *
+ * Revision 1.1  1995/02/09  15:51:52  quinn
+ * Works better now.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <comstack.h>
+#include <tcpip.h>
+#include <sys/time.h>
+
+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 *addrp, int *addrlen);
+COMSTACK tcpip_accept(COMSTACK h);
+
+int completeBER(unsigned char *buf, int len);
+
+#ifdef TRACE_TCPIP
+#define TRC(x) x
+#else
+#define TRC(X)
+#endif
+
+typedef struct tcpip_state
+{
+    char *altbuf; /* alternate buffer for surplus data */
+    int altsize;  /* size as malloced */
+    int altlen;   /* length of data or 0 if none */
+
+    int written;  /* -1 if we aren't writing */
+    int towrite;  /* to verify against user input */
+} tcpip_state;
+
+COMSTACK tcpip_type(int blocking, int protocol)
+{
+    COMSTACK p;
+    struct protoent *proto;
+    tcpip_state *state;
+    int s;
+
+    if (!(proto = getprotobyname("tcp")))
+       return 0;
+    if ((s = socket(AF_INET, SOCK_STREAM, proto->p_proto)) < 0)
+       return 0;
+    if (!(p = malloc(sizeof(struct comstack))))
+       return 0;
+    if (!(state = p->private = malloc(sizeof(tcpip_state))))
+       return 0;
+    if (!(p->blocking = blocking) && fcntl(s, F_SETFL, O_NONBLOCK) < 0)
+       return 0;
+
+    p->iofile = s;
+    p->type = tcpip_type;
+    p->protocol = protocol;
+
+    p->f_connect = tcpip_connect;
+    p->f_rcvconnect = tcpip_rcvconnect;
+    p->f_get = tcpip_get;
+    p->f_put = tcpip_put;
+    p->f_close = tcpip_close;
+    p->f_more = tcpip_more;
+    p->f_bind = tcpip_bind;
+    p->f_listen = tcpip_listen;
+    p->f_accept = tcpip_accept;
+
+    p->state = CS_UNBND;
+    p->event = CS_NONE;
+    p->errno = 0;
+    p->stackerr = 0;
+
+    state->altbuf = 0;
+    state->altsize = state->altlen = 0;
+    state->towrite = state->written = -1;
+
+    p->timeout = COMSTACK_DEFAULT_TIMEOUT;
+    TRC(fprintf(stderr, "Created new TCPIP comstack\n"));
+
+    return p;
+}
+
+struct sockaddr_in *tcpip_strtoaddr(const char *str)
+{
+    static struct sockaddr_in add;
+    struct hostent *hp;
+    char *p, buf[512];
+    short int port = 210;
+    unsigned tmpadd;
+
+    TRC(fprintf(stderr, "tcpip_strtoaddress: %s\n", str ? str : "NULL"));
+    add.sin_family = AF_INET;
+    strcpy(buf, str);
+    if ((p = strchr(buf, ':')))
+    {
+       *p = 0;
+       port = atoi(p + 1);
+    }
+    add.sin_port = htons(port);
+    if ((hp = gethostbyname(buf)))
+       memcpy(&add.sin_addr.s_addr, *hp->h_addr_list, sizeof(struct in_addr));
+    else if ((tmpadd = (unsigned) inet_addr(buf)) != 0)
+       memcpy(&add.sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
+    else
+       return 0;
+    return &add;
+}
+
+int tcpip_more(COMSTACK h)
+{
+    tcpip_state *sp = h->private;
+
+    return sp->altlen && completeBER((unsigned char *) sp->altbuf, sp->altlen);
+}
+
+/*
+ * connect(2) will block - nothing we can do short of doing weird things
+ * like spawning subprocesses or threading or some weird junk like that.
+ */
+int tcpip_connect(COMSTACK h, void *address)
+{
+    struct sockaddr_in *add = address;
+
+    TRC(fprintf(stderr, "tcpip_connect\n"));
+    if (connect(h->iofile, (struct sockaddr *) add, sizeof(*add)) < 0)
+    {
+       if (errno == EINPROGRESS)
+           return 1;
+       return -1;
+    }
+    h->state = CS_DATAXFER;
+    return 0;
+}
+
+/*
+ * nop
+ */
+int tcpip_rcvconnect(COMSTACK h)
+{
+    TRC(fprintf(stderr, "tcpip_rcvconnect\n"));
+    return 0;
+}
+
+int tcpip_bind(COMSTACK h, void *address, int mode)
+{
+    struct sockaddr *addr = address;
+    int one = 1;
+
+    TRC(fprintf(stderr, "tcpip_bind\n"));
+    if (setsockopt(h->iofile, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
+    {
+       h->errno = CSYSERR;
+       return -1;
+    }
+    if (bind(h->iofile, addr, sizeof(struct sockaddr_in)) < 0)
+    {
+       h->errno = CSYSERR;
+       return -1;
+    }
+    if (mode == CS_SERVER && listen(h->iofile, 3) < 0)
+    {
+       h->errno = CSYSERR;
+       return -1;
+    }
+    h->state = CS_IDLE;
+    return 0;
+}
+
+int tcpip_listen(COMSTACK h, char *raddr, int *addrlen)
+{
+    struct sockaddr_in addr;
+    int len = sizeof(addr);
+
+    TRC(fprintf(stderr, "tcpip_listen\n"));
+    if (h->state != CS_IDLE)
+    {
+       h->errno = CSOUTSTATE;
+       return -1;
+    }
+    if ((h->newfd = accept(h->iofile, (struct sockaddr*)&addr, &len)) < 0)
+    {
+       if (errno == EWOULDBLOCK)
+           h->errno = CSNODATA;
+       else
+           h->errno = CSYSERR;
+       return -1;
+    }
+    if (addrlen && *addrlen > sizeof(struct sockaddr_in))
+       memcpy(raddr, &addr, *addrlen = sizeof(struct sockaddr_in));
+    else if (addrlen)
+       *addrlen = 0;
+    h->state = CS_INCON;
+    return 0;
+}
+
+COMSTACK tcpip_accept(COMSTACK h)
+{
+    COMSTACK new;
+    tcpip_state *state;
+
+    TRC(fprintf(stderr, "tcpip_accept\n"));
+    if (h->state != CS_INCON)
+    {
+       h->errno = CSOUTSTATE;
+       return 0;
+    }
+    if (!(new = malloc(sizeof(*new))))
+    {
+       h->errno = CSYSERR;
+       return 0;
+    }
+    memcpy(new, h, sizeof(*h));
+    new->iofile = h->newfd;
+    if (!(state = new->private = malloc(sizeof(tcpip_state))))
+    {
+       h->errno = CSYSERR;
+       return 0;
+    }
+    if (!new->blocking && fcntl(new->iofile, F_SETFL, O_NONBLOCK) < 0)
+       return 0;
+    state->altbuf = 0;
+    state->altsize = state->altlen = 0;
+    state->towrite = state->written = -1;
+    new->state = CS_DATAXFER;
+    h->state = CS_IDLE;
+    return new;
+}
+
+#define CS_TCPIP_BUFCHUNK 4096
+
+/*
+ * Return: -1 error, >1 good, len of buffer, ==1 incomplete buffer,
+ * 0=connection closed.
+ */
+int tcpip_get(COMSTACK h, char **buf, int *bufsize)
+{
+    tcpip_state *sp = h->private;
+    char *tmpc;
+    int tmpi, berlen, rest, req, tomove;
+    int hasread = 0, res;
+
+    TRC(fprintf(stderr, "tcpip_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;
+    }
+    while (!(berlen = completeBER((unsigned char *)*buf, hasread)))
+    {
+       if (!*bufsize)
+       {
+           if (!(*buf = malloc(*bufsize = CS_TCPIP_BUFCHUNK)))
+               return -1;
+       }
+       else if (*bufsize - hasread < CS_TCPIP_BUFCHUNK)
+           if (!(*buf = realloc(*buf, *bufsize *= 2)))
+               return -1;
+       if ((res = read(h->iofile, *buf + hasread, CS_TCPIP_BUFCHUNK)) < 0)
+           if (errno == EWOULDBLOCK)
+               break;
+           else
+               return -1;
+       if (!res)
+           return 0;
+       hasread += res;
+       TRC(fprintf(stderr, "  res=%d, hasread=%d\n", res, hasread));
+    }
+    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 = malloc(sp->altsize = req)))
+               return -1;
+       } else if (sp->altsize < req)
+           if (!(sp->altbuf = realloc(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_TCPIP_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 tcpip_put(COMSTACK h, char *buf, int size)
+{
+    int res;
+    struct tcpip_state *state = h->private;
+
+    TRC(fprintf(stderr, "tcpip_put: size=%d\n", size));
+    if (state->towrite < 0)
+    {
+       state->towrite = size;
+       state->written = 0;
+    }
+    else if (state->towrite != size)
+    {
+       h->errno = CSWRONGBUF;
+       return -1;
+    }
+    while (state->towrite > state->written)
+    {
+       if ((res = write(h->iofile, buf + state->written, size -
+           state->written)) < 0)
+       {
+           if (errno == EAGAIN)
+           {
+               TRC(fprintf(stderr, "  Flow control stop\n"));
+               return 1;
+           }
+           h->errno = 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 tcpip_close(COMSTACK h)
+{
+    tcpip_state *sp = h->private;
+
+    TRC(fprintf(stderr, "tcpip_close\n"));
+    close(h->iofile);
+    if (sp->altbuf)
+       free(sp->altbuf);
+    free(sp);
+    free(h);
+    return 0;
+}
diff --git a/comstack/xmosi.c b/comstack/xmosi.c
new file mode 100644 (file)
index 0000000..9e15a28
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 1995, Index Data
+ * See the file LICENSE for details.
+ * Sebastian Hammer, Adam Dickmeiss
+ *
+ * $Log: xmosi.c,v $
+ * Revision 1.1  1995-06-14 09:58:20  quinn
+ * Renamed yazlib to comstack.
+ *
+ * Revision 1.15  1995/05/29  08:12:33  quinn
+ * Updates to aynch. operations.
+ *
+ * Revision 1.14  1995/05/16  09:37:31  quinn
+ * Fixed bug
+ *
+ * Revision 1.13  1995/05/16  08:51:19  quinn
+ * License, documentation, and memory fixes
+ *
+ * Revision 1.12  1995/05/02  08:53:24  quinn
+ * Trying in vain to fix comm with ISODE
+ *
+ * Revision 1.11  1995/04/21  16:32:08  quinn
+ * *** empty log message ***
+ *
+ * Revision 1.10  1995/03/27  08:36:14  quinn
+ * Some work on nonblocking operation in xmosi.c and rfct.c.
+ * Added protocol parameter to cs_create()
+ *
+ * Revision 1.9  1995/03/20  09:47:23  quinn
+ * Added server-side support to xmosi.c
+ * Fixed possible problems in rfct
+ * Other little mods
+ *
+ * Revision 1.8  1995/03/16  13:29:30  quinn
+ * Beginning to add server-side functions
+ *
+ * Revision 1.7  1995/03/14  10:28:47  quinn
+ * Adding server-side support to tcpip.c and fixing bugs in nonblocking I/O
+ *
+ * Revision 1.6  1995/03/09  15:22:43  quinn
+ * Fixed two bugs in get/rcv
+ *
+ * Revision 1.5  1995/03/07  16:29:47  quinn
+ * Various fixes.
+ *
+ * Revision 1.4  1995/03/07  10:26:56  quinn
+ * Initialized type field in the comstacks.
+ *
+ * Revision 1.3  1995/03/06  16:48:03  quinn
+ * Smallish changes.
+ *
+ * Revision 1.2  1995/03/06  10:54:41  quinn
+ * Server-side functions (t_bind/t_listen/t_accept) seem to work ok, now.
+ * Nonblocking mode needs work (and testing!)
+ * Added makensap to replace function in mosiutil.c.
+ *
+ * Revision 1.1  1995/03/01  08:40:33  quinn
+ * First working version of rfct. Addressing needs work.
+ *
+ */
+
+/*
+ * Glue layer for Peter Furniss' xtimosi package.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <comstack.h>
+#include <xmosi.h>
+
+#include <oid.h>
+
+int mosi_connect(COMSTACK h, void *address);
+int mosi_get(COMSTACK h, char **buf, int *bufsize);
+int mosi_put(COMSTACK h, char *buf, int size);
+int mosi_more(COMSTACK h) { return 0; } /* not correct */
+int mosi_close(COMSTACK h);
+int mosi_rcvconnect(COMSTACK h);
+int mosi_bind(COMSTACK h, void *address, int mode);
+int mosi_listen(COMSTACK h, char *addrp, int *addrlen);
+COMSTACK mosi_accept(COMSTACK h);
+
+typedef struct mosi_state
+{
+    struct t_info info;        /* data returned by t_open */
+    struct t_call *call;
+    int hasread;               /* how many bytes read of current PDU */
+    int haswrit;               /* how many bytes have we written */
+} mosi_state;
+
+static char *oidtostr(int *o)
+{
+    static char buf[512];
+
+    buf[0] = '\0';
+    while (*o >= 0)
+    {
+       sprintf(buf + strlen(buf), "%d", *o);
+       if (*(++o) >= 0)
+           strcat(buf, " ");
+    }
+    return buf;
+}
+
+static int addopt(struct netbuf *optbuf, unsigned long level, unsigned long
+    name, enum oid_proto proto, enum oid_class class, enum oid_value value)
+{
+    int *oid;
+    oident ent;
+    char *str;
+
+    ent.proto = proto;
+    ent.class = class;
+    ent.value = value;
+    if (!(oid = oid_getoidbyent(&ent)))
+       return -1;
+    str = oidtostr(oid);
+    if (addoidoption(optbuf, level, name, str) < 0)
+       return -1;
+    return 0;
+}
+
+COMSTACK mosi_type(int blocking, int protocol)
+{
+    COMSTACK r;
+    mosi_state *state;
+    int flags = O_RDWR;
+
+    if (!(r = malloc(sizeof(*r))))
+       return 0;
+    if (!(state = r->private = malloc(sizeof(*state))))
+       return 0;
+
+    state->call = 0;
+    state->hasread = 0;
+    state->haswrit = 0;
+    r->protocol = protocol;
+    r->state = CS_UNBND;
+    r->type = mosi_type;
+    r->blocking = blocking;
+    r->f_connect = mosi_connect;
+    r->f_put = mosi_put;
+    r->f_get = mosi_get;
+    r->f_close = mosi_close;
+    r->f_more = mosi_more;
+    r->f_rcvconnect = mosi_rcvconnect;
+    r->f_bind = mosi_bind;
+    r->f_listen = mosi_listen;
+    r->f_accept = mosi_accept;
+
+    if (!blocking)
+       flags |= O_NONBLOCK;
+    if ((r->iofile = u_open(CO_MOSI_NAME, flags, &state->info)) < 0)
+       return 0;
+
+    r->timeout = COMSTACK_DEFAULT_TIMEOUT;
+
+    return r;
+}
+
+int hex2oct(char *hex, char *oct)
+{
+    int len = 0;
+    unsigned val;
+
+    while (sscanf(hex, "%2x", &val) == 1)
+    {
+       if (strlen(hex) < 2)
+           return -1;
+       *((unsigned char*) oct++) = (unsigned char) val;
+       len++;
+       hex += 2;
+    }
+    return len;
+}
+
+/*
+ * addressing specific to our hack of OSI transport. A sockaddr_in wrapped
+ * up in a t_mosiaddr in a netbuf (on a stick).
+ */
+struct netbuf *mosi_strtoaddr(const char *str)
+{
+    struct netbuf *ret = malloc(sizeof(struct netbuf));
+    struct sockaddr_in *add = malloc(sizeof(struct sockaddr_in));
+    struct t_mosiaddr *mosiaddr = malloc(sizeof(struct t_mosiaddr));
+    struct hostent *hp;
+    char *p, *b, buf[512], *nsap;
+    short int port = 102;
+    unsigned long tmpadd;
+    int ll = 0;
+
+    assert(ret && add && mosiaddr);
+#if 0
+    mosiaddr->osi_ap_inv_id = NO_INVOKEID;
+    mosiaddr->osi_ae_inv_id = NO_INVOKEID;
+#endif
+    mosiaddr->osi_apt_len = 0;
+    mosiaddr->osi_aeq_len = 0;
+    p = (char*)MOSI_PADDR(mosiaddr);
+    *(p++) = 0; /* No presentation selector */
+    ll++;
+    *(p++) = 0; /* no session selector */
+    ll++;
+    /* do we have a transport selector? */
+    strcpy(buf, str);
+    if ((nsap = strchr(buf, '/')))
+    {
+       *(nsap++) = '\0';
+       if ((*p = hex2oct(buf, p + 1)) < 0)
+           return 0;
+       ll += *p + 1;
+       p += *p + 1;
+    }
+    else
+    {
+       nsap = buf;
+       *(p++) = 0;
+       ll++;
+    }
+    if (nsap && *nsap)
+    {
+       add->sin_family = AF_INET;
+       strcpy(buf, nsap);
+       if ((b = strchr(buf, ':')))
+       {
+           *b = 0;
+           port = atoi(b + 1);
+       }
+       add->sin_port = htons(port);
+       if ((hp = gethostbyname(buf)))
+           memcpy(&add->sin_addr.s_addr, *hp->h_addr_list, sizeof(struct in_addr));
+       else if ((tmpadd = inet_addr(buf)) != 0)
+           memcpy(&add->sin_addr.s_addr, &tmpadd, sizeof(struct in_addr));
+       else
+           return 0;
+       *(p++) = (char) sizeof(*add);
+       ll++;
+       memcpy(p, add, sizeof(*add));
+       ll += sizeof(*add);
+    }
+    else
+    {
+       *(p++) = 0;
+       ll++;
+    }
+    mosiaddr->osi_paddr_len = ll;
+    ret->buf = (char*)mosiaddr;
+    ret->len = ret->maxlen = 100 /* sizeof(*mosiaddr) */ ;
+
+    return ret;
+}
+
+int mosi_connect(COMSTACK h, void *address)
+{
+    struct netbuf *addr = address, *local;
+    struct t_call *snd, *rcv;
+    struct t_bind bnd;
+
+    if (!(snd = (struct t_call *) u_alloc(h->iofile, T_CALL, T_ALL)))
+       return -1;
+    if (!(rcv = (struct t_call *) u_alloc(h->iofile, T_CALL, T_ALL)))
+       return -1;
+
+    snd->udata.len = 0;
+    if (addopt(&snd->opt, ISO_APCO, AP_CNTX_NAME, h->protocol, CLASS_APPCTX,
+       VAL_BASIC_CTX) < 0)
+       return -1;
+    if (addopt(&snd->opt, ISO_APCO, AP_ABS_SYN, h->protocol, CLASS_ABSYN,
+       VAL_APDU) < 0)
+       return -1;
+    /*
+     * We don't specify record formats yet.
+     *
+     * Xtimosi adds the oid for BER as transfer syntax automatically.
+     */
+
+    bnd.qlen = 0;
+
+    if (h->state == CS_UNBND)
+    {
+       local = mosi_strtoaddr("");   /* not good in long run */
+       memcpy(&bnd.addr, local, sizeof(*local));
+       if (u_bind(h->iofile, &bnd, 0) < 0)
+           return -1;
+    }
+
+    memcpy(&snd->addr, addr, sizeof(*addr));
+    if (u_connect(h->iofile, snd, rcv) < 0)
+    {
+       if (t_errno == TNODATA)
+           return 1;
+       return -1; 
+    }
+    return 0;
+}
+
+int mosi_rcvconnect(COMSTACK h)
+{
+    if (u_rcvconnect(h->iofile, 0) < 0)
+    {
+       if (t_errno == TNODATA)
+           return 1;
+       return -1;
+    }
+    return 0;
+}
+
+int mosi_bind(COMSTACK h, void *address, int mode)
+{
+    int res;
+    struct t_bind bnd;
+
+    if (mode == CS_SERVER)
+       bnd.qlen = 3;
+    else
+       bnd.qlen = 0;
+    memcpy(&bnd.addr, address, sizeof(struct netbuf));
+    if ((res = u_bind(h->iofile, &bnd, 0)) < 0)
+       return -1;
+    h->state = CS_IDLE;
+    return 0;
+}
+
+int mosi_listen(COMSTACK h, char *addp, int *addrlen)
+{
+    int res;
+    mosi_state *st = h->private;
+
+    if (!(st->call = (struct t_call*) t_alloc(h->iofile, T_CALL_STR,
+        T_ALL)))
+       return -1;
+    if ((res = u_listen(h->iofile, st->call)) < 0)
+    {
+       if (t_errno == TNODATA)
+           return 1;
+       return -1;
+    }
+    h->state = CS_INCON;
+    return 0;
+}
+
+COMSTACK mosi_accept(COMSTACK h)
+{
+    COMSTACK new;
+    void *local;
+    struct mosi_state *st = h->private, *ns;
+    int flags = O_RDWR;
+
+    if (h->state != CS_INCON)
+    {
+       h->errno = CSOUTSTATE;
+       return 0;
+    }
+    if (!(new = malloc(sizeof(*new))))
+       return 0;
+    *new = *h;
+    if (!(new->private = ns = malloc(sizeof(*ns))))
+       return 0;
+    *ns = *st;
+    if (!h->blocking)
+       flags |= O_NONBLOCK;
+    if ((new->iofile = u_open_r(CO_MOSI_NAME, flags, &st->info, st->call)) < 0)
+       return 0;
+    if (!(local = mosi_strtoaddr("")))
+       return 0;
+    if (mosi_bind(new, local, CS_CLIENT) < 0) /* CS_CLIENT: qlen == 0 */
+       return 0;
+    memcpy(&st->call->addr, local, sizeof(st->call->addr));
+    if (u_accept(h->iofile, new->iofile, st->call) < 0)
+    {
+       mosi_close(new);
+       return 0;
+    }
+    return new;
+}
+
+#define CS_MOSI_BUFCHUNK 4096
+
+int mosi_get(COMSTACK h, char **buf, int *bufsize)
+{
+    int flags = 0, res;
+    mosi_state *ct = h->private;
+    int got;
+
+    do
+    {
+       if (!*bufsize)
+       {
+           if (!(*buf = malloc(*bufsize = CS_MOSI_BUFCHUNK)))
+               return -1;
+       }
+       else if (*bufsize - ct->hasread < CS_MOSI_BUFCHUNK)
+           if (!(*buf = realloc(*buf, *bufsize *= 2)))
+               return -1;
+
+       if ((res = u_rcv(h->iofile, *buf + ct->hasread, CS_MOSI_BUFCHUNK,
+           &flags)) <= 0)
+       {
+           if (t_errno == TNODATA)
+               return 1;
+           return -1;
+       }
+       ct->hasread += res;
+    }
+    while (flags & T_MORE);
+
+    /* all done. Reset hasread */
+    got = ct->hasread;
+    ct->hasread = 0;  
+    return got;
+}
+
+int mosi_put(COMSTACK h, char *buf, int size)
+{
+    mosi_state *ct = h->private;
+    int res = u_snd(h->iofile, buf + ct->haswrit, size - ct->haswrit, 0);
+
+    if (res == size - ct->haswrit)
+    {
+       ct->haswrit = 0;
+       return 0;
+    }
+    else if (res < 0)
+    {
+       if (t_errno == TFLOW)
+           return 1;
+       return -1;
+    }
+    ct->haswrit += res;
+    return 1;
+}
+
+int mosi_close(COMSTACK h)
+{
+    free(h->private);
+    if (h->iofile >= 0)
+       u_close(h->iofile);
+    free(h);
+    return 0;
+}