Blame SOURCES/0000-Refactor-cm-functions-in-sendto_kdc.c.patch

4be148
Tweaked a bit to apply to 1.12:
4be148
* krb5_int64 hadn't been replaced by int64_t yet.
4be148
4be148
commit 346883c48f1b9e09b1af2cf73e3b96ee8f934072
4be148
Author: Greg Hudson <ghudson@mit.edu>
4be148
Date:   Wed Mar 26 13:21:45 2014 -0400
4be148
4be148
    Refactor cm functions in sendto_kdc.c
4be148
    
4be148
    Move get_curtime_ms and the cm functions near the top of the file
4be148
    right after structure definitions.  Except for cm_select_or_poll,
4be148
    define each cm function separately for poll and for select, since the
4be148
    implementations don't share much in common.  Instead of
4be148
    cm_unset_write, define cm_read and cm_write functions to put an fd in
4be148
    read-only or write-only state.  Remove the ssflags argument from
4be148
    cm_add_fd and just expect the caller to make a subsequent call to
4be148
    cm_read or cm_write.  Always select for exceptions when using select.
4be148
    (Polling for exceptions is implicit with poll).
4be148
    
4be148
    With these changes, we no longer select/poll for reading on a TCP
4be148
    connection until we are done writing to it.  So in service_tcp_fd,
4be148
    remove the check for unexpected read events.
4be148
4be148
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
4be148
index e60a375..e773a0a 100644
4be148
--- a/src/lib/krb5/os/sendto_kdc.c
4be148
+++ b/src/lib/krb5/os/sendto_kdc.c
4be148
@@ -59,8 +59,7 @@
4be148
 
4be148
 typedef krb5_int64 time_ms;
4be148
 
4be148
-/* Since fd_set is large on some platforms (8K on AIX 5.2), this probably
4be148
- * shouldn't be allocated in automatic storage. */
4be148
+/* This can be pretty large, so should not be stack-allocated. */
4be148
 struct select_state {
4be148
 #ifdef USE_POLL
4be148
     struct pollfd fds[MAX_POLLFDS];
4be148
@@ -107,6 +106,183 @@ struct conn_state {
4be148
     time_ms endtime;
4be148
 };
4be148
 
4be148
+/* Get current time in milliseconds. */
4be148
+static krb5_error_code
4be148
+get_curtime_ms(time_ms *time_out)
4be148
+{
4be148
+    struct timeval tv;
4be148
+
4be148
+    if (gettimeofday(&tv, 0))
4be148
+        return errno;
4be148
+    *time_out = (time_ms)tv.tv_sec * 1000 + tv.tv_usec / 1000;
4be148
+    return 0;
4be148
+}
4be148
+
4be148
+#ifdef USE_POLL
4be148
+
4be148
+/* Find a pollfd in selstate by fd, or abort if we can't find it. */
4be148
+static inline struct pollfd *
4be148
+find_pollfd(struct select_state *selstate, int fd)
4be148
+{
4be148
+    int i;
4be148
+
4be148
+    for (i = 0; i < selstate->nfds; i++) {
4be148
+        if (selstate->fds[i].fd == fd)
4be148
+            return &selstate->fds[i];
4be148
+    }
4be148
+    abort();
4be148
+}
4be148
+
4be148
+static void
4be148
+cm_init_selstate(struct select_state *selstate)
4be148
+{
4be148
+    selstate->nfds = 0;
4be148
+}
4be148
+
4be148
+static krb5_boolean
4be148
+cm_add_fd(struct select_state *selstate, int fd)
4be148
+{
4be148
+    if (selstate->nfds >= MAX_POLLFDS)
4be148
+        return FALSE;
4be148
+    selstate->fds[selstate->nfds].fd = fd;
4be148
+    selstate->fds[selstate->nfds].events = 0;
4be148
+    selstate->nfds++;
4be148
+    return TRUE;
4be148
+}
4be148
+
4be148
+static void
4be148
+cm_remove_fd(struct select_state *selstate, int fd)
4be148
+{
4be148
+    struct pollfd *pfd = find_pollfd(selstate, fd);
4be148
+
4be148
+    *pfd = selstate->fds[selstate->nfds - 1];
4be148
+    selstate->nfds--;
4be148
+}
4be148
+
4be148
+/* Poll for reading (and not writing) on fd the next time we poll. */
4be148
+static void
4be148
+cm_read(struct select_state *selstate, int fd)
4be148
+{
4be148
+    find_pollfd(selstate, fd)->events = POLLIN;
4be148
+}
4be148
+
4be148
+/* Poll for writing (and not reading) on fd the next time we poll. */
4be148
+static void
4be148
+cm_write(struct select_state *selstate, int fd)
4be148
+{
4be148
+    find_pollfd(selstate, fd)->events = POLLOUT;
4be148
+}
4be148
+
4be148
+/* Get the output events for fd in the form of ssflags. */
4be148
+static unsigned int
4be148
+cm_get_ssflags(struct select_state *selstate, int fd)
4be148
+{
4be148
+    struct pollfd *pfd = find_pollfd(selstate, fd);
4be148
+
4be148
+    return ((pfd->revents & POLLIN) ? SSF_READ : 0) |
4be148
+        ((pfd->revents & POLLOUT) ? SSF_WRITE : 0) |
4be148
+        ((pfd->revents & POLLERR) ? SSF_EXCEPTION : 0);
4be148
+}
4be148
+
4be148
+#else /* not USE_POLL */
4be148
+
4be148
+static void
4be148
+cm_init_selstate(struct select_state *selstate)
4be148
+{
4be148
+    selstate->nfds = 0;
4be148
+    selstate->max = 0;
4be148
+    FD_ZERO(&selstate->rfds);
4be148
+    FD_ZERO(&selstate->wfds);
4be148
+    FD_ZERO(&selstate->xfds);
4be148
+}
4be148
+
4be148
+static krb5_boolean
4be148
+cm_add_fd(struct select_state *selstate, int fd)
4be148
+{
4be148
+#ifndef _WIN32  /* On Windows FD_SETSIZE is a count, not a max value. */
4be148
+    if (fd >= FD_SETSIZE)
4be148
+        return FALSE;
4be148
+#endif
4be148
+    FD_SET(fd, &selstate->xfds);
4be148
+    if (selstate->max <= fd)
4be148
+        selstate->max = fd + 1;
4be148
+    selstate->nfds++;
4be148
+    return TRUE;
4be148
+}
4be148
+
4be148
+static void
4be148
+cm_remove_fd(struct select_state *selstate, int fd)
4be148
+{
4be148
+    FD_CLR(fd, &selstate->rfds);
4be148
+    FD_CLR(fd, &selstate->wfds);
4be148
+    FD_CLR(fd, &selstate->xfds);
4be148
+    if (selstate->max == fd + 1) {
4be148
+        while (selstate->max > 0 &&
4be148
+               !FD_ISSET(selstate->max - 1, &selstate->rfds) &&
4be148
+               !FD_ISSET(selstate->max - 1, &selstate->wfds) &&
4be148
+               !FD_ISSET(selstate->max - 1, &selstate->xfds))
4be148
+            selstate->max--;
4be148
+    }
4be148
+    selstate->nfds--;
4be148
+}
4be148
+
4be148
+/* Select for reading (and not writing) on fd the next time we select. */
4be148
+static void
4be148
+cm_read(struct select_state *selstate, int fd)
4be148
+{
4be148
+    FD_SET(fd, &selstate->rfds);
4be148
+    FD_CLR(fd, &selstate->wfds);
4be148
+}
4be148
+
4be148
+/* Select for writing (and not reading) on fd the next time we select. */
4be148
+static void
4be148
+cm_write(struct select_state *selstate, int fd)
4be148
+{
4be148
+    FD_CLR(fd, &selstate->rfds);
4be148
+    FD_SET(fd, &selstate->wfds);
4be148
+}
4be148
+
4be148
+/* Get the events for fd from selstate after a select. */
4be148
+static unsigned int
4be148
+cm_get_ssflags(struct select_state *selstate, int fd)
4be148
+{
4be148
+    return (FD_ISSET(fd, &selstate->rfds) ? SSF_READ : 0) |
4be148
+        (FD_ISSET(fd, &selstate->wfds) ? SSF_WRITE : 0) |
4be148
+        (FD_ISSET(fd, &selstate->xfds) ? SSF_EXCEPTION : 0);
4be148
+}
4be148
+
4be148
+#endif /* not USE_POLL */
4be148
+
4be148
+static krb5_error_code
4be148
+cm_select_or_poll(const struct select_state *in, time_ms endtime,
4be148
+                  struct select_state *out, int *sret)
4be148
+{
4be148
+#ifndef USE_POLL
4be148
+    struct timeval tv;
4be148
+#endif
4be148
+    krb5_error_code retval;
4be148
+    time_ms curtime, interval;
4be148
+
4be148
+    retval = get_curtime_ms(&curtime);
4be148
+    if (retval != 0)
4be148
+        return retval;
4be148
+    interval = (curtime < endtime) ? endtime - curtime : 0;
4be148
+
4be148
+    /* We don't need a separate copy of the selstate for poll, but use one for
4be148
+     * consistency with how we use select. */
4be148
+    *out = *in;
4be148
+
4be148
+#ifdef USE_POLL
4be148
+    *sret = poll(out->fds, out->nfds, interval);
4be148
+#else
4be148
+    tv.tv_sec = interval / 1000;
4be148
+    tv.tv_usec = interval % 1000 * 1000;
4be148
+    *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, &tv;;
4be148
+#endif
4be148
+
4be148
+    return (*sret < 0) ? SOCKET_ERRNO : 0;
4be148
+}
4be148
+
4be148
 static int
4be148
 in_addrlist(struct server_entry *entry, struct serverlist *list)
4be148
 {
4be148
@@ -251,18 +427,6 @@ cleanup:
4be148
     return retval;
4be148
 }
4be148
 
4be148
-/* Get current time in milliseconds. */
4be148
-static krb5_error_code
4be148
-get_curtime_ms(time_ms *time_out)
4be148
-{
4be148
-    struct timeval tv;
4be148
-
4be148
-    if (gettimeofday(&tv, 0))
4be148
-        return errno;
4be148
-    *time_out = (time_ms)tv.tv_sec * 1000 + tv.tv_usec / 1000;
4be148
-    return 0;
4be148
-}
4be148
-
4be148
 /*
4be148
  * Notes:
4be148
  *
4be148
@@ -283,144 +447,6 @@ get_curtime_ms(time_ms *time_out)
4be148
  *   connections already in progress
4be148
  */
4be148
 
4be148
-static void
4be148
-cm_init_selstate(struct select_state *selstate)
4be148
-{
4be148
-    selstate->nfds = 0;
4be148
-#ifndef USE_POLL
4be148
-    selstate->max = 0;
4be148
-    FD_ZERO(&selstate->rfds);
4be148
-    FD_ZERO(&selstate->wfds);
4be148
-    FD_ZERO(&selstate->xfds);
4be148
-#endif
4be148
-}
4be148
-
4be148
-static krb5_boolean
4be148
-cm_add_fd(struct select_state *selstate, int fd, unsigned int ssflags)
4be148
-{
4be148
-#ifdef USE_POLL
4be148
-    if (selstate->nfds >= MAX_POLLFDS)
4be148
-        return FALSE;
4be148
-    selstate->fds[selstate->nfds].fd = fd;
4be148
-    selstate->fds[selstate->nfds].events = 0;
4be148
-    if (ssflags & SSF_READ)
4be148
-        selstate->fds[selstate->nfds].events |= POLLIN;
4be148
-    if (ssflags & SSF_WRITE)
4be148
-        selstate->fds[selstate->nfds].events |= POLLOUT;
4be148
-#else
4be148
-#ifndef _WIN32  /* On Windows FD_SETSIZE is a count, not a max value. */
4be148
-    if (fd >= FD_SETSIZE)
4be148
-        return FALSE;
4be148
-#endif
4be148
-    if (ssflags & SSF_READ)
4be148
-        FD_SET(fd, &selstate->rfds);
4be148
-    if (ssflags & SSF_WRITE)
4be148
-        FD_SET(fd, &selstate->wfds);
4be148
-    if (ssflags & SSF_EXCEPTION)
4be148
-        FD_SET(fd, &selstate->xfds);
4be148
-    if (selstate->max <= fd)
4be148
-        selstate->max = fd + 1;
4be148
-#endif
4be148
-    selstate->nfds++;
4be148
-    return TRUE;
4be148
-}
4be148
-
4be148
-static void
4be148
-cm_remove_fd(struct select_state *selstate, int fd)
4be148
-{
4be148
-#ifdef USE_POLL
4be148
-    int i;
4be148
-
4be148
-    /* Find the FD in the array and move the last entry to its place. */
4be148
-    assert(selstate->nfds > 0);
4be148
-    for (i = 0; i < selstate->nfds && selstate->fds[i].fd != fd; i++);
4be148
-    assert(i < selstate->nfds);
4be148
-    selstate->fds[i] = selstate->fds[selstate->nfds - 1];
4be148
-#else
4be148
-    FD_CLR(fd, &selstate->rfds);
4be148
-    FD_CLR(fd, &selstate->wfds);
4be148
-    FD_CLR(fd, &selstate->xfds);
4be148
-    if (selstate->max == 1 + fd) {
4be148
-        while (selstate->max > 0
4be148
-               && ! FD_ISSET(selstate->max-1, &selstate->rfds)
4be148
-               && ! FD_ISSET(selstate->max-1, &selstate->wfds)
4be148
-               && ! FD_ISSET(selstate->max-1, &selstate->xfds))
4be148
-            selstate->max--;
4be148
-    }
4be148
-#endif
4be148
-    selstate->nfds--;
4be148
-}
4be148
-
4be148
-static void
4be148
-cm_unset_write(struct select_state *selstate, int fd)
4be148
-{
4be148
-#ifdef USE_POLL
4be148
-    int i;
4be148
-
4be148
-    for (i = 0; i < selstate->nfds && selstate->fds[i].fd != fd; i++);
4be148
-    assert(i < selstate->nfds);
4be148
-    selstate->fds[i].events &= ~POLLOUT;
4be148
-#else
4be148
-    FD_CLR(fd, &selstate->wfds);
4be148
-#endif
4be148
-}
4be148
-
4be148
-static krb5_error_code
4be148
-cm_select_or_poll(const struct select_state *in, time_ms endtime,
4be148
-                  struct select_state *out, int *sret)
4be148
-{
4be148
-#ifndef USE_POLL
4be148
-    struct timeval tv;
4be148
-#endif
4be148
-    krb5_error_code retval;
4be148
-    time_ms curtime, interval;
4be148
-
4be148
-    retval = get_curtime_ms(&curtime);
4be148
-    if (retval != 0)
4be148
-        return retval;
4be148
-    interval = (curtime < endtime) ? endtime - curtime : 0;
4be148
-
4be148
-    /* We don't need a separate copy of the selstate for poll, but use one for
4be148
-     * consistency with how we use select. */
4be148
-    *out = *in;
4be148
-
4be148
-#ifdef USE_POLL
4be148
-    *sret = poll(out->fds, out->nfds, interval);
4be148
-#else
4be148
-    tv.tv_sec = interval / 1000;
4be148
-    tv.tv_usec = interval % 1000 * 1000;
4be148
-    *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, &tv;;
4be148
-#endif
4be148
-
4be148
-    return (*sret < 0) ? SOCKET_ERRNO : 0;
4be148
-}
4be148
-
4be148
-static unsigned int
4be148
-cm_get_ssflags(struct select_state *selstate, int fd)
4be148
-{
4be148
-    unsigned int ssflags = 0;
4be148
-#ifdef USE_POLL
4be148
-    int i;
4be148
-
4be148
-    for (i = 0; i < selstate->nfds && selstate->fds[i].fd != fd; i++);
4be148
-    assert(i < selstate->nfds);
4be148
-    if (selstate->fds[i].revents & POLLIN)
4be148
-        ssflags |= SSF_READ;
4be148
-    if (selstate->fds[i].revents & POLLOUT)
4be148
-        ssflags |= SSF_WRITE;
4be148
-    if (selstate->fds[i].revents & POLLERR)
4be148
-        ssflags |= SSF_EXCEPTION;
4be148
-#else
4be148
-    if (FD_ISSET(fd, &selstate->rfds))
4be148
-        ssflags |= SSF_READ;
4be148
-    if (FD_ISSET(fd, &selstate->wfds))
4be148
-        ssflags |= SSF_WRITE;
4be148
-    if (FD_ISSET(fd, &selstate->xfds))
4be148
-        ssflags |= SSF_EXCEPTION;
4be148
-#endif
4be148
-    return ssflags;
4be148
-}
4be148
-
4be148
 static int service_tcp_fd(krb5_context context, struct conn_state *conn,
4be148
                           struct select_state *selstate, int ssflags);
4be148
 static int service_udp_fd(krb5_context context, struct conn_state *conn,
4be148
@@ -600,7 +626,6 @@ start_connection(krb5_context context, struct conn_state *state,
4be148
                  struct sendto_callback_info *callback_info)
4be148
 {
4be148
     int fd, e;
4be148
-    unsigned int ssflags;
4be148
     static const int one = 1;
4be148
     static const struct linger lopt = { 0, 0 };
4be148
 
4be148
@@ -676,15 +701,17 @@ start_connection(krb5_context context, struct conn_state *state,
4be148
             state->state = READING;
4be148
         }
4be148
     }
4be148
-    ssflags = SSF_READ | SSF_EXCEPTION;
4be148
-    if (state->state == CONNECTING || state->state == WRITING)
4be148
-        ssflags |= SSF_WRITE;
4be148
-    if (!cm_add_fd(selstate, state->fd, ssflags)) {
4be148
+
4be148
+    if (!cm_add_fd(selstate, state->fd)) {
4be148
         (void) closesocket(state->fd);
4be148
         state->fd = INVALID_SOCKET;
4be148
         state->state = FAILED;
4be148
         return -1;
4be148
     }
4be148
+    if (state->state == CONNECTING || state->state == WRITING)
4be148
+        cm_write(selstate, state->fd);
4be148
+    else
4be148
+        cm_read(selstate, state->fd);
4be148
 
4be148
     return 0;
4be148
 }
4be148
@@ -768,9 +795,8 @@ service_tcp_fd(krb5_context context, struct conn_state *conn,
4be148
     ssize_t nwritten, nread;
4be148
     SOCKET_WRITEV_TEMP tmp;
4be148
 
4be148
-    /* Check for a socket exception or readable data before we expect it. */
4be148
-    if (ssflags & SSF_EXCEPTION ||
4be148
-        ((ssflags & SSF_READ) && conn->state != READING))
4be148
+    /* Check for a socket exception. */
4be148
+    if (ssflags & SSF_EXCEPTION)
4be148
         goto kill_conn;
4be148
 
4be148
     switch (conn->state) {
4be148
@@ -810,7 +836,7 @@ service_tcp_fd(krb5_context context, struct conn_state *conn,
4be148
         }
4be148
         if (conn->x.out.sg_count == 0) {
4be148
             /* Done writing, switch to reading. */
4be148
-            cm_unset_write(selstate, conn->fd);
4be148
+            cm_read(selstate, conn->fd);
4be148
             conn->state = READING;
4be148
             conn->x.in.bufsizebytes_read = 0;
4be148
             conn->x.in.bufsize = 0;