+ FD_MUTEX_UNLOCK(&fd_mutex);
+
+#ifdef WITH_TCP
+ /*
+ * We track requests using this socket only for
+ * TCP. For UDP, we don't currently close
+ * sockets.
+ */
+#ifdef WITH_PROXY
+ if (this->type != RAD_LISTEN_PROXY)
+#endif
+ {
+ if (this->count != 0) {
+ fr_packet_list_walk(pl, this,
+ remove_all_requests);
+ }
+
+ if (this->count == 0) {
+ this->status = RAD_LISTEN_STATUS_FINISH;
+ goto finish;
+ }
+ }
+#ifdef WITH_PROXY
+ else {
+ int count;
+
+ /*
+ * Duplicate code
+ */
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ if (!fr_packet_list_socket_freeze(proxy_list,
+ this->fd)) {
+ radlog(L_ERR, "Fatal error freezing socket: %s",
+ fr_strerror());
+ exit(1);
+ }
+
+ /*
+ * Doing this with the proxy mutex held
+ * is a Bad Thing. We should move to
+ * finer-grained mutexes.
+ */
+ count = this->count;
+ if (count > 0) {
+ fr_packet_list_walk(proxy_list, this,
+ remove_all_proxied_requests);
+ }
+ count = this->count; /* protected by mutex */
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+
+ if (count == 0) {
+ this->status = RAD_LISTEN_STATUS_FINISH;
+ goto finish;
+ }
+ }
+#endif /* WITH_PROXY */
+#endif /* WITH_TCP */
+
+ /*
+ * Re-open the socket, pointing it to /dev/null.
+ * This means that all writes proceed without
+ * blocking, and all reads return "no data".
+ *
+ * This leaves the socket active, so any child
+ * threads won't go insane. But it means that
+ * they cannot send or receive any packets.
+ *
+ * This is EXTRA work in the normal case, when
+ * sockets are closed without error. But it lets
+ * us have one simple processing method for all
+ * sockets.
+ */
+ devnull = open("/dev/null", O_RDWR);
+ if (devnull < 0) {
+ radlog(L_ERR, "FATAL failure opening /dev/null: %s",
+ strerror(errno));
+ exit(1);
+ }
+ if (dup2(devnull, this->fd) < 0) {
+ radlog(L_ERR, "FATAL failure closing socket: %s",
+ strerror(errno));
+ exit(1);
+ }
+ close(devnull);
+
+ this->status = RAD_LISTEN_STATUS_CLOSED;
+
+ /*
+ * Fall through to the next section.
+ */
+ }
+
+#ifdef WITH_TCP
+ /*
+ * Called ONLY from the main thread. On the following
+ * conditions:
+ *
+ * idle timeout
+ * max lifetime
+ *
+ * (and falling through from "forcibly close FD" above)
+ * client closed connection on us
+ * client sent us a bad packet.
+ */
+ if (this->status == RAD_LISTEN_STATUS_CLOSED) {
+ int count = this->count;
+
+#ifdef WITH_DETAIL
+ rad_assert(this->type != RAD_LISTEN_DETAIL);
+#endif
+
+#ifdef WITH_PROXY
+ /*
+ * Remove it from the list of active sockets, so
+ * that it isn't used when proxying new packets.
+ */
+ if (this->type == RAD_LISTEN_PROXY) {
+ PTHREAD_MUTEX_LOCK(&proxy_mutex);
+ if (!fr_packet_list_socket_freeze(proxy_list,
+ this->fd)) {
+ radlog(L_ERR, "Fatal error freezing socket: %s",
+ fr_strerror());
+ exit(1);
+ }
+ count = this->count; /* protected by mutex */
+ PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
+ }
+#endif
+
+ /*
+ * Requests are still using the socket. Wait for
+ * them to finish.
+ */
+ if (count != 0) {
+ struct timeval when;
+ listen_socket_t *sock = this->data;
+
+ /*
+ * Try again to clean up the socket in 30
+ * seconds.
+ */
+ gettimeofday(&when, NULL);
+ when.tv_sec += 30;
+
+ if (!fr_event_insert(el,
+ (fr_event_callback_t) event_new_fd,
+ this, &when, &sock->ev)) {
+ rad_panic("Failed to insert event");
+ }
+
+ return 1;
+ }
+
+ /*
+ * No one is using this socket: we can delete it
+ * immediately.
+ */