simplify multipath signal handlers
[multipath-tools/.git] / multipathd / uxlsnr.c
1 /*
2  * Original author : tridge@samba.org, January 2002
3  *
4  * Copyright (c) 2005 Christophe Varoqui
5  * Copyright (c) 2005 Benjamin Marzinski, Redhat
6  */
7
8 /*
9  * A simple domain socket listener
10  */
11 #define _GNU_SOURCE
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <unistd.h>
15 #include <stdarg.h>
16 #include <fcntl.h>
17 #include <errno.h>
18 #include <sys/ioctl.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 #include <sys/un.h>
22 #include <sys/poll.h>
23 #include <signal.h>
24 #include <checkers.h>
25 #include <memory.h>
26 #include <debug.h>
27 #include <vector.h>
28 #include <structs.h>
29 #include <structs_vec.h>
30 #include <uxsock.h>
31 #include <defaults.h>
32
33 #include "main.h"
34 #include "cli.h"
35 #include "uxlsnr.h"
36
37 struct timespec sleep_time = {5, 0};
38
39 struct client {
40         int fd;
41         struct client *next, *prev;
42 };
43
44 static struct client *clients;
45 static unsigned num_clients;
46 struct pollfd *polls;
47 volatile sig_atomic_t reconfig_sig = 0;
48 volatile sig_atomic_t log_reset_sig = 0;
49
50 /*
51  * handle a new client joining
52  */
53 static void new_client(int ux_sock)
54 {
55         struct client *c;
56         struct sockaddr addr;
57         socklen_t len = sizeof(addr);
58         int fd;
59
60         fd = accept(ux_sock, &addr, &len);
61
62         if (fd == -1)
63                 return;
64
65         /* put it in our linked list */
66         c = (struct client *)MALLOC(sizeof(*c));
67         memset(c, 0, sizeof(*c));
68         c->fd = fd;
69         c->next = clients;
70         if (c->next) c->next->prev = c;
71         clients = c;
72         num_clients++;
73 }
74
75 /*
76  * kill off a dead client
77  */
78 static void dead_client(struct client *c)
79 {
80         close(c->fd);
81         if (c->prev) c->prev->next = c->next;
82         if (c->next) c->next->prev = c->prev;
83         if (c == clients) clients = c->next;
84         FREE(c);
85         num_clients--;
86 }
87
88 void free_polls (void)
89 {
90         if (polls)
91                 FREE(polls);
92 }
93
94 void uxsock_cleanup(void *arg)
95 {
96         cli_exit();
97         free_polls();
98 }
99
100 /*
101  * entry point
102  */
103 void * uxsock_listen(int (*uxsock_trigger)(char *, char **, int *, void *),
104                         void * trigger_data)
105 {
106         int ux_sock;
107         size_t len;
108         int rlen;
109         char *inbuf;
110         char *reply;
111         sigset_t mask;
112
113         ux_sock = ux_socket_listen(DEFAULT_SOCKET);
114
115         if (ux_sock == -1) {
116                 condlog(0, "ux_socket_listen error");
117                 exit(1);
118         }
119
120         pthread_cleanup_push(uxsock_cleanup, NULL);
121
122         polls = (struct pollfd *)MALLOC(0);
123         pthread_sigmask(SIG_SETMASK, NULL, &mask);
124         sigdelset(&mask, SIGHUP);
125         sigdelset(&mask, SIGUSR1);
126         while (1) {
127                 struct client *c;
128                 int i, poll_count;
129
130                 /* setup for a poll */
131                 polls = REALLOC(polls, (1+num_clients) * sizeof(*polls));
132                 polls[0].fd = ux_sock;
133                 polls[0].events = POLLIN;
134
135                 /* setup the clients */
136                 for (i=1, c = clients; c; i++, c = c->next) {
137                         polls[i].fd = c->fd;
138                         polls[i].events = POLLIN;
139                 }
140
141                 /* most of our life is spent in this call */
142                 poll_count = ppoll(polls, i, &sleep_time, &mask);
143
144                 if (poll_count == -1) {
145                         if (errno == EINTR) {
146                                 handle_signals();
147                                 continue;
148                         }
149
150                         /* something went badly wrong! */
151                         condlog(0, "poll");
152                         pthread_exit(NULL);
153                 }
154
155                 if (poll_count == 0)
156                         continue;
157
158                 /* see if a client wants to speak to us */
159                 for (i=1, c = clients; c; i++) {
160                         struct client *next = c->next;
161
162                         if (polls[i].revents & POLLIN) {
163                                 if (recv_packet(c->fd, &inbuf, &len) != 0) {
164                                         dead_client(c);
165                                 } else {
166                                         inbuf[len - 1] = 0;
167                                         condlog(4, "Got request [%s]", inbuf);
168                                         uxsock_trigger(inbuf, &reply, &rlen,
169                                                        trigger_data);
170                                         if (reply) {
171                                                 if (send_packet(c->fd, reply,
172                                                                 rlen) != 0) {
173                                                         dead_client(c);
174                                                 }
175                                                 condlog(4, "Reply [%d bytes]",
176                                                         rlen);
177                                                 FREE(reply);
178                                                 reply = NULL;
179                                         }
180                                         FREE(inbuf);
181                                 }
182                         }
183                         c = next;
184                 }
185
186                 /* see if we got a new client */
187                 if (polls[0].revents & POLLIN) {
188                         new_client(ux_sock);
189                 }
190         }
191
192         pthread_cleanup_pop(1);
193         close(ux_sock);
194         return NULL;
195 }