2 * Copyright (C) 1997 Andre Noll <maan@tuebingen.mpg.de>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file client_common.c Common functions of para_client and para_audiod. */
9 #include <netinet/in.h>
10 #include <sys/socket.h>
12 #include <sys/types.h>
13 #include <arpa/inet.h>
26 #include "client.cmdline.h"
28 #include "buffer_tree.h"
32 /** The size of the receiving buffer. */
33 #define CLIENT_BUFSIZE 4000
36 * Close the connection to para_server and free all resources.
38 * \param ct Pointer to the client data.
40 * \sa \ref client_open().
42 void client_close(struct client_task
*ct
)
47 free(ct
->config_file
);
49 client_cmdline_parser_free(&ct
->conf
);
50 free(ct
->challenge_hash
);
57 * The preselect hook for server commands.
59 * The task pointer must contain a pointer to the initialized client data
60 * structure as it is returned by client_open().
62 * This function checks the state of the connection and adds the file descriptor
63 * of the connection to the read or write fd set of s accordingly.
65 static void client_pre_select(struct sched
*s
, void *context
)
68 struct client_task
*ct
= context
;
75 case CL_SENT_CH_RESPONSE
:
76 para_fd_set(ct
->scc
.fd
, &s
->rfds
, &s
->max_fileno
);
79 case CL_RECEIVED_WELCOME
:
80 case CL_RECEIVED_PROCEED
:
81 case CL_RECEIVED_CHALLENGE
:
82 para_fd_set(ct
->scc
.fd
, &s
->wfds
, &s
->max_fileno
);
87 ret
= btr_node_status(ct
->btrn
[1], 0, BTR_NT_LEAF
);
91 para_fd_set(ct
->scc
.fd
, &s
->wfds
, &s
->max_fileno
);
96 ret
= btr_node_status(ct
->btrn
[0], 0, BTR_NT_ROOT
);
100 para_fd_set(ct
->scc
.fd
, &s
->rfds
, &s
->max_fileno
);
106 static int send_sb(struct client_task
*ct
, int channel
, void *buf
, size_t numbytes
,
107 enum sb_designator band
, bool dont_free
)
109 int ret
, fd
= ct
->scc
.fd
;
112 if (!ct
->sbc
[channel
]) {
113 struct sb_buffer sbb
;
114 sb_transformation trafo
= ct
->status
< CL_RECEIVED_PROCEED
?
116 sbb
= (typeof(sbb
))SBB_INIT(band
, buf
, numbytes
);
117 ct
->sbc
[channel
] = sb_new_send(&sbb
, dont_free
, trafo
, ct
->scc
.send
);
119 ret
= sb_get_send_buffers(ct
->sbc
[channel
], iov
);
120 ret
= xwritev(fd
, iov
, ret
);
122 sb_free(ct
->sbc
[channel
]);
123 ct
->sbc
[channel
] = NULL
;
126 if (sb_sent(ct
->sbc
[channel
], ret
)) {
127 ct
->sbc
[channel
] = NULL
;
133 static int recv_sb(struct client_task
*ct
, fd_set
*rfds
,
134 struct sb_buffer
*result
)
138 sb_transformation trafo
;
142 if (!FD_ISSET(ct
->scc
.fd
, rfds
))
144 if (ct
->status
< CL_SENT_CH_RESPONSE
)
145 trafo
= trafo_context
= NULL
;
148 trafo_context
= ct
->scc
.recv
;
151 ct
->sbc
[0] = sb_new_recv(0, trafo
, trafo_context
);
153 sb_get_recv_buffer(ct
->sbc
[0], &iov
);
154 ret
= read_nonblock(ct
->scc
.fd
, iov
.iov_base
, iov
.iov_len
, rfds
, &n
);
162 ret
= sb_received(ct
->sbc
[0], n
, result
);
172 static char **parse_features(char *buf
)
175 const char id
[] = "\nFeatures: ";
176 char *p
, *q
, **features
;
186 create_argv(p
, ",", &features
);
187 for (i
= 0; features
[i
]; i
++)
188 PARA_INFO_LOG("server feature: %s\n", features
[i
]);
192 static int dispatch_sbb(struct client_task
*ct
, struct sb_buffer
*sbb
)
195 const char *designator
[] = {SB_DESIGNATORS_ARRAY
};
199 if (sbb
->band
< NUM_SB_DESIGNATORS
)
200 PARA_DEBUG_LOG("band: %s\n", designator
[sbb
->band
]);
203 case SBD_AWAITING_DATA
:
204 ct
->status
= CL_SENDING
;
208 if (iov_valid(&sbb
->iov
))
209 btr_add_output(sbb
->iov
.iov_base
, sbb
->iov
.iov_len
,
216 case SBD_WARNING_LOG
:
220 if (iov_valid(&sbb
->iov
)) {
221 int ll
= sbb
->band
- SBD_DEBUG_LOG
;
222 para_log(ll
, "remote: %s", (char *)sbb
->iov
.iov_base
);
226 case SBD_EXIT__SUCCESS
:
227 ret
= -E_SERVER_CMD_SUCCESS
;
229 case SBD_EXIT__FAILURE
:
230 ret
= -E_SERVER_CMD_FAILURE
;
233 PARA_ERROR_LOG("invalid band %d\n", sbb
->band
);
238 free(sbb
->iov
.iov_base
);
240 sbb
->iov
.iov_base
= NULL
;
244 static bool has_feature(const char *feature
, struct client_task
*ct
)
246 return find_arg(feature
, ct
->features
) >= 0? true : false;
249 static int send_sb_command(struct client_task
*ct
)
256 return send_sb(ct
, 0, NULL
, 0, 0, false);
258 for (i
= 0; i
< ct
->conf
.inputs_num
; i
++)
259 len
+= strlen(ct
->conf
.inputs
[i
]) + 1;
260 p
= command
= para_malloc(len
);
261 for (i
= 0; i
< ct
->conf
.inputs_num
; i
++) {
262 strcpy(p
, ct
->conf
.inputs
[i
]);
263 p
+= strlen(ct
->conf
.inputs
[i
]) + 1;
265 PARA_DEBUG_LOG("--> %s\n", command
);
266 return send_sb(ct
, 0, command
, len
, SBD_COMMAND
, false);
270 * The post select hook for client commands.
272 * Depending on the current state of the connection and the status of the read
273 * and write fd sets of s, this function performs the necessary steps to
274 * authenticate the connection, to send the command given by t->private_data
275 * and to receive para_server's output, if any.
277 static int client_post_select(struct sched
*s
, void *context
)
279 struct client_task
*ct
= context
;
282 char buf
[CLIENT_BUFSIZE
];
284 ret
= task_get_notification(ct
->task
);
289 switch (ct
->status
) {
290 case CL_CONNECTED
: /* receive welcome message */
291 ret
= read_nonblock(ct
->scc
.fd
, buf
, sizeof(buf
), &s
->rfds
, &n
);
292 if (ret
< 0 || n
== 0)
294 ct
->features
= parse_features(buf
);
295 if (!has_feature("sideband", ct
)) {
296 PARA_ERROR_LOG("server has no sideband support\n");
297 ret
= -E_INCOMPAT_FEAT
;
300 ct
->status
= CL_RECEIVED_WELCOME
;
302 case CL_RECEIVED_WELCOME
: /* send auth command */
303 if (!FD_ISSET(ct
->scc
.fd
, &s
->wfds
))
305 sprintf(buf
, AUTH_REQUEST_MSG
"%s sideband%s", ct
->user
,
306 has_feature("aes_ctr128", ct
)? ",aes_ctr128" : "");
307 PARA_INFO_LOG("--> %s\n", buf
);
308 ret
= write_buffer(ct
->scc
.fd
, buf
);
311 ct
->status
= CL_SENT_AUTH
;
315 * Receive challenge and session keys, decrypt the challenge and
316 * send back the hash of the decrypted challenge.
319 /* decrypted challenge/session key buffer */
320 unsigned char crypt_buf
[1024];
321 struct sb_buffer sbb
;
324 ret
= recv_sb(ct
, &s
->rfds
, &sbb
);
327 if (sbb
.band
!= SBD_CHALLENGE
) {
329 free(sbb
.iov
.iov_base
);
333 PARA_INFO_LOG("<-- [challenge] (%zu bytes)\n", n
);
334 ret
= priv_decrypt(ct
->key_file
, crypt_buf
,
335 sbb
.iov
.iov_base
, n
);
336 free(sbb
.iov
.iov_base
);
339 ct
->challenge_hash
= para_malloc(HASH_SIZE
);
340 hash_function((char *)crypt_buf
, CHALLENGE_SIZE
, ct
->challenge_hash
);
341 use_aes
= has_feature("aes_ctr128", ct
);
342 ct
->scc
.send
= sc_new(crypt_buf
+ CHALLENGE_SIZE
, SESSION_KEY_LEN
, use_aes
);
343 ct
->scc
.recv
= sc_new(crypt_buf
+ CHALLENGE_SIZE
+ SESSION_KEY_LEN
,
344 SESSION_KEY_LEN
, use_aes
);
345 hash_to_asc(ct
->challenge_hash
, buf
);
346 PARA_INFO_LOG("--> %s\n", buf
);
347 ct
->status
= CL_RECEIVED_CHALLENGE
;
350 case CL_RECEIVED_CHALLENGE
:
351 ret
= send_sb(ct
, 0, ct
->challenge_hash
, HASH_SIZE
,
352 SBD_CHALLENGE_RESPONSE
, false);
354 ct
->challenge_hash
= NULL
;
357 ct
->status
= CL_SENT_CH_RESPONSE
;
359 case CL_SENT_CH_RESPONSE
: /* read server response */
361 struct sb_buffer sbb
;
362 ret
= recv_sb(ct
, &s
->rfds
, &sbb
);
365 free(sbb
.iov
.iov_base
);
366 if (sbb
.band
!= SBD_PROCEED
)
369 ct
->status
= CL_RECEIVED_PROCEED
;
372 case CL_RECEIVED_PROCEED
: /* concat args and send command */
374 if (!FD_ISSET(ct
->scc
.fd
, &s
->wfds
))
376 ret
= send_sb_command(ct
);
379 ct
->status
= CL_EXECUTING
;
386 ret
= btr_node_status(ct
->btrn
[1], 0, BTR_NT_LEAF
);
387 if (ret
== -E_BTR_EOF
) {
388 /* empty blob data packet indicates EOF */
389 PARA_INFO_LOG("blob sent\n");
390 ret
= send_sb(ct
, 1, NULL
, 0, SBD_BLOB_DATA
, true);
396 if (ret
> 0 && FD_ISSET(ct
->scc
.fd
, &s
->wfds
)) {
397 sz
= btr_next_buffer(ct
->btrn
[1], &buf2
);
399 ret
= send_sb(ct
, 1, buf2
, sz
, SBD_BLOB_DATA
, true);
403 btr_consume(ct
->btrn
[1], sz
);
409 ret
= btr_node_status(ct
->btrn
[0], 0, BTR_NT_ROOT
);
412 if (ret
> 0 && FD_ISSET(ct
->scc
.fd
, &s
->rfds
)) {
413 struct sb_buffer sbb
;
414 ret
= recv_sb(ct
, &s
->rfds
, &sbb
);
418 ret
= dispatch_sbb(ct
, &sbb
);
428 PARA_INFO_LOG("channel 1: %s\n", para_strerror(-ret
));
429 btr_remove_node(&ct
->btrn
[1]);
434 PARA_INFO_LOG("channel 0: %s\n", para_strerror(-ret
));
435 btr_remove_node(&ct
->btrn
[0]);
436 if (ct
->btrn
[1] && ct
->status
== CL_SENDING
)
441 btr_remove_node(&ct
->btrn
[0]);
442 btr_remove_node(&ct
->btrn
[1]);
443 if (ret
!= -E_SERVER_CMD_SUCCESS
&& ret
!= -E_SERVER_CMD_FAILURE
)
444 PARA_ERROR_LOG("%s\n", para_strerror(-ret
));
445 if (ct
->scc
.fd
>= 0) {
449 free_argv(ct
->features
);
451 sc_free(ct
->scc
.recv
);
453 sc_free(ct
->scc
.send
);
459 * Connect to para_server and register the client task.
461 * \param ct The initialized client task structure.
462 * \param s The scheduler instance to register the client task to.
463 * \param parent The parent node of the client btr node.
464 * \param child The child node of the client node.
466 * The client task structure given by \a ct must be allocated and initialized
467 * by \ref client_parse_config() before this function is called.
471 int client_connect(struct client_task
*ct
, struct sched
*s
,
472 struct btr_node
*parent
, struct btr_node
*child
)
476 PARA_NOTICE_LOG("connecting %s:%d\n", ct
->conf
.hostname_arg
,
477 ct
->conf
.server_port_arg
);
479 ret
= para_connect_simple(IPPROTO_TCP
, ct
->conf
.hostname_arg
,
480 ct
->conf
.server_port_arg
);
484 ret
= mark_fd_nonblocking(ct
->scc
.fd
);
487 ct
->status
= CL_CONNECTED
;
488 ct
->btrn
[0] = btr_new_node(&(struct btr_node_description
)
489 EMBRACE(.name
= "client recv", .parent
= NULL
, .child
= child
));
490 ct
->btrn
[1] = btr_new_node(&(struct btr_node_description
)
491 EMBRACE(.name
= "client send", .parent
= parent
, .child
= NULL
));
493 ct
->task
= task_register(&(struct task_info
) {
495 .pre_select
= client_pre_select
,
496 .post_select
= client_post_select
,
506 __noreturn
static void print_help_and_die(struct client_task
*ct
)
508 struct ggo_help h
= DEFINE_GGO_HELP(client
);
509 bool d
= ct
->conf
.detailed_help_given
;
511 ggo_print_help(&h
, d
? GPH_STANDARD_FLAGS_DETAILED
: GPH_STANDARD_FLAGS
);
516 * Parse a client configuration.
518 * \param argc Usual argument count.
519 * \param argv Usual argument vector.
520 * \param ct_ptr Filled in by this function.
521 * \param loglevel If not \p NULL, the number of the loglevel is stored here.
523 * This checks the command line options given by \a argc and \a argv, sets
524 * default values for the user name and the name of the rsa key file and reads
525 * further options from the config file.
527 * Upon successful return, \a ct_ptr points to a dynamically allocated and
528 * initialized client task struct.
530 * \return The number of non-option arguments in \a argc/argv on success,
531 * negative on errors.
533 int client_parse_config(int argc
, char *argv
[], struct client_task
**ct_ptr
,
536 char *home
= para_homedir();
538 struct client_task
*ct
= para_calloc(sizeof(struct client_task
));
542 ret
= -E_CLIENT_SYNTAX
;
543 if (client_cmdline_parser(argc
, argv
, &ct
->conf
))
545 version_handle_flag("client", ct
->conf
.version_given
);
546 if (ct
->conf
.help_given
|| ct
->conf
.detailed_help_given
)
547 print_help_and_die(ct
);
549 ct
->config_file
= ct
->conf
.config_file_given
?
550 para_strdup(ct
->conf
.config_file_arg
) :
551 make_message("%s/.paraslash/client.conf", home
);
552 ret
= file_exists(ct
->config_file
);
553 if (!ret
&& ct
->conf
.config_file_given
) {
558 struct client_cmdline_parser_params params
= {
562 .check_ambiguity
= 0,
566 if (client_cmdline_parser_config_file(ct
->config_file
,
570 ct
->user
= ct
->conf
.user_given
?
571 para_strdup(ct
->conf
.user_arg
) : para_logname();
573 if (ct
->conf
.key_file_given
)
574 ct
->key_file
= para_strdup(ct
->conf
.key_file_arg
);
576 ct
->key_file
= make_message("%s/.paraslash/key.%s",
578 if (!file_exists(ct
->key_file
)) {
580 ct
->key_file
= make_message("%s/.ssh/id_rsa", home
);
585 *loglevel
= get_loglevel_by_name(ct
->conf
.loglevel_arg
);
586 PARA_INFO_LOG("loglevel: %s\n", ct
->conf
.loglevel_arg
);
587 PARA_INFO_LOG("config_file: %s\n", ct
->config_file
);
588 PARA_INFO_LOG("key_file: %s\n", ct
->key_file
);
589 ret
= ct
->conf
.inputs_num
;
593 PARA_ERROR_LOG("%s\n", para_strerror(-ret
));
601 * Parse the client configuration and open a connection to para_server.
603 * \param argc See \ref client_parse_config.
604 * \param argv See \ref client_parse_config.
605 * \param ct_ptr See \ref client_parse_config.
606 * \param loglevel See \ref client_parse_config.
607 * \param parent See \ref client_connect().
608 * \param child See \ref client_connect().
609 * \param sched See \ref client_connect().
611 * This function combines client_parse_config() and client_connect(). It is
612 * considered a syntax error if no command was given, i.e. if the number
613 * of non-option arguments is zero.
617 int client_open(int argc
, char *argv
[], struct client_task
**ct_ptr
,
618 int *loglevel
, struct btr_node
*parent
, struct btr_node
*child
,
621 int ret
= client_parse_config(argc
, argv
, ct_ptr
, loglevel
);
626 ret
= -E_CLIENT_SYNTAX
;
629 ret
= client_connect(*ct_ptr
, sched
, parent
, child
);
634 client_close(*ct_ptr
);