xref: /openbmc/libmctp/utils/mctp-demux-daemon.c (revision 0b278a63)
13d36ee2eSJeremy Kerr /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
23d36ee2eSJeremy Kerr 
38e31cfd1SJeremy Kerr #define _GNU_SOURCE
48e31cfd1SJeremy Kerr 
58e31cfd1SJeremy Kerr #include <assert.h>
68e31cfd1SJeremy Kerr #include <err.h>
78e31cfd1SJeremy Kerr #include <getopt.h>
88e31cfd1SJeremy Kerr #include <poll.h>
98e31cfd1SJeremy Kerr #include <stdio.h>
108e31cfd1SJeremy Kerr #include <stdlib.h>
118e31cfd1SJeremy Kerr #include <string.h>
128e31cfd1SJeremy Kerr #include <unistd.h>
138e31cfd1SJeremy Kerr 
148e31cfd1SJeremy Kerr #include <sys/socket.h>
158e31cfd1SJeremy Kerr #include <sys/un.h>
168e31cfd1SJeremy Kerr 
178e31cfd1SJeremy Kerr #include "libmctp.h"
188e31cfd1SJeremy Kerr #include "libmctp-serial.h"
198e31cfd1SJeremy Kerr #include "libmctp-astlpc.h"
208e31cfd1SJeremy Kerr 
218e31cfd1SJeremy Kerr #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
228e31cfd1SJeremy Kerr 
238e31cfd1SJeremy Kerr static const mctp_eid_t local_eid_default = 8;
248e31cfd1SJeremy Kerr static char sockname[] = "\0mctp-mux";
258e31cfd1SJeremy Kerr 
268e31cfd1SJeremy Kerr struct binding {
278e31cfd1SJeremy Kerr 	const char	*name;
288e31cfd1SJeremy Kerr 	int		(*init)(struct mctp *mctp, struct binding *binding,
298e31cfd1SJeremy Kerr 				mctp_eid_t eid, int n_params,
308e31cfd1SJeremy Kerr 				char * const * params);
318e31cfd1SJeremy Kerr 	int		(*get_fd)(struct binding *binding);
328e31cfd1SJeremy Kerr 	int		(*process)(struct binding *binding);
338e31cfd1SJeremy Kerr 	void		*data;
348e31cfd1SJeremy Kerr };
358e31cfd1SJeremy Kerr 
368e31cfd1SJeremy Kerr struct client {
378e31cfd1SJeremy Kerr 	bool		active;
388e31cfd1SJeremy Kerr 	int		sock;
398e31cfd1SJeremy Kerr 	uint8_t		type;
408e31cfd1SJeremy Kerr };
418e31cfd1SJeremy Kerr 
428e31cfd1SJeremy Kerr struct ctx {
438e31cfd1SJeremy Kerr 	struct mctp	*mctp;
448e31cfd1SJeremy Kerr 	struct binding	*binding;
458e31cfd1SJeremy Kerr 	bool		verbose;
468e31cfd1SJeremy Kerr 	int		local_eid;
478e31cfd1SJeremy Kerr 
488e31cfd1SJeremy Kerr 	int		sock;
498e31cfd1SJeremy Kerr 	struct pollfd	*pollfds;
508e31cfd1SJeremy Kerr 
518e31cfd1SJeremy Kerr 	struct client	*clients;
528e31cfd1SJeremy Kerr 	int		n_clients;
538e31cfd1SJeremy Kerr };
548e31cfd1SJeremy Kerr 
558e31cfd1SJeremy Kerr static void tx_message(struct ctx *ctx, mctp_eid_t eid, void *msg, size_t len)
568e31cfd1SJeremy Kerr {
578e31cfd1SJeremy Kerr 	mctp_message_tx(ctx->mctp, eid, msg, len);
588e31cfd1SJeremy Kerr }
598e31cfd1SJeremy Kerr 
608e31cfd1SJeremy Kerr static void client_remove_inactive(struct ctx *ctx)
618e31cfd1SJeremy Kerr {
628e31cfd1SJeremy Kerr 	int i;
638e31cfd1SJeremy Kerr 
648e31cfd1SJeremy Kerr 	for (i = 0; i < ctx->n_clients; i++) {
658e31cfd1SJeremy Kerr 		struct client *client = &ctx->clients[i];
668e31cfd1SJeremy Kerr 		if (client->active)
678e31cfd1SJeremy Kerr 			continue;
688e31cfd1SJeremy Kerr 		close(client->sock);
698e31cfd1SJeremy Kerr 
708e31cfd1SJeremy Kerr 		ctx->n_clients--;
718e31cfd1SJeremy Kerr 		memmove(&ctx->clients[i], &ctx->clients[i+1],
728e31cfd1SJeremy Kerr 				(ctx->n_clients - i) * sizeof(*ctx->clients));
738e31cfd1SJeremy Kerr 		ctx->clients = realloc(ctx->clients,
748e31cfd1SJeremy Kerr 				ctx->n_clients * sizeof(*ctx->clients));
758e31cfd1SJeremy Kerr 	}
768e31cfd1SJeremy Kerr }
778e31cfd1SJeremy Kerr 
788e31cfd1SJeremy Kerr static void rx_message(uint8_t eid, void *data, void *msg, size_t len)
798e31cfd1SJeremy Kerr {
808e31cfd1SJeremy Kerr 	struct ctx *ctx = data;
818e31cfd1SJeremy Kerr 	struct iovec iov[2];
828e31cfd1SJeremy Kerr 	struct msghdr msghdr;
838e31cfd1SJeremy Kerr 	bool removed;
848e31cfd1SJeremy Kerr 	uint8_t type;
858e31cfd1SJeremy Kerr 	int i, rc;
868e31cfd1SJeremy Kerr 
878e31cfd1SJeremy Kerr 	if (len < 2)
888e31cfd1SJeremy Kerr 		return;
898e31cfd1SJeremy Kerr 
908e31cfd1SJeremy Kerr 	type = *(uint8_t *)msg;
918e31cfd1SJeremy Kerr 
928e31cfd1SJeremy Kerr 	if (ctx->verbose)
938e31cfd1SJeremy Kerr 		fprintf(stderr, "MCTP message received: len %zd, type %d\n",
948e31cfd1SJeremy Kerr 				len, type);
958e31cfd1SJeremy Kerr 
968e31cfd1SJeremy Kerr 	memset(&msghdr, 0, sizeof(msghdr));
978e31cfd1SJeremy Kerr 	msghdr.msg_iov = iov;
988e31cfd1SJeremy Kerr 	msghdr.msg_iovlen = 2;
998e31cfd1SJeremy Kerr 	iov[0].iov_base = &eid;
1008e31cfd1SJeremy Kerr 	iov[0].iov_len = 1;
1018e31cfd1SJeremy Kerr 	iov[1].iov_base = msg;
1028e31cfd1SJeremy Kerr 	iov[1].iov_len = len;
1038e31cfd1SJeremy Kerr 
1048e31cfd1SJeremy Kerr 	for (i = 0; i < ctx->n_clients; i++) {
1058e31cfd1SJeremy Kerr 		struct client *client = &ctx->clients[i];
1068e31cfd1SJeremy Kerr 
1078e31cfd1SJeremy Kerr 		if (client->type != type)
1088e31cfd1SJeremy Kerr 			continue;
1098e31cfd1SJeremy Kerr 
1108e31cfd1SJeremy Kerr 		if (ctx->verbose)
1118e31cfd1SJeremy Kerr 			fprintf(stderr, "  forwarding to client %d\n", i);
1128e31cfd1SJeremy Kerr 
1138e31cfd1SJeremy Kerr 		rc = sendmsg(client->sock, &msghdr, 0);
1148e31cfd1SJeremy Kerr 		if (rc != (ssize_t)(len + 1)) {
1158e31cfd1SJeremy Kerr 			client->active = false;
1168e31cfd1SJeremy Kerr 			removed = true;
1178e31cfd1SJeremy Kerr 		}
1188e31cfd1SJeremy Kerr 	}
1198e31cfd1SJeremy Kerr 
1208e31cfd1SJeremy Kerr 	if (removed)
1218e31cfd1SJeremy Kerr 		client_remove_inactive(ctx);
1228e31cfd1SJeremy Kerr 
1238e31cfd1SJeremy Kerr }
1248e31cfd1SJeremy Kerr 
1258e31cfd1SJeremy Kerr static int binding_serial_init(struct mctp *mctp, struct binding *binding,
1268e31cfd1SJeremy Kerr 		mctp_eid_t eid, int n_params, char * const *params)
1278e31cfd1SJeremy Kerr {
1288e31cfd1SJeremy Kerr 	struct mctp_binding_serial *serial;
1298e31cfd1SJeremy Kerr 	const char *path;
1308e31cfd1SJeremy Kerr 	int rc;
1318e31cfd1SJeremy Kerr 
1328e31cfd1SJeremy Kerr 	if (n_params != 1) {
1338e31cfd1SJeremy Kerr 		warnx("serial binding requires device param");
1348e31cfd1SJeremy Kerr 		return -1;
1358e31cfd1SJeremy Kerr 	}
1368e31cfd1SJeremy Kerr 
1378e31cfd1SJeremy Kerr 	path = params[0];
1388e31cfd1SJeremy Kerr 
1398e31cfd1SJeremy Kerr 	serial = mctp_serial_init();
1408e31cfd1SJeremy Kerr 	assert(serial);
1418e31cfd1SJeremy Kerr 
1428e31cfd1SJeremy Kerr 	rc = mctp_serial_open_path(serial, path);
1438e31cfd1SJeremy Kerr 	if (rc)
1448e31cfd1SJeremy Kerr 		return -1;
1458e31cfd1SJeremy Kerr 
1468e31cfd1SJeremy Kerr 	mctp_serial_register_bus(serial, mctp, eid);
1478e31cfd1SJeremy Kerr 
1488e31cfd1SJeremy Kerr 	binding->data = serial;
1498e31cfd1SJeremy Kerr 
1508e31cfd1SJeremy Kerr 	return 0;
1518e31cfd1SJeremy Kerr }
1528e31cfd1SJeremy Kerr 
1538e31cfd1SJeremy Kerr static int binding_serial_get_fd(struct binding *binding)
1548e31cfd1SJeremy Kerr {
1558e31cfd1SJeremy Kerr 	return mctp_serial_get_fd(binding->data);
1568e31cfd1SJeremy Kerr }
1578e31cfd1SJeremy Kerr 
1588e31cfd1SJeremy Kerr static int binding_serial_process(struct binding *binding)
1598e31cfd1SJeremy Kerr {
1608e31cfd1SJeremy Kerr 	return mctp_serial_read(binding->data);
1618e31cfd1SJeremy Kerr }
1628e31cfd1SJeremy Kerr 
1638e31cfd1SJeremy Kerr static int binding_astlpc_init(struct mctp *mctp, struct binding *binding,
1648e31cfd1SJeremy Kerr 		mctp_eid_t eid, int n_params,
1658e31cfd1SJeremy Kerr 		char * const *params __attribute__((unused)))
1668e31cfd1SJeremy Kerr {
1678e31cfd1SJeremy Kerr 	struct mctp_binding_astlpc *astlpc;
1688e31cfd1SJeremy Kerr 
1698e31cfd1SJeremy Kerr 	if (n_params) {
1708e31cfd1SJeremy Kerr 		warnx("astlpc binding does not accept parameters");
1718e31cfd1SJeremy Kerr 		return -1;
1728e31cfd1SJeremy Kerr 	}
1738e31cfd1SJeremy Kerr 
1748e31cfd1SJeremy Kerr 	astlpc = mctp_astlpc_init();
1758e31cfd1SJeremy Kerr 	if (!astlpc) {
1768e31cfd1SJeremy Kerr 		warnx("could not initialise astlpc binding");
1778e31cfd1SJeremy Kerr 		return -1;
1788e31cfd1SJeremy Kerr 	}
1798e31cfd1SJeremy Kerr 
1808e31cfd1SJeremy Kerr 	mctp_astlpc_register_bus(astlpc, mctp, eid);
1818e31cfd1SJeremy Kerr 	binding->data = astlpc;
1828e31cfd1SJeremy Kerr 	return 0;
1838e31cfd1SJeremy Kerr }
1848e31cfd1SJeremy Kerr 
1858e31cfd1SJeremy Kerr static int binding_astlpc_get_fd(struct binding *binding)
1868e31cfd1SJeremy Kerr {
1878e31cfd1SJeremy Kerr 	return mctp_astlpc_get_fd(binding->data);
1888e31cfd1SJeremy Kerr }
1898e31cfd1SJeremy Kerr 
1908e31cfd1SJeremy Kerr static int binding_astlpc_process(struct binding *binding)
1918e31cfd1SJeremy Kerr {
1928e31cfd1SJeremy Kerr 	return mctp_astlpc_poll(binding->data);
1938e31cfd1SJeremy Kerr }
1948e31cfd1SJeremy Kerr 
1958e31cfd1SJeremy Kerr struct binding bindings[] = {
1968e31cfd1SJeremy Kerr 	{
1978e31cfd1SJeremy Kerr 		.name = "serial",
1988e31cfd1SJeremy Kerr 		.init = binding_serial_init,
1998e31cfd1SJeremy Kerr 		.get_fd = binding_serial_get_fd,
2008e31cfd1SJeremy Kerr 		.process = binding_serial_process,
2018e31cfd1SJeremy Kerr 	},
2028e31cfd1SJeremy Kerr 	{
2038e31cfd1SJeremy Kerr 		.name = "astlpc",
2048e31cfd1SJeremy Kerr 		.init = binding_astlpc_init,
2058e31cfd1SJeremy Kerr 		.get_fd = binding_astlpc_get_fd,
2068e31cfd1SJeremy Kerr 		.process = binding_astlpc_process,
2078e31cfd1SJeremy Kerr 	}
2088e31cfd1SJeremy Kerr };
2098e31cfd1SJeremy Kerr 
2108e31cfd1SJeremy Kerr struct binding *binding_lookup(const char *name)
2118e31cfd1SJeremy Kerr {
2128e31cfd1SJeremy Kerr 	struct binding *binding;
2138e31cfd1SJeremy Kerr 	unsigned int i;
2148e31cfd1SJeremy Kerr 
2158e31cfd1SJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(bindings); i++) {
2168e31cfd1SJeremy Kerr 		binding = &bindings[i];
2178e31cfd1SJeremy Kerr 
2188e31cfd1SJeremy Kerr 		if (!strcmp(binding->name, name))
2198e31cfd1SJeremy Kerr 			return binding;
2208e31cfd1SJeremy Kerr 	}
2218e31cfd1SJeremy Kerr 
2228e31cfd1SJeremy Kerr 	return NULL;
2238e31cfd1SJeremy Kerr }
2248e31cfd1SJeremy Kerr 
2258e31cfd1SJeremy Kerr static int socket_init(struct ctx *ctx)
2268e31cfd1SJeremy Kerr {
2278e31cfd1SJeremy Kerr 	struct sockaddr_un addr;
2288e31cfd1SJeremy Kerr 	int namelen, rc;
2298e31cfd1SJeremy Kerr 
2308e31cfd1SJeremy Kerr 	namelen = sizeof(sockname) - 1;
2318e31cfd1SJeremy Kerr 	addr.sun_family = AF_UNIX;
2328e31cfd1SJeremy Kerr 	memcpy(addr.sun_path, sockname, namelen);
2338e31cfd1SJeremy Kerr 
2348e31cfd1SJeremy Kerr 	ctx->sock = socket(AF_UNIX, SOCK_SEQPACKET, 0);
2358e31cfd1SJeremy Kerr 	if (ctx->sock < 0) {
2368e31cfd1SJeremy Kerr 		warn("can't create socket");
2378e31cfd1SJeremy Kerr 		return -1;
2388e31cfd1SJeremy Kerr 	}
2398e31cfd1SJeremy Kerr 
2408e31cfd1SJeremy Kerr 	rc = bind(ctx->sock, (struct sockaddr *)&addr,
2418e31cfd1SJeremy Kerr 			sizeof(addr.sun_family) + namelen);
2428e31cfd1SJeremy Kerr 	if (rc) {
2438e31cfd1SJeremy Kerr 		warn("can't bind socket");
2448e31cfd1SJeremy Kerr 		goto err_close;
2458e31cfd1SJeremy Kerr 	}
2468e31cfd1SJeremy Kerr 
2478e31cfd1SJeremy Kerr 	rc = listen(ctx->sock, 1);
2488e31cfd1SJeremy Kerr 	if (rc) {
2498e31cfd1SJeremy Kerr 		warn("can't listen on socket");
2508e31cfd1SJeremy Kerr 		goto err_close;
2518e31cfd1SJeremy Kerr 	}
2528e31cfd1SJeremy Kerr 
2538e31cfd1SJeremy Kerr 	return 0;
2548e31cfd1SJeremy Kerr 
2558e31cfd1SJeremy Kerr err_close:
2568e31cfd1SJeremy Kerr 	close(ctx->sock);
2578e31cfd1SJeremy Kerr 	return -1;
2588e31cfd1SJeremy Kerr }
2598e31cfd1SJeremy Kerr 
2608e31cfd1SJeremy Kerr static int socket_process(struct ctx *ctx)
2618e31cfd1SJeremy Kerr {
2628e31cfd1SJeremy Kerr 	struct client *client;
2638e31cfd1SJeremy Kerr 	int fd;
2648e31cfd1SJeremy Kerr 
2658e31cfd1SJeremy Kerr 	fd = accept4(ctx->sock, NULL, 0, SOCK_NONBLOCK);
2668e31cfd1SJeremy Kerr 	if (fd < 0)
2678e31cfd1SJeremy Kerr 		return -1;
2688e31cfd1SJeremy Kerr 
2698e31cfd1SJeremy Kerr 	ctx->n_clients++;
2708e31cfd1SJeremy Kerr 	ctx->clients = realloc(ctx->clients,
2718e31cfd1SJeremy Kerr 			ctx->n_clients * sizeof(struct client));
2728e31cfd1SJeremy Kerr 
2738e31cfd1SJeremy Kerr 	client = &ctx->clients[ctx->n_clients-1];
2748e31cfd1SJeremy Kerr 	memset(client, 0, sizeof(client));
2758e31cfd1SJeremy Kerr 	client->active = true;
2768e31cfd1SJeremy Kerr 	client->sock = fd;
2778e31cfd1SJeremy Kerr 
2788e31cfd1SJeremy Kerr 	return 0;
2798e31cfd1SJeremy Kerr }
2808e31cfd1SJeremy Kerr 
2818e31cfd1SJeremy Kerr static int client_process_recv(struct ctx *ctx, int idx)
2828e31cfd1SJeremy Kerr {
2838e31cfd1SJeremy Kerr 	struct client *client = &ctx->clients[idx];
2848e31cfd1SJeremy Kerr 	uint8_t buf[4096];
2858e31cfd1SJeremy Kerr 	int rc;
2868e31cfd1SJeremy Kerr 
2878e31cfd1SJeremy Kerr 	/* are we waiting for a type message? */
2888e31cfd1SJeremy Kerr 	if (!client->type) {
2898e31cfd1SJeremy Kerr 		uint8_t type;
2908e31cfd1SJeremy Kerr 		rc = read(client->sock, &type, 1);
2918e31cfd1SJeremy Kerr 		if (rc <= 0)
2928e31cfd1SJeremy Kerr 			goto out_close;
2938e31cfd1SJeremy Kerr 
2948e31cfd1SJeremy Kerr 		if (type == 0) {
2958e31cfd1SJeremy Kerr 			rc = -1;
2968e31cfd1SJeremy Kerr 			goto out_close;
2978e31cfd1SJeremy Kerr 		}
2988e31cfd1SJeremy Kerr 		if (ctx->verbose)
2998e31cfd1SJeremy Kerr 			fprintf(stderr, "client[%d] registered for type %u\n",
3008e31cfd1SJeremy Kerr 					idx, type);
3018e31cfd1SJeremy Kerr 		client->type = type;
3028e31cfd1SJeremy Kerr 		return 0;
3038e31cfd1SJeremy Kerr 	}
3048e31cfd1SJeremy Kerr 
3058e31cfd1SJeremy Kerr 	/* todo: size detection through MSG_TRUNC or MSG_PEEK */
3068e31cfd1SJeremy Kerr 	rc = recv(client->sock, buf, sizeof(buf), 0);
3078e31cfd1SJeremy Kerr 	if (rc < 0) {
3088e31cfd1SJeremy Kerr 		warn("can't receive from client");
3098e31cfd1SJeremy Kerr 		goto out_close;
3108e31cfd1SJeremy Kerr 	}
3118e31cfd1SJeremy Kerr 
3128e31cfd1SJeremy Kerr 	if (rc == 0) {
3138e31cfd1SJeremy Kerr 		rc = -1;
3148e31cfd1SJeremy Kerr 		goto out_close;
3158e31cfd1SJeremy Kerr 	}
3168e31cfd1SJeremy Kerr 
3178e31cfd1SJeremy Kerr 	if (rc > 0) {
3188e31cfd1SJeremy Kerr 		uint8_t eid = buf[0];
3198e31cfd1SJeremy Kerr 		if (ctx->verbose)
3208e31cfd1SJeremy Kerr 			fprintf(stderr,
3218e31cfd1SJeremy Kerr 				"client[%d] sent message: dest 0x%02x len %d\n",
3228e31cfd1SJeremy Kerr 				idx, eid, rc - 1);
3238e31cfd1SJeremy Kerr 
3248e31cfd1SJeremy Kerr 		tx_message(ctx, eid, buf + 1, rc - 1);
3258e31cfd1SJeremy Kerr 	}
3268e31cfd1SJeremy Kerr 
3278e31cfd1SJeremy Kerr 	return 0;
3288e31cfd1SJeremy Kerr 
3298e31cfd1SJeremy Kerr out_close:
3308e31cfd1SJeremy Kerr 	client->active = false;
3318e31cfd1SJeremy Kerr 	return rc;
3328e31cfd1SJeremy Kerr }
3338e31cfd1SJeremy Kerr 
3348e31cfd1SJeremy Kerr static int binding_init(struct ctx *ctx, const char *name,
3358e31cfd1SJeremy Kerr 		int argc, char * const *argv)
3368e31cfd1SJeremy Kerr {
3378e31cfd1SJeremy Kerr 	int rc;
3388e31cfd1SJeremy Kerr 
3398e31cfd1SJeremy Kerr 	ctx->binding = binding_lookup(name);
3408e31cfd1SJeremy Kerr 	if (!ctx->binding) {
3418e31cfd1SJeremy Kerr 		warnx("no such binding '%s'", name);
3428e31cfd1SJeremy Kerr 		return -1;
3438e31cfd1SJeremy Kerr 	}
3448e31cfd1SJeremy Kerr 
3458e31cfd1SJeremy Kerr 	rc = ctx->binding->init(ctx->mctp, ctx->binding, ctx->local_eid,
3468e31cfd1SJeremy Kerr 			argc, argv);
3478e31cfd1SJeremy Kerr 	return rc;
3488e31cfd1SJeremy Kerr }
3498e31cfd1SJeremy Kerr 
3508e31cfd1SJeremy Kerr enum {
3518e31cfd1SJeremy Kerr 	FD_BINDING = 0,
3528e31cfd1SJeremy Kerr 	FD_SOCKET,
3538e31cfd1SJeremy Kerr 	FD_NR,
3548e31cfd1SJeremy Kerr };
3558e31cfd1SJeremy Kerr 
3568e31cfd1SJeremy Kerr static int run_daemon(struct ctx *ctx)
3578e31cfd1SJeremy Kerr {
3588e31cfd1SJeremy Kerr 	bool clients_changed = false;
3598e31cfd1SJeremy Kerr 	int rc, i;
3608e31cfd1SJeremy Kerr 
3618e31cfd1SJeremy Kerr 	ctx->pollfds = malloc(FD_NR * sizeof(struct pollfd));
3628e31cfd1SJeremy Kerr 
3638e31cfd1SJeremy Kerr 	ctx->pollfds[FD_BINDING].fd =
3648e31cfd1SJeremy Kerr 		ctx->binding->get_fd(ctx->binding);
3658e31cfd1SJeremy Kerr 	ctx->pollfds[FD_BINDING].events = POLLIN;
3668e31cfd1SJeremy Kerr 
3678e31cfd1SJeremy Kerr 	ctx->pollfds[FD_SOCKET].fd = ctx->sock;
3688e31cfd1SJeremy Kerr 	ctx->pollfds[FD_SOCKET].events = POLLIN;
3698e31cfd1SJeremy Kerr 
3708e31cfd1SJeremy Kerr 	mctp_set_rx_all(ctx->mctp, rx_message, ctx);
3718e31cfd1SJeremy Kerr 
3728e31cfd1SJeremy Kerr 	for (;;) {
3738e31cfd1SJeremy Kerr 		if (clients_changed) {
3748e31cfd1SJeremy Kerr 			int i;
3758e31cfd1SJeremy Kerr 
3768e31cfd1SJeremy Kerr 			ctx->pollfds = realloc(ctx->pollfds,
3778e31cfd1SJeremy Kerr 					(ctx->n_clients + FD_NR) *
3788e31cfd1SJeremy Kerr 						sizeof(struct pollfd));
3798e31cfd1SJeremy Kerr 
3808e31cfd1SJeremy Kerr 			for (i = 0; i < ctx->n_clients; i++) {
3818e31cfd1SJeremy Kerr 				ctx->pollfds[FD_NR+i].fd =
3828e31cfd1SJeremy Kerr 					ctx->clients[i].sock;
3838e31cfd1SJeremy Kerr 				ctx->pollfds[FD_NR+i].events = POLLIN;
3848e31cfd1SJeremy Kerr 			}
3858e31cfd1SJeremy Kerr 			clients_changed = false;
3868e31cfd1SJeremy Kerr 		}
3878e31cfd1SJeremy Kerr 
3888e31cfd1SJeremy Kerr 		rc = poll(ctx->pollfds, ctx->n_clients + FD_NR, -1);
3898e31cfd1SJeremy Kerr 		if (rc < 0) {
3908e31cfd1SJeremy Kerr 			warn("poll failed");
3918e31cfd1SJeremy Kerr 			break;
3928e31cfd1SJeremy Kerr 		}
3938e31cfd1SJeremy Kerr 
3948e31cfd1SJeremy Kerr 		if (!rc)
3958e31cfd1SJeremy Kerr 			continue;
3968e31cfd1SJeremy Kerr 
3978e31cfd1SJeremy Kerr 		if (ctx->pollfds[FD_BINDING].revents) {
3988e31cfd1SJeremy Kerr 			rc = ctx->binding->process(ctx->binding);
3998e31cfd1SJeremy Kerr 			if (rc)
4008e31cfd1SJeremy Kerr 				break;
4018e31cfd1SJeremy Kerr 		}
4028e31cfd1SJeremy Kerr 
4038e31cfd1SJeremy Kerr 		for (i = 0; i < ctx->n_clients; i++) {
4048e31cfd1SJeremy Kerr 			if (!ctx->pollfds[FD_NR+i].revents)
4058e31cfd1SJeremy Kerr 				continue;
4068e31cfd1SJeremy Kerr 
4078e31cfd1SJeremy Kerr 			rc = client_process_recv(ctx, i);
4088e31cfd1SJeremy Kerr 			if (rc)
4098e31cfd1SJeremy Kerr 				clients_changed = true;
4108e31cfd1SJeremy Kerr 		}
4118e31cfd1SJeremy Kerr 
4128e31cfd1SJeremy Kerr 		if (ctx->pollfds[FD_SOCKET].revents) {
4138e31cfd1SJeremy Kerr 			rc = socket_process(ctx);
4148e31cfd1SJeremy Kerr 			if (rc)
4158e31cfd1SJeremy Kerr 				break;
4168e31cfd1SJeremy Kerr 			clients_changed = true;
4178e31cfd1SJeremy Kerr 		}
4188e31cfd1SJeremy Kerr 
4198e31cfd1SJeremy Kerr 		if (clients_changed)
4208e31cfd1SJeremy Kerr 			client_remove_inactive(ctx);
4218e31cfd1SJeremy Kerr 
4228e31cfd1SJeremy Kerr 	}
4238e31cfd1SJeremy Kerr 
4248e31cfd1SJeremy Kerr 
4258e31cfd1SJeremy Kerr 	free(ctx->pollfds);
4268e31cfd1SJeremy Kerr 
4278e31cfd1SJeremy Kerr 	return rc;
4288e31cfd1SJeremy Kerr }
4298e31cfd1SJeremy Kerr 
4308e31cfd1SJeremy Kerr static const struct option options[] = {
4318e31cfd1SJeremy Kerr 	{ "verbose", no_argument, 0, 'v' },
4328e31cfd1SJeremy Kerr 	{ "eid", required_argument, 0, 'e' },
4338e31cfd1SJeremy Kerr 	{ 0 },
4348e31cfd1SJeremy Kerr };
4358e31cfd1SJeremy Kerr 
4368e31cfd1SJeremy Kerr static void usage(const char *progname)
4378e31cfd1SJeremy Kerr {
4388e31cfd1SJeremy Kerr 	unsigned int i;
4398e31cfd1SJeremy Kerr 
4408e31cfd1SJeremy Kerr 	fprintf(stderr, "usage: %s <binding> [params]\n", progname);
4418e31cfd1SJeremy Kerr 	fprintf(stderr, "Available bindings:\n");
4428e31cfd1SJeremy Kerr 	for (i = 0; i < ARRAY_SIZE(bindings); i++)
4438e31cfd1SJeremy Kerr 		fprintf(stderr, "  %s\n", bindings[i].name);
4448e31cfd1SJeremy Kerr }
4458e31cfd1SJeremy Kerr 
4468e31cfd1SJeremy Kerr int main(int argc, char * const *argv)
4478e31cfd1SJeremy Kerr {
4488e31cfd1SJeremy Kerr 	struct ctx *ctx, _ctx;
4498e31cfd1SJeremy Kerr 	int rc;
4508e31cfd1SJeremy Kerr 
4518e31cfd1SJeremy Kerr 	ctx = &_ctx;
4528e31cfd1SJeremy Kerr 	ctx->clients = NULL;
4538e31cfd1SJeremy Kerr 	ctx->n_clients = 0;
4548e31cfd1SJeremy Kerr 	ctx->local_eid = local_eid_default;
4558e31cfd1SJeremy Kerr 
4568e31cfd1SJeremy Kerr 	for (;;) {
4578e31cfd1SJeremy Kerr 		rc = getopt_long(argc, argv, "e:v", options, NULL);
4588e31cfd1SJeremy Kerr 		if (rc == -1)
4598e31cfd1SJeremy Kerr 			break;
4608e31cfd1SJeremy Kerr 		switch (rc) {
4618e31cfd1SJeremy Kerr 		case 'v':
4628e31cfd1SJeremy Kerr 			ctx->verbose = true;
4638e31cfd1SJeremy Kerr 			break;
4648e31cfd1SJeremy Kerr 		case 'e':
4658e31cfd1SJeremy Kerr 			ctx->local_eid = atoi(optarg);
4668e31cfd1SJeremy Kerr 			break;
4678e31cfd1SJeremy Kerr 		default:
4688e31cfd1SJeremy Kerr 			fprintf(stderr, "Invalid argument\n");
4698e31cfd1SJeremy Kerr 			return EXIT_FAILURE;
4708e31cfd1SJeremy Kerr 		}
4718e31cfd1SJeremy Kerr 	}
4728e31cfd1SJeremy Kerr 
4738e31cfd1SJeremy Kerr 	if (optind >= argc) {
4748e31cfd1SJeremy Kerr 		fprintf(stderr, "missing binding argument\n");
4758e31cfd1SJeremy Kerr 		usage(argv[0]);
4768e31cfd1SJeremy Kerr 		return EXIT_FAILURE;
4778e31cfd1SJeremy Kerr 	}
4788e31cfd1SJeremy Kerr 
479*0b278a63SJeremy Kerr 	mctp_set_log_stdio(ctx->verbose ? MCTP_LOG_DEBUG : MCTP_LOG_WARNING);
480*0b278a63SJeremy Kerr 
4818e31cfd1SJeremy Kerr 	ctx->mctp = mctp_init();
4828e31cfd1SJeremy Kerr 	assert(ctx->mctp);
4838e31cfd1SJeremy Kerr 
4848e31cfd1SJeremy Kerr 	rc = binding_init(ctx, argv[optind], argc - optind - 1, argv + optind + 1);
4858e31cfd1SJeremy Kerr 	if (rc)
4868e31cfd1SJeremy Kerr 		return EXIT_FAILURE;
4878e31cfd1SJeremy Kerr 
4888e31cfd1SJeremy Kerr 	rc = socket_init(ctx);
4898e31cfd1SJeremy Kerr 	if (rc)
4908e31cfd1SJeremy Kerr 		return EXIT_FAILURE;
4918e31cfd1SJeremy Kerr 
4928e31cfd1SJeremy Kerr 	rc = run_daemon(ctx);
4938e31cfd1SJeremy Kerr 
4948e31cfd1SJeremy Kerr 	return rc ? EXIT_FAILURE : EXIT_SUCCESS;
4958e31cfd1SJeremy Kerr 
4968e31cfd1SJeremy Kerr }
497