# upstram PR: https://bz.apache.org/bugzilla/show_bug.cgi?id=59914
# FreeBSD PR: 211430
========================================================================
--- apr-1.7.6/poll/unix/kqueue.c.orig	2022-01-19 23:17:18 UTC
+++ apr-1.7.6/poll/unix/kqueue.c
@@ -25,21 +25,40 @@
 
 #ifdef HAVE_KQUEUE
 
-static apr_int16_t get_kqueue_revent(apr_int16_t event, apr_int16_t flags)
+static apr_int16_t get_kqueue_revent(apr_int16_t event, apr_int16_t flags,
+                                     int fflags, intptr_t data)
 {
     apr_int16_t rv = 0;
 
-    if (event == EVFILT_READ)
-        rv |= APR_POLLIN;
-    else if (event == EVFILT_WRITE)
-        rv |= APR_POLLOUT;
-    if (flags & EV_EOF)
-        rv |= APR_POLLHUP;
-    /* APR_POLLPRI, APR_POLLERR, and APR_POLLNVAL are not handled by this
-     * implementation.
+    /* APR_POLLPRI and APR_POLLNVAL are not handled by this implementation.
      * TODO: See if EV_ERROR + certain system errors in the returned data field
      * should map to APR_POLLNVAL.
      */
+    if (event == EVFILT_READ) {
+	if (data > 0 || fflags == 0)
+	    rv |= APR_POLLIN;
+	else
+	    rv |= APR_POLLERR;
+        /*
+	 * Don't return POLLHUP if connect fails.  Apparently Linux
+         * does not, and this is expected by serf in order for IPv6 to
+	 * IPv4 or multihomed host fallback to work.
+         *
+	 * ETIMEDOUT is ambiguous here since we don't know if a
+	 * connection was established.  We don't want to return
+	 * POLLHUP here if the connection attempt timed out, but
+	 * we do if the connection was successful but later dropped.
+	 * For now, favor the latter.
+	 */
+	if ((flags & EV_EOF) != 0 && fflags != ECONNREFUSED &&
+	    fflags != ENETUNREACH && fflags != EHOSTUNREACH)
+	    rv |= APR_POLLHUP;
+    } else if (event == EVFILT_WRITE) {
+	if (data > 0 || fflags == 0)
+	    rv |= APR_POLLOUT;
+	else
+	    rv |= APR_POLLERR;
+    }
     return rv;
 }
 
@@ -293,7 +312,9 @@ static apr_status_t impl_pollset_poll(apr_pollset_t *p
                 pollset->p->result_set[j] = *fd;
                 pollset->p->result_set[j].rtnevents =
                         get_kqueue_revent(pollset->p->ke_set[i].filter,
-                                          pollset->p->ke_set[i].flags);
+                                          pollset->p->ke_set[i].flags,
+                                          pollset->p->ke_set[i].fflags,
+                                          pollset->p->ke_set[i].data);
                 j++;
             }
         }
@@ -478,7 +499,9 @@ static apr_status_t impl_pollcb_poll(apr_pollcb_t *pol
             }
 
             pollfd->rtnevents = get_kqueue_revent(pollcb->pollset.ke[i].filter,
-                                                  pollcb->pollset.ke[i].flags);
+                                                  pollcb->pollset.ke[i].flags,
+                                                  pollcb->pollset.ke[i].fflags,
+                                                  pollcb->pollset.ke[i].data);
             
             rv = func(baton, pollfd);
             
