Protocol behavior sections. record_get raw returning Z External *.
authorAdam Dickmeiss <adam@indexdata.dk>
Sun, 11 Nov 2001 22:25:25 +0000 (22:25 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Sun, 11 Nov 2001 22:25:25 +0000 (22:25 +0000)
doc/zoom.xml
zoom/zoom-c.c
zoom/zoomtst7.c

index c350599..2937474 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $Id: zoom.xml,v 1.6 2001-11-06 17:05:19 adam Exp $ -->
+<!-- $Id: zoom.xml,v 1.7 2001-11-11 22:25:25 adam Exp $ -->
  <chapter id="zoom"><title>Building clients with ZOOM</title>
   
   <para>
    that because of typedefs. All destroy methods should gracefully ignore a
    <literal>NULL</literal> pointer.
   </para>
+  <para>
+   In each of the sections below you'll find a sub section called
+   protocol behavior, that descries how the API maps to the Z39.50
+   protocol.
+  </para>
   <sect1 id="zoom.connections"><title>Connections</title>
    
    <para>The Connection object is a session with a target.
       <row><entry>
         async</entry><entry>If true (1) the connection operates in 
         asynchronous operation which means that all calls are non-blocking
-        except <function>Z3950_event</function>.
+        except
+        <link linkend="zoom.events"><function>Z3950_event</function></link>.
        </entry><entry>0</entry></row>
       <row><entry>
         maximumRecordSize</entry><entry> Maximum size of single record.
     holds messages for the error and additional-info if passed as
     non-<literal>NULL</literal>.
    </para>
+   <sect2><title>Protocol behavior</title>
+    <para>
+     The calls <function>Z3950_connection_new</function> and
+     <function>Z3950_connection_connect</function> establises a TCP/IP
+      connection and sends an Initialize Request to the target if
+      possible. In addition, the calls waits for an Initialize Response
+      from the target and the result is inspected (OK or rejected).
+    </para>
+    <para>
+     If <literal>proxy</literal> is set then the client will establish
+     a TCP/IP connection with the peer as specified by the
+     <literal>proxy</literal> host and the hostname as part of the
+     connect calls will be set as part of the Initialize Request.
+     The proxy server will then "forward" the PDU's transparently
+     to the target behind the proxy.
+    </para>
+    <para>
+     For the authentication parameters, if option <literal>user</literal>
+     is set and both options <literal>group</literal> and
+     <literal>pass</literal> are unset, then Open style
+     authentication is used (Version 2/3) in which case the username
+     is usually followed by a slash, then by a password.
+     If either <literal>group</literal>
+     or <literal>pass</literal> is set then idPass authentication
+     (Version 3 only) is used. If none of the options are set, no
+     authentication parameters are set as part of the Initialize Request
+     (obviously).
+    </para>
+    <para>
+     When option <literal>async</literal> is 1, it really means that
+     all network operations are postponed (and queued) until the
+     function <literal>Z3950_event</literal> is invoked. When doing so
+     it doesn't make sense to check for errors after
+     <literal>Z3950_connection_new</literal> is called since that
+     operation "connecting - and init" is still incomplete and the
+     API cannot tell the outcome (yet).
+    </para>
+    </sect2>
   </sect1>
   <sect1 id="zoom.query"><title>Queries</title>
    <para>
     sort criteria using the same string notation for sort as offered by
     the <link linkend="sortspec">YAZ client</link>.
    </para>
+   <sect2><title>Protocol behavior</title>
+    <para>
+     The query object is just an interface for the member Query
+     in the SearchRequest. The sortby-function is an interface to the
+     sortSequence member of the SortRequest.
+    </para>
+   </sect2>
   </sect1>
   <sect1 id="zoom.resultsets"><title>Result sets</title>
    <para>
         value, then target will return all records using small element set name
        </entry><entry>0</entry></row>
       <row><entry>
-        largeSetLowerBound</entry><entry>If hits is greator than this value, the target
-        will return no records.
+        largeSetLowerBound</entry><entry>If hits is greator than this
+        value, the target will return no records.
        </entry><entry>1</entry></row>
       <row><entry>
         mediumSetPresentNumber</entry><entry>This value represents
      </tbody>
     </tgroup>
    </table>
+   <sect2>
+    <title>Protocol behavior</title>
+    <para>
+     The creation of a result set involves at least a SearchRequest
+     - SearchResponse protocol handshake. Following that, if a sort
+     critieria was specified as part of the query, a sortRequest -
+     SortResponse handshake takes place. Note that it is necessary to
+     perform sorting before any retrieval takes place, so no records will
+     be returned from the target as part of the SearchResponse because these
+     would be unsorted. Hence, piggyback is disabled when sort critieria
+     is set. Following Search - and a Possible sort, Retrieval takes
+     place - as one or more Present Requests - Present Response being
+     transferred.
+     </para>
+    <para>
+     The API allows for two different modes for retrieval. A high level
+     mode which is somewhat more powerful and a low level one.
+     The low level is "enabled" when the settings
+     <literal>smallSetUpperBound</literal>,
+     <literal>mediumSetPresentNumber</literal> and
+     <literal>largeSetLowerBound</literal> are set. The low level mode
+     thus allows you to precisely set how records are returned as part
+     of a search response as offered by the Z39.50 protocol.
+     Since the client may be retrieving records as part of the
+     search response, this mode doesn't work well if sorting is used.
+     </para>
+    <para>
+     The high-level mode allows you to fetch a range of records from
+     the result set with a given start offset. When you use this mode
+     the client will automatically use piggyback if that is possible
+     with the target and perform one or more present requests as needed.
+     Even if the target returns fewer records as part of a present response
+     because of a record size limit, etc. the client will repeat sending
+     present requests. As an example, if option <literal>start</literal>
+     is 0 (default) and <literal>count</literal> is 4, and
+     <literal>piggyback</literal> is 1 (default) and no sorting critieria
+     is specified, then the client will attempt to retrieve the 4
+     records as part the search response (using piggyback). On the other
+     hand, if either <literal>start</literal> is positive or if
+     a sorting criteria is set, or if <literal>piggyback</literal>
+     is 0, then the client will not perform piggyback but send Present
+     Requests instead.
+    </para>
+    <para>
+     If either of the options <literal>mediumSetElementSetName</literal> and
+     <literal>smallSetElementSetName</literal> are unset, the value
+     of option <literal>elementSetName</literal> is used for piggyback
+     searches. This means that for the high-level mode you only have
+     to specify one elementSetName option rather than three.
+     </para>
+   </sect2>
   </sect1>
   <sect1 id="zoom.records"><title>Records</title>
    <para>
     Function <function>Z3950_resultset_records</function> retrieves
     a number of records from a result set. Parameter <literal>start</literal>
     and <literal>count</literal> specifies the range of records to
-    be returned. Upon completion array <literal>recs[0], ..recs[count-1]</literal>
+    be returned. Upon completion array
+    <literal>recs[0], ..recs[count-1]</literal>
     holds record objects for the records. The array of records
      <literal>recs</literal> should be allocate prior to calling 
     <function>Z3950_resultset_records</function>. Note that for those
     nature (type) of the pointer depends on the <function>type</function>
     given. In addition for certain types, the length
     <literal>len</literal> passed will be set to the size in bytes of
-    the returned information. The types <literal>database</literal>,
-    <literal>syntax</literal> and <literal>render</literal> are
-    supported. More will be added later.
+    the returned information.
+    <variablelist>
+     <varlistentry><term><literal>database</literal></term>
+      <listitem><para>The database that holds the record is returned
+        as a C string. Return type <literal>char *</literal>. 
+       </para></listitem>
+      </varlistentry>
+     <varlistentry><term><literal>syntax</literal></term>
+      <listitem><para>The transfer syntax (OID) of the record is returned
+        as a C string. Return type <literal>char *</literal>. 
+       </para></listitem>
+      </varlistentry>
+     <varlistentry><term><literal>render</literal></term>
+      <listitem><para>The record is returned in a display friendly
+        format. Upon completion buffer is returned
+        (type <literal>char *</literal>) and length is stored in
+        <literal>*len</literal>.
+       </para></listitem>
+      </varlistentry>
+     <varlistentry><term><literal>raw</literal></term>
+      <listitem><para>The record is returned in the internal
+        YAZ specific format. The raw data is returned as type 
+        <literal>Z_External *</literal> is just the type for
+        the member <literal>retrievalRecord</literal> in
+        type <literal>NamePlusRecord</literal>.
+       </para></listitem>
+      </varlistentry>
+    </variablelist>
    </para>
+   <sect2><title>Protocol behavior</title>
+    <para>
+     The functions <function>Z3950_resultset_record</function> and
+     <function>Z3950_resultset_records</function> inspects the client-side
+     record cache. If the records(s) were not found, i.e. not yet retrieved
+     from, they are fetched using Present Requests.
+    </para>
+   </sect2>
   </sect1>
   <sect1 id="zoom.options"><title>Options</title>
    <para>
-    Most &zoom; objects provide a way to specify options to default behaviour.
+    Most &zoom; objects provide a way to specify options to default behavior.
     From an implementation point of view a set of options is just like
     an associate array / hash array, etc.
    </para>
     occurred for connection <literal>cs[n-1]</literal>.
     When no events are pending for the connections, a value of zero is
     returned.
-    To make sure all outstanding requests are performed call this function
+    To ensure that all outstanding requests are performed call this function
     repeatedly until zero is returned.
    </para>
   </sect1>
index 8b38ce3..21ae004 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: zoom-c.c,v 1.3 2001-11-06 17:05:19 adam Exp $
+ * $Id: zoom-c.c,v 1.4 2001-11-11 22:25:25 adam Exp $
  *
  * ZOOM layer for C, connections, result sets, queries.
  */
 
 #include "zoom-p.h"
 
+#define USE_POLL 0
+
+#if USE_POLL
+#include <sys/poll.h>
+#endif
+
 static Z3950_record record_cache_lookup (Z3950_resultset r,
                                         int pos,
                                         const char *elementSetName);
@@ -434,7 +440,8 @@ static void do_connect (Z3950_connection c)
        if (ret >= 0)
        {
            c->state = STATE_CONNECTING; 
-           c->mask = Z3950_SELECT_READ | Z3950_SELECT_WRITE | Z3950_SELECT_EXCEPT;
+           c->mask = Z3950_SELECT_READ | Z3950_SELECT_WRITE | 
+                Z3950_SELECT_EXCEPT;
            return;
        }
     }
@@ -820,6 +827,15 @@ void *Z3950_record_get (Z3950_record rec, const char *type, size_t *len)
        }
        return 0;
     }
+    else if (!strcmp (type, "raw"))
+    {
+       if (npr->which == Z_NamePlusRecord_databaseRecord)
+       {
+            *len = -1;
+           return (Z_External *) npr->u.databaseRecord;
+       }
+       return 0;
+    }
     return 0;
 }
 
@@ -1192,12 +1208,12 @@ static int do_write_ex (Z3950_connection c, char *buf_out, int len_out)
     else if (r == 1)
     {
        c->state = STATE_ESTABLISHED;
-       c->mask = Z3950_SELECT_READ|Z3950_SELECT_WRITE;
+       c->mask = Z3950_SELECT_READ|Z3950_SELECT_WRITE|Z3950_SELECT_EXCEPT;
     }
     else
     {
        c->state = STATE_ESTABLISHED;
-       c->mask = Z3950_SELECT_READ;
+       c->mask = Z3950_SELECT_READ|Z3950_SELECT_EXCEPT;
     }
     return 0;
 }
@@ -1293,7 +1309,7 @@ int Z3950_connection_do_io(Z3950_connection c, int mask)
 {
 #if 0
     int r = cs_look(c->cs);
-    yaz_log (LOG_DEBUG, "Z3950_connection_do_io c=%p mask=%d cs_look=%d",
+    yaz_log (LOG_LOG, "Z3950_connection_do_io c=%p mask=%d cs_look=%d",
             c, mask, r);
     
     if (r == CS_NONE)
@@ -1303,7 +1319,7 @@ int Z3950_connection_do_io(Z3950_connection c, int mask)
     }
     else if (r == CS_CONNECT)
     {
-       yaz_log (LOG_DEBUG, "calling rcvconnect");
+       yaz_log (LOG_LOG, "calling rcvconnect");
        if (cs_rcvconnect (c->cs) < 0)
        {
            c->error = Z3950_ERROR_CONNECT;
@@ -1350,9 +1366,14 @@ int Z3950_connection_do_io(Z3950_connection c, int mask)
 
 int Z3950_event (int no, Z3950_connection *cs)
 {
+#if USE_POLL
+    struct pollfd pollfds[1024];
+    Z3950_connection poll_cs[1024];
+#else
     struct timeval tv;
     fd_set input, output, except;
-    int i, r;
+#endif
+    int i, r, nfds;
     int max_fd = 0;
 
     for (i = 0; i<no; i++)
@@ -1365,13 +1386,17 @@ int Z3950_event (int no, Z3950_connection *cs)
        }
     }
 
+#if USE_POLL
+
+#else
     tv.tv_sec = 15;
     tv.tv_usec = 0;
     
     FD_ZERO (&input);
     FD_ZERO (&output);
     FD_ZERO (&except);
-    r = 0;
+#endif
+    nfds = 0;
     for (i = 0; i<no; i++)
     {
        Z3950_connection c = cs[i];
@@ -1386,23 +1411,43 @@ int Z3950_event (int no, Z3950_connection *cs)
            continue;
        if (max_fd < fd)
            max_fd = fd;
+
+#if USE_POLL
+        if (mask)
+        {
+            short poll_events = 0;
+
+            if (mask & Z3950_SELECT_READ)
+                poll_events += POLLIN;
+            if (mask & Z3950_SELECT_WRITE)
+                poll_events += POLLOUT;
+            if (mask & Z3950_SELECT_EXCEPT)
+                poll_events += POLLERR;
+            pollfds[nfds].fd = fd;
+            pollfds[nfds].events = poll_events;
+            pollfds[nfds].revents = 0;
+            poll_cs[nfds] = c;
+            nfds++;
+        }
+#else
        if (mask & Z3950_SELECT_READ)
        {
            FD_SET (fd, &input);
-           r++;
+           nfds++;
        }
        if (mask & Z3950_SELECT_WRITE)
        {
            FD_SET (fd, &output);
-           r++;
+           nfds++;
        }
        if (mask & Z3950_SELECT_EXCEPT)
        {
            FD_SET (fd, &except);
-           r++;
+           nfds++;
        }
+#endif
     }
-    if (!r)
+    if (!nfds)
     {
        for (i = 0; i<no; i++)
        {
@@ -1423,10 +1468,36 @@ int Z3950_event (int no, Z3950_connection *cs)
        yaz_log (LOG_DEBUG, "no more events");
        return 0;
     }
+#if USE_POLL
+    yaz_log (LOG_LOG, "poll start");
+    r = poll (pollfds, nfds, 15000);
+    yaz_log (LOG_LOG, "poll stop, returned r=%d", r);
+    for (i = 0; i<nfds; i++)
+    {
+        Z3950_connection c = poll_cs[i];
+        if (r && c->mask)
+        {
+            int mask = 0;
+            if (pollfds[i].revents & POLLIN)
+                mask += Z3950_SELECT_READ;
+            if (pollfds[i].revents & POLLOUT)
+                mask += Z3950_SELECT_WRITE;
+            if (pollfds[i].revents & POLLERR)
+                mask += Z3950_SELECT_EXCEPT;
+            if (mask)
+                Z3950_connection_do_io(c, mask);
+        }
+        else if (r == 0 && c->mask)
+        {
+           /* timeout and this connection was waiting */
+           c->error = Z3950_ERROR_TIMEOUT;
+           c->event_pending = 1;
+        }
+    }
+#else
     yaz_log (LOG_DEBUG, "select start");
     r = select (max_fd+1, &input, &output, &except, &tv);
     yaz_log (LOG_DEBUG, "select stop, returned r=%d", r);
-
     for (i = 0; i<no; i++)
     {
        Z3950_connection c = cs[i];
@@ -1455,6 +1526,8 @@ int Z3950_event (int no, Z3950_connection *cs)
            c->event_pending = 1;
        }
     }
+#endif
+
     for (i = 0; i<no; i++)
     {
        Z3950_connection c = cs[i];
index fd113cf..6c3aa6b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: zoomtst7.c,v 1.3 2001-11-06 17:05:19 adam Exp $
+ * $Id: zoomtst7.c,v 1.4 2001-11-11 22:25:25 adam Exp $
  *
  * API test..
  */
@@ -22,6 +22,15 @@ int main(int argc, char **argv)
 
     o = Z3950_options_create ();
 
+    z = Z3950_connection_new ("localhost", 9999);
+    if (Z3950_connection_error (z, 0, 0))
+    {
+        printf ("error - couldn't connect?\n");
+        exit (1);
+    }
+        
+    Z3950_connection_destroy (z);
+
     for (block = 0; block < 3; block++)
     {
        switch (block)