X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=client_common.c;h=e34ed641401c7b91f612e8e5922c0fbd19baa0ac;hp=eb9f9e1fcda2a49ba960582ba67be9c882897a20;hb=e151dbb79eac16326585ec0a33cf48029f5f22f4;hpb=82d08fb6da4dfc7d93d1ee0cce4706721378fe12 diff --git a/client_common.c b/client_common.c index eb9f9e1f..e34ed641 100644 --- a/client_common.c +++ b/client_common.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1997-2011 Andre Noll + * Copyright (C) 1997-2012 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -27,24 +27,45 @@ #define CLIENT_BUFSIZE 4000 /** - * Close the connection to para_server and free all resources. + * Close the connection to para_server and deallocate per-command ressources. * - * \param ct Pointer to the client data. + * \param ct The client task. + * + * This frees all ressources of the current command but keeps the configuration + * in \p ct->conf. * - * \sa client_open. + * \sa \ref client_close(). */ -void client_close(struct client_task *ct) +void client_disconnect(struct client_task *ct) { if (!ct) return; if (ct->scc.fd >= 0) close(ct->scc.fd); + free_argv(ct->features); sc_free(ct->scc.recv); + ct->scc.recv = NULL; sc_free(ct->scc.send); + ct->scc.send = NULL; + btr_free_node(ct->btrn); + ct->btrn = NULL; +} + +/** + * Close the connection to para_server and free all resources. + * + * \param ct Pointer to the client data. + * + * \sa \ref client_open(), \ref client_disconnect(). + */ +void client_close(struct client_task *ct) +{ + if (!ct) + return; + client_disconnect(ct); free(ct->user); free(ct->config_file); free(ct->key_file); - btr_free_node(ct->btrn); client_cmdline_parser_free(&ct->conf); free(ct); } @@ -132,6 +153,31 @@ static int client_recv_buffer(struct client_task *ct, fd_set *rfds, return 0; } +static char **parse_features(char *buf) +{ + int i; + const char id[] = "\nFeatures: "; + char *p, *q, **features; + + p = strstr(buf, id); + if (!p) + return NULL; + p += strlen(id); + q = strchr(p, '\n'); + if (!q) + return NULL; + *q = '\0'; + create_argv(p, ",", &features); + for (i = 0; features[i]; i++) + PARA_INFO_LOG("server feature: %s\n", features[i]); + return features; +} + +static bool has_feature(const char *feature, struct client_task *ct) +{ + return find_arg(feature, ct->features) >= 0? true : false; +} + /** * The post select hook for client commands. * @@ -161,14 +207,19 @@ static void client_post_select(struct sched *s, struct task *t) ret = client_recv_buffer(ct, &s->rfds, buf, sizeof(buf), &n); if (ret < 0 || n == 0) goto out; + ct->features = parse_features(buf); ct->status = CL_RECEIVED_WELCOME; return; case CL_RECEIVED_WELCOME: /* send auth command */ - sprintf(buf, AUTH_REQUEST_MSG "%s", ct->user); - PARA_INFO_LOG("--> %s\n", buf); if (!FD_ISSET(ct->scc.fd, &s->wfds)) return; - ret = send_buffer(ct->scc.fd, buf); + if (has_feature("sideband", ct)) { + ct->use_sideband = true; + sprintf(buf, AUTH_REQUEST_MSG "%s sideband", ct->user); + } else + sprintf(buf, AUTH_REQUEST_MSG "%s", ct->user); + PARA_INFO_LOG("--> %s\n", buf); + ret = write_buffer(ct->scc.fd, buf); if (ret < 0) goto out; ct->status = CL_SENT_AUTH; @@ -198,8 +249,7 @@ static void client_post_select(struct sched *s, struct task *t) SESSION_KEY_LEN); hash_to_asc(challenge_hash, buf); PARA_INFO_LOG("--> %s\n", buf); - ret = send_bin_buffer(ct->scc.fd, (char *)challenge_hash, - HASH_SIZE); + ret = write_all(ct->scc.fd, (char *)challenge_hash, HASH_SIZE); if (ret < 0) goto out; ct->status = CL_SENT_CH_RESPONSE; @@ -309,25 +359,43 @@ out: } } -/* connect to para_server and register the client task */ -static int client_connect(struct client_task *ct) +/** + * Connect to para_server and register the client task. + * + * \param ct The initialized client task structure. + * \param s The scheduler instance to register the client task to. + * \param parent The parent node of the client btr node. + * \param child The child node of the client node. + * + * The client task structure given by \a ct must be allocated and initialized + * by \ref client_parse_config() before this function is called. + * + * \return Standard. + */ +int client_connect(struct client_task *ct, struct sched *s, + struct btr_node *parent, struct btr_node *child) { int ret; + PARA_NOTICE_LOG("connecting %s:%d\n", ct->conf.hostname_arg, + ct->conf.server_port_arg); ct->scc.fd = -1; ret = para_connect_simple(IPPROTO_TCP, ct->conf.hostname_arg, ct->conf.server_port_arg); if (ret < 0) return ret; ct->scc.fd = ret; - ct->status = CL_CONNECTED; ret = mark_fd_nonblocking(ct->scc.fd); if (ret < 0) goto err_out; + ct->status = CL_CONNECTED; + ct->btrn = btr_new_node(&(struct btr_node_description) + EMBRACE(.name = "client", .parent = parent, .child = child)); ct->task.pre_select = client_pre_select; ct->task.post_select = client_post_select; + ct->task.error = 0; sprintf(ct->task.status, "client"); - register_task(&ct->task); + register_task(s, &ct->task); return 1; err_out: close(ct->scc.fd); @@ -336,40 +404,36 @@ err_out: } /** - * Open connection to para_server. + * Parse a client configuration. * * \param argc Usual argument count. * \param argv Usual argument vector. - * \param ct_ptr Points to dynamically allocated and initialized client task - * struct upon successful return. + * \param ct_ptr Filled in by this function. * \param loglevel If not \p NULL, the number of the loglevel is stored here. - * \param parent Add the new buffer tree node as a child of this node. - * \param child Add the new buffer tree node as a parent of this node. * - * Check the command line options given by \a argc and argv, set default values - * for user name and rsa key file, read further option from the config file. - * Finally, establish a connection to para_server. + * This checks the command line options given by \a argc and \a argv, sets + * default values for the user name and the name of the rsa key file and reads + * further options from the config file. * - * \return Standard. + * Upon successful return, \a ct_ptr points to a dynamically allocated and + * initialized client task struct. + * + * \return The number of non-option arguments in \a argc/argv on success, + * negative on errors. */ -int client_open(int argc, char *argv[], struct client_task **ct_ptr, - int *loglevel, struct btr_node *parent, struct btr_node *child) +int client_parse_config(int argc, char *argv[], struct client_task **ct_ptr, + int *loglevel) { char *home = para_homedir(); int ret; struct client_task *ct = para_calloc(sizeof(struct client_task)); - ct->btrn = btr_new_node(&(struct btr_node_description) - EMBRACE(.name = "client", .parent = parent, .child = child)); *ct_ptr = ct; ct->scc.fd = -1; ret = -E_CLIENT_SYNTAX; if (client_cmdline_parser(argc, argv, &ct->conf)) goto out; HANDLE_VERSION_FLAG("client", ct->conf); - ret = -E_CLIENT_SYNTAX; - if (!ct->conf.inputs_num) - goto out; ct->config_file = ct->conf.config_file_given? para_strdup(ct->conf.config_file_arg) : @@ -411,16 +475,52 @@ int client_open(int argc, char *argv[], struct client_task **ct_ptr, PARA_INFO_LOG("loglevel: %s\n", ct->conf.loglevel_arg); PARA_INFO_LOG("config_file: %s\n", ct->config_file); PARA_INFO_LOG("key_file: %s\n", ct->key_file); - PARA_NOTICE_LOG("connecting %s:%d\n", ct->conf.hostname_arg, - ct->conf.server_port_arg); - ret = client_connect(ct); + ret = ct->conf.inputs_num; out: free(home); if (ret < 0) { PARA_ERROR_LOG("%s\n", para_strerror(-ret)); - btr_remove_node(ct->btrn); client_close(ct); *ct_ptr = NULL; } return ret; } + +/** + * Parse the client configuration and open a connection to para_server. + * + * \param argc See \ref client_parse_config. + * \param argv See \ref client_parse_config. + * \param ct_ptr See \ref client_parse_config. + * \param loglevel See \ref client_parse_config. + * \param parent See \ref client_connect(). + * \param child See \ref client_connect(). + * \param sched See \ref client_connect(). + * + * This function combines client_parse_config() and client_connect(). It is + * considered a syntax error if no command was given, i.e. if the number + * of non-option arguments is zero. + * + * \return Standard. + */ +int client_open(int argc, char *argv[], struct client_task **ct_ptr, + int *loglevel, struct btr_node *parent, struct btr_node *child, + struct sched *sched) +{ + int ret = client_parse_config(argc, argv, ct_ptr, loglevel); + + if (ret < 0) + return ret; + if (ret == 0) { + ret = -E_CLIENT_SYNTAX; + goto fail; + } + ret = client_connect(*ct_ptr, sched, parent, child); + if (ret < 0) + goto fail; + return 1; +fail: + client_close(*ct_ptr); + *ct_ptr = NULL; + return ret; +}