From 7868411859749906ef464a5142933687904f0eff Mon Sep 17 00:00:00 2001 From: Ben Kibbey Date: Thu, 25 Dec 2014 20:05:18 -0500 Subject: [PATCH] Add STATUS_STATE to indicate client state change. This status message will be sent to all connected clients other than the current one to indicate that the client state has changed. Can be disabled with the new "send_state" configuration parameter. --- doc/config.example | 3 +++ doc/pwmd.html | 10 ++++++++++ doc/pwmd.texi | 12 +++++++++++ src/commands.c | 17 +++++++++++++--- src/common.h | 8 +++++--- src/rcfile.c | 1 + src/status.c | 58 +++++++++++++++++++++++++++++++++++++++++++----------- src/status.h | 4 +++- 8 files changed, 95 insertions(+), 18 deletions(-) diff --git a/doc/config.example b/doc/config.example index 5b6579f9..e30caa50 100644 --- a/doc/config.example +++ b/doc/config.example @@ -155,6 +155,9 @@ # not in a command. #keepalive_interval=60 +# Send client state information to all connected clients. +#send_state=true + # END GLOBAL SETTINGS # File specific settings are allowed by placing the filename in braces. Each diff --git a/doc/pwmd.html b/doc/pwmd.html index 6f08aa95..86d13090 100644 --- a/doc/pwmd.html +++ b/doc/pwmd.html @@ -534,6 +534,12 @@ another pinentry to complete and for the pinentry waiting for user input. lock and returning an error. The default is 50.

+
send_state = boolean
+

When true and the state of a client changes, send a status message to +all connected clients about the client whose state changed (see GETINFO). +The default is true. +

+
@@ -1692,6 +1698,10 @@ exist on the file-system. <sent> <total>Sent to the current client when transferring data. It has two space delimited arguments. The first being the current amount of bytes transferred and the other being the total bytes to be transferred. +STATE +<client_id> <state>Sent to all connected clients to indicate that client_id has +changed to state (see GETINFO to describe the available client +states).
diff --git a/doc/pwmd.texi b/doc/pwmd.texi index ef2af952..d74bc68f 100644 --- a/doc/pwmd.texi +++ b/doc/pwmd.texi @@ -448,6 +448,11 @@ another pinentry to complete and for the pinentry waiting for user input. The default timeout in tenths of a second before giving up waiting for a file lock and returning an error. The default is @code{50}. +@item send_state = boolean +When @code{true} and the state of a client changes, send a status message to +all connected clients about the client whose state changed (@pxref{GETINFO}). +The default is @code{true}. + @end table @cindex Data file configuration options @@ -664,6 +669,13 @@ exist on the file-system. @tab Sent to the current client when transferring data. It has two space delimited arguments. The first being the current amount of bytes transferred and the other being the total bytes to be transferred. + +@item STATE +@cindex STATE +@tab @code{ } +@tab Sent to all connected clients to indicate that @var{client_id} has +changed to @var{state} (@pxref{GETINFO} to describe the available client +states). @end multitable @c Node, Next, Previous, Up diff --git a/src/commands.c b/src/commands.c index 9216a1ef..f5f0ff19 100644 --- a/src/commands.c +++ b/src/commands.c @@ -103,6 +103,16 @@ static gpg_error_t validate_checksum (struct client_s *, struct cache_data_s *); static gpg_error_t update_checksum (struct client_s *client); +void +update_client_state (struct client_s *client, unsigned s) +{ + client->thd->state = s; + + if (config_get_boolean ("global", "send_state")) + send_status_all_not_self (STATUS_STATE, "%p %u", client->thd->tid, + client->thd->state); +} + static gpg_error_t unlock_file_mutex (struct client_s *client, int remove) { @@ -4103,7 +4113,7 @@ command_startup (assuan_context_t ctx, const char *name) client->last_rc = rc = gpg_error (file_modified (client, cmd)); if (!rc) - client->thd->state = CLIENT_STATE_COMMAND; + update_client_state (client, CLIENT_STATE_COMMAND); return rc; } @@ -4124,7 +4134,7 @@ command_finalize (assuan_context_t ctx, gpg_error_t rc) #ifdef WITH_GNUTLS client->thd->buffer_timeout = client->thd->last_buffer_size = 0; #endif - client->thd->state = CLIENT_STATE_IDLE; + update_client_state (client, CLIENT_STATE_IDLE); } static gpg_error_t @@ -4388,6 +4398,7 @@ send_client_list (assuan_context_t ctx) unsigned i, t; char **list = NULL; char *line; + int with_state = config_get_boolean ("global", "send_state"); MUTEX_LOCK (&cn_mutex); pthread_cleanup_push (cleanup_mutex_cb, &cn_mutex); @@ -4410,7 +4421,7 @@ send_client_list (assuan_context_t ctx) #endif thd->cl && thd->cl->flags & FLAG_HAS_LOCK ? 1 : 0, self == thd->tid ? 1 : 0, - thd->state + with_state ? thd->state : CLIENT_STATE_UNKNOWN )) { strv_free (list); diff --git a/src/common.h b/src/common.h index 53863de2..fe9ae5d4 100644 --- a/src/common.h +++ b/src/common.h @@ -58,9 +58,10 @@ #include "status.h" #include "agent.h" -#define CLIENT_STATE_IDLE 0x0000 -#define CLIENT_STATE_COMMAND 0x0001 -#define CLIENT_STATE_DISCON 0x0002 +#define CLIENT_STATE_UNKNOWN 0x0000 +#define CLIENT_STATE_IDLE 0x0001 +#define CLIENT_STATE_COMMAND 0x0002 +#define CLIENT_STATE_DISCON 0x0003 struct client_thread_s { @@ -117,5 +118,6 @@ gpg_error_t do_validate_peer (assuan_context_t ctx, const char *section, gpg_error_t acl_check_common (struct client_s *client, const char *user, uid_t uid, gid_t gid, int *allowed); gpg_error_t peer_is_invoker(struct client_s *client); +void update_client_state (struct client_s *client, unsigned s); #endif diff --git a/src/rcfile.c b/src/rcfile.c index ad2e1e60..243429ca 100644 --- a/src/rcfile.c +++ b/src/rcfile.c @@ -103,6 +103,7 @@ static struct config_params_s { "invoking_user", PARAM_CHARP, NULL}, { "invoking_tls", PARAM_CHARP, NULL}, { "lock_timeout", PARAM_INT, DEFAULT_LOCK_TIMEOUT}, + { "send_state", PARAM_BOOL, "true"}, { NULL, 0, NULL}, }; diff --git a/src/status.c b/src/status.c index 15da1e18..efab94a6 100644 --- a/src/status.c +++ b/src/status.c @@ -115,6 +115,9 @@ send_status (assuan_context_t ctx, status_msg_t which, const char *fmt, ...) line = line + strlen (status) + 1; } break; + case STATUS_STATE: + status = "STATE"; + break; } if (!ctx) @@ -215,8 +218,8 @@ send_status (assuan_context_t ctx, status_msg_t which, const char *fmt, ...) return rc; } -void -send_status_all (status_msg_t s, const char *fmt, ...) +static void +do_send_status_all (status_msg_t s, const char *line, pthread_t *not_tid) { MUTEX_LOCK (&cn_mutex); int i = 0; @@ -229,6 +232,9 @@ send_status_all (status_msg_t s, const char *fmt, ...) char c = 0xff; int match = 0; + if (not_tid && pthread_equal (*not_tid, thd->tid)) + continue; + MUTEX_LOCK (&thd->status_mutex); for (p = thd->msg_queue; p; p = p->next) @@ -240,7 +246,7 @@ send_status_all (status_msg_t s, const char *fmt, ...) } } - if (match) + if (match && s != STATUS_STATE) { MUTEX_UNLOCK (&thd->status_mutex); continue; @@ -248,14 +254,7 @@ send_status_all (status_msg_t s, const char *fmt, ...) msg = xcalloc (1, sizeof (struct status_msg_s)); msg->s = s; - if (fmt) - { - va_list ap; - - va_start (ap, fmt); - str_vasprintf (&msg->line, fmt, ap); - va_end (ap); - } + msg->line = line ? str_dup (line) : NULL; for (p = thd->msg_queue; p && p->next; p = p->next); if (!p) @@ -269,3 +268,40 @@ send_status_all (status_msg_t s, const char *fmt, ...) MUTEX_UNLOCK (&cn_mutex); } + +void +send_status_all_not_self (status_msg_t s, const char *fmt, ...) +{ + char *line = NULL; + pthread_t tid = pthread_self (); + + if (fmt) + { + va_list ap; + + va_start (ap, fmt); + str_vasprintf (&line, fmt, ap); + va_end (ap); + } + + do_send_status_all (s, line, &tid); + xfree (line); +} + +void +send_status_all (status_msg_t s, const char *fmt, ...) +{ + char *line = NULL; + + if (fmt) + { + va_list ap; + + va_start (ap, fmt); + str_vasprintf (&line, fmt, ap); + va_end (ap); + } + + do_send_status_all (s, line, NULL); + xfree (line); +} diff --git a/src/status.h b/src/status.h index d26e6bcd..b57a3444 100644 --- a/src/status.h +++ b/src/status.h @@ -34,7 +34,8 @@ typedef enum STATUS_GENKEY, STATUS_NEWFILE, STATUS_AGENT, - STATUS_KEEPALIVE + STATUS_KEEPALIVE, + STATUS_STATE, } status_msg_t; struct status_msg_s @@ -47,5 +48,6 @@ struct status_msg_s gpg_error_t send_status (assuan_context_t ctx, status_msg_t which, const char *fmt, ...); void send_status_all (status_msg_t s, const char *fmt, ...); +void send_status_all_not_self (status_msg_t s, const char *fmt, ...); #endif -- 2.11.4.GIT