Avoid possible one-byte overrun in ioset_line_read().
[srvx.git] / src / ioset.c
index 444579e9c46d7fb84d58eb75a65f047096a3f1f6..9cf1c433fe78ce20f029336ca9d2a000e7fa30dc 100644 (file)
@@ -142,10 +142,17 @@ ioset_add(int fd) {
     res->fd = fd;
     ioq_init(&res->send, 1024);
     ioq_init(&res->recv, 1024);
+#if defined(F_GETFL)
     flags = fcntl(fd, F_GETFL);
     fcntl(fd, F_SETFL, flags|O_NONBLOCK);
     flags = fcntl(fd, F_GETFD);
     fcntl(fd, F_SETFD, flags|FD_CLOEXEC);
+#else
+    /* I hope you're using the Win32 backend or something else that
+     * automatically marks the file descriptor non-blocking...
+     */
+    (void)flags;
+#endif
     engine->add(res);
     return res;
 }
@@ -259,7 +266,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;
         }
     }
@@ -308,6 +314,20 @@ ioset_close(struct io_fd *fdp, int os_close) {
         active_fd = NULL;
     if (fdp->destroy_cb)
         fdp->destroy_cb(fdp);
+#if defined(HAVE_WSAEVENTSELECT)
+    /* This is one huge kludge.  Sorry! */
+    if (fdp->send.get != fdp->send.put && (os_close & 2)) {
+        engine->remove(fdp, 0);
+        ioset_try_write(fdp);
+        /* it may need to send the beginning of the buffer now.. */
+        if (fdp->send.get != fdp->send.put)
+            ioset_try_write(fdp);
+    }
+    free(fdp->send.buf);
+    free(fdp->recv.buf);
+    if (os_close & 1)
+        closesocket(fdp->fd);
+#else
     if (fdp->send.get != fdp->send.put && (os_close & 2)) {
         int flags;
 
@@ -322,7 +342,8 @@ ioset_close(struct io_fd *fdp, int os_close) {
     free(fdp->recv.buf);
     if (os_close & 1)
         close(fdp->fd);
-    engine->remove(fdp);
+    engine->remove(fdp, os_close & 1);
+#endif
     free(fdp);
 }
 
@@ -431,18 +452,21 @@ ioset_buffered_read(struct io_fd *fd) {
 
 int
 ioset_line_read(struct io_fd *fd, char *dest, int max) {
-    int avail, done;
-    if ((fd->state == IO_CLOSED) && (!ioq_get_avail(&fd->recv) ||  (fd->line_len < 0)))
+    int line_len;
+    int avail;
+    int done;
+
+    line_len = fd->line_len;
+    if ((fd->state == IO_CLOSED) && (!ioq_get_avail(&fd->recv) ||  (line_len < 0)))
         return 0;
-    if (fd->line_len < 0)
+    if (line_len < 0)
         return -1;
-    if (fd->line_len < max)
-        max = fd->line_len;
+    if (line_len < max)
+        max = line_len;
     avail = ioq_get_avail(&fd->recv);
     if (max > avail) {
         memcpy(dest, fd->recv.buf + fd->recv.get, avail);
-        fd->recv.get += avail;
-        assert(fd->recv.get == fd->recv.size);
+        assert(fd->recv.get + avail == fd->recv.size);
         fd->recv.get = 0;
         done = avail;
     } else {
@@ -452,9 +476,9 @@ ioset_line_read(struct io_fd *fd, char *dest, int max) {
     fd->recv.get += max - done;
     if (fd->recv.get == fd->recv.size)
         fd->recv.get = 0;
-    dest[max] = 0;
+    dest[max - 1] = 0;
     ioset_find_line_length(fd);
-    return max;
+    return line_len;
 }
 
 void