split client.c
authorAndre <maan@p133.(none)>
Thu, 15 Jun 2006 08:07:53 +0000 (10:07 +0200)
committerAndre <maan@p133.(none)>
Thu, 15 Jun 2006 08:07:53 +0000 (10:07 +0200)
new file: client.h
new file: client_common.c

This completes the preparations for including para_client into para_audiod.
client_common.c contains all functions that are also useful for para_audiod.

client.c
client.h [new file with mode: 0644]
client_common.c [new file with mode: 0644]
command.c
configure.ac
error.h
net.c
net.h

index 94fff72..d2f4643 100644 (file)
--- a/client.c
+++ b/client.c
 #include "para.h"
 #include "list.h"
 #include "sched.h"
-#include "config.h"
 #include "client.cmdline.h"
-#include "crypt.h"
-#include "rc4.h"
-#include <openssl/rc4.h>
-#include "net.h"
-#include "fd.h"
 #include "string.h"
 #include "stdin.h"
 #include "stdout.h"
+#include "client.h"
 #include "error.h"
 
-enum {
-       CL_CONNECTED,
-       CL_RECEIVED_WELCOME,
-       CL_SENT_AUTH,
-       CL_RECEIVED_CHALLENGE,
-       CL_SENT_CH_RESPONSE,
-       CL_RECEIVED_PROCEED,
-       CL_SENT_COMMAND,
-       CL_SENDING_STDIN,
-       CL_RECEIVING_SERVER_OUTPUT
-};
-
-#define CLIENT_BUFSIZE 8192
-
-struct private_client_data {
-       int status;
-       int fd;
-       struct client_args_info conf;
-       char *config_file;
-       char *key_file;
-       char *user;
-       RC4_KEY rc4_recv_key;
-       RC4_KEY rc4_send_key;
-       struct task task;
-       int eof;
-       char buf[CLIENT_BUFSIZE];
-       size_t loaded;
-       int check_r;
-       int check_w;
-       long unsigned challenge_nr;
-       /* only used if stdin gets sent to para_server */
-       char *inbuf;
-       size_t *in_loaded;
-       int *in_eof;
-};
-
 INIT_CLIENT_ERRLISTS;
 
 static struct private_client_data *pcd;
 static struct stdin_task sit;
 static struct stdout_task sot;
 
-
-static void rc4_send(unsigned long len, const unsigned char *indata,
-               unsigned char *outdata)
-{
-       RC4(&pcd->rc4_send_key, len, indata, outdata);
-}
-
-static void rc4_recv(unsigned long len, const unsigned char *indata,
-               unsigned char *outdata)
-{
-       RC4(&pcd->rc4_recv_key, len, indata, outdata);
-}
-
-
 /*
  * client log function
  */
@@ -104,289 +49,6 @@ void para_log(int ll, const char* fmt,...)
        va_end(argp);
 }
 
-static void client_close(struct private_client_data *pcd)
-{
-       if (pcd)
-               return;
-       if (pcd->fd >= 0)
-               close(pcd->fd);
-       free(pcd->user);
-       free(pcd->config_file);
-       free(pcd->key_file);
-       free(pcd);
-}
-
-static int client_parse_config(int argc, char *argv[],
-               struct private_client_data **pcd_ptr)
-{
-       char *home = para_homedir();
-       struct stat statbuf;
-       int ret;
-       struct private_client_data *p =
-               para_calloc(sizeof(struct private_client_data));
-
-       p->fd = -1;
-       cmdline_parser(argc, argv, &p->conf);
-       ret = - E_CLIENT_SYNTAX;
-       if (!p->conf.inputs_num)
-               goto out;
-       p->user = p->conf.user_given?
-               para_strdup(p->conf.user_arg) : para_logname();
-
-       p->key_file = p->conf.key_file_given?
-               para_strdup(p->conf.key_file_arg) :
-               make_message("%s/.paraslash/key.%s", home, p->user);
-
-       p->config_file = p->conf.config_file_given?
-               para_strdup(p->conf.config_file_arg) :
-               make_message("%s/.paraslash/client.conf", home);
-       ret = stat(p->config_file, &statbuf);
-       if (ret && p->conf.config_file_given) {
-               ret = -E_NO_CONFIG;
-               goto out;
-       }
-       if (!ret)
-               cmdline_parser_configfile(p->config_file, &p->conf, 0, 0, 0);
-       ret = 1;
-       *pcd_ptr = p;
-       PARA_INFO_LOG(
-               "current loglevel: %d\n"
-               "using config_file: %s\n"
-               "using key_file: %s\n"
-               "connecting to %s:%d\n" ,
-               p->conf.loglevel_arg,
-               p->config_file,
-               p->key_file,
-               p->conf.hostname_arg, p->conf.server_port_arg
-       );
-out:
-       free(home);
-       if (ret < 0)
-               client_close(p);
-       return ret;
-}
-
-static void client_pre_select(struct sched *s, struct task *t)
-{
-       struct private_client_data *p = t->private_data;
-
-       PARA_INFO_LOG("status %d\n", p->status);
-       t->ret = 1;
-       pcd->check_r = 0;
-       pcd->check_w = 0;
-       if (p->fd < 0)
-               return;
-       switch (pcd->status) {
-       case CL_CONNECTED:
-       case CL_SENT_AUTH:
-       case CL_SENT_CH_RESPONSE:
-       case CL_SENT_COMMAND:
-               para_fd_set(pcd->fd, &s->rfds, &s->max_fileno);
-               pcd->check_r = 1;
-               return;
-
-       case CL_RECEIVED_WELCOME:
-       case CL_RECEIVED_CHALLENGE:
-       case CL_RECEIVED_PROCEED:
-               para_fd_set(pcd->fd, &s->wfds, &s->max_fileno);
-               pcd->check_w = 1;
-               return;
-
-       case CL_RECEIVING_SERVER_OUTPUT:
-               if (pcd->loaded < CLIENT_BUFSIZE - 1) {
-                       para_fd_set(pcd->fd, &s->rfds, &s->max_fileno);
-                       p->check_r = 1;
-               }
-               return;
-       case CL_SENDING_STDIN:
-               if (*p->in_loaded) {
-                       PARA_INFO_LOG("loaded: %d\n", *p->in_loaded);
-                       para_fd_set(p->fd, &s->wfds, &s->max_fileno);
-                       p->check_w = 1;
-               } else {
-                       if (*p->in_eof) {
-                               t->ret = -E_INPUT_EOF;
-                               s->timeout.tv_sec = 0;
-                               s->timeout.tv_usec = 1;
-                       }
-               }
-               return;
-       }
-}
-
-static ssize_t client_recv_buffer(struct private_client_data *p)
-{
-       ssize_t ret = recv_buffer(p->fd, p->buf + p->loaded,
-               CLIENT_BUFSIZE - p->loaded);
-       if (!ret)
-               return -E_SERVER_EOF;
-       if (ret > 0)
-               p->loaded += ret;
-       return ret;
-
-}
-
-static void client_post_select(struct sched *s, struct task *t)
-{
-       struct private_client_data *p = t->private_data;
-
-       PARA_INFO_LOG("status %d\n", p->status);
-       t->ret = 1;
-       if (p->fd < 0)
-               return;
-       if (!p->check_r && !p->check_w)
-               return;
-       if (p->check_r && !FD_ISSET(p->fd, &s->rfds))
-               return;
-       if (p->check_w && !FD_ISSET(p->fd, &s->wfds))
-               return;
-       switch (p->status) {
-       case CL_CONNECTED: /* receive welcome message */
-               t->ret = client_recv_buffer(p);
-               if (t->ret > 0)
-                       p->status = CL_RECEIVED_WELCOME;
-               return;
-       case CL_RECEIVED_WELCOME: /* send auth command */
-               sprintf(p->buf, "auth %s%s", p->conf.plain_given?
-                       "" : "rc4 ", p->user);
-               PARA_INFO_LOG("--> %s\n", p->buf);
-               t->ret = send_buffer(p->fd, p->buf);
-               if (t->ret >= 0)
-                       p->status = CL_SENT_AUTH;
-               return;
-       case CL_SENT_AUTH: /* receive challenge number */
-               p->loaded = 0;
-               t->ret = client_recv_buffer(p);
-               if (t->ret < 0)
-                       return;
-               if (t->ret != 64) {
-                       t->ret = -E_INVALID_CHALLENGE;
-                       PARA_ERROR_LOG("received the following: %s\n", p->buf);
-                       return;
-               }
-               PARA_INFO_LOG("%s", "<-- [challenge]\n");
-               /* decrypt challenge number */
-               t->ret = para_decrypt_challenge(p->key_file, &p->challenge_nr,
-                       (unsigned char *) p->buf, 64);
-               if (t->ret > 0)
-                       p->status = CL_RECEIVED_CHALLENGE;
-               return;
-       case CL_RECEIVED_CHALLENGE: /* send decrypted challenge */
-               PARA_INFO_LOG("--> %lu\n", p->challenge_nr);
-               t->ret = send_va_buffer(p->fd, "%s%lu", CHALLENGE_RESPONSE_MSG,
-                       p->challenge_nr);
-               if (t->ret > 0)
-                       p->status = CL_SENT_CH_RESPONSE;
-               return;
-       case CL_SENT_CH_RESPONSE: /* read server response */
-               {
-               size_t bytes_received;
-               unsigned char rc4_buf[2 * RC4_KEY_LEN] = "";
-               p->loaded = 0;
-               t->ret = client_recv_buffer(p);
-               if (t->ret < 0)
-                       return;
-               bytes_received = t->ret;
-               PARA_INFO_LOG("++++ server info ++++\n%s\n++++ end of server "
-                       "info ++++\n", p->buf);
-               /* check if server has sent "Proceed" message */
-               t->ret = -E_CLIENT_AUTH;
-               if (!strstr(p->buf, PROCEED_MSG))
-                       return;
-               t->ret = 1;
-               p->status = CL_RECEIVED_PROCEED;
-               if (bytes_received < PROCEED_MSG_LEN + 32)
-                       return;
-               PARA_INFO_LOG("%s", "decrypting session key\n");
-               t->ret = para_decrypt_buffer(p->key_file, rc4_buf,
-                       (unsigned char *)p->buf + PROCEED_MSG_LEN + 1,
-                       bytes_received - PROCEED_MSG_LEN - 1);
-               if (t->ret < 0)
-                       return;
-               RC4_set_key(&p->rc4_send_key, RC4_KEY_LEN, rc4_buf);
-               RC4_set_key(&p->rc4_recv_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
-               enable_crypt(p->fd, rc4_recv, rc4_send);
-               }
-       case CL_RECEIVED_PROCEED: /* concat args and send command */
-               {
-               int i;
-               char *command = NULL;
-               for (i = 0; i < p->conf.inputs_num; i++) {
-                       char *tmp = command;
-                       command = make_message("%s\n%s", command?
-                               command : "", p->conf.inputs[i]);
-                       free(tmp);
-               }
-               command = para_strcat(command, EOC_MSG "\n");
-               PARA_INFO_LOG("--> %s\n", command);
-               t->ret = send_buffer(p->fd, command);
-               free(command);
-               if (t->ret > 0)
-                       p->status = CL_SENT_COMMAND;
-               return;
-               }
-       case CL_SENT_COMMAND:
-               p->loaded = 0;
-               t->ret = client_recv_buffer(p);
-               if (t->ret < 0)
-                       return;
-               t->ret = -E_HANDSHAKE_COMPLETE;
-               if (strstr(p->buf, AWAITING_DATA_MSG))
-                       p->status = CL_SENDING_STDIN;
-               else
-                       p->status = CL_RECEIVING_SERVER_OUTPUT;
-               return;
-       case CL_SENDING_STDIN: /* FIXME: might block */
-               PARA_INFO_LOG("loaded: %d\n", *p->in_loaded);
-               t->ret = send_bin_buffer(p->fd, p->inbuf, *p->in_loaded);
-               if (t->ret <= 0) {
-                       if (!t->ret)
-                               t->ret = 1;
-                       return;
-               }
-               *p->in_loaded = 0; /* FIXME: short writes */
-               return;
-       case CL_RECEIVING_SERVER_OUTPUT:
-               t->ret = client_recv_buffer(p);
-               return;
-       }
-
-}
-static int client_open(struct private_client_data *pcd)
-{
-       int ret;
-       struct hostent *he;
-       struct sockaddr_in their_addr;
-
-       /* get the host info */
-       PARA_NOTICE_LOG("getting host info of %s\n",
-               pcd->conf.hostname_arg);
-       ret = get_host_info(pcd->conf.hostname_arg, &he);
-       if (ret < 0)
-               goto out;
-       /* get new socket */
-       ret = get_socket();
-       if (ret < 0)
-               goto out;
-       pcd->fd = ret;
-       /* init their_addr */
-       init_sockaddr(&their_addr, pcd->conf.server_port_arg, he);
-       /* connect */
-       PARA_NOTICE_LOG("connecting to %s\n", pcd->conf.hostname_arg);
-       ret = para_connect(pcd->fd, &their_addr);
-       if (ret < 0)
-               goto out;
-       pcd->status = CL_CONNECTED;
-       pcd->task.pre_select = client_pre_select;
-       pcd->task.post_select = client_post_select;
-       pcd->task.private_data = pcd;
-       sprintf(pcd->task.status, "client");
-       register_task(&pcd->task);
-       ret = 1;
-out:
-       return ret;
-}
-
 static void client_event_handler(struct task *t)
 {
        struct private_client_data *p = t->private_data;
diff --git a/client.h b/client.h
new file mode 100644 (file)
index 0000000..8f7b9a5
--- /dev/null
+++ b/client.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 1997-2006 Andre Noll <maan@systemlinux.org>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ */
+
+/** \file client.h common client functions and exported symbols from client_common.c */
+
+#include <openssl/rc4.h>
+enum {
+       CL_CONNECTED,
+       CL_RECEIVED_WELCOME,
+       CL_SENT_AUTH,
+       CL_RECEIVED_CHALLENGE,
+       CL_SENT_CH_RESPONSE,
+       CL_RECEIVED_PROCEED,
+       CL_SENT_COMMAND,
+       CL_SENDING_STDIN,
+       CL_RECEIVING_SERVER_OUTPUT
+};
+
+#define CLIENT_BUFSIZE 8192
+
+struct private_client_data {
+       int status;
+       int fd;
+       struct client_args_info conf;
+       char *config_file;
+       char *key_file;
+       char *user;
+       RC4_KEY rc4_recv_key;
+       RC4_KEY rc4_send_key;
+       struct task task;
+       int eof;
+       char buf[CLIENT_BUFSIZE];
+       size_t loaded;
+       int check_r;
+       int check_w;
+       long unsigned challenge_nr;
+       /* only used if stdin gets sent to para_server */
+       char *inbuf;
+       size_t *in_loaded;
+       int *in_eof;
+};
+
+int client_open(struct private_client_data *pcd);
+void client_close(struct private_client_data *pcd);
+int client_parse_config(int argc, char *argv[],
+       struct private_client_data **pcd_ptr);
+void client_pre_select(struct sched *s, struct task *t);
+void client_post_select(struct sched *s, struct task *t);
diff --git a/client_common.c b/client_common.c
new file mode 100644 (file)
index 0000000..a0128ad
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 1997-2006 Andre Noll <maan@systemlinux.org>
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License as published by
+ *     the Free Software Foundation; either version 2 of the License, or
+ *     (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public License
+ *     along with this program; if not, write to the Free Software
+ *     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ */
+
+/** \file client_common.c common functions of para_client and para_audiod */
+
+#include "para.h"
+#include "list.h"
+#include "sched.h"
+#include "client.cmdline.h"
+#include "crypt.h"
+#include "rc4.h"
+#include "net.h"
+#include "fd.h"
+#include "string.h"
+#include "client.h"
+#include "error.h"
+
+void rc4_send(unsigned long len, const unsigned char *indata,
+               unsigned char *outdata, void *private_data)
+{
+       struct private_client_data *pcd = private_data;
+       RC4(&pcd->rc4_send_key, len, indata, outdata);
+}
+
+void rc4_recv(unsigned long len, const unsigned char *indata,
+               unsigned char *outdata, void *private_data)
+{
+       struct private_client_data *pcd = private_data;
+       RC4(&pcd->rc4_recv_key, len, indata, outdata);
+}
+
+
+void client_close(struct private_client_data *pcd)
+{
+       if (pcd)
+               return;
+       if (pcd->fd >= 0)
+               close(pcd->fd);
+       free(pcd->user);
+       free(pcd->config_file);
+       free(pcd->key_file);
+       free(pcd);
+}
+
+int client_parse_config(int argc, char *argv[],
+               struct private_client_data **pcd_ptr)
+{
+       char *home = para_homedir();
+       struct stat statbuf;
+       int ret;
+       struct private_client_data *pcd =
+               para_calloc(sizeof(struct private_client_data));
+
+       pcd->fd = -1;
+       cmdline_parser(argc, argv, &pcd->conf);
+       ret = - E_CLIENT_SYNTAX;
+       if (!pcd->conf.inputs_num)
+               goto out;
+       pcd->user = pcd->conf.user_given?
+               para_strdup(pcd->conf.user_arg) : para_logname();
+
+       pcd->key_file = pcd->conf.key_file_given?
+               para_strdup(pcd->conf.key_file_arg) :
+               make_message("%s/.paraslash/key.%s", home, pcd->user);
+
+       pcd->config_file = pcd->conf.config_file_given?
+               para_strdup(pcd->conf.config_file_arg) :
+               make_message("%s/.paraslash/client.conf", home);
+       ret = stat(pcd->config_file, &statbuf);
+       if (ret && pcd->conf.config_file_given) {
+               ret = -E_NO_CONFIG;
+               goto out;
+       }
+       if (!ret)
+               cmdline_parser_configfile(pcd->config_file, &pcd->conf, 0, 0, 0);
+       ret = 1;
+       *pcd_ptr = pcd;
+       PARA_INFO_LOG(
+               "current loglevel: %d\n"
+               "using config_file: %s\n"
+               "using key_file: %s\n"
+               "connecting to %s:%d\n" ,
+               pcd->conf.loglevel_arg,
+               pcd->config_file,
+               pcd->key_file,
+               pcd->conf.hostname_arg, pcd->conf.server_port_arg
+       );
+out:
+       free(home);
+       if (ret < 0)
+               client_close(pcd);
+       return ret;
+}
+
+void client_pre_select(struct sched *s, struct task *t)
+{
+       struct private_client_data *pcd = t->private_data;
+
+       PARA_INFO_LOG("status %d\n", pcd->status);
+       t->ret = 1;
+       pcd->check_r = 0;
+       pcd->check_w = 0;
+       if (pcd->fd < 0)
+               return;
+       switch (pcd->status) {
+       case CL_CONNECTED:
+       case CL_SENT_AUTH:
+       case CL_SENT_CH_RESPONSE:
+       case CL_SENT_COMMAND:
+               para_fd_set(pcd->fd, &s->rfds, &s->max_fileno);
+               pcd->check_r = 1;
+               return;
+
+       case CL_RECEIVED_WELCOME:
+       case CL_RECEIVED_CHALLENGE:
+       case CL_RECEIVED_PROCEED:
+               para_fd_set(pcd->fd, &s->wfds, &s->max_fileno);
+               pcd->check_w = 1;
+               return;
+
+       case CL_RECEIVING_SERVER_OUTPUT:
+               if (pcd->loaded < CLIENT_BUFSIZE - 1) {
+                       para_fd_set(pcd->fd, &s->rfds, &s->max_fileno);
+                       pcd->check_r = 1;
+               }
+               return;
+       case CL_SENDING_STDIN:
+               if (*pcd->in_loaded) {
+                       PARA_INFO_LOG("loaded: %d\n", *pcd->in_loaded);
+                       para_fd_set(pcd->fd, &s->wfds, &s->max_fileno);
+                       pcd->check_w = 1;
+               } else {
+                       if (*pcd->in_eof) {
+                               t->ret = -E_INPUT_EOF;
+                               s->timeout.tv_sec = 0;
+                               s->timeout.tv_usec = 1;
+                       }
+               }
+               return;
+       }
+}
+
+static ssize_t client_recv_buffer(struct private_client_data *pcd)
+{
+       ssize_t ret = recv_buffer(pcd->fd, pcd->buf + pcd->loaded,
+               CLIENT_BUFSIZE - pcd->loaded);
+       if (!ret)
+               return -E_SERVER_EOF;
+       if (ret > 0)
+               pcd->loaded += ret;
+       return ret;
+
+}
+
+void client_post_select(struct sched *s, struct task *t)
+{
+       struct private_client_data *pcd = t->private_data;
+
+       PARA_INFO_LOG("status %d\n", pcd->status);
+       t->ret = 1;
+       if (pcd->fd < 0)
+               return;
+       if (!pcd->check_r && !pcd->check_w)
+               return;
+       if (pcd->check_r && !FD_ISSET(pcd->fd, &s->rfds))
+               return;
+       if (pcd->check_w && !FD_ISSET(pcd->fd, &s->wfds))
+               return;
+       switch (pcd->status) {
+       case CL_CONNECTED: /* receive welcome message */
+               t->ret = client_recv_buffer(pcd);
+               if (t->ret > 0)
+                       pcd->status = CL_RECEIVED_WELCOME;
+               return;
+       case CL_RECEIVED_WELCOME: /* send auth command */
+               sprintf(pcd->buf, "auth %s%s", pcd->conf.plain_given?
+                       "" : "rc4 ", pcd->user);
+               PARA_INFO_LOG("--> %s\n", pcd->buf);
+               t->ret = send_buffer(pcd->fd, pcd->buf);
+               if (t->ret >= 0)
+                       pcd->status = CL_SENT_AUTH;
+               return;
+       case CL_SENT_AUTH: /* receive challenge number */
+               pcd->loaded = 0;
+               t->ret = client_recv_buffer(pcd);
+               if (t->ret < 0)
+                       return;
+               if (t->ret != 64) {
+                       t->ret = -E_INVALID_CHALLENGE;
+                       PARA_ERROR_LOG("received the following: %s\n", pcd->buf);
+                       return;
+               }
+               PARA_INFO_LOG("%s", "<-- [challenge]\n");
+               /* decrypt challenge number */
+               t->ret = para_decrypt_challenge(pcd->key_file, &pcd->challenge_nr,
+                       (unsigned char *) pcd->buf, 64);
+               if (t->ret > 0)
+                       pcd->status = CL_RECEIVED_CHALLENGE;
+               return;
+       case CL_RECEIVED_CHALLENGE: /* send decrypted challenge */
+               PARA_INFO_LOG("--> %lu\n", pcd->challenge_nr);
+               t->ret = send_va_buffer(pcd->fd, "%s%lu", CHALLENGE_RESPONSE_MSG,
+                       pcd->challenge_nr);
+               if (t->ret > 0)
+                       pcd->status = CL_SENT_CH_RESPONSE;
+               return;
+       case CL_SENT_CH_RESPONSE: /* read server response */
+               {
+               size_t bytes_received;
+               unsigned char rc4_buf[2 * RC4_KEY_LEN] = "";
+               pcd->loaded = 0;
+               t->ret = client_recv_buffer(pcd);
+               if (t->ret < 0)
+                       return;
+               bytes_received = t->ret;
+               PARA_INFO_LOG("++++ server info ++++\n%s\n++++ end of server "
+                       "info ++++\n", pcd->buf);
+               /* check if server has sent "Proceed" message */
+               t->ret = -E_CLIENT_AUTH;
+               if (!strstr(pcd->buf, PROCEED_MSG))
+                       return;
+               t->ret = 1;
+               pcd->status = CL_RECEIVED_PROCEED;
+               if (bytes_received < PROCEED_MSG_LEN + 32)
+                       return;
+               PARA_INFO_LOG("%s", "decrypting session key\n");
+               t->ret = para_decrypt_buffer(pcd->key_file, rc4_buf,
+                       (unsigned char *)pcd->buf + PROCEED_MSG_LEN + 1,
+                       bytes_received - PROCEED_MSG_LEN - 1);
+               if (t->ret < 0)
+                       return;
+               RC4_set_key(&pcd->rc4_send_key, RC4_KEY_LEN, rc4_buf);
+               RC4_set_key(&pcd->rc4_recv_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
+               enable_crypt(pcd->fd, rc4_recv, rc4_send, pcd);
+               }
+       case CL_RECEIVED_PROCEED: /* concat args and send command */
+               {
+               int i;
+               char *command = NULL;
+               for (i = 0; i < pcd->conf.inputs_num; i++) {
+                       char *tmp = command;
+                       command = make_message("%s\n%s", command?
+                               command : "", pcd->conf.inputs[i]);
+                       free(tmp);
+               }
+               command = para_strcat(command, EOC_MSG "\n");
+               PARA_INFO_LOG("--> %s\n", command);
+               t->ret = send_buffer(pcd->fd, command);
+               free(command);
+               if (t->ret > 0)
+                       pcd->status = CL_SENT_COMMAND;
+               return;
+               }
+       case CL_SENT_COMMAND:
+               pcd->loaded = 0;
+               t->ret = client_recv_buffer(pcd);
+               if (t->ret < 0)
+                       return;
+               t->ret = -E_HANDSHAKE_COMPLETE;
+               if (strstr(pcd->buf, AWAITING_DATA_MSG))
+                       pcd->status = CL_SENDING_STDIN;
+               else
+                       pcd->status = CL_RECEIVING_SERVER_OUTPUT;
+               return;
+       case CL_SENDING_STDIN: /* FIXME: might block */
+               PARA_INFO_LOG("loaded: %d\n", *pcd->in_loaded);
+               t->ret = send_bin_buffer(pcd->fd, pcd->inbuf, *pcd->in_loaded);
+               if (t->ret <= 0) {
+                       if (!t->ret)
+                               t->ret = 1;
+                       return;
+               }
+               *pcd->in_loaded = 0; /* FIXME: short writes */
+               return;
+       case CL_RECEIVING_SERVER_OUTPUT:
+               t->ret = client_recv_buffer(pcd);
+               return;
+       }
+
+}
+
+int client_open(struct private_client_data *pcd)
+{
+       int ret;
+       struct hostent *he;
+       struct sockaddr_in their_addr;
+
+       /* get the host info */
+       PARA_NOTICE_LOG("getting host info of %s\n",
+               pcd->conf.hostname_arg);
+       ret = get_host_info(pcd->conf.hostname_arg, &he);
+       if (ret < 0)
+               goto out;
+       /* get new socket */
+       ret = get_socket();
+       if (ret < 0)
+               goto out;
+       pcd->fd = ret;
+       /* init their_addr */
+       init_sockaddr(&their_addr, pcd->conf.server_port_arg, he);
+       /* connect */
+       PARA_NOTICE_LOG("connecting to %s\n", pcd->conf.hostname_arg);
+       ret = para_connect(pcd->fd, &their_addr);
+       if (ret < 0)
+               goto out;
+       pcd->status = CL_CONNECTED;
+       pcd->task.pre_select = client_pre_select;
+       pcd->task.post_select = client_post_select;
+       pcd->task.private_data = pcd;
+       sprintf(pcd->task.status, "client");
+       register_task(&pcd->task);
+       ret = 1;
+out:
+       return ret;
+}
index 00f8dc3..9098ad3 100644 (file)
--- a/command.c
+++ b/command.c
@@ -1069,12 +1069,14 @@ static void init_rc4_keys(void)
        RC4_set_key(&rc4_send_key, RC4_KEY_LEN, rc4_buf + RC4_KEY_LEN);
 }
 
-static void rc4_recv(unsigned long len, const unsigned char *indata, unsigned char *outdata)
+static void rc4_recv(unsigned long len, const unsigned char *indata,
+               unsigned char *outdata, __a_unused void *private_data)
 {
        RC4(&rc4_recv_key, len, indata, outdata);
 }
 
-static void rc4_send(unsigned long len, const unsigned char *indata, unsigned char *outdata)
+static void rc4_send(unsigned long len, const unsigned char *indata,
+               unsigned char *outdata, __a_unused void *private_data)
 {
        RC4(&rc4_send_key, len, indata, outdata);
 }
@@ -1168,7 +1170,7 @@ int handle_connect(int fd, struct sockaddr_in *addr)
        if (ret < 0)
                goto err_out;
        if (use_rc4)
-               enable_crypt(fd, rc4_recv, rc4_send);
+               enable_crypt(fd, rc4_recv, rc4_send, NULL);
        /* read command */
        while ((numbytes = recv_buffer(fd, buf, sizeof(buf))) > 0) {
 //             PARA_INFO_LOG("recvd: %s (%d)\n", buf, numbytes);
index 7f3c85d..49b3198 100644 (file)
@@ -86,7 +86,7 @@ write_ldflags=""
 write_writers="file"
 
 client_cmdline_objs="client.cmdline"
-client_errlist_objs="client net string crypt fd sched stdin stdout"
+client_errlist_objs="client net string crypt fd sched stdin stdout client_common"
 client_ldflags=""
 
 ########################################################################### ssl
diff --git a/error.h b/error.h
index f6f916a..78e3242 100644 (file)
--- a/error.h
+++ b/error.h
@@ -20,6 +20,7 @@
 
 /** \cond list of all subsystems that support the shiny error facility */
 enum para_subsystem {
+       SS_CLIENT,
        SS_GUI,
        SS_TIME,
        SS_WAV,
@@ -31,7 +32,7 @@ enum para_subsystem {
        SS_RECV,
        SS_NET,
        SS_ORTP_RECV,
-       SS_CLIENT,
+       SS_CLIENT_COMMON,
        SS_AUDIOC,
        SS_SCHED,
        SS_AUDIOD,
@@ -77,6 +78,7 @@ enum para_subsystem {
 
 /* these do not need error handling (yet) */
 #define SERVER_ERRORS
+#define CLIENT_ERRORS
 #define WAV_ERRORS
 #define COMPRESS_ERRORS
 #define TIME_ERRORS
@@ -100,12 +102,13 @@ extern const char **para_errlist[];
        PARA_ERROR(AUDIOC_OVERRUN, "audioc buffer overrun"), \
 
 
-#define CLIENT_ERRORS \
+
+
+#define CLIENT_COMMON_ERRORS \
        PARA_ERROR(CLIENT_SYNTAX, "syntax error"), \
        PARA_ERROR(INVALID_CHALLENGE, "did not receive valid challenge"), \
-       PARA_ERROR(CLIENT_AUTH, "authentication failed"), \
-       PARA_ERROR(SHORT_CLIENT_WRITE, "short client write"), \
        PARA_ERROR(NO_CONFIG, "config file not found"), \
+       PARA_ERROR(CLIENT_AUTH, "authentication failed"), \
        PARA_ERROR(SERVER_EOF, "connection closed by para_server"), \
        PARA_ERROR(INPUT_EOF, "end of input"), \
        PARA_ERROR(HANDSHAKE_COMPLETE, ""), /* not really an error */ \
@@ -553,6 +556,7 @@ SS_ENUM(ALSA_WRITER);
 SS_ENUM(FILE_WRITER);
 SS_ENUM(RINGBUFFER);
 SS_ENUM(CLIENT);
+SS_ENUM(CLIENT_COMMON);
 SS_ENUM(AUDIOC);
 /** \endcond */
 #undef PARA_ERROR
diff --git a/net.c b/net.c
index 850a9f3..28bc777 100644 (file)
--- a/net.c
+++ b/net.c
 #include "string.h"
 #include "error.h"
 
-static crypt_function **crypt_functions;
-static unsigned max_crypt_fd;
+struct crypt_data {
+       crypt_function *recv;
+       crypt_function *send;
+       void *private_data;
+};
+
+static struct crypt_data *crypt_data_array;
+static unsigned cda_size = 0;
 
-void enable_crypt(int fd, crypt_function *recv, crypt_function *send)
+void enable_crypt(int fd, crypt_function *recv, crypt_function *send,
+       void *private_data)
 {
-       if (max_crypt_fd < fd) {
-               crypt_functions = para_realloc(crypt_functions,
-                       2 * (fd + 1) * sizeof(crypt_function*));
-               max_crypt_fd = fd;
+       if (fd + 1 > cda_size) {
+               crypt_data_array = para_realloc(crypt_data_array,
+                       (fd + 1) * sizeof(struct crypt_data));
+               memset(crypt_data_array + cda_size * sizeof(struct crypt_data), 0,
+                       (fd + 1 - cda_size) * sizeof(struct crypt_data));
+               cda_size = fd + 1;
        }
-       crypt_functions[2 * fd] = recv;
-       crypt_functions[2 * fd + 1] = send;
+       crypt_data_array[fd].recv = recv;
+       crypt_data_array[fd].send = send;
+       crypt_data_array[fd].private_data = private_data;
        PARA_INFO_LOG("rc4 encryption activated for fd %d\n", fd);
 }
 
 void disable_crypt(int fd)
 {
-       crypt_functions[2 * fd] = NULL;
-       crypt_functions[2 * fd + 1] = NULL;
+       if (cda_size < fd + 1)
+               return;
+       crypt_data_array[fd].recv = NULL;
+       crypt_data_array[fd].send = NULL;
+       crypt_data_array[fd].private_data = NULL;
 }
 
 
@@ -115,14 +128,14 @@ int send_bin_buffer(int fd, const char *buf, size_t len)
        int ret;
        crypt_function *cf = NULL;
 
-       if (fd <= max_crypt_fd)
-               cf = crypt_functions[2 * fd + 1];
-
        if (!len)
                PARA_CRIT_LOG("%s", "len == 0\n");
+       if (fd + 1 <= cda_size)
+               cf = crypt_data_array[fd].send;
        if (cf) {
+               void *private = crypt_data_array[fd].private_data;
                unsigned char *outbuf = para_malloc(len);
-               (*cf)(len, (unsigned char *)buf, outbuf);
+               (*cf)(len, (unsigned char *)buf, outbuf, private);
                ret = sendall(fd, (char *)outbuf, &len);
                free(outbuf);
        } else
@@ -183,13 +196,14 @@ __must_check int recv_bin_buffer(int fd, char *buf, ssize_t size)
        int n;
        crypt_function *cf = NULL;
 
-       if (fd <= max_crypt_fd)
-               cf = crypt_functions[2 * fd];
+       if (fd + 1 <= cda_size)
+               cf = crypt_data_array[fd].recv;
        if (cf) {
                unsigned char *tmp = para_malloc(size);
+               void *private = crypt_data_array[fd].private_data;
                n = recv(fd, tmp, size, 0);
                if (n > 0)
-                       (*cf)(n, tmp, (unsigned char *)buf);
+                       (*cf)(n, tmp, (unsigned char *)buf, private);
                free(tmp);
        } else
                n = recv(fd, buf, size, 0);
diff --git a/net.h b/net.h
index 172e4ae..58732c0 100644 (file)
--- a/net.h
+++ b/net.h
@@ -29,7 +29,7 @@
 #endif
 
 typedef void crypt_function(unsigned long len,
-       const unsigned char *indata, unsigned char *outdata);
+       const unsigned char *indata, unsigned char *outdata, void *private_data);
 
 #include <netdb.h> /* hostent */
 int get_host_info(char *host, struct hostent **ret);
@@ -48,6 +48,7 @@ int recv_cred_buffer(int, char *, size_t);
 ssize_t send_cred_buffer(int, char*);
 int recv_pattern(int fd, const char *pattern, size_t bufsize);
 int init_tcp_socket(int port);
-void enable_crypt(int fd, crypt_function *recv, crypt_function *send);
+void enable_crypt(int fd, crypt_function *recv, crypt_function *send,
+       void *private_data);
 void disable_crypt(int fd);