[PATCH v2] alfred: notify event listener via unix socket

2022-05-02 Thread Marek Lindner
The alfred server instance accepts event notification registration
via the unix socket. These notification sockets only inform
registered parties of the availability of an alfred datatype change.
The actual data itself needs to be retrieved via the existing data
retrieval mechanisms.

Unlike the update-command this event monitor allows:

- multiple parallel listeners
- programmatic access to changes without requiring multiple processes

The alfred client allows to monitor events via the newly added '-E'
(event monitor) command line option. Serving as debugging tool and
example code at the same time.

Signed-off-by: Marek Lindner 
---

v2:
- fix typ0s
- replace list_del_init() with list_del()
- remove unnecessary INIT_LIST_HEAD()
- change --event-monitor to not require an argument

 alfred.h |  15 ++
 client.c |  54 
 main.c   |  10 +++-
 man/alfred.8 |   3 ++
 packet.h |  26 ++
 recv.c   |   4 +-
 server.c |   5 ++
 unix_sock.c  | 141 +++
 8 files changed, 256 insertions(+), 2 deletions(-)

diff --git a/alfred.h b/alfred.h
index 2d98a30..f442c48 100644
--- a/alfred.h
+++ b/alfred.h
@@ -94,6 +94,7 @@ enum clientmode {
CLIENT_CHANGE_INTERFACE,
CLIENT_CHANGE_BAT_IFACE,
CLIENT_SERVER_STATUS,
+   CLIENT_EVENT_MONITOR,
 };
 
 struct interface {
@@ -110,8 +111,15 @@ struct interface {
struct list_head list;
 };
 
+struct event_listener {
+   int fd;
+
+   struct list_head list;
+};
+
 struct globals {
struct list_head interfaces;
+   struct list_head event_listeners;
 
char *net_iface;
struct server *best_server; /* NULL if we are a server ourselves */
@@ -157,6 +165,7 @@ int alfred_client_modeswitch(struct globals *globals);
 int alfred_client_change_interface(struct globals *globals);
 int alfred_client_change_bat_iface(struct globals *globals);
 int alfred_client_server_status(struct globals *globals);
+int alfred_client_event_monitor(struct globals *globals);
 /* recv.c */
 int recv_alfred_packet(struct globals *globals, struct interface *interface,
   int recv_sock);
@@ -186,6 +195,12 @@ int unix_sock_open_client(struct globals *globals);
 int unix_sock_close(struct globals *globals);
 int unix_sock_req_data_finish(struct globals *globals,
  struct transaction_head *head);
+int unix_sock_events_select_prepare(struct globals *globals, fd_set *fds,
+   fd_set *errfds, int maxsock);
+void unix_sock_events_select_handle(struct globals *globals,
+   fd_set *fds, fd_set *errfds);
+void unix_sock_events_close_all(struct globals *globals);
+void unix_sock_event_notify(struct globals *globals, uint8_t type);
 /* vis.c */
 int vis_update_data(struct globals *globals);
 /* netsock.c */
diff --git a/client.c b/client.c
index 81cdd7c..d86d23c 100644
--- a/client.c
+++ b/client.c
@@ -452,3 +452,57 @@ err:
unix_sock_close(globals);
return 0;
 }
+
+int alfred_client_event_monitor(struct globals *globals)
+{
+   struct alfred_event_register_v0 event_register;
+   struct alfred_event_notify_v0 event_notify;
+   int ret, len;
+
+   if (unix_sock_open_client(globals))
+   return -1;
+
+   len = sizeof(event_register);
+
+   event_register.header.type = ALFRED_EVENT_REGISTER;
+   event_register.header.version = ALFRED_VERSION;
+   event_register.header.length = 0;
+
+   ret = write(globals->unix_sock, _register, len);
+   if (ret != len) {
+   fprintf(stderr, "%s: only wrote %d of %d bytes: %s\n",
+   __func__, ret, len, strerror(errno));
+   goto err;
+   }
+
+   while (true) {
+   len = read(globals->unix_sock, _notify, 
sizeof(event_notify));
+   if (len == 0) {
+   fprintf(stdout, "Server closed the connection\n");
+   goto err;
+   }
+
+   if (len < 0) {
+   perror("read from unix socket failed");
+   goto err;
+   }
+
+   if (len != sizeof(event_notify)) {
+   fprintf(stderr, "notify read bytes: %d (expected: 
%zu)\n",
+   len, sizeof(event_notify));
+   goto err;
+   }
+
+   if (event_notify.header.version != ALFRED_VERSION)
+   continue;
+
+   if (event_notify.header.type != ALFRED_EVENT_NOTIFY)
+   continue;
+
+   fprintf(stdout, "Event: type = %hhu\n", event_notify.type);
+   }
+
+err:
+   unix_sock_close(globals);
+   return 0;
+}
diff --git a/main.c b/main.c
index 68d6efd..6dfb1e7 100644
--- a/main.c
+++ b/main.c
@@ -39,6 +39,7 @@ static void alfred_usage(void)
printf("  -I, 

[PATCH] alfred: Drop argument requirement from --server-status

2022-05-02 Thread Sven Eckelmann
The short form -S doesn't require a parameter but the --server-status
requires one (which no one reads). If none is supplied, following is
printed:

   ./alfred: option '--server-status' requires an argument

and the execution stops. Just drop this requirement because it is not used
and no where documented.

Fixes: 5a7d28b1866d ("alfred: introduce 'server status' IPC call")
Signed-off-by: Sven Eckelmann 
---
 main.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/main.c b/main.c
index 68d6efd..30e18a5 100644
--- a/main.c
+++ b/main.c
@@ -163,7 +163,7 @@ static struct globals *alfred_init(int argc, char *argv[])
{"modeswitch",  required_argument,  NULL,   'M'},
{"change-interface",required_argument,  NULL,   'I'},
{"change-bat-iface",required_argument,  NULL,   'B'},
-   {"server-status",   required_argument,  NULL,   'S'},
+   {"server-status",   no_argument,NULL,   'S'},
{"unix-path",   required_argument,  NULL,   'u'},
{"update-command",  required_argument,  NULL,   'c'},
{"version", no_argument,NULL,   'v'},
-- 
2.34.1