496daa81f4cb0c2c733a15508f7c372426c094b1
[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 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <stdarg.h>
15 #include <fcntl.h>
16 #include <errno.h>
17 #include <sys/ioctl.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/un.h>
21 #include <sys/poll.h>
22
23 #include <checkers.h>
24
25 #include <memory.h>
26 #include <debug.h>
27 #include <vector.h>
28 #include <structs.h>
29 #include <uxsock.h>
30 #include <defaults.h>
31
32 #include "uxlsnr.h"
33
34 #define SLEEP_TIME 5000
35
36 struct client {
37         int fd;
38         struct client *next, *prev;
39 };
40
41 static struct client *clients;
42 static unsigned num_clients;
43
44 /*
45  * handle a new client joining
46  */
47 static void new_client(int ux_sock)
48 {
49         struct client *c;
50         struct sockaddr addr;
51         socklen_t len = sizeof(addr);
52         int fd;
53
54         fd = accept(ux_sock, &addr, &len);
55         
56         if (fd == -1)
57                 return;
58
59         /* put it in our linked list */
60         c = (struct client *)MALLOC(sizeof(*c));
61         memset(c, 0, sizeof(*c));
62         c->fd = fd;
63         c->next = clients;
64         if (c->next) c->next->prev = c;
65         clients = c;
66         num_clients++;
67 }
68
69 /*
70  * kill off a dead client
71  */
72 static void dead_client(struct client *c)
73 {
74         close(c->fd);
75         if (c->prev) c->prev->next = c->next;
76         if (c->next) c->next->prev = c->prev;
77         if (c == clients) clients = c->next;
78         FREE(c);
79         num_clients--;
80 }
81
82 void free_polls (void)
83 {
84         FREE(polls);
85 }
86
87 /*
88  * entry point
89  */
90 void * uxsock_listen(int (*uxsock_trigger)(char *, char **, int *, void *),
91                         void * trigger_data)
92 {
93         int ux_sock;
94         size_t len;
95         int rlen;
96         char *inbuf;
97         char *reply;
98
99         ux_sock = ux_socket_listen(DEFAULT_SOCKET);
100
101         if (ux_sock == -1) {
102                 condlog(0, "ux_socket_listen error");
103                 exit(1);
104         }
105
106         polls = (struct pollfd *)MALLOC(0);
107
108         while (1) {
109                 struct client *c;
110                 int i, poll_count;
111
112                 /* setup for a poll */
113                 polls = REALLOC(polls, (1+num_clients) * sizeof(*polls));
114                 polls[0].fd = ux_sock;
115                 polls[0].events = POLLIN;
116
117                 /* setup the clients */
118                 for (i=1, c = clients; c; i++, c = c->next) {
119                         polls[i].fd = c->fd;
120                         polls[i].events = POLLIN;
121                 }
122
123                 /* most of our life is spent in this call */
124                 poll_count = poll(polls, i, SLEEP_TIME);
125                 
126                 if (poll_count == -1) {
127                         if (errno == EINTR)
128                                 continue;
129
130                         /* something went badly wrong! */
131                         condlog(0, "poll");
132                         exit(1);
133                 }
134
135                 if (poll_count == 0)
136                         continue;
137
138                 /* see if a client wants to speak to us */
139                 for (i=1, c = clients; c; i++) {
140                         struct client *next = c->next;
141
142                         if (polls[i].revents & POLLIN) {
143                                 if (recv_packet(c->fd, &inbuf, &len) != 0) {
144                                         dead_client(c);
145                                 } else {
146                                         inbuf[len - 1] = 0;
147                                         condlog(4, "Got request [%s]", inbuf);
148                                         uxsock_trigger(inbuf, &reply, &rlen,
149                                                         trigger_data);
150
151                                         if (reply) {
152                                                 if (send_packet(c->fd, reply,
153                                                      rlen) != 0) {
154                                                         dead_client(c);
155                                                 }
156                                                 FREE(reply);
157                                                 reply = NULL;
158                                         }
159                                         FREE(inbuf);
160                                 }
161                         }
162                         c = next;
163                 }
164
165                 /* see if we got a new client */
166                 if (polls[0].revents & POLLIN) {
167                         new_client(ux_sock);
168                 }
169         }
170
171         return NULL;
172 }