Преглед изворни кода

system: BReactor, BConnection: properly handle HUP event so that it is possible to ready any remaining data after a HUP is
received. This happens in particular when reading from a pipe to a child process and the child closes its end of the pipe.

ambrop7 пре 13 година
родитељ
комит
e1a3b6cbe2
5 измењених фајлова са 52 додато и 25 уклоњено
  1. 44 22
      system/BConnection_unix.c
  2. 1 0
      system/BConnection_unix.h
  3. 4 1
      system/BReactor_badvpn.c
  4. 2 1
      system/BReactor_badvpn.h
  5. 1 1
      tuntap/BTap.c

+ 44 - 22
system/BConnection_unix.c

@@ -242,17 +242,19 @@ static void connection_send (BConnection *o)
     ASSERT(o->send.state == SEND_STATE_BUSY)
     
     // limit
-    if (!BReactorLimit_Increment(&o->send.limit)) {
-        // wait for fd
-        o->wait_events |= BREACTOR_WRITE;
-        BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
-        return;
+    if (!o->is_hupd) {
+        if (!BReactorLimit_Increment(&o->send.limit)) {
+            // wait for fd
+            o->wait_events |= BREACTOR_WRITE;
+            BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
+            return;
+        }
     }
     
     // send
     int bytes = write(o->fd, o->send.busy_data, o->send.busy_data_len);
     if (bytes < 0) {
-        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+        if (!o->is_hupd && (errno == EAGAIN || errno == EWOULDBLOCK)) {
             // wait for fd
             o->wait_events |= BREACTOR_WRITE;
             BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
@@ -280,17 +282,19 @@ static void connection_recv (BConnection *o)
     ASSERT(o->recv.state == RECV_STATE_BUSY)
     
     // limit
-    if (!BReactorLimit_Increment(&o->recv.limit)) {
-        // wait for fd
-        o->wait_events |= BREACTOR_READ;
-        BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
-        return;
+    if (!o->is_hupd) {
+        if (!BReactorLimit_Increment(&o->recv.limit)) {
+            // wait for fd
+            o->wait_events |= BREACTOR_READ;
+            BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
+            return;
+        }
     }
     
     // recv
     int bytes = read(o->fd, o->recv.busy_data, o->recv.busy_data_avail);
     if (bytes < 0) {
-        if (errno == EAGAIN || errno == EWOULDBLOCK) {
+        if (!o->is_hupd && (errno == EAGAIN || errno == EWOULDBLOCK)) {
             // wait for fd
             o->wait_events |= BREACTOR_READ;
             BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
@@ -325,6 +329,7 @@ static void connection_fd_handler (BConnection *o, int events)
 {
     DebugObject_Access(&o->d_obj);
     DebugError_AssertNoError(&o->d_err);
+    ASSERT(!o->is_hupd)
     
     // clear handled events
     o->wait_events &= ~events;
@@ -333,12 +338,18 @@ static void connection_fd_handler (BConnection *o, int events)
     int have_send = 0;
     int have_recv = 0;
     
-    if ((events & BREACTOR_WRITE) || ((events & BREACTOR_ERROR) && o->send.state == SEND_STATE_BUSY)) {
+    // if we got a HUP event, stop monitoring the file descriptor
+    if ((events & BREACTOR_HUP)) {
+        BReactor_RemoveFileDescriptor(o->reactor, &o->bfd);
+        o->is_hupd = 1;
+    }
+    
+    if ((events & BREACTOR_WRITE) || ((events & (BREACTOR_ERROR|BREACTOR_HUP)) && o->send.state == SEND_STATE_BUSY)) {
         ASSERT(o->send.state == SEND_STATE_BUSY)
         have_send = 1;
     }
     
-    if ((events & BREACTOR_READ) || ((events & BREACTOR_ERROR) && o->recv.state == RECV_STATE_BUSY)) {
+    if ((events & BREACTOR_READ) || ((events & (BREACTOR_ERROR|BREACTOR_HUP)) && o->recv.state == RECV_STATE_BUSY)) {
         ASSERT(o->recv.state == RECV_STATE_BUSY)
         have_recv = 1;
     }
@@ -357,9 +368,11 @@ static void connection_fd_handler (BConnection *o, int events)
         return;
     }
     
-    BLog(BLOG_ERROR, "fd error event");
-    connection_report_error(o);
-    return;
+    if (!o->is_hupd) {
+        BLog(BLOG_ERROR, "fd error event");
+        connection_report_error(o);
+        return;
+    }
 }
 
 static void connection_send_job_handler (BConnection *o)
@@ -873,6 +886,9 @@ int BConnection_Init (BConnection *o, struct BConnection_source source, BReactor
         } break;
     }
     
+    // set not HUPd
+    o->is_hupd = 0;
+    
     // init BFileDescriptor
     BFileDescriptor_Init(&o->bfd, o->fd, (BFileDescriptor_handler)connection_fd_handler, o);
     if (!BReactor_AddFileDescriptor(o->reactor, &o->bfd)) {
@@ -917,7 +933,9 @@ void BConnection_Free (BConnection *o)
     BReactorLimit_Free(&o->send.limit);
     
     // free BFileDescriptor
-    BReactor_RemoveFileDescriptor(o->reactor, &o->bfd);
+    if (!o->is_hupd) {
+        BReactor_RemoveFileDescriptor(o->reactor, &o->bfd);
+    }
     
     // close fd
     if (o->close_fd) {
@@ -970,8 +988,10 @@ void BConnection_SendAsync_Free (BConnection *o)
     ASSERT(o->send.state == SEND_STATE_READY || o->send.state == SEND_STATE_BUSY)
     
     // update events
-    o->wait_events &= ~BREACTOR_WRITE;
-    BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
+    if (!o->is_hupd) {
+        o->wait_events &= ~BREACTOR_WRITE;
+        BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
+    }
     
     // free job
     BPending_Free(&o->send.job);
@@ -1013,8 +1033,10 @@ void BConnection_RecvAsync_Free (BConnection *o)
     ASSERT(o->recv.state == RECV_STATE_READY || o->recv.state == RECV_STATE_BUSY || o->recv.state == RECV_STATE_INITED_CLOSED)
     
     // update events
-    o->wait_events &= ~BREACTOR_READ;
-    BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
+    if (!o->is_hupd) {
+        o->wait_events &= ~BREACTOR_READ;
+        BReactor_SetFileDescriptorEvents(o->reactor, &o->bfd, o->wait_events);
+    }
     
     // free job
     BPending_Free(&o->recv.job);

+ 1 - 0
system/BConnection_unix.h

@@ -63,6 +63,7 @@ struct BConnection_s {
     BConnection_handler handler;
     int fd;
     int close_fd;
+    int is_hupd;
     BFileDescriptor bfd;
     int wait_events;
     struct {

+ 4 - 1
system/BReactor_badvpn.c

@@ -848,9 +848,12 @@ int BReactor_Exec (BReactor *bsys)
             if ((bfd->waitEvents&BREACTOR_WRITE) && (event->events&EPOLLOUT)) {
                 events |= BREACTOR_WRITE;
             }
-            if ((event->events&EPOLLERR) || (event->events&EPOLLHUP)) {
+            if ((event->events&EPOLLERR)) {
                 events |= BREACTOR_ERROR;
             }
+            if ((event->events&EPOLLHUP)) {
+                events |= BREACTOR_HUP;
+            }
             
             if (!events) {
                 BLog(BLOG_ERROR, "no events detected?");

+ 2 - 1
system/BReactor_badvpn.h

@@ -171,6 +171,7 @@ struct BFileDescriptor_t;
 #define BREACTOR_READ (1 << 0)
 #define BREACTOR_WRITE (1 << 1)
 #define BREACTOR_ERROR (1 << 2)
+#define BREACTOR_HUP (1 << 3)
 
 /**
  * Handler function invoked by the reactor when one or more events are detected.
@@ -181,7 +182,7 @@ struct BFileDescriptor_t;
  *
  * @param user value passed to {@link BFileDescriptor_Init}
  * @param events bitmask composed of a subset of monitored events (BREACTOR_READ, BREACTOR_WRITE),
- *               and possibly the error event (BREACTOR_ERROR).
+ *               and possibly the error event BREACTOR_ERROR and the hang-up event BREACTOR_HUP.
  *               Will be nonzero.
  */
 typedef void (*BFileDescriptor_handler) (void *user, int events);

+ 1 - 1
tuntap/BTap.c

@@ -96,7 +96,7 @@ static void fd_handler (BTap *o, int events)
     DebugObject_Access(&o->d_obj);
     DebugError_AssertNoError(&o->d_err);
     
-    if (events&BREACTOR_ERROR) {
+    if (events&(BREACTOR_ERROR|BREACTOR_HUP)) {
         BLog(BLOG_WARNING, "device fd reports error?");
     }