blob: 09770612edac3d2fbfb87ddbcd7ee736f5853174 [file] [log] [blame]
Willy Tarreaubaaee002006-06-26 02:48:02 +02001/*
2 * Proxy variables and functions.
3 *
4 * Copyright 2000-2006 Willy Tarreau <w@1wt.eu>
5 *
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
13#include <fcntl.h>
14#include <unistd.h>
15#include <sys/types.h>
16#include <sys/socket.h>
17#include <sys/stat.h>
18
Willy Tarreau2dd0d472006-06-29 17:53:05 +020019#include <common/defaults.h>
20#include <common/compat.h>
Willy Tarreaue3ba5f02006-06-29 18:54:54 +020021#include <common/config.h>
Willy Tarreau2dd0d472006-06-29 17:53:05 +020022#include <common/time.h>
Willy Tarreaubaaee002006-06-26 02:48:02 +020023
24#include <types/global.h>
25#include <types/polling.h>
26
27#include <proto/client.h>
28#include <proto/fd.h>
29#include <proto/log.h>
30#include <proto/proxy.h>
31
32
33int listeners; /* # of listeners */
34struct proxy *proxy = NULL; /* list of all existing proxies */
35
36
37/*
38 * this function starts all the proxies. Its return value is composed from
39 * ERR_NONE, ERR_RETRYABLE and ERR_FATAL. Retryable errors will only be printed
40 * if <verbose> is not zero.
41 */
42int start_proxies(int verbose)
43{
44 struct proxy *curproxy;
45 struct listener *listener;
46 int err = ERR_NONE;
47 int fd, pxerr;
48
49 for (curproxy = proxy; curproxy != NULL; curproxy = curproxy->next) {
50 if (curproxy->state != PR_STNEW)
51 continue; /* already initialized */
52
53 pxerr = 0;
54 for (listener = curproxy->listen; listener != NULL; listener = listener->next) {
55 if (listener->fd != -1)
56 continue; /* already initialized */
57
58 if ((fd = socket(listener->addr.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
59 if (verbose)
60 Alert("cannot create listening socket for proxy %s. Aborting.\n",
61 curproxy->id);
62 err |= ERR_RETRYABLE;
63 pxerr |= 1;
64 continue;
65 }
66
67 if (fd >= global.maxsock) {
68 Alert("socket(): not enough free sockets for proxy %s. Raise -n argument. Aborting.\n",
69 curproxy->id);
70 close(fd);
71 err |= ERR_FATAL;
72 pxerr |= 1;
73 break;
74 }
75
76 if ((fcntl(fd, F_SETFL, O_NONBLOCK) == -1) ||
77 (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
78 (char *) &one, sizeof(one)) == -1)) {
79 Alert("cannot make socket non-blocking for proxy %s. Aborting.\n",
80 curproxy->id);
81 close(fd);
82 err |= ERR_FATAL;
83 pxerr |= 1;
84 break;
85 }
86
87 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(one)) == -1) {
88 Alert("cannot do so_reuseaddr for proxy %s. Continuing.\n",
89 curproxy->id);
90 }
91
92#ifdef SO_REUSEPORT
93 /* OpenBSD supports this. As it's present in old libc versions of Linux,
94 * it might return an error that we will silently ignore.
95 */
96 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *) &one, sizeof(one));
97#endif
98 if (bind(fd,
99 (struct sockaddr *)&listener->addr,
100 listener->addr.ss_family == AF_INET6 ?
101 sizeof(struct sockaddr_in6) :
102 sizeof(struct sockaddr_in)) == -1) {
103 if (verbose)
104 Alert("cannot bind socket for proxy %s. Aborting.\n",
105 curproxy->id);
106 close(fd);
107 err |= ERR_RETRYABLE;
108 pxerr |= 1;
109 continue;
110 }
111
112 if (listen(fd, curproxy->maxconn) == -1) {
113 if (verbose)
114 Alert("cannot listen to socket for proxy %s. Aborting.\n",
115 curproxy->id);
116 close(fd);
117 err |= ERR_RETRYABLE;
118 pxerr |= 1;
119 continue;
120 }
121
122 /* the socket is ready */
123 listener->fd = fd;
124
125 /* the function for the accept() event */
Willy Tarreau54469402006-07-29 16:59:06 +0200126 fdtab[fd].cb[DIR_RD].f = &event_accept;
127 fdtab[fd].cb[DIR_WR].f = NULL; /* never called */
128 fdtab[fd].cb[DIR_RD].b = fdtab[fd].cb[DIR_WR].b = NULL;
Willy Tarreaubaaee002006-06-26 02:48:02 +0200129 fdtab[fd].owner = (struct task *)curproxy; /* reference the proxy instead of a task */
130 fdtab[fd].state = FD_STLISTEN;
Willy Tarreau2a429502006-10-15 14:52:29 +0200131 MY_FD_SET(fd, StaticReadEvent);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200132 fd_insert(fd);
133 listeners++;
134 }
135
136 if (!pxerr) {
137 curproxy->state = PR_STRUN;
138 send_log(curproxy, LOG_NOTICE, "Proxy %s started.\n", curproxy->id);
139 }
140 }
141
142 return err;
143}
144
145
146/*
147 * this function enables proxies when there are enough free sessions,
148 * or stops them when the table is full. It is designed to be called from the
149 * select_loop(). It returns the time left before next expiration event
150 * during stop time, TIME_ETERNITY otherwise.
151 */
152int maintain_proxies(void)
153{
154 struct proxy *p;
155 struct listener *l;
156 int tleft; /* time left */
157
158 p = proxy;
159 tleft = TIME_ETERNITY; /* infinite time */
160
161 /* if there are enough free sessions, we'll activate proxies */
162 if (actconn < global.maxconn) {
163 while (p) {
164 if (p->nbconn < p->maxconn) {
165 if (p->state == PR_STIDLE) {
166 for (l = p->listen; l != NULL; l = l->next) {
Willy Tarreau2a429502006-10-15 14:52:29 +0200167 MY_FD_SET(l->fd, StaticReadEvent);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200168 }
169 p->state = PR_STRUN;
170 }
171 }
172 else {
173 if (p->state == PR_STRUN) {
174 for (l = p->listen; l != NULL; l = l->next) {
Willy Tarreau2a429502006-10-15 14:52:29 +0200175 MY_FD_CLR(l->fd, StaticReadEvent);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200176 }
177 p->state = PR_STIDLE;
178 }
179 }
180 p = p->next;
181 }
182 }
183 else { /* block all proxies */
184 while (p) {
185 if (p->state == PR_STRUN) {
186 for (l = p->listen; l != NULL; l = l->next) {
Willy Tarreau2a429502006-10-15 14:52:29 +0200187 MY_FD_CLR(l->fd, StaticReadEvent);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200188 }
189 p->state = PR_STIDLE;
190 }
191 p = p->next;
192 }
193 }
194
195 if (stopping) {
196 p = proxy;
197 while (p) {
198 if (p->state != PR_STSTOPPED) {
199 int t;
200 t = tv_remain2(&now, &p->stop_time);
201 if (t == 0) {
202 Warning("Proxy %s stopped.\n", p->id);
203 send_log(p, LOG_WARNING, "Proxy %s stopped.\n", p->id);
204
205 for (l = p->listen; l != NULL; l = l->next) {
206 fd_delete(l->fd);
207 listeners--;
208 }
209 p->state = PR_STSTOPPED;
210 }
211 else {
212 tleft = MINTIME(t, tleft);
213 }
214 }
215 p = p->next;
216 }
217 }
218 return tleft;
219}
220
221
222/*
223 * this function disables health-check servers so that the process will quickly be ignored
224 * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace
225 * time will not be used since it would already not listen anymore to the socket.
226 */
227void soft_stop(void)
228{
229 struct proxy *p;
230
231 stopping = 1;
232 p = proxy;
233 tv_now(&now); /* else, the old time before select will be used */
234 while (p) {
235 if (p->state != PR_STSTOPPED) {
236 Warning("Stopping proxy %s in %d ms.\n", p->id, p->grace);
237 send_log(p, LOG_WARNING, "Stopping proxy %s in %d ms.\n", p->id, p->grace);
238 tv_delayfrom(&p->stop_time, &now, p->grace);
239 }
240 p = p->next;
241 }
242}
243
244
245/*
246 * Linux unbinds the listen socket after a SHUT_RD, and ignores SHUT_WR.
247 * Solaris refuses either shutdown().
248 * OpenBSD ignores SHUT_RD but closes upon SHUT_WR and refuses to rebind.
249 * So a common validation path involves SHUT_WR && listen && SHUT_RD.
250 * If disabling at least one listener returns an error, then the proxy
251 * state is set to PR_STERROR because we don't know how to resume from this.
252 */
253void pause_proxy(struct proxy *p)
254{
255 struct listener *l;
256 for (l = p->listen; l != NULL; l = l->next) {
257 if (shutdown(l->fd, SHUT_WR) == 0 &&
258 listen(l->fd, p->maxconn) == 0 &&
259 shutdown(l->fd, SHUT_RD) == 0) {
Willy Tarreau2a429502006-10-15 14:52:29 +0200260 MY_FD_CLR(l->fd, StaticReadEvent);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200261 if (p->state != PR_STERROR)
262 p->state = PR_STPAUSED;
263 }
264 else
265 p->state = PR_STERROR;
266 }
267}
268
269/*
270 * This function temporarily disables listening so that another new instance
271 * can start listening. It is designed to be called upon reception of a
272 * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop
273 * the proxy, or a SIGTTIN can be sent to listen again.
274 */
275void pause_proxies(void)
276{
277 int err;
278 struct proxy *p;
279
280 err = 0;
281 p = proxy;
282 tv_now(&now); /* else, the old time before select will be used */
283 while (p) {
284 if (p->state != PR_STERROR &&
285 p->state != PR_STSTOPPED &&
286 p->state != PR_STPAUSED) {
287 Warning("Pausing proxy %s.\n", p->id);
288 send_log(p, LOG_WARNING, "Pausing proxy %s.\n", p->id);
289 pause_proxy(p);
290 if (p->state != PR_STPAUSED) {
291 err |= 1;
292 Warning("Proxy %s failed to enter pause mode.\n", p->id);
293 send_log(p, LOG_WARNING, "Proxy %s failed to enter pause mode.\n", p->id);
294 }
295 }
296 p = p->next;
297 }
298 if (err) {
299 Warning("Some proxies refused to pause, performing soft stop now.\n");
300 send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n");
301 soft_stop();
302 }
303}
304
305
306/*
307 * This function reactivates listening. This can be used after a call to
308 * sig_pause(), for example when a new instance has failed starting up.
309 * It is designed to be called upon reception of a SIGTTIN.
310 */
311void listen_proxies(void)
312{
313 struct proxy *p;
314 struct listener *l;
315
316 p = proxy;
317 tv_now(&now); /* else, the old time before select will be used */
318 while (p) {
319 if (p->state == PR_STPAUSED) {
320 Warning("Enabling proxy %s.\n", p->id);
321 send_log(p, LOG_WARNING, "Enabling proxy %s.\n", p->id);
322
323 for (l = p->listen; l != NULL; l = l->next) {
324 if (listen(l->fd, p->maxconn) == 0) {
325 if (actconn < global.maxconn && p->nbconn < p->maxconn) {
Willy Tarreau2a429502006-10-15 14:52:29 +0200326 MY_FD_SET(l->fd, StaticReadEvent);
Willy Tarreaubaaee002006-06-26 02:48:02 +0200327 p->state = PR_STRUN;
328 }
329 else
330 p->state = PR_STIDLE;
331 } else {
332 int port;
333
334 if (l->addr.ss_family == AF_INET6)
335 port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port);
336 else
337 port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port);
338
339 Warning("Port %d busy while trying to enable proxy %s.\n",
340 port, p->id);
341 send_log(p, LOG_WARNING, "Port %d busy while trying to enable proxy %s.\n",
342 port, p->id);
343 /* Another port might have been enabled. Let's stop everything. */
344 pause_proxy(p);
345 break;
346 }
347 }
348 }
349 p = p->next;
350 }
351}
352
353
354/*
355 * Local variables:
356 * c-indent-level: 8
357 * c-basic-offset: 8
358 * End:
359 */