[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r30827 - msh/src
From: |
gnunet |
Subject: |
[GNUnet-SVN] r30827 - msh/src |
Date: |
Wed, 20 Nov 2013 14:58:08 +0100 |
Author: harsha
Date: 2013-11-20 14:58:08 +0100 (Wed, 20 Nov 2013)
New Revision: 30827
Added:
msh/src/pmonitor.c
msh/src/pmonitor.h
msh/src/server.c
msh/src/server.h
Removed:
msh/src/mshd-server.c
msh/src/mshd_pmonitor.c
msh/src/mshd_pmonitor.h
Modified:
msh/src/msh.c
msh/src/mshd.c
msh/src/test_pty.c
Log:
- file rename; fork upon accepting new connections
Modified: msh/src/msh.c
===================================================================
--- msh/src/msh.c 2013-11-20 10:55:44 UTC (rev 30826)
+++ msh/src/msh.c 2013-11-20 13:58:08 UTC (rev 30827)
@@ -680,8 +680,6 @@
static int
read_tty_settings ()
{
- unsigned int cnt;
-
if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0)
{
GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "ioctl");
@@ -692,6 +690,7 @@
GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "tcgetattr");
return GNUNET_SYSERR;
}
+ return GNUNET_OK;
}
Deleted: msh/src/mshd-server.c
===================================================================
--- msh/src/mshd-server.c 2013-11-20 10:55:44 UTC (rev 30826)
+++ msh/src/mshd-server.c 2013-11-20 13:58:08 UTC (rev 30827)
@@ -1,1161 +0,0 @@
-/**
- * @file mshd-server.c
- * @brief functions implementing server functionalities of MSH daemon. We
- * listen for commands from locally started MSH instances and also for
- * executing commands given by remote MSH daemons.
- * @author Sree Harsha Totakura <address@hidden>
- */
-
-#include "common.h"
-#include <gnunet/gnunet_util_lib.h>
-#include <termios.h>
-#include "mshd.h"
-#include "addressmap.h"
-#include "mshd_pmonitor.h"
-#include "util.h"
-
-#define TIMEOUT_SECS(s) \
- GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, s)
-
-#define LOG(kind,...) \
- GNUNET_log_from (kind, "mshd-server", __VA_ARGS__)
-
-#define LOG_DEBUG(...) LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
-
-#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
-
-#define LOG_STRERROR(kind,cmd) \
- GNUNET_log_from_strerror (kind, "mshd-error", cmd)
-
-/**
- * server handle for accepting requests from local MSH instances
- */
-static struct GNUNET_SERVER_Handle *local_serv;
-
-/**
- * server handle for acceptiong requests from remote MSHD instances
- */
-static struct GNUNET_SERVER_Handle *daemon_serv;
-
-/**
- * Notification queue for the local server
- */
-static struct GNUNET_SERVER_NotificationContext *local_serv_nc;
-
-/**
- * Notification queue for the daemon server
- */
-static struct GNUNET_SERVER_NotificationContext *daemon_serv_nc;
-
-/**
- * Our UID. We use this for access checks
- */
-uid_t our_uid;
-
-/**
- * Our GID. We use this for access checks
- */
-uid_t our_gid;
-
-
-/**
- * Context for connections requiring to execute commands
- */
-struct ExecCtx
-{
- /**
- * The client handle this context is associated with
- */
- struct GNUNET_SERVER_Client *client;
-
- /**
- * The command strings to execute
- */
- char **args;
-
- /**
- * file handle for processes input
- */
- struct GNUNET_DISK_FileHandle *fin;
-
- /**
- * file handle for processes output
- */
- struct GNUNET_DISK_FileHandle *fout;
-
- /**
- * input buffer. Data from this buffer is written to proc's STDIN when it is
- * available for writing.
- */
- char *buf;
-
- /**
- * If this session were to be interactive, the message containing the setting
- * to use for the pseudo-tty we create
- */
- struct MSH_MSG_PtyMode *pty_mode;
-
- /**
- * The size of the input buffer
- */
- size_t bufsize;
-
- /**
- * salt hash used for authentication
- */
- struct GNUNET_HashCode salt;
-
- /**
- * timeout task
- */
- GNUNET_SCHEDULER_TaskIdentifier timeout_task;
-
- /**
- * task to read the output from the process
- */
- GNUNET_SCHEDULER_TaskIdentifier fout_task;
-
- /**
- * task to write data received from the client to proc's STDIN
- */
- GNUNET_SCHEDULER_TaskIdentifier fin_task;
-
- /**
- * The pid of the child we start
- */
- pid_t child_pid;
-
- /**
- * If this is an interactive session, this is the master side of the
- * pseudo-tty we create
- */
- int master;
-
- /**
- * Is this an interactive session?
- */
- int interactive;
-
- /**
- * Is this session authentication?
- */
- int authenticated;
-
- /**
- * If this is an interactive session, is a pseudo-tty created?
- */
- int pty_created;
-};
-
-
-/**
- * Destroys an execution context
- *
- * @param ctx execution context
- */
-static void
-destroy_exec_ctx (struct ExecCtx *ctx)
-{
- unsigned int cnt;
-
- GNUNET_SERVER_client_drop (ctx->client);
- if (NULL != ctx->args)
- {
- for (cnt = 0; NULL != ctx->args[cnt]; cnt++)
- GNUNET_free (ctx->args[cnt]);
- GNUNET_free (ctx->args);
- }
- if (0 != ctx->child_pid)
- {
- MSH_monitor_process_pid_cancel (ctx->child_pid);
- GNUNET_break (0 == kill (ctx->child_pid, SIGTERM));
- }
- GNUNET_DISK_file_close (ctx->fin);
- GNUNET_DISK_file_close (ctx->fout);
- if (GNUNET_SCHEDULER_NO_TASK != ctx->timeout_task)
- GNUNET_SCHEDULER_cancel (ctx->timeout_task);
- if (GNUNET_SCHEDULER_NO_TASK != ctx->fout_task)
- GNUNET_SCHEDULER_cancel (ctx->fout_task);
- if (NULL != ctx->buf)
- GNUNET_free (ctx->buf);
- GNUNET_free_non_null (ctx->pty_mode);
- GNUNET_free (ctx);
-}
-
-
-/**
- * Parse contingious 0-terminated strings from a buffer of given length
- *
- * @param buf the buffer
- * @param size the size of the buffer
- * @param s will contain the array of strings upon return
- * @return the number of strings returned in the array
- */
-static int
-parse_strings (const char *buf, size_t size, char ***s)
-{
- const char *p;
- char **strs;
- size_t off;
- unsigned int cnt;
-
- cnt = 0;
- strs = NULL;
- p = NULL;
- for (off = 0; off < size; off++)
- {
- if ('\0' == buf[off])
- {
- if (NULL == p)
- continue;
- GNUNET_array_append (strs, cnt, GNUNET_strdup (p));
- p = NULL;
- continue;
- }
- if (NULL != p)
- continue;
- p = &buf[off];
- }
- if (0 < cnt)
- GNUNET_array_append (strs, cnt, NULL);
- *s = strs;
- return cnt;
-}
-
-
-/**
- * Create a challenge message
- *
- * @param ctx the execution context
- * @return the challenge message
- */
-static struct GNUNET_MessageHeader *
-create_challenge_message (struct ExecCtx *ctx)
-{
- struct MSH_MSG_Challenge *msg;
- uint16_t size;
-
- GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, &ctx->salt);
- size = sizeof (struct MSH_MSG_Challenge);
- msg = GNUNET_malloc (size);
- msg->header.type = htons (MSH_MTYPE_CHALLENGE);
- msg->header.size = htons (size);
- GNUNET_CRYPTO_hash_to_enc (&ctx->salt, &msg->salt);
- LOG_DEBUG ("Challenge nonce: %104s\n", msg->salt.encoding);
- return &msg->header;
-}
-
-
-/**
- * Functions with this signature are called whenever a message is
- * received.
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_addresslookup (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader* message)
-{
- const struct MSH_MSG_AddressLookup *msg;
- struct MSH_MSG_AddressLookupReply *reply;
- struct InstanceAddr *iaddr;
- char *emsg;
- in_addr_t ip;
- uint16_t port;
- uint16_t reply_size;
-
- emsg = NULL;
- port = 0;
- msg = (const struct MSH_MSG_AddressLookup *) message;
- ip = ntohl (msg->ip);
- if (GNUNET_NO == reversemap_check (rmap, ip))
- {
- emsg = "Given IP address not present in the current mapping\n";
- goto respond;
- }
- iaddr = reversemap_lookup (rmap, ip);
- GNUNET_assert (NULL != iaddr);
- port = instance_address_port (iaddr);
- LOG_DEBUG ("Received ADDRESS_LOOKUP message for IP: %s and port %u\n",
- ip2str (ip), port);
- respond:
- reply_size = sizeof (struct MSH_MSG_AddressLookupReply);
- if (NULL != emsg)
- reply_size += strlen (emsg) + 1;
- reply = GNUNET_malloc (reply_size);
- reply->header.size = htons (reply_size);
- reply->header.type = htons (MSH_MTYPE_ADDRESS_LOOKUP_REPLY);
- reply->port = htons (port);
- if (NULL != emsg)
- (void) strcpy (reply->emsg, emsg);
- GNUNET_SERVER_notification_context_unicast (local_serv_nc, client,
- &reply->header, GNUNET_NO);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Generate the credential for the given challenge
- *
- * @param c the challenge
- * @param cred output parameter for the credential
- */
-static void
-auth_challenge_cred (struct GNUNET_HashCode *c, struct GNUNET_HashCode *cred)
-{
- struct GNUNET_HashCode xor;
-
- GNUNET_CRYPTO_hash_xor (c, &shash, &xor);
- GNUNET_CRYPTO_hash (&xor, sizeof (struct GNUNET_HashCode), cred);
-}
-
-
-/**
- * Functions with this signature are called whenever a message is
- * received.
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_auth_challenge (void *cls, struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader* message)
-{
- const struct MSH_MSG_Challenge *msg;
- struct MSH_MSG_ChallengeResponse *reply;
- struct GNUNET_HashCode salt;
- struct GNUNET_HashCode cred;
-
- msg = (const struct MSH_MSG_Challenge *) message;
- LOG_DEBUG ("Challenge nonce: %104s\n", msg->salt.encoding);
- GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_hash_from_string
- ((const char *) msg->salt.encoding, &salt));
- auth_challenge_cred (&salt, &cred);
- reply = GNUNET_malloc (sizeof (struct MSH_MSG_ChallengeResponse));
- reply->header.size = htons (sizeof (struct MSH_MSG_ChallengeResponse));
- reply->header.type = htons (MSH_MTYPE_CHALLENGE_RESPONSE);
- GNUNET_CRYPTO_hash_to_enc (&cred, &reply->auth);
- GNUNET_SERVER_notification_context_unicast (local_serv_nc, client,
- &reply->header, GNUNET_NO);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
-}
-
-
-/**
- * Function to call for access control checks.
- *
- * @param cls closure
- * @param ucred credentials, if available, otherwise NULL
- * @param addr address
- * @param addrlen length of address
- * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
- * for unknown address family (will be denied).
- */
-static int
-check_local_access (void *cls,
- const struct GNUNET_CONNECTION_Credentials *cred,
- const struct sockaddr * addr, socklen_t addrlen)
-{
- if ((our_uid != cred->uid) && (our_gid != cred->gid))
- return GNUNET_NO;
- return GNUNET_YES;
-}
-
-
-/**
- * Callback to be called when ever a client connects to the local server
- *
- * @param cls NULL
- * @param client the client handle
- */
-static void
-local_server_connect (void *cls, struct GNUNET_SERVER_Client *client)
-{
- if (NULL == client) /* Server shutting down */
- return;
- LOG_DEBUG ("A client has been connected locally\n");
- GNUNET_SERVER_notification_context_add (local_serv_nc, client);
-}
-
-
-/**
- * Initialise the local server
- *
- * @param unixpath the name to use while opening the abstract UNIX domain
socket
- * for listening
- * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
- */
-int
-init_local_server (const char *unixpath)
-{
- struct sockaddr_un saddr;
- static const struct GNUNET_SERVER_MessageHandler handlers[] = {
- {&handle_addresslookup, NULL, MSH_MTYPE_ADDRESS_LOOKUP, sizeof (struct
- MSH_MSG_AddressLookup)},
- {&handle_auth_challenge, NULL, MSH_MTYPE_CHALLENGE, sizeof (struct
MSH_MSG_Challenge)},
- {NULL, NULL, 0, 0}
- };
- struct sockaddr *saddrs[] = {
- ((struct sockaddr *) &saddr),
- NULL
- };
- socklen_t saddr_lens[] = {
- sizeof (struct sockaddr_un),
- 0
- };
-
- our_uid = getuid ();
- our_gid = getgid ();
- saddr.sun_family = AF_UNIX;
- (void) memset (saddr.sun_path, 0, sizeof (saddr.sun_path));
- (void) strncpy (saddr.sun_path, unixpath, sizeof (saddr.sun_path) - 1);
- local_serv = GNUNET_SERVER_create (&check_local_access, NULL,
- saddrs,
- saddr_lens,
- GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_YES);
- if (NULL == local_serv)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- GNUNET_SERVER_add_handlers (local_serv, handlers);
- GNUNET_SERVER_connect_notify (local_serv, &local_server_connect, NULL);
- local_serv_nc = GNUNET_SERVER_notification_context_create (local_serv, 1);
- return GNUNET_OK;
-}
-
-
-/**
- * Shutdown the local server
- */
-void
-shutdown_local_server ()
-{
- if (NULL != local_serv)
- {
- GNUNET_SERVER_destroy (local_serv);
- local_serv = NULL;
- }
-}
-
-
-/******************************************************************************/
-/* Daemon server. Responsbile for executing commands submitted by remote MSH
*/
-/* clients
*/
-/******************************************************************************/
-
-
-/**
- * Handle session open message and start challenge authentication.
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_session_open (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader* message)
-{
- struct ExecCtx *exec_ctx;
- const struct MSH_MSG_SessionOpen *msg;
- struct GNUNET_MessageHeader *reply;
- uint16_t size;
-
- LOG_DEBUG ("Received a SESSION_OPEN message\n");
- exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
- GNUNET_assert (NULL != exec_ctx);
- if (NULL != exec_ctx->args)
- {
- GNUNET_break (0);
- goto close_conn;
- }
- if (MSH_SESSION_TYPE_INTERACTIVE == ntohl (msg->type))
- exec_ctx->interactive = GNUNET_YES;
- reply = create_challenge_message (exec_ctx);
- LOG_DEBUG ("Sending AUTH_CHALLENGE\n");
- GNUNET_SERVER_notification_context_unicast (daemon_serv_nc, client, reply,
- GNUNET_NO);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
-
- close_conn:
- GNUNET_break_op (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-}
-
-
-/**
- * Task to read the output from a process and send it to client
- *
- * @param cls the client context
- * @param tc scheduler task context
- */
-static void
-read_fout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct ExecCtx *exec_ctx = cls;
- struct MSH_MSG_CmdIO *msg;
- static char data[MAX_IO_DATA];
- ssize_t size;
- uint16_t msize;
-
- exec_ctx->fout_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
- {
- return;
- }
- size = GNUNET_DISK_file_read_non_blocking (exec_ctx->fout, data,
MAX_IO_DATA);
- if (size <= 0)
- {
- GNUNET_break (GNUNET_SYSERR != size);
- GNUNET_SERVER_client_disconnect (exec_ctx->client);
- return;
- }
- msize = size + sizeof (struct MSH_MSG_CmdIO);
- msg = GNUNET_malloc (msize);
- msg->header.type = htons (MSH_MTYPE_CMD_STREAM_STDOUT);
- msg->header.size = htons (msize);
- memcpy (msg->data, data, size);
- GNUNET_SERVER_notification_context_unicast (daemon_serv_nc, exec_ctx->client,
- &msg->header, GNUNET_NO);
- exec_ctx->fout_task =
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- exec_ctx->fout, &read_fout, exec_ctx);
-}
-
-
-/**
- * Configure the terminal for the child
- */
-static int
-parse_term_mode (const struct MSH_MSG_PtyMode *msg,
- struct termios *tio,
- struct winsize *ws,
- char **termstr)
-{
- uint16_t *params;
- char *str;
- unsigned int cnt;
- unsigned int ns;
- uint16_t msize;
- size_t expected;
- speed_t ospeed;
- speed_t ispeed;
-
- msize = ntohs (msg->header.size);
- ns = ntohs (msg->nsettings);
- expected = (sizeof (struct MSH_MSG_PtyMode) + (sizeof (uint16_t) * ns * 2));
- if (msize < expected)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
-#define PARSE_WIN_SIZE(field) \
- ws->field = ntohs (msg->field);
- PARSE_WIN_SIZE (ws_row);
- PARSE_WIN_SIZE (ws_col);
- PARSE_WIN_SIZE (ws_xpixel);
- PARSE_WIN_SIZE (ws_ypixel);
-#undef PARSE_WIN_SIZE
- ospeed = baud_to_speed (ntohl (msg->ospeed));
- ispeed = baud_to_speed (ntohl (msg->ispeed));
- if (0 != cfsetospeed (tio, ospeed))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (0 != cfsetispeed (tio, ispeed))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- params = (uint16_t *) &msg[1];
- for (cnt = 0; cnt < ns; cnt++)
- {
- switch (ntohs (params[2 * cnt]))
- {
-#define TTYCHAR(NAME,OP) \
- case OP: \
- tio->c_cc[NAME] = ntohs (params[(2 * cnt)+1]); \
- break;
-#define TTYMODE(NAME, FIELD, OP) \
- case OP: \
- if (1 == ntohs (params[(2 * cnt)+1])) \
- tio->FIELD |= NAME; \
- break;
-#include "ttymodes.h"
-#undef TTYCHAR
-#undef TTYMODE
-
- default:
- GNUNET_assert (0);
- }
- }
- if (0 == (msize - expected))
- return GNUNET_OK;
- str = ((void *) msg) + expected;
- if ('\0' != str[(msize - expected) - 1])
- {
- GNUNET_break (0);
- str = NULL;
- return GNUNET_OK;
- }
- *termstr = GNUNET_strdup (str);
- return GNUNET_OK;
-}
-
-
-/**
- * Callback that will be called when a child processes terminates. The
- * associated client context for the client which requested this process will
be
- * destroyed
- *
- * @param cls the closure passed to MSH_monitor_process()
- * @param type the process status type
- * @param long the return/exit code of the process
- */
-static void
-proc_exit_cb (void *cls, enum GNUNET_OS_ProcessStatusType type, int code)
-{
- struct ExecCtx *exec_ctx = cls;
-
- LOG_DEBUG ("Command `%s' exited.\n", exec_ctx->args[0]);
- exec_ctx->child_pid = 0;
- GNUNET_SCHEDULER_cancel (exec_ctx->fout_task);
- exec_ctx->fout_task = GNUNET_SCHEDULER_add_now (&read_fout, exec_ctx);
-}
-
-
-/**
- * start the process from the execution process
- *
- * @param ctx the execution context
- * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
- */
-static int
-proc_exec (struct ExecCtx *ctx)
-{
- struct GNUNET_DISK_PipeHandle *pin;
- struct GNUNET_DISK_PipeHandle *pout;
- struct GNUNET_OS_Process *proc;
- char *fnpty;
- char *termstr;
- struct winsize ws;
- struct termios tio;
- int ret;
- int slave;
-
- if (!ctx->interactive)
- {
- pin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, 0, 0);
- pout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_YES, 0, 0);
- GNUNET_assert ((NULL != pin && (NULL != pout)));
- proc = GNUNET_OS_start_process_vap (GNUNET_NO,
- GNUNET_OS_INHERIT_STD_NONE,
- pin,
- pout,
- ctx->args[0],
- ctx->args);
- if (NULL == proc)
- return GNUNET_SYSERR;
- ctx->child_pid = GNUNET_OS_process_get_pid (proc);
- GNUNET_OS_process_destroy (proc);
- MSH_monitor_process_pid (ctx->child_pid, &proc_exit_cb, ctx);
- ctx->fin = GNUNET_DISK_pipe_detach_end (pin, GNUNET_DISK_PIPE_END_WRITE);
- ctx->fout = GNUNET_DISK_pipe_detach_end (pout, GNUNET_DISK_PIPE_END_READ);
- GNUNET_assert ((NULL != ctx->fin && (NULL != ctx->fout)));
- GNUNET_assert (GNUNET_OK == GNUNET_DISK_pipe_close (pin));
- GNUNET_assert (GNUNET_OK == GNUNET_DISK_pipe_close (pout));
- ctx->fout_task =
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- ctx->fout, &read_fout, ctx);
- return GNUNET_OK;
- }
- if (NULL == (fnpty = ptsname (ctx->master)))
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "ptsname");
- return GNUNET_SYSERR;
- }
- ret = fork ();
- if (-1 == ret)
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
- return GNUNET_SYSERR;
- }
- if (0 != ret)
- {
- int fd;
-
- LOG_DEBUG ("Forked child successfully\n");
- ctx->child_pid = ret;
- MSH_monitor_process_pid (ctx->child_pid, &proc_exit_cb, ctx);
- /* forward streams to and from child */
- ctx->fin = GNUNET_DISK_get_handle_from_int_fd (ctx->master);
- fd = dup (ctx->master);
- if (-1 == fd)
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup");
- GNUNET_assert (0 == kill (ret, SIGTERM));
- return GNUNET_SYSERR;
- }
- ctx->fout = GNUNET_DISK_get_handle_from_int_fd (fd);
- ctx->fout_task =
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
ctx->fout,
- &read_fout, ctx);
-
- return GNUNET_OK;
- }
- close (ctx->master);
- LOG_DEBUG ("Opening slave PTY %s\n", fnpty);
- slave = open (fnpty, O_RDWR);
- if (-1 == slave)
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "open");
- _exit (1);
- }
- if (-1 == tcgetattr (slave, &tio))
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "tcgetattr");
- _exit (1);
- }
- termstr = NULL;
- parse_term_mode (ctx->pty_mode, &tio, &ws, &termstr);
- GNUNET_free (ctx->pty_mode);
- ctx->pty_mode = NULL;
- if (NULL != termstr)
- {
- GNUNET_break (0 == setenv ("TERM", termstr, 1));
- GNUNET_free (termstr);
- }
- else
- GNUNET_break (0 == setenv ("TERM", "MSH", 1));
- if (-1 == tcsetattr (slave, TCSANOW, &tio))
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "tcsetattr");
- //_exit (1); /* Ignore for now */
- }
- if (-1 == ioctl (slave, TIOCSWINSZ, &ws))
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "ioctl");
- _exit (1);
- }
- if (-1 == setsid ())
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsid");
- _exit (1);
- }
- close (0);
- close (1);
- //close (2);
- if ( (-1 == dup2 (slave, 0)) ||
- (-1 == dup2 (slave, 1)) ) //||
- //(-1 == dup2 (slave, 2)) )
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup");
- _exit (2);
- }
- close (slave);
- LOG_DEBUG ("Execing %s\n", ctx->args[0]);
- if (-1 == execvp (ctx->args[0], ctx->args))
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "execvp");
- _exit (1);
- }
- GNUNET_assert (0); /* This should never be reached */
-}
-
-
-/**
- * Handle session open message and start challenge authentication.
- *
- * @param cls closure
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_runcmd (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader* message)
-{
- const struct MSH_MSG_RunCmd *msg;
- struct ExecCtx *exec_ctx;
- struct GNUNET_MessageHeader *reply;
- uint16_t size;
-
- LOG_DEBUG ("Received a RUN_CMD message\n");
- exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
- GNUNET_assert (NULL != exec_ctx);
- if (GNUNET_YES != exec_ctx->authenticated)
- {
- GNUNET_break_op (0);
- goto close_conn;
- }
- if (exec_ctx->interactive && !exec_ctx->pty_created)
- {
- GNUNET_break_op (0);
- goto close_conn;
- }
- if (NULL != exec_ctx->args)
- {
- GNUNET_break (0);
- goto close_conn;
- }
- size = ntohs (message->size);
- if ( size <= sizeof (struct MSH_MSG_RunCmd))
- {
- GNUNET_break_op (0);
- goto close_conn;
- }
- msg = (const struct MSH_MSG_RunCmd *) message;
- if (0 == parse_strings (msg->cmd,
- size - sizeof (struct MSH_MSG_RunCmd),
- &exec_ctx->args))
- {
- GNUNET_break_op (0);
- goto close_conn;
- }
- GNUNET_SCHEDULER_cancel (exec_ctx->timeout_task);
- exec_ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
- if (GNUNET_OK != proc_exec (exec_ctx))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- "Command `%s' not found or not executable\n", exec_ctx->args[0]);
- goto close_conn;
- }
- reply = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader));
- reply->size = htons (sizeof (struct GNUNET_MessageHeader));
- reply->type = htons (MSH_MTYPE_EXEC_BEGIN);
- GNUNET_SERVER_notification_context_unicast (daemon_serv_nc, exec_ctx->client,
- reply, GNUNET_NO);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
-
- close_conn:
- GNUNET_break_op (0);
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-}
-
-
-/**
- * Functions with this signature are called whenever a message is
- * received.
- *
- * @param cls NULL
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_auth_challenge_response (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader* message)
-{
- const struct MSH_MSG_ChallengeResponse *msg;
- struct GNUNET_MessageHeader *reply;
- struct ExecCtx *exec_ctx;
- struct GNUNET_HashCode cred;
- struct GNUNET_CRYPTO_HashAsciiEncoded enc;
-
- exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
- GNUNET_assert (NULL != exec_ctx);
- auth_challenge_cred (&exec_ctx->salt, &cred);
- GNUNET_CRYPTO_hash_to_enc (&cred, &enc);
- msg = (const struct MSH_MSG_ChallengeResponse *) message;
- if (0 != memcmp (&msg->auth, &enc,
- sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
- {
- LOG_DEBUG ("Auth failed: \n"
- " Required: %s\n"
- " Given: %s\n", enc.encoding, msg->auth.encoding);
- GNUNET_break (0);
- goto err_ret;
- }
- exec_ctx->authenticated = GNUNET_YES;
- return;
-
- err_ret:
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-}
-
-
-/**
- * Task to write data from input buffer to proc's STDIN
- *
- * @param cls the client context
- * @return tc scheduler task context
- */
-static void
-write_fin (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct ExecCtx *exec_ctx = cls;
- ssize_t wrote;
-
- exec_ctx->fin_task = GNUNET_SCHEDULER_NO_TASK;
- if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))
- {
- GNUNET_free (exec_ctx->buf);
- exec_ctx->buf = NULL;
- exec_ctx->bufsize = 0;
- goto err_ret;
- }
- wrote = GNUNET_DISK_file_write (exec_ctx->fin,
- exec_ctx->buf, exec_ctx->bufsize);
- if (GNUNET_SYSERR == wrote)
- {
- LOG_ERROR ("Error writing to proc's STDIN\n");
- goto err_ret;
- }
- if (wrote == exec_ctx->bufsize)
- {
- GNUNET_free (exec_ctx->buf);
- exec_ctx->buf = NULL;
- exec_ctx->bufsize = 0;
- GNUNET_SERVER_receive_done (exec_ctx->client, GNUNET_OK);
- return;
- }
- GNUNET_assert (wrote < exec_ctx->bufsize);
- exec_ctx->bufsize -= wrote;
- exec_ctx->buf = memmove (exec_ctx->buf, exec_ctx->buf + wrote,
- exec_ctx->bufsize);
- exec_ctx->buf = GNUNET_realloc (exec_ctx->buf, exec_ctx->bufsize);
- exec_ctx->fin_task =
- GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
- exec_ctx->fin,
- &write_fin, exec_ctx);
- return;
-
- err_ret:
- GNUNET_SERVER_receive_done (exec_ctx->client, GNUNET_SYSERR);
-}
-
-
-/**
- * Handler for messages with command's input stream data. The date will be
- * written to the command's standard input stream.
- *
- * @param cls NULL
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_command_input (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader* message)
-{
- const struct MSH_MSG_CmdIO *msg;
- struct ExecCtx *exec_ctx;
- ssize_t wrote;
- uint16_t size;
-
- LOG_DEBUG ("Received CMD_IO_STDIN message\n");
- size = ntohs (message->size);
- msg = (const struct MSH_MSG_CmdIO *) message;
- exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
- GNUNET_assert (NULL != exec_ctx);
- size -= sizeof (struct MSH_MSG_CmdIO);
- wrote = GNUNET_DISK_file_write (exec_ctx->fin, msg->data, size);
- if (GNUNET_SYSERR == wrote)
- {
- LOG_ERROR ("Error writing to proc's STDIN\n");
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
- return;
- }
- LOG_DEBUG ("Wrote %zd to proc's STDIN\n", wrote);
- if (wrote == size)
- {
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
- }
- GNUNET_assert (wrote < size);
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == exec_ctx->fin_task);
- GNUNET_assert (NULL == exec_ctx->buf);
- GNUNET_assert (0 == exec_ctx->bufsize);
- exec_ctx->bufsize = size - wrote;
- exec_ctx->buf = GNUNET_malloc (exec_ctx->bufsize);
- (void) memcpy (exec_ctx->buf, msg->data + wrote, exec_ctx->bufsize);
- exec_ctx->fin_task =
- GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
- exec_ctx->fin,
- &write_fin, exec_ctx);
- GNUNET_SERVER_disable_receive_done_warning (client);
-}
-
-
-/**
- * Handler for messages containing the settings to be used while creating a
- * psuedo-tty. This message must only be received for interactive sessions
- * before #MSH_MSG_RunCmd message is received.
- *
- * @param cls NULL
- * @param client identification of the client
- * @param message the actual message
- */
-static void
-handle_pty_mode (void *cls,
- struct GNUNET_SERVER_Client *client,
- const struct GNUNET_MessageHeader* message)
-{
- struct winsize ws;
- struct termios tio;
- const struct MSH_MSG_PtyMode *msg;
- uint16_t *params;
- char *termstr;
- struct ExecCtx *exec_ctx;
- size_t expected;
- speed_t ospeed;
- speed_t ispeed;
- int master;
- unsigned int cnt;
- unsigned int ns;
- uint16_t size;
-
- size = ntohs (message->size);
- if (size <= sizeof (struct MSH_MSG_PtyMode))
- {
- GNUNET_break (0);
- goto close_conn;
- }
- exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
- GNUNET_assert (NULL != exec_ctx);
- msg = (const struct MSH_MSG_PtyMode *) message;
- master = posix_openpt (O_RDWR);
- if (-1 == master)
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "posix_openpt");
- goto close_conn;
- }
- if (-1 == grantpt (master))
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "grantpt");
- goto close_conn;
- }
- if (-1 == unlockpt (master))
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "unlockpt");
- goto close_conn;
- }
- exec_ctx->master = master;
- exec_ctx->pty_created = GNUNET_YES;
- exec_ctx->pty_mode = (struct MSH_MSG_PtyMode *) GNUNET_copy_message
(message);
- GNUNET_SERVER_receive_done (client, GNUNET_OK);
- return;
-
- close_conn:
- GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
-}
-
-
-/**
- * Callback to be called when ever a client connects to the daemon server
- *
- * @param cls NULL
- * @param client the client handle
- */
-static void
-daemon_server_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
-{
- struct ExecCtx *exec_ctx;
-
- if (NULL == client)
- return;
- LOG_DEBUG ("A remote client has disconnected\n");
- exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
- GNUNET_assert (NULL != exec_ctx);
- destroy_exec_ctx (exec_ctx);
-}
-
-
-/**
- * Initialises the server which spawns processes and forwards it stdin and
stdout
- *
- * @param h the network handle of the socket to listen for incoming connections
- */
-int
-init_daemon_server ()
-{
- static const struct GNUNET_SERVER_MessageHandler handlers[] = {
- {&handle_session_open, NULL, MSH_MTYPE_SESSION_OPEN,
- sizeof (struct MSH_MSG_SessionOpen)},
- {&handle_runcmd, NULL, MSH_MTYPE_RUNCMD, 0},
- {&handle_auth_challenge_response, NULL, MSH_MTYPE_CHALLENGE_RESPONSE,
- sizeof (struct MSH_MSG_ChallengeResponse)},
- {&handle_command_input, NULL, MSH_MTYPE_CMD_STREAM_STDIN, 0},
- {&handle_pty_mode, NULL, MSH_MTYPE_PTY_MODE, 0},
- {NULL, NULL, 0, 0}
- };
-
- daemon_serv = GNUNET_SERVER_create_with_sockets (NULL,
- NULL,
- NULL,
-
GNUNET_TIME_UNIT_FOREVER_REL,
- GNUNET_YES);
- if (NULL == daemon_serv)
- return GNUNET_SYSERR;
- GNUNET_SERVER_add_handlers (daemon_serv, handlers);
- GNUNET_SERVER_disconnect_notify (daemon_serv, &daemon_server_disconnect,
NULL);
- daemon_serv_nc = GNUNET_SERVER_notification_context_create (daemon_serv, 1);
- return GNUNET_OK;
-}
-
-
-/**
- * Timeout task for timing out connections until they authenticate. Once
- * authenticated the connection will not be timed out.
- *
- * @param cls the client context
- * @param tc scheduler task context
- */
-static void
-timeout_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- struct ExecCtx *exec_ctx = cls;
-
- exec_ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
- GNUNET_SERVER_client_disconnect (exec_ctx->client);
-}
-
-
-/**
- * Create a client for the daemon server from a new client connection
- *
- * @param conn the connection to derive the client from
- */
-void
-daemon_server_add_connection (struct GNUNET_CONNECTION_Handle *conn)
-{
- struct ExecCtx *exec_ctx;
- struct GNUNET_SERVER_Client *client;
-
- exec_ctx = GNUNET_malloc (sizeof (struct ExecCtx));
- client = GNUNET_SERVER_connect_socket (daemon_serv, conn);
- exec_ctx->client = client;
- GNUNET_SERVER_client_set_user_context (client, exec_ctx);
- GNUNET_SERVER_notification_context_add (daemon_serv_nc, client);
- exec_ctx->timeout_task =
- GNUNET_SCHEDULER_add_delayed (TIMEOUT_SECS (30), &timeout_cb, exec_ctx);
-}
-
-
-/**
- * Shutdown the daemon server
- */
-void
-shutdown_daemon_server ()
-{
- if (NULL != daemon_serv)
- {
- GNUNET_SERVER_destroy (daemon_serv);
- daemon_serv = NULL;
- }
- if (NULL != daemon_serv_nc)
- {
- GNUNET_SERVER_notification_context_destroy (daemon_serv_nc);
- daemon_serv_nc = NULL;
- }
-}
-
-/* End of mshd-server.c */
Modified: msh/src/mshd.c
===================================================================
--- msh/src/mshd.c 2013-11-20 10:55:44 UTC (rev 30826)
+++ msh/src/mshd.c 2013-11-20 13:58:08 UTC (rev 30827)
@@ -126,15 +126,21 @@
* connections are used to verify which IP addresses of this instance are
* reachable from other instances
*/
- LISTEN_MODE_PROBE,
+ MODE_PROBE,
/**
* In this mode the listen socket accepts requests for starting remote
processes
*/
- LISTEN_MODE_SERV
-} listen_mode;;
+ MODE_SERV,
+ /**
+ * Worker mode
+ */
+ MODE_WORKER
+} mode;
+
+
/**
* Mapping for instance addresses
*/
@@ -199,7 +205,7 @@
/**
* Task for asynchronous accept on the socket
*/
-static GNUNET_SCHEDULER_TaskIdentifier atask;
+static GNUNET_SCHEDULER_TaskIdentifier accept_task;
/**
* Task for finalising a round
@@ -274,6 +280,43 @@
/**
+ * Function to copy NULL terminated list of arguments
+ *
+ * @param argv the NULL terminated list of arguments. Cannot be NULL.
+ * @return the copied NULL terminated arguments
+ */
+static char **
+copy_argv (char *const *argv)
+{
+ char **argv_dup;
+ unsigned int argp;
+
+ GNUNET_assert (NULL != argv);
+ for (argp = 0; NULL != argv[argp]; argp++) ;
+ argv_dup = GNUNET_malloc (sizeof (char *) * (argp + 1));
+ for (argp = 0; NULL != argv[argp]; argp++)
+ argv_dup[argp] = strdup (argv[argp]);
+ return argv_dup;
+}
+
+
+/**
+ * Frees the given NULL terminated arguments
+ *
+ * @param argv the NULL terminated list of arguments
+ */
+static void
+free_argv (char **argv)
+{
+ unsigned int argp;
+
+ for (argp = 0; NULL != argv[argp]; argp++)
+ GNUNET_free (argv[argp]);
+ GNUNET_free (argv);
+}
+
+
+/**
* Perform cleanup for shutdown
*
* @param cls NULL
@@ -283,9 +326,58 @@
do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
shutdown_task = GNUNET_SCHEDULER_NO_TASK;
- shutdown_local_server ();
- shutdown_daemon_server ();
- MSH_pmonitor_shutdown ();
+ switch (mode)
+ {
+ case MODE_PROBE:
+ break;
+ case MODE_SERV:
+ shutdown_local_server ();
+ MSH_pmonitor_shutdown ();
+ break;
+ case MODE_WORKER:
+ shutdown_daemon_server ();
+ break;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != accept_task)
+ {
+ GNUNET_SCHEDULER_cancel (accept_task);
+ accept_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != listen_socket)
+ {
+ GNUNET_NETWORK_socket_close (listen_socket);
+ listen_socket = NULL;
+ }
+ if (NULL != bitmap)
+ {
+ bitmap_destroy (bitmap);
+ bitmap = NULL;
+ }
+ if (NULL != addrmap)
+ {
+ addressmap_destroy (addrmap);
+ addrmap = NULL;
+ }
+ if (NULL != rmap)
+ {
+ reverse_map_destroy (rmap);
+ rmap = NULL;
+ }
+ GNUNET_free_non_null (s_addrs);
+ s_addrs = NULL;
+ if (NULL != run_args)
+ {
+ free_argv (run_args);
+ run_args = NULL;
+ }
+ GNUNET_free_non_null (unixpath);
+ unixpath = NULL;
+ if (NULL != hostsfile)
+ {
+ (void) unlink (hostsfile);
+ GNUNET_free (hostsfile);
+ hostsfile = NULL;
+ }
}
@@ -362,25 +454,56 @@
/**
+ * Fork a worker process. This process forks a child which initiates the MSH
+ * execution protocol. Once the protocol authenticates the connecting client,
+ * it then forks and execs the remote command.
+ */
+static pid_t
+spawn_worker ()
+{
+ struct GNUNET_NETWORK_Handle *sock;
+ struct GNUNET_CONNECTION_Handle *conn;
+ pid_t ret;
+
+ ret = fork ();
+ if (0 != ret)
+ return ret;
+ /* Child process continues here */
+ GNUNET_assert (MODE_SERV == mode);
+ GNUNET_assert (NULL != listen_socket);
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+ shutdown_task = GNUNET_SCHEDULER_NO_TASK;
+ do_shutdown (NULL, NULL);
+ sock = GNUNET_NETWORK_socket_accept (listen_socket, NULL, NULL);
+ conn = GNUNET_CONNECTION_create_from_existing (sock);
+ mode = MODE_WORKER;
+ init_daemon_server ();
+ daemon_server_add_connection (conn);
+ return 0;
+}
+
+
+/**
* Task to call accept and close on a listening socket
*
* @param cls NULL
* @param tc the scheduler task context
*/
static void
-accept_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+accept_conn (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
struct ReadContext *rctx;
struct GNUNET_CONNECTION_Handle *conn;
+ pid_t pid;
- atask = GNUNET_SCHEDULER_NO_TASK;
+ accept_task = GNUNET_SCHEDULER_NO_TASK;
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
{
goto clo_ret;
}
- switch (listen_mode)
+ switch (mode)
{
- case LISTEN_MODE_PROBE:
+ case MODE_PROBE:
LOG_DEBUG ("%d: Got a probe connect\n", rank);
conn = GNUNET_CONNECTION_create_from_accept (NULL, NULL, listen_socket);
if (NULL == conn)
@@ -395,22 +518,22 @@
GNUNET_TIME_UNIT_FOREVER_REL, conn_reader,
rctx);
GNUNET_CONTAINER_DLL_insert_tail (rhead, rtail, rctx);
break;
- case LISTEN_MODE_SERV:
+ case MODE_SERV:
+ pid = spawn_worker ();
+ if (-1 == pid)
{
- struct GNUNET_NETWORK_Handle *client_sock;
- struct GNUNET_CONNECTION_Handle *client_conn;
-
- LOG_DEBUG ("Got a command execution connection\n");
- client_sock = GNUNET_NETWORK_socket_accept (listen_socket, NULL, NULL);
- client_conn = GNUNET_CONNECTION_create_from_existing (client_sock);
- daemon_server_add_connection (client_conn);
+ GNUNET_break (0);
+ GNUNET_SCHEDULER_shutdown ();
+ goto clo_ret;
}
+ if (0 == pid) /* state is cleared and hence we return */
+ return;
break;
- default:
+ case MODE_WORKER:
GNUNET_assert (0);
}
- atask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
- listen_socket, &accept_task, NULL);
+ accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+ listen_socket, &accept_conn, NULL);
return;
clo_ret:
@@ -531,10 +654,7 @@
LOG_DEBUG ("Verification phase complete; commencing reduction phase\n");
GNUNET_break (GNUNET_OK == reduce_ntree ());
addressmap_print (addrmap);
- listen_mode = LISTEN_MODE_SERV;
rmap = addressmap_create_reverse_mapping (addrmap);
- shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
- &do_shutdown, NULL);
pid = (intmax_t) getpid ();
GNUNET_assert (0 < asprintf (&unixpath, "%ju.sock", pid));
hostsfile = GNUNET_DISK_mktemp ("MSHD_HOSTS");
@@ -546,11 +666,11 @@
setenv (MSHD_HOSTSFILE, hostsfile, 1);
setenv (MSHD_SOCK_NAME, unixpath, 1);
init_local_server (unixpath);
- init_daemon_server ();
MSH_pmonitor_init ();
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == atask);
- atask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
- listen_socket, &accept_task, NULL);
+ mode = MODE_SERV;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == accept_task);
+ accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+ listen_socket, &accept_conn, NULL);
if (0 == rank)
{
proc = GNUNET_OS_start_process_vap (GNUNET_NO,
@@ -605,8 +725,8 @@
unsigned int cnt;
finalise_task = GNUNET_SCHEDULER_NO_TASK;
- GNUNET_SCHEDULER_cancel (atask);
- atask = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_SCHEDULER_cancel (accept_task);
+ accept_task = GNUNET_SCHEDULER_NO_TASK;
while (NULL != (ctx = vactx_head))
{
cleanup_verifyaddressctx (ctx);
@@ -986,8 +1106,8 @@
return GNUNET_SYSERR;
if (NULL == (riainfos = receive_addresses ()))
return GNUNET_SYSERR;
- atask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
- listen_socket, &accept_task, NULL);
+ accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
+ listen_socket, &accept_conn,
NULL);
if (MPI_SUCCESS != MPI_Barrier (MPI_COMM_WORLD))
{
@@ -1018,43 +1138,6 @@
/**
- * Function to copy NULL terminated list of arguments
- *
- * @param argv the NULL terminated list of arguments. Cannot be NULL.
- * @return the copied NULL terminated arguments
- */
-static char **
-copy_argv (char *const *argv)
-{
- char **argv_dup;
- unsigned int argp;
-
- GNUNET_assert (NULL != argv);
- for (argp = 0; NULL != argv[argp]; argp++) ;
- argv_dup = GNUNET_malloc (sizeof (char *) * (argp + 1));
- for (argp = 0; NULL != argv[argp]; argp++)
- argv_dup[argp] = strdup (argv[argp]);
- return argv_dup;
-}
-
-
-/**
- * Frees the given NULL terminated arguments
- *
- * @param argv the NULL terminated list of arguments
- */
-static void
-free_argv (char **argv)
-{
- unsigned int argp;
-
- for (argp = 0; NULL != argv[argp]; argp++)
- GNUNET_free (argv[argp]);
- GNUNET_free (argv);
-}
-
-
-/**
* Main function that will be run.
*
* @param cls closure
@@ -1110,6 +1193,8 @@
return;
}
schedule_next_round ();
+ shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &do_shutdown, NULL);
return;
clo_ret:
@@ -1168,26 +1253,10 @@
ret = 0;
fail:
- if (NULL != bitmap)
- {
- bitmap_destroy (bitmap);
- bitmap = NULL;
- }
- if (NULL != addrmap)
- addressmap_destroy (addrmap);
- if (NULL != rmap)
- reverse_map_destroy (rmap);
- GNUNET_free_non_null (s_addrs);
- if (NULL != run_args)
- free_argv (run_args);
- GNUNET_free_non_null (unixpath);
- if (NULL != hostsfile)
- {
- (void) unlink (hostsfile);
- GNUNET_free (hostsfile);
- }
- LOG_DEBUG ("Finalizing\n");
+ if (MODE_WORKER == mode)
+ return ret;
+ LOG_DEBUG ("Finalizing...\n");
GNUNET_break (MPI_SUCCESS == MPI_Finalize());
- LOG_DEBUG ("Returning\n");
+ LOG_DEBUG ("Done\n");
return ret;
}
Deleted: msh/src/mshd_pmonitor.c
===================================================================
--- msh/src/mshd_pmonitor.c 2013-11-20 10:55:44 UTC (rev 30826)
+++ msh/src/mshd_pmonitor.c 2013-11-20 13:58:08 UTC (rev 30827)
@@ -1,314 +0,0 @@
-/**
- * @file mshd_pmonitor.c
- * @brief process monitoring functions
- * @author Sree Harsha Totakura <address@hidden>
- */
-
-#include "common.h"
-#include "gnunet/gnunet_util_lib.h"
-#include "mshd_pmonitor.h"
-
-/**
- * Generic logging shortcut
- */
-#define LOG(kind, ...) \
- GNUNET_log_from (kind, "mshd-pmonitor", __VA_ARGS__)
-
-/**
- * Debug logging shorthand
- */
-#define LOG_DEBUG(...) \
- LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
-
-
-struct MonitorCtx
-{
- /**
- * Termination notification callback
- */
- MSH_ProcExitCallback cb;
-
- /**
- * closure for the above callback
- */
- void *cls;
-};
-
-/**
- * Task to kill the child
- */
-static GNUNET_SCHEDULER_TaskIdentifier child_death_task_id;
-
-/**
- * Pipe used to communicate shutdown via signal.
- */
-static struct GNUNET_DISK_PipeHandle *sigpipe;
-
-/**
- * Signal context for SIGCHLD
- */
-static struct GNUNET_SIGNAL_Context *shc_chld;
-
-/**
- * hashmap for storing process monitoring context
- */
-static struct GNUNET_CONTAINER_MultiHashMap32 *map;
-
-
-/**
- * Task triggered whenever we receive a SIGCHLD (child
- * process died).
- *
- * @param cls closure, NULL if we need to self-restart
- * @param tc context
- */
-static void
-child_death_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
-{
- const struct GNUNET_DISK_FileHandle *pr;
- struct MonitorCtx *ctx;
- MSH_ProcExitCallback cb;
- void *cb_cls;
- char c[16];
- enum GNUNET_OS_ProcessStatusType type;
- int status;
- pid_t cid;
- int code;
-
- cb = NULL;
- pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
- child_death_task_id = GNUNET_SCHEDULER_NO_TASK;
- if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
- {
- child_death_task_id =
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- pr, &child_death_task, NULL);
- return;
- }
- /* consume the signal */
- GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
- LOG_DEBUG ("Got SIGCHLD\n");
- cid = waitpid (-1, &status, WNOHANG);
- if (0 == cid)
- {
- LOG_DEBUG ("Child hasn't died. Resuming to monitor its status\n");
- goto resume;
- }
- if (-1 == cid)
- {
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "wait");
- goto resume;
- }
- type = GNUNET_OS_PROCESS_UNKNOWN;
- if (WIFEXITED (status))
- {
- type = GNUNET_OS_PROCESS_EXITED;
- code = WEXITSTATUS (status);
- }
- if (WIFSIGNALED (status))
- {
- type = GNUNET_OS_PROCESS_SIGNALED;
- code = WTERMSIG (status);
- }
- if (GNUNET_OS_PROCESS_UNKNOWN == type)
- {
- GNUNET_break (0);
- goto resume;
- }
- ctx = GNUNET_CONTAINER_multihashmap32_get (map, (uint32_t) cid);
- if (NULL == ctx)
- goto resume;
- cb = ctx->cb;
- cb_cls = ctx->cls;
- GNUNET_CONTAINER_multihashmap32_remove (map, (uint32_t) cid, ctx);
- GNUNET_free (ctx);
-
- resume:
- child_death_task_id =
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- pr, &child_death_task, NULL);
- if (NULL != cb)
- cb (cb_cls, type, code);
-}
-
-
-/**
- * Signal handler called for SIGCHLD.
- */
-static void
-sighandler_child_death ()
-{
- static char c;
- int old_errno; /* back-up errno */
-
- old_errno = errno;
- GNUNET_break (1 ==
- GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
- (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
- &c, sizeof (c)));
- errno = old_errno;
-}
-
-
-/**
- * Initialise process monitoring subsystem. Registers SIGCHLD signal handler
- * and the necessary pipe mechanism for reading the signal notification in a
- * safe way
- */
-void
-MSH_pmonitor_init ()
-{
- const struct GNUNET_DISK_FileHandle *pr;
-
- GNUNET_assert (NULL == sigpipe);
- GNUNET_assert (NULL == shc_chld);
- GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == child_death_task_id);
- GNUNET_assert (NULL != (sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO,
- GNUNET_NO, GNUNET_NO)));
- GNUNET_assert (NULL != (shc_chld = GNUNET_SIGNAL_handler_install
- (GNUNET_SIGCHLD, &sighandler_child_death)));
- pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
- map = GNUNET_CONTAINER_multihashmap32_create (10);
- GNUNET_assert (NULL != map);
- child_death_task_id =
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- pr, &child_death_task, NULL);
-
-}
-
-
-/**
- * Iterator over hash map entries.
- *
- * @param cls closure
- * @param key current key code
- * @param value value in the hash map
- * @return GNUNET_YES if we should continue to
- * iterate,
- * GNUNET_NO if not.
- */
-static int
-cleanup_iterator (void *cls, uint32_t key, void *value)
-{
- struct MonitorCtx *ctx = value;
-
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap32_remove (map,
- key,
- ctx));
- GNUNET_free (ctx);
- return GNUNET_YES;
-}
-
-
-/**
- * shutdown process monitoring subsystem
- */
-void
-MSH_pmonitor_shutdown ()
-{
- /* fixme clear monitoring contexts */
- GNUNET_assert (NULL != map);
- GNUNET_break (GNUNET_SYSERR !=
- GNUNET_CONTAINER_multihashmap32_iterate (map,
- &cleanup_iterator,
- NULL));
- GNUNET_CONTAINER_multihashmap32_destroy (map);
- map = NULL;
- GNUNET_assert (NULL != sigpipe);
- GNUNET_assert (NULL != shc_chld);
- if (GNUNET_SCHEDULER_NO_TASK != child_death_task_id)
- {
- GNUNET_SCHEDULER_cancel (child_death_task_id);
- child_death_task_id = GNUNET_SCHEDULER_NO_TASK;
- }
- GNUNET_SIGNAL_handler_uninstall (shc_chld);
- shc_chld = NULL;
- GNUNET_DISK_pipe_close (sigpipe);
- sigpipe = NULL;
-}
-
-
-/**
- * Monitors a process for its termination.
- *
- * @param proc the process to monitor for termination
- * @param cb the callback to be called for notifying the termination of the
- * process
- * @param cls the closure for the above callback
- */
-void
-MSH_monitor_process_pid (pid_t pid,
- MSH_ProcExitCallback cb, void *cls)
-{
- struct MonitorCtx *ctx;
-
- GNUNET_assert (NULL != map);
- ctx = GNUNET_malloc (sizeof (struct MonitorCtx));
- ctx->cb = cb;
- ctx->cls = cls;
- GNUNET_assert
- (GNUNET_OK ==
- GNUNET_CONTAINER_multihashmap32_put (map, (uint32_t) pid, ctx,
-
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
-}
-
-
-/**
- * Monitors a process for its termination.
- *
- * @param proc the process to monitor for termination
- * @param cb the callback to be called for notifying the termination of the
- * process
- * @param cls the closure for the above callback
- */
-void
-MSH_monitor_process (struct GNUNET_OS_Process *proc,
- MSH_ProcExitCallback cb, void *cls)
-{
- pid_t pid;
-
- pid = GNUNET_OS_process_get_pid (proc);
- MSH_monitor_process_pid (pid, cb, cls);
-}
-
-
-/**
- * Stop monitoring a process
- *
- * @param proc
- * @return GNUNET_OK upon success; GNUNET_SYSERR if the process is not being
- * monitored earlier
- */
-int
-MSH_monitor_process_pid_cancel (pid_t pid)
-{
- struct MonitorCtx *ctx;
-
- GNUNET_assert (NULL != map);
- ctx = GNUNET_CONTAINER_multihashmap32_get (map, (uint32_t) pid);
- if (NULL == ctx)
- return GNUNET_SYSERR;
- GNUNET_assert (GNUNET_YES ==
- GNUNET_CONTAINER_multihashmap32_remove
- (map, (uint32_t) pid, ctx));
- GNUNET_free (ctx);
- return GNUNET_OK;
-}
-
-
-/**
- * Stop monitoring a process
- *
- * @param proc
- * @return GNUNET_OK upon success; GNUNET_SYSERR if the process is not being
- * monitored earlier
- */
-int
-MSH_monitor_process_cancel (struct GNUNET_OS_Process *proc)
-{
- pid_t pid;
-
- pid = GNUNET_OS_process_get_pid (proc);
- return MSH_monitor_process_pid_cancel (pid);
-}
Deleted: msh/src/mshd_pmonitor.h
===================================================================
--- msh/src/mshd_pmonitor.h 2013-11-20 10:55:44 UTC (rev 30826)
+++ msh/src/mshd_pmonitor.h 2013-11-20 13:58:08 UTC (rev 30827)
@@ -1,66 +0,0 @@
-/**
- * @file mshd_pmonitor.h
- * @brief interface for process monitoring functions
- * @author Sree Harsha Totakura <address@hidden>
- */
-
-#ifndef MSHD_PMONITOR_H_
-#define MSHD_PMONITOR_H_
-
-#include <gnunet/gnunet_os_lib.h>
-
-/**
- * Initialise process monitoring subsystem. Registers SIGCHLD signal handler
- * and the necessary pipe mechanism for reading the signal notification in a
- * safe way
- */
-void
-MSH_pmonitor_init ();
-
-
-/**
- * shutdown process monitoring subsystem
- */
-void
-MSH_pmonitor_shutdown ();
-
-
-/**
- * Callbacks of this type can be supplied to MSH_monitor_process() to be
- * notified when the corresponding processes exits.
- *
- * @param cls the closure passed to MSH_monitor_process()
- * @param type the process status type
- * @param long the return/exit code of the process
- */
-typedef void (*MSH_ProcExitCallback) (void *cls,
- enum GNUNET_OS_ProcessStatusType type,
- int code);
-
-
-/**
- * Monitors a process for its termination.
- *
- * @param proc the process to monitor for termination
- * @param cb the callback to be called for notifying the termination of the
- * process
- * @param cls the closure for the above callback
- */
-void
-MSH_monitor_process (struct GNUNET_OS_Process *proc,
- MSH_ProcExitCallback cb, void *cls);
-
-
-/**
- * Stop monitoring a process
- *
- * @param proc
- * @return GNUNET_OK upon success; GNUNET_SYSERR if the process is not being
- * monitored earlier
- */
-int
-MSH_monitor_process_cancel (struct GNUNET_OS_Process *proc);
-
-#endif /* MSHD_PMONITOR_H_ */
-
-/* End of mshd_pmonitor.h */
Copied: msh/src/pmonitor.c (from rev 30820, msh/src/mshd_pmonitor.c)
===================================================================
--- msh/src/pmonitor.c (rev 0)
+++ msh/src/pmonitor.c 2013-11-20 13:58:08 UTC (rev 30827)
@@ -0,0 +1,314 @@
+/**
+ * @file pmonitor.c
+ * @brief process monitoring functions
+ * @author Sree Harsha Totakura <address@hidden>
+ */
+
+#include "common.h"
+#include "gnunet/gnunet_util_lib.h"
+#include "pmonitor.h"
+
+/**
+ * Generic logging shortcut
+ */
+#define LOG(kind, ...) \
+ GNUNET_log_from (kind, "mshd-pmonitor", __VA_ARGS__)
+
+/**
+ * Debug logging shorthand
+ */
+#define LOG_DEBUG(...) \
+ LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
+
+
+struct MonitorCtx
+{
+ /**
+ * Termination notification callback
+ */
+ MSH_ProcExitCallback cb;
+
+ /**
+ * closure for the above callback
+ */
+ void *cls;
+};
+
+/**
+ * Task to kill the child
+ */
+static GNUNET_SCHEDULER_TaskIdentifier child_death_task_id;
+
+/**
+ * Pipe used to communicate shutdown via signal.
+ */
+static struct GNUNET_DISK_PipeHandle *sigpipe;
+
+/**
+ * Signal context for SIGCHLD
+ */
+static struct GNUNET_SIGNAL_Context *shc_chld;
+
+/**
+ * hashmap for storing process monitoring context
+ */
+static struct GNUNET_CONTAINER_MultiHashMap32 *map;
+
+
+/**
+ * Task triggered whenever we receive a SIGCHLD (child
+ * process died).
+ *
+ * @param cls closure, NULL if we need to self-restart
+ * @param tc context
+ */
+static void
+child_death_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ const struct GNUNET_DISK_FileHandle *pr;
+ struct MonitorCtx *ctx;
+ MSH_ProcExitCallback cb;
+ void *cb_cls;
+ char c[16];
+ enum GNUNET_OS_ProcessStatusType type;
+ int status;
+ pid_t cid;
+ int code;
+
+ cb = NULL;
+ pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
+ child_death_task_id = GNUNET_SCHEDULER_NO_TASK;
+ if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
+ {
+ child_death_task_id =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ pr, &child_death_task, NULL);
+ return;
+ }
+ /* consume the signal */
+ GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
+ LOG_DEBUG ("Got SIGCHLD\n");
+ cid = waitpid (-1, &status, WNOHANG);
+ if (0 == cid)
+ {
+ LOG_DEBUG ("Child hasn't died. Resuming to monitor its status\n");
+ goto resume;
+ }
+ if (-1 == cid)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "wait");
+ goto resume;
+ }
+ type = GNUNET_OS_PROCESS_UNKNOWN;
+ if (WIFEXITED (status))
+ {
+ type = GNUNET_OS_PROCESS_EXITED;
+ code = WEXITSTATUS (status);
+ }
+ if (WIFSIGNALED (status))
+ {
+ type = GNUNET_OS_PROCESS_SIGNALED;
+ code = WTERMSIG (status);
+ }
+ if (GNUNET_OS_PROCESS_UNKNOWN == type)
+ {
+ GNUNET_break (0);
+ goto resume;
+ }
+ ctx = GNUNET_CONTAINER_multihashmap32_get (map, (uint32_t) cid);
+ if (NULL == ctx)
+ goto resume;
+ cb = ctx->cb;
+ cb_cls = ctx->cls;
+ GNUNET_CONTAINER_multihashmap32_remove (map, (uint32_t) cid, ctx);
+ GNUNET_free (ctx);
+
+ resume:
+ child_death_task_id =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ pr, &child_death_task, NULL);
+ if (NULL != cb)
+ cb (cb_cls, type, code);
+}
+
+
+/**
+ * Signal handler called for SIGCHLD.
+ */
+static void
+sighandler_child_death ()
+{
+ static char c;
+ int old_errno; /* back-up errno */
+
+ old_errno = errno;
+ GNUNET_break (1 ==
+ GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
+ (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
+ &c, sizeof (c)));
+ errno = old_errno;
+}
+
+
+/**
+ * Initialise process monitoring subsystem. Registers SIGCHLD signal handler
+ * and the necessary pipe mechanism for reading the signal notification in a
+ * safe way
+ */
+void
+MSH_pmonitor_init ()
+{
+ const struct GNUNET_DISK_FileHandle *pr;
+
+ GNUNET_assert (NULL == sigpipe);
+ GNUNET_assert (NULL == shc_chld);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == child_death_task_id);
+ GNUNET_assert (NULL != (sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO,
+ GNUNET_NO, GNUNET_NO)));
+ GNUNET_assert (NULL != (shc_chld = GNUNET_SIGNAL_handler_install
+ (GNUNET_SIGCHLD, &sighandler_child_death)));
+ pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
+ map = GNUNET_CONTAINER_multihashmap32_create (10);
+ GNUNET_assert (NULL != map);
+ child_death_task_id =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ pr, &child_death_task, NULL);
+
+}
+
+
+/**
+ * Iterator over hash map entries.
+ *
+ * @param cls closure
+ * @param key current key code
+ * @param value value in the hash map
+ * @return GNUNET_YES if we should continue to
+ * iterate,
+ * GNUNET_NO if not.
+ */
+static int
+cleanup_iterator (void *cls, uint32_t key, void *value)
+{
+ struct MonitorCtx *ctx = value;
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_remove (map,
+ key,
+ ctx));
+ GNUNET_free (ctx);
+ return GNUNET_YES;
+}
+
+
+/**
+ * shutdown process monitoring subsystem
+ */
+void
+MSH_pmonitor_shutdown ()
+{
+ /* fixme clear monitoring contexts */
+ GNUNET_assert (NULL != map);
+ GNUNET_break (GNUNET_SYSERR !=
+ GNUNET_CONTAINER_multihashmap32_iterate (map,
+ &cleanup_iterator,
+ NULL));
+ GNUNET_CONTAINER_multihashmap32_destroy (map);
+ map = NULL;
+ GNUNET_assert (NULL != sigpipe);
+ GNUNET_assert (NULL != shc_chld);
+ if (GNUNET_SCHEDULER_NO_TASK != child_death_task_id)
+ {
+ GNUNET_SCHEDULER_cancel (child_death_task_id);
+ child_death_task_id = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_SIGNAL_handler_uninstall (shc_chld);
+ shc_chld = NULL;
+ GNUNET_DISK_pipe_close (sigpipe);
+ sigpipe = NULL;
+}
+
+
+/**
+ * Monitors a process for its termination.
+ *
+ * @param proc the process to monitor for termination
+ * @param cb the callback to be called for notifying the termination of the
+ * process
+ * @param cls the closure for the above callback
+ */
+void
+MSH_monitor_process_pid (pid_t pid,
+ MSH_ProcExitCallback cb, void *cls)
+{
+ struct MonitorCtx *ctx;
+
+ GNUNET_assert (NULL != map);
+ ctx = GNUNET_malloc (sizeof (struct MonitorCtx));
+ ctx->cb = cb;
+ ctx->cls = cls;
+ GNUNET_assert
+ (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap32_put (map, (uint32_t) pid, ctx,
+
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+}
+
+
+/**
+ * Monitors a process for its termination.
+ *
+ * @param proc the process to monitor for termination
+ * @param cb the callback to be called for notifying the termination of the
+ * process
+ * @param cls the closure for the above callback
+ */
+void
+MSH_monitor_process (struct GNUNET_OS_Process *proc,
+ MSH_ProcExitCallback cb, void *cls)
+{
+ pid_t pid;
+
+ pid = GNUNET_OS_process_get_pid (proc);
+ MSH_monitor_process_pid (pid, cb, cls);
+}
+
+
+/**
+ * Stop monitoring a process
+ *
+ * @param proc
+ * @return GNUNET_OK upon success; GNUNET_SYSERR if the process is not being
+ * monitored earlier
+ */
+int
+MSH_monitor_process_pid_cancel (pid_t pid)
+{
+ struct MonitorCtx *ctx;
+
+ GNUNET_assert (NULL != map);
+ ctx = GNUNET_CONTAINER_multihashmap32_get (map, (uint32_t) pid);
+ if (NULL == ctx)
+ return GNUNET_SYSERR;
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap32_remove
+ (map, (uint32_t) pid, ctx));
+ GNUNET_free (ctx);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Stop monitoring a process
+ *
+ * @param proc
+ * @return GNUNET_OK upon success; GNUNET_SYSERR if the process is not being
+ * monitored earlier
+ */
+int
+MSH_monitor_process_cancel (struct GNUNET_OS_Process *proc)
+{
+ pid_t pid;
+
+ pid = GNUNET_OS_process_get_pid (proc);
+ return MSH_monitor_process_pid_cancel (pid);
+}
Copied: msh/src/pmonitor.h (from rev 30820, msh/src/mshd_pmonitor.h)
===================================================================
--- msh/src/pmonitor.h (rev 0)
+++ msh/src/pmonitor.h 2013-11-20 13:58:08 UTC (rev 30827)
@@ -0,0 +1,90 @@
+/**
+ * @file pmonitor.h
+ * @brief interface for process monitoring functions
+ * @author Sree Harsha Totakura <address@hidden>
+ */
+
+#ifndef MSHD_PMONITOR_H_
+#define MSHD_PMONITOR_H_
+
+#include <gnunet/gnunet_os_lib.h>
+
+/**
+ * Initialise process monitoring subsystem. Registers SIGCHLD signal handler
+ * and the necessary pipe mechanism for reading the signal notification in a
+ * safe way
+ */
+void
+MSH_pmonitor_init ();
+
+
+/**
+ * shutdown process monitoring subsystem
+ */
+void
+MSH_pmonitor_shutdown ();
+
+
+/**
+ * Callbacks of this type can be supplied to MSH_monitor_process() to be
+ * notified when the corresponding processes exits.
+ *
+ * @param cls the closure passed to MSH_monitor_process()
+ * @param type the process status type
+ * @param long the return/exit code of the process
+ */
+typedef void (*MSH_ProcExitCallback) (void *cls,
+ enum GNUNET_OS_ProcessStatusType type,
+ int code);
+
+
+/**
+ * Monitors a process for its termination.
+ *
+ * @param proc the process to monitor for termination
+ * @param cb the callback to be called for notifying the termination of the
+ * process
+ * @param cls the closure for the above callback
+ */
+void
+MSH_monitor_process (struct GNUNET_OS_Process *proc,
+ MSH_ProcExitCallback cb, void *cls);
+
+
+/**
+ * Stop monitoring a process
+ *
+ * @param proc
+ * @return GNUNET_OK upon success; GNUNET_SYSERR if the process is not being
+ * monitored earlier
+ */
+int
+MSH_monitor_process_cancel (struct GNUNET_OS_Process *proc);
+
+
+/**
+ * Monitors a process for its termination.
+ *
+ * @param proc the process to monitor for termination
+ * @param cb the callback to be called for notifying the termination of the
+ * process
+ * @param cls the closure for the above callback
+ */
+void
+MSH_monitor_process_pid (pid_t pid,
+ MSH_ProcExitCallback cb, void *cls);
+
+
+/**
+ * Stop monitoring a process
+ *
+ * @param proc
+ * @return GNUNET_OK upon success; GNUNET_SYSERR if the process is not being
+ * monitored earlier
+ */
+int
+MSH_monitor_process_pid_cancel (pid_t pid);
+
+#endif /* MSHD_PMONITOR_H_ */
+
+/* End of pmonitor.h */
Copied: msh/src/server.c (from rev 30822, msh/src/mshd-server.c)
===================================================================
--- msh/src/server.c (rev 0)
+++ msh/src/server.c 2013-11-20 13:58:08 UTC (rev 30827)
@@ -0,0 +1,1156 @@
+/**
+ * @file server.c
+ * @brief functions implementing server functionalities of MSH daemon. We
+ * listen for commands from locally started MSH instances and also for
+ * executing commands given by remote MSH daemons.
+ * @author Sree Harsha Totakura <address@hidden>
+ */
+
+#include "common.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <termios.h>
+#include "mshd.h"
+#include "addressmap.h"
+#include "pmonitor.h"
+#include "util.h"
+
+#define TIMEOUT_SECS(s) \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, s)
+
+#define LOG(kind,...) \
+ GNUNET_log_from (kind, "server", __VA_ARGS__)
+
+#define LOG_DEBUG(...) LOG(GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
+
+#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
+
+#define LOG_STRERROR(kind,cmd) \
+ GNUNET_log_from_strerror (kind, "mshd-error", cmd)
+
+/**
+ * server handle for accepting requests from local MSH instances
+ */
+static struct GNUNET_SERVER_Handle *local_serv;
+
+/**
+ * server handle for acceptiong requests from remote MSHD instances
+ */
+static struct GNUNET_SERVER_Handle *daemon_serv;
+
+/**
+ * Notification queue for the local server
+ */
+static struct GNUNET_SERVER_NotificationContext *local_serv_nc;
+
+/**
+ * Notification queue for the daemon server
+ */
+static struct GNUNET_SERVER_NotificationContext *daemon_serv_nc;
+
+/**
+ * Our UID. We use this for access checks
+ */
+uid_t our_uid;
+
+/**
+ * Our GID. We use this for access checks
+ */
+uid_t our_gid;
+
+
+/**
+ * Context for connections requiring to execute commands
+ */
+struct ExecCtx
+{
+ /**
+ * The client handle this context is associated with
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * The command strings to execute
+ */
+ char **args;
+
+ /**
+ * file handle for processes input
+ */
+ struct GNUNET_DISK_FileHandle *fin;
+
+ /**
+ * file handle for processes output
+ */
+ struct GNUNET_DISK_FileHandle *fout;
+
+ /**
+ * input buffer. Data from this buffer is written to proc's STDIN when it is
+ * available for writing.
+ */
+ char *buf;
+
+ /**
+ * If this session were to be interactive, the message containing the setting
+ * to use for the pseudo-tty we create
+ */
+ struct MSH_MSG_PtyMode *pty_mode;
+
+ /**
+ * The size of the input buffer
+ */
+ size_t bufsize;
+
+ /**
+ * salt hash used for authentication
+ */
+ struct GNUNET_HashCode salt;
+
+ /**
+ * timeout task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+ /**
+ * task to read the output from the process
+ */
+ GNUNET_SCHEDULER_TaskIdentifier fout_task;
+
+ /**
+ * task to write data received from the client to proc's STDIN
+ */
+ GNUNET_SCHEDULER_TaskIdentifier fin_task;
+
+ /**
+ * The pid of the child we start
+ */
+ pid_t child_pid;
+
+ /**
+ * If this is an interactive session, this is the master side of the
+ * pseudo-tty we create
+ */
+ int master;
+
+ /**
+ * Is this an interactive session?
+ */
+ int interactive;
+
+ /**
+ * Is this session authentication?
+ */
+ int authenticated;
+
+ /**
+ * If this is an interactive session, is a pseudo-tty created?
+ */
+ int pty_created;
+};
+
+/*
+ * Converts a numeric baud rate to a POSIX speed_t.
+ */
+speed_t
+baud_to_speed(int baud);
+
+
+/**
+ * Destroys an execution context
+ *
+ * @param ctx execution context
+ */
+static void
+destroy_exec_ctx (struct ExecCtx *ctx)
+{
+ unsigned int cnt;
+
+ GNUNET_SERVER_client_drop (ctx->client);
+ if (NULL != ctx->args)
+ {
+ for (cnt = 0; NULL != ctx->args[cnt]; cnt++)
+ GNUNET_free (ctx->args[cnt]);
+ GNUNET_free (ctx->args);
+ }
+ if (0 != ctx->child_pid)
+ {
+ MSH_monitor_process_pid_cancel (ctx->child_pid);
+ GNUNET_break (0 == kill (ctx->child_pid, SIGTERM));
+ }
+ GNUNET_DISK_file_close (ctx->fin);
+ GNUNET_DISK_file_close (ctx->fout);
+ if (GNUNET_SCHEDULER_NO_TASK != ctx->timeout_task)
+ GNUNET_SCHEDULER_cancel (ctx->timeout_task);
+ if (GNUNET_SCHEDULER_NO_TASK != ctx->fout_task)
+ GNUNET_SCHEDULER_cancel (ctx->fout_task);
+ if (NULL != ctx->buf)
+ GNUNET_free (ctx->buf);
+ GNUNET_free_non_null (ctx->pty_mode);
+ GNUNET_free (ctx);
+}
+
+
+/**
+ * Parse contingious 0-terminated strings from a buffer of given length
+ *
+ * @param buf the buffer
+ * @param size the size of the buffer
+ * @param s will contain the array of strings upon return
+ * @return the number of strings returned in the array
+ */
+static int
+parse_strings (const char *buf, size_t size, char ***s)
+{
+ const char *p;
+ char **strs;
+ size_t off;
+ unsigned int cnt;
+
+ cnt = 0;
+ strs = NULL;
+ p = NULL;
+ for (off = 0; off < size; off++)
+ {
+ if ('\0' == buf[off])
+ {
+ if (NULL == p)
+ continue;
+ GNUNET_array_append (strs, cnt, GNUNET_strdup (p));
+ p = NULL;
+ continue;
+ }
+ if (NULL != p)
+ continue;
+ p = &buf[off];
+ }
+ if (0 < cnt)
+ GNUNET_array_append (strs, cnt, NULL);
+ *s = strs;
+ return cnt;
+}
+
+
+/**
+ * Create a challenge message
+ *
+ * @param ctx the execution context
+ * @return the challenge message
+ */
+static struct GNUNET_MessageHeader *
+create_challenge_message (struct ExecCtx *ctx)
+{
+ struct MSH_MSG_Challenge *msg;
+ uint16_t size;
+
+ GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, &ctx->salt);
+ size = sizeof (struct MSH_MSG_Challenge);
+ msg = GNUNET_malloc (size);
+ msg->header.type = htons (MSH_MTYPE_CHALLENGE);
+ msg->header.size = htons (size);
+ GNUNET_CRYPTO_hash_to_enc (&ctx->salt, &msg->salt);
+ LOG_DEBUG ("Challenge nonce: %104s\n", msg->salt.encoding);
+ return &msg->header;
+}
+
+
+/**
+ * Functions with this signature are called whenever a message is
+ * received.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_addresslookup (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader* message)
+{
+ const struct MSH_MSG_AddressLookup *msg;
+ struct MSH_MSG_AddressLookupReply *reply;
+ struct InstanceAddr *iaddr;
+ char *emsg;
+ in_addr_t ip;
+ uint16_t port;
+ uint16_t reply_size;
+
+ emsg = NULL;
+ port = 0;
+ msg = (const struct MSH_MSG_AddressLookup *) message;
+ ip = ntohl (msg->ip);
+ if (GNUNET_NO == reversemap_check (rmap, ip))
+ {
+ emsg = "Given IP address not present in the current mapping\n";
+ goto respond;
+ }
+ iaddr = reversemap_lookup (rmap, ip);
+ GNUNET_assert (NULL != iaddr);
+ port = instance_address_port (iaddr);
+ LOG_DEBUG ("Received ADDRESS_LOOKUP message for IP: %s and port %u\n",
+ ip2str (ip), port);
+ respond:
+ reply_size = sizeof (struct MSH_MSG_AddressLookupReply);
+ if (NULL != emsg)
+ reply_size += strlen (emsg) + 1;
+ reply = GNUNET_malloc (reply_size);
+ reply->header.size = htons (reply_size);
+ reply->header.type = htons (MSH_MTYPE_ADDRESS_LOOKUP_REPLY);
+ reply->port = htons (port);
+ if (NULL != emsg)
+ (void) strcpy (reply->emsg, emsg);
+ GNUNET_SERVER_notification_context_unicast (local_serv_nc, client,
+ &reply->header, GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Generate the credential for the given challenge
+ *
+ * @param c the challenge
+ * @param cred output parameter for the credential
+ */
+static void
+auth_challenge_cred (struct GNUNET_HashCode *c, struct GNUNET_HashCode *cred)
+{
+ struct GNUNET_HashCode xor;
+
+ GNUNET_CRYPTO_hash_xor (c, &shash, &xor);
+ GNUNET_CRYPTO_hash (&xor, sizeof (struct GNUNET_HashCode), cred);
+}
+
+
+/**
+ * Functions with this signature are called whenever a message is
+ * received.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_auth_challenge (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader* message)
+{
+ const struct MSH_MSG_Challenge *msg;
+ struct MSH_MSG_ChallengeResponse *reply;
+ struct GNUNET_HashCode salt;
+ struct GNUNET_HashCode cred;
+
+ msg = (const struct MSH_MSG_Challenge *) message;
+ LOG_DEBUG ("Challenge nonce: %104s\n", msg->salt.encoding);
+ GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_hash_from_string
+ ((const char *) msg->salt.encoding, &salt));
+ auth_challenge_cred (&salt, &cred);
+ reply = GNUNET_malloc (sizeof (struct MSH_MSG_ChallengeResponse));
+ reply->header.size = htons (sizeof (struct MSH_MSG_ChallengeResponse));
+ reply->header.type = htons (MSH_MTYPE_CHALLENGE_RESPONSE);
+ GNUNET_CRYPTO_hash_to_enc (&cred, &reply->auth);
+ GNUNET_SERVER_notification_context_unicast (local_serv_nc, client,
+ &reply->header, GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Function to call for access control checks.
+ *
+ * @param cls closure
+ * @param ucred credentials, if available, otherwise NULL
+ * @param addr address
+ * @param addrlen length of address
+ * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
+ * for unknown address family (will be denied).
+ */
+static int
+check_local_access (void *cls,
+ const struct GNUNET_CONNECTION_Credentials *cred,
+ const struct sockaddr * addr, socklen_t addrlen)
+{
+ if ((our_uid != cred->uid) && (our_gid != cred->gid))
+ return GNUNET_NO;
+ return GNUNET_YES;
+}
+
+
+/**
+ * Callback to be called when ever a client connects to the local server
+ *
+ * @param cls NULL
+ * @param client the client handle
+ */
+static void
+local_server_connect (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ if (NULL == client) /* Server shutting down */
+ return;
+ LOG_DEBUG ("A client has been connected locally\n");
+ GNUNET_SERVER_notification_context_add (local_serv_nc, client);
+}
+
+
+/**
+ * Initialise the local server
+ *
+ * @param unixpath the name to use while opening the abstract UNIX domain
socket
+ * for listening
+ * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
+ */
+int
+init_local_server (const char *unixpath)
+{
+ struct sockaddr_un saddr;
+ static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+ {&handle_addresslookup, NULL, MSH_MTYPE_ADDRESS_LOOKUP, sizeof (struct
+ MSH_MSG_AddressLookup)},
+ {&handle_auth_challenge, NULL, MSH_MTYPE_CHALLENGE, sizeof (struct
MSH_MSG_Challenge)},
+ {NULL, NULL, 0, 0}
+ };
+ struct sockaddr *saddrs[] = {
+ ((struct sockaddr *) &saddr),
+ NULL
+ };
+ socklen_t saddr_lens[] = {
+ sizeof (struct sockaddr_un),
+ 0
+ };
+
+ our_uid = getuid ();
+ our_gid = getgid ();
+ saddr.sun_family = AF_UNIX;
+ (void) memset (saddr.sun_path, 0, sizeof (saddr.sun_path));
+ (void) strncpy (saddr.sun_path, unixpath, sizeof (saddr.sun_path) - 1);
+ local_serv = GNUNET_SERVER_create (&check_local_access, NULL,
+ saddrs,
+ saddr_lens,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES);
+ if (NULL == local_serv)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_SERVER_add_handlers (local_serv, handlers);
+ GNUNET_SERVER_connect_notify (local_serv, &local_server_connect, NULL);
+ local_serv_nc = GNUNET_SERVER_notification_context_create (local_serv, 1);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Shutdown the local server
+ */
+void
+shutdown_local_server ()
+{
+ if (NULL != local_serv)
+ {
+ GNUNET_SERVER_destroy (local_serv);
+ local_serv = NULL;
+ }
+}
+
+
+/******************************************************************************/
+/* Daemon server. Responsbile for executing commands submitted by remote MSH
*/
+/* clients
*/
+/******************************************************************************/
+
+
+/**
+ * Handle session open message and start challenge authentication.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_session_open (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader* message)
+{
+ struct ExecCtx *exec_ctx;
+ const struct MSH_MSG_SessionOpen *msg;
+ struct GNUNET_MessageHeader *reply;
+
+ LOG_DEBUG ("Received a SESSION_OPEN message\n");
+ exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
+ GNUNET_assert (NULL != exec_ctx);
+ msg = (const struct MSH_MSG_SessionOpen *) message;
+ if (NULL != exec_ctx->args)
+ {
+ GNUNET_break (0);
+ goto close_conn;
+ }
+ if (MSH_SESSION_TYPE_INTERACTIVE == ntohl (msg->type))
+ exec_ctx->interactive = GNUNET_YES;
+ reply = create_challenge_message (exec_ctx);
+ LOG_DEBUG ("Sending AUTH_CHALLENGE\n");
+ GNUNET_SERVER_notification_context_unicast (daemon_serv_nc, client, reply,
+ GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+
+ close_conn:
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+}
+
+
+/**
+ * Task to read the output from a process and send it to client
+ *
+ * @param cls the client context
+ * @param tc scheduler task context
+ */
+static void
+read_fout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ExecCtx *exec_ctx = cls;
+ struct MSH_MSG_CmdIO *msg;
+ static char data[MAX_IO_DATA];
+ ssize_t size;
+ uint16_t msize;
+
+ exec_ctx->fout_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ {
+ return;
+ }
+ size = GNUNET_DISK_file_read_non_blocking (exec_ctx->fout, data,
MAX_IO_DATA);
+ if (size <= 0)
+ {
+ GNUNET_break (GNUNET_SYSERR != size);
+ GNUNET_SERVER_client_disconnect (exec_ctx->client);
+ return;
+ }
+ msize = size + sizeof (struct MSH_MSG_CmdIO);
+ msg = GNUNET_malloc (msize);
+ msg->header.type = htons (MSH_MTYPE_CMD_STREAM_STDOUT);
+ msg->header.size = htons (msize);
+ memcpy (msg->data, data, size);
+ GNUNET_SERVER_notification_context_unicast (daemon_serv_nc, exec_ctx->client,
+ &msg->header, GNUNET_NO);
+ exec_ctx->fout_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ exec_ctx->fout, &read_fout, exec_ctx);
+}
+
+
+/**
+ * Configure the terminal for the child
+ */
+static int
+parse_term_mode (const struct MSH_MSG_PtyMode *msg,
+ struct termios *tio,
+ struct winsize *ws,
+ char **termstr)
+{
+ uint16_t *params;
+ char *str;
+ unsigned int cnt;
+ unsigned int ns;
+ uint16_t msize;
+ size_t expected;
+ speed_t ospeed;
+ speed_t ispeed;
+
+ msize = ntohs (msg->header.size);
+ ns = ntohs (msg->nsettings);
+ expected = (sizeof (struct MSH_MSG_PtyMode) + (sizeof (uint16_t) * ns * 2));
+ if (msize < expected)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+#define PARSE_WIN_SIZE(field) \
+ ws->field = ntohs (msg->field);
+ PARSE_WIN_SIZE (ws_row);
+ PARSE_WIN_SIZE (ws_col);
+ PARSE_WIN_SIZE (ws_xpixel);
+ PARSE_WIN_SIZE (ws_ypixel);
+#undef PARSE_WIN_SIZE
+ ospeed = baud_to_speed (ntohl (msg->ospeed));
+ ispeed = baud_to_speed (ntohl (msg->ispeed));
+ if (0 != cfsetospeed (tio, ospeed))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (0 != cfsetispeed (tio, ispeed))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ params = (uint16_t *) &msg[1];
+ for (cnt = 0; cnt < ns; cnt++)
+ {
+ switch (ntohs (params[2 * cnt]))
+ {
+#define TTYCHAR(NAME,OP) \
+ case OP: \
+ tio->c_cc[NAME] = ntohs (params[(2 * cnt)+1]); \
+ break;
+#define TTYMODE(NAME, FIELD, OP) \
+ case OP: \
+ if (1 == ntohs (params[(2 * cnt)+1])) \
+ tio->FIELD |= NAME; \
+ break;
+#include "ttymodes.h"
+#undef TTYCHAR
+#undef TTYMODE
+
+ default:
+ GNUNET_assert (0);
+ }
+ }
+ if (0 == (msize - expected))
+ return GNUNET_OK;
+ str = ((void *) msg) + expected;
+ if ('\0' != str[(msize - expected) - 1])
+ {
+ GNUNET_break (0);
+ str = NULL;
+ return GNUNET_OK;
+ }
+ *termstr = GNUNET_strdup (str);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Callback that will be called when a child processes terminates. The
+ * associated client context for the client which requested this process will
be
+ * destroyed
+ *
+ * @param cls the closure passed to MSH_monitor_process()
+ * @param type the process status type
+ * @param long the return/exit code of the process
+ */
+static void
+proc_exit_cb (void *cls, enum GNUNET_OS_ProcessStatusType type, int code)
+{
+ struct ExecCtx *exec_ctx = cls;
+
+ LOG_DEBUG ("Command `%s' exited.\n", exec_ctx->args[0]);
+ exec_ctx->child_pid = 0;
+ GNUNET_SCHEDULER_cancel (exec_ctx->fout_task);
+ exec_ctx->fout_task = GNUNET_SCHEDULER_add_now (&read_fout, exec_ctx);
+}
+
+
+/**
+ * start the process from the execution process
+ *
+ * @param ctx the execution context
+ * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
+ */
+static int
+proc_exec (struct ExecCtx *ctx)
+{
+ struct GNUNET_DISK_PipeHandle *pin;
+ struct GNUNET_DISK_PipeHandle *pout;
+ struct GNUNET_OS_Process *proc;
+ char *fnpty;
+ char *termstr;
+ struct winsize ws;
+ struct termios tio;
+ int ret;
+ int slave;
+
+ if (!ctx->interactive)
+ {
+ pin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_NO, 0, 0);
+ pout = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_YES, 0, 0);
+ GNUNET_assert ((NULL != pin && (NULL != pout)));
+ proc = GNUNET_OS_start_process_vap (GNUNET_NO,
+ GNUNET_OS_INHERIT_STD_NONE,
+ pin,
+ pout,
+ ctx->args[0],
+ ctx->args);
+ if (NULL == proc)
+ return GNUNET_SYSERR;
+ ctx->child_pid = GNUNET_OS_process_get_pid (proc);
+ GNUNET_OS_process_destroy (proc);
+ MSH_monitor_process_pid (ctx->child_pid, &proc_exit_cb, ctx);
+ ctx->fin = GNUNET_DISK_pipe_detach_end (pin, GNUNET_DISK_PIPE_END_WRITE);
+ ctx->fout = GNUNET_DISK_pipe_detach_end (pout, GNUNET_DISK_PIPE_END_READ);
+ GNUNET_assert ((NULL != ctx->fin && (NULL != ctx->fout)));
+ GNUNET_assert (GNUNET_OK == GNUNET_DISK_pipe_close (pin));
+ GNUNET_assert (GNUNET_OK == GNUNET_DISK_pipe_close (pout));
+ ctx->fout_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ ctx->fout, &read_fout, ctx);
+ return GNUNET_OK;
+ }
+ if (NULL == (fnpty = ptsname (ctx->master)))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "ptsname");
+ return GNUNET_SYSERR;
+ }
+ ret = fork ();
+ if (-1 == ret)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
+ return GNUNET_SYSERR;
+ }
+ if (0 != ret)
+ {
+ int fd;
+
+ LOG_DEBUG ("Forked child successfully\n");
+ ctx->child_pid = ret;
+ MSH_monitor_process_pid (ctx->child_pid, &proc_exit_cb, ctx);
+ /* forward streams to and from child */
+ ctx->fin = GNUNET_DISK_get_handle_from_int_fd (ctx->master);
+ fd = dup (ctx->master);
+ if (-1 == fd)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup");
+ GNUNET_assert (0 == kill (ret, SIGTERM));
+ return GNUNET_SYSERR;
+ }
+ ctx->fout = GNUNET_DISK_get_handle_from_int_fd (fd);
+ ctx->fout_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
ctx->fout,
+ &read_fout, ctx);
+
+ return GNUNET_OK;
+ }
+ close (ctx->master);
+ LOG_DEBUG ("Opening slave PTY %s\n", fnpty);
+ slave = open (fnpty, O_RDWR);
+ if (-1 == slave)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "open");
+ _exit (1);
+ }
+ if (-1 == tcgetattr (slave, &tio))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "tcgetattr");
+ _exit (1);
+ }
+ termstr = NULL;
+ parse_term_mode (ctx->pty_mode, &tio, &ws, &termstr);
+ GNUNET_free (ctx->pty_mode);
+ ctx->pty_mode = NULL;
+ if (NULL != termstr)
+ {
+ GNUNET_break (0 == setenv ("TERM", termstr, 1));
+ GNUNET_free (termstr);
+ }
+ else
+ GNUNET_break (0 == setenv ("TERM", "MSH", 1));
+ if (-1 == tcsetattr (slave, TCSANOW, &tio))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "tcsetattr");
+ //_exit (1); /* Ignore for now */
+ }
+ if (-1 == ioctl (slave, TIOCSWINSZ, &ws))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "ioctl");
+ _exit (1);
+ }
+ if (-1 == setsid ())
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsid");
+ _exit (1);
+ }
+ close (0);
+ close (1);
+ //close (2);
+ if ( (-1 == dup2 (slave, 0)) ||
+ (-1 == dup2 (slave, 1)) ) //||
+ //(-1 == dup2 (slave, 2)) )
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup");
+ _exit (2);
+ }
+ close (slave);
+ LOG_DEBUG ("Execing %s\n", ctx->args[0]);
+ if (-1 == execvp (ctx->args[0], ctx->args))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "execvp");
+ _exit (1);
+ }
+ GNUNET_assert (0); /* This should never be reached */
+}
+
+
+/**
+ * Handle session open message and start challenge authentication.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_runcmd (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader* message)
+{
+ const struct MSH_MSG_RunCmd *msg;
+ struct ExecCtx *exec_ctx;
+ struct GNUNET_MessageHeader *reply;
+ uint16_t size;
+
+ LOG_DEBUG ("Received a RUN_CMD message\n");
+ exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
+ GNUNET_assert (NULL != exec_ctx);
+ if (GNUNET_YES != exec_ctx->authenticated)
+ {
+ GNUNET_break_op (0);
+ goto close_conn;
+ }
+ if (exec_ctx->interactive && !exec_ctx->pty_created)
+ {
+ GNUNET_break_op (0);
+ goto close_conn;
+ }
+ if (NULL != exec_ctx->args)
+ {
+ GNUNET_break (0);
+ goto close_conn;
+ }
+ size = ntohs (message->size);
+ if ( size <= sizeof (struct MSH_MSG_RunCmd))
+ {
+ GNUNET_break_op (0);
+ goto close_conn;
+ }
+ msg = (const struct MSH_MSG_RunCmd *) message;
+ if (0 == parse_strings (msg->cmd,
+ size - sizeof (struct MSH_MSG_RunCmd),
+ &exec_ctx->args))
+ {
+ GNUNET_break_op (0);
+ goto close_conn;
+ }
+ GNUNET_SCHEDULER_cancel (exec_ctx->timeout_task);
+ exec_ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ if (GNUNET_OK != proc_exec (exec_ctx))
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Command `%s' not found or not executable\n", exec_ctx->args[0]);
+ goto close_conn;
+ }
+ reply = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader));
+ reply->size = htons (sizeof (struct GNUNET_MessageHeader));
+ reply->type = htons (MSH_MTYPE_EXEC_BEGIN);
+ GNUNET_SERVER_notification_context_unicast (daemon_serv_nc, exec_ctx->client,
+ reply, GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+
+ close_conn:
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+}
+
+
+/**
+ * Functions with this signature are called whenever a message is
+ * received.
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_auth_challenge_response (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader* message)
+{
+ const struct MSH_MSG_ChallengeResponse *msg;
+ //struct GNUNET_MessageHeader *reply; FIXME
+ struct ExecCtx *exec_ctx;
+ struct GNUNET_HashCode cred;
+ struct GNUNET_CRYPTO_HashAsciiEncoded enc;
+
+ exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
+ GNUNET_assert (NULL != exec_ctx);
+ auth_challenge_cred (&exec_ctx->salt, &cred);
+ GNUNET_CRYPTO_hash_to_enc (&cred, &enc);
+ msg = (const struct MSH_MSG_ChallengeResponse *) message;
+ if (0 != memcmp (&msg->auth, &enc,
+ sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
+ {
+ LOG_DEBUG ("Auth failed: \n"
+ " Required: %s\n"
+ " Given: %s\n", enc.encoding, msg->auth.encoding);
+ GNUNET_break (0);
+ goto err_ret;
+ }
+ exec_ctx->authenticated = GNUNET_YES;
+ return;
+
+ err_ret:
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+}
+
+
+/**
+ * Task to write data from input buffer to proc's STDIN
+ *
+ * @param cls the client context
+ * @return tc scheduler task context
+ */
+static void
+write_fin (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ExecCtx *exec_ctx = cls;
+ ssize_t wrote;
+
+ exec_ctx->fin_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY))
+ {
+ GNUNET_free (exec_ctx->buf);
+ exec_ctx->buf = NULL;
+ exec_ctx->bufsize = 0;
+ goto err_ret;
+ }
+ wrote = GNUNET_DISK_file_write (exec_ctx->fin,
+ exec_ctx->buf, exec_ctx->bufsize);
+ if (GNUNET_SYSERR == wrote)
+ {
+ LOG_ERROR ("Error writing to proc's STDIN\n");
+ goto err_ret;
+ }
+ if (wrote == exec_ctx->bufsize)
+ {
+ GNUNET_free (exec_ctx->buf);
+ exec_ctx->buf = NULL;
+ exec_ctx->bufsize = 0;
+ GNUNET_SERVER_receive_done (exec_ctx->client, GNUNET_OK);
+ return;
+ }
+ GNUNET_assert (wrote < exec_ctx->bufsize);
+ exec_ctx->bufsize -= wrote;
+ exec_ctx->buf = memmove (exec_ctx->buf, exec_ctx->buf + wrote,
+ exec_ctx->bufsize);
+ exec_ctx->buf = GNUNET_realloc (exec_ctx->buf, exec_ctx->bufsize);
+ exec_ctx->fin_task =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ exec_ctx->fin,
+ &write_fin, exec_ctx);
+ return;
+
+ err_ret:
+ GNUNET_SERVER_receive_done (exec_ctx->client, GNUNET_SYSERR);
+}
+
+
+/**
+ * Handler for messages with command's input stream data. The date will be
+ * written to the command's standard input stream.
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_command_input (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader* message)
+{
+ const struct MSH_MSG_CmdIO *msg;
+ struct ExecCtx *exec_ctx;
+ ssize_t wrote;
+ uint16_t size;
+
+ LOG_DEBUG ("Received CMD_IO_STDIN message\n");
+ size = ntohs (message->size);
+ msg = (const struct MSH_MSG_CmdIO *) message;
+ exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
+ GNUNET_assert (NULL != exec_ctx);
+ size -= sizeof (struct MSH_MSG_CmdIO);
+ wrote = GNUNET_DISK_file_write (exec_ctx->fin, msg->data, size);
+ if (GNUNET_SYSERR == wrote)
+ {
+ LOG_ERROR ("Error writing to proc's STDIN\n");
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ LOG_DEBUG ("Wrote %zd to proc's STDIN\n", wrote);
+ if (wrote == size)
+ {
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ GNUNET_assert (wrote < size);
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == exec_ctx->fin_task);
+ GNUNET_assert (NULL == exec_ctx->buf);
+ GNUNET_assert (0 == exec_ctx->bufsize);
+ exec_ctx->bufsize = size - wrote;
+ exec_ctx->buf = GNUNET_malloc (exec_ctx->bufsize);
+ (void) memcpy (exec_ctx->buf, msg->data + wrote, exec_ctx->bufsize);
+ exec_ctx->fin_task =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ exec_ctx->fin,
+ &write_fin, exec_ctx);
+ GNUNET_SERVER_disable_receive_done_warning (client);
+}
+
+
+/**
+ * Handler for messages containing the settings to be used while creating a
+ * psuedo-tty. This message must only be received for interactive sessions
+ * before #MSH_MSG_RunCmd message is received.
+ *
+ * @param cls NULL
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_pty_mode (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader* message)
+{
+ struct ExecCtx *exec_ctx;
+ int master;
+ uint16_t size;
+
+ size = ntohs (message->size);
+ if (size <= sizeof (struct MSH_MSG_PtyMode))
+ {
+ GNUNET_break (0);
+ goto close_conn;
+ }
+ exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
+ GNUNET_assert (NULL != exec_ctx);
+ master = posix_openpt (O_RDWR);
+ if (-1 == master)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "posix_openpt");
+ goto close_conn;
+ }
+ if (-1 == grantpt (master))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "grantpt");
+ goto close_conn;
+ }
+ if (-1 == unlockpt (master))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "unlockpt");
+ goto close_conn;
+ }
+ exec_ctx->master = master;
+ exec_ctx->pty_created = GNUNET_YES;
+ exec_ctx->pty_mode = (struct MSH_MSG_PtyMode *) GNUNET_copy_message
(message);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+
+ close_conn:
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+}
+
+
+/**
+ * Callback to be called when ever a client connects to the daemon server
+ *
+ * @param cls NULL
+ * @param client the client handle
+ */
+static void
+daemon_server_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ struct ExecCtx *exec_ctx;
+
+ if (NULL == client)
+ return;
+ LOG_DEBUG ("A remote client has disconnected\n");
+ exec_ctx = GNUNET_SERVER_client_get_user_context (client, struct ExecCtx);
+ GNUNET_assert (NULL != exec_ctx);
+ destroy_exec_ctx (exec_ctx);
+}
+
+
+/**
+ * Initialises the server which spawns processes and forwards it stdin and
stdout
+ *
+ * @param h the network handle of the socket to listen for incoming connections
+ */
+int
+init_daemon_server ()
+{
+ static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+ {&handle_session_open, NULL, MSH_MTYPE_SESSION_OPEN,
+ sizeof (struct MSH_MSG_SessionOpen)},
+ {&handle_runcmd, NULL, MSH_MTYPE_RUNCMD, 0},
+ {&handle_auth_challenge_response, NULL, MSH_MTYPE_CHALLENGE_RESPONSE,
+ sizeof (struct MSH_MSG_ChallengeResponse)},
+ {&handle_command_input, NULL, MSH_MTYPE_CMD_STREAM_STDIN, 0},
+ {&handle_pty_mode, NULL, MSH_MTYPE_PTY_MODE, 0},
+ {NULL, NULL, 0, 0}
+ };
+
+ daemon_serv = GNUNET_SERVER_create_with_sockets (NULL,
+ NULL,
+ NULL,
+
GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES);
+ if (NULL == daemon_serv)
+ return GNUNET_SYSERR;
+ GNUNET_SERVER_add_handlers (daemon_serv, handlers);
+ GNUNET_SERVER_disconnect_notify (daemon_serv, &daemon_server_disconnect,
NULL);
+ daemon_serv_nc = GNUNET_SERVER_notification_context_create (daemon_serv, 1);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Timeout task for timing out connections until they authenticate. Once
+ * authenticated the connection will not be timed out.
+ *
+ * @param cls the client context
+ * @param tc scheduler task context
+ */
+static void
+timeout_cb (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ExecCtx *exec_ctx = cls;
+
+ exec_ctx->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_SERVER_client_disconnect (exec_ctx->client);
+}
+
+
+/**
+ * Create a client for the daemon server from a new client connection
+ *
+ * @param conn the connection to derive the client from
+ */
+void
+daemon_server_add_connection (struct GNUNET_CONNECTION_Handle *conn)
+{
+ struct ExecCtx *exec_ctx;
+ struct GNUNET_SERVER_Client *client;
+
+ exec_ctx = GNUNET_malloc (sizeof (struct ExecCtx));
+ client = GNUNET_SERVER_connect_socket (daemon_serv, conn);
+ exec_ctx->client = client;
+ GNUNET_SERVER_client_set_user_context (client, exec_ctx);
+ GNUNET_SERVER_notification_context_add (daemon_serv_nc, client);
+ exec_ctx->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (TIMEOUT_SECS (30), &timeout_cb, exec_ctx);
+}
+
+
+/**
+ * Shutdown the daemon server
+ */
+void
+shutdown_daemon_server ()
+{
+ if (NULL != daemon_serv)
+ {
+ GNUNET_SERVER_destroy (daemon_serv);
+ daemon_serv = NULL;
+ }
+ if (NULL != daemon_serv_nc)
+ {
+ GNUNET_SERVER_notification_context_destroy (daemon_serv_nc);
+ daemon_serv_nc = NULL;
+ }
+}
+
+/* End of server.c */
Added: msh/src/server.h
===================================================================
--- msh/src/server.h (rev 0)
+++ msh/src/server.h 2013-11-20 13:58:08 UTC (rev 30827)
@@ -0,0 +1,56 @@
+/**
+ * @file server.c
+ * @brief functions implementing server functionalities of MSH daemon. We
+ * listen for commands from locally started MSH instances and also for
+ * executing commands given by remote MSH daemons.
+ * @author Sree Harsha Totakura <address@hidden>
+ */
+
+#ifndef MSHD_SERVER_H_
+#define MSHD_SERVER_H_
+
+
+/**
+ * Shutdown the local server
+ */
+void
+shutdown_local_server ();
+
+
+/**
+ * Shutdown the daemon server
+ */
+void
+shutdown_daemon_server ();
+
+
+/**
+ * Create a client for the daemon server from a new client connection
+ *
+ * @param conn the connection to derive the client from
+ */
+void
+daemon_server_add_connection (struct GNUNET_CONNECTION_Handle *conn);
+
+
+/**
+ * Initialises the server which spawns processes and forwards it stdin and
stdout
+ *
+ * @param h the network handle of the socket to listen for incoming connections
+ */
+int
+init_daemon_server ();
+
+
+/**
+ * Initialise the local server
+ *
+ * @param unixpath the name to use while opening the abstract UNIX domain
socket
+ * for listening
+ * @return GNUNET_OK upon success; GNUNET_SYSERR upon failure
+ */
+int
+init_local_server (const char *unixpath);
+
+
+#endif /* MSHD_SERVER_H_ */
Modified: msh/src/test_pty.c
===================================================================
--- msh/src/test_pty.c 2013-11-20 10:55:44 UTC (rev 30826)
+++ msh/src/test_pty.c 2013-11-20 13:58:08 UTC (rev 30827)
@@ -42,7 +42,6 @@
static struct GNUNET_DISK_PipeHandle *sigpipe;
static struct GNUNET_DISK_FileHandle *chld_io;
-static struct GNUNET_DISK_FileHandle *our_in;
static struct GNUNET_CONNECTION_Handle *conn;
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r30827 - msh/src,
gnunet <=