#ifdef HAVE_PTHREAD_H
pthread_mutex_destroy(&(sock->mutex));
#endif
+
+ (void) rbtree_deletebydata(sock->home->listeners, this);
}
#endif /* WITH_TLS */
}
listen_free(&this);
return NULL;
}
+
+ if (!rbtree_insert(home->listeners, this)) {
+ ERROR("(TLS) Failed adding tracking informtion for proxy socket '%s'", buffer);
+ listen_free(&this);
+ return NULL;
+ }
}
/*
this->recv = proxy_tls_recv;
this->proxy_send = proxy_tls_send;
+ /*
+ * Make sure that this listener is associated with the home server.
+ *
+ * Since it's TCP+TLS, this socket can only be associated with one home server.
+ */
+
#ifdef WITH_COA_TUNNEL
if (home->recv_coa) {
RADCLIENT *client;
for (this = fr_hash_table_iter_init(coa_key->ht, &iter);
this != NULL;
this = fr_hash_table_iter_next(coa_key->ht, &iter)) {
+ if (this->blocked) continue;
+
if (this->dead) continue;
if (!found) {
home->port);
}
+#ifdef WITH_TLS
+static int eol_home_listener(void *ctx, UNUSED void *data)
+{
+ rad_listen_t *this = talloc_get_type_abort(ctx, rad_listen_t);
+
+ /*
+ * The socket isn't blocked, we can still use it.
+ *
+ * i.e. the home server is dead for a reason OTHER than
+ * "all available sockets are blocked".
+ *
+ * We can still ping the home server via sockets which
+ * are writable.
+ */
+ if (!this->blocked) return 0;
+
+ this->status = RAD_LISTEN_STATUS_EOL;
+
+ FD_MUTEX_LOCK(&fd_mutex);
+ this->next = new_listeners;
+ new_listeners = this;
+ FD_MUTEX_UNLOCK(&fd_mutex);
+
+ return 1; /* alway delete from this tree */
+}
+#endif
+
void mark_home_server_dead(home_server_t *home, struct timeval *when, bool down)
{
int previous_state = home->state;
home->state = HOME_STATE_IS_DEAD;
home_trigger(home, "home_server.dead");
+#ifdef WITH_TLS
+ /*
+ * If the home server is dead, then close all of the sockets associated with it.
+ *
+ * Note that the "EOL listener" code expects to _also_
+ * delete the listeners. At which point we end up with a
+ * mutex locked twice, and bad things happen. The
+ * solution is to move the listeners to the global
+ * "waiting for update" list, and then notify ourselves
+ * that there are listeners waiting to be updated.
+ */
+ if (home->listeners) {
+ ASSERT_MASTER;
+
+ rbtree_walk(home->listeners, RBTREE_DELETE_ORDER, eol_home_listener, NULL);
+ radius_signal_self(RADIUS_SIGNAL_SELF_NEW_FD);
+ }
+#endif
+
/*
* Administratively down - don't do anything to bring it
* up.
buffer, fr_strerror());
fr_exit(1);
}
+
+#ifdef WITH_TLS
+ /*
+ * Remove this socket from the list of sockets assocated with this home server.
+ *
+ * This MUST be done with the proxy mutex locked!
+ */
+ if (home->tls) {
+ (void) rbtree_deletebydata(sock->home->listeners, this);
+ }
+#endif
+
PTHREAD_MUTEX_UNLOCK(&proxy_mutex);
#ifdef WITH_COA_TUNNEL
return true;
}
+#ifdef WITH_TLS
+/*
+ * The listeners are always different. And we always look them up by *known* listener. And not "find me some random thing".
+ */
+static int listener_cmp(void const *one, void const *two)
+{
+ if (one < two) return -1;
+ if (one > two) return +1;
+
+ return 0;
+}
+#endif
+
/** Alloc a new home server defined by a CONF_SECTION
*
* @param ctx to allocate home_server_t in.
if (rcode < 0) goto error;
if (!home->connect_timeout || (home->connect_timeout > 30)) home->connect_timeout = 30;
+
+ home->listeners = rbtree_create(home, listener_cmp, NULL, RBTREE_FLAG_LOCK);
+ if (!home->listeners) goto error;
}
#endif
} /* end of parse home server */