Asynch. API
authorSebastian Hammer <quinn@indexdata.com>
Thu, 20 Apr 1995 15:25:25 +0000 (15:25 +0000)
committerSebastian Hammer <quinn@indexdata.com>
Thu, 20 Apr 1995 15:25:25 +0000 (15:25 +0000)
include/zaccess.h
zlayer/Makefile
zlayer/zaccess-yaz.c
zlayer/zaccess.c

index 91f7a97..2b3e8d7 100644 (file)
@@ -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
index 8cc7c3a..40ebdc0 100644 (file)
@@ -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)
index 1dd02b2..31ef242 100644 (file)
@@ -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
  * 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 <stdlib.h>
@@ -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;
+}
index 0420161..6d7bc9f 100644 (file)
@@ -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
  */
 
 /*
- * 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 <stdlib.h>
@@ -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,