Use ZOOM_API(int) for public function ZOOM_connection_is_idle
[yaz-moved-to-github.git] / src / zoom-c.c
index f8242b9..2cb5bc9 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2006, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: zoom-c.c,v 1.82 2006-08-08 20:58:52 adam Exp $
+ * $Id: zoom-c.c,v 1.92 2006-10-05 14:58:58 adam Exp $
  */
 /**
  * \file zoom-c.c
@@ -40,6 +40,9 @@
 #include <sys/select.h>
 #endif
 #ifdef WIN32
+#if FD_SETSIZE < 512
+#define FD_SETSIZE 512
+#endif
 #include <winsock.h>
 #endif
 
@@ -55,7 +58,7 @@ static zoom_ret ZOOM_connection_send_init(ZOOM_connection c);
 static zoom_ret do_write_ex(ZOOM_connection c, char *buf_out, int len_out);
 static char *cql2pqf(ZOOM_connection c, const char *cql);
 
-static void initlog()
+static void initlog(void)
 {
     static int log_level_initialized = 0;
     if (!log_level_initialized)
@@ -203,6 +206,11 @@ ZOOM_task ZOOM_connection_add_task(ZOOM_connection c, int which)
     return *taskp;
 }
 
+ZOOM_API(int) ZOOM_connection_is_idle(ZOOM_connection c)
+{
+    return c->tasks ? 0 : 1;
+}
+
 ZOOM_task ZOOM_connection_insert_task(ZOOM_connection c, int which)
 {
     ZOOM_task task = (ZOOM_task) xmalloc(sizeof(*task));
@@ -314,6 +322,7 @@ ZOOM_API(ZOOM_connection)
     return c;
 }
 
+
 /* set database names. Take local databases (if set); otherwise
    take databases given in ZURL (if set); otherwise use Default */
 static char **set_DatabaseNames(ZOOM_connection con, ZOOM_options options,
@@ -371,6 +380,9 @@ ZOOM_API(void)
     yaz_log(log_api, "%p ZOOM_connection_connect host=%s portnum=%d",
             c, host, portnum);
 
+    set_ZOOM_error(c, ZOOM_ERROR_NONE, 0);
+    ZOOM_connection_remove_tasks(c);
+
     if (c->cs)
     {
         yaz_log(log_details, "%p ZOOM_connection_connect reconnect ok", c);
@@ -472,8 +484,6 @@ ZOOM_API(void)
     c->async = ZOOM_options_get_bool(c->options, "async", 0);
     yaz_log(log_details, "%p ZOOM_connection_connect async=%d", c, c->async);
  
-    set_ZOOM_error(c, ZOOM_ERROR_NONE, 0);
-
     task = ZOOM_connection_add_task(c, ZOOM_TASK_CONNECT);
 
     if (!c->async)
@@ -673,7 +683,7 @@ void ZOOM_resultset_addref(ZOOM_resultset r)
     }
 }
 
-ZOOM_resultset ZOOM_resultset_create()
+ZOOM_resultset ZOOM_resultset_create(void)
 {
     int i;
     ZOOM_resultset r = (ZOOM_resultset) xmalloc(sizeof(*r));
@@ -906,6 +916,17 @@ static void do_close(ZOOM_connection c)
     c->state = STATE_IDLE;
 }
 
+static int ZOOM_test_reconnect(ZOOM_connection c)
+{
+    if (!c->reconnect_ok)
+        return 0;
+    do_close(c);
+    c->reconnect_ok = 0;
+    c->tasks->running = 0;
+    ZOOM_connection_insert_task(c, ZOOM_TASK_CONNECT);
+    return 1;
+}
+
 static void ZOOM_resultset_retrieve(ZOOM_resultset r,
                                     int force_sync, int start, int count)
 {
@@ -1187,23 +1208,28 @@ static zoom_ret ZOOM_connection_send_init(ZOOM_connection c)
     ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_1);
     ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_2);
     ODR_MASK_SET(ireq->protocolVersion, Z_ProtocolVersion_3);
-
+    
     /* Index Data's Z39.50 Implementor Id is 81 */
-    ireq->implementationId = odr_prepend(c->odr_out,
-                                         ZOOM_options_get(c->options, "implementationId"),
-                                         odr_prepend(c->odr_out, "81", ireq->implementationId));
-
-    ireq->implementationName = odr_prepend(c->odr_out,
-                                           ZOOM_options_get(c->options, "implementationName"),
-                                           odr_prepend(c->odr_out, "ZOOM-C", ireq->implementationName));
-
-    version = odr_strdup(c->odr_out, "$Revision: 1.82 $");
+    ireq->implementationId =
+        odr_prepend(c->odr_out,
+                    ZOOM_options_get(c->options, "implementationId"),
+                    odr_prepend(c->odr_out, "81", ireq->implementationId));
+    
+    ireq->implementationName = 
+        odr_prepend(c->odr_out,
+                    ZOOM_options_get(c->options, "implementationName"),
+                    odr_prepend(c->odr_out, "ZOOM-C",
+                                ireq->implementationName));
+    
+    version = odr_strdup(c->odr_out, "$Revision: 1.92 $");
     if (strlen(version) > 10)   /* check for unexpanded CVS strings */
         version[strlen(version)-2] = '\0';
-    ireq->implementationVersion = odr_prepend(c->odr_out,
-                                              ZOOM_options_get(c->options, "implementationVersion"),
-                                              odr_prepend(c->odr_out, &version[11], ireq->implementationVersion));
-
+    ireq->implementationVersion = 
+        odr_prepend(c->odr_out,
+                    ZOOM_options_get(c->options, "implementationVersion"),
+                    odr_prepend(c->odr_out, &version[11],
+                                ireq->implementationVersion));
+    
     *ireq->maximumRecordSize =
         ZOOM_options_get_int(c->options, "maximumRecordSize", 1024*1024);
     *ireq->preferredMessageSize =
@@ -1293,7 +1319,7 @@ static zoom_ret send_srw(ZOOM_connection c, Z_SRW_PDU *sr)
     }
     else if (c->sru_mode == zoom_sru_soap)
     {
-        yaz_sru_post_encode(gdu->u.HTTP_Request, sr, c->odr_out, c->charset);
+        yaz_sru_soap_encode(gdu->u.HTTP_Request, sr, c->odr_out, c->charset);
     }
     if (!z_GDU(c->odr_out, &gdu, 0, 0))
         return zoom_complete;
@@ -1313,7 +1339,7 @@ static zoom_ret ZOOM_connection_srw_send_search(ZOOM_connection c)
     int *start, *count;
     ZOOM_resultset resultset = 0;
     Z_SRW_PDU *sr = 0;
-    const char *recordPacking = 0;
+    const char *option_val = 0;
 
     if (c->error)                  /* don't continue on error */
         return zoom_complete;
@@ -1381,12 +1407,14 @@ static zoom_ret ZOOM_connection_srw_send_search(ZOOM_connection c)
     sr->u.request->maximumRecords = odr_intdup(
         c->odr_out, resultset->step>0 ? resultset->step : *count);
     sr->u.request->recordSchema = resultset->schema;
-
-    recordPacking = ZOOM_resultset_option_get(resultset, "recordPacking");
-
-    if (recordPacking)
-        sr->u.request->recordPacking = odr_strdup(c->odr_out, recordPacking);
     
+    option_val = ZOOM_resultset_option_get(resultset, "recordPacking");
+    if (option_val)
+        sr->u.request->recordPacking = odr_strdup(c->odr_out, option_val);
+
+    option_val = ZOOM_resultset_option_get(resultset, "extraArgs");
+    if (option_val)
+        sr->extra_args = odr_strdup(c->odr_out, option_val);
     return send_srw(c, sr);
 }
 #else
@@ -2503,15 +2531,9 @@ ZOOM_API(ZOOM_scanset)
 ZOOM_API(ZOOM_scanset)
     ZOOM_connection_scan1(ZOOM_connection c, ZOOM_query q)
 {
-    ZOOM_scanset scan = (ZOOM_scanset) xmalloc(sizeof(*scan));
     char *start;
     char *freeme = 0;
-
-    scan->connection = c;
-    scan->odr = odr_createmem(ODR_DECODE);
-    scan->options = ZOOM_options_create_with_parent(c->options);
-    scan->refcount = 1;
-    scan->scan_response = 0;
+    ZOOM_scanset scan = 0;
 
     /*
      * We need to check the query-type, so we can recognise CQL and
@@ -2520,22 +2542,35 @@ ZOOM_API(ZOOM_scanset)
      * inspection of the ZOOM_query_prefix() and ZOOM_query_cql()
      * functions shows how the structure is set up in each case.
      */
-    if (q->z_query->which == Z_Query_type_1) {
+    if (!q->z_query)
+        return 0;
+    else if (q->z_query->which == Z_Query_type_1) 
+    {
         yaz_log(log_api, "%p ZOOM_connection_scan1 q=%p PQF '%s'",
                 c, q, q->query_string);
         start = q->query_string;
-    } else if (q->z_query->which == Z_Query_type_104) {
+    } 
+    else if (q->z_query->which == Z_Query_type_104)
+    {
         yaz_log(log_api, "%p ZOOM_connection_scan1 q=%p CQL '%s'",
                 c, q, q->query_string);
         start = freeme = cql2pqf(c, q->query_string);
         if (start == 0)
             return 0;
-    } else {
+    } 
+    else
+    {
         yaz_log(YLOG_FATAL, "%p ZOOM_connection_scan1 q=%p unknown type '%s'",
                 c, q, q->query_string);
         abort();
     }
 
+    scan = (ZOOM_scanset) xmalloc(sizeof(*scan));
+    scan->connection = c;
+    scan->odr = odr_createmem(ODR_DECODE);
+    scan->options = ZOOM_options_create_with_parent(c->options);
+    scan->refcount = 1;
+    scan->scan_response = 0;
     scan->termListAndStartPoint =
         p_query_scan(scan->odr, PROTO_Z3950, &scan->attributeSet, start);
     xfree(freeme);
@@ -3405,13 +3440,7 @@ static void recv_apdu(ZOOM_connection c, Z_APDU *apdu)
         break;
     case Z_APDU_close:
         yaz_log(log_api, "%p recv_apdu Close PDU", c);
-        if (c->reconnect_ok)
-        {
-            do_close(c);
-            c->tasks->running = 0;
-            ZOOM_connection_insert_task(c, ZOOM_TASK_CONNECT);
-        }
-        else
+        if (!ZOOM_test_reconnect(c))
         {
             set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, c->host_port);
             do_close(c);
@@ -3591,13 +3620,9 @@ static int do_read(ZOOM_connection c)
         return 0;
     if (r <= 0)
     {
-        if (c->reconnect_ok)
+        if (ZOOM_test_reconnect(c))
         {
-            do_close(c);
-            c->reconnect_ok = 0;
             yaz_log(log_details, "%p do_read reconnect read", c);
-            c->tasks->running = 0;
-            ZOOM_connection_insert_task(c, ZOOM_TASK_CONNECT);
         }
         else
         {
@@ -3654,13 +3679,8 @@ static zoom_ret do_write_ex(ZOOM_connection c, char *buf_out, int len_out)
     if ((r = cs_put(c->cs, buf_out, len_out)) < 0)
     {
         yaz_log(log_details, "%p do_write_ex write failed", c);
-        if (c->reconnect_ok)
+        if (ZOOM_test_reconnect(c))
         {
-            do_close(c);
-            c->reconnect_ok = 0;
-            yaz_log(log_details, "%p do_write_ex reconnect write", c);
-            c->tasks->running = 0;
-            ZOOM_connection_insert_task(c, ZOOM_TASK_CONNECT);
             return zoom_pending;
         }
         if (c->state == STATE_CONNECTING)
@@ -3839,7 +3859,7 @@ ZOOM_API(int)
     return ZOOM_connection_error_x(c, cp, addinfo, 0);
 }
 
-static int ZOOM_connection_do_io(ZOOM_connection c, int mask)
+static void ZOOM_connection_do_io(ZOOM_connection c, int mask)
 {
     ZOOM_Event event = 0;
     int r = cs_look(c->cs);
@@ -3855,10 +3875,7 @@ static int ZOOM_connection_do_io(ZOOM_connection c, int mask)
     }
     else if (r == CS_CONNECT)
     {
-        int ret;
-        event = ZOOM_Event_create(ZOOM_EVENT_CONNECT);
-
-        ret = cs_rcvconnect(c->cs);
+        int ret = ret = cs_rcvconnect(c->cs);
         yaz_log(log_details, "%p ZOOM_connection_do_io "
                 "cs_rcvconnect returned %d", c, ret);
         if (ret == 1)
@@ -3868,10 +3885,10 @@ static int ZOOM_connection_do_io(ZOOM_connection c, int mask)
                 c->mask += ZOOM_SELECT_WRITE;
             if (c->cs->io_pending & CS_WANT_READ)
                 c->mask += ZOOM_SELECT_READ;
-            ZOOM_connection_put_event(c, event);
         }
         else if (ret == 0)
         {
+            event = ZOOM_Event_create(ZOOM_EVENT_CONNECT);
             ZOOM_connection_put_event(c, event);
             get_cert(c);
             if (c->proto == PROTO_Z3950)
@@ -3890,17 +3907,29 @@ static int ZOOM_connection_do_io(ZOOM_connection c, int mask)
         {
             set_ZOOM_error(c, ZOOM_ERROR_CONNECT, c->host_port);
             do_close(c);
-            ZOOM_connection_put_event(c, event);
         }
     }
     else
     {
+        if (mask & ZOOM_SELECT_EXCEPT)
+        {
+            if (ZOOM_test_reconnect(c))
+            {
+                event = ZOOM_Event_create(ZOOM_EVENT_CONNECT);
+                ZOOM_connection_put_event(c, event);
+            }
+            else
+            {
+                set_ZOOM_error(c, ZOOM_ERROR_CONNECTION_LOST, c->host_port);
+                do_close(c);
+            }
+            return;
+        }
         if (mask & ZOOM_SELECT_READ)
             do_read(c);
         if (c->cs && (mask & ZOOM_SELECT_WRITE))
             do_write(c);
     }
-    return 1;
 }
 
 ZOOM_API(int)