#include <event2/event.h>
+#define TR_MAX_SOCKETS 10
+
/* struct for hanging on to a socket listener event */
struct tr_socket_event {
- int sock_fd; /* the fd for the socket */
- struct event *ev; /* its event */
+ size_t n_sock_fd; /* how many of those are filled in? */
+ int sock_fd[TR_MAX_SOCKETS]; /* the fd for the socket */
+ struct event *ev[TR_MAX_SOCKETS]; /* its events */
};
/* prototypes */
TRP_AUTH_FUNC auth_handler,
const char *hostname,
unsigned int port,
- void *cookie);
+ void *cookie,
+ int *fd_out,
+ size_t max_fd);
TR_MQ_MSG *trps_mq_pop(TRPS_INSTANCE *trps);
void trps_mq_add(TRPS_INSTANCE *trps, TR_MQ_MSG *msg);
TRP_RC trps_authorize_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn);
/* TID Server functions, in tid/tids.c */
TR_EXPORT TIDS_INSTANCE *tids_create (TALLOC_CTX *mem_ctx);
-TR_EXPORT int tids_start (TIDS_INSTANCE *tids, TIDS_REQ_FUNC *req_handler,
- TIDS_AUTH_FUNC *auth_handler, const char *hostname,
- unsigned int port, void *cookie);
TR_EXPORT int tids_get_listener (TIDS_INSTANCE *tids, TIDS_REQ_FUNC *req_handler,
- TIDS_AUTH_FUNC *auth_handler, const char *hostname,
- unsigned int port, void *cookie);
+ TIDS_AUTH_FUNC *auth_handler, const char *hostname,
+ unsigned int port, void *cookie, int *fd_out, size_t max_fd);
TR_EXPORT int tids_accept(TIDS_INSTANCE *tids, int listen);
TR_EXPORT int tids_send_response (TIDS_INSTANCE *tids, TID_REQ *req, TID_RESP *resp);
TR_EXPORT int tids_send_err_response (TIDS_INSTANCE *tids, TID_REQ *req, const char *err_msg);
}
}
-static int tids_listen (TIDS_INSTANCE *tids, int port)
+static int tids_listen(TIDS_INSTANCE *tids, int port, int *fd_out, size_t max_fd)
{
- int rc = 0;
- int conn = -1;
- int optval = 1;
-
- union {
- struct sockaddr_storage storage;
- struct sockaddr_in in4;
- } addr;
-
- struct sockaddr_in *saddr = (struct sockaddr_in *) &addr.in4;
-
- saddr->sin_port = htons (port);
- saddr->sin_family = AF_INET;
- saddr->sin_addr.s_addr = INADDR_ANY;
-
- if (0 > (conn = socket (AF_INET, SOCK_STREAM, 0)))
- return conn;
+ int rc = 0;
+ int conn = -1;
+ int optval = 1;
+ struct addrinfo *ai=NULL;
+ struct addrinfo *ai_head=NULL;
+ struct addrinfo hints={.ai_flags=AI_PASSIVE,
+ .ai_family=AF_UNSPEC,
+ .ai_socktype=SOCK_STREAM,
+ .ai_protocol=IPPROTO_TCP};
+ char *port_str=NULL;
+
+ port_str=talloc_asprintf(NULL, "%d", port);
+ if (port_str==NULL) {
+ tr_debug("tids_listen: unable to allocate port.");
+ return -1;
+ }
- setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
+ getaddrinfo(NULL, port_str, &hints, &ai_head);
+ talloc_free(port_str);
- if (0 > (rc = bind (conn, (struct sockaddr *) saddr, sizeof(struct sockaddr_in))))
- return rc;
+ /* TODO: listen on all ports */
+ for (ai=ai_head; ai!=NULL; ai=ai->ai_next) {
+ if (ai->ai_family==AF_INET6) {
+ ai=talloc_memdup(NULL, ai, sizeof(struct addrinfo)); /* get a permanent copy of this */
+ break;
+ }
+ }
+ freeaddrinfo(ai_head);
- if (0 > (rc = listen(conn, 512)))
- return rc;
+ if (ai==NULL) {
+ tr_debug("tids_listen: no addresses available for listening.");
+ return -1;
+ }
- tr_debug("tids_listen: TID Server listening on port %d", port);
- return conn;
+ if (0 > (conn = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))) {
+ tr_debug("tids_listen: unable to open socket.");
+ talloc_free(ai);
+ return -1;
+ }
+
+ optval=1;
+ setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
+/* setsockopt(conn, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); */
+
+ rc=bind(conn, ai->ai_addr, ai->ai_addrlen);
+ talloc_free(ai);
+ if (rc<0) {
+ char errmsg[255];
+ tr_debug("tids_listen: unable to bind to socket (%s).", strerror_r(errno, errmsg, 255));
+ close(conn);
+ return -1;
+ }
+
+ if (0 > (rc = listen(conn, 512))) {
+ tr_debug("trps_listen: unable to listen on bound socket.");
+ close(conn);
+ return rc;
+ }
+
+ tr_debug("tids_listen: TID Server listening on port %d", port);
+ return conn;
}
/* returns EACCES if authorization is denied */
TIDS_AUTH_FUNC *auth_handler,
const char *hostname,
unsigned int port,
- void *cookie)
+ void *cookie,
+ int *fd_out,
+ size_t max_fd)
{
- int listen = -1;
+ size_t n_fd=0;
+ size_t ii=0;
tids->tids_port = port;
- if (0 > (listen = tids_listen(tids, port))) {
- char errbuf[256];
- if (0 == strerror_r(errno, errbuf, 256)) {
- tr_debug("tids_get_listener: Error opening port %d: %s.", port, errbuf);
- } else {
- tr_debug("tids_get_listener: Unknown error openining port %d.", port);
- }
- }
-
- if (listen > 0) {
+ n_fd=tids_listen(tids, port, fd_out, max_fd);
+ if (n_fd==0)
+ tr_debug("tids_get_listener: Error opening port %d");
+ else {
/* opening port succeeded */
tr_debug("tids_get_listener: Opened port %d.", port);
/* make this socket non-blocking */
- if (0 != fcntl(listen, F_SETFL, O_NONBLOCK)) {
- tr_debug("tids_get_listener: Error setting O_NONBLOCK.");
- close(listen);
- listen=-1;
+ for (ii=0; ii<n_fd; ii++) {
+ if (0 != fcntl(fd_out[ii], F_SETFL, O_NONBLOCK)) {
+ tr_debug("tids_get_listener: Error setting O_NONBLOCK.");
+ for (ii=0; ii<n_fd; ii++) {
+ close(fd_out[ii]);
+ fd_out[ii]=-1;
+ }
+ n_fd=0;
+ break;
+ }
}
}
- if (listen > 0) {
+ if (n_fd>0) {
/* store the caller's request handler & cookie */
tids->req_handler = req_handler;
tids->auth_handler = auth_handler;
tids->cookie = cookie;
}
- return listen;
+ return n_fd;
}
/* Accept and process a connection on a port opened with tids_get_listener() */
return 0;
}
-/* Process tids requests forever. Should not return except on error. */
-int tids_start (TIDS_INSTANCE *tids,
- TIDS_REQ_FUNC *req_handler,
- TIDS_AUTH_FUNC *auth_handler,
- const char *hostname,
- unsigned int port,
- void *cookie)
-{
- int listen = -1;
- int conn = -1;
- pid_t pid;
-
- tids->tids_port = port;
- if (0 > (listen = tids_listen(tids, port)))
- perror ("Error from tids_listen()");
-
- /* store the caller's request handler & cookie */
- tids->req_handler = req_handler;
- tids->auth_handler = auth_handler;
- tids->hostname = hostname;
- tids->cookie = cookie;
-
- tr_info("Trust Path Query Server starting on host %s:%d.", hostname, port);
-
- while(1) { /* accept incoming conns until we are stopped */
-
- if (0 > (conn = accept(listen, NULL, NULL))) {
- perror("Error from TIDS Server accept()");
- return 1;
- }
-
- if (0 > (pid = fork())) {
- perror("Error on fork()");
- return 1;
- }
-
- if (pid == 0) {
- close(listen);
- tids_handle_connection(tids, conn);
- close(conn);
- exit(0); /* exit to kill forked child process */
- } else {
- close(conn);
- }
-
- /* clean up any processes that have completed */
- while (waitpid(-1, 0, WNOHANG) > 0);
- }
-
- return 1; /* should never get here, loops "forever" */
-}
-
void tids_destroy (TIDS_INSTANCE *tids)
{
/* clean up logfiles */
TR_INSTANCE *tr = NULL;
struct cmdline_args opts;
struct event_base *ev_base;
- struct tr_socket_event tids_ev;
+ struct tr_socket_event tids_ev = {0};
struct event *cfgwatch_ev;
configure_signals();
retval=-1;
goto cleanup;
}
+
tr_debug("tr_tids_req_handler: Community was a COI, switching.");
/* TBD -- In theory there can be more than one? How would that work? */
if ((!cfg_comm->apcs) || (!cfg_comm->apcs->id)) {
TALLOC_CTX *tmp_ctx=talloc_new(NULL);
struct tr_tids_event_cookie *cookie=NULL;
int retval=0;
+ size_t ii=0;
if (tids_ev == NULL) {
tr_debug("tr_tids_event_init: Null tids_ev.");
talloc_steal(tids, cookie);
/* get a tids listener */
- tids_ev->sock_fd=tids_get_listener(tids,
- tr_tids_req_handler,
- tr_tids_gss_handler,
- cfg_mgr->active->internal->hostname,
- cfg_mgr->active->internal->tids_port,
- (void *)cookie);
- if (tids_ev->sock_fd < 0) {
+ tids_ev->n_sock_fd=tids_get_listener(tids,
+ tr_tids_req_handler,
+ tr_tids_gss_handler,
+ cfg_mgr->active->internal->hostname,
+ cfg_mgr->active->internal->tids_port,
+ (void *)cookie,
+ tids_ev->sock_fd,
+ TR_MAX_SOCKETS);
+ if (tids_ev->n_sock_fd==0) {
tr_crit("Error opening TID server socket.");
retval=1;
goto cleanup;
}
- /* and its event */
- tids_ev->ev=event_new(base,
- tids_ev->sock_fd,
- EV_READ|EV_PERSIST,
- tr_tids_event_cb,
- (void *)tids);
- event_add(tids_ev->ev, NULL);
+ /* Set up events */
+ for (ii=0; ii<tids_ev->n_sock_fd; ii++) {
+ tids_ev->ev[ii]=event_new(base,
+ tids_ev->sock_fd[ii],
+ EV_READ|EV_PERSIST,
+ tr_tids_event_cb,
+ (void *)tids);
+ event_add(tids_ev->ev[ii], NULL);
+ }
cleanup:
talloc_free(tmp_ctx);
struct tr_trps_event_cookie *sweep_cookie=NULL;
struct timeval zero_time={0,0};
TRP_RC retval=TRP_ERROR;
+ size_t ii=0;
if (tr->events != NULL) {
tr_notice("tr_trps_event_init: tr->events was not null. Freeing before reallocating..");
trps_cookie->cfg_mgr=tr->cfg_mgr;
/* get a trps listener */
- listen_ev->sock_fd=trps_get_listener(tr->trps,
- tr_trps_msg_handler,
- tr_trps_gss_handler,
- tr->cfg_mgr->active->internal->hostname,
- tr->cfg_mgr->active->internal->trps_port,
- (void *)trps_cookie);
- if (listen_ev->sock_fd < 0) {
+ listen_ev->n_sock_fd=trps_get_listener(tr->trps,
+ tr_trps_msg_handler,
+ tr_trps_gss_handler,
+ tr->cfg_mgr->active->internal->hostname,
+ tr->cfg_mgr->active->internal->trps_port,
+ (void *)trps_cookie,
+ listen_ev->sock_fd,
+ TR_MAX_SOCKETS);
+ if (listen_ev->n_sock_fd==0) {
tr_crit("Error opening TRP server socket.");
retval=TRP_ERROR;
tr_trps_events_free(tr->events);
tr->events=NULL;
goto cleanup;
}
- trps_cookie->ev=listen_ev->ev; /* in case it needs to frob the event */
-
- /* and its event */
- listen_ev->ev=event_new(base,
- listen_ev->sock_fd,
- EV_READ|EV_PERSIST,
- tr_trps_event_cb,
- (void *)(tr->trps));
- event_add(listen_ev->ev, NULL);
+
+ /* Set up events for the sockets */
+ for (ii=0; ii<listen_ev->n_sock_fd; ii++) {
+ listen_ev->ev[ii]=event_new(base,
+ listen_ev->sock_fd[ii],
+ EV_READ|EV_PERSIST,
+ tr_trps_event_cb,
+ (void *)(tr->trps));
+ event_add(listen_ev->ev[ii], NULL);
+ }
/* now set up message queue processing event, only triggered by
* tr_trps_mq_cb() */
return rc;
}
-/* Listens on all interfaces */
-static int trps_listen(TRPS_INSTANCE *trps, int port)
+/* Listens on all interfaces. Returns number of sockets opened. Their
+ * descriptors are stored in *fd_out, which should point to space for
+ * up to max_fd of them. */
+static size_t trps_listen(TRPS_INSTANCE *trps, int port, int *fd_out, size_t max_fd)
{
int rc = 0;
int conn = -1;
.ai_socktype=SOCK_STREAM,
.ai_protocol=IPPROTO_TCP};
char *port_str=NULL;
+ size_t n_opened=0;
port_str=talloc_asprintf(NULL, "%d", port);
if (port_str==NULL) {
tr_debug("trps_listen: unable to allocate port.");
return -1;
}
- rc=getaddrinfo(NULL, port_str, &hints, &ai_head);
+ getaddrinfo(NULL, port_str, &hints, &ai_head);
talloc_free(port_str);
/* TODO: listen on all ports */
- for (ai=ai_head; ai!=NULL; ai=ai->ai_next) {
+ for (ai=ai_head,n_opened=0; (ai!=NULL)&&(n_opened<max_fd); ai=ai->ai_next) {
+ if (0 > (conn = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))) {
+ tr_debug("trps_listen: unable to open socket.");
+ continue;
+ }
+
+ optval=1;
+ if (0!=setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)))
+ tr_debug("trps_listen: unable to set SO_REUSEADDR."); /* not fatal? */
+
if (ai->ai_family==AF_INET6) {
- ai=talloc_memdup(NULL, ai, sizeof(struct addrinfo)); /* get a permanent copy of this */
- break;
+ /* don't allow IPv4-mapped IPv6 addresses (per RFC4942, not sure
+ * if still relevant) */
+ if (0!=setsockopt(conn, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval))) {
+ tr_debug("trps_listen: unable to set IPV6_V6ONLY. Skipping interface.");
+ close(conn);
+ continue;
+ }
+ }
+
+ rc=bind(conn, ai->ai_addr, ai->ai_addrlen);
+ if (rc<0) {
+ tr_debug("trps_listen: unable to bind to socket.");
+ close(conn);
+ continue;
+ }
+
+ if (0>listen(conn, 512)) {
+ tr_debug("trps_listen: unable to listen on bound socket.");
+ close(conn);
+ continue;
}
+
+ /* ok, this one worked. Save it */
+ fd_out[n_opened++]=conn;
}
freeaddrinfo(ai_head);
- if (ai==NULL) {
+ if (n_opened==0) {
tr_debug("trps_listen: no addresses available for listening.");
return -1;
}
- if (0 > (conn = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol))) {
- tr_debug("trps_listen: unable to open socket.");
- talloc_free(ai);
- return -1;
- }
-
- optval=1;
- setsockopt(conn, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
-/* setsockopt(conn, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)); */
+ tr_debug("trps_listen: TRP Server listening on port %d on %d socket%s",
+ port,
+ n_opened,
+ (n_opened==1)?"":"s");
- rc=bind(conn, ai->ai_addr, ai->ai_addrlen);
- talloc_free(ai);
-
- if (rc<0) {
- char errmsg[255];
- tr_debug("trps_listen: unable to bind to socket (%s).", strerror_r(errno, errmsg, 255));
- close(conn);
- return -1;
- }
-
- if (0>listen(conn, 512)) {
- tr_debug("trps_listen: unable to listen on bound socket.");
- close(conn);
- return -1;
- }
-
- tr_debug("trps_listen: TRP Server listening on port %d", port);
- return conn;
+ return n_opened;
}
/* get the currently selected route if available */
TRP_AUTH_FUNC auth_handler,
const char *hostname,
unsigned int port,
- void *cookie)
+ void *cookie,
+ int *fd_out,
+ size_t max_fd)
{
- int listen = -1;
-
- if (0 > (listen = trps_listen(trps, port))) {
- char errbuf[256];
- if (0 == strerror_r(errno, errbuf, 256)) {
- tr_debug("trps_get_listener: Error opening port %d: %s.", port, errbuf);
- } else {
- tr_debug("trps_get_listener: Unknown error openining port %d.", port);
- }
- }
+ size_t n_fd=0;
+ size_t ii=0;
- if (listen > 0) {
+ n_fd=trps_listen(trps, port, fd_out, max_fd);
+ if (n_fd==0)
+ tr_debug("trps_get_listener: Error opening port %d.");
+ else {
/* opening port succeeded */
tr_debug("trps_get_listener: Opened port %d.", port);
- /* make this socket non-blocking */
- if (0 != fcntl(listen, F_SETFL, O_NONBLOCK)) {
- tr_debug("trps_get_listener: Error setting O_NONBLOCK.");
- close(listen);
- listen=-1;
+ /* make the sockets non-blocking */
+ for (ii=0; ii<n_fd; ii++) {
+ if (0 != fcntl(fd_out[ii], F_SETFL, O_NONBLOCK)) {
+ tr_debug("trps_get_listener: Error setting O_NONBLOCK.");
+ for (ii=0; ii<n_fd; ii++) {
+ close(fd_out[ii]);
+ fd_out[ii]=-1;
+ }
+ n_fd=0;
+ break;
+ }
}
}
- if (listen > 0) {
+ if (n_fd>0) {
/* store the caller's request handler & cookie */
trps->msg_handler = msg_handler;
trps->auth_handler = auth_handler;
trps->cookie = cookie;
}
- return listen;
+ return n_fd;
}
TRP_RC trps_authorize_connection(TRPS_INSTANCE *trps, TRP_CONNECTION *conn)