X-Git-Url: http://www.project-moonshot.org/gitweb/?p=trust_router.git;a=blobdiff_plain;f=mon%2Fmons.c;h=b0a04003bed9ac71b0b8316d6200d52e15805547;hp=31ecb15ed1be270b9789922600e3d87c60b7a90f;hb=7458d6a285fa526fd8cec03e1bbb497650a0e405;hpb=605ee6f071ad51755ba07b4e1a712814bbf4f780 diff --git a/mon/mons.c b/mon/mons.c index 31ecb15..b0a0400 100644 --- a/mon/mons.c +++ b/mon/mons.c @@ -44,6 +44,22 @@ #include #include +#include "mons_handlers.h" + +static void mons_sweep_procs(MONS_INSTANCE *mons); + +static int mons_destructor(void *object) +{ + MONS_INSTANCE *mons = talloc_get_type_abort(object, MONS_INSTANCE); + if (mons->handlers) + g_ptr_array_unref(mons->handlers); + + if (mons->pids) + g_array_unref(mons->pids); + + return 0; +} + /** * Allocate a new MONS_INSTANCE * @@ -55,20 +71,95 @@ MONS_INSTANCE *mons_new(TALLOC_CTX *mem_ctx) MONS_INSTANCE *mons = talloc(mem_ctx, MONS_INSTANCE); if (mons) { + mons->hostname = NULL; mons->port = 0; + mons->tids = NULL; + mons->trps = NULL; mons->req_handler = NULL; mons->auth_handler = NULL; mons->cookie = NULL; + + /* Before any steps that may fail, install the destructor */ + talloc_set_destructor((void *)mons, mons_destructor); + mons->authorized_gss_names = tr_gss_names_new(mons); if (mons->authorized_gss_names == NULL) { talloc_free(mons); - mons = NULL; + return NULL; + } + + mons->handlers = g_ptr_array_new(); + if (mons->handlers == NULL) { + talloc_free(mons); + return NULL; + } + + mons->pids = g_array_new(FALSE, FALSE, sizeof(pid_t)); + if (mons->pids == NULL) { + talloc_free(mons); + return NULL; } } return mons; } /** + * Callback to process a request and produce a response + * + * @param req_str JSON-encoded request + * @param data pointer to a MONS_INSTANCE + * @return pointer to the response string or null to send no response + */ +static TR_MSG *mons_req_cb(TALLOC_CTX *mem_ctx, TR_MSG *req_msg, void *data) +{ + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + MONS_INSTANCE *mons = talloc_get_type_abort(data, MONS_INSTANCE); + MON_REQ *req = NULL; + MON_RESP *resp = NULL; + TR_MSG *resp_msg = NULL; /* This is the response value */ + + /* Validate inputs */ + if (req_msg == NULL) + goto cleanup; + + req = tr_msg_get_mon_req(req_msg); + if (req == NULL) { + /* this is an internal error */ + tr_err("mons_req_cb: Received incorrect message type (was %d, expected %d)", + tr_msg_get_msg_type(req_msg), + MON_REQUEST); + /* TODO send an error response */ + goto cleanup; + } + + /* Allocate a response message */ + resp_msg = talloc(tmp_ctx, TR_MSG); + if (resp_msg == NULL) { + /* can't return a message, just emit an error */ + tr_crit("mons_req_cb: Error allocating response message."); + goto cleanup; + } + + /* Handle the request */ + resp = mons_handle_request(resp_msg, mons, req); + if (resp == NULL) { + /* error processing the request */ + /* TODO send back an error */ + goto cleanup; + } + + /* Set the response message payload */ + tr_msg_set_mon_resp(resp_msg, resp); + + /* Put the response message in the caller's context so it does not get freed when we exit */ + talloc_steal(mem_ctx, resp_msg); + +cleanup: + talloc_free(tmp_ctx); + return resp_msg; +} + +/** * Create a listener for monitoring requests * * Accept connections with mons_accept() @@ -83,13 +174,8 @@ MONS_INSTANCE *mons_new(TALLOC_CTX *mem_ctx) * @param max_fd * @return */ -int mons_get_listener(MONS_INSTANCE *mons, - MONS_REQ_FUNC *req_handler, - MONS_AUTH_FUNC *auth_handler, - unsigned int port, - void *cookie, - int *fd_out, - size_t max_fd) +int mons_get_listener(MONS_INSTANCE *mons, MONS_REQ_FUNC *req_handler, MONS_AUTH_FUNC *auth_handler, const char *hostname, + unsigned int port, void *cookie, int *fd_out, size_t max_fd) { size_t n_fd=0; size_t ii=0; @@ -120,6 +206,7 @@ int mons_get_listener(MONS_INSTANCE *mons, /* store the caller's request handler & cookie */ mons->req_handler = req_handler; mons->auth_handler = auth_handler; + mons->hostname = hostname; mons->cookie = cookie; } @@ -138,8 +225,8 @@ int mons_accept(MONS_INSTANCE *mons, int listen) int conn=-1; int pid=-1; - if (0 > (conn = accept(listen, NULL, NULL))) { - perror("Error from monitoring interface accept()"); + if (0 > (conn = tr_sock_accept(listen))) { + tr_err("mons_accept: Error accepting connection"); return 1; } @@ -150,19 +237,60 @@ int mons_accept(MONS_INSTANCE *mons, int listen) if (pid == 0) { close(listen); - tr_gss_handle_connection(conn, - "trustmonitor", mons->hostname, /* acceptor name */ - mons->auth_handler, mons->cookie, /* auth callback and cookie */ - mons_req_cb, mons /* req callback and cookie */ - ); + switch(tr_gss_handle_connection(conn, + "trustmonitor", mons->hostname, /* acceptor name */ + mons->auth_handler, mons->cookie, /* auth callback and cookie */ + mons_req_cb, mons /* req callback and cookie */ + )) { + case TR_GSS_SUCCESS: + /* do nothing */ + break; + + case TR_GSS_ERROR: + tr_debug("mons_accept: Error returned by tr_gss_handle_connection()"); + break; + + default: + tr_err("mons_accept: Unexpected value returned by tr_gss_handle_connection()"); + break; + } close(conn); exit(0); /* exit to kill forked child process */ - } else { - close(conn); } + /* Only the parent process gets here */ + close(conn); + g_array_append_val(mons->pids, pid); + /* clean up any processes that have completed */ - while (waitpid(-1, 0, WNOHANG) > 0); + mons_sweep_procs(mons); return 0; } + +void mons_sweep_procs(MONS_INSTANCE *mons) +{ + guint ii; + pid_t pid; + int status; + + /* loop backwards over the array so we can remove elements as we go */ + for (ii=mons->pids->len; ii > 0; ii--) { + /* ii-1 is the current index */ + pid = g_array_index(mons->pids, pid_t, ii-1); + if (waitpid(pid, &status, WNOHANG) > 0) { + /* the process exited */ + tr_debug("mons_sweep_procs: monitoring process %d terminated.", pid); + + g_array_remove_index_fast(mons->pids, ii-1); /* disturbs only indices >= ii-1 which we've already handled */ + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) == 0) + tr_debug("mons_sweep_procs: monitoring process %d succeeded.", pid); + else + tr_debug("mons_sweep_procs: monitoring process %d exited with status %d.", pid, WTERMSIG(status)); + } else if (WIFSIGNALED(status)) { + tr_debug("mons_sweep_procs: monitoring process %d terminated by signal %d.", pid, WTERMSIG(status)); + } + } + } +}