root/src/noit_listener.c

Revision 4dccf830640c308658d62f7896f78488734381bc, 8.8 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

xpointer-esque inheritence... actually quite neat

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7
8 #include <unistd.h>
9 #include <errno.h>
10 #include <sys/time.h>
11 #include <sys/socket.h>
12 #include <sys/ioctl.h>
13 #include <netinet/in.h>
14 #include <sys/un.h>
15 #include <arpa/inet.h>
16
17 #include "eventer/eventer.h"
18 #include "utils/noit_log.h"
19 #include "noit_listener.h"
20 #include "noit_conf.h"
21
22 static int
23 noit_listener_accept_ssl(eventer_t e, int mask,
24                          void *closure, struct timeval *tv) {
25   int rv;
26   listener_closure_t listener_closure = (listener_closure_t)closure;
27   eventer_ssl_ctx_t *ctx;
28   if(!closure) goto socketfail;
29
30   rv = eventer_SSL_accept(e, &mask);
31   if(rv > 0) {
32     e->callback = listener_closure->dispatch_callback;
33     /* We must make a copy of the acceptor_closure_t for each new
34      * connection.
35      */
36     e->closure = malloc(sizeof(*listener_closure->dispatch_closure));
37     memcpy(e->closure, listener_closure->dispatch_closure,
38            sizeof(*listener_closure->dispatch_closure));
39     return e->callback(e, mask, e->closure, tv);
40   }
41   if(errno == EAGAIN) return mask|EVENTER_EXCEPTION;
42   ctx = eventer_get_eventer_ssl_ctx(e);
43   eventer_ssl_ctx_free(ctx);
44
45  socketfail:
46   eventer_remove_fd(e->fd);
47   e->opset->close(e->fd, &mask, e);
48   return 0;
49 }
50
51 static int
52 noit_listener_acceptor(eventer_t e, int mask,
53                        void *closure, struct timeval *tv) {
54   int conn, newmask = EVENTER_READ;
55   socklen_t salen;
56   listener_closure_t listener_closure = (listener_closure_t)closure;
57   union {
58     struct sockaddr_in addr4;
59     struct sockaddr_in6 addr6;
60     struct sockaddr_un unix;
61   } s;
62
63   if(mask & EVENTER_EXCEPTION) {
64  socketfail:
65     eventer_remove_fd(e->fd);
66     e->opset->close(e->fd, &mask, e);
67     return 0;
68   }
69
70   conn = e->opset->accept(e->fd, (struct sockaddr *)&s, &salen, &newmask, e);
71   if(conn >= 0) {
72     socklen_t on = 1;
73     eventer_t newe;
74     if(ioctl(conn, FIONBIO, &on)) {
75       close(conn);
76       goto accept_bail;
77     }
78     newe = eventer_alloc();
79     newe->fd = conn;
80     newe->mask = EVENTER_READ | EVENTER_WRITE | EVENTER_EXCEPTION;
81     if(listener_closure->sslconfig->size) {
82       char *cert, *key, *ca, *ciphers;
83       eventer_ssl_ctx_t *ctx;
84       /* We have an SSL configuration.  While our socket accept is
85        * complete, we now have to SSL_accept, which could require
86        * several reads and writes and needs its own event callback.
87        */
88 #define SSLCONFGET(var,name) do { \
89   if(!noit_hash_retrieve(listener_closure->sslconfig, name, strlen(name), \
90                          (void **)&var)) var = NULL; } while(0)
91       SSLCONFGET(cert, "certificate_file");
92       SSLCONFGET(key, "key_file");
93       SSLCONFGET(ca, "ca_chain");
94       SSLCONFGET(ciphers, "ciphers");
95       ctx = eventer_ssl_ctx_new(SSL_SERVER, cert, key, ca, ciphers);
96       if(!ctx) {
97         eventer_free(newe);
98         goto socketfail;
99       }
100       EVENTER_ATTACH_SSL(newe, ctx);
101       newe->callback = noit_listener_accept_ssl;
102       newe->closure = listener_closure;
103     }
104     else {
105       newe->callback = listener_closure->dispatch_callback;
106       /* We must make a copy of the acceptor_closure_t for each new
107        * connection.
108        */
109       newe->closure = malloc(sizeof(*listener_closure->dispatch_closure));
110       memcpy(newe->closure, listener_closure->dispatch_closure,
111              sizeof(*listener_closure->dispatch_closure));
112     }
113     eventer_add(newe);
114   }
115  accept_bail:
116   return newmask | EVENTER_EXCEPTION;
117 }
118
119 int
120 noit_listener(char *host, unsigned short port, int type,
121               int backlog, noit_hash_table *sslconfig,
122               noit_hash_table *config,
123               eventer_func_t handler, void *service_ctx) {
124   int rv, fd;
125   int8_t family;
126   int sockaddr_len;
127   socklen_t on;
128   long reuse;
129   listener_closure_t listener_closure;
130   eventer_t event;
131   union {
132     struct in_addr addr4;
133     struct in6_addr addr6;
134   } a;
135   union {
136     struct sockaddr_in addr4;
137     struct sockaddr_in6 addr6;
138     struct sockaddr_un unix;
139   } s;
140   const char *event_name;
141
142   noitL(noit_debug, "noit_listener(%s, %d, %d, %d, %s, %p)\n",
143         host, port, type, backlog,
144         (event_name = eventer_name_for_callback(handler))?event_name:"??",
145         service_ctx);
146   if(host[0] == '/') {
147     family = AF_UNIX;
148   }
149   else {
150     family = AF_INET;
151     rv = inet_pton(family, host, &a);
152     if(rv != 1) {
153       family = AF_INET6;
154       rv = inet_pton(family, host, &a);
155       if(rv != 1) {
156         if(!strcmp(host, "*")) {
157           family = AF_INET;
158           a.addr4.s_addr = INADDR_ANY;
159         } else {
160           noitL(noit_stderr, "Cannot translate '%s' to IP\n", host);
161           return -1;
162         }
163       }
164     }
165   }
166
167   fd = socket(family, type, 0);
168   if(fd < 0) return -1;
169
170   on = 1;
171   if(ioctl(fd, FIONBIO, &on)) {
172     close(fd);
173     return -1;
174   }
175
176   reuse = 1;
177   if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
178                  (void*)&reuse, sizeof(reuse)) != 0) {
179     close(fd);
180     return -1;
181   }
182
183   memset(&s, 0, sizeof(s));
184   if(family == AF_UNIX) {
185     struct stat sb;
186     /* unlink the path iff it is a socket */
187     if(stat(host, &sb) == -1) {
188       if(errno != ENOENT) {
189         noitL(noit_stderr, "%s: %s\n", host, strerror(errno));
190         close(fd);
191         return -1;
192       }
193     }
194     else {
195       if(sb.st_mode & S_IFSOCK)
196         unlink(host);
197       else {
198         noitL(noit_stderr, "unlink %s failed: %s\n", host, strerror(errno));
199         close(fd);
200         return -1;
201       }
202     }
203     strncpy(s.unix.sun_path, host, sizeof(s.unix.sun_path)-1);
204     sockaddr_len = sizeof(s.unix);
205   }
206   else {
207     s.addr6.sin6_family = family;
208     s.addr6.sin6_port = htons(port);
209     memcpy(&s.addr6.sin6_addr, &a, sizeof(a));
210     sockaddr_len = (family == AF_INET) ?  sizeof(s.addr4) : sizeof(s.addr6);
211   }
212   if(bind(fd, (struct sockaddr *)&s, sockaddr_len) < 0) {
213     noitL(noit_stderr, "bind failed[%s]: %s\n", host, strerror(errno));
214     close(fd);
215     return -1;
216   }
217
218   if(type == SOCK_STREAM) {
219     if(listen(fd, backlog) < 0) {
220       close(fd);
221       return -1;
222     }
223   }
224
225   listener_closure = calloc(1, sizeof(*listener_closure));
226   listener_closure->family = family;
227   listener_closure->port = htons(port);
228   listener_closure->sslconfig = calloc(1, sizeof(noit_hash_table));
229   noit_hash_merge_as_dict(listener_closure->sslconfig, sslconfig);
230   listener_closure->dispatch_callback = handler;
231
232   listener_closure->dispatch_closure =
233     calloc(1, sizeof(*listener_closure->dispatch_closure));
234   listener_closure->dispatch_closure->config = config;
235   listener_closure->dispatch_closure->service_ctx = service_ctx;
236
237   event = eventer_alloc();
238   event->fd = fd;
239   event->mask = EVENTER_READ | EVENTER_EXCEPTION;
240   event->callback = noit_listener_acceptor;
241   event->closure = listener_closure;
242
243   eventer_add(event);
244   return 0;
245 }
246
247 void
248 noit_listener_reconfig() {
249   int i, cnt = 0;
250   noit_conf_section_t *listener_configs;
251
252   listener_configs = noit_conf_get_sections(NULL, "/noit/listeners//listener",
253                                             &cnt);
254   noitL(noit_stderr, "Found %d /noit/listeners/listener stanzas\n", cnt);
255   for(i=0; i<cnt; i++) {
256     char address[256];
257     char type[256];
258     unsigned short port;
259     int portint;
260     int backlog;
261     eventer_func_t f;
262     noit_hash_table *sslconfig, *config;
263
264     if(!noit_conf_get_stringbuf(listener_configs[i],
265                                 "ancestor-or-self::node()/@type",
266                                 type, sizeof(type))) {
267       noitL(noit_stderr, "No type specified in listener stanza %d\n", i+1);
268       continue;
269     }
270     f = eventer_callback_for_name(type);
271     if(!f) {
272       noitL(noit_stderr,
273             "Cannot find handler for listener type: '%s'\n", type);
274       continue;
275     }
276     if(!noit_conf_get_stringbuf(listener_configs[i],
277                                 "ancestor-or-self::node()/@address",
278                                 address, sizeof(address))) {
279       address[0] = '*';
280       address[1] = '\0';
281     }
282     if(!noit_conf_get_int(listener_configs[i],
283                           "ancestor-or-self::node()/@port", &portint))
284       portint = 0;
285     port = (unsigned short) portint;
286     if(address[0] != '/' && (portint == 0 || (port != portint))) {
287       /* UNIX sockets don't require a port (they'll ignore it if specified */
288       noitL(noit_stderr,
289             "Invalid port [%d] specified in stanza %d\n", port, i+1);
290       continue;
291     }
292     if(!noit_conf_get_int(listener_configs[i],
293                           "ancestor-or-self::node()/@backlog", &backlog))
294       backlog = 5;
295
296     sslconfig = noit_conf_get_hash(listener_configs[i], "sslconfig");
297     config = noit_conf_get_hash(listener_configs[i], "config");
298
299     noit_listener(address, port, SOCK_STREAM, backlog,
300                   sslconfig, config, f, NULL);
301   }
302 }
303 void
304 noit_listener_init() {
305   eventer_name_callback("noit_listener_acceptor", noit_listener_acceptor);
306   eventer_name_callback("noit_listener_accept_ssl", noit_listener_accept_ssl);
307   noit_listener_reconfig();
308 }
309
Note: See TracBrowser for help on using the browser.