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