2 * Original author : tridge@samba.org, January 2002
4 * Copyright (c) 2005 Christophe Varoqui
5 * Copyright (c) 2005 Benjamin Marzinski, Redhat
9 * A simple domain socket listener
18 #include <sys/ioctl.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
31 #include "structs_vec.h"
35 #include "mpath_cmd.h"
36 #include "time-util.h"
42 struct timespec sleep_time = {5, 0};
45 struct list_head node;
49 #define MIN_POLLS 1023
52 pthread_mutex_t client_lock = PTHREAD_MUTEX_INITIALIZER;
55 static bool _socket_client_is_root(int fd);
57 static bool _socket_client_is_root(int fd)
62 len = sizeof(struct ucred);
64 (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &uc, &len) == 0) &&
68 /* Treat error as not root client */
73 * handle a new client joining
75 static void new_client(int ux_sock)
79 socklen_t len = sizeof(addr);
82 fd = accept(ux_sock, &addr, &len);
87 c = (struct client *)MALLOC(sizeof(*c));
92 memset(c, 0, sizeof(*c));
93 INIT_LIST_HEAD(&c->node);
96 /* put it in our linked list */
97 pthread_mutex_lock(&client_lock);
98 list_add_tail(&c->node, &clients);
99 pthread_mutex_unlock(&client_lock);
103 * kill off a dead client
105 static void _dead_client(struct client *c)
108 list_del_init(&c->node);
114 static void dead_client(struct client *c)
116 pthread_cleanup_push(cleanup_lock, &client_lock);
117 pthread_mutex_lock(&client_lock);
119 pthread_cleanup_pop(1);
122 void free_polls (void)
128 void check_timeout(struct timespec start_time, char *inbuf,
129 unsigned int timeout)
131 struct timespec diff_time, end_time;
133 if (start_time.tv_sec &&
134 clock_gettime(CLOCK_MONOTONIC, &end_time) == 0) {
137 timespecsub(&end_time, &start_time, &diff_time);
138 msecs = diff_time.tv_sec * 1000 +
139 diff_time.tv_nsec / (1000 * 1000);
141 condlog(2, "cli cmd '%s' timeout reached "
142 "after %lu.%06lu secs", inbuf,
143 diff_time.tv_sec, diff_time.tv_nsec / 1000);
147 void uxsock_cleanup(void *arg)
149 struct client *client_loop;
150 struct client *client_tmp;
151 long ux_sock = (long)arg;
155 pthread_mutex_lock(&client_lock);
156 list_for_each_entry_safe(client_loop, client_tmp, &clients, node) {
157 _dead_client(client_loop);
159 pthread_mutex_unlock(&client_lock);
168 void * uxsock_listen(uxsock_trigger_fn uxsock_trigger, long ux_sock,
175 int old_clients = MIN_POLLS;
177 condlog(3, "uxsock: startup listener");
178 polls = (struct pollfd *)MALLOC((MIN_POLLS + 1) * sizeof(struct pollfd));
180 condlog(0, "uxsock: failed to allocate poll fds");
184 sigdelset(&mask, SIGINT);
185 sigdelset(&mask, SIGTERM);
186 sigdelset(&mask, SIGHUP);
187 sigdelset(&mask, SIGUSR1);
189 struct client *c, *tmp;
190 int i, poll_count, num_clients;
192 /* setup for a poll */
193 pthread_mutex_lock(&client_lock);
195 list_for_each_entry(c, &clients, node) {
198 if (num_clients != old_clients) {
200 if (num_clients <= MIN_POLLS && old_clients > MIN_POLLS) {
201 new = REALLOC(polls, (1 + MIN_POLLS) *
202 sizeof(struct pollfd));
203 } else if (num_clients <= MIN_POLLS && old_clients <= MIN_POLLS) {
206 new = REALLOC(polls, (1+num_clients) *
207 sizeof(struct pollfd));
210 pthread_mutex_unlock(&client_lock);
211 condlog(0, "%s: failed to realloc %d poll fds",
212 "uxsock", 1 + num_clients);
216 old_clients = num_clients;
219 polls[0].fd = ux_sock;
220 polls[0].events = POLLIN;
222 /* setup the clients */
224 list_for_each_entry(c, &clients, node) {
226 polls[i].events = POLLIN;
229 pthread_mutex_unlock(&client_lock);
231 /* most of our life is spent in this call */
232 poll_count = ppoll(polls, i, &sleep_time, &mask);
234 handle_signals(false);
235 if (poll_count == -1) {
236 if (errno == EINTR) {
237 handle_signals(true);
241 /* something went badly wrong! */
242 condlog(0, "uxsock: poll failed with %d", errno);
247 if (poll_count == 0) {
248 handle_signals(true);
252 /* see if a client wants to speak to us */
253 for (i = 1; i < num_clients + 1; i++) {
254 if (polls[i].revents & POLLIN) {
255 struct timespec start_time;
258 pthread_mutex_lock(&client_lock);
259 list_for_each_entry(tmp, &clients, node) {
260 if (tmp->fd == polls[i].fd) {
265 pthread_mutex_unlock(&client_lock);
267 condlog(4, "cli%d: new fd %d",
271 if (clock_gettime(CLOCK_MONOTONIC, &start_time)
273 start_time.tv_sec = 0;
274 if (recv_packet_from_client(c->fd, &inbuf,
281 condlog(4, "recv_packet_from_client "
285 condlog(4, "cli[%d]: Got request [%s]",
287 uxsock_trigger(inbuf, &reply, &rlen,
288 _socket_client_is_root(c->fd),
291 if (send_packet(c->fd,
295 condlog(4, "cli[%d]: "
302 check_timeout(start_time, inbuf,
307 /* see if we got a non-fatal signal */
308 handle_signals(true);
310 /* see if we got a new client */
311 if (polls[0].revents & POLLIN) {