Remove ioset engine update call that could read after free().
[srvx.git] / src / ioset.c
index a66af6f8b8fbb8badf2db3e20f71fbf4c98693d2..a199275f1d3fa2c87196a53dc006421de5623902 100644 (file)
@@ -93,7 +93,8 @@ extern struct io_engine io_engine_select;
 void
 ioset_init(void)
 {
-    assert(engine == NULL);
+    if (engine) /* someone beat us to it */
+        return;
 
 #if WITH_IOSET_KQUEUE
     if (!engine && io_engine_kqueue.init())
@@ -133,15 +134,19 @@ ioset_add(int fd) {
         log_module(MAIN_LOG, LOG_ERROR, "Somebody called ioset_add(%d) on a negative fd!", fd);
         return 0;
     }
+    if (!engine)
+        ioset_init();
     res = calloc(1, sizeof(*res));
     if (!res)
         return 0;
     res->fd = fd;
     ioq_init(&res->send, 1024);
     ioq_init(&res->recv, 1024);
-    engine->add(res);
     flags = fcntl(fd, F_GETFL);
     fcntl(fd, F_SETFL, flags|O_NONBLOCK);
+    flags = fcntl(fd, F_GETFD);
+    fcntl(fd, F_SETFD, flags|FD_CLOEXEC);
+    engine->add(res);
     return res;
 }
 
@@ -254,7 +259,6 @@ ioset_connect(struct sockaddr *local, unsigned int sa_size, const char *peer, un
         case EHOSTUNREACH:
         case ECONNREFUSED:
             ioset_close(io_fd, 1);
-            engine->update(io_fd);
             return NULL;
         }
     }
@@ -269,10 +273,16 @@ ioset_connect(struct sockaddr *local, unsigned int sa_size, const char *peer, un
     return io_fd;
 }
 
+void ioset_update(struct io_fd *fd) {
+    engine->update(fd);
+}
+
 static void
 ioset_try_write(struct io_fd *fd) {
     int res;
-    unsigned int req = ioq_get_avail(&fd->send);
+    unsigned int req;
+
+    req = ioq_get_avail(&fd->send);
     res = write(fd->fd, fd->send.buf+fd->send.get, req);
     if (res < 0) {
         switch (errno) {
@@ -297,7 +307,7 @@ ioset_close(struct io_fd *fdp, int os_close) {
         active_fd = NULL;
     if (fdp->destroy_cb)
         fdp->destroy_cb(fdp);
-    if (fdp->send.get != fdp->send.put) {
+    if (fdp->send.get != fdp->send.put && (os_close & 2)) {
         int flags;
 
        flags = fcntl(fdp->fd, F_GETFL);
@@ -309,7 +319,7 @@ ioset_close(struct io_fd *fdp, int os_close) {
     }
     free(fdp->send.buf);
     free(fdp->recv.buf);
-    if (os_close)
+    if (os_close & 1)
         close(fdp->fd);
     engine->remove(fdp);
     free(fdp);
@@ -399,7 +409,7 @@ ioset_buffered_read(struct io_fd *fd) {
         if (fd->recv.put == fd->recv.size)
             fd->recv.put = 0;
         fdnum = fd->fd;
-        while (fd->wants_reads && (fd->line_len > 0)) {
+        while (fd->line_len > 0) {
             struct io_fd *old_active;
             int died = 0;