blob: c4c3d379045932acb8ff9986b5b4d6cc41b890bb [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>
35#include <common/time.h>
36#include <common/version.h>
37
38#include <types/acl.h>
39#include <types/capture.h>
40#include <types/client.h>
41#include <types/global.h>
42#include <types/polling.h>
43#include <types/proxy.h>
44#include <types/server.h>
45
46#include <proto/acl.h>
47#include <proto/backend.h>
48#include <proto/buffers.h>
Willy Tarreau3e76e722007-10-17 18:57:38 +020049#include <proto/dumpstats.h>
Willy Tarreau92fb9832007-10-16 17:34:28 +020050#include <proto/fd.h>
51#include <proto/log.h>
52#include <proto/protocols.h>
53#include <proto/proto_uxst.h>
54#include <proto/queue.h>
Willy Tarreau3e76e722007-10-17 18:57:38 +020055#include <proto/senddata.h>
Willy Tarreau92fb9832007-10-16 17:34:28 +020056#include <proto/session.h>
57#include <proto/stream_sock.h>
58#include <proto/task.h>
59
60#ifndef MAXPATHLEN
61#define MAXPATHLEN 128
62#endif
63
Willy Tarreaudabf2e22007-10-28 21:59:24 +010064static int uxst_bind_listeners(struct protocol *proto);
65static int uxst_unbind_listeners(struct protocol *proto);
66
67/* Note: must not be declared <const> as its list will be overwritten */
68static struct protocol proto_unix = {
69 .name = "unix_stream",
70 .sock_domain = PF_UNIX,
71 .sock_type = SOCK_STREAM,
72 .sock_prot = 0,
73 .sock_family = AF_UNIX,
74 .sock_addrlen = sizeof(struct sockaddr_un),
75 .l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path),/* path len */
76 .read = &stream_sock_read,
77 .write = &stream_sock_write,
78 .bind_all = uxst_bind_listeners,
79 .unbind_all = uxst_unbind_listeners,
80 .enable_all = enable_all_listeners,
81 .disable_all = disable_all_listeners,
82 .listeners = LIST_HEAD_INIT(proto_unix.listeners),
83 .nb_listeners = 0,
84};
85
86
87/********************************
88 * 1) low-level socket functions
89 ********************************/
90
91
Willy Tarreau92fb9832007-10-16 17:34:28 +020092/* This function creates a named PF_UNIX stream socket at address <path>. Note
Willy Tarreaue6ad2b12007-10-18 12:45:54 +020093 * that the path cannot be NULL nor empty. <uid> and <gid> different of -1 will
94 * be used to change the socket owner. If <mode> is not 0, it will be used to
95 * restrict access to the socket. While it is known not to be portable on every
96 * OS, it's still useful where it works.
Willy Tarreau92fb9832007-10-16 17:34:28 +020097 * It returns the assigned file descriptor, or -1 in the event of an error.
98 */
Willy Tarreaue6ad2b12007-10-18 12:45:54 +020099static int create_uxst_socket(const char *path, uid_t uid, gid_t gid, mode_t mode)
Willy Tarreau92fb9832007-10-16 17:34:28 +0200100{
101 char tempname[MAXPATHLEN];
102 char backname[MAXPATHLEN];
103 struct sockaddr_un addr;
104
105 int ret, sock;
106
107 /* 1. create socket names */
108 if (!path[0]) {
109 Alert("Invalid name for a UNIX socket. Aborting.\n");
110 goto err_return;
111 }
112
113 ret = snprintf(tempname, MAXPATHLEN, "%s.%d.tmp", 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 ret = snprintf(backname, MAXPATHLEN, "%s.%d.bak", path, pid);
120 if (ret < 0 || ret >= MAXPATHLEN) {
121 Alert("name too long for UNIX socket. Aborting.\n");
122 goto err_return;
123 }
124
125 /* 2. clean existing orphaned entries */
126 if (unlink(tempname) < 0 && errno != ENOENT) {
127 Alert("error when trying to unlink previous UNIX socket. Aborting.\n");
128 goto err_return;
129 }
130
131 if (unlink(backname) < 0 && errno != ENOENT) {
132 Alert("error when trying to unlink previous UNIX socket. Aborting.\n");
133 goto err_return;
134 }
135
136 /* 3. backup existing socket */
137 if (link(path, backname) < 0 && errno != ENOENT) {
138 Alert("error when trying to preserve previous UNIX socket. Aborting.\n");
139 goto err_return;
140 }
141
142 /* 4. prepare new socket */
143 addr.sun_family = AF_UNIX;
144 strncpy(addr.sun_path, tempname, sizeof(addr.sun_path));
145 addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
146
147 sock = socket(PF_UNIX, SOCK_STREAM, 0);
148 if (sock < 0) {
149 Alert("cannot create socket for UNIX listener. Aborting.\n");
150 goto err_unlink_back;
151 }
152
153 if (sock >= global.maxsock) {
154 Alert("socket(): not enough free sockets for UNIX listener. Raise -n argument. Aborting.\n");
155 goto err_unlink_temp;
156 }
157
158 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
159 Alert("cannot make UNIX socket non-blocking. Aborting.\n");
160 goto err_unlink_temp;
161 }
162
163 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
164 /* note that bind() creates the socket <tempname> on the file system */
165 Alert("cannot bind socket for UNIX listener. Aborting.\n");
166 goto err_unlink_temp;
167 }
168
Willy Tarreaue6ad2b12007-10-18 12:45:54 +0200169 if (((uid != -1 || gid != -1) && (chown(tempname, uid, gid) == -1)) ||
170 (mode != 0 && chmod(tempname, mode) == -1)) {
171 Alert("cannot change UNIX socket ownership. Aborting.\n");
172 goto err_unlink_temp;
173 }
174
Willy Tarreau92fb9832007-10-16 17:34:28 +0200175 if (listen(sock, 0) < 0) {
176 Alert("cannot listen to socket for UNIX listener. Aborting.\n");
177 goto err_unlink_temp;
178 }
179
180 /* 5. install.
181 * Point of no return: we are ready, we'll switch the sockets. We don't
182 * fear loosing the socket <path> because we have a copy of it in
183 * backname.
184 */
185 if (rename(tempname, path) < 0) {
186 Alert("cannot switch final and temporary sockets for UNIX listener. Aborting.\n");
187 goto err_rename;
188 }
189
190 /* 6. cleanup */
191 unlink(backname); /* no need to keep this one either */
192
193 return sock;
194
195 err_rename:
196 ret = rename(backname, path);
197 if (ret < 0 && errno == ENOENT)
198 unlink(path);
199 err_unlink_temp:
200 unlink(tempname);
201 close(sock);
202 err_unlink_back:
203 unlink(backname);
204 err_return:
205 return -1;
206}
207
208/* Tries to destroy the UNIX stream socket <path>. The socket must not be used
209 * anymore. It practises best effort, and no error is returned.
210 */
211static void destroy_uxst_socket(const char *path)
212{
213 struct sockaddr_un addr;
214 int sock, ret;
215
216 /* We might have been chrooted, so we may not be able to access the
217 * socket. In order to avoid bothering the other end, we connect with a
218 * wrong protocol, namely SOCK_DGRAM. The return code from connect()
219 * is enough to know if the socket is still live or not. If it's live
220 * in mode SOCK_STREAM, we get EPROTOTYPE or anything else but not
221 * ECONNREFUSED. In this case, we do not touch it because it's used
222 * by some other process.
223 */
224 sock = socket(PF_UNIX, SOCK_DGRAM, 0);
225 if (sock < 0)
226 return;
227
228 addr.sun_family = AF_UNIX;
229 strncpy(addr.sun_path, path, sizeof(addr.sun_path));
Willy Tarreau10ae5482007-10-18 16:15:52 +0200230 addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200231 ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
232 if (ret < 0 && errno == ECONNREFUSED) {
233 /* Connect failed: the socket still exists but is not used
234 * anymore. Let's remove this socket now.
235 */
236 unlink(path);
237 }
238 close(sock);
239}
240
241
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100242/********************************
243 * 2) listener-oriented functions
244 ********************************/
245
246
247/* This function creates the UNIX socket associated to the listener. It changes
248 * the state from ASSIGNED to LISTEN. The socket is NOT enabled for polling.
249 * The return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL.
250 */
251static int uxst_bind_listener(struct listener *listener)
252{
253 int fd;
254
255 if (listener->state != LI_ASSIGNED)
256 return ERR_NONE; /* already bound */
257
258 fd = create_uxst_socket(((struct sockaddr_un *)&listener->addr)->sun_path,
259 listener->perm.ux.uid,
260 listener->perm.ux.gid,
261 listener->perm.ux.mode);
262 if (fd == -1)
263 return ERR_FATAL;
264
265 /* the socket is now listening */
266 listener->fd = fd;
267 listener->state = LI_LISTEN;
268
269 /* the function for the accept() event */
270 fd_insert(fd);
271 fdtab[fd].cb[DIR_RD].f = listener->accept;
272 fdtab[fd].cb[DIR_WR].f = NULL; /* never called */
273 fdtab[fd].cb[DIR_RD].b = fdtab[fd].cb[DIR_WR].b = NULL;
274 fdtab[fd].owner = (struct task *)listener; /* reference the listener instead of a task */
275 fdtab[fd].state = FD_STLISTEN;
276 fdtab[fd].peeraddr = NULL;
277 fdtab[fd].peerlen = 0;
278 fdtab[fd].listener = NULL;
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100279 return ERR_NONE;
280}
281
282/* This function closes the UNIX sockets for the specified listener.
283 * The listener enters the LI_ASSIGNED state. It always returns ERR_NONE.
284 */
285static int uxst_unbind_listener(struct listener *listener)
286{
287 if (listener->state == LI_READY)
288 EV_FD_CLR(listener->fd, DIR_RD);
289
290 if (listener->state >= LI_LISTEN) {
Willy Tarreau8eebe5e2007-10-28 22:07:08 +0100291 fd_delete(listener->fd);
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100292 listener->state = LI_ASSIGNED;
293 destroy_uxst_socket(((struct sockaddr_un *)&listener->addr)->sun_path);
294 }
295 return ERR_NONE;
296}
297
298/* Add a listener to the list of unix stream listeners. The listener's state
299 * is automatically updated from LI_INIT to LI_ASSIGNED. The number of
300 * listeners is updated. This is the function to use to add a new listener.
301 */
302void uxst_add_listener(struct listener *listener)
303{
304 if (listener->state != LI_INIT)
305 return;
306 listener->state = LI_ASSIGNED;
307 listener->proto = &proto_unix;
308 LIST_ADDQ(&proto_unix.listeners, &listener->proto_list);
309 proto_unix.nb_listeners++;
310}
311
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100312/********************************
313 * 3) protocol-oriented functions
314 ********************************/
315
316
Willy Tarreau92fb9832007-10-16 17:34:28 +0200317/* This function creates all UNIX sockets bound to the protocol entry <proto>.
318 * It is intended to be used as the protocol's bind_all() function.
319 * The sockets will be registered but not added to any fd_set, in order not to
320 * loose them across the fork(). A call to uxst_enable_listeners() is needed
321 * to complete initialization.
322 *
323 * The return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL.
324 */
325static int uxst_bind_listeners(struct protocol *proto)
326{
327 struct listener *listener;
328 int err = ERR_NONE;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200329
330 list_for_each_entry(listener, &proto->listeners, proto_list) {
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100331 err |= uxst_bind_listener(listener);
332 if (err != ERR_NONE)
Willy Tarreau92fb9832007-10-16 17:34:28 +0200333 continue;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200334 }
Willy Tarreau92fb9832007-10-16 17:34:28 +0200335 return err;
336}
337
Willy Tarreau92fb9832007-10-16 17:34:28 +0200338
339/* This function stops all listening UNIX sockets bound to the protocol
340 * <proto>. It does not detaches them from the protocol.
341 * It always returns ERR_NONE.
342 */
343static int uxst_unbind_listeners(struct protocol *proto)
344{
345 struct listener *listener;
346
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100347 list_for_each_entry(listener, &proto->listeners, proto_list)
348 uxst_unbind_listener(listener);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200349 return ERR_NONE;
350}
351
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100352
353/********************************
354 * 4) high-level functions
355 ********************************/
356
357
Willy Tarreau92fb9832007-10-16 17:34:28 +0200358/*
359 * This function is called on a read event from a listen socket, corresponding
360 * to an accept. It tries to accept as many connections as possible.
361 * It returns 0. Since we use UNIX sockets on the local system for monitoring
362 * purposes and other related things, we do not need to output as many messages
363 * as with TCP which can fall under attack.
364 */
365int uxst_event_accept(int fd) {
366 struct listener *l = (struct listener *)fdtab[fd].owner;
367 struct session *s;
368 struct task *t;
369 int cfd;
370 int max_accept;
371
372 if (global.nbproc > 1)
373 max_accept = 8; /* let other processes catch some connections too */
374 else
375 max_accept = -1;
376
377 while (max_accept--) {
378 struct sockaddr_storage addr;
379 socklen_t laddr = sizeof(addr);
380
381 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
382 switch (errno) {
383 case EAGAIN:
384 case EINTR:
385 case ECONNABORTED:
386 return 0; /* nothing more to accept */
387 case ENFILE:
388 /* Process reached system FD limit. Check system tunables. */
389 return 0;
390 case EMFILE:
391 /* Process reached process FD limit. Check 'ulimit-n'. */
392 return 0;
393 case ENOBUFS:
394 case ENOMEM:
395 /* Process reached system memory limit. Check system tunables. */
396 return 0;
397 default:
398 return 0;
399 }
400 }
401
402 if (l->nbconn >= l->maxconn) {
403 /* too many connections, we shoot this one and return.
404 * FIXME: it would be better to simply switch the listener's
405 * state to LI_FULL and disable the FD. We could re-enable
406 * it upon fd_delete(), but this requires all protocols to
407 * be switched.
408 */
409 close(cfd);
410 return 0;
411 }
412
413 if ((s = pool_alloc2(pool2_session)) == NULL) {
414 Alert("out of memory in uxst_event_accept().\n");
415 close(cfd);
416 return 0;
417 }
418
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +0100419 s->flags = 0;
420
Willy Tarreau92fb9832007-10-16 17:34:28 +0200421 if ((t = pool_alloc2(pool2_task)) == NULL) {
422 Alert("out of memory in uxst_event_accept().\n");
423 close(cfd);
424 pool_free2(pool2_session, s);
425 return 0;
426 }
427
428 s->cli_addr = addr;
429
430 /* FIXME: should be checked earlier */
431 if (cfd >= global.maxsock) {
432 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
433 close(cfd);
434 pool_free2(pool2_task, t);
435 pool_free2(pool2_session, s);
436 return 0;
437 }
438
439 if (fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) {
440 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
441 close(cfd);
442 pool_free2(pool2_task, t);
443 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;
450
451 s->task = t;
452 s->fe = NULL;
453 s->be = NULL;
454
455 s->cli_state = CL_STDATA;
456 s->srv_state = SV_STIDLE;
457 s->req = s->rep = NULL; /* will be allocated later */
458
459 s->cli_fd = cfd;
460 s->srv_fd = -1;
461 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);
474 pool_free2(pool2_session, s);
475 return 0;
476 }
477
478 if ((s->rep = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */
479 pool_free2(pool2_buffer, s->req);
480 close(cfd); /* nothing can be done for this fd without memory */
481 pool_free2(pool2_task, t);
482 pool_free2(pool2_session, s);
483 return 0;
484 }
485
486 buffer_init(s->req);
487 buffer_init(s->rep);
488 s->req->rlim += BUFSIZE;
489 s->rep->rlim += BUFSIZE;
490
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
502 tv_eternity(&s->req->rex);
503 tv_eternity(&s->req->wex);
504 tv_eternity(&s->req->cex);
505 tv_eternity(&s->rep->rex);
506 tv_eternity(&s->rep->wex);
507
508 tv_eternity(&s->req->wto);
509 tv_eternity(&s->req->cto);
510 tv_eternity(&s->req->rto);
511 tv_eternity(&s->rep->rto);
512 tv_eternity(&s->rep->cto);
513 tv_eternity(&s->rep->wto);
514
515 if (l->timeout)
516 s->req->rto = *l->timeout;
517
518 if (l->timeout)
519 s->rep->wto = *l->timeout;
520
521 tv_eternity(&t->expire);
522 if (l->timeout && tv_isset(l->timeout)) {
523 EV_FD_SET(cfd, DIR_RD);
524 tv_add(&s->req->rex, &now, &s->req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200525 t->expire = s->req->rex;
526 }
527
Willy Tarreau92fb9832007-10-16 17:34:28 +0200528 task_wakeup(t);
529
530 l->nbconn++; /* warning! right now, it's up to the handler to decrease this */
531 if (l->nbconn >= l->maxconn) {
532 EV_FD_CLR(l->fd, DIR_RD);
533 l->state = LI_FULL;
534 }
535 actconn++;
536 totalconn++;
537
538 //fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p, cfd=%d, maxfd=%d\n", p, actconn, totalconn, t, cfd, maxfd);
539 } /* end of while (p->feconn < p->maxconn) */
540 //fprintf(stderr,"fct %s:%d\n", __FUNCTION__, __LINE__);
541 return 0;
542}
543
544/*
545 * manages the client FSM and its socket. It returns 1 if a state has changed
546 * (and a resync may be needed), otherwise 0.
547 */
548static int process_uxst_cli(struct session *t)
549{
550 int s = t->srv_state;
551 int c = t->cli_state;
552 struct buffer *req = t->req;
553 struct buffer *rep = t->rep;
554 //fprintf(stderr,"fct %s:%d\n", __FUNCTION__, __LINE__);
555 if (c == CL_STDATA) {
556 /* FIXME: this error handling is partly buggy because we always report
557 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
558 * or HEADER phase. BTW, it's not logical to expire the client while
559 * we're waiting for the server to connect.
560 */
561 /* read or write error */
562 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
563 buffer_shutr(req);
564 buffer_shutw(rep);
565 fd_delete(t->cli_fd);
566 t->cli_state = CL_STCLOSE;
567 if (!(t->flags & SN_ERR_MASK))
568 t->flags |= SN_ERR_CLICL;
569 if (!(t->flags & SN_FINST_MASK)) {
570 if (t->pend_pos)
571 t->flags |= SN_FINST_Q;
572 else if (s == SV_STCONN)
573 t->flags |= SN_FINST_C;
574 else
575 t->flags |= SN_FINST_D;
576 }
577 return 1;
578 }
579 /* last read, or end of server write */
580 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
581 EV_FD_CLR(t->cli_fd, DIR_RD);
582 buffer_shutr(req);
583 t->cli_state = CL_STSHUTR;
584 return 1;
585 }
586 /* last server read and buffer empty */
587 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
588 EV_FD_CLR(t->cli_fd, DIR_WR);
589 buffer_shutw(rep);
590 shutdown(t->cli_fd, SHUT_WR);
591 /* We must ensure that the read part is still alive when switching
592 * to shutw */
593 EV_FD_SET(t->cli_fd, DIR_RD);
594 tv_add_ifset(&req->rex, &now, &req->rto);
595 t->cli_state = CL_STSHUTW;
596 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
597 return 1;
598 }
599 /* read timeout */
600 else if (tv_isle(&req->rex, &now)) {
601 EV_FD_CLR(t->cli_fd, DIR_RD);
602 buffer_shutr(req);
603 t->cli_state = CL_STSHUTR;
604 if (!(t->flags & SN_ERR_MASK))
605 t->flags |= SN_ERR_CLITO;
606 if (!(t->flags & SN_FINST_MASK)) {
607 if (t->pend_pos)
608 t->flags |= SN_FINST_Q;
609 else if (s == SV_STCONN)
610 t->flags |= SN_FINST_C;
611 else
612 t->flags |= SN_FINST_D;
613 }
614 return 1;
615 }
616 /* write timeout */
617 else if (tv_isle(&rep->wex, &now)) {
618 EV_FD_CLR(t->cli_fd, DIR_WR);
619 buffer_shutw(rep);
620 shutdown(t->cli_fd, SHUT_WR);
621 /* We must ensure that the read part is still alive when switching
622 * to shutw */
623 EV_FD_SET(t->cli_fd, DIR_RD);
624 tv_add_ifset(&req->rex, &now, &req->rto);
625
626 t->cli_state = CL_STSHUTW;
627 if (!(t->flags & SN_ERR_MASK))
628 t->flags |= SN_ERR_CLITO;
629 if (!(t->flags & SN_FINST_MASK)) {
630 if (t->pend_pos)
631 t->flags |= SN_FINST_Q;
632 else if (s == SV_STCONN)
633 t->flags |= SN_FINST_C;
634 else
635 t->flags |= SN_FINST_D;
636 }
637 return 1;
638 }
639
640 if (req->l >= req->rlim - req->data) {
641 /* no room to read more data */
642 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
643 /* stop reading until we get some space */
644 tv_eternity(&req->rex);
645 }
646 } else {
647 /* there's still some space in the buffer */
648 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
649 if (!tv_isset(&req->rto) ||
650 (t->srv_state < SV_STDATA && tv_isset(&req->wto)))
651 /* If the client has no timeout, or if the server not ready yet, and we
652 * know for sure that it can expire, then it's cleaner to disable the
653 * timeout on the client side so that too low values cannot make the
654 * sessions abort too early.
655 */
656 tv_eternity(&req->rex);
657 else
658 tv_add(&req->rex, &now, &req->rto);
659 }
660 }
661
662 if ((rep->l == 0) ||
663 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
664 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
665 /* stop writing */
666 tv_eternity(&rep->wex);
667 }
668 } else {
669 /* buffer not empty */
670 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
671 /* restart writing */
672 if (tv_add_ifset(&rep->wex, &now, &rep->wto)) {
673 /* FIXME: to prevent the client from expiring read timeouts during writes,
674 * we refresh it. */
675 req->rex = rep->wex;
676 }
677 else
678 tv_eternity(&rep->wex);
679 }
680 }
681 return 0; /* other cases change nothing */
682 }
683 else if (c == CL_STSHUTR) {
684 if (rep->flags & BF_WRITE_ERROR) {
685 buffer_shutw(rep);
686 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 }
700 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
701 buffer_shutw(rep);
702 fd_delete(t->cli_fd);
703 t->cli_state = CL_STCLOSE;
704 return 1;
705 }
706 else if (tv_isle(&rep->wex, &now)) {
707 buffer_shutw(rep);
708 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
723 if (rep->l == 0) {
724 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
725 /* stop writing */
726 tv_eternity(&rep->wex);
727 }
728 } else {
729 /* buffer not empty */
730 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
731 /* restart writing */
732 if (!tv_add_ifset(&rep->wex, &now, &rep->wto))
733 tv_eternity(&rep->wex);
734 }
735 }
736 return 0;
737 }
738 else if (c == CL_STSHUTW) {
739 if (req->flags & BF_READ_ERROR) {
740 buffer_shutr(req);
741 fd_delete(t->cli_fd);
742 t->cli_state = CL_STCLOSE;
743 if (!(t->flags & SN_ERR_MASK))
744 t->flags |= SN_ERR_CLICL;
745 if (!(t->flags & SN_FINST_MASK)) {
746 if (t->pend_pos)
747 t->flags |= SN_FINST_Q;
748 else if (s == SV_STCONN)
749 t->flags |= SN_FINST_C;
750 else
751 t->flags |= SN_FINST_D;
752 }
753 return 1;
754 }
755 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
756 buffer_shutr(req);
757 fd_delete(t->cli_fd);
758 t->cli_state = CL_STCLOSE;
759 return 1;
760 }
761 else if (tv_isle(&req->rex, &now)) {
762 buffer_shutr(req);
763 fd_delete(t->cli_fd);
764 t->cli_state = CL_STCLOSE;
765 if (!(t->flags & SN_ERR_MASK))
766 t->flags |= SN_ERR_CLITO;
767 if (!(t->flags & SN_FINST_MASK)) {
768 if (t->pend_pos)
769 t->flags |= SN_FINST_Q;
770 else if (s == SV_STCONN)
771 t->flags |= SN_FINST_C;
772 else
773 t->flags |= SN_FINST_D;
774 }
775 return 1;
776 }
777 else if (req->l >= req->rlim - req->data) {
778 /* no room to read more data */
779
780 /* FIXME-20050705: is it possible for a client to maintain a session
781 * after the timeout by sending more data after it receives a close ?
782 */
783
784 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
785 /* stop reading until we get some space */
786 tv_eternity(&req->rex);
787 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
788 }
789 } else {
790 /* there's still some space in the buffer */
791 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
792 if (!tv_add_ifset(&req->rex, &now, &req->rto))
793 tv_eternity(&req->rex);
794 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
795 }
796 }
797 return 0;
798 }
799 else { /* CL_STCLOSE: nothing to do */
800 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
801 int len;
802 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be?t->be->id:"",
803 (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
804 write(1, trash, len);
805 }
806 return 0;
807 }
808 return 0;
809}
810
811#if 0
812 /* FIXME! This part has not been completely converted yet, and it may
813 * still be very specific to TCPv4 ! Also, it relies on some parameters
814 * such as conn_retries which are not set upon accept().
815 */
816/*
817 * Manages the server FSM and its socket. It returns 1 if a state has changed
818 * (and a resync may be needed), otherwise 0.
819 */
820static int process_uxst_srv(struct session *t)
821{
822 int s = t->srv_state;
823 int c = t->cli_state;
824 struct buffer *req = t->req;
825 struct buffer *rep = t->rep;
826 int conn_err;
827
828 if (s == SV_STIDLE) {
829 if (c == CL_STCLOSE || c == CL_STSHUTW ||
830 (c == CL_STSHUTR &&
831 (t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
832 tv_eternity(&req->cex);
833 if (t->pend_pos)
834 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
835 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C);
836 return 1;
837 }
838 else {
839 /* FIXME: reimplement the TARPIT check here */
840
841 /* Right now, we will need to create a connection to the server.
842 * We might already have tried, and got a connection pending, in
843 * which case we will not do anything till it's pending. It's up
844 * to any other session to release it and wake us up again.
845 */
846 if (t->pend_pos) {
847 if (!tv_isle(&req->cex, &now))
848 return 0;
849 else {
850 /* we've been waiting too long here */
851 tv_eternity(&req->cex);
852 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
853 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q);
854 if (t->srv)
855 t->srv->failed_conns++;
856 if (t->fe)
857 t->fe->failed_conns++;
858 return 1;
859 }
860 }
861
862 do {
863 /* first, get a connection */
864 if (srv_redispatch_connect(t))
865 return t->srv_state != SV_STIDLE;
866
867 /* try to (re-)connect to the server, and fail if we expire the
868 * number of retries.
869 */
870 if (srv_retryable_connect(t)) {
871 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
872 return t->srv_state != SV_STIDLE;
873 }
874 } while (1);
875 }
876 }
877 else if (s == SV_STCONN) { /* connection in progress */
878 if (c == CL_STCLOSE || c == CL_STSHUTW ||
879 (c == CL_STSHUTR &&
880 ((t->req->l == 0 && !(req->flags & BF_WRITE_STATUS)) ||
881 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
882 tv_eternity(&req->cex);
883 fd_delete(t->srv_fd);
884 if (t->srv)
885 t->srv->cur_sess--;
886
887 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C);
888 return 1;
889 }
890 if (!(req->flags & BF_WRITE_STATUS) && !tv_isle(&req->cex, &now)) {
891 //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);
892 return 0; /* nothing changed */
893 }
894 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
895 /* timeout, asynchronous connect error or first write error */
896 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
897
898 fd_delete(t->srv_fd);
899 if (t->srv)
900 t->srv->cur_sess--;
901
902 if (!(req->flags & BF_WRITE_STATUS))
903 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
904 else
905 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
906
907 /* ensure that we have enough retries left */
908 if (srv_count_retry_down(t, conn_err))
909 return 1;
910
911 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
912 /* We're on our last chance, and the REDISP option was specified.
913 * We will ignore cookie and force to balance or use the dispatcher.
914 */
915 /* let's try to offer this slot to anybody */
916 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +0200917 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200918
919 if (t->srv)
920 t->srv->failed_conns++;
921 t->be->failed_conns++;
922
923 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
924 t->srv = NULL; /* it's left to the dispatcher to choose a server */
925
926 /* first, get a connection */
927 if (srv_redispatch_connect(t))
928 return t->srv_state != SV_STIDLE;
929 }
930
931 do {
932 /* Now we will try to either reconnect to the same server or
933 * connect to another server. If the connection gets queued
934 * because all servers are saturated, then we will go back to
935 * the SV_STIDLE state.
936 */
937 if (srv_retryable_connect(t)) {
938 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
939 return t->srv_state != SV_STCONN;
940 }
941
942 /* we need to redispatch the connection to another server */
943 if (srv_redispatch_connect(t))
944 return t->srv_state != SV_STCONN;
945 } while (1);
946 }
947 else { /* no error or write 0 */
948 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
949
950 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
951 if (req->l == 0) /* nothing to write */ {
952 EV_FD_CLR(t->srv_fd, DIR_WR);
953 tv_eternity(&req->wex);
954 } else /* need the right to write */ {
955 EV_FD_SET(t->srv_fd, DIR_WR);
956 if (tv_add_ifset(&req->wex, &now, &req->wto)) {
957 /* FIXME: to prevent the server from expiring read timeouts during writes,
958 * we refresh it. */
959 rep->rex = req->wex;
960 }
961 else
962 tv_eternity(&req->wex);
963 }
964
965 EV_FD_SET(t->srv_fd, DIR_RD);
966 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
967 tv_eternity(&rep->rex);
968
969 t->srv_state = SV_STDATA;
970 if (t->srv)
971 t->srv->cum_sess++;
972 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
973
974 /* if the user wants to log as soon as possible, without counting
975 bytes from the server, then this is the right moment. */
976 if (t->fe && t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
977 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
978 //uxst_sess_log(t);
979 }
980 tv_eternity(&req->cex);
981 return 1;
982 }
983 }
984 else if (s == SV_STDATA) {
985 /* read or write error */
986 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
987 buffer_shutr(rep);
988 buffer_shutw(req);
989 fd_delete(t->srv_fd);
990 if (t->srv) {
991 t->srv->cur_sess--;
992 t->srv->failed_resp++;
993 }
994 t->be->failed_resp++;
995 t->srv_state = SV_STCLOSE;
996 if (!(t->flags & SN_ERR_MASK))
997 t->flags |= SN_ERR_SRVCL;
998 if (!(t->flags & SN_FINST_MASK))
999 t->flags |= SN_FINST_D;
1000 /* We used to have a free connection slot. Since we'll never use it,
1001 * we have to inform the server that it may be used by another session.
1002 */
1003 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001004 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001005
1006 return 1;
1007 }
1008 /* last read, or end of client write */
1009 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
1010 EV_FD_CLR(t->srv_fd, DIR_RD);
1011 buffer_shutr(rep);
1012 t->srv_state = SV_STSHUTR;
1013 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1014 return 1;
1015 }
1016 /* end of client read and no more data to send */
1017 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
1018 EV_FD_CLR(t->srv_fd, DIR_WR);
1019 buffer_shutw(req);
1020 shutdown(t->srv_fd, SHUT_WR);
1021 /* We must ensure that the read part is still alive when switching
1022 * to shutw */
1023 EV_FD_SET(t->srv_fd, DIR_RD);
1024 tv_add_ifset(&rep->rex, &now, &rep->rto);
1025
1026 t->srv_state = SV_STSHUTW;
1027 return 1;
1028 }
1029 /* read timeout */
1030 else if (tv_isle(&rep->rex, &now)) {
1031 EV_FD_CLR(t->srv_fd, DIR_RD);
1032 buffer_shutr(rep);
1033 t->srv_state = SV_STSHUTR;
1034 if (!(t->flags & SN_ERR_MASK))
1035 t->flags |= SN_ERR_SRVTO;
1036 if (!(t->flags & SN_FINST_MASK))
1037 t->flags |= SN_FINST_D;
1038 return 1;
1039 }
1040 /* write timeout */
1041 else if (tv_isle(&req->wex, &now)) {
1042 EV_FD_CLR(t->srv_fd, DIR_WR);
1043 buffer_shutw(req);
1044 shutdown(t->srv_fd, SHUT_WR);
1045 /* We must ensure that the read part is still alive when switching
1046 * to shutw */
1047 EV_FD_SET(t->srv_fd, DIR_RD);
1048 tv_add_ifset(&rep->rex, &now, &rep->rto);
1049 t->srv_state = SV_STSHUTW;
1050 if (!(t->flags & SN_ERR_MASK))
1051 t->flags |= SN_ERR_SRVTO;
1052 if (!(t->flags & SN_FINST_MASK))
1053 t->flags |= SN_FINST_D;
1054 return 1;
1055 }
1056
1057 /* recompute request time-outs */
1058 if (req->l == 0) {
1059 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
1060 /* stop writing */
1061 tv_eternity(&req->wex);
1062 }
1063 }
1064 else { /* buffer not empty, there are still data to be transferred */
1065 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
1066 /* restart writing */
1067 if (tv_add_ifset(&req->wex, &now, &req->wto)) {
1068 /* FIXME: to prevent the server from expiring read timeouts during writes,
1069 * we refresh it. */
1070 rep->rex = req->wex;
1071 }
1072 else
1073 tv_eternity(&req->wex);
1074 }
1075 }
1076
1077 /* recompute response time-outs */
1078 if (rep->l == BUFSIZE) { /* no room to read more data */
1079 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
1080 tv_eternity(&rep->rex);
1081 }
1082 }
1083 else {
1084 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
1085 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
1086 tv_eternity(&rep->rex);
1087 }
1088 }
1089
1090 return 0; /* other cases change nothing */
1091 }
1092 else if (s == SV_STSHUTR) {
1093 if (req->flags & BF_WRITE_ERROR) {
1094 //EV_FD_CLR(t->srv_fd, DIR_WR);
1095 buffer_shutw(req);
1096 fd_delete(t->srv_fd);
1097 if (t->srv) {
1098 t->srv->cur_sess--;
1099 t->srv->failed_resp++;
1100 }
1101 t->be->failed_resp++;
1102 //close(t->srv_fd);
1103 t->srv_state = SV_STCLOSE;
1104 if (!(t->flags & SN_ERR_MASK))
1105 t->flags |= SN_ERR_SRVCL;
1106 if (!(t->flags & SN_FINST_MASK))
1107 t->flags |= SN_FINST_D;
1108 /* We used to have a free connection slot. Since we'll never use it,
1109 * we have to inform the server that it may be used by another session.
1110 */
1111 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001112 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001113
1114 return 1;
1115 }
1116 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
1117 //EV_FD_CLR(t->srv_fd, DIR_WR);
1118 buffer_shutw(req);
1119 fd_delete(t->srv_fd);
1120 if (t->srv)
1121 t->srv->cur_sess--;
1122 //close(t->srv_fd);
1123 t->srv_state = SV_STCLOSE;
1124 /* We used to have a free connection slot. Since we'll never use it,
1125 * we have to inform the server that it may be used by another session.
1126 */
1127 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001128 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001129
1130 return 1;
1131 }
1132 else if (tv_isle(&req->wex, &now)) {
1133 //EV_FD_CLR(t->srv_fd, DIR_WR);
1134 buffer_shutw(req);
1135 fd_delete(t->srv_fd);
1136 if (t->srv)
1137 t->srv->cur_sess--;
1138 //close(t->srv_fd);
1139 t->srv_state = SV_STCLOSE;
1140 if (!(t->flags & SN_ERR_MASK))
1141 t->flags |= SN_ERR_SRVTO;
1142 if (!(t->flags & SN_FINST_MASK))
1143 t->flags |= SN_FINST_D;
1144 /* We used to have a free connection slot. Since we'll never use it,
1145 * we have to inform the server that it may be used by another session.
1146 */
1147 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001148 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001149
1150 return 1;
1151 }
1152 else if (req->l == 0) {
1153 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
1154 /* stop writing */
1155 tv_eternity(&req->wex);
1156 }
1157 }
1158 else { /* buffer not empty */
1159 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
1160 /* restart writing */
1161 if (!tv_add_ifset(&req->wex, &now, &req->wto))
1162 tv_eternity(&req->wex);
1163 }
1164 }
1165 return 0;
1166 }
1167 else if (s == SV_STSHUTW) {
1168 if (rep->flags & BF_READ_ERROR) {
1169 //EV_FD_CLR(t->srv_fd, DIR_RD);
1170 buffer_shutr(rep);
1171 fd_delete(t->srv_fd);
1172 if (t->srv) {
1173 t->srv->cur_sess--;
1174 t->srv->failed_resp++;
1175 }
1176 t->be->failed_resp++;
1177 //close(t->srv_fd);
1178 t->srv_state = SV_STCLOSE;
1179 if (!(t->flags & SN_ERR_MASK))
1180 t->flags |= SN_ERR_SRVCL;
1181 if (!(t->flags & SN_FINST_MASK))
1182 t->flags |= SN_FINST_D;
1183 /* We used to have a free connection slot. Since we'll never use it,
1184 * we have to inform the server that it may be used by another session.
1185 */
1186 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001187 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001188
1189 return 1;
1190 }
1191 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
1192 //EV_FD_CLR(t->srv_fd, DIR_RD);
1193 buffer_shutr(rep);
1194 fd_delete(t->srv_fd);
1195 if (t->srv)
1196 t->srv->cur_sess--;
1197 //close(t->srv_fd);
1198 t->srv_state = SV_STCLOSE;
1199 /* We used to have a free connection slot. Since we'll never use it,
1200 * we have to inform the server that it may be used by another session.
1201 */
1202 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001203 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001204
1205 return 1;
1206 }
1207 else if (tv_isle(&rep->rex, &now)) {
1208 //EV_FD_CLR(t->srv_fd, DIR_RD);
1209 buffer_shutr(rep);
1210 fd_delete(t->srv_fd);
1211 if (t->srv)
1212 t->srv->cur_sess--;
1213 //close(t->srv_fd);
1214 t->srv_state = SV_STCLOSE;
1215 if (!(t->flags & SN_ERR_MASK))
1216 t->flags |= SN_ERR_SRVTO;
1217 if (!(t->flags & SN_FINST_MASK))
1218 t->flags |= SN_FINST_D;
1219 /* We used to have a free connection slot. Since we'll never use it,
1220 * we have to inform the server that it may be used by another session.
1221 */
1222 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001223 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001224
1225 return 1;
1226 }
1227 else if (rep->l == BUFSIZE) { /* no room to read more data */
1228 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
1229 tv_eternity(&rep->rex);
1230 }
1231 }
1232 else {
1233 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
1234 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
1235 tv_eternity(&rep->rex);
1236 }
1237 }
1238 return 0;
1239 }
1240 else { /* SV_STCLOSE : nothing to do */
1241 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1242 int len;
1243 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
1244 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1245 write(1, trash, len);
1246 }
1247 return 0;
1248 }
1249 return 0;
1250}
1251
1252/* Processes the client and server jobs of a session task, then
1253 * puts it back to the wait queue in a clean state, or
1254 * cleans up its resources if it must be deleted. Returns
1255 * the time the task accepts to wait, or TIME_ETERNITY for
1256 * infinity.
1257 */
1258void process_uxst_session(struct task *t, struct timeval *next)
1259{
1260 struct session *s = t->context;
1261 int fsm_resync = 0;
1262
1263 do {
1264 fsm_resync = 0;
1265 fsm_resync |= process_uxst_cli(s);
1266 if (s->srv_state == SV_STIDLE) {
1267 if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) {
1268 s->srv_state = SV_STCLOSE;
1269 fsm_resync |= 1;
1270 continue;
1271 }
1272 if (s->cli_state == CL_STSHUTR ||
1273 (s->req->l >= s->req->rlim - s->req->data)) {
1274 if (s->req->l == 0) {
1275 s->srv_state = SV_STCLOSE;
1276 fsm_resync |= 1;
1277 continue;
1278 }
1279 /* OK we have some remaining data to process */
1280 /* Just as an exercice, we copy the req into the resp,
1281 * and flush the req.
1282 */
1283 memcpy(s->rep->data, s->req->data, sizeof(s->rep->data));
1284 s->rep->l = s->req->l;
1285 s->rep->rlim = s->rep->data + BUFSIZE;
1286 s->rep->w = s->rep->data;
1287 s->rep->lr = s->rep->r = s->rep->data + s->rep->l;
1288
1289 s->req->l = 0;
1290 s->srv_state = SV_STCLOSE;
1291
1292 fsm_resync |= 1;
1293 continue;
1294 }
1295 }
1296 } while (fsm_resync);
1297
1298 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +01001299
1300 if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
1301 session_process_counters(s);
1302
Willy Tarreau92fb9832007-10-16 17:34:28 +02001303 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1304 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1305
1306 t->expire = s->req->rex;
1307 tv_min(&t->expire, &s->req->rex, &s->req->wex);
1308 tv_bound(&t->expire, &s->req->cex);
1309 tv_bound(&t->expire, &s->rep->rex);
1310 tv_bound(&t->expire, &s->rep->wex);
1311
1312 /* restore t to its place in the task list */
1313 task_queue(t);
1314
1315 *next = t->expire;
1316 return; /* nothing more to do */
1317 }
1318
1319 if (s->fe)
1320 s->fe->feconn--;
1321 if (s->be && (s->flags & SN_BE_ASSIGNED))
1322 s->be->beconn--;
1323 actconn--;
1324
1325 if (unlikely((global.mode & MODE_DEBUG) &&
1326 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
1327 int len;
1328 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
1329 s->uniq_id, s->be->id,
1330 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
1331 write(1, trash, len);
1332 }
1333
1334 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +01001335 session_process_counters(s);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001336
1337 /* let's do a final log if we need it */
1338 if (s->logs.logwait &&
1339 !(s->flags & SN_MONITOR) &&
1340 (s->req->total || !(s->fe && s->fe->options & PR_O_NULLNOLOG))) {
1341 //uxst_sess_log(s);
1342 }
1343
1344 /* the task MUST not be in the run queue anymore */
1345 task_delete(t);
1346 session_free(s);
1347 task_free(t);
1348 tv_eternity(next);
1349}
1350#endif /* not converted */
1351
1352
1353/* Processes data exchanges on the statistics socket. The client processing
1354 * is called and the task is put back in the wait queue or it is cleared.
1355 * In order to ease the transition, we simply simulate the server status
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001356 * for now. It only knows states SV_STIDLE, SV_STCONN, SV_STDATA, and
1357 * SV_STCLOSE. Returns in <next> the task's expiration date.
Willy Tarreau92fb9832007-10-16 17:34:28 +02001358 */
1359void process_uxst_stats(struct task *t, struct timeval *next)
1360{
1361 struct session *s = t->context;
1362 struct listener *listener;
1363 int fsm_resync = 0;
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001364 int last_rep_l;
Willy Tarreau92fb9832007-10-16 17:34:28 +02001365
1366 do {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001367 char *args[MAX_UXST_ARGS + 1];
1368 char *line, *p;
1369 int arg;
1370
Willy Tarreau3e76e722007-10-17 18:57:38 +02001371 fsm_resync = process_uxst_cli(s);
Willy Tarreau3e76e722007-10-17 18:57:38 +02001372
1373 if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) {
1374 s->srv_state = SV_STCLOSE;
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001375 break;
Willy Tarreau3e76e722007-10-17 18:57:38 +02001376 }
1377
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001378 switch (s->srv_state) {
1379 case SV_STIDLE:
1380 /* stats output not initialized yet */
1381 memset(&s->data_ctx.stats, 0, sizeof(s->data_ctx.stats));
1382 s->data_source = DATA_SRC_STATS;
1383 s->srv_state = SV_STCONN;
1384 fsm_resync |= 1;
1385 break;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001386
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001387 case SV_STCONN: /* will change to SV_STANALYZE */
1388 /* stats initialized, but waiting for the command */
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001389 line = s->req->data;
1390 p = memchr(line, '\n', s->req->l);
1391
1392 if (!p)
1393 continue;
1394
1395 *p = '\0';
1396
1397 while (isspace((unsigned char)*line))
1398 line++;
1399
1400 arg = 0;
1401 args[arg] = line;
1402
1403 while (*line && arg < MAX_UXST_ARGS) {
1404 if (isspace((unsigned char)*line)) {
1405 *line++ = '\0';
1406
1407 while (isspace((unsigned char)*line))
1408 line++;
1409
1410 args[++arg] = line;
Willy Tarreaua8efd362008-01-03 10:19:15 +01001411 continue;
1412 }
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001413
1414 line++;
Willy Tarreaua8efd362008-01-03 10:19:15 +01001415 }
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001416
1417 while (++arg <= MAX_UXST_ARGS)
1418 args[arg] = line;
1419
1420 if (!strcmp(args[0], "show")) {
1421 if (!strcmp(args[1], "stat")) {
1422 if (*args[2] && *args[3] && *args[4]) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001423 s->data_ctx.stats.flags |= STAT_BOUND;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001424 s->data_ctx.stats.iid = atoi(args[2]);
1425 s->data_ctx.stats.type = atoi(args[3]);
1426 s->data_ctx.stats.sid = atoi(args[4]);
1427 }
1428
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001429 s->data_ctx.stats.flags |= STAT_SHOW_STAT;
1430 s->data_ctx.stats.flags |= STAT_FMT_CSV;
1431 s->srv_state = SV_STDATA;
1432 fsm_resync |= 1;
Willy Tarreau92fb9832007-10-16 17:34:28 +02001433 continue;
1434 }
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001435
1436 if (!strcmp(args[1], "info")) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001437 s->data_ctx.stats.flags |= STAT_SHOW_INFO;
1438 s->data_ctx.stats.flags |= STAT_FMT_CSV;
1439 s->srv_state = SV_STDATA;
1440 fsm_resync |= 1;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001441 continue;
1442 }
Willy Tarreau92fb9832007-10-16 17:34:28 +02001443 }
Willy Tarreau3e76e722007-10-17 18:57:38 +02001444
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001445 s->srv_state = SV_STCLOSE;
1446 fsm_resync |= 1;
Willy Tarreau3e76e722007-10-17 18:57:38 +02001447 continue;
1448
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001449 case SV_STDATA:
1450 /* OK we have to process the request. Since it is possible
1451 * that we get there with the client output paused, we
1452 * will simply check that we have really sent some data
1453 * and wake the client up if needed.
1454 */
1455 last_rep_l = s->rep->l;
1456 if (stats_dump_raw(s, NULL) != 0) {
1457 s->srv_state = SV_STCLOSE;
1458 fsm_resync |= 1;
1459 }
1460 if (s->rep->l != last_rep_l)
1461 fsm_resync |= 1;
1462 break;
Willy Tarreau3e76e722007-10-17 18:57:38 +02001463 }
Willy Tarreau92fb9832007-10-16 17:34:28 +02001464 } while (fsm_resync);
1465
1466 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
1467 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1468 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1469
1470 t->expire = s->req->rex;
1471 tv_min(&t->expire, &s->req->rex, &s->req->wex);
1472 tv_bound(&t->expire, &s->req->cex);
1473 tv_bound(&t->expire, &s->rep->rex);
1474 tv_bound(&t->expire, &s->rep->wex);
1475
1476 /* restore t to its place in the task list */
1477 task_queue(t);
1478
1479 *next = t->expire;
1480 return; /* nothing more to do */
1481 }
1482
1483 actconn--;
1484 listener = fdtab[s->cli_fd].listener;
1485 if (listener) {
1486 listener->nbconn--;
1487 if (listener->state == LI_FULL &&
1488 listener->nbconn < listener->maxconn) {
1489 /* we should reactivate the listener */
1490 EV_FD_SET(listener->fd, DIR_RD);
1491 listener->state = LI_READY;
1492 }
1493 }
1494
1495 /* the task MUST not be in the run queue anymore */
1496 task_delete(t);
1497 session_free(s);
1498 task_free(t);
1499 tv_eternity(next);
1500}
1501
Willy Tarreau92fb9832007-10-16 17:34:28 +02001502__attribute__((constructor))
1503static void __uxst_protocol_init(void)
1504{
1505 protocol_register(&proto_unix);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001506}
1507
1508
1509/*
1510 * Local variables:
1511 * c-indent-level: 8
1512 * c-basic-offset: 8
1513 * End:
1514 */