From 015df1a4126226d11e1b0cee52b7d569ca2f567e Mon Sep 17 00:00:00 2001 From: Sebastian Hammer Date: Thu, 20 Apr 1995 15:25:25 +0000 Subject: [PATCH] Asynch. API --- include/zaccess.h | 68 ++++++++++++++++++++++++++--- zlayer/Makefile | 7 ++- zlayer/zaccess-yaz.c | 118 ++++++++++++++++++++++++++++++++++++-------------- zlayer/zaccess.c | 82 +++++++++++++++++++++++------------ 4 files changed, 208 insertions(+), 67 deletions(-) diff --git a/include/zaccess.h b/include/zaccess.h index 91f7a97..2b3e8d7 100644 --- a/include/zaccess.h +++ b/include/zaccess.h @@ -2,7 +2,10 @@ * Europagate, 1995 * * $Log: zaccess.h,v $ - * Revision 1.11 1995/04/19 12:55:41 quinn + * Revision 1.12 1995/04/20 15:25:25 quinn + * Asynch. API + * + * Revision 1.11 1995/04/19 12:55:41 quinn * Added auth * * Revision 1.10 1995/04/17 11:27:24 quinn @@ -26,8 +29,8 @@ #define ZASS_NAME "EUROPAGATE E-mail/Z39.50 gateway" #define ZASS_VERSION "development 0.2" -#define ZASS_MAXRECORDSIZE 10000 -#define ZASS_PREFERREDMESSAGESIZE 10000 +#define ZASS_MAXRECORDSIZE 40000 +#define ZASS_PREFERREDMESSAGESIZE 40000 typedef struct zass *ZASS; @@ -77,10 +80,63 @@ typedef struct zass_presentent struct zass_record *records; } zass_presentent; -ZASS zass_open(char *host, int port, char *auth); +/* + * open a connection to the target. If complete is NULL, the connection + * will be blocking, and complete will be ignored by the following + * primitives. If complete is not null, the connection will be non-blocking. + * if the connection cannot be established immediately, *complete will + * be set to zero, and the user should call openresult when select signals + * that I/O is possible. Returns NULL on a fatal error in the connection + * establishment. + */ +ZASS zass_open(char *host, int port, int *complete, char *auth); + +/* + * second half of connection establishment in nonblocking mode. + * Returns: + * -1 with *complete == 0 : call again when select allows. + * -1 with *complete == 1 : fatal error. Abort connection. + * 0 : success. + */ +int zass_openresult(ZASS a, int *complete); + +/* + * Return the file handle of the association (for select() & other fun. + */ +int zass_fileno(ZASS a); + +/* + * Returns: + * NULL with *complete == 0 : call searchresult when select allows (nonbl. only) + * NULL with *complete == 1 : fatal error. Abort connection. + * non-null : operation complete. + */ const struct zass_searchent *zass_search(ZASS a, struct ccl_rpn_node *query, - char *resname, char *databases); + char *resname, char *databases, int *complete); + +/* + * Returns: + * NULL with *complete == 0 : call again when select allows (nonbl. only) + * NULL with *complete == 1 : fatal error. Abort connection. + * non-null : operation complete. + */ +const struct zass_searchent *zass_searchresult(ZASS a, int *complete); + +/* + * Returns: + * NULL with *complete == 0 : call presentresult when select ok (nonbl. only) + * NULL with *complete == 1 : fatal error. Abort connection. + * non-null : operation complete. + */ const struct zass_presentent *zass_present(ZASS a, char *resname, int start, - int num); + int num, int *complete); + +/* + * Returns: + * NULL with *complete == 0 : call again when select allows (nonbl. only) + * NULL with *complete == 1 : fatal error. Abort connection. + * non-null : operation complete. + */ +const struct zass_presentent *zass_presentresult(ZASS a, int *complete); #endif diff --git a/zlayer/Makefile b/zlayer/Makefile index 8cc7c3a..40ebdc0 100644 --- a/zlayer/Makefile +++ b/zlayer/Makefile @@ -2,7 +2,10 @@ # Europagate, 1995 # # $Log: Makefile,v $ -# Revision 1.13 1995/04/19 16:08:25 adam +# Revision 1.14 1995/04/20 15:25:31 quinn +# Asynch. API +# +# Revision 1.13 1995/04/19 16:08:25 adam # Minor changes. # # Revision 1.12 1995/04/19 16:02:28 adam @@ -46,7 +49,7 @@ SHELL=/bin/sh #ZLIB=$(ZPRE)/libz3950.a ZINC=-I../../yaz/include -ZDEFS=-DUSE_XTIMOSI +#ZDEFS=-DUSE_XTIMOSI ZLIB=../../yaz/lib/libyaz.a INCLUDE=-I. -I../include $(ZINC) diff --git a/zlayer/zaccess-yaz.c b/zlayer/zaccess-yaz.c index 1dd02b2..31ef242 100644 --- a/zlayer/zaccess-yaz.c +++ b/zlayer/zaccess-yaz.c @@ -4,7 +4,10 @@ * Z39.50 API for the Email gateway - YAZ version * * $Log: zaccess-yaz.c,v $ - * Revision 1.4 1995/04/19 16:02:28 adam + * Revision 1.5 1995/04/20 15:25:32 quinn + * Asynch. API + * + * Revision 1.4 1995/04/19 16:02:28 adam * Record type hack. * * Revision 1.3 1995/04/19 12:55:15 quinn @@ -16,11 +19,10 @@ * Revision 1.1 1995/04/17 11:26:53 quinn * Added YAZ version of zaccess * - * */ /* - * Interface to the Z39.50 toolkit. + * Interface to the YAZ Z39.50 toolkit. */ #include @@ -45,14 +47,14 @@ struct zass /* Z-assoc */ ODR encode; ODR decode; int fd; /* low-level socket (for select only) */ + int nonblocking; int maxrecordsize; int preferredmessagesize; - char *outbuf; /* intermediary buffer */ char *inbuf; int inbuflen; }; -static Z_APDU *get_apdu(struct zass *z) +static Z_APDU *get_apdu(struct zass *z, int *complete) { int res; Z_APDU *ap; @@ -60,16 +62,28 @@ static Z_APDU *get_apdu(struct zass *z) if ((res = cs_get(z->ass, &z->inbuf, &z->inbuflen)) <= 0) { gw_log(GW_LOG_WARN, ZASS_TYPE, "cs_get failed"); + if (complete) + *complete = 1; return 0; } + else if (res == 1) + { + if (complete) + *complete = 0; + return 0; + } odr_reset(z->decode); odr_setbuf(z->decode, z->inbuf, res); if (!z_APDU(z->decode, &ap, 0)) { gw_log(GW_LOG_WARN, ZASS_TYPE, "decode: %s", odr_errlist[odr_geterror(z->decode)]); + if (complete) + *complete = 0; return 0; } + if (complete) + *complete = 1; return ap; } @@ -89,7 +103,7 @@ static int send_apdu(struct zass *z, Z_APDU *a) gw_log(GW_LOG_FATAL, ZASS_TYPE, "cs_put"); return -1; } - odr_reset(z->encode); + odr_reset(z->encode); /* release odr_allocated structures */ return 0; } @@ -115,14 +129,16 @@ static int send_initreq(struct zass *p, char *auth) ODR_MASK_SET(&protocolVersion, Z_ProtocolVersion_2); init.preferredMessageSize = &p->preferredmessagesize; init.maximumRecordSize = &p->maxrecordsize; - if (!auth) - init.idAuthentication = 0; - else + + if (auth) { init.idAuthentication = &idauth; idauth.which = Z_IdAuthentication_open; idauth.u.open = auth; } + else + init.idAuthentication = 0; + init.idAuthentication = 0; init.implementationId = ZASS_ID; sprintf(name, "%s (YAZ protocol layer)", ZASS_NAME); init.implementationName = name; @@ -133,12 +149,17 @@ static int send_initreq(struct zass *p, char *auth) return 0; } -static int receive_initres(struct zass *p) +int zass_fileno(ZASS a) +{ + return a->fd; +} + +int zass_openresult(ZASS p, int *complete) { Z_APDU *ap; Z_InitResponse *res; - if (!(ap = get_apdu(p))) + if (!(ap = get_apdu(p, complete))) return -1; if (ap->which != Z_APDU_initResponse) { @@ -166,7 +187,7 @@ static int receive_initres(struct zass *p) return 0; } -ZASS zass_open(char *host, int port, char *auth) +ZASS zass_open(char *host, int port, int *complete, char *auth) { struct zass *p; char addstr[512]; @@ -177,6 +198,13 @@ ZASS zass_open(char *host, int port, char *auth) gw_log(GW_LOG_FATAL|GW_LOG_ERRNO, ZASS_TYPE, "malloc"); return 0; } + if (complete) + { + *complete = 1; + p->nonblocking = 1; + } + else + p->nonblocking = 0; if (!(p->encode = odr_createmem(ODR_ENCODE)) || !(p->decode = odr_createmem(ODR_DECODE))) { @@ -185,17 +213,13 @@ ZASS zass_open(char *host, int port, char *auth) } p->maxrecordsize = ZASS_MAXRECORDSIZE; p->preferredmessagesize = ZASS_PREFERREDMESSAGESIZE; - if (!(p->outbuf = malloc(p->maxrecordsize + 1024))) - { - gw_log(GW_LOG_FATAL|GW_LOG_ERRNO, ZASS_TYPE, "malloc"); - return 0; - } - odr_setbuf(p->encode, p->outbuf, p->maxrecordsize + 1024); if (!(p->ass = cs_create(tcpip_type, 1, CS_Z3950))) { gw_log(GW_LOG_FATAL|GW_LOG_ERRNO, ZASS_TYPE, "cs_create"); return 0; } + p->inbuf = 0; + p->inbuflen = 0; sprintf(addstr, "%s:%d", host, port); if (!(address = tcpip_strtoaddr(addstr))) { @@ -209,18 +233,25 @@ ZASS zass_open(char *host, int port, char *auth) gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to connect to %s", addstr); return 0; } - gw_log(ZASS_DEBUG, ZASS_TYPE, "connected ok"); - p->inbuf = 0; - p->inbuflen = 0; - if (send_initreq(p, auth) < 0 || receive_initres(p) < 0) + gw_log(ZASS_DEBUG, ZASS_TYPE, "connected ok... initializing"); + if (send_initreq(p, auth) < 0) { - gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to initialize"); + gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to send init"); return 0; } - gw_log(ZASS_DEBUG, ZASS_TYPE, "Sent init request"); - return p; + if (p->nonblocking) + { + *complete = 0; + return p; + } + if (zass_openresult(p, complete) < 0) + return 0; + return p; /* all done */ } +/* + * Convert the egate (ccl2rpn) version of RPN to YAZ RPN. + */ static Z_RPNStructure *rpn2rpn(ODR o, struct ccl_rpn_node *q) { Z_RPNStructure *r = odr_malloc(o, sizeof(*r)); @@ -283,13 +314,13 @@ static Z_RPNStructure *rpn2rpn(ODR o, struct ccl_rpn_node *q) } } -static const struct zass_searchent *search_result(ZASS a) +const struct zass_searchent *zass_searchresult(ZASS a, int *complete) { static struct zass_searchent r; Z_APDU *apdu; Z_SearchResponse *res; - if (!(apdu = get_apdu(a))) + if (!(apdu = get_apdu(a, complete))) return 0; if (apdu->which != Z_APDU_searchResponse) { @@ -331,7 +362,7 @@ static const struct zass_searchent *search_result(ZASS a) } const struct zass_searchent *zass_search(ZASS a, struct ccl_rpn_node *query, - char *resname, char *databases) + char *resname, char *databases, int *complete) { Z_Query q; Z_RPNQuery rpnq; @@ -384,12 +415,20 @@ const struct zass_searchent *zass_search(ZASS a, struct ccl_rpn_node *query, bib1.class = CLASS_ATTSET; bib1.value = VAL_BIB1; rpnq.attributeSetId = oid_getoidbyent(&bib1); + + if (complete) + *complete = 1; if (!(rpnq.RPNStructure = rpn2rpn(a->encode, query))) return 0; if (send_apdu(a, &apdu) < 0) return 0; - - return search_result(a); + if (complete) + { + *complete = 0; + return 0; + } + else + return zass_searchresult(a, complete); } /* @@ -477,7 +516,9 @@ static int send_present(ZASS a, char *name, int start, int num, { Z_APDU apdu; Z_PresentRequest req; +#if 0 oident recsyn; +#endif apdu.which = Z_APDU_presentRequest; apdu.u.presentRequest = &req; @@ -499,13 +540,16 @@ static int send_present(ZASS a, char *name, int start, int num, /* * Note that 1== first record. + * TODO: make this baby operate in nonblocking mode, too. */ const struct zass_presentent *zass_present(ZASS a, char *resname, int start, - int num) + int num, int *complete) { static struct zass_presentent r; zass_record **rec = &r.records; + if (complete) + *complete = 1; r.num = 0; if (r.records) { @@ -521,8 +565,12 @@ const struct zass_presentent *zass_present(ZASS a, char *resname, int start, "Fetching %d records from # %d", num - r.num, start); if (send_present(a, resname, start, num - r.num, VAL_USMARC) < 0) return 0; - if (!(apdu = get_apdu(a))) + if (!(apdu = get_apdu(a, complete))) + { + if (complete) + *complete = 1; return 0; + } if (apdu->which != Z_APDU_presentResponse) { gw_log(GW_LOG_FATAL, ZASS_TYPE, "Expected presentresponse, got #%d", @@ -556,3 +604,9 @@ const struct zass_presentent *zass_present(ZASS a, char *resname, int start, while (num - r.num && start); return &r; } + +const struct zass_presentent *zass_presentresult(ZASS a, int *complete) +{ + *complete = 1; + return 0; +} diff --git a/zlayer/zaccess.c b/zlayer/zaccess.c index 0420161..6d7bc9f 100644 --- a/zlayer/zaccess.c +++ b/zlayer/zaccess.c @@ -4,7 +4,10 @@ * Z39.50 API for the Email gateway * * $Log: zaccess.c,v $ - * Revision 1.15 1995/04/17 11:26:55 quinn + * Revision 1.16 1995/04/20 15:25:34 quinn + * Asynch. API + * + * Revision 1.15 1995/04/17 11:26:55 quinn * Added YAZ version of zaccess * * Revision 1.14 1995/02/23 08:32:26 adam @@ -49,7 +52,18 @@ */ /* - * Interface to the Z39.50 toolkit. + * Interface to the Z39.50 toolkit. Primary function is to hide Zdist, or + * whatever lower-layer we decide to use later. The decision to add a + * layer atop the toolkit was twofold: It vastly simplifies the + * implementation of the protocol persistence, and it hides Zdist. The + * latter is useful after Zdist has gone and changed their fine API after + * we went through all the trouble of documenting it in our Design. Don't + * want that to happen again. + * + * For the time being at least, we'll have these routines hang (or err) if + * they get a WOULDBLOCK on a write. That seems safe since, under normal + * circumstances, the network buffers should always be able to absorb + * the small request packages. */ #include @@ -121,7 +135,38 @@ int rpn2kwaqs(struct ccl_rpn_node *q, char **p) } } -ZASS zass_open(char *host, int port) +int zass_openresult(ZASS p, int *complete) +{ + int len; + PINITRESPONSE ires; + + if ((len = zutil_GetBERFromNet(p->ass, (unsigned char*)p->buf, + p->maxrecordsize)) <= 0) + { + gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to receive initresponse"); + return 0; + } + ires = (PINITRESPONSE) zutil_CreateFromData((unsigned char*)p->buf, len); + if (InitResponse_GetTag(ires) != INITRESPONSE_TAG) + { + gw_log(GW_LOG_FATAL, ZASS_TYPE, "Expected initresponse from target"); + return 0; + } + gw_log(ZASS_DEBUG, ZASS_TYPE, "Got initresponse"); + if (!InitResponse_GetResult(ires)) + { + gw_log(GW_LOG_FATAL, ZASS_TYPE, "Access to target denied."); + return 0; + } + gw_log(ZASS_DEBUG, ZASS_TYPE, "Connected OK"); + p->preferredmessagesize = InitResponse_GetPreferredMessageSize(ires); + p->maxrecordsize = InitResponse_GetExceptionalRecordSize(ires); + InitResponse_Destroy(ires); + *complete = 1; + return 0; +} + +ZASS zass_open(char *host, int port, int *complete) { struct zass *p; PINITREQUEST ireq; @@ -156,8 +201,8 @@ ZASS zass_open(char *host, int port) gw_log(GW_LOG_WARN, ZASS_TYPE, "netbox_Open failed"); return 0; } - gw_log(ZASS_DEBUG, ZASS_TYPE, "Opened connection to %s:%d", p->ass->HostName, - p->ass->Port); + gw_log(ZASS_DEBUG, ZASS_TYPE, "Opened connection to %s:%d", + p->ass->HostName, p->ass->Port); sprintf(name, "%s (ZDIST protocol layer)", ZASS_NAME); ireq = InitRequest_CreateInitAllASCII(0, "yy", "yy", p->maxrecordsize, p->preferredmessagesize, ZASS_ID, name, ZASS_VERSION, 0); @@ -180,29 +225,12 @@ ZASS zass_open(char *host, int port) return 0; } gw_log(ZASS_DEBUG, ZASS_TYPE, "Sent initrequest."); - if ((len = zutil_GetBERFromNet(p->ass, (unsigned char*)p->buf, - p->maxrecordsize)) <= 0) - { - gw_log(GW_LOG_FATAL, ZASS_TYPE, "Failed to receive initresponse"); - return 0; - } - ires = (PINITRESPONSE) zutil_CreateFromData((unsigned char*)p->buf, len); - if (InitResponse_GetTag(ires) != INITRESPONSE_TAG) - { - gw_log(GW_LOG_FATAL, ZASS_TYPE, "Expected initresponse from target"); - return 0; - } - gw_log(ZASS_DEBUG, ZASS_TYPE, "Got initresponse"); - if (!InitResponse_GetResult(ires)) - { - gw_log(GW_LOG_FATAL, ZASS_TYPE, "Access to target denied."); + + if (zass_openresult(p, complete) < 0 && (!complete || *complete)) return 0; - } - gw_log(ZASS_DEBUG, ZASS_TYPE, "Connected OK"); - p->preferredmessagesize = InitResponse_GetPreferredMessageSize(ires); - p->maxrecordsize = InitResponse_GetExceptionalRecordSize(ires); - InitResponse_Destroy(ires); - return p; + else + return p; + } const struct zass_searchent *zass_search(ZASS a, struct ccl_rpn_node *query, -- 1.7.10.4