blob: dc2b93388bc58dbf89f7d86a755fe5e276ea44c3 [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>
Willy Tarreau3e76e722007-10-17 18:57:38 +020050#include <proto/senddata.h>
Willy Tarreau92fb9832007-10-16 17:34:28 +020051#include <proto/session.h>
52#include <proto/stream_sock.h>
53#include <proto/task.h>
54
55#ifndef MAXPATHLEN
56#define MAXPATHLEN 128
57#endif
58
Willy Tarreaudabf2e22007-10-28 21:59:24 +010059static int uxst_bind_listeners(struct protocol *proto);
60static int uxst_unbind_listeners(struct protocol *proto);
61
62/* Note: must not be declared <const> as its list will be overwritten */
63static struct protocol proto_unix = {
64 .name = "unix_stream",
65 .sock_domain = PF_UNIX,
66 .sock_type = SOCK_STREAM,
67 .sock_prot = 0,
68 .sock_family = AF_UNIX,
69 .sock_addrlen = sizeof(struct sockaddr_un),
70 .l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path),/* path len */
71 .read = &stream_sock_read,
72 .write = &stream_sock_write,
73 .bind_all = uxst_bind_listeners,
74 .unbind_all = uxst_unbind_listeners,
75 .enable_all = enable_all_listeners,
76 .disable_all = disable_all_listeners,
77 .listeners = LIST_HEAD_INIT(proto_unix.listeners),
78 .nb_listeners = 0,
79};
80
81
82/********************************
83 * 1) low-level socket functions
84 ********************************/
85
86
Willy Tarreau92fb9832007-10-16 17:34:28 +020087/* This function creates a named PF_UNIX stream socket at address <path>. Note
Willy Tarreaue6ad2b12007-10-18 12:45:54 +020088 * that the path cannot be NULL nor empty. <uid> and <gid> different of -1 will
89 * be used to change the socket owner. If <mode> is not 0, it will be used to
90 * restrict access to the socket. While it is known not to be portable on every
91 * OS, it's still useful where it works.
Willy Tarreau92fb9832007-10-16 17:34:28 +020092 * It returns the assigned file descriptor, or -1 in the event of an error.
93 */
Willy Tarreaue6ad2b12007-10-18 12:45:54 +020094static int create_uxst_socket(const char *path, uid_t uid, gid_t gid, mode_t mode)
Willy Tarreau92fb9832007-10-16 17:34:28 +020095{
96 char tempname[MAXPATHLEN];
97 char backname[MAXPATHLEN];
98 struct sockaddr_un addr;
99
100 int ret, sock;
101
102 /* 1. create socket names */
103 if (!path[0]) {
104 Alert("Invalid name for a UNIX socket. Aborting.\n");
105 goto err_return;
106 }
107
108 ret = snprintf(tempname, MAXPATHLEN, "%s.%d.tmp", path, pid);
109 if (ret < 0 || ret >= MAXPATHLEN) {
110 Alert("name too long for UNIX socket. Aborting.\n");
111 goto err_return;
112 }
113
114 ret = snprintf(backname, MAXPATHLEN, "%s.%d.bak", path, pid);
115 if (ret < 0 || ret >= MAXPATHLEN) {
116 Alert("name too long for UNIX socket. Aborting.\n");
117 goto err_return;
118 }
119
120 /* 2. clean existing orphaned entries */
121 if (unlink(tempname) < 0 && errno != ENOENT) {
122 Alert("error when trying to unlink previous UNIX socket. Aborting.\n");
123 goto err_return;
124 }
125
126 if (unlink(backname) < 0 && errno != ENOENT) {
127 Alert("error when trying to unlink previous UNIX socket. Aborting.\n");
128 goto err_return;
129 }
130
131 /* 3. backup existing socket */
132 if (link(path, backname) < 0 && errno != ENOENT) {
133 Alert("error when trying to preserve previous UNIX socket. Aborting.\n");
134 goto err_return;
135 }
136
137 /* 4. prepare new socket */
138 addr.sun_family = AF_UNIX;
139 strncpy(addr.sun_path, tempname, sizeof(addr.sun_path));
140 addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
141
142 sock = socket(PF_UNIX, SOCK_STREAM, 0);
143 if (sock < 0) {
144 Alert("cannot create socket for UNIX listener. Aborting.\n");
145 goto err_unlink_back;
146 }
147
148 if (sock >= global.maxsock) {
149 Alert("socket(): not enough free sockets for UNIX listener. Raise -n argument. Aborting.\n");
150 goto err_unlink_temp;
151 }
152
153 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
154 Alert("cannot make UNIX socket non-blocking. Aborting.\n");
155 goto err_unlink_temp;
156 }
157
158 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
159 /* note that bind() creates the socket <tempname> on the file system */
160 Alert("cannot bind socket for UNIX listener. Aborting.\n");
161 goto err_unlink_temp;
162 }
163
Willy Tarreaue6ad2b12007-10-18 12:45:54 +0200164 if (((uid != -1 || gid != -1) && (chown(tempname, uid, gid) == -1)) ||
165 (mode != 0 && chmod(tempname, mode) == -1)) {
166 Alert("cannot change UNIX socket ownership. Aborting.\n");
167 goto err_unlink_temp;
168 }
169
Willy Tarreau92fb9832007-10-16 17:34:28 +0200170 if (listen(sock, 0) < 0) {
171 Alert("cannot listen to socket for UNIX listener. Aborting.\n");
172 goto err_unlink_temp;
173 }
174
175 /* 5. install.
176 * Point of no return: we are ready, we'll switch the sockets. We don't
177 * fear loosing the socket <path> because we have a copy of it in
178 * backname.
179 */
180 if (rename(tempname, path) < 0) {
181 Alert("cannot switch final and temporary sockets for UNIX listener. Aborting.\n");
182 goto err_rename;
183 }
184
185 /* 6. cleanup */
186 unlink(backname); /* no need to keep this one either */
187
188 return sock;
189
190 err_rename:
191 ret = rename(backname, path);
192 if (ret < 0 && errno == ENOENT)
193 unlink(path);
194 err_unlink_temp:
195 unlink(tempname);
196 close(sock);
197 err_unlink_back:
198 unlink(backname);
199 err_return:
200 return -1;
201}
202
203/* Tries to destroy the UNIX stream socket <path>. The socket must not be used
204 * anymore. It practises best effort, and no error is returned.
205 */
206static void destroy_uxst_socket(const char *path)
207{
208 struct sockaddr_un addr;
209 int sock, ret;
210
211 /* We might have been chrooted, so we may not be able to access the
212 * socket. In order to avoid bothering the other end, we connect with a
213 * wrong protocol, namely SOCK_DGRAM. The return code from connect()
214 * is enough to know if the socket is still live or not. If it's live
215 * in mode SOCK_STREAM, we get EPROTOTYPE or anything else but not
216 * ECONNREFUSED. In this case, we do not touch it because it's used
217 * by some other process.
218 */
219 sock = socket(PF_UNIX, SOCK_DGRAM, 0);
220 if (sock < 0)
221 return;
222
223 addr.sun_family = AF_UNIX;
224 strncpy(addr.sun_path, path, sizeof(addr.sun_path));
Willy Tarreau10ae5482007-10-18 16:15:52 +0200225 addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200226 ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
227 if (ret < 0 && errno == ECONNREFUSED) {
228 /* Connect failed: the socket still exists but is not used
229 * anymore. Let's remove this socket now.
230 */
231 unlink(path);
232 }
233 close(sock);
234}
235
236
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100237/********************************
238 * 2) listener-oriented functions
239 ********************************/
240
241
242/* This function creates the UNIX socket associated to the listener. It changes
243 * the state from ASSIGNED to LISTEN. The socket is NOT enabled for polling.
244 * The return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL.
245 */
246static int uxst_bind_listener(struct listener *listener)
247{
248 int fd;
249
250 if (listener->state != LI_ASSIGNED)
251 return ERR_NONE; /* already bound */
252
253 fd = create_uxst_socket(((struct sockaddr_un *)&listener->addr)->sun_path,
254 listener->perm.ux.uid,
255 listener->perm.ux.gid,
256 listener->perm.ux.mode);
257 if (fd == -1)
258 return ERR_FATAL;
259
260 /* the socket is now listening */
261 listener->fd = fd;
262 listener->state = LI_LISTEN;
263
264 /* the function for the accept() event */
265 fd_insert(fd);
266 fdtab[fd].cb[DIR_RD].f = listener->accept;
267 fdtab[fd].cb[DIR_WR].f = NULL; /* never called */
268 fdtab[fd].cb[DIR_RD].b = fdtab[fd].cb[DIR_WR].b = NULL;
Willy Tarreaueabf3132008-08-29 23:36:51 +0200269 fdtab[fd].owner = listener; /* reference the listener instead of a task */
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100270 fdtab[fd].state = FD_STLISTEN;
271 fdtab[fd].peeraddr = NULL;
272 fdtab[fd].peerlen = 0;
273 fdtab[fd].listener = NULL;
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100274 return ERR_NONE;
275}
276
277/* This function closes the UNIX sockets for the specified listener.
278 * The listener enters the LI_ASSIGNED state. It always returns ERR_NONE.
279 */
280static int uxst_unbind_listener(struct listener *listener)
281{
282 if (listener->state == LI_READY)
283 EV_FD_CLR(listener->fd, DIR_RD);
284
285 if (listener->state >= LI_LISTEN) {
Willy Tarreau8eebe5e2007-10-28 22:07:08 +0100286 fd_delete(listener->fd);
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100287 listener->state = LI_ASSIGNED;
288 destroy_uxst_socket(((struct sockaddr_un *)&listener->addr)->sun_path);
289 }
290 return ERR_NONE;
291}
292
293/* Add a listener to the list of unix stream listeners. The listener's state
294 * is automatically updated from LI_INIT to LI_ASSIGNED. The number of
295 * listeners is updated. This is the function to use to add a new listener.
296 */
297void uxst_add_listener(struct listener *listener)
298{
299 if (listener->state != LI_INIT)
300 return;
301 listener->state = LI_ASSIGNED;
302 listener->proto = &proto_unix;
303 LIST_ADDQ(&proto_unix.listeners, &listener->proto_list);
304 proto_unix.nb_listeners++;
305}
306
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100307/********************************
308 * 3) protocol-oriented functions
309 ********************************/
310
311
Willy Tarreau92fb9832007-10-16 17:34:28 +0200312/* This function creates all UNIX sockets bound to the protocol entry <proto>.
313 * It is intended to be used as the protocol's bind_all() function.
314 * The sockets will be registered but not added to any fd_set, in order not to
315 * loose them across the fork(). A call to uxst_enable_listeners() is needed
316 * to complete initialization.
317 *
318 * The return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL.
319 */
320static int uxst_bind_listeners(struct protocol *proto)
321{
322 struct listener *listener;
323 int err = ERR_NONE;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200324
325 list_for_each_entry(listener, &proto->listeners, proto_list) {
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100326 err |= uxst_bind_listener(listener);
327 if (err != ERR_NONE)
Willy Tarreau92fb9832007-10-16 17:34:28 +0200328 continue;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200329 }
Willy Tarreau92fb9832007-10-16 17:34:28 +0200330 return err;
331}
332
Willy Tarreau92fb9832007-10-16 17:34:28 +0200333
334/* This function stops all listening UNIX sockets bound to the protocol
335 * <proto>. It does not detaches them from the protocol.
336 * It always returns ERR_NONE.
337 */
338static int uxst_unbind_listeners(struct protocol *proto)
339{
340 struct listener *listener;
341
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100342 list_for_each_entry(listener, &proto->listeners, proto_list)
343 uxst_unbind_listener(listener);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200344 return ERR_NONE;
345}
346
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100347
348/********************************
349 * 4) high-level functions
350 ********************************/
351
352
Willy Tarreau92fb9832007-10-16 17:34:28 +0200353/*
354 * This function is called on a read event from a listen socket, corresponding
355 * to an accept. It tries to accept as many connections as possible.
356 * It returns 0. Since we use UNIX sockets on the local system for monitoring
357 * purposes and other related things, we do not need to output as many messages
358 * as with TCP which can fall under attack.
359 */
360int uxst_event_accept(int fd) {
Willy Tarreaueabf3132008-08-29 23:36:51 +0200361 struct listener *l = fdtab[fd].owner;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200362 struct session *s;
363 struct task *t;
364 int cfd;
365 int max_accept;
366
367 if (global.nbproc > 1)
368 max_accept = 8; /* let other processes catch some connections too */
369 else
370 max_accept = -1;
371
372 while (max_accept--) {
373 struct sockaddr_storage addr;
374 socklen_t laddr = sizeof(addr);
375
376 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
377 switch (errno) {
378 case EAGAIN:
379 case EINTR:
380 case ECONNABORTED:
381 return 0; /* nothing more to accept */
382 case ENFILE:
383 /* Process reached system FD limit. Check system tunables. */
384 return 0;
385 case EMFILE:
386 /* Process reached process FD limit. Check 'ulimit-n'. */
387 return 0;
388 case ENOBUFS:
389 case ENOMEM:
390 /* Process reached system memory limit. Check system tunables. */
391 return 0;
392 default:
393 return 0;
394 }
395 }
396
397 if (l->nbconn >= l->maxconn) {
398 /* too many connections, we shoot this one and return.
399 * FIXME: it would be better to simply switch the listener's
400 * state to LI_FULL and disable the FD. We could re-enable
401 * it upon fd_delete(), but this requires all protocols to
402 * be switched.
403 */
404 close(cfd);
405 return 0;
406 }
407
408 if ((s = pool_alloc2(pool2_session)) == NULL) {
409 Alert("out of memory in uxst_event_accept().\n");
410 close(cfd);
411 return 0;
412 }
413
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +0100414 s->flags = 0;
Willy Tarreauf8533202008-08-16 14:55:08 +0200415 s->term_trace = 0;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +0100416
Willy Tarreau92fb9832007-10-16 17:34:28 +0200417 if ((t = pool_alloc2(pool2_task)) == NULL) {
418 Alert("out of memory in uxst_event_accept().\n");
419 close(cfd);
420 pool_free2(pool2_session, s);
421 return 0;
422 }
423
424 s->cli_addr = addr;
425
426 /* FIXME: should be checked earlier */
427 if (cfd >= global.maxsock) {
428 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
429 close(cfd);
430 pool_free2(pool2_task, t);
431 pool_free2(pool2_session, s);
432 return 0;
433 }
434
435 if (fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) {
436 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
437 close(cfd);
438 pool_free2(pool2_task, t);
439 pool_free2(pool2_session, s);
440 return 0;
441 }
442
Willy Tarreau9789f7b2008-06-24 08:17:16 +0200443 task_init(t);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200444 t->process = l->handler;
445 t->context = s;
Willy Tarreau91e99932008-06-30 07:51:00 +0200446 t->nice = -64; /* we want to boost priority for local stats */
Willy Tarreau92fb9832007-10-16 17:34:28 +0200447
448 s->task = t;
449 s->fe = NULL;
450 s->be = NULL;
451
452 s->cli_state = CL_STDATA;
453 s->srv_state = SV_STIDLE;
454 s->req = s->rep = NULL; /* will be allocated later */
455
456 s->cli_fd = cfd;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200457 s->srv = NULL;
458 s->pend_pos = NULL;
459
460 memset(&s->logs, 0, sizeof(s->logs));
461 memset(&s->txn, 0, sizeof(s->txn));
462
Willy Tarreau3e76e722007-10-17 18:57:38 +0200463 s->data_state = DATA_ST_INIT;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200464 s->data_source = DATA_SRC_NONE;
465 s->uniq_id = totalconn;
466
467 if ((s->req = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */
468 close(cfd); /* nothing can be done for this fd without memory */
469 pool_free2(pool2_task, t);
470 pool_free2(pool2_session, s);
471 return 0;
472 }
473
474 if ((s->rep = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */
475 pool_free2(pool2_buffer, s->req);
476 close(cfd); /* nothing can be done for this fd without memory */
477 pool_free2(pool2_task, t);
478 pool_free2(pool2_session, s);
479 return 0;
480 }
481
482 buffer_init(s->req);
483 buffer_init(s->rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200484
485 fd_insert(cfd);
486 fdtab[cfd].owner = t;
487 fdtab[cfd].listener = l;
488 fdtab[cfd].state = FD_STREADY;
489 fdtab[cfd].cb[DIR_RD].f = l->proto->read;
490 fdtab[cfd].cb[DIR_RD].b = s->req;
491 fdtab[cfd].cb[DIR_WR].f = l->proto->write;
492 fdtab[cfd].cb[DIR_WR].b = s->rep;
493 fdtab[cfd].peeraddr = (struct sockaddr *)&s->cli_addr;
494 fdtab[cfd].peerlen = sizeof(s->cli_addr);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200495
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200496 s->req->rex = TICK_ETERNITY;
497 s->req->wex = TICK_ETERNITY;
Willy Tarreauffab5b42008-08-17 18:03:28 +0200498 s->req->analyse_exp = TICK_ETERNITY;
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200499 s->rep->rex = TICK_ETERNITY;
500 s->rep->wex = TICK_ETERNITY;
Willy Tarreauffab5b42008-08-17 18:03:28 +0200501 s->rep->analyse_exp = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200502
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200503 s->req->wto = TICK_ETERNITY;
504 s->req->cto = TICK_ETERNITY;
505 s->req->rto = TICK_ETERNITY;
506 s->rep->rto = TICK_ETERNITY;
507 s->rep->cto = TICK_ETERNITY;
508 s->rep->wto = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200509
510 if (l->timeout)
511 s->req->rto = *l->timeout;
512
513 if (l->timeout)
514 s->rep->wto = *l->timeout;
515
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200516 t->expire = TICK_ETERNITY;
517 if (l->timeout && *l->timeout) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200518 EV_FD_SET(cfd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200519 s->req->rex = tick_add(now_ms, s->req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200520 t->expire = s->req->rex;
521 }
522
Willy Tarreaufdccded2008-08-29 18:19:04 +0200523 task_wakeup(t, TASK_WOKEN_INIT);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200524
525 l->nbconn++; /* warning! right now, it's up to the handler to decrease this */
526 if (l->nbconn >= l->maxconn) {
527 EV_FD_CLR(l->fd, DIR_RD);
528 l->state = LI_FULL;
529 }
530 actconn++;
531 totalconn++;
532
533 //fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p, cfd=%d, maxfd=%d\n", p, actconn, totalconn, t, cfd, maxfd);
534 } /* end of while (p->feconn < p->maxconn) */
535 //fprintf(stderr,"fct %s:%d\n", __FUNCTION__, __LINE__);
536 return 0;
537}
538
539/*
540 * manages the client FSM and its socket. It returns 1 if a state has changed
541 * (and a resync may be needed), otherwise 0.
542 */
543static int process_uxst_cli(struct session *t)
544{
545 int s = t->srv_state;
546 int c = t->cli_state;
547 struct buffer *req = t->req;
548 struct buffer *rep = t->rep;
549 //fprintf(stderr,"fct %s:%d\n", __FUNCTION__, __LINE__);
550 if (c == CL_STDATA) {
551 /* FIXME: this error handling is partly buggy because we always report
552 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
553 * or HEADER phase. BTW, it's not logical to expire the client while
554 * we're waiting for the server to connect.
555 */
556 /* read or write error */
557 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200558 buffer_shutr(req);
559 buffer_shutw(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200560 fd_delete(t->cli_fd);
561 t->cli_state = CL_STCLOSE;
562 if (!(t->flags & SN_ERR_MASK))
563 t->flags |= SN_ERR_CLICL;
564 if (!(t->flags & SN_FINST_MASK)) {
565 if (t->pend_pos)
566 t->flags |= SN_FINST_Q;
567 else if (s == SV_STCONN)
568 t->flags |= SN_FINST_C;
569 else
570 t->flags |= SN_FINST_D;
571 }
572 return 1;
573 }
574 /* last read, or end of server write */
575 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
576 EV_FD_CLR(t->cli_fd, DIR_RD);
577 buffer_shutr(req);
578 t->cli_state = CL_STSHUTR;
579 return 1;
580 }
581 /* last server read and buffer empty */
Willy Tarreaue393fe22008-08-16 22:18:07 +0200582 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->flags & BF_EMPTY)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200583 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +0200584 buffer_shutw(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200585 shutdown(t->cli_fd, SHUT_WR);
586 /* We must ensure that the read part is still alive when switching
587 * to shutw */
588 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200589 req->rex = tick_add_ifset(now_ms, req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200590 t->cli_state = CL_STSHUTW;
591 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
592 return 1;
593 }
594 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200595 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200596 EV_FD_CLR(t->cli_fd, DIR_RD);
597 buffer_shutr(req);
598 t->cli_state = CL_STSHUTR;
599 if (!(t->flags & SN_ERR_MASK))
600 t->flags |= SN_ERR_CLITO;
601 if (!(t->flags & SN_FINST_MASK)) {
602 if (t->pend_pos)
603 t->flags |= SN_FINST_Q;
604 else if (s == SV_STCONN)
605 t->flags |= SN_FINST_C;
606 else
607 t->flags |= SN_FINST_D;
608 }
609 return 1;
610 }
611 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200612 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200613 EV_FD_CLR(t->cli_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +0200614 buffer_shutw(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200615 shutdown(t->cli_fd, SHUT_WR);
616 /* We must ensure that the read part is still alive when switching
617 * to shutw */
618 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200619 req->rex = tick_add_ifset(now_ms, req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200620
621 t->cli_state = CL_STSHUTW;
622 if (!(t->flags & SN_ERR_MASK))
623 t->flags |= SN_ERR_CLITO;
624 if (!(t->flags & SN_FINST_MASK)) {
625 if (t->pend_pos)
626 t->flags |= SN_FINST_Q;
627 else if (s == SV_STCONN)
628 t->flags |= SN_FINST_C;
629 else
630 t->flags |= SN_FINST_D;
631 }
632 return 1;
633 }
634
Willy Tarreaue393fe22008-08-16 22:18:07 +0200635 if (req->flags & BF_FULL) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200636 /* no room to read more data */
637 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
638 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200639 req->rex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200640 }
641 } else {
642 /* there's still some space in the buffer */
643 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200644 if (!req->rto ||
645 (t->srv_state < SV_STDATA && req->wto))
Willy Tarreau92fb9832007-10-16 17:34:28 +0200646 /* If the client has no timeout, or if the server not ready yet, and we
647 * know for sure that it can expire, then it's cleaner to disable the
648 * timeout on the client side so that too low values cannot make the
649 * sessions abort too early.
650 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200651 req->rex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200652 else
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200653 req->rex = tick_add(now_ms, req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200654 }
655 }
656
Willy Tarreaue393fe22008-08-16 22:18:07 +0200657 if ((rep->flags & BF_EMPTY) ||
Willy Tarreau92fb9832007-10-16 17:34:28 +0200658 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
659 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
660 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200661 rep->wex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200662 }
663 } else {
664 /* buffer not empty */
665 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
666 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200667 rep->wex = tick_add_ifset(now_ms, rep->wto);
668 if (rep->wex) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200669 /* FIXME: to prevent the client from expiring read timeouts during writes,
670 * we refresh it. */
671 req->rex = rep->wex;
672 }
Willy Tarreau92fb9832007-10-16 17:34:28 +0200673 }
674 }
675 return 0; /* other cases change nothing */
676 }
677 else if (c == CL_STSHUTR) {
678 if (rep->flags & BF_WRITE_ERROR) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200679 buffer_shutw(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200680 fd_delete(t->cli_fd);
681 t->cli_state = CL_STCLOSE;
682 if (!(t->flags & SN_ERR_MASK))
683 t->flags |= SN_ERR_CLICL;
684 if (!(t->flags & SN_FINST_MASK)) {
685 if (t->pend_pos)
686 t->flags |= SN_FINST_Q;
687 else if (s == SV_STCONN)
688 t->flags |= SN_FINST_C;
689 else
690 t->flags |= SN_FINST_D;
691 }
692 return 1;
693 }
Willy Tarreaue393fe22008-08-16 22:18:07 +0200694 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->flags & BF_EMPTY)) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200695 buffer_shutw(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200696 fd_delete(t->cli_fd);
697 t->cli_state = CL_STCLOSE;
698 return 1;
699 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200700 else if (tick_is_expired(rep->wex, now_ms)) {
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 if (!(t->flags & SN_ERR_MASK))
705 t->flags |= SN_ERR_CLITO;
706 if (!(t->flags & SN_FINST_MASK)) {
707 if (t->pend_pos)
708 t->flags |= SN_FINST_Q;
709 else if (s == SV_STCONN)
710 t->flags |= SN_FINST_C;
711 else
712 t->flags |= SN_FINST_D;
713 }
714 return 1;
715 }
716
Willy Tarreaue393fe22008-08-16 22:18:07 +0200717 if (rep->flags & BF_EMPTY) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200718 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
719 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200720 rep->wex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200721 }
722 } else {
723 /* buffer not empty */
724 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
725 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200726 rep->wex = tick_add_ifset(now_ms, rep->wto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200727 }
728 }
729 return 0;
730 }
731 else if (c == CL_STSHUTW) {
732 if (req->flags & BF_READ_ERROR) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200733 buffer_shutr(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200734 fd_delete(t->cli_fd);
735 t->cli_state = CL_STCLOSE;
736 if (!(t->flags & SN_ERR_MASK))
737 t->flags |= SN_ERR_CLICL;
738 if (!(t->flags & SN_FINST_MASK)) {
739 if (t->pend_pos)
740 t->flags |= SN_FINST_Q;
741 else if (s == SV_STCONN)
742 t->flags |= SN_FINST_C;
743 else
744 t->flags |= SN_FINST_D;
745 }
746 return 1;
747 }
748 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200749 buffer_shutr(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200750 fd_delete(t->cli_fd);
751 t->cli_state = CL_STCLOSE;
752 return 1;
753 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200754 else if (tick_is_expired(req->rex, now_ms)) {
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 if (!(t->flags & SN_ERR_MASK))
759 t->flags |= SN_ERR_CLITO;
760 if (!(t->flags & SN_FINST_MASK)) {
761 if (t->pend_pos)
762 t->flags |= SN_FINST_Q;
763 else if (s == SV_STCONN)
764 t->flags |= SN_FINST_C;
765 else
766 t->flags |= SN_FINST_D;
767 }
768 return 1;
769 }
Willy Tarreaue393fe22008-08-16 22:18:07 +0200770 else if (req->flags & BF_FULL) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200771 /* no room to read more data */
772
773 /* FIXME-20050705: is it possible for a client to maintain a session
774 * after the timeout by sending more data after it receives a close ?
775 */
776
777 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
778 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200779 req->rex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200780 }
781 } else {
782 /* there's still some space in the buffer */
783 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200784 req->rex = tick_add_ifset(now_ms, req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200785 }
786 }
787 return 0;
788 }
789 else { /* CL_STCLOSE: nothing to do */
790 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
791 int len;
792 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be?t->be->id:"",
Willy Tarreaufa7e1022008-10-19 07:30:41 +0200793 (unsigned short)t->cli_fd, (unsigned short)t->req->cons->fd);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200794 write(1, trash, len);
795 }
796 return 0;
797 }
798 return 0;
799}
800
801#if 0
802 /* FIXME! This part has not been completely converted yet, and it may
803 * still be very specific to TCPv4 ! Also, it relies on some parameters
804 * such as conn_retries which are not set upon accept().
805 */
806/*
807 * Manages the server FSM and its socket. It returns 1 if a state has changed
808 * (and a resync may be needed), otherwise 0.
809 */
810static int process_uxst_srv(struct session *t)
811{
812 int s = t->srv_state;
813 int c = t->cli_state;
814 struct buffer *req = t->req;
815 struct buffer *rep = t->rep;
816 int conn_err;
817
818 if (s == SV_STIDLE) {
819 if (c == CL_STCLOSE || c == CL_STSHUTW ||
820 (c == CL_STSHUTR &&
Willy Tarreaue393fe22008-08-16 22:18:07 +0200821 (t->req->flags & BF_EMPTY || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
Willy Tarreau92fb9832007-10-16 17:34:28 +0200822 tv_eternity(&req->cex);
823 if (t->pend_pos)
824 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
825 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C);
826 return 1;
827 }
828 else {
829 /* FIXME: reimplement the TARPIT check here */
830
831 /* Right now, we will need to create a connection to the server.
832 * We might already have tried, and got a connection pending, in
833 * which case we will not do anything till it's pending. It's up
834 * to any other session to release it and wake us up again.
835 */
836 if (t->pend_pos) {
837 if (!tv_isle(&req->cex, &now))
838 return 0;
839 else {
840 /* we've been waiting too long here */
841 tv_eternity(&req->cex);
842 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
843 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q);
844 if (t->srv)
845 t->srv->failed_conns++;
846 if (t->fe)
847 t->fe->failed_conns++;
848 return 1;
849 }
850 }
851
852 do {
853 /* first, get a connection */
854 if (srv_redispatch_connect(t))
855 return t->srv_state != SV_STIDLE;
856
857 /* try to (re-)connect to the server, and fail if we expire the
858 * number of retries.
859 */
860 if (srv_retryable_connect(t)) {
861 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
862 return t->srv_state != SV_STIDLE;
863 }
864 } while (1);
865 }
866 }
867 else if (s == SV_STCONN) { /* connection in progress */
868 if (c == CL_STCLOSE || c == CL_STSHUTW ||
869 (c == CL_STSHUTR &&
Willy Tarreau3da77c52008-08-29 09:58:42 +0200870 ((t->req->flags & BF_EMPTY && !(req->flags & BF_WRITE_ACTIVITY)) ||
Willy Tarreau92fb9832007-10-16 17:34:28 +0200871 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
872 tv_eternity(&req->cex);
873 fd_delete(t->srv_fd);
874 if (t->srv)
875 t->srv->cur_sess--;
876
877 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C);
878 return 1;
879 }
Willy Tarreau3da77c52008-08-29 09:58:42 +0200880 if (!(req->flags & BF_WRITE_ACTIVITY) && !tv_isle(&req->cex, &now)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200881 //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);
882 return 0; /* nothing changed */
883 }
Willy Tarreau3da77c52008-08-29 09:58:42 +0200884 else if (!(req->flags & BF_WRITE_ACTIVITY) || (req->flags & BF_WRITE_ERROR)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200885 /* timeout, asynchronous connect error or first write error */
886 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
887
888 fd_delete(t->srv_fd);
889 if (t->srv)
890 t->srv->cur_sess--;
891
Willy Tarreau3da77c52008-08-29 09:58:42 +0200892 if (!(req->flags & BF_WRITE_ACTIVITY))
Willy Tarreau92fb9832007-10-16 17:34:28 +0200893 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
894 else
895 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
896
897 /* ensure that we have enough retries left */
898 if (srv_count_retry_down(t, conn_err))
899 return 1;
900
901 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
902 /* We're on our last chance, and the REDISP option was specified.
903 * We will ignore cookie and force to balance or use the dispatcher.
904 */
905 /* let's try to offer this slot to anybody */
906 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +0200907 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200908
909 if (t->srv)
910 t->srv->failed_conns++;
911 t->be->failed_conns++;
912
913 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
914 t->srv = NULL; /* it's left to the dispatcher to choose a server */
915
916 /* first, get a connection */
917 if (srv_redispatch_connect(t))
918 return t->srv_state != SV_STIDLE;
919 }
920
921 do {
922 /* Now we will try to either reconnect to the same server or
923 * connect to another server. If the connection gets queued
924 * because all servers are saturated, then we will go back to
925 * the SV_STIDLE state.
926 */
927 if (srv_retryable_connect(t)) {
928 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
929 return t->srv_state != SV_STCONN;
930 }
931
932 /* we need to redispatch the connection to another server */
933 if (srv_redispatch_connect(t))
934 return t->srv_state != SV_STCONN;
935 } while (1);
936 }
937 else { /* no error or write 0 */
938 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
939
940 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
Willy Tarreaue393fe22008-08-16 22:18:07 +0200941 if (req->flags & BF_EMPTY) /* nothing to write */ {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200942 EV_FD_CLR(t->srv_fd, DIR_WR);
943 tv_eternity(&req->wex);
944 } else /* need the right to write */ {
945 EV_FD_SET(t->srv_fd, DIR_WR);
946 if (tv_add_ifset(&req->wex, &now, &req->wto)) {
947 /* FIXME: to prevent the server from expiring read timeouts during writes,
948 * we refresh it. */
949 rep->rex = req->wex;
950 }
951 else
952 tv_eternity(&req->wex);
953 }
954
955 EV_FD_SET(t->srv_fd, DIR_RD);
956 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
957 tv_eternity(&rep->rex);
958
959 t->srv_state = SV_STDATA;
960 if (t->srv)
961 t->srv->cum_sess++;
Willy Tarreaue393fe22008-08-16 22:18:07 +0200962 buffer_set_rlim(rep, BUFSIZE); /* no rewrite needed */
Willy Tarreau92fb9832007-10-16 17:34:28 +0200963
964 /* if the user wants to log as soon as possible, without counting
965 bytes from the server, then this is the right moment. */
966 if (t->fe && t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
967 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
968 //uxst_sess_log(t);
969 }
970 tv_eternity(&req->cex);
971 return 1;
972 }
973 }
974 else if (s == SV_STDATA) {
975 /* read or write error */
976 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
Willy Tarreauba392ce2008-08-16 21:13:23 +0200977 buffer_shutr(rep);
978 buffer_shutw(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200979 fd_delete(t->srv_fd);
980 if (t->srv) {
981 t->srv->cur_sess--;
982 t->srv->failed_resp++;
983 }
984 t->be->failed_resp++;
985 t->srv_state = SV_STCLOSE;
986 if (!(t->flags & SN_ERR_MASK))
987 t->flags |= SN_ERR_SRVCL;
988 if (!(t->flags & SN_FINST_MASK))
989 t->flags |= SN_FINST_D;
990 /* We used to have a free connection slot. Since we'll never use it,
991 * we have to inform the server that it may be used by another session.
992 */
993 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +0200994 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200995
996 return 1;
997 }
998 /* last read, or end of client write */
999 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
1000 EV_FD_CLR(t->srv_fd, DIR_RD);
1001 buffer_shutr(rep);
1002 t->srv_state = SV_STSHUTR;
1003 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1004 return 1;
1005 }
1006 /* end of client read and no more data to send */
Willy Tarreaue393fe22008-08-16 22:18:07 +02001007 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->flags & BF_EMPTY)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +02001008 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001009 buffer_shutw(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001010 shutdown(t->srv_fd, SHUT_WR);
1011 /* We must ensure that the read part is still alive when switching
1012 * to shutw */
1013 EV_FD_SET(t->srv_fd, DIR_RD);
1014 tv_add_ifset(&rep->rex, &now, &rep->rto);
1015
1016 t->srv_state = SV_STSHUTW;
1017 return 1;
1018 }
1019 /* read timeout */
1020 else if (tv_isle(&rep->rex, &now)) {
1021 EV_FD_CLR(t->srv_fd, DIR_RD);
1022 buffer_shutr(rep);
1023 t->srv_state = SV_STSHUTR;
1024 if (!(t->flags & SN_ERR_MASK))
1025 t->flags |= SN_ERR_SRVTO;
1026 if (!(t->flags & SN_FINST_MASK))
1027 t->flags |= SN_FINST_D;
1028 return 1;
1029 }
1030 /* write timeout */
1031 else if (tv_isle(&req->wex, &now)) {
1032 EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001033 buffer_shutw(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001034 shutdown(t->srv_fd, SHUT_WR);
1035 /* We must ensure that the read part is still alive when switching
1036 * to shutw */
1037 EV_FD_SET(t->srv_fd, DIR_RD);
1038 tv_add_ifset(&rep->rex, &now, &rep->rto);
1039 t->srv_state = SV_STSHUTW;
1040 if (!(t->flags & SN_ERR_MASK))
1041 t->flags |= SN_ERR_SRVTO;
1042 if (!(t->flags & SN_FINST_MASK))
1043 t->flags |= SN_FINST_D;
1044 return 1;
1045 }
1046
1047 /* recompute request time-outs */
Willy Tarreaue393fe22008-08-16 22:18:07 +02001048 if (req->flags & BF_EMPTY) {
Willy Tarreau92fb9832007-10-16 17:34:28 +02001049 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
1050 /* stop writing */
1051 tv_eternity(&req->wex);
1052 }
1053 }
1054 else { /* buffer not empty, there are still data to be transferred */
1055 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
1056 /* restart writing */
1057 if (tv_add_ifset(&req->wex, &now, &req->wto)) {
1058 /* FIXME: to prevent the server from expiring read timeouts during writes,
1059 * we refresh it. */
1060 rep->rex = req->wex;
1061 }
1062 else
1063 tv_eternity(&req->wex);
1064 }
1065 }
1066
1067 /* recompute response time-outs */
1068 if (rep->l == BUFSIZE) { /* no room to read more data */
1069 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
1070 tv_eternity(&rep->rex);
1071 }
1072 }
1073 else {
1074 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
1075 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
1076 tv_eternity(&rep->rex);
1077 }
1078 }
1079
1080 return 0; /* other cases change nothing */
1081 }
1082 else if (s == SV_STSHUTR) {
1083 if (req->flags & BF_WRITE_ERROR) {
1084 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001085 buffer_shutw(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001086 fd_delete(t->srv_fd);
1087 if (t->srv) {
1088 t->srv->cur_sess--;
1089 t->srv->failed_resp++;
1090 }
1091 t->be->failed_resp++;
1092 //close(t->srv_fd);
1093 t->srv_state = SV_STCLOSE;
1094 if (!(t->flags & SN_ERR_MASK))
1095 t->flags |= SN_ERR_SRVCL;
1096 if (!(t->flags & SN_FINST_MASK))
1097 t->flags |= SN_FINST_D;
1098 /* We used to have a free connection slot. Since we'll never use it,
1099 * we have to inform the server that it may be used by another session.
1100 */
1101 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001102 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001103
1104 return 1;
1105 }
Willy Tarreaue393fe22008-08-16 22:18:07 +02001106 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->flags & BF_EMPTY)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +02001107 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001108 buffer_shutw(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001109 fd_delete(t->srv_fd);
1110 if (t->srv)
1111 t->srv->cur_sess--;
1112 //close(t->srv_fd);
1113 t->srv_state = SV_STCLOSE;
1114 /* We used to have a free connection slot. Since we'll never use it,
1115 * we have to inform the server that it may be used by another session.
1116 */
1117 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001118 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001119
1120 return 1;
1121 }
1122 else if (tv_isle(&req->wex, &now)) {
1123 //EV_FD_CLR(t->srv_fd, DIR_WR);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001124 buffer_shutw(req);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001125 fd_delete(t->srv_fd);
1126 if (t->srv)
1127 t->srv->cur_sess--;
1128 //close(t->srv_fd);
1129 t->srv_state = SV_STCLOSE;
1130 if (!(t->flags & SN_ERR_MASK))
1131 t->flags |= SN_ERR_SRVTO;
1132 if (!(t->flags & SN_FINST_MASK))
1133 t->flags |= SN_FINST_D;
1134 /* We used to have a free connection slot. Since we'll never use it,
1135 * we have to inform the server that it may be used by another session.
1136 */
1137 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001138 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001139
1140 return 1;
1141 }
Willy Tarreaue393fe22008-08-16 22:18:07 +02001142 else if (req->flags & BF_EMPTY) {
Willy Tarreau92fb9832007-10-16 17:34:28 +02001143 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
1144 /* stop writing */
1145 tv_eternity(&req->wex);
1146 }
1147 }
1148 else { /* buffer not empty */
1149 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
1150 /* restart writing */
1151 if (!tv_add_ifset(&req->wex, &now, &req->wto))
1152 tv_eternity(&req->wex);
1153 }
1154 }
1155 return 0;
1156 }
1157 else if (s == SV_STSHUTW) {
1158 if (rep->flags & BF_READ_ERROR) {
1159 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001160 buffer_shutr(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001161 fd_delete(t->srv_fd);
1162 if (t->srv) {
1163 t->srv->cur_sess--;
1164 t->srv->failed_resp++;
1165 }
1166 t->be->failed_resp++;
1167 //close(t->srv_fd);
1168 t->srv_state = SV_STCLOSE;
1169 if (!(t->flags & SN_ERR_MASK))
1170 t->flags |= SN_ERR_SRVCL;
1171 if (!(t->flags & SN_FINST_MASK))
1172 t->flags |= SN_FINST_D;
1173 /* We used to have a free connection slot. Since we'll never use it,
1174 * we have to inform the server that it may be used by another session.
1175 */
1176 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001177 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001178
1179 return 1;
1180 }
1181 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
1182 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001183 buffer_shutr(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001184 fd_delete(t->srv_fd);
1185 if (t->srv)
1186 t->srv->cur_sess--;
1187 //close(t->srv_fd);
1188 t->srv_state = SV_STCLOSE;
1189 /* We used to have a free connection slot. Since we'll never use it,
1190 * we have to inform the server that it may be used by another session.
1191 */
1192 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001193 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001194
1195 return 1;
1196 }
1197 else if (tv_isle(&rep->rex, &now)) {
1198 //EV_FD_CLR(t->srv_fd, DIR_RD);
Willy Tarreauba392ce2008-08-16 21:13:23 +02001199 buffer_shutr(rep);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001200 fd_delete(t->srv_fd);
1201 if (t->srv)
1202 t->srv->cur_sess--;
1203 //close(t->srv_fd);
1204 t->srv_state = SV_STCLOSE;
1205 if (!(t->flags & SN_ERR_MASK))
1206 t->flags |= SN_ERR_SRVTO;
1207 if (!(t->flags & SN_FINST_MASK))
1208 t->flags |= SN_FINST_D;
1209 /* We used to have a free connection slot. Since we'll never use it,
1210 * we have to inform the server that it may be used by another session.
1211 */
1212 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001213 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001214
1215 return 1;
1216 }
1217 else if (rep->l == BUFSIZE) { /* no room to read more data */
1218 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
1219 tv_eternity(&rep->rex);
1220 }
1221 }
1222 else {
1223 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
1224 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
1225 tv_eternity(&rep->rex);
1226 }
1227 }
1228 return 0;
1229 }
1230 else { /* SV_STCLOSE : nothing to do */
1231 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1232 int len;
1233 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
1234 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1235 write(1, trash, len);
1236 }
1237 return 0;
1238 }
1239 return 0;
1240}
1241
1242/* Processes the client and server jobs of a session task, then
1243 * puts it back to the wait queue in a clean state, or
1244 * cleans up its resources if it must be deleted. Returns
1245 * the time the task accepts to wait, or TIME_ETERNITY for
1246 * infinity.
1247 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001248void process_uxst_session(struct task *t, int *next)
Willy Tarreau92fb9832007-10-16 17:34:28 +02001249{
1250 struct session *s = t->context;
1251 int fsm_resync = 0;
1252
1253 do {
1254 fsm_resync = 0;
1255 fsm_resync |= process_uxst_cli(s);
1256 if (s->srv_state == SV_STIDLE) {
1257 if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) {
1258 s->srv_state = SV_STCLOSE;
1259 fsm_resync |= 1;
1260 continue;
1261 }
1262 if (s->cli_state == CL_STSHUTR ||
Willy Tarreaue393fe22008-08-16 22:18:07 +02001263 (s->req->flags & BF_FULL)) {
1264 if (s->req->flags & BF_EMPTY) {
Willy Tarreau92fb9832007-10-16 17:34:28 +02001265 s->srv_state = SV_STCLOSE;
1266 fsm_resync |= 1;
1267 continue;
1268 }
1269 /* OK we have some remaining data to process */
1270 /* Just as an exercice, we copy the req into the resp,
1271 * and flush the req.
1272 */
1273 memcpy(s->rep->data, s->req->data, sizeof(s->rep->data));
1274 s->rep->l = s->req->l;
Willy Tarreaue393fe22008-08-16 22:18:07 +02001275 buffer_set_rlim(s->rep, BUFSIZE);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001276 s->rep->w = s->rep->data;
1277 s->rep->lr = s->rep->r = s->rep->data + s->rep->l;
1278
1279 s->req->l = 0;
1280 s->srv_state = SV_STCLOSE;
1281
1282 fsm_resync |= 1;
1283 continue;
1284 }
1285 }
1286 } while (fsm_resync);
1287
1288 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +01001289
1290 if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
1291 session_process_counters(s);
1292
Willy Tarreau92fb9832007-10-16 17:34:28 +02001293 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1294 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1295
1296 t->expire = s->req->rex;
1297 tv_min(&t->expire, &s->req->rex, &s->req->wex);
1298 tv_bound(&t->expire, &s->req->cex);
1299 tv_bound(&t->expire, &s->rep->rex);
1300 tv_bound(&t->expire, &s->rep->wex);
1301
1302 /* restore t to its place in the task list */
1303 task_queue(t);
1304
1305 *next = t->expire;
1306 return; /* nothing more to do */
1307 }
1308
1309 if (s->fe)
1310 s->fe->feconn--;
1311 if (s->be && (s->flags & SN_BE_ASSIGNED))
1312 s->be->beconn--;
1313 actconn--;
1314
1315 if (unlikely((global.mode & MODE_DEBUG) &&
1316 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
1317 int len;
1318 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
1319 s->uniq_id, s->be->id,
1320 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
1321 write(1, trash, len);
1322 }
1323
1324 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +01001325 session_process_counters(s);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001326
1327 /* let's do a final log if we need it */
1328 if (s->logs.logwait &&
1329 !(s->flags & SN_MONITOR) &&
1330 (s->req->total || !(s->fe && s->fe->options & PR_O_NULLNOLOG))) {
1331 //uxst_sess_log(s);
1332 }
1333
1334 /* the task MUST not be in the run queue anymore */
1335 task_delete(t);
1336 session_free(s);
1337 task_free(t);
1338 tv_eternity(next);
1339}
1340#endif /* not converted */
1341
1342
1343/* Processes data exchanges on the statistics socket. The client processing
1344 * is called and the task is put back in the wait queue or it is cleared.
1345 * In order to ease the transition, we simply simulate the server status
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001346 * for now. It only knows states SV_STIDLE, SV_STCONN, SV_STDATA, and
1347 * SV_STCLOSE. Returns in <next> the task's expiration date.
Willy Tarreau92fb9832007-10-16 17:34:28 +02001348 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001349void process_uxst_stats(struct task *t, int *next)
Willy Tarreau92fb9832007-10-16 17:34:28 +02001350{
1351 struct session *s = t->context;
1352 struct listener *listener;
1353 int fsm_resync = 0;
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001354 int last_rep_l;
Willy Tarreau92fb9832007-10-16 17:34:28 +02001355
1356 do {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001357 char *args[MAX_UXST_ARGS + 1];
1358 char *line, *p;
1359 int arg;
1360
Willy Tarreau3e76e722007-10-17 18:57:38 +02001361 fsm_resync = process_uxst_cli(s);
Willy Tarreau3e76e722007-10-17 18:57:38 +02001362
1363 if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) {
1364 s->srv_state = SV_STCLOSE;
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001365 break;
Willy Tarreau3e76e722007-10-17 18:57:38 +02001366 }
1367
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001368 switch (s->srv_state) {
1369 case SV_STIDLE:
1370 /* stats output not initialized yet */
1371 memset(&s->data_ctx.stats, 0, sizeof(s->data_ctx.stats));
1372 s->data_source = DATA_SRC_STATS;
1373 s->srv_state = SV_STCONN;
1374 fsm_resync |= 1;
1375 break;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001376
Willy Tarreauadfb8562008-08-11 15:24:42 +02001377 case SV_STCONN: /* should be changed to SV_STHEADERS or something more obvious */
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001378 /* stats initialized, but waiting for the command */
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001379 line = s->req->data;
1380 p = memchr(line, '\n', s->req->l);
1381
1382 if (!p)
1383 continue;
1384
1385 *p = '\0';
1386
1387 while (isspace((unsigned char)*line))
1388 line++;
1389
1390 arg = 0;
1391 args[arg] = line;
1392
1393 while (*line && arg < MAX_UXST_ARGS) {
1394 if (isspace((unsigned char)*line)) {
1395 *line++ = '\0';
1396
1397 while (isspace((unsigned char)*line))
1398 line++;
1399
1400 args[++arg] = line;
Willy Tarreaua8efd362008-01-03 10:19:15 +01001401 continue;
1402 }
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001403
1404 line++;
Willy Tarreaua8efd362008-01-03 10:19:15 +01001405 }
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001406
1407 while (++arg <= MAX_UXST_ARGS)
1408 args[arg] = line;
1409
1410 if (!strcmp(args[0], "show")) {
1411 if (!strcmp(args[1], "stat")) {
1412 if (*args[2] && *args[3] && *args[4]) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001413 s->data_ctx.stats.flags |= STAT_BOUND;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001414 s->data_ctx.stats.iid = atoi(args[2]);
1415 s->data_ctx.stats.type = atoi(args[3]);
1416 s->data_ctx.stats.sid = atoi(args[4]);
1417 }
1418
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001419 s->data_ctx.stats.flags |= STAT_SHOW_STAT;
1420 s->data_ctx.stats.flags |= STAT_FMT_CSV;
1421 s->srv_state = SV_STDATA;
1422 fsm_resync |= 1;
Willy Tarreau92fb9832007-10-16 17:34:28 +02001423 continue;
1424 }
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001425
1426 if (!strcmp(args[1], "info")) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001427 s->data_ctx.stats.flags |= STAT_SHOW_INFO;
1428 s->data_ctx.stats.flags |= STAT_FMT_CSV;
1429 s->srv_state = SV_STDATA;
1430 fsm_resync |= 1;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001431 continue;
1432 }
Willy Tarreau92fb9832007-10-16 17:34:28 +02001433 }
Willy Tarreau3e76e722007-10-17 18:57:38 +02001434
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001435 s->srv_state = SV_STCLOSE;
1436 fsm_resync |= 1;
Willy Tarreau3e76e722007-10-17 18:57:38 +02001437 continue;
1438
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001439 case SV_STDATA:
1440 /* OK we have to process the request. Since it is possible
1441 * that we get there with the client output paused, we
1442 * will simply check that we have really sent some data
1443 * and wake the client up if needed.
1444 */
1445 last_rep_l = s->rep->l;
1446 if (stats_dump_raw(s, NULL) != 0) {
1447 s->srv_state = SV_STCLOSE;
1448 fsm_resync |= 1;
1449 }
1450 if (s->rep->l != last_rep_l)
1451 fsm_resync |= 1;
1452 break;
Willy Tarreau3e76e722007-10-17 18:57:38 +02001453 }
Willy Tarreau92fb9832007-10-16 17:34:28 +02001454 } while (fsm_resync);
1455
1456 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
1457 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1458 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1459
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001460 t->expire = tick_first(tick_first(s->req->rex, s->req->wex),
1461 tick_first(s->rep->rex, s->rep->wex));
Willy Tarreau92fb9832007-10-16 17:34:28 +02001462
1463 /* restore t to its place in the task list */
1464 task_queue(t);
1465
1466 *next = t->expire;
1467 return; /* nothing more to do */
1468 }
1469
1470 actconn--;
1471 listener = fdtab[s->cli_fd].listener;
1472 if (listener) {
1473 listener->nbconn--;
1474 if (listener->state == LI_FULL &&
1475 listener->nbconn < listener->maxconn) {
1476 /* we should reactivate the listener */
1477 EV_FD_SET(listener->fd, DIR_RD);
1478 listener->state = LI_READY;
1479 }
1480 }
1481
1482 /* the task MUST not be in the run queue anymore */
1483 task_delete(t);
1484 session_free(s);
1485 task_free(t);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001486 *next = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +02001487}
1488
Willy Tarreau92fb9832007-10-16 17:34:28 +02001489__attribute__((constructor))
1490static void __uxst_protocol_init(void)
1491{
1492 protocol_register(&proto_unix);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001493}
1494
1495
1496/*
1497 * Local variables:
1498 * c-indent-level: 8
1499 * c-basic-offset: 8
1500 * End:
1501 */