From: Sebastian Hammer Date: Wed, 14 Jun 1995 09:58:19 +0000 (+0000) Subject: Renamed yazlib to comstack. X-Git-Tag: YAZ.1.8~983 X-Git-Url: http://git.indexdata.com/?p=yaz-moved-to-github.git;a=commitdiff_plain;h=8a425ff5328260fff0dcc28f08b5bdf6bfac84ab Renamed yazlib to comstack. --- diff --git a/comstack/Makefile b/comstack/Makefile new file mode 100644 index 0000000..46f9770 --- /dev/null +++ b/comstack/Makefile @@ -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.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 index 0000000..2912d35 --- /dev/null +++ b/comstack/comstack.c @@ -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 index 0000000..d816123 --- /dev/null +++ b/comstack/tcpip.c @@ -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 +#include +#include +#include +#include +#include + +#include +#include +#include + +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 index 0000000..9e15a28 --- /dev/null +++ b/comstack/xmosi.c @@ -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 +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include + +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; +}