blob: 377c985d4eb2955770cf1cc7fbce8743872f7685 [file] [log] [blame]
Willy Tarreaudd815982007-10-16 12:25:14 +02001/*
Willy Tarreau645513a2010-05-24 20:55:15 +02002 * Protocol registration and listener management functions.
Willy Tarreaudd815982007-10-16 12:25:14 +02003 *
Willy Tarreau645513a2010-05-24 20:55:15 +02004 * Copyright 2000-2010 Willy Tarreau <w@1wt.eu>
Willy Tarreaudd815982007-10-16 12:25:14 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
Willy Tarreaubbebbbf2012-05-07 21:22:09 +020013#include <errno.h>
Willy Tarreaudd815982007-10-16 12:25:14 +020014#include <stdio.h>
15#include <string.h>
16
17#include <common/config.h>
Willy Tarreaudabf2e22007-10-28 21:59:24 +010018#include <common/errors.h>
Willy Tarreaudd815982007-10-16 12:25:14 +020019#include <common/mini-clist.h>
20#include <common/standard.h>
Willy Tarreaubbebbbf2012-05-07 21:22:09 +020021#include <common/time.h>
22
23#include <types/global.h>
Willy Tarreaudd815982007-10-16 12:25:14 +020024
Willy Tarreau645513a2010-05-24 20:55:15 +020025#include <proto/acl.h>
Willy Tarreaub648d632007-10-28 22:13:50 +010026#include <proto/fd.h>
Willy Tarreaubbebbbf2012-05-07 21:22:09 +020027#include <proto/freq_ctr.h>
28#include <proto/log.h>
29#include <proto/task.h>
Willy Tarreaub648d632007-10-28 22:13:50 +010030
Willy Tarreaudd815982007-10-16 12:25:14 +020031/* List head of all registered protocols */
32static struct list protocols = LIST_HEAD_INIT(protocols);
33
Willy Tarreaudabf2e22007-10-28 21:59:24 +010034/* This function adds the specified listener's file descriptor to the polling
35 * lists if it is in the LI_LISTEN state. The listener enters LI_READY or
36 * LI_FULL state depending on its number of connections.
37 */
38void enable_listener(struct listener *listener)
39{
40 if (listener->state == LI_LISTEN) {
41 if (listener->nbconn < listener->maxconn) {
Willy Tarreau49b046d2012-08-09 12:11:58 +020042 fd_want_recv(listener->fd);
Willy Tarreaudabf2e22007-10-28 21:59:24 +010043 listener->state = LI_READY;
44 } else {
45 listener->state = LI_FULL;
46 }
47 }
48}
49
50/* This function removes the specified listener's file descriptor from the
51 * polling lists if it is in the LI_READY or in the LI_FULL state. The listener
52 * enters LI_LISTEN.
53 */
54void disable_listener(struct listener *listener)
55{
56 if (listener->state < LI_READY)
57 return;
58 if (listener->state == LI_READY)
Willy Tarreau49b046d2012-08-09 12:11:58 +020059 fd_stop_recv(listener->fd);
Willy Tarreaue6ca1fc2011-07-24 22:03:52 +020060 if (listener->state == LI_LIMITED)
61 LIST_DEL(&listener->wait_queue);
Willy Tarreaudabf2e22007-10-28 21:59:24 +010062 listener->state = LI_LISTEN;
63}
64
Willy Tarreaube58c382011-07-24 18:28:10 +020065/* This function tries to temporarily disable a listener, depending on the OS
66 * capabilities. Linux unbinds the listen socket after a SHUT_RD, and ignores
67 * SHUT_WR. Solaris refuses either shutdown(). OpenBSD ignores SHUT_RD but
68 * closes upon SHUT_WR and refuses to rebind. So a common validation path
69 * involves SHUT_WR && listen && SHUT_RD. In case of success, the FD's polling
70 * is disabled. It normally returns non-zero, unless an error is reported.
71 */
72int pause_listener(struct listener *l)
73{
74 if (l->state <= LI_PAUSED)
75 return 1;
76
77 if (shutdown(l->fd, SHUT_WR) != 0)
78 return 0; /* Solaris dies here */
79
80 if (listen(l->fd, l->backlog ? l->backlog : l->maxconn) != 0)
81 return 0; /* OpenBSD dies here */
82
83 if (shutdown(l->fd, SHUT_RD) != 0)
84 return 0; /* should always be OK */
85
Willy Tarreaue6ca1fc2011-07-24 22:03:52 +020086 if (l->state == LI_LIMITED)
87 LIST_DEL(&l->wait_queue);
88
Willy Tarreau49b046d2012-08-09 12:11:58 +020089 fd_stop_recv(l->fd);
Willy Tarreaube58c382011-07-24 18:28:10 +020090 l->state = LI_PAUSED;
91 return 1;
92}
93
Willy Tarreaue6ca1fc2011-07-24 22:03:52 +020094/* This function tries to resume a temporarily disabled listener. Paused, full,
95 * limited and disabled listeners are handled, which means that this function
96 * may replace enable_listener(). The resulting state will either be LI_READY
97 * or LI_FULL. 0 is returned in case of failure to resume (eg: dead socket).
Willy Tarreaube58c382011-07-24 18:28:10 +020098 */
99int resume_listener(struct listener *l)
100{
101 if (l->state < LI_PAUSED)
102 return 0;
103
104 if (l->state == LI_PAUSED &&
105 listen(l->fd, l->backlog ? l->backlog : l->maxconn) != 0)
106 return 0;
107
108 if (l->state == LI_READY)
109 return 1;
110
Willy Tarreaue6ca1fc2011-07-24 22:03:52 +0200111 if (l->state == LI_LIMITED)
112 LIST_DEL(&l->wait_queue);
113
Willy Tarreaube58c382011-07-24 18:28:10 +0200114 if (l->nbconn >= l->maxconn) {
115 l->state = LI_FULL;
116 return 1;
117 }
118
Willy Tarreau49b046d2012-08-09 12:11:58 +0200119 fd_want_recv(l->fd);
Willy Tarreaube58c382011-07-24 18:28:10 +0200120 l->state = LI_READY;
121 return 1;
122}
123
Willy Tarreau62793712011-07-24 19:23:38 +0200124/* Marks a ready listener as full so that the session code tries to re-enable
125 * it upon next close() using resume_listener().
126 */
127void listener_full(struct listener *l)
128{
129 if (l->state >= LI_READY) {
Willy Tarreaue6ca1fc2011-07-24 22:03:52 +0200130 if (l->state == LI_LIMITED)
131 LIST_DEL(&l->wait_queue);
132
Willy Tarreau49b046d2012-08-09 12:11:58 +0200133 fd_stop_recv(l->fd);
Willy Tarreau62793712011-07-24 19:23:38 +0200134 l->state = LI_FULL;
135 }
136}
137
Willy Tarreaue6ca1fc2011-07-24 22:03:52 +0200138/* Marks a ready listener as limited so that we only try to re-enable it when
139 * resources are free again. It will be queued into the specified queue.
140 */
141void limit_listener(struct listener *l, struct list *list)
142{
143 if (l->state == LI_READY) {
144 LIST_ADDQ(list, &l->wait_queue);
Willy Tarreau49b046d2012-08-09 12:11:58 +0200145 fd_stop_recv(l->fd);
Willy Tarreaue6ca1fc2011-07-24 22:03:52 +0200146 l->state = LI_LIMITED;
147 }
148}
149
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100150/* This function adds all of the protocol's listener's file descriptors to the
151 * polling lists when they are in the LI_LISTEN state. It is intended to be
152 * used as a protocol's generic enable_all() primitive, for use after the
153 * fork(). It puts the listeners into LI_READY or LI_FULL states depending on
154 * their number of connections. It always returns ERR_NONE.
155 */
156int enable_all_listeners(struct protocol *proto)
157{
158 struct listener *listener;
159
160 list_for_each_entry(listener, &proto->listeners, proto_list)
161 enable_listener(listener);
162 return ERR_NONE;
163}
164
165/* This function removes all of the protocol's listener's file descriptors from
166 * the polling lists when they are in the LI_READY or LI_FULL states. It is
167 * intended to be used as a protocol's generic disable_all() primitive. It puts
168 * the listeners into LI_LISTEN, and always returns ERR_NONE.
169 */
170int disable_all_listeners(struct protocol *proto)
171{
172 struct listener *listener;
173
174 list_for_each_entry(listener, &proto->listeners, proto_list)
175 disable_listener(listener);
176 return ERR_NONE;
177}
178
Willy Tarreaue6ca1fc2011-07-24 22:03:52 +0200179/* Dequeues all of the listeners waiting for a resource in wait queue <queue>. */
180void dequeue_all_listeners(struct list *list)
181{
182 struct listener *listener, *l_back;
183
184 list_for_each_entry_safe(listener, l_back, list, wait_queue) {
185 /* This cannot fail because the listeners are by definition in
186 * the LI_LIMITED state. The function also removes the entry
187 * from the queue.
188 */
189 resume_listener(listener);
190 }
191}
192
Willy Tarreaub648d632007-10-28 22:13:50 +0100193/* This function closes the listening socket for the specified listener,
194 * provided that it's already in a listening state. The listener enters the
195 * LI_ASSIGNED state. It always returns ERR_NONE. This function is intended
196 * to be used as a generic function for standard protocols.
197 */
198int unbind_listener(struct listener *listener)
199{
200 if (listener->state == LI_READY)
Willy Tarreau49b046d2012-08-09 12:11:58 +0200201 fd_stop_recv(listener->fd);
Willy Tarreaub648d632007-10-28 22:13:50 +0100202
Willy Tarreaue6ca1fc2011-07-24 22:03:52 +0200203 if (listener->state == LI_LIMITED)
204 LIST_DEL(&listener->wait_queue);
205
Willy Tarreaube58c382011-07-24 18:28:10 +0200206 if (listener->state >= LI_PAUSED) {
Willy Tarreaub648d632007-10-28 22:13:50 +0100207 fd_delete(listener->fd);
208 listener->state = LI_ASSIGNED;
209 }
210 return ERR_NONE;
211}
212
Willy Tarreau3acf8c32007-10-28 22:35:41 +0100213/* This function closes all listening sockets bound to the protocol <proto>,
214 * and the listeners end in LI_ASSIGNED state if they were higher. It does not
215 * detach them from the protocol. It always returns ERR_NONE.
216 */
217int unbind_all_listeners(struct protocol *proto)
218{
219 struct listener *listener;
220
221 list_for_each_entry(listener, &proto->listeners, proto_list)
222 unbind_listener(listener);
223 return ERR_NONE;
224}
225
Willy Tarreau1a64d162007-10-28 22:26:05 +0100226/* Delete a listener from its protocol's list of listeners. The listener's
227 * state is automatically updated from LI_ASSIGNED to LI_INIT. The protocol's
228 * number of listeners is updated. Note that the listener must have previously
229 * been unbound. This is the generic function to use to remove a listener.
230 */
231void delete_listener(struct listener *listener)
232{
233 if (listener->state != LI_ASSIGNED)
234 return;
235 listener->state = LI_INIT;
236 LIST_DEL(&listener->proto_list);
237 listener->proto->nb_listeners--;
238}
239
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200240/* This function is called on a read event from a listening socket, corresponding
241 * to an accept. It tries to accept as many connections as possible, and for each
242 * calls the listener's accept handler (generally the frontend's accept handler).
243 */
Willy Tarreauafad0e02012-08-09 14:45:22 +0200244void listener_accept(int fd)
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200245{
246 struct listener *l = fdtab[fd].owner;
247 struct proxy *p = l->frontend;
248 int max_accept = global.tune.maxaccept;
249 int cfd;
250 int ret;
251
252 if (unlikely(l->nbconn >= l->maxconn)) {
253 listener_full(l);
Willy Tarreauafad0e02012-08-09 14:45:22 +0200254 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200255 }
256
257 if (global.cps_lim && !(l->options & LI_O_UNLIMITED)) {
258 int max = freq_ctr_remain(&global.conn_per_sec, global.cps_lim, 0);
259
260 if (unlikely(!max)) {
261 /* frontend accept rate limit was reached */
262 limit_listener(l, &global_listener_queue);
263 task_schedule(global_listener_queue_task, tick_add(now_ms, next_event_delay(&global.conn_per_sec, global.cps_lim, 0)));
Willy Tarreauafad0e02012-08-09 14:45:22 +0200264 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200265 }
266
267 if (max_accept > max)
268 max_accept = max;
269 }
270
271 if (p && p->fe_sps_lim) {
272 int max = freq_ctr_remain(&p->fe_sess_per_sec, p->fe_sps_lim, 0);
273
274 if (unlikely(!max)) {
275 /* frontend accept rate limit was reached */
276 limit_listener(l, &p->listener_queue);
277 task_schedule(p->task, tick_add(now_ms, next_event_delay(&p->fe_sess_per_sec, p->fe_sps_lim, 0)));
Willy Tarreauafad0e02012-08-09 14:45:22 +0200278 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200279 }
280
281 if (max_accept > max)
282 max_accept = max;
283 }
284
285 /* Note: if we fail to allocate a connection because of configured
286 * limits, we'll schedule a new attempt worst 1 second later in the
287 * worst case. If we fail due to system limits or temporary resource
288 * shortage, we try again 100ms later in the worst case.
289 */
290 while (max_accept--) {
291 struct sockaddr_storage addr;
292 socklen_t laddr = sizeof(addr);
293
294 if (unlikely(actconn >= global.maxconn) && !(l->options & LI_O_UNLIMITED)) {
295 limit_listener(l, &global_listener_queue);
296 task_schedule(global_listener_queue_task, tick_add(now_ms, 1000)); /* try again in 1 second */
Willy Tarreauafad0e02012-08-09 14:45:22 +0200297 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200298 }
299
300 if (unlikely(p && p->feconn >= p->maxconn)) {
301 limit_listener(l, &p->listener_queue);
Willy Tarreauafad0e02012-08-09 14:45:22 +0200302 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200303 }
304
305 cfd = accept(fd, (struct sockaddr *)&addr, &laddr);
306 if (unlikely(cfd == -1)) {
307 switch (errno) {
308 case EAGAIN:
309 case EINTR:
310 case ECONNABORTED:
Willy Tarreauafad0e02012-08-09 14:45:22 +0200311 fd_poll_recv(fd);
312 return; /* nothing more to accept */
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200313 case ENFILE:
314 if (p)
315 send_log(p, LOG_EMERG,
316 "Proxy %s reached system FD limit at %d. Please check system tunables.\n",
317 p->id, maxfd);
318 limit_listener(l, &global_listener_queue);
319 task_schedule(global_listener_queue_task, tick_add(now_ms, 100)); /* try again in 100 ms */
Willy Tarreauafad0e02012-08-09 14:45:22 +0200320 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200321 case EMFILE:
322 if (p)
323 send_log(p, LOG_EMERG,
324 "Proxy %s reached process FD limit at %d. Please check 'ulimit-n' and restart.\n",
325 p->id, maxfd);
326 limit_listener(l, &global_listener_queue);
327 task_schedule(global_listener_queue_task, tick_add(now_ms, 100)); /* try again in 100 ms */
Willy Tarreauafad0e02012-08-09 14:45:22 +0200328 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200329 case ENOBUFS:
330 case ENOMEM:
331 if (p)
332 send_log(p, LOG_EMERG,
333 "Proxy %s reached system memory limit at %d sockets. Please check system tunables.\n",
334 p->id, maxfd);
335 limit_listener(l, &global_listener_queue);
336 task_schedule(global_listener_queue_task, tick_add(now_ms, 100)); /* try again in 100 ms */
Willy Tarreauafad0e02012-08-09 14:45:22 +0200337 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200338 default:
Willy Tarreauafad0e02012-08-09 14:45:22 +0200339 /* unexpected result, let's go back to poll */
340 fd_poll_recv(fd);
341 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200342 }
343 }
344
Willy Tarreaufe7f1ea2012-05-20 19:22:25 +0200345 /* if this connection comes from a known monitoring system, we want to ignore
346 * it as soon as possible, which means closing it immediately if it is only a
347 * TCP-based monitoring check.
348 */
349 if (unlikely((l->options & LI_O_CHK_MONNET) &&
350 (p->mode == PR_MODE_TCP) &&
351 addr.ss_family == AF_INET &&
352 (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr)) {
353 close(cfd);
354 continue;
355 }
356
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200357 if (unlikely(cfd >= global.maxsock)) {
358 send_log(p, LOG_EMERG,
359 "Proxy %s reached the configured maximum connection limit. Please check the global 'maxconn' value.\n",
360 p->id);
361 close(cfd);
362 limit_listener(l, &global_listener_queue);
363 task_schedule(global_listener_queue_task, tick_add(now_ms, 1000)); /* try again in 1 second */
Willy Tarreauafad0e02012-08-09 14:45:22 +0200364 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200365 }
366
367 /* increase the per-process number of cumulated connections */
368 if (!(l->options & LI_O_UNLIMITED)) {
369 update_freq_ctr(&global.conn_per_sec, 1);
370 if (global.conn_per_sec.curr_ctr > global.cps_max)
371 global.cps_max = global.conn_per_sec.curr_ctr;
372 actconn++;
373 }
374
375 jobs++;
376 totalconn++;
377 l->nbconn++;
378
379 if (l->counters) {
380 if (l->nbconn > l->counters->conn_max)
381 l->counters->conn_max = l->nbconn;
382 }
383
384 ret = l->accept(l, cfd, &addr);
385 if (unlikely(ret <= 0)) {
386 /* The connection was closed by session_accept(). Either
387 * we just have to ignore it (ret == 0) or it's a critical
388 * error due to a resource shortage, and we must stop the
389 * listener (ret < 0).
390 */
391 if (!(l->options & LI_O_UNLIMITED))
392 actconn--;
393 jobs--;
394 l->nbconn--;
395 if (ret == 0) /* successful termination */
396 continue;
397
398 limit_listener(l, &global_listener_queue);
399 task_schedule(global_listener_queue_task, tick_add(now_ms, 100)); /* try again in 100 ms */
Willy Tarreauafad0e02012-08-09 14:45:22 +0200400 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200401 }
402
403 if (l->nbconn >= l->maxconn) {
404 listener_full(l);
Willy Tarreauafad0e02012-08-09 14:45:22 +0200405 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200406 }
407
Willy Tarreauaece46a2012-07-06 12:25:58 +0200408 } /* end of while (max_accept--) */
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200409
Willy Tarreauaece46a2012-07-06 12:25:58 +0200410 /* we've exhausted max_accept, so there is no need to poll again */
Willy Tarreauafad0e02012-08-09 14:45:22 +0200411 return;
Willy Tarreaubbebbbf2012-05-07 21:22:09 +0200412}
413
Willy Tarreaudd815982007-10-16 12:25:14 +0200414/* Registers the protocol <proto> */
415void protocol_register(struct protocol *proto)
416{
417 LIST_ADDQ(&protocols, &proto->list);
418}
419
420/* Unregisters the protocol <proto>. Note that all listeners must have
421 * previously been unbound.
422 */
423void protocol_unregister(struct protocol *proto)
424{
425 LIST_DEL(&proto->list);
426 LIST_INIT(&proto->list);
427}
428
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100429/* binds all listeners of all registered protocols. Returns a composition
Willy Tarreaudd815982007-10-16 12:25:14 +0200430 * of ERR_NONE, ERR_RETRYABLE, ERR_FATAL.
431 */
Emeric Bruncf20bf12010-10-22 16:06:11 +0200432int protocol_bind_all(char *errmsg, int errlen)
Willy Tarreaudd815982007-10-16 12:25:14 +0200433{
434 struct protocol *proto;
435 int err;
436
437 err = 0;
438 list_for_each_entry(proto, &protocols, list) {
Emeric Bruncf20bf12010-10-22 16:06:11 +0200439 if (proto->bind_all) {
440 err |= proto->bind_all(proto, errmsg, errlen);
441 if ( err & ERR_ABORT )
442 break;
443 }
Willy Tarreaudd815982007-10-16 12:25:14 +0200444 }
445 return err;
446}
447
448/* unbinds all listeners of all registered protocols. They are also closed.
449 * This must be performed before calling exit() in order to get a chance to
450 * remove file-system based sockets and pipes.
Emeric Bruncf20bf12010-10-22 16:06:11 +0200451 * Returns a composition of ERR_NONE, ERR_RETRYABLE, ERR_FATAL, ERR_ABORT.
Willy Tarreaudd815982007-10-16 12:25:14 +0200452 */
453int protocol_unbind_all(void)
454{
455 struct protocol *proto;
456 int err;
457
458 err = 0;
459 list_for_each_entry(proto, &protocols, list) {
Emeric Bruncf20bf12010-10-22 16:06:11 +0200460 if (proto->unbind_all) {
Willy Tarreaudd815982007-10-16 12:25:14 +0200461 err |= proto->unbind_all(proto);
Emeric Bruncf20bf12010-10-22 16:06:11 +0200462 }
Willy Tarreaudd815982007-10-16 12:25:14 +0200463 }
464 return err;
465}
466
467/* enables all listeners of all registered protocols. This is intended to be
468 * used after a fork() to enable reading on all file descriptors. Returns a
469 * composition of ERR_NONE, ERR_RETRYABLE, ERR_FATAL.
470 */
471int protocol_enable_all(void)
472{
473 struct protocol *proto;
474 int err;
475
476 err = 0;
477 list_for_each_entry(proto, &protocols, list) {
Emeric Bruncf20bf12010-10-22 16:06:11 +0200478 if (proto->enable_all) {
Willy Tarreaudd815982007-10-16 12:25:14 +0200479 err |= proto->enable_all(proto);
Emeric Bruncf20bf12010-10-22 16:06:11 +0200480 }
Willy Tarreaudd815982007-10-16 12:25:14 +0200481 }
482 return err;
483}
484
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100485/* disables all listeners of all registered protocols. This may be used before
486 * a fork() to avoid duplicating poll lists. Returns a composition of ERR_NONE,
487 * ERR_RETRYABLE, ERR_FATAL.
488 */
489int protocol_disable_all(void)
490{
491 struct protocol *proto;
492 int err;
493
494 err = 0;
495 list_for_each_entry(proto, &protocols, list) {
Emeric Bruncf20bf12010-10-22 16:06:11 +0200496 if (proto->disable_all) {
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100497 err |= proto->disable_all(proto);
Emeric Bruncf20bf12010-10-22 16:06:11 +0200498 }
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100499 }
500 return err;
501}
502
Willy Tarreau26d8c592012-05-07 18:12:14 +0200503/* Returns the protocol handler for socket family <family> or NULL if not found */
504struct protocol *protocol_by_family(int family)
505{
506 struct protocol *proto;
507
508 list_for_each_entry(proto, &protocols, list) {
509 if (proto->sock_domain == family)
510 return proto;
511 }
512 return NULL;
513}
514
Willy Tarreau645513a2010-05-24 20:55:15 +0200515/************************************************************************/
516/* All supported ACL keywords must be declared here. */
517/************************************************************************/
518
Willy Tarreaua5e37562011-12-16 17:06:15 +0100519/* set temp integer to the number of connexions to the same listening socket */
Willy Tarreau645513a2010-05-24 20:55:15 +0200520static int
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200521acl_fetch_dconn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
Willy Tarreau24e32d82012-04-23 23:55:44 +0200522 const struct arg *args, struct sample *smp)
Willy Tarreau645513a2010-05-24 20:55:15 +0200523{
Willy Tarreauf853c462012-04-23 18:53:56 +0200524 smp->type = SMP_T_UINT;
525 smp->data.uint = l4->listener->nbconn;
Willy Tarreau645513a2010-05-24 20:55:15 +0200526 return 1;
527}
528
Willy Tarreaua5e37562011-12-16 17:06:15 +0100529/* set temp integer to the id of the socket (listener) */
Willy Tarreau645513a2010-05-24 20:55:15 +0200530static int
Willy Tarreau32a6f2e2012-04-25 10:13:36 +0200531acl_fetch_so_id(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
Willy Tarreau24e32d82012-04-23 23:55:44 +0200532 const struct arg *args, struct sample *smp)
Willy Tarreau37406352012-04-23 16:16:37 +0200533{
Willy Tarreauf853c462012-04-23 18:53:56 +0200534 smp->type = SMP_T_UINT;
535 smp->data.uint = l4->listener->luid;
Willy Tarreau645513a2010-05-24 20:55:15 +0200536 return 1;
537}
538
Willy Tarreau61612d42012-04-19 18:42:05 +0200539/* Note: must not be declared <const> as its list will be overwritten.
540 * Please take care of keeping this list alphabetically sorted.
541 */
Willy Tarreau645513a2010-05-24 20:55:15 +0200542static struct acl_kw_list acl_kws = {{ },{
Willy Tarreau61612d42012-04-19 18:42:05 +0200543 { "dst_conn", acl_parse_int, acl_fetch_dconn, acl_match_int, ACL_USE_NOTHING, 0 },
544 { "so_id", acl_parse_int, acl_fetch_so_id, acl_match_int, ACL_USE_NOTHING, 0 },
Willy Tarreau645513a2010-05-24 20:55:15 +0200545 { NULL, NULL, NULL, NULL },
546}};
547
548__attribute__((constructor))
549static void __protocols_init(void)
550{
551 acl_register_keywords(&acl_kws);
552}
553
554/*
555 * Local variables:
556 * c-indent-level: 8
557 * c-basic-offset: 8
558 * End:
559 */