Added GFS utility function bend_assoc_is_alive which returns 1 if
authorAdam Dickmeiss <adam@indexdata.dk>
Mon, 4 Dec 2006 14:56:54 +0000 (14:56 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Mon, 4 Dec 2006 14:56:54 +0000 (14:56 +0000)
association is still alive (client is connected); 0 otherwise (client
closed connection). This allows busy servers to stop working for
impatient clients.

NEWS
include/yaz/backend.h
src/eventl.c
src/eventl.h
src/seshigh.c
src/session.h
ztest/ztest.c

diff --git a/NEWS b/NEWS
index 34d01f1..e64545b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+Added GFS utility function bend_assoc_is_alive which returns 1 if
+association is still alive (client is connected); 0 otherwise (client
+closed connection). This allows busy servers to stop working for
+impatient clients.
+
 Fixed bug #740: Handle SRU records referring to xmlns's outside recordData.
 
 --- 2.1.40 2006/11/27
index 39c4c67..ff0b15d 100644 (file)
@@ -24,7 +24,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-/* $Id: backend.h,v 1.38 2006-10-09 21:02:41 adam Exp $ */
+/* $Id: backend.h,v 1.39 2006-12-04 14:56:54 adam Exp $ */
 
 /** 
  * \file backend.h
@@ -329,6 +329,7 @@ YAZ_EXPORT statserv_options_block *statserv_getcontrol(void);
 YAZ_EXPORT void statserv_setcontrol(statserv_options_block *block);
 YAZ_EXPORT int check_ip_tcpd(void *cd, const char *addr, int len, int type);
 
+YAZ_EXPORT int bend_assoc_is_alive(bend_association assoc);
 
 YAZ_END_CDECL
 
index 2392cc8..2fcac05 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: eventl.c,v 1.9 2005-06-25 15:46:04 adam Exp $
+ * $Id: eventl.c,v 1.10 2006-12-04 14:56:55 adam Exp $
  */
 
 /**
@@ -78,6 +78,31 @@ IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags, int chan_id)
     return new_iochan;
 }
 
+int iochan_is_alive(IOCHAN chan)
+{
+    static struct timeval to;
+    fd_set in, out, except;
+    int res, max;
+
+    to.tv_sec = 0;
+    to.tv_usec = 0;
+
+    FD_ZERO(&in);
+    FD_ZERO(&out);
+    FD_ZERO(&except);
+
+    FD_SET(chan->fd, &in);
+
+    max = chan->fd + 1;
+
+    res = YAZ_EV_SELECT(max + 1, &in, 0, 0, &to);
+    if (res == 0)
+        return 1;
+    if (!ir_read(chan, EVENT_INPUT))
+        return 0;
+    return 1;
+}
+
 int event_loop(IOCHAN *iochans)
 {
     do /* loop as long as there are active associations to process */
index a11fe47..099d764 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: eventl.h,v 1.6 2005-06-25 15:46:04 adam Exp $
+ * $Id: eventl.h,v 1.7 2006-12-04 14:56:55 adam Exp $
  */
 
 /**
@@ -30,7 +30,6 @@ typedef struct iochan
 #define EVENT_OUTPUT    0x02
 #define EVENT_EXCEPT    0x04
 #define EVENT_TIMEOUT   0x08
-#define EVENT_WORK      0x10
 int force_event;
     IOC_CALLBACK fun;
     void *data;
@@ -59,6 +58,7 @@ int force_event;
 #define iochan_settimeout(i, t) ((i)->max_idle = (t), (i)->last_event = time(0))
 
 IOCHAN iochan_create(int fd, IOC_CALLBACK cb, int flags, int port);
+int iochan_is_alive(IOCHAN chan);
 int event_loop(IOCHAN *iochans);
 void statserv_remove (IOCHAN pIOChannel);
 #endif
index 28830c2..e29973e 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * Copyright (C) 1995-2005, Index Data ApS
+ * Copyright (C) 1995-2006, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: seshigh.c,v 1.104 2006-11-14 08:37:38 adam Exp $
+ * $Id: seshigh.c,v 1.105 2006-12-04 14:56:55 adam Exp $
  */
 /**
  * \file seshigh.c
@@ -264,83 +264,31 @@ static void do_close(association *a, int reason, char *message)
     do_close_req (a, reason, message, req);
 }
 
-/*
- * This is where PDUs from the client are read and the further
- * processing is initiated. Flow of control moves down through the
- * various process_* functions below, until the encoded result comes back up
- * to the output handler in here.
- * 
- *  h     : the I/O channel that has an outstanding event.
- *  event : the current outstanding event.
- */
-void ir_session(IOCHAN h, int event)
+
+int ir_read(IOCHAN h, int event)
 {
-    int res;
     association *assoc = (association *)iochan_getdata(h);
     COMSTACK conn = assoc->client_link;
     request *req;
-
-    assert(h && conn && assoc);
-    if (event == EVENT_TIMEOUT)
+    
+    if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
     {
-        if (assoc->state != ASSOC_UP)
+        yaz_log(YLOG_DEBUG, "ir_session (input)");
+        /* We aren't speaking to this fellow */
+        if (assoc->state == ASSOC_DEAD)
         {
-            yaz_log(YLOG_DEBUG, "Final timeout - closing connection.");
-            /* do we need to lod this at all */
+            yaz_log(log_sessiondetail, "Connection closed - end of session");
             cs_close(conn);
             destroy_association(assoc);
             iochan_destroy(h);
+            return 0;
         }
-        else
-        {
-            yaz_log(log_sessiondetail, 
-                    "Session idle too long. Sending close.");
-            do_close(assoc, Z_Close_lackOfActivity, 0);
-        }
-        return;
-    }
-    if (event & assoc->cs_accept_mask)
-    {
-        if (!cs_accept (conn))
-        {
-            yaz_log (YLOG_WARN, "accept failed");
-            destroy_association(assoc);
-            iochan_destroy(h);
-        }
-        iochan_clearflag (h, EVENT_OUTPUT);
-        if (conn->io_pending) 
-        {   /* cs_accept didn't complete */
-            assoc->cs_accept_mask = 
-                ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
-                ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
+        assoc->cs_get_mask = EVENT_INPUT;
 
-            iochan_setflag (h, assoc->cs_accept_mask);
-        }
-        else
-        {   /* cs_accept completed. Prepare for reading (cs_get) */
-            assoc->cs_accept_mask = 0;
-            assoc->cs_get_mask = EVENT_INPUT;
-            iochan_setflag (h, assoc->cs_get_mask);
-        }
-        return;
-    }
-    if ((event & assoc->cs_get_mask) || (event & EVENT_WORK)) /* input */
-    {
-        if ((assoc->cs_put_mask & EVENT_INPUT) == 0 && (event & assoc->cs_get_mask))
+        do
         {
-            yaz_log(YLOG_DEBUG, "ir_session (input)");
-            /* We aren't speaking to this fellow */
-            if (assoc->state == ASSOC_DEAD)
-            {
-                yaz_log(log_sessiondetail, "Connection closed - end of session");
-                cs_close(conn);
-                destroy_association(assoc);
-                iochan_destroy(h);
-                return;
-            }
-            assoc->cs_get_mask = EVENT_INPUT;
-            res = cs_get(conn, &assoc->input_buffer,
-                &assoc->input_buffer_len);
+            int res = cs_get(conn, &assoc->input_buffer,
+                             &assoc->input_buffer_len);
             if (res < 0 && cs_errno(conn) == CSBUFSIZE)
             {
                 yaz_log(log_session, "Connection error: %s res=%d",
@@ -348,31 +296,26 @@ void ir_session(IOCHAN h, int event)
                 req = request_get(&assoc->incoming); /* get a new request */
                 do_close_req(assoc, Z_Close_protocolError, 
                              "Incoming package too large", req);
-                return;
+                return 0;
             }
             else if (res <= 0)
             {
-                yaz_log(log_sessiondetail, "Connection closed by client");
-                cs_close(conn);
-                destroy_association(assoc);
-                iochan_destroy(h);
-                return;
+                yaz_log(log_session, "Connection closed by client");
+                assoc->state = ASSOC_DEAD;
+                return 0;
             }
             else if (res == 1) /* incomplete read - wait for more  */
             {
                 if (conn->io_pending & CS_WANT_WRITE)
                     assoc->cs_get_mask |= EVENT_OUTPUT;
                 iochan_setflag(h, assoc->cs_get_mask);
-                return;
+                return 1;
             }
-            if (cs_more(conn)) /* more stuff - call us again later, please */
-                iochan_setevent(h, EVENT_INPUT);
-                
             /* we got a complete PDU. Let's decode it */
             yaz_log(YLOG_DEBUG, "Got PDU, %d bytes: lead=%02X %02X %02X", res,
-                            assoc->input_buffer[0] & 0xff,
-                            assoc->input_buffer[1] & 0xff,
-                            assoc->input_buffer[2] & 0xff);
+                    assoc->input_buffer[0] & 0xff,
+                    assoc->input_buffer[1] & 0xff,
+                    assoc->input_buffer[2] & 0xff);
             req = request_get(&assoc->incoming); /* get a new request */
             odr_reset(assoc->decode);
             odr_setbuf(assoc->decode, assoc->input_buffer, res, 0);
@@ -396,20 +339,87 @@ void ir_session(IOCHAN h, int event)
                     assoc->state = ASSOC_DEAD;
                     process_gdu_response(assoc, req, p);
                 }
-                return;
+                return 0;
             }
             req->request_mem = odr_extract_mem(assoc->decode);
             if (assoc->print) 
             {
                 if (!z_GDU(assoc->print, &req->gdu_request, 0, 0))
                     yaz_log(YLOG_WARN, "ODR print error: %s", 
-                       odr_errmsg(odr_geterror(assoc->print)));
+                            odr_errmsg(odr_geterror(assoc->print)));
                 odr_reset(assoc->print);
             }
             request_enq(&assoc->incoming, req);
         }
+        while (cs_more(conn));
+    }
+    return 1;
+}
+
+/*
+ * This is where PDUs from the client are read and the further
+ * processing is initiated. Flow of control moves down through the
+ * various process_* functions below, until the encoded result comes back up
+ * to the output handler in here.
+ * 
+ *  h     : the I/O channel that has an outstanding event.
+ *  event : the current outstanding event.
+ */
+void ir_session(IOCHAN h, int event)
+{
+    int res;
+    association *assoc = (association *)iochan_getdata(h);
+    COMSTACK conn = assoc->client_link;
+    request *req;
+
+    assert(h && conn && assoc);
+    if (event == EVENT_TIMEOUT)
+    {
+        if (assoc->state != ASSOC_UP)
+        {
+            yaz_log(YLOG_DEBUG, "Final timeout - closing connection.");
+            /* do we need to lod this at all */
+            cs_close(conn);
+            destroy_association(assoc);
+            iochan_destroy(h);
+        }
+        else
+        {
+            yaz_log(log_sessiondetail, 
+                    "Session idle too long. Sending close.");
+            do_close(assoc, Z_Close_lackOfActivity, 0);
+        }
+        return;
+    }
+    if (event & assoc->cs_accept_mask)
+    {
+        if (!cs_accept (conn))
+        {
+            yaz_log (YLOG_WARN, "accept failed");
+            destroy_association(assoc);
+            iochan_destroy(h);
+        }
+        iochan_clearflag (h, EVENT_OUTPUT);
+        if (conn->io_pending) 
+        {   /* cs_accept didn't complete */
+            assoc->cs_accept_mask = 
+                ((conn->io_pending & CS_WANT_WRITE) ? EVENT_OUTPUT : 0) |
+                ((conn->io_pending & CS_WANT_READ) ? EVENT_INPUT : 0);
 
-        /* can we do something yet? */
+            iochan_setflag (h, assoc->cs_accept_mask);
+        }
+        else
+        {   /* cs_accept completed. Prepare for reading (cs_get) */
+            assoc->cs_accept_mask = 0;
+            assoc->cs_get_mask = EVENT_INPUT;
+            iochan_setflag (h, assoc->cs_get_mask);
+        }
+        return;
+    }
+    if (event & assoc->cs_get_mask) /* input */
+    {
+        if (!ir_read(h, event))
+            return;
         req = request_head(&assoc->incoming);
         if (req->state == REQUEST_IDLE)
         {
@@ -2116,13 +2126,18 @@ static int process_gdu_response(association *assoc, request *req, Z_GDU *res)
     iochan_setflag(assoc->client_chan, EVENT_OUTPUT);
     assoc->cs_put_mask = EVENT_OUTPUT;
     /* Is there more work to be done? give that to the input handler too */
-#if 1
-    if (request_head(&assoc->incoming))
+    for (;;)
     {
-        yaz_log (YLOG_DEBUG, "more work to be done");
-        iochan_setevent(assoc->client_chan, EVENT_WORK);
+        req = request_head(&assoc->incoming);
+        if (req && req->state == REQUEST_IDLE)
+        {
+            yaz_log(YLOG_LOG, "process next request 3");
+            request_deq(&assoc->incoming);
+            process_gdu_request(assoc, req);
+        }
+        else
+            break;
     }
-#endif
     return 0;
 }
 
@@ -2334,7 +2349,7 @@ static Z_APDU *process_initRequest(association *assoc, request *reqb)
                 assoc->init->implementation_name,
                 odr_prepend(assoc->encode, "GFS", resp->implementationName));
 
-    version = odr_strdup(assoc->encode, "$Revision: 1.104 $");
+    version = odr_strdup(assoc->encode, "$Revision: 1.105 $");
     if (strlen(version) > 10)   /* check for unexpanded CVS strings */
         version[strlen(version)-2] = '\0';
     resp->implementationVersion = odr_prepend(assoc->encode,
@@ -3510,6 +3525,15 @@ static Z_APDU *process_ESRequest(association *assoc, request *reqb, int *fd)
     return apdu;
 }
 
+int bend_assoc_is_alive(bend_association assoc)
+{
+    if (assoc->state == ASSOC_DEAD)
+        return 0; /* already marked as dead. Don't check I/O chan anymore */
+
+    return iochan_is_alive(assoc->client_chan);
+}
+
+
 /*
  * Local variables:
  * c-basic-offset: 4
index 6ac5299..b63d2cf 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2006, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: session.h,v 1.11 2006-05-07 14:48:25 adam Exp $
+ * $Id: session.h,v 1.12 2006-12-04 14:56:55 adam Exp $
  */
 /**
  * \file session.h
@@ -133,6 +133,8 @@ int statserv_must_terminate(void);
 
 int control_association(association *assoc, const char *host, int force);
 
+int ir_read(IOCHAN h, int event);
+
 #endif
 /*
  * Local variables:
index 51ead41..515d1ac 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (C) 1995-2005, Index Data ApS
  * See the file LICENSE for details.
  *
- * $Id: ztest.c,v 1.81 2006-05-06 00:52:15 quinn Exp $
+ * $Id: ztest.c,v 1.82 2006-12-04 14:56:55 adam Exp $
  */
 
 /*
@@ -54,7 +54,17 @@ int ztest_search(void *handle, bend_search_rr *rr)
     else if(!yaz_matchstr (rr->basenames[0], "Slow"))
     {
 #if HAVE_UNISTD_H
-        sleep(3);
+        /* wait up to 3 seconds and check if connection is still alive */
+        int i;
+        for (i = 0; i<3; i++)
+        {
+            if (!bend_assoc_is_alive(rr->association))
+            {
+                yaz_log(YLOG_LOG, "search aborted");
+                break;
+            }
+            sleep(1);
+        }
 #endif
         ;
     }