From aa3fe79526bbce17f5ceec4d9c2d2246f01d6828 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Thu, 5 Jan 2012 17:19:49 +0100 Subject: [PATCH] Pass command via sideband. This makes para_cclient pass the paraslash command and its arguments as a sideband packet to para_server if possible. For sideband connections the command and its arguments are stored as NULL-terminated strings. This is better than separating by newlines (as we do for non-sideband connections) because it allows for arguments containing newlines. Suitable helpers for creating and parsing a buffer of NULL-terminated strings, are provided in client_common.c and command.c, respectively. No change for non-sideband connections. --- client_common.c | 27 +++++++++++++++++ command.c | 79 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 88 insertions(+), 18 deletions(-) diff --git a/client_common.c b/client_common.c index 53f7b5a9..ff351e89 100644 --- a/client_common.c +++ b/client_common.c @@ -245,6 +245,26 @@ static bool has_feature(const char *feature, struct client_task *ct) return find_arg(feature, ct->features) >= 0? true : false; } +static int send_sb_command(struct client_task *ct) +{ + int i; + char *command, *p; + size_t len = 0; + + if (ct->sbc) + return send_sb(ct, NULL, 0, 0, false); + + for (i = 0; i < ct->conf.inputs_num; i++) + len += strlen(ct->conf.inputs[i]) + 1; + p = command = para_malloc(len); + for (i = 0; i < ct->conf.inputs_num; i++) { + strcpy(p, ct->conf.inputs[i]); + p += strlen(ct->conf.inputs[i]) + 1; + } + PARA_DEBUG_LOG("--> %s\n", command); + return send_sb(ct, command, len, SBD_COMMAND, false); +} + /** * The post select hook for client commands. * @@ -385,6 +405,13 @@ static void client_post_select(struct sched *s, struct task *t) char *command = NULL; if (!FD_ISSET(ct->scc.fd, &s->wfds)) return; + if (ct->use_sideband) { + ret = send_sb_command(ct); + if (ret <= 0) + goto out; + ct->status = CL_SENT_COMMAND; + return; + } for (i = 0; i < ct->conf.inputs_num; i++) { char *tmp = command; command = make_message("%s\n%s", command? diff --git a/command.c b/command.c index 8deb69ce..c18cd4dd 100644 --- a/command.c +++ b/command.c @@ -856,6 +856,38 @@ out: #define HANDSHAKE_BUFSIZE 4096 +static int parse_sb_command(struct command_context *cc, struct iovec *iov) +{ + int ret, i; + char *p, *end; + + ret = -E_BAD_CMD; + if (iov->iov_base == NULL || iov->iov_len == 0) + goto out; + p = iov->iov_base; + p[iov->iov_len - 1] = '\0'; /* just to be sure */ + cc->cmd = get_cmd_ptr(p, NULL); + if (!cc->cmd) + goto out; + ret = check_perms(cc->u->perms, cc->cmd); + if (ret < 0) + goto out; + end = iov->iov_base + iov->iov_len; + for (i = 0, p = iov->iov_base; p < end; i++) + p += strlen(p) + 1; + cc->argc = i; + cc->argv = para_malloc((cc->argc + 1) * sizeof(char *)); + for (i = 0, p = iov->iov_base; p < end; i++) { + cc->argv[i] = para_strdup(p); + p += strlen(p) + 1; + } + cc->argv[cc->argc] = NULL; + ret = cc->argc; +out: + free(iov->iov_base); + return ret; +} + /** * Perform user authentication and execute a command. * @@ -981,24 +1013,35 @@ __noreturn void handle_connect(int fd, const char *peername) ret = sc_send_buffer(&cc->scc, PROCEED_MSG); if (ret < 0) goto net_err; - ret = read_command(&cc->scc, &command); - if (ret == -E_COMMAND_SYNTAX) - goto err_out; - if (ret < 0) - goto net_err; - ret = -E_BAD_CMD; - cc->cmd = parse_cmd(command); - if (!cc->cmd) - goto err_out; - /* valid command, check permissions */ - ret = check_perms(cc->u->perms, cc->cmd); - if (ret < 0) - goto err_out; - /* valid command and sufficient perms */ - ret = create_argv(command, "\n", &cc->argv); - if (ret < 0) - goto err_out; - cc->argc = ret; + if (cc->use_sideband) { + struct iovec iov; + ret = recv_sb(&cc->scc, SBD_COMMAND, MAX_COMMAND_LEN, &iov); + if (ret < 0) + goto net_err; + ret = parse_sb_command(cc, &iov); + if (ret < 0) + goto err_out; + cc->argc = ret; + } else { + ret = read_command(&cc->scc, &command); + if (ret == -E_COMMAND_SYNTAX) + goto err_out; + if (ret < 0) + goto net_err; + ret = -E_BAD_CMD; + cc->cmd = parse_cmd(command); + if (!cc->cmd) + goto err_out; + /* valid command, check permissions */ + ret = check_perms(cc->u->perms, cc->cmd); + if (ret < 0) + goto err_out; + /* valid command and sufficient perms */ + ret = create_argv(command, "\n", &cc->argv); + if (ret < 0) + goto err_out; + cc->argc = ret; + } PARA_NOTICE_LOG("calling com_%s() for %s@%s\n", cc->cmd->name, cc->u->name, peername); ret = cc->cmd->handler(cc); -- 2.39.5