blob: 4b0cd9e92c4f3403e7413d83e6a9302e496ad7d3 [file] [log] [blame]
Willy Tarreau92fb9832007-10-16 17:34:28 +02001/*
2 * UNIX SOCK_STREAM protocol layer (uxst)
3 *
Willy Tarreau7c669d72008-06-20 15:04:11 +02004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreau92fb9832007-10-16 17:34:28 +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
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <syslog.h>
20#include <time.h>
21
22#include <sys/param.h>
23#include <sys/socket.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/un.h>
27
28#include <common/compat.h>
29#include <common/config.h>
30#include <common/debug.h>
Willy Tarreaud740bab2007-10-28 11:14:07 +010031#include <common/errors.h>
Willy Tarreau92fb9832007-10-16 17:34:28 +020032#include <common/memory.h>
33#include <common/mini-clist.h>
34#include <common/standard.h>
Willy Tarreau0c303ee2008-07-07 00:09:58 +020035#include <common/ticks.h>
Willy Tarreau92fb9832007-10-16 17:34:28 +020036#include <common/time.h>
37#include <common/version.h>
38
Willy Tarreau92fb9832007-10-16 17:34:28 +020039#include <types/global.h>
Willy Tarreau92fb9832007-10-16 17:34:28 +020040
41#include <proto/acl.h>
42#include <proto/backend.h>
43#include <proto/buffers.h>
Willy Tarreau3e76e722007-10-17 18:57:38 +020044#include <proto/dumpstats.h>
Willy Tarreau92fb9832007-10-16 17:34:28 +020045#include <proto/fd.h>
46#include <proto/log.h>
47#include <proto/protocols.h>
48#include <proto/proto_uxst.h>
49#include <proto/queue.h>
50#include <proto/session.h>
51#include <proto/stream_sock.h>
52#include <proto/task.h>
53
54#ifndef MAXPATHLEN
55#define MAXPATHLEN 128
56#endif
57
Willy Tarreaudabf2e22007-10-28 21:59:24 +010058static int uxst_bind_listeners(struct protocol *proto);
59static int uxst_unbind_listeners(struct protocol *proto);
60
61/* Note: must not be declared <const> as its list will be overwritten */
62static struct protocol proto_unix = {
63 .name = "unix_stream",
64 .sock_domain = PF_UNIX,
65 .sock_type = SOCK_STREAM,
66 .sock_prot = 0,
67 .sock_family = AF_UNIX,
68 .sock_addrlen = sizeof(struct sockaddr_un),
69 .l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path),/* path len */
70 .read = &stream_sock_read,
71 .write = &stream_sock_write,
72 .bind_all = uxst_bind_listeners,
73 .unbind_all = uxst_unbind_listeners,
74 .enable_all = enable_all_listeners,
75 .disable_all = disable_all_listeners,
76 .listeners = LIST_HEAD_INIT(proto_unix.listeners),
77 .nb_listeners = 0,
78};
79
80
81/********************************
82 * 1) low-level socket functions
83 ********************************/
84
85
Willy Tarreau92fb9832007-10-16 17:34:28 +020086/* This function creates a named PF_UNIX stream socket at address <path>. Note
Willy Tarreaue6ad2b12007-10-18 12:45:54 +020087 * that the path cannot be NULL nor empty. <uid> and <gid> different of -1 will
88 * be used to change the socket owner. If <mode> is not 0, it will be used to
89 * restrict access to the socket. While it is known not to be portable on every
90 * OS, it's still useful where it works.
Willy Tarreau92fb9832007-10-16 17:34:28 +020091 * It returns the assigned file descriptor, or -1 in the event of an error.
92 */
Willy Tarreaue6ad2b12007-10-18 12:45:54 +020093static int create_uxst_socket(const char *path, uid_t uid, gid_t gid, mode_t mode)
Willy Tarreau92fb9832007-10-16 17:34:28 +020094{
95 char tempname[MAXPATHLEN];
96 char backname[MAXPATHLEN];
97 struct sockaddr_un addr;
98
99 int ret, sock;
100
101 /* 1. create socket names */
102 if (!path[0]) {
103 Alert("Invalid name for a UNIX socket. Aborting.\n");
104 goto err_return;
105 }
106
107 ret = snprintf(tempname, MAXPATHLEN, "%s.%d.tmp", path, pid);
108 if (ret < 0 || ret >= MAXPATHLEN) {
109 Alert("name too long for UNIX socket. Aborting.\n");
110 goto err_return;
111 }
112
113 ret = snprintf(backname, MAXPATHLEN, "%s.%d.bak", path, pid);
114 if (ret < 0 || ret >= MAXPATHLEN) {
115 Alert("name too long for UNIX socket. Aborting.\n");
116 goto err_return;
117 }
118
119 /* 2. clean existing orphaned entries */
120 if (unlink(tempname) < 0 && errno != ENOENT) {
121 Alert("error when trying to unlink previous UNIX socket. Aborting.\n");
122 goto err_return;
123 }
124
125 if (unlink(backname) < 0 && errno != ENOENT) {
126 Alert("error when trying to unlink previous UNIX socket. Aborting.\n");
127 goto err_return;
128 }
129
130 /* 3. backup existing socket */
131 if (link(path, backname) < 0 && errno != ENOENT) {
132 Alert("error when trying to preserve previous UNIX socket. Aborting.\n");
133 goto err_return;
134 }
135
136 /* 4. prepare new socket */
137 addr.sun_family = AF_UNIX;
138 strncpy(addr.sun_path, tempname, sizeof(addr.sun_path));
139 addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
140
141 sock = socket(PF_UNIX, SOCK_STREAM, 0);
142 if (sock < 0) {
143 Alert("cannot create socket for UNIX listener. Aborting.\n");
144 goto err_unlink_back;
145 }
146
147 if (sock >= global.maxsock) {
148 Alert("socket(): not enough free sockets for UNIX listener. Raise -n argument. Aborting.\n");
149 goto err_unlink_temp;
150 }
151
152 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
153 Alert("cannot make UNIX socket non-blocking. Aborting.\n");
154 goto err_unlink_temp;
155 }
156
157 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
158 /* note that bind() creates the socket <tempname> on the file system */
159 Alert("cannot bind socket for UNIX listener. Aborting.\n");
160 goto err_unlink_temp;
161 }
162
Willy Tarreaue6ad2b12007-10-18 12:45:54 +0200163 if (((uid != -1 || gid != -1) && (chown(tempname, uid, gid) == -1)) ||
164 (mode != 0 && chmod(tempname, mode) == -1)) {
165 Alert("cannot change UNIX socket ownership. Aborting.\n");
166 goto err_unlink_temp;
167 }
168
Willy Tarreau92fb9832007-10-16 17:34:28 +0200169 if (listen(sock, 0) < 0) {
170 Alert("cannot listen to socket for UNIX listener. Aborting.\n");
171 goto err_unlink_temp;
172 }
173
174 /* 5. install.
175 * Point of no return: we are ready, we'll switch the sockets. We don't
176 * fear loosing the socket <path> because we have a copy of it in
177 * backname.
178 */
179 if (rename(tempname, path) < 0) {
180 Alert("cannot switch final and temporary sockets for UNIX listener. Aborting.\n");
181 goto err_rename;
182 }
183
184 /* 6. cleanup */
185 unlink(backname); /* no need to keep this one either */
186
187 return sock;
188
189 err_rename:
190 ret = rename(backname, path);
191 if (ret < 0 && errno == ENOENT)
192 unlink(path);
193 err_unlink_temp:
194 unlink(tempname);
195 close(sock);
196 err_unlink_back:
197 unlink(backname);
198 err_return:
199 return -1;
200}
201
202/* Tries to destroy the UNIX stream socket <path>. The socket must not be used
203 * anymore. It practises best effort, and no error is returned.
204 */
205static void destroy_uxst_socket(const char *path)
206{
207 struct sockaddr_un addr;
208 int sock, ret;
209
210 /* We might have been chrooted, so we may not be able to access the
211 * socket. In order to avoid bothering the other end, we connect with a
212 * wrong protocol, namely SOCK_DGRAM. The return code from connect()
213 * is enough to know if the socket is still live or not. If it's live
214 * in mode SOCK_STREAM, we get EPROTOTYPE or anything else but not
215 * ECONNREFUSED. In this case, we do not touch it because it's used
216 * by some other process.
217 */
218 sock = socket(PF_UNIX, SOCK_DGRAM, 0);
219 if (sock < 0)
220 return;
221
222 addr.sun_family = AF_UNIX;
223 strncpy(addr.sun_path, path, sizeof(addr.sun_path));
Willy Tarreau10ae5482007-10-18 16:15:52 +0200224 addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200225 ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
226 if (ret < 0 && errno == ECONNREFUSED) {
227 /* Connect failed: the socket still exists but is not used
228 * anymore. Let's remove this socket now.
229 */
230 unlink(path);
231 }
232 close(sock);
233}
234
235
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100236/********************************
237 * 2) listener-oriented functions
238 ********************************/
239
240
241/* This function creates the UNIX socket associated to the listener. It changes
242 * the state from ASSIGNED to LISTEN. The socket is NOT enabled for polling.
243 * The return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL.
244 */
245static int uxst_bind_listener(struct listener *listener)
246{
247 int fd;
248
249 if (listener->state != LI_ASSIGNED)
250 return ERR_NONE; /* already bound */
251
252 fd = create_uxst_socket(((struct sockaddr_un *)&listener->addr)->sun_path,
253 listener->perm.ux.uid,
254 listener->perm.ux.gid,
255 listener->perm.ux.mode);
256 if (fd == -1)
257 return ERR_FATAL;
258
259 /* the socket is now listening */
260 listener->fd = fd;
261 listener->state = LI_LISTEN;
262
263 /* the function for the accept() event */
264 fd_insert(fd);
265 fdtab[fd].cb[DIR_RD].f = listener->accept;
266 fdtab[fd].cb[DIR_WR].f = NULL; /* never called */
267 fdtab[fd].cb[DIR_RD].b = fdtab[fd].cb[DIR_WR].b = NULL;
Willy Tarreaueabf3132008-08-29 23:36:51 +0200268 fdtab[fd].owner = listener; /* reference the listener instead of a task */
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100269 fdtab[fd].state = FD_STLISTEN;
270 fdtab[fd].peeraddr = NULL;
271 fdtab[fd].peerlen = 0;
272 fdtab[fd].listener = NULL;
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100273 return ERR_NONE;
274}
275
276/* This function closes the UNIX sockets for the specified listener.
277 * The listener enters the LI_ASSIGNED state. It always returns ERR_NONE.
278 */
279static int uxst_unbind_listener(struct listener *listener)
280{
281 if (listener->state == LI_READY)
282 EV_FD_CLR(listener->fd, DIR_RD);
283
284 if (listener->state >= LI_LISTEN) {
Willy Tarreau8eebe5e2007-10-28 22:07:08 +0100285 fd_delete(listener->fd);
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100286 listener->state = LI_ASSIGNED;
287 destroy_uxst_socket(((struct sockaddr_un *)&listener->addr)->sun_path);
288 }
289 return ERR_NONE;
290}
291
292/* Add a listener to the list of unix stream listeners. The listener's state
293 * is automatically updated from LI_INIT to LI_ASSIGNED. The number of
294 * listeners is updated. This is the function to use to add a new listener.
295 */
296void uxst_add_listener(struct listener *listener)
297{
298 if (listener->state != LI_INIT)
299 return;
300 listener->state = LI_ASSIGNED;
301 listener->proto = &proto_unix;
302 LIST_ADDQ(&proto_unix.listeners, &listener->proto_list);
303 proto_unix.nb_listeners++;
304}
305
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100306/********************************
307 * 3) protocol-oriented functions
308 ********************************/
309
310
Willy Tarreau92fb9832007-10-16 17:34:28 +0200311/* This function creates all UNIX sockets bound to the protocol entry <proto>.
312 * It is intended to be used as the protocol's bind_all() function.
313 * The sockets will be registered but not added to any fd_set, in order not to
314 * loose them across the fork(). A call to uxst_enable_listeners() is needed
315 * to complete initialization.
316 *
317 * The return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL.
318 */
319static int uxst_bind_listeners(struct protocol *proto)
320{
321 struct listener *listener;
322 int err = ERR_NONE;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200323
324 list_for_each_entry(listener, &proto->listeners, proto_list) {
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100325 err |= uxst_bind_listener(listener);
326 if (err != ERR_NONE)
Willy Tarreau92fb9832007-10-16 17:34:28 +0200327 continue;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200328 }
Willy Tarreau92fb9832007-10-16 17:34:28 +0200329 return err;
330}
331
Willy Tarreau92fb9832007-10-16 17:34:28 +0200332
333/* This function stops all listening UNIX sockets bound to the protocol
334 * <proto>. It does not detaches them from the protocol.
335 * It always returns ERR_NONE.
336 */
337static int uxst_unbind_listeners(struct protocol *proto)
338{
339 struct listener *listener;
340
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100341 list_for_each_entry(listener, &proto->listeners, proto_list)
342 uxst_unbind_listener(listener);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200343 return ERR_NONE;
344}
345
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100346
347/********************************
348 * 4) high-level functions
349 ********************************/
350
351
Willy Tarreau92fb9832007-10-16 17:34:28 +0200352/*
353 * This function is called on a read event from a listen socket, corresponding
354 * to an accept. It tries to accept as many connections as possible.
355 * It returns 0. Since we use UNIX sockets on the local system for monitoring
356 * purposes and other related things, we do not need to output as many messages
357 * as with TCP which can fall under attack.
358 */
359int uxst_event_accept(int fd) {
Willy Tarreaueabf3132008-08-29 23:36:51 +0200360 struct listener *l = fdtab[fd].owner;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200361 struct session *s;
362 struct task *t;
363 int cfd;
364 int max_accept;
365
366 if (global.nbproc > 1)
367 max_accept = 8; /* let other processes catch some connections too */
368 else
369 max_accept = -1;
370
371 while (max_accept--) {
372 struct sockaddr_storage addr;
373 socklen_t laddr = sizeof(addr);
374
375 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
376 switch (errno) {
377 case EAGAIN:
378 case EINTR:
379 case ECONNABORTED:
380 return 0; /* nothing more to accept */
381 case ENFILE:
382 /* Process reached system FD limit. Check system tunables. */
383 return 0;
384 case EMFILE:
385 /* Process reached process FD limit. Check 'ulimit-n'. */
386 return 0;
387 case ENOBUFS:
388 case ENOMEM:
389 /* Process reached system memory limit. Check system tunables. */
390 return 0;
391 default:
392 return 0;
393 }
394 }
395
396 if (l->nbconn >= l->maxconn) {
397 /* too many connections, we shoot this one and return.
398 * FIXME: it would be better to simply switch the listener's
399 * state to LI_FULL and disable the FD. We could re-enable
400 * it upon fd_delete(), but this requires all protocols to
401 * be switched.
402 */
403 close(cfd);
404 return 0;
405 }
406
407 if ((s = pool_alloc2(pool2_session)) == NULL) {
408 Alert("out of memory in uxst_event_accept().\n");
409 close(cfd);
410 return 0;
411 }
412
Willy Tarreauf54f8bd2008-11-23 19:53:55 +0100413 LIST_ADDQ(&sessions, &s->list);
414
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +0100415 s->flags = 0;
Willy Tarreauf8533202008-08-16 14:55:08 +0200416 s->term_trace = 0;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +0100417
Willy Tarreau92fb9832007-10-16 17:34:28 +0200418 if ((t = pool_alloc2(pool2_task)) == NULL) {
419 Alert("out of memory in uxst_event_accept().\n");
420 close(cfd);
Willy Tarreauf54f8bd2008-11-23 19:53:55 +0100421 LIST_DEL(&s->list);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200422 pool_free2(pool2_session, s);
423 return 0;
424 }
425
426 s->cli_addr = addr;
427
428 /* FIXME: should be checked earlier */
429 if (cfd >= global.maxsock) {
430 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
431 close(cfd);
432 pool_free2(pool2_task, t);
Willy Tarreauf54f8bd2008-11-23 19:53:55 +0100433 LIST_DEL(&s->list);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200434 pool_free2(pool2_session, s);
435 return 0;
436 }
437
438 if (fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) {
439 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
440 close(cfd);
441 pool_free2(pool2_task, t);
Willy Tarreauf54f8bd2008-11-23 19:53:55 +0100442 LIST_DEL(&s->list);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200443 pool_free2(pool2_session, s);
444 return 0;
445 }
446
Willy Tarreau9789f7b2008-06-24 08:17:16 +0200447 task_init(t);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200448 t->process = l->handler;
449 t->context = s;
Willy Tarreau91e99932008-06-30 07:51:00 +0200450 t->nice = -64; /* we want to boost priority for local stats */
Willy Tarreau92fb9832007-10-16 17:34:28 +0200451
452 s->task = t;
453 s->fe = NULL;
454 s->be = NULL;
455
456 s->cli_state = CL_STDATA;
457 s->srv_state = SV_STIDLE;
458 s->req = s->rep = NULL; /* will be allocated later */
459
460 s->cli_fd = cfd;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200461 s->srv = NULL;
462 s->pend_pos = NULL;
463
464 memset(&s->logs, 0, sizeof(s->logs));
465 memset(&s->txn, 0, sizeof(s->txn));
466
Willy Tarreau3e76e722007-10-17 18:57:38 +0200467 s->data_state = DATA_ST_INIT;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200468 s->data_source = DATA_SRC_NONE;
469 s->uniq_id = totalconn;
470
471 if ((s->req = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */
472 close(cfd); /* nothing can be done for this fd without memory */
473 pool_free2(pool2_task, t);
Willy Tarreauf54f8bd2008-11-23 19:53:55 +0100474 LIST_DEL(&s->list);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200475 pool_free2(pool2_session, s);
476 return 0;
477 }
478
479 if ((s->rep = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */
480 pool_free2(pool2_buffer, s->req);
481 close(cfd); /* nothing can be done for this fd without memory */
482 pool_free2(pool2_task, t);
Willy Tarreauf54f8bd2008-11-23 19:53:55 +0100483 LIST_DEL(&s->list);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200484 pool_free2(pool2_session, s);
485 return 0;
486 }
487
488 buffer_init(s->req);
489 buffer_init(s->rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200490
491 fd_insert(cfd);
492 fdtab[cfd].owner = t;
493 fdtab[cfd].listener = l;
494 fdtab[cfd].state = FD_STREADY;
495 fdtab[cfd].cb[DIR_RD].f = l->proto->read;
496 fdtab[cfd].cb[DIR_RD].b = s->req;
497 fdtab[cfd].cb[DIR_WR].f = l->proto->write;
498 fdtab[cfd].cb[DIR_WR].b = s->rep;
499 fdtab[cfd].peeraddr = (struct sockaddr *)&s->cli_addr;
500 fdtab[cfd].peerlen = sizeof(s->cli_addr);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200501
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200502 s->req->rex = TICK_ETERNITY;
503 s->req->wex = TICK_ETERNITY;
Willy Tarreauffab5b42008-08-17 18:03:28 +0200504 s->req->analyse_exp = TICK_ETERNITY;
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200505 s->rep->rex = TICK_ETERNITY;
506 s->rep->wex = TICK_ETERNITY;
Willy Tarreauffab5b42008-08-17 18:03:28 +0200507 s->rep->analyse_exp = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200508
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200509 s->req->wto = TICK_ETERNITY;
510 s->req->cto = TICK_ETERNITY;
511 s->req->rto = TICK_ETERNITY;
512 s->rep->rto = TICK_ETERNITY;
513 s->rep->cto = TICK_ETERNITY;
514 s->rep->wto = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200515
516 if (l->timeout)
517 s->req->rto = *l->timeout;
518
519 if (l->timeout)
520 s->rep->wto = *l->timeout;
521
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200522 t->expire = TICK_ETERNITY;
523 if (l->timeout && *l->timeout) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200524 EV_FD_SET(cfd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200525 s->req->rex = tick_add(now_ms, s->req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200526 t->expire = s->req->rex;
527 }
528
Willy Tarreaufdccded2008-08-29 18:19:04 +0200529 task_wakeup(t, TASK_WOKEN_INIT);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200530
531 l->nbconn++; /* warning! right now, it's up to the handler to decrease this */
532 if (l->nbconn >= l->maxconn) {
533 EV_FD_CLR(l->fd, DIR_RD);
534 l->state = LI_FULL;
535 }
536 actconn++;
537 totalconn++;
538
539 //fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p, cfd=%d, maxfd=%d\n", p, actconn, totalconn, t, cfd, maxfd);
540 } /* end of while (p->feconn < p->maxconn) */
541 //fprintf(stderr,"fct %s:%d\n", __FUNCTION__, __LINE__);
542 return 0;
543}
544
545/*
546 * manages the client FSM and its socket. It returns 1 if a state has changed
547 * (and a resync may be needed), otherwise 0.
548 */
549static int process_uxst_cli(struct session *t)
550{
551 int s = t->srv_state;
552 int c = t->cli_state;
553 struct buffer *req = t->req;
554 struct buffer *rep = t->rep;
555 //fprintf(stderr,"fct %s:%d\n", __FUNCTION__, __LINE__);
556 if (c == CL_STDATA) {
557 /* FIXME: this error handling is partly buggy because we always report
558 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
559 * or HEADER phase. BTW, it's not logical to expire the client while
560 * we're waiting for the server to connect.
561 */
562 /* read or write error */
563 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200564 buffer_shutr(req);
565 buffer_shutw(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200566 fd_delete(t->cli_fd);
567 t->cli_state = CL_STCLOSE;
568 if (!(t->flags & SN_ERR_MASK))
569 t->flags |= SN_ERR_CLICL;
570 if (!(t->flags & SN_FINST_MASK)) {
571 if (t->pend_pos)
572 t->flags |= SN_FINST_Q;
573 else if (s == SV_STCONN)
574 t->flags |= SN_FINST_C;
575 else
576 t->flags |= SN_FINST_D;
577 }
578 return 1;
579 }
580 /* last read, or end of server write */
581 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
582 EV_FD_CLR(t->cli_fd, DIR_RD);
583 buffer_shutr(req);
584 t->cli_state = CL_STSHUTR;
585 return 1;
Willy Tarreauf54f8bd2008-11-23 19:53:55 +0100586 }
Willy Tarreau92fb9832007-10-16 17:34:28 +0200587 /* last server read and buffer empty */
Willy Tarreaue393fe22008-08-16 22:18:07 +0200588 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->flags & BF_EMPTY)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200589 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +0200590 buffer_shutw(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200591 shutdown(t->cli_fd, SHUT_WR);
592 /* We must ensure that the read part is still alive when switching
593 * to shutw */
594 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200595 req->rex = tick_add_ifset(now_ms, req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200596 t->cli_state = CL_STSHUTW;
597 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
598 return 1;
599 }
600 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200601 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200602 EV_FD_CLR(t->cli_fd, DIR_RD);
603 buffer_shutr(req);
604 t->cli_state = CL_STSHUTR;
605 if (!(t->flags & SN_ERR_MASK))
606 t->flags |= SN_ERR_CLITO;
607 if (!(t->flags & SN_FINST_MASK)) {
608 if (t->pend_pos)
609 t->flags |= SN_FINST_Q;
610 else if (s == SV_STCONN)
611 t->flags |= SN_FINST_C;
612 else
613 t->flags |= SN_FINST_D;
614 }
615 return 1;
Willy Tarreauf54f8bd2008-11-23 19:53:55 +0100616 }
Willy Tarreau92fb9832007-10-16 17:34:28 +0200617 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200618 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200619 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +0200620 buffer_shutw(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200621 shutdown(t->cli_fd, SHUT_WR);
622 /* We must ensure that the read part is still alive when switching
623 * to shutw */
624 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200625 req->rex = tick_add_ifset(now_ms, req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200626
627 t->cli_state = CL_STSHUTW;
628 if (!(t->flags & SN_ERR_MASK))
629 t->flags |= SN_ERR_CLITO;
630 if (!(t->flags & SN_FINST_MASK)) {
631 if (t->pend_pos)
632 t->flags |= SN_FINST_Q;
633 else if (s == SV_STCONN)
634 t->flags |= SN_FINST_C;
635 else
636 t->flags |= SN_FINST_D;
637 }
638 return 1;
639 }
640
Willy Tarreaue393fe22008-08-16 22:18:07 +0200641 if (req->flags & BF_FULL) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200642 /* no room to read more data */
643 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
644 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200645 req->rex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200646 }
647 } else {
648 /* there's still some space in the buffer */
649 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200650 if (!req->rto ||
651 (t->srv_state < SV_STDATA && req->wto))
Willy Tarreau92fb9832007-10-16 17:34:28 +0200652 /* If the client has no timeout, or if the server not ready yet, and we
653 * know for sure that it can expire, then it's cleaner to disable the
654 * timeout on the client side so that too low values cannot make the
655 * sessions abort too early.
656 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200657 req->rex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200658 else
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200659 req->rex = tick_add(now_ms, req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200660 }
661 }
662
Willy Tarreaue393fe22008-08-16 22:18:07 +0200663 if ((rep->flags & BF_EMPTY) ||
Willy Tarreau92fb9832007-10-16 17:34:28 +0200664 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
665 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
666 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200667 rep->wex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200668 }
669 } else {
670 /* buffer not empty */
671 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
672 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200673 rep->wex = tick_add_ifset(now_ms, rep->wto);
674 if (rep->wex) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200675 /* FIXME: to prevent the client from expiring read timeouts during writes,
676 * we refresh it. */
677 req->rex = rep->wex;
678 }
Willy Tarreau92fb9832007-10-16 17:34:28 +0200679 }
680 }
681 return 0; /* other cases change nothing */
682 }
683 else if (c == CL_STSHUTR) {
684 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200685 buffer_shutw(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200686 fd_delete(t->cli_fd);
687 t->cli_state = CL_STCLOSE;
688 if (!(t->flags & SN_ERR_MASK))
689 t->flags |= SN_ERR_CLICL;
690 if (!(t->flags & SN_FINST_MASK)) {
691 if (t->pend_pos)
692 t->flags |= SN_FINST_Q;
693 else if (s == SV_STCONN)
694 t->flags |= SN_FINST_C;
695 else
696 t->flags |= SN_FINST_D;
697 }
698 return 1;
699 }
Willy Tarreaue393fe22008-08-16 22:18:07 +0200700 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->flags & BF_EMPTY)) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200701 buffer_shutw(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200702 fd_delete(t->cli_fd);
703 t->cli_state = CL_STCLOSE;
704 return 1;
705 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200706 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200707 buffer_shutw(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200708 fd_delete(t->cli_fd);
709 t->cli_state = CL_STCLOSE;
710 if (!(t->flags & SN_ERR_MASK))
711 t->flags |= SN_ERR_CLITO;
712 if (!(t->flags & SN_FINST_MASK)) {
713 if (t->pend_pos)
714 t->flags |= SN_FINST_Q;
715 else if (s == SV_STCONN)
716 t->flags |= SN_FINST_C;
717 else
718 t->flags |= SN_FINST_D;
719 }
720 return 1;
721 }
722
Willy Tarreaue393fe22008-08-16 22:18:07 +0200723 if (rep->flags & BF_EMPTY) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200724 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
725 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200726 rep->wex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200727 }
728 } else {
729 /* buffer not empty */
730 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
731 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200732 rep->wex = tick_add_ifset(now_ms, rep->wto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200733 }
734 }
735 return 0;
736 }
737 else if (c == CL_STSHUTW) {
738 if (req->flags & BF_READ_ERROR) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200739 buffer_shutr(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200740 fd_delete(t->cli_fd);
741 t->cli_state = CL_STCLOSE;
742 if (!(t->flags & SN_ERR_MASK))
743 t->flags |= SN_ERR_CLICL;
744 if (!(t->flags & SN_FINST_MASK)) {
745 if (t->pend_pos)
746 t->flags |= SN_FINST_Q;
747 else if (s == SV_STCONN)
748 t->flags |= SN_FINST_C;
749 else
750 t->flags |= SN_FINST_D;
751 }
752 return 1;
753 }
754 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200755 buffer_shutr(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200756 fd_delete(t->cli_fd);
757 t->cli_state = CL_STCLOSE;
758 return 1;
759 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200760 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200761 buffer_shutr(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200762 fd_delete(t->cli_fd);
763 t->cli_state = CL_STCLOSE;
764 if (!(t->flags & SN_ERR_MASK))
765 t->flags |= SN_ERR_CLITO;
766 if (!(t->flags & SN_FINST_MASK)) {
767 if (t->pend_pos)
768 t->flags |= SN_FINST_Q;
769 else if (s == SV_STCONN)
770 t->flags |= SN_FINST_C;
771 else
772 t->flags |= SN_FINST_D;
773 }
774 return 1;
775 }
Willy Tarreaue393fe22008-08-16 22:18:07 +0200776 else if (req->flags & BF_FULL) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200777 /* no room to read more data */
778
779 /* FIXME-20050705: is it possible for a client to maintain a session
780 * after the timeout by sending more data after it receives a close ?
781 */
782
783 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
784 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200785 req->rex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200786 }
787 } else {
788 /* there's still some space in the buffer */
789 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200790 req->rex = tick_add_ifset(now_ms, req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200791 }
792 }
793 return 0;
794 }
795 else { /* CL_STCLOSE: nothing to do */
796 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
797 int len;
798 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be?t->be->id:"",
Willy Tarreaufa7e1022008-10-19 07:30:41 +0200799 (unsigned short)t->cli_fd, (unsigned short)t->req->cons->fd);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200800 write(1, trash, len);
801 }
802 return 0;
803 }
804 return 0;
805}
806
807#if 0
808 /* FIXME! This part has not been completely converted yet, and it may
809 * still be very specific to TCPv4 ! Also, it relies on some parameters
810 * such as conn_retries which are not set upon accept().
811 */
812/*
813 * Manages the server FSM and its socket. It returns 1 if a state has changed
814 * (and a resync may be needed), otherwise 0.
815 */
816static int process_uxst_srv(struct session *t)
817{
818 int s = t->srv_state;
819 int c = t->cli_state;
820 struct buffer *req = t->req;
821 struct buffer *rep = t->rep;
822 int conn_err;
823
824 if (s == SV_STIDLE) {
825 if (c == CL_STCLOSE || c == CL_STSHUTW ||
826 (c == CL_STSHUTR &&
Willy Tarreaue393fe22008-08-16 22:18:07 +0200827 (t->req->flags & BF_EMPTY || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau92fb9832007-10-16 17:34:28 +0200828 tv_eternity(&req->cex);
829 if (t->pend_pos)
830 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
831 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C);
832 return 1;
833 }
834 else {
835 /* FIXME: reimplement the TARPIT check here */
836
837 /* Right now, we will need to create a connection to the server.
838 * We might already have tried, and got a connection pending, in
839 * which case we will not do anything till it's pending. It's up
840 * to any other session to release it and wake us up again.
841 */
842 if (t->pend_pos) {
843 if (!tv_isle(&req->cex, &now))
844 return 0;
845 else {
846 /* we've been waiting too long here */
847 tv_eternity(&req->cex);
848 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
849 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q);
850 if (t->srv)
851 t->srv->failed_conns++;
852 if (t->fe)
853 t->fe->failed_conns++;
854 return 1;
855 }
856 }
857
858 do {
859 /* first, get a connection */
860 if (srv_redispatch_connect(t))
861 return t->srv_state != SV_STIDLE;
862
863 /* try to (re-)connect to the server, and fail if we expire the
864 * number of retries.
865 */
866 if (srv_retryable_connect(t)) {
867 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
868 return t->srv_state != SV_STIDLE;
869 }
870 } while (1);
871 }
872 }
873 else if (s == SV_STCONN) { /* connection in progress */
874 if (c == CL_STCLOSE || c == CL_STSHUTW ||
875 (c == CL_STSHUTR &&
Willy Tarreau3da77c52008-08-29 09:58:42 +0200876 ((t->req->flags & BF_EMPTY && !(req->flags & BF_WRITE_ACTIVITY)) ||
Willy Tarreau92fb9832007-10-16 17:34:28 +0200877 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
878 tv_eternity(&req->cex);
879 fd_delete(t->srv_fd);
880 if (t->srv)
881 t->srv->cur_sess--;
882
883 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C);
884 return 1;
885 }
Willy Tarreau3da77c52008-08-29 09:58:42 +0200886 if (!(req->flags & BF_WRITE_ACTIVITY) && !tv_isle(&req->cex, &now)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200887 //fprintf(stderr,"1: c=%d, s=%d, now=%d.%06d, exp=%d.%06d\n", c, s, now.tv_sec, now.tv_usec, req->cex.tv_sec, req->cex.tv_usec);
888 return 0; /* nothing changed */
889 }
Willy Tarreau3da77c52008-08-29 09:58:42 +0200890 else if (!(req->flags & BF_WRITE_ACTIVITY) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200891 /* timeout, asynchronous connect error or first write error */
892 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
893
894 fd_delete(t->srv_fd);
895 if (t->srv)
896 t->srv->cur_sess--;
897
Willy Tarreau3da77c52008-08-29 09:58:42 +0200898 if (!(req->flags & BF_WRITE_ACTIVITY))
Willy Tarreau92fb9832007-10-16 17:34:28 +0200899 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
900 else
901 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
902
903 /* ensure that we have enough retries left */
904 if (srv_count_retry_down(t, conn_err))
905 return 1;
906
907 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
908 /* We're on our last chance, and the REDISP option was specified.
909 * We will ignore cookie and force to balance or use the dispatcher.
910 */
911 /* let's try to offer this slot to anybody */
912 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +0200913 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200914
915 if (t->srv)
916 t->srv->failed_conns++;
917 t->be->failed_conns++;
918
919 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
920 t->srv = NULL; /* it's left to the dispatcher to choose a server */
921
922 /* first, get a connection */
923 if (srv_redispatch_connect(t))
924 return t->srv_state != SV_STIDLE;
925 }
926
927 do {
928 /* Now we will try to either reconnect to the same server or
929 * connect to another server. If the connection gets queued
930 * because all servers are saturated, then we will go back to
931 * the SV_STIDLE state.
932 */
933 if (srv_retryable_connect(t)) {
934 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
935 return t->srv_state != SV_STCONN;
936 }
937
938 /* we need to redispatch the connection to another server */
939 if (srv_redispatch_connect(t))
940 return t->srv_state != SV_STCONN;
941 } while (1);
942 }
943 else { /* no error or write 0 */
944 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
945
946 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
Willy Tarreaue393fe22008-08-16 22:18:07 +0200947 if (req->flags & BF_EMPTY) /* nothing to write */ {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200948 EV_FD_CLR(t->srv_fd, DIR_WR);
949 tv_eternity(&req->wex);
950 } else /* need the right to write */ {
951 EV_FD_SET(t->srv_fd, DIR_WR);
952 if (tv_add_ifset(&req->wex, &now, &req->wto)) {
953 /* FIXME: to prevent the server from expiring read timeouts during writes,
954 * we refresh it. */
955 rep->rex = req->wex;
956 }
957 else
958 tv_eternity(&req->wex);
959 }
960
961 EV_FD_SET(t->srv_fd, DIR_RD);
962 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
963 tv_eternity(&rep->rex);
964
965 t->srv_state = SV_STDATA;
966 if (t->srv)
967 t->srv->cum_sess++;
Willy Tarreaue393fe22008-08-16 22:18:07 +0200968 buffer_set_rlim(rep, BUFSIZE); /* no rewrite needed */
Willy Tarreau92fb9832007-10-16 17:34:28 +0200969
970 /* if the user wants to log as soon as possible, without counting
971 bytes from the server, then this is the right moment. */
972 if (t->fe && t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
973 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
974 //uxst_sess_log(t);
975 }
976 tv_eternity(&req->cex);
977 return 1;
978 }
979 }
980 else if (s == SV_STDATA) {
981 /* read or write error */
982 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200983 buffer_shutr(rep);
984 buffer_shutw(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200985 fd_delete(t->srv_fd);
986 if (t->srv) {
987 t->srv->cur_sess--;
988 t->srv->failed_resp++;
989 }
990 t->be->failed_resp++;
991 t->srv_state = SV_STCLOSE;
992 if (!(t->flags & SN_ERR_MASK))
993 t->flags |= SN_ERR_SRVCL;
994 if (!(t->flags & SN_FINST_MASK))
995 t->flags |= SN_FINST_D;
996 /* We used to have a free connection slot. Since we'll never use it,
997 * we have to inform the server that it may be used by another session.
998 */
999 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001000 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001001
1002 return 1;
1003 }
1004 /* last read, or end of client write */
1005 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
1006 EV_FD_CLR(t->srv_fd, DIR_RD);
1007 buffer_shutr(rep);
1008 t->srv_state = SV_STSHUTR;
1009 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1010 return 1;
1011 }
1012 /* end of client read and no more data to send */
Willy Tarreaue393fe22008-08-16 22:18:07 +02001013 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->flags & BF_EMPTY)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +02001014 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001015 buffer_shutw(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001016 shutdown(t->srv_fd, SHUT_WR);
1017 /* We must ensure that the read part is still alive when switching
1018 * to shutw */
1019 EV_FD_SET(t->srv_fd, DIR_RD);
1020 tv_add_ifset(&rep->rex, &now, &rep->rto);
1021
1022 t->srv_state = SV_STSHUTW;
1023 return 1;
1024 }
1025 /* read timeout */
1026 else if (tv_isle(&rep->rex, &now)) {
1027 EV_FD_CLR(t->srv_fd, DIR_RD);
1028 buffer_shutr(rep);
1029 t->srv_state = SV_STSHUTR;
1030 if (!(t->flags & SN_ERR_MASK))
1031 t->flags |= SN_ERR_SRVTO;
1032 if (!(t->flags & SN_FINST_MASK))
1033 t->flags |= SN_FINST_D;
1034 return 1;
1035 }
1036 /* write timeout */
1037 else if (tv_isle(&req->wex, &now)) {
1038 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001039 buffer_shutw(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001040 shutdown(t->srv_fd, SHUT_WR);
1041 /* We must ensure that the read part is still alive when switching
1042 * to shutw */
1043 EV_FD_SET(t->srv_fd, DIR_RD);
1044 tv_add_ifset(&rep->rex, &now, &rep->rto);
1045 t->srv_state = SV_STSHUTW;
1046 if (!(t->flags & SN_ERR_MASK))
1047 t->flags |= SN_ERR_SRVTO;
1048 if (!(t->flags & SN_FINST_MASK))
1049 t->flags |= SN_FINST_D;
1050 return 1;
1051 }
1052
1053 /* recompute request time-outs */
Willy Tarreaue393fe22008-08-16 22:18:07 +02001054 if (req->flags & BF_EMPTY) {
Willy Tarreau92fb9832007-10-16 17:34:28 +02001055 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
1056 /* stop writing */
1057 tv_eternity(&req->wex);
1058 }
1059 }
1060 else { /* buffer not empty, there are still data to be transferred */
1061 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
1062 /* restart writing */
1063 if (tv_add_ifset(&req->wex, &now, &req->wto)) {
1064 /* FIXME: to prevent the server from expiring read timeouts during writes,
1065 * we refresh it. */
1066 rep->rex = req->wex;
1067 }
1068 else
1069 tv_eternity(&req->wex);
1070 }
1071 }
1072
1073 /* recompute response time-outs */
1074 if (rep->l == BUFSIZE) { /* no room to read more data */
1075 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
1076 tv_eternity(&rep->rex);
1077 }
1078 }
1079 else {
1080 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
1081 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
1082 tv_eternity(&rep->rex);
1083 }
1084 }
1085
1086 return 0; /* other cases change nothing */
1087 }
1088 else if (s == SV_STSHUTR) {
1089 if (req->flags & BF_WRITE_ERROR) {
1090 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001091 buffer_shutw(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001092 fd_delete(t->srv_fd);
1093 if (t->srv) {
1094 t->srv->cur_sess--;
1095 t->srv->failed_resp++;
1096 }
1097 t->be->failed_resp++;
1098 //close(t->srv_fd);
1099 t->srv_state = SV_STCLOSE;
1100 if (!(t->flags & SN_ERR_MASK))
1101 t->flags |= SN_ERR_SRVCL;
1102 if (!(t->flags & SN_FINST_MASK))
1103 t->flags |= SN_FINST_D;
1104 /* We used to have a free connection slot. Since we'll never use it,
1105 * we have to inform the server that it may be used by another session.
1106 */
1107 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001108 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001109
1110 return 1;
1111 }
Willy Tarreaue393fe22008-08-16 22:18:07 +02001112 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->flags & BF_EMPTY)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +02001113 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001114 buffer_shutw(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001115 fd_delete(t->srv_fd);
1116 if (t->srv)
1117 t->srv->cur_sess--;
1118 //close(t->srv_fd);
1119 t->srv_state = SV_STCLOSE;
1120 /* We used to have a free connection slot. Since we'll never use it,
1121 * we have to inform the server that it may be used by another session.
1122 */
1123 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001124 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001125
1126 return 1;
1127 }
1128 else if (tv_isle(&req->wex, &now)) {
1129 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001130 buffer_shutw(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001131 fd_delete(t->srv_fd);
1132 if (t->srv)
1133 t->srv->cur_sess--;
1134 //close(t->srv_fd);
1135 t->srv_state = SV_STCLOSE;
1136 if (!(t->flags & SN_ERR_MASK))
1137 t->flags |= SN_ERR_SRVTO;
1138 if (!(t->flags & SN_FINST_MASK))
1139 t->flags |= SN_FINST_D;
1140 /* We used to have a free connection slot. Since we'll never use it,
1141 * we have to inform the server that it may be used by another session.
1142 */
1143 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001144 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001145
1146 return 1;
1147 }
Willy Tarreaue393fe22008-08-16 22:18:07 +02001148 else if (req->flags & BF_EMPTY) {
Willy Tarreau92fb9832007-10-16 17:34:28 +02001149 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
1150 /* stop writing */
1151 tv_eternity(&req->wex);
1152 }
1153 }
1154 else { /* buffer not empty */
1155 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
1156 /* restart writing */
1157 if (!tv_add_ifset(&req->wex, &now, &req->wto))
1158 tv_eternity(&req->wex);
1159 }
1160 }
1161 return 0;
1162 }
1163 else if (s == SV_STSHUTW) {
1164 if (rep->flags & BF_READ_ERROR) {
1165 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001166 buffer_shutr(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001167 fd_delete(t->srv_fd);
1168 if (t->srv) {
1169 t->srv->cur_sess--;
1170 t->srv->failed_resp++;
1171 }
1172 t->be->failed_resp++;
1173 //close(t->srv_fd);
1174 t->srv_state = SV_STCLOSE;
1175 if (!(t->flags & SN_ERR_MASK))
1176 t->flags |= SN_ERR_SRVCL;
1177 if (!(t->flags & SN_FINST_MASK))
1178 t->flags |= SN_FINST_D;
1179 /* We used to have a free connection slot. Since we'll never use it,
1180 * we have to inform the server that it may be used by another session.
1181 */
1182 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001183 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001184
1185 return 1;
1186 }
1187 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
1188 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001189 buffer_shutr(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001190 fd_delete(t->srv_fd);
1191 if (t->srv)
1192 t->srv->cur_sess--;
1193 //close(t->srv_fd);
1194 t->srv_state = SV_STCLOSE;
1195 /* We used to have a free connection slot. Since we'll never use it,
1196 * we have to inform the server that it may be used by another session.
1197 */
1198 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001199 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001200
1201 return 1;
1202 }
1203 else if (tv_isle(&rep->rex, &now)) {
1204 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001205 buffer_shutr(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001206 fd_delete(t->srv_fd);
1207 if (t->srv)
1208 t->srv->cur_sess--;
1209 //close(t->srv_fd);
1210 t->srv_state = SV_STCLOSE;
1211 if (!(t->flags & SN_ERR_MASK))
1212 t->flags |= SN_ERR_SRVTO;
1213 if (!(t->flags & SN_FINST_MASK))
1214 t->flags |= SN_FINST_D;
1215 /* We used to have a free connection slot. Since we'll never use it,
1216 * we have to inform the server that it may be used by another session.
1217 */
1218 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001219 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001220
1221 return 1;
1222 }
1223 else if (rep->l == BUFSIZE) { /* no room to read more data */
1224 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
1225 tv_eternity(&rep->rex);
1226 }
1227 }
1228 else {
1229 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
1230 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
1231 tv_eternity(&rep->rex);
1232 }
1233 }
1234 return 0;
1235 }
1236 else { /* SV_STCLOSE : nothing to do */
1237 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1238 int len;
1239 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
1240 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1241 write(1, trash, len);
1242 }
1243 return 0;
1244 }
1245 return 0;
1246}
1247
1248/* Processes the client and server jobs of a session task, then
1249 * puts it back to the wait queue in a clean state, or
1250 * cleans up its resources if it must be deleted. Returns
1251 * the time the task accepts to wait, or TIME_ETERNITY for
1252 * infinity.
1253 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001254void process_uxst_session(struct task *t, int *next)
Willy Tarreau92fb9832007-10-16 17:34:28 +02001255{
1256 struct session *s = t->context;
1257 int fsm_resync = 0;
1258
1259 do {
1260 fsm_resync = 0;
1261 fsm_resync |= process_uxst_cli(s);
1262 if (s->srv_state == SV_STIDLE) {
1263 if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) {
1264 s->srv_state = SV_STCLOSE;
1265 fsm_resync |= 1;
1266 continue;
1267 }
1268 if (s->cli_state == CL_STSHUTR ||
Willy Tarreaue393fe22008-08-16 22:18:07 +02001269 (s->req->flags & BF_FULL)) {
1270 if (s->req->flags & BF_EMPTY) {
Willy Tarreau92fb9832007-10-16 17:34:28 +02001271 s->srv_state = SV_STCLOSE;
1272 fsm_resync |= 1;
1273 continue;
1274 }
1275 /* OK we have some remaining data to process */
1276 /* Just as an exercice, we copy the req into the resp,
1277 * and flush the req.
1278 */
1279 memcpy(s->rep->data, s->req->data, sizeof(s->rep->data));
1280 s->rep->l = s->req->l;
Willy Tarreaue393fe22008-08-16 22:18:07 +02001281 buffer_set_rlim(s->rep, BUFSIZE);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001282 s->rep->w = s->rep->data;
1283 s->rep->lr = s->rep->r = s->rep->data + s->rep->l;
1284
1285 s->req->l = 0;
1286 s->srv_state = SV_STCLOSE;
1287
1288 fsm_resync |= 1;
1289 continue;
1290 }
1291 }
1292 } while (fsm_resync);
1293
1294 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +01001295
1296 if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
1297 session_process_counters(s);
1298
Willy Tarreau92fb9832007-10-16 17:34:28 +02001299 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1300 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1301
1302 t->expire = s->req->rex;
1303 tv_min(&t->expire, &s->req->rex, &s->req->wex);
1304 tv_bound(&t->expire, &s->req->cex);
1305 tv_bound(&t->expire, &s->rep->rex);
1306 tv_bound(&t->expire, &s->rep->wex);
1307
1308 /* restore t to its place in the task list */
1309 task_queue(t);
1310
1311 *next = t->expire;
1312 return; /* nothing more to do */
1313 }
1314
1315 if (s->fe)
1316 s->fe->feconn--;
1317 if (s->be && (s->flags & SN_BE_ASSIGNED))
1318 s->be->beconn--;
1319 actconn--;
1320
1321 if (unlikely((global.mode & MODE_DEBUG) &&
1322 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
1323 int len;
1324 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
1325 s->uniq_id, s->be->id,
1326 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
1327 write(1, trash, len);
1328 }
1329
1330 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +01001331 session_process_counters(s);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001332
1333 /* let's do a final log if we need it */
1334 if (s->logs.logwait &&
1335 !(s->flags & SN_MONITOR) &&
1336 (s->req->total || !(s->fe && s->fe->options & PR_O_NULLNOLOG))) {
1337 //uxst_sess_log(s);
1338 }
1339
1340 /* the task MUST not be in the run queue anymore */
1341 task_delete(t);
1342 session_free(s);
1343 task_free(t);
1344 tv_eternity(next);
1345}
1346#endif /* not converted */
1347
1348
1349/* Processes data exchanges on the statistics socket. The client processing
1350 * is called and the task is put back in the wait queue or it is cleared.
1351 * In order to ease the transition, we simply simulate the server status
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001352 * for now. It only knows states SV_STIDLE, SV_STCONN, SV_STDATA, and
1353 * SV_STCLOSE. Returns in <next> the task's expiration date.
Willy Tarreau92fb9832007-10-16 17:34:28 +02001354 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001355void process_uxst_stats(struct task *t, int *next)
Willy Tarreau92fb9832007-10-16 17:34:28 +02001356{
1357 struct session *s = t->context;
1358 struct listener *listener;
1359 int fsm_resync = 0;
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001360 int last_rep_l;
Willy Tarreau92fb9832007-10-16 17:34:28 +02001361
1362 do {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001363 char *args[MAX_UXST_ARGS + 1];
1364 char *line, *p;
1365 int arg;
1366
Willy Tarreau3e76e722007-10-17 18:57:38 +02001367 fsm_resync = process_uxst_cli(s);
Willy Tarreau3e76e722007-10-17 18:57:38 +02001368
1369 if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) {
1370 s->srv_state = SV_STCLOSE;
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001371 break;
Willy Tarreau3e76e722007-10-17 18:57:38 +02001372 }
1373
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001374 switch (s->srv_state) {
1375 case SV_STIDLE:
1376 /* stats output not initialized yet */
1377 memset(&s->data_ctx.stats, 0, sizeof(s->data_ctx.stats));
1378 s->data_source = DATA_SRC_STATS;
1379 s->srv_state = SV_STCONN;
1380 fsm_resync |= 1;
1381 break;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001382
Willy Tarreauadfb8562008-08-11 15:24:42 +02001383 case SV_STCONN: /* should be changed to SV_STHEADERS or something more obvious */
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001384 /* stats initialized, but waiting for the command */
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001385 line = s->req->data;
1386 p = memchr(line, '\n', s->req->l);
1387
1388 if (!p)
1389 continue;
1390
1391 *p = '\0';
1392
1393 while (isspace((unsigned char)*line))
1394 line++;
1395
1396 arg = 0;
1397 args[arg] = line;
1398
1399 while (*line && arg < MAX_UXST_ARGS) {
1400 if (isspace((unsigned char)*line)) {
1401 *line++ = '\0';
1402
1403 while (isspace((unsigned char)*line))
1404 line++;
1405
1406 args[++arg] = line;
Willy Tarreaua8efd362008-01-03 10:19:15 +01001407 continue;
1408 }
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001409
1410 line++;
Willy Tarreaua8efd362008-01-03 10:19:15 +01001411 }
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001412
1413 while (++arg <= MAX_UXST_ARGS)
1414 args[arg] = line;
1415
1416 if (!strcmp(args[0], "show")) {
1417 if (!strcmp(args[1], "stat")) {
1418 if (*args[2] && *args[3] && *args[4]) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001419 s->data_ctx.stats.flags |= STAT_BOUND;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001420 s->data_ctx.stats.iid = atoi(args[2]);
1421 s->data_ctx.stats.type = atoi(args[3]);
1422 s->data_ctx.stats.sid = atoi(args[4]);
1423 }
1424
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001425 s->data_ctx.stats.flags |= STAT_SHOW_STAT;
1426 s->data_ctx.stats.flags |= STAT_FMT_CSV;
1427 s->srv_state = SV_STDATA;
1428 fsm_resync |= 1;
Willy Tarreau92fb9832007-10-16 17:34:28 +02001429 continue;
1430 }
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001431
1432 if (!strcmp(args[1], "info")) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001433 s->data_ctx.stats.flags |= STAT_SHOW_INFO;
1434 s->data_ctx.stats.flags |= STAT_FMT_CSV;
1435 s->srv_state = SV_STDATA;
1436 fsm_resync |= 1;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001437 continue;
1438 }
Willy Tarreau92fb9832007-10-16 17:34:28 +02001439 }
Willy Tarreau3e76e722007-10-17 18:57:38 +02001440
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001441 s->srv_state = SV_STCLOSE;
1442 fsm_resync |= 1;
Willy Tarreau3e76e722007-10-17 18:57:38 +02001443 continue;
1444
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001445 case SV_STDATA:
1446 /* OK we have to process the request. Since it is possible
1447 * that we get there with the client output paused, we
1448 * will simply check that we have really sent some data
1449 * and wake the client up if needed.
1450 */
1451 last_rep_l = s->rep->l;
1452 if (stats_dump_raw(s, NULL) != 0) {
1453 s->srv_state = SV_STCLOSE;
1454 fsm_resync |= 1;
1455 }
1456 if (s->rep->l != last_rep_l)
1457 fsm_resync |= 1;
1458 break;
Willy Tarreau3e76e722007-10-17 18:57:38 +02001459 }
Willy Tarreau92fb9832007-10-16 17:34:28 +02001460 } while (fsm_resync);
1461
1462 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
1463 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1464 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1465
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001466 t->expire = tick_first(tick_first(s->req->rex, s->req->wex),
1467 tick_first(s->rep->rex, s->rep->wex));
Willy Tarreau92fb9832007-10-16 17:34:28 +02001468
1469 /* restore t to its place in the task list */
1470 task_queue(t);
1471
1472 *next = t->expire;
1473 return; /* nothing more to do */
1474 }
1475
1476 actconn--;
1477 listener = fdtab[s->cli_fd].listener;
1478 if (listener) {
1479 listener->nbconn--;
1480 if (listener->state == LI_FULL &&
1481 listener->nbconn < listener->maxconn) {
1482 /* we should reactivate the listener */
1483 EV_FD_SET(listener->fd, DIR_RD);
1484 listener->state = LI_READY;
1485 }
1486 }
1487
1488 /* the task MUST not be in the run queue anymore */
1489 task_delete(t);
1490 session_free(s);
1491 task_free(t);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001492 *next = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +02001493}
1494
Willy Tarreau92fb9832007-10-16 17:34:28 +02001495__attribute__((constructor))
1496static void __uxst_protocol_init(void)
1497{
1498 protocol_register(&proto_unix);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001499}
1500
1501
1502/*
1503 * Local variables:
1504 * c-indent-level: 8
1505 * c-basic-offset: 8
1506 * End:
1507 */