Reformat: delete trailing whitespace
[yazpp-moved-to-github.git] / src / yaz-pdu-assoc.cpp
index 5a41980..9af1ab7 100644 (file)
@@ -1,16 +1,21 @@
-/*
- * Copyright (c) 1998-2004, Index Data.
+/* This file is part of the yazpp toolkit.
+ * Copyright (C) 1998-2012 Index Data and Mike Taylor
  * See the file LICENSE for details.
- * 
- * $Id: yaz-pdu-assoc.cpp,v 1.43 2005-06-25 15:53:19 adam Exp $
  */
 
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
 #include <assert.h>
 #include <string.h>
 #include <yaz/log.h>
 #include <yaz/tcpip.h>
 
-#include <yaz++/pdu-assoc.h>
+#include <yazpp/pdu-assoc.h>
+
+#if HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
 
 using namespace yazpp_1;
 
@@ -30,6 +35,7 @@ void PDU_Assoc::init(ISocketObservable *socketObservable)
     m_destroyed = 0;
     m_idleTime = 0;
     m_log = YLOG_DEBUG;
+    m_session_is_dead = false;
 }
 
 PDU_Assoc::PDU_Assoc(ISocketObservable *socketObservable)
@@ -38,7 +44,7 @@ PDU_Assoc::PDU_Assoc(ISocketObservable *socketObservable)
 }
 
 PDU_Assoc::PDU_Assoc(ISocketObservable *socketObservable,
-                             COMSTACK cs)
+                     COMSTACK cs)
 {
     init(socketObservable);
     m_cs = cs;
@@ -79,7 +85,7 @@ void PDU_Assoc::socketNotify(int event)
           this, m_state, event);
     if (event & SOCKET_OBSERVE_EXCEPT)
     {
-        close();
+        shutdown();
         m_PDU_Observer->failNotify();
         return;
     }
@@ -95,7 +101,7 @@ void PDU_Assoc::socketNotify(int event)
         {
             yaz_log (m_log, "PDU_Assoc::cs_accept failed");
             m_cs = 0;
-            close();
+            shutdown();
             m_PDU_Observer->failNotify();
         }
         else
@@ -110,7 +116,7 @@ void PDU_Assoc::socketNotify(int event)
                 m_state = Ready;
                 flush_PDU();
             }
-            else  
+            else
             {   // accept still incomplete.
                 yaz_log(m_log, "maskObserver 2");
                 m_socketObservable->maskObserver(this,
@@ -119,11 +125,11 @@ void PDU_Assoc::socketNotify(int event)
         }
         break;
     case Connecting:
-        if (event & SOCKET_OBSERVE_READ && 
+        if (event & SOCKET_OBSERVE_READ &&
             event & SOCKET_OBSERVE_WRITE)
         {
             // For Unix: if both read and write is set, then connect failed.
-            close();
+            shutdown();
             m_PDU_Observer->failNotify();
         }
         else
@@ -154,7 +160,7 @@ void PDU_Assoc::socketNotify(int event)
         {
             int res;
             COMSTACK new_line;
-            
+
             if ((res = cs_listen(m_cs, 0, 0)) == 1)
                 return;
             if (res < 0)
@@ -164,7 +170,7 @@ void PDU_Assoc::socketNotify(int event)
             }
             if (!(new_line = cs_accept(m_cs)))
                 return;
-            /* 1. create socket-manager 
+            /* 1. create socket-manager
                2. create pdu-assoc
                3. create top-level object
                     setup observer for child fileid in pdu-assoc
@@ -199,7 +205,7 @@ void PDU_Assoc::socketNotify(int event)
                 else if (res <= 0)
                 {
                     yaz_log (m_log, "PDU_Assoc::Connection closed by peer");
-                    close();
+                    shutdown();
                     if (m_PDU_Observer)
                         m_PDU_Observer->failNotify(); // problem here..
                     return;
@@ -214,7 +220,7 @@ void PDU_Assoc::socketNotify(int event)
                 PDU_Queue **pq = &m_queue_in;
                 while (*pq)
                     pq = &(*pq)->m_next;
-                
+
                 *pq = new PDU_Queue(m_input_buf, res);
 #else
                 m_PDU_Observer->recv_PDU(m_input_buf, res);
@@ -234,21 +240,31 @@ void PDU_Assoc::socketNotify(int event)
         break;
     case Closed:
         yaz_log (m_log, "CLOSING state=%d event was %d", m_state, event);
-        close();
+        shutdown();
         m_PDU_Observer->failNotify();
         break;
     default:
         yaz_log (m_log, "Unknown state=%d event was %d", m_state, event);
-        close();
+        shutdown();
+        m_PDU_Observer->failNotify();
+    }
+}
+
+void PDU_Assoc::close_session()
+{
+    m_session_is_dead = true;
+    if (!m_queue_out)
+    {
+        shutdown();
         m_PDU_Observer->failNotify();
     }
 }
 
-void PDU_Assoc::close()
+void PDU_Assoc::shutdown()
 {
     PDU_Assoc *ch;
     for (ch = m_children; ch; ch = ch->m_next)
-        ch->close();
+        ch->shutdown();
 
     m_socketObservable->deleteObserver(this);
     m_state = Closed;
@@ -271,7 +287,7 @@ void PDU_Assoc::close()
 
 void PDU_Assoc::destroy()
 {
-    close();
+    shutdown();
 
     if (m_destroyed)
         *m_destroyed = 1;
@@ -316,7 +332,7 @@ PDU_Assoc::PDU_Queue::~PDU_Queue()
 int PDU_Assoc::flush_PDU()
 {
     int r;
-    
+
     if (m_state != Ready && m_state != Writing)
     {
         yaz_log (m_log, "YAZ_PDU_Assoc::flush_PDU, not ready");
@@ -331,13 +347,18 @@ int PDU_Assoc::flush_PDU()
         m_socketObservable->maskObserver(this, SOCKET_OBSERVE_READ|
                                          SOCKET_OBSERVE_WRITE|
                                          SOCKET_OBSERVE_EXCEPT);
+        if (m_session_is_dead)
+        {
+            shutdown();
+            m_PDU_Observer->failNotify();
+        }
         return 0;
     }
     r = cs_put (m_cs, q->m_buf, q->m_len);
     if (r < 0)
     {
         yaz_log (m_log, "PDU_Assoc::flush_PDU cs_put failed");
-        close();
+        shutdown();
         m_PDU_Observer->failNotify();
         return r;
     }
@@ -356,7 +377,7 @@ int PDU_Assoc::flush_PDU()
         yaz_log (m_log, "PDU_Assoc::flush_PDU cs_put %d bytes fd=%d (inc)",
                  q->m_len, cs_fileno(m_cs));
         return r;
-    } 
+    }
     yaz_log (m_log, "PDU_Assoc::flush_PDU cs_put %d bytes", q->m_len);
     // whole packet sent... delete this and proceed to next ...
     m_queue_out = q->m_next;
@@ -368,6 +389,8 @@ int PDU_Assoc::flush_PDU()
         yaz_log(m_log, "maskObserver 8");
         m_socketObservable->maskObserver(this, SOCKET_OBSERVE_READ|
                                          SOCKET_OBSERVE_EXCEPT);
+        if (m_session_is_dead)
+            shutdown();
     }
     return r;
 }
@@ -377,7 +400,7 @@ int PDU_Assoc::send_PDU(const char *buf, int len)
     yaz_log (m_log, "PDU_Assoc::send_PDU");
     PDU_Queue **pq = &m_queue_out;
     int is_idle = (*pq ? 0 : 1);
-    
+
     if (!m_cs)
     {
         yaz_log (m_log, "PDU_Assoc::send_PDU failed, m_cs == 0");
@@ -401,7 +424,30 @@ COMSTACK PDU_Assoc::comstack(const char *type_and_host, void **vp)
 
 int PDU_Assoc::listen(IPDU_Observer *observer, const char *addr)
 {
-    close();
+    if (*addr == '\0')
+    {
+        m_socketObservable->deleteObserver(this);
+        m_state = Closed;
+        if (m_cs)
+        {
+            yaz_log (m_log, "PDU_Assoc::close fd=%d", cs_fileno(m_cs));
+            cs_close (m_cs);
+        }
+        m_cs = 0;
+        while (m_queue_out)
+        {
+            PDU_Queue *q_this = m_queue_out;
+            m_queue_out = m_queue_out->m_next;
+            delete q_this;
+        }
+        xfree (m_input_buf);
+        m_input_buf = 0;
+        m_input_len = 0;
+
+        return 0;
+    }
+
+    shutdown();
 
     m_PDU_Observer = observer;
     void *ap;
@@ -411,11 +457,21 @@ int PDU_Assoc::listen(IPDU_Observer *observer, const char *addr)
         return -1;
     if (cs_bind(m_cs, ap, CS_SERVER) < 0)
         return -2;
-    m_socketObservable->addObserver(cs_fileno(m_cs), this);
+
+    int fd = cs_fileno(m_cs);
+#if HAVE_FCNTL_H
+    int oldflags = fcntl(fd, F_GETFD, 0);
+    if (oldflags >= 0)
+    {
+        oldflags |= FD_CLOEXEC;
+        fcntl(fd, F_SETFD, oldflags);
+    }
+#endif
+    m_socketObservable->addObserver(fd, this);
     yaz_log(m_log, "maskObserver 9");
     m_socketObservable->maskObserver(this, SOCKET_OBSERVE_READ|
                                      SOCKET_OBSERVE_EXCEPT);
-    yaz_log (m_log, "PDU_Assoc::listen ok fd=%d", cs_fileno(m_cs));
+    yaz_log (m_log, "PDU_Assoc::listen ok fd=%d", fd);
     m_state = Listen;
     return 0;
 }
@@ -430,7 +486,7 @@ void PDU_Assoc::idleTime(int idleTime)
 int PDU_Assoc::connect(IPDU_Observer *observer, const char *addr)
 {
     yaz_log (m_log, "PDU_Assoc::connect %s", addr);
-    close();
+    shutdown();
     m_PDU_Observer = observer;
     void *ap;
     m_cs = comstack(addr, &ap);
@@ -477,14 +533,20 @@ void PDU_Assoc::childNotify(COMSTACK cs)
 {
     PDU_Assoc *new_observable =
         new PDU_Assoc (m_socketObservable, cs);
-    
-    new_observable->m_next = m_children;
-    m_children = new_observable;
-    new_observable->m_parent = this;
 
     // Clone PDU Observer
     new_observable->m_PDU_Observer = m_PDU_Observer->sessionNotify
         (new_observable, cs_fileno(cs));
+
+    if (!new_observable->m_PDU_Observer)
+    {
+        new_observable->shutdown();
+        delete new_observable;
+        return;
+    }
+    new_observable->m_next = m_children;
+    m_children = new_observable;
+    new_observable->m_parent = this;
 }
 
 const char*PDU_Assoc::getpeername()
@@ -496,6 +558,7 @@ const char*PDU_Assoc::getpeername()
 /*
  * Local variables:
  * c-basic-offset: 4
+ * c-file-style: "Stroustrup"
  * indent-tabs-mode: nil
  * End:
  * vim: shiftwidth=4 tabstop=8 expandtab