blob: 43383735664553b15bbb6a132aba99630ff67b7e [file] [log] [blame]
Willy Tarreau92fb9832007-10-16 17:34:28 +02001/*
2 * UNIX SOCK_STREAM protocol layer (uxst)
3 *
4 * Copyright 2000-2007 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <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;
279 fdtab[fd].ev = 0;
280 return ERR_NONE;
281}
282
283/* This function closes the UNIX sockets for the specified listener.
284 * The listener enters the LI_ASSIGNED state. It always returns ERR_NONE.
285 */
286static int uxst_unbind_listener(struct listener *listener)
287{
288 if (listener->state == LI_READY)
289 EV_FD_CLR(listener->fd, DIR_RD);
290
291 if (listener->state >= LI_LISTEN) {
292 close(listener->fd);
293 listener->state = LI_ASSIGNED;
294 destroy_uxst_socket(((struct sockaddr_un *)&listener->addr)->sun_path);
295 }
296 return ERR_NONE;
297}
298
299/* Add a listener to the list of unix stream listeners. The listener's state
300 * is automatically updated from LI_INIT to LI_ASSIGNED. The number of
301 * listeners is updated. This is the function to use to add a new listener.
302 */
303void uxst_add_listener(struct listener *listener)
304{
305 if (listener->state != LI_INIT)
306 return;
307 listener->state = LI_ASSIGNED;
308 listener->proto = &proto_unix;
309 LIST_ADDQ(&proto_unix.listeners, &listener->proto_list);
310 proto_unix.nb_listeners++;
311}
312
313/* Delete a listener from the list of unix stream listeners. The listener's
314 * state is automatically updated from LI_ASSIGNED to LI_INIT. The number of
315 * listeners is updated. Note that the listener must have previously been
316 * unbound. This is the function to use to remove a listener.
317 */
318void uxst_del_listener(struct listener *listener)
319{
320 if (listener->state != LI_ASSIGNED)
321 return;
322 listener->state = LI_INIT;
323 LIST_DEL(&listener->proto_list);
324 proto_unix.nb_listeners--;
325}
326
327
328/********************************
329 * 3) protocol-oriented functions
330 ********************************/
331
332
Willy Tarreau92fb9832007-10-16 17:34:28 +0200333/* This function creates all UNIX sockets bound to the protocol entry <proto>.
334 * It is intended to be used as the protocol's bind_all() function.
335 * The sockets will be registered but not added to any fd_set, in order not to
336 * loose them across the fork(). A call to uxst_enable_listeners() is needed
337 * to complete initialization.
338 *
339 * The return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL.
340 */
341static int uxst_bind_listeners(struct protocol *proto)
342{
343 struct listener *listener;
344 int err = ERR_NONE;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200345
346 list_for_each_entry(listener, &proto->listeners, proto_list) {
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100347 err |= uxst_bind_listener(listener);
348 if (err != ERR_NONE)
Willy Tarreau92fb9832007-10-16 17:34:28 +0200349 continue;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200350 }
Willy Tarreau92fb9832007-10-16 17:34:28 +0200351 return err;
352}
353
Willy Tarreau92fb9832007-10-16 17:34:28 +0200354
355/* This function stops all listening UNIX sockets bound to the protocol
356 * <proto>. It does not detaches them from the protocol.
357 * It always returns ERR_NONE.
358 */
359static int uxst_unbind_listeners(struct protocol *proto)
360{
361 struct listener *listener;
362
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100363 list_for_each_entry(listener, &proto->listeners, proto_list)
364 uxst_unbind_listener(listener);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200365 return ERR_NONE;
366}
367
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100368
369/********************************
370 * 4) high-level functions
371 ********************************/
372
373
Willy Tarreau92fb9832007-10-16 17:34:28 +0200374/*
375 * This function is called on a read event from a listen socket, corresponding
376 * to an accept. It tries to accept as many connections as possible.
377 * It returns 0. Since we use UNIX sockets on the local system for monitoring
378 * purposes and other related things, we do not need to output as many messages
379 * as with TCP which can fall under attack.
380 */
381int uxst_event_accept(int fd) {
382 struct listener *l = (struct listener *)fdtab[fd].owner;
383 struct session *s;
384 struct task *t;
385 int cfd;
386 int max_accept;
387
388 if (global.nbproc > 1)
389 max_accept = 8; /* let other processes catch some connections too */
390 else
391 max_accept = -1;
392
393 while (max_accept--) {
394 struct sockaddr_storage addr;
395 socklen_t laddr = sizeof(addr);
396
397 if ((cfd = accept(fd, (struct sockaddr *)&addr, &laddr)) == -1) {
398 switch (errno) {
399 case EAGAIN:
400 case EINTR:
401 case ECONNABORTED:
402 return 0; /* nothing more to accept */
403 case ENFILE:
404 /* Process reached system FD limit. Check system tunables. */
405 return 0;
406 case EMFILE:
407 /* Process reached process FD limit. Check 'ulimit-n'. */
408 return 0;
409 case ENOBUFS:
410 case ENOMEM:
411 /* Process reached system memory limit. Check system tunables. */
412 return 0;
413 default:
414 return 0;
415 }
416 }
417
418 if (l->nbconn >= l->maxconn) {
419 /* too many connections, we shoot this one and return.
420 * FIXME: it would be better to simply switch the listener's
421 * state to LI_FULL and disable the FD. We could re-enable
422 * it upon fd_delete(), but this requires all protocols to
423 * be switched.
424 */
425 close(cfd);
426 return 0;
427 }
428
429 if ((s = pool_alloc2(pool2_session)) == NULL) {
430 Alert("out of memory in uxst_event_accept().\n");
431 close(cfd);
432 return 0;
433 }
434
435 if ((t = pool_alloc2(pool2_task)) == NULL) {
436 Alert("out of memory in uxst_event_accept().\n");
437 close(cfd);
438 pool_free2(pool2_session, s);
439 return 0;
440 }
441
442 s->cli_addr = addr;
443
444 /* FIXME: should be checked earlier */
445 if (cfd >= global.maxsock) {
446 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
447 close(cfd);
448 pool_free2(pool2_task, t);
449 pool_free2(pool2_session, s);
450 return 0;
451 }
452
453 if (fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) {
454 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
455 close(cfd);
456 pool_free2(pool2_task, t);
457 pool_free2(pool2_session, s);
458 return 0;
459 }
460
461 t->wq = NULL;
462 t->qlist.p = NULL;
463 t->state = TASK_IDLE;
464 t->process = l->handler;
465 t->context = s;
466
467 s->task = t;
468 s->fe = NULL;
469 s->be = NULL;
470
471 s->cli_state = CL_STDATA;
472 s->srv_state = SV_STIDLE;
473 s->req = s->rep = NULL; /* will be allocated later */
474
475 s->cli_fd = cfd;
476 s->srv_fd = -1;
477 s->srv = NULL;
478 s->pend_pos = NULL;
479
480 memset(&s->logs, 0, sizeof(s->logs));
481 memset(&s->txn, 0, sizeof(s->txn));
482
Willy Tarreau3e76e722007-10-17 18:57:38 +0200483 s->data_state = DATA_ST_INIT;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200484 s->data_source = DATA_SRC_NONE;
485 s->uniq_id = totalconn;
486
487 if ((s->req = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */
488 close(cfd); /* nothing can be done for this fd without memory */
489 pool_free2(pool2_task, t);
490 pool_free2(pool2_session, s);
491 return 0;
492 }
493
494 if ((s->rep = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */
495 pool_free2(pool2_buffer, s->req);
496 close(cfd); /* nothing can be done for this fd without memory */
497 pool_free2(pool2_task, t);
498 pool_free2(pool2_session, s);
499 return 0;
500 }
501
502 buffer_init(s->req);
503 buffer_init(s->rep);
504 s->req->rlim += BUFSIZE;
505 s->rep->rlim += BUFSIZE;
506
507 fd_insert(cfd);
508 fdtab[cfd].owner = t;
509 fdtab[cfd].listener = l;
510 fdtab[cfd].state = FD_STREADY;
511 fdtab[cfd].cb[DIR_RD].f = l->proto->read;
512 fdtab[cfd].cb[DIR_RD].b = s->req;
513 fdtab[cfd].cb[DIR_WR].f = l->proto->write;
514 fdtab[cfd].cb[DIR_WR].b = s->rep;
515 fdtab[cfd].peeraddr = (struct sockaddr *)&s->cli_addr;
516 fdtab[cfd].peerlen = sizeof(s->cli_addr);
517 fdtab[cfd].ev = 0;
518
519
520 tv_eternity(&s->req->rex);
521 tv_eternity(&s->req->wex);
522 tv_eternity(&s->req->cex);
523 tv_eternity(&s->rep->rex);
524 tv_eternity(&s->rep->wex);
525
526 tv_eternity(&s->req->wto);
527 tv_eternity(&s->req->cto);
528 tv_eternity(&s->req->rto);
529 tv_eternity(&s->rep->rto);
530 tv_eternity(&s->rep->cto);
531 tv_eternity(&s->rep->wto);
532
533 if (l->timeout)
534 s->req->rto = *l->timeout;
535
536 if (l->timeout)
537 s->rep->wto = *l->timeout;
538
539 tv_eternity(&t->expire);
540 if (l->timeout && tv_isset(l->timeout)) {
541 EV_FD_SET(cfd, DIR_RD);
542 tv_add(&s->req->rex, &now, &s->req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200543 t->expire = s->req->rex;
544 }
545
546 task_queue(t);
547 task_wakeup(t);
548
549 l->nbconn++; /* warning! right now, it's up to the handler to decrease this */
550 if (l->nbconn >= l->maxconn) {
551 EV_FD_CLR(l->fd, DIR_RD);
552 l->state = LI_FULL;
553 }
554 actconn++;
555 totalconn++;
556
557 //fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p, cfd=%d, maxfd=%d\n", p, actconn, totalconn, t, cfd, maxfd);
558 } /* end of while (p->feconn < p->maxconn) */
559 //fprintf(stderr,"fct %s:%d\n", __FUNCTION__, __LINE__);
560 return 0;
561}
562
563/*
564 * manages the client FSM and its socket. It returns 1 if a state has changed
565 * (and a resync may be needed), otherwise 0.
566 */
567static int process_uxst_cli(struct session *t)
568{
569 int s = t->srv_state;
570 int c = t->cli_state;
571 struct buffer *req = t->req;
572 struct buffer *rep = t->rep;
573 //fprintf(stderr,"fct %s:%d\n", __FUNCTION__, __LINE__);
574 if (c == CL_STDATA) {
575 /* FIXME: this error handling is partly buggy because we always report
576 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
577 * or HEADER phase. BTW, it's not logical to expire the client while
578 * we're waiting for the server to connect.
579 */
580 /* read or write error */
581 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
582 buffer_shutr(req);
583 buffer_shutw(rep);
584 fd_delete(t->cli_fd);
585 t->cli_state = CL_STCLOSE;
586 if (!(t->flags & SN_ERR_MASK))
587 t->flags |= SN_ERR_CLICL;
588 if (!(t->flags & SN_FINST_MASK)) {
589 if (t->pend_pos)
590 t->flags |= SN_FINST_Q;
591 else if (s == SV_STCONN)
592 t->flags |= SN_FINST_C;
593 else
594 t->flags |= SN_FINST_D;
595 }
596 return 1;
597 }
598 /* last read, or end of server write */
599 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
600 EV_FD_CLR(t->cli_fd, DIR_RD);
601 buffer_shutr(req);
602 t->cli_state = CL_STSHUTR;
603 return 1;
604 }
605 /* last server read and buffer empty */
606 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
607 EV_FD_CLR(t->cli_fd, DIR_WR);
608 buffer_shutw(rep);
609 shutdown(t->cli_fd, SHUT_WR);
610 /* We must ensure that the read part is still alive when switching
611 * to shutw */
612 EV_FD_SET(t->cli_fd, DIR_RD);
613 tv_add_ifset(&req->rex, &now, &req->rto);
614 t->cli_state = CL_STSHUTW;
615 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
616 return 1;
617 }
618 /* read timeout */
619 else if (tv_isle(&req->rex, &now)) {
620 EV_FD_CLR(t->cli_fd, DIR_RD);
621 buffer_shutr(req);
622 t->cli_state = CL_STSHUTR;
623 if (!(t->flags & SN_ERR_MASK))
624 t->flags |= SN_ERR_CLITO;
625 if (!(t->flags & SN_FINST_MASK)) {
626 if (t->pend_pos)
627 t->flags |= SN_FINST_Q;
628 else if (s == SV_STCONN)
629 t->flags |= SN_FINST_C;
630 else
631 t->flags |= SN_FINST_D;
632 }
633 return 1;
634 }
635 /* write timeout */
636 else if (tv_isle(&rep->wex, &now)) {
637 EV_FD_CLR(t->cli_fd, DIR_WR);
638 buffer_shutw(rep);
639 shutdown(t->cli_fd, SHUT_WR);
640 /* We must ensure that the read part is still alive when switching
641 * to shutw */
642 EV_FD_SET(t->cli_fd, DIR_RD);
643 tv_add_ifset(&req->rex, &now, &req->rto);
644
645 t->cli_state = CL_STSHUTW;
646 if (!(t->flags & SN_ERR_MASK))
647 t->flags |= SN_ERR_CLITO;
648 if (!(t->flags & SN_FINST_MASK)) {
649 if (t->pend_pos)
650 t->flags |= SN_FINST_Q;
651 else if (s == SV_STCONN)
652 t->flags |= SN_FINST_C;
653 else
654 t->flags |= SN_FINST_D;
655 }
656 return 1;
657 }
658
659 if (req->l >= req->rlim - req->data) {
660 /* no room to read more data */
661 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
662 /* stop reading until we get some space */
663 tv_eternity(&req->rex);
664 }
665 } else {
666 /* there's still some space in the buffer */
667 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
668 if (!tv_isset(&req->rto) ||
669 (t->srv_state < SV_STDATA && tv_isset(&req->wto)))
670 /* If the client has no timeout, or if the server not ready yet, and we
671 * know for sure that it can expire, then it's cleaner to disable the
672 * timeout on the client side so that too low values cannot make the
673 * sessions abort too early.
674 */
675 tv_eternity(&req->rex);
676 else
677 tv_add(&req->rex, &now, &req->rto);
678 }
679 }
680
681 if ((rep->l == 0) ||
682 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
683 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
684 /* stop writing */
685 tv_eternity(&rep->wex);
686 }
687 } else {
688 /* buffer not empty */
689 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
690 /* restart writing */
691 if (tv_add_ifset(&rep->wex, &now, &rep->wto)) {
692 /* FIXME: to prevent the client from expiring read timeouts during writes,
693 * we refresh it. */
694 req->rex = rep->wex;
695 }
696 else
697 tv_eternity(&rep->wex);
698 }
699 }
700 return 0; /* other cases change nothing */
701 }
702 else if (c == CL_STSHUTR) {
703 if (rep->flags & BF_WRITE_ERROR) {
704 buffer_shutw(rep);
705 fd_delete(t->cli_fd);
706 t->cli_state = CL_STCLOSE;
707 if (!(t->flags & SN_ERR_MASK))
708 t->flags |= SN_ERR_CLICL;
709 if (!(t->flags & SN_FINST_MASK)) {
710 if (t->pend_pos)
711 t->flags |= SN_FINST_Q;
712 else if (s == SV_STCONN)
713 t->flags |= SN_FINST_C;
714 else
715 t->flags |= SN_FINST_D;
716 }
717 return 1;
718 }
719 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
720 buffer_shutw(rep);
721 fd_delete(t->cli_fd);
722 t->cli_state = CL_STCLOSE;
723 return 1;
724 }
725 else if (tv_isle(&rep->wex, &now)) {
726 buffer_shutw(rep);
727 fd_delete(t->cli_fd);
728 t->cli_state = CL_STCLOSE;
729 if (!(t->flags & SN_ERR_MASK))
730 t->flags |= SN_ERR_CLITO;
731 if (!(t->flags & SN_FINST_MASK)) {
732 if (t->pend_pos)
733 t->flags |= SN_FINST_Q;
734 else if (s == SV_STCONN)
735 t->flags |= SN_FINST_C;
736 else
737 t->flags |= SN_FINST_D;
738 }
739 return 1;
740 }
741
742 if (rep->l == 0) {
743 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
744 /* stop writing */
745 tv_eternity(&rep->wex);
746 }
747 } else {
748 /* buffer not empty */
749 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
750 /* restart writing */
751 if (!tv_add_ifset(&rep->wex, &now, &rep->wto))
752 tv_eternity(&rep->wex);
753 }
754 }
755 return 0;
756 }
757 else if (c == CL_STSHUTW) {
758 if (req->flags & BF_READ_ERROR) {
759 buffer_shutr(req);
760 fd_delete(t->cli_fd);
761 t->cli_state = CL_STCLOSE;
762 if (!(t->flags & SN_ERR_MASK))
763 t->flags |= SN_ERR_CLICL;
764 if (!(t->flags & SN_FINST_MASK)) {
765 if (t->pend_pos)
766 t->flags |= SN_FINST_Q;
767 else if (s == SV_STCONN)
768 t->flags |= SN_FINST_C;
769 else
770 t->flags |= SN_FINST_D;
771 }
772 return 1;
773 }
774 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
775 buffer_shutr(req);
776 fd_delete(t->cli_fd);
777 t->cli_state = CL_STCLOSE;
778 return 1;
779 }
780 else if (tv_isle(&req->rex, &now)) {
781 buffer_shutr(req);
782 fd_delete(t->cli_fd);
783 t->cli_state = CL_STCLOSE;
784 if (!(t->flags & SN_ERR_MASK))
785 t->flags |= SN_ERR_CLITO;
786 if (!(t->flags & SN_FINST_MASK)) {
787 if (t->pend_pos)
788 t->flags |= SN_FINST_Q;
789 else if (s == SV_STCONN)
790 t->flags |= SN_FINST_C;
791 else
792 t->flags |= SN_FINST_D;
793 }
794 return 1;
795 }
796 else if (req->l >= req->rlim - req->data) {
797 /* no room to read more data */
798
799 /* FIXME-20050705: is it possible for a client to maintain a session
800 * after the timeout by sending more data after it receives a close ?
801 */
802
803 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
804 /* stop reading until we get some space */
805 tv_eternity(&req->rex);
806 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
807 }
808 } else {
809 /* there's still some space in the buffer */
810 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
811 if (!tv_add_ifset(&req->rex, &now, &req->rto))
812 tv_eternity(&req->rex);
813 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
814 }
815 }
816 return 0;
817 }
818 else { /* CL_STCLOSE: nothing to do */
819 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
820 int len;
821 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be?t->be->id:"",
822 (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
823 write(1, trash, len);
824 }
825 return 0;
826 }
827 return 0;
828}
829
830#if 0
831 /* FIXME! This part has not been completely converted yet, and it may
832 * still be very specific to TCPv4 ! Also, it relies on some parameters
833 * such as conn_retries which are not set upon accept().
834 */
835/*
836 * Manages the server FSM and its socket. It returns 1 if a state has changed
837 * (and a resync may be needed), otherwise 0.
838 */
839static int process_uxst_srv(struct session *t)
840{
841 int s = t->srv_state;
842 int c = t->cli_state;
843 struct buffer *req = t->req;
844 struct buffer *rep = t->rep;
845 int conn_err;
846
847 if (s == SV_STIDLE) {
848 if (c == CL_STCLOSE || c == CL_STSHUTW ||
849 (c == CL_STSHUTR &&
850 (t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
851 tv_eternity(&req->cex);
852 if (t->pend_pos)
853 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
854 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C);
855 return 1;
856 }
857 else {
858 /* FIXME: reimplement the TARPIT check here */
859
860 /* Right now, we will need to create a connection to the server.
861 * We might already have tried, and got a connection pending, in
862 * which case we will not do anything till it's pending. It's up
863 * to any other session to release it and wake us up again.
864 */
865 if (t->pend_pos) {
866 if (!tv_isle(&req->cex, &now))
867 return 0;
868 else {
869 /* we've been waiting too long here */
870 tv_eternity(&req->cex);
871 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
872 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q);
873 if (t->srv)
874 t->srv->failed_conns++;
875 if (t->fe)
876 t->fe->failed_conns++;
877 return 1;
878 }
879 }
880
881 do {
882 /* first, get a connection */
883 if (srv_redispatch_connect(t))
884 return t->srv_state != SV_STIDLE;
885
886 /* try to (re-)connect to the server, and fail if we expire the
887 * number of retries.
888 */
889 if (srv_retryable_connect(t)) {
890 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
891 return t->srv_state != SV_STIDLE;
892 }
893 } while (1);
894 }
895 }
896 else if (s == SV_STCONN) { /* connection in progress */
897 if (c == CL_STCLOSE || c == CL_STSHUTW ||
898 (c == CL_STSHUTR &&
899 ((t->req->l == 0 && !(req->flags & BF_WRITE_STATUS)) ||
900 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
901 tv_eternity(&req->cex);
902 fd_delete(t->srv_fd);
903 if (t->srv)
904 t->srv->cur_sess--;
905
906 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C);
907 return 1;
908 }
909 if (!(req->flags & BF_WRITE_STATUS) && !tv_isle(&req->cex, &now)) {
910 //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);
911 return 0; /* nothing changed */
912 }
913 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
914 /* timeout, asynchronous connect error or first write error */
915 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
916
917 fd_delete(t->srv_fd);
918 if (t->srv)
919 t->srv->cur_sess--;
920
921 if (!(req->flags & BF_WRITE_STATUS))
922 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
923 else
924 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
925
926 /* ensure that we have enough retries left */
927 if (srv_count_retry_down(t, conn_err))
928 return 1;
929
930 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
931 /* We're on our last chance, and the REDISP option was specified.
932 * We will ignore cookie and force to balance or use the dispatcher.
933 */
934 /* let's try to offer this slot to anybody */
935 if (may_dequeue_tasks(t->srv, t->be))
936 task_wakeup(t->srv->queue_mgt);
937
938 if (t->srv)
939 t->srv->failed_conns++;
940 t->be->failed_conns++;
941
942 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
943 t->srv = NULL; /* it's left to the dispatcher to choose a server */
944
945 /* first, get a connection */
946 if (srv_redispatch_connect(t))
947 return t->srv_state != SV_STIDLE;
948 }
949
950 do {
951 /* Now we will try to either reconnect to the same server or
952 * connect to another server. If the connection gets queued
953 * because all servers are saturated, then we will go back to
954 * the SV_STIDLE state.
955 */
956 if (srv_retryable_connect(t)) {
957 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
958 return t->srv_state != SV_STCONN;
959 }
960
961 /* we need to redispatch the connection to another server */
962 if (srv_redispatch_connect(t))
963 return t->srv_state != SV_STCONN;
964 } while (1);
965 }
966 else { /* no error or write 0 */
967 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
968
969 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
970 if (req->l == 0) /* nothing to write */ {
971 EV_FD_CLR(t->srv_fd, DIR_WR);
972 tv_eternity(&req->wex);
973 } else /* need the right to write */ {
974 EV_FD_SET(t->srv_fd, DIR_WR);
975 if (tv_add_ifset(&req->wex, &now, &req->wto)) {
976 /* FIXME: to prevent the server from expiring read timeouts during writes,
977 * we refresh it. */
978 rep->rex = req->wex;
979 }
980 else
981 tv_eternity(&req->wex);
982 }
983
984 EV_FD_SET(t->srv_fd, DIR_RD);
985 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
986 tv_eternity(&rep->rex);
987
988 t->srv_state = SV_STDATA;
989 if (t->srv)
990 t->srv->cum_sess++;
991 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
992
993 /* if the user wants to log as soon as possible, without counting
994 bytes from the server, then this is the right moment. */
995 if (t->fe && t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
996 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
997 //uxst_sess_log(t);
998 }
999 tv_eternity(&req->cex);
1000 return 1;
1001 }
1002 }
1003 else if (s == SV_STDATA) {
1004 /* read or write error */
1005 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
1006 buffer_shutr(rep);
1007 buffer_shutw(req);
1008 fd_delete(t->srv_fd);
1009 if (t->srv) {
1010 t->srv->cur_sess--;
1011 t->srv->failed_resp++;
1012 }
1013 t->be->failed_resp++;
1014 t->srv_state = SV_STCLOSE;
1015 if (!(t->flags & SN_ERR_MASK))
1016 t->flags |= SN_ERR_SRVCL;
1017 if (!(t->flags & SN_FINST_MASK))
1018 t->flags |= SN_FINST_D;
1019 /* We used to have a free connection slot. Since we'll never use it,
1020 * we have to inform the server that it may be used by another session.
1021 */
1022 if (may_dequeue_tasks(t->srv, t->be))
1023 task_wakeup(t->srv->queue_mgt);
1024
1025 return 1;
1026 }
1027 /* last read, or end of client write */
1028 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
1029 EV_FD_CLR(t->srv_fd, DIR_RD);
1030 buffer_shutr(rep);
1031 t->srv_state = SV_STSHUTR;
1032 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1033 return 1;
1034 }
1035 /* end of client read and no more data to send */
1036 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
1037 EV_FD_CLR(t->srv_fd, DIR_WR);
1038 buffer_shutw(req);
1039 shutdown(t->srv_fd, SHUT_WR);
1040 /* We must ensure that the read part is still alive when switching
1041 * to shutw */
1042 EV_FD_SET(t->srv_fd, DIR_RD);
1043 tv_add_ifset(&rep->rex, &now, &rep->rto);
1044
1045 t->srv_state = SV_STSHUTW;
1046 return 1;
1047 }
1048 /* read timeout */
1049 else if (tv_isle(&rep->rex, &now)) {
1050 EV_FD_CLR(t->srv_fd, DIR_RD);
1051 buffer_shutr(rep);
1052 t->srv_state = SV_STSHUTR;
1053 if (!(t->flags & SN_ERR_MASK))
1054 t->flags |= SN_ERR_SRVTO;
1055 if (!(t->flags & SN_FINST_MASK))
1056 t->flags |= SN_FINST_D;
1057 return 1;
1058 }
1059 /* write timeout */
1060 else if (tv_isle(&req->wex, &now)) {
1061 EV_FD_CLR(t->srv_fd, DIR_WR);
1062 buffer_shutw(req);
1063 shutdown(t->srv_fd, SHUT_WR);
1064 /* We must ensure that the read part is still alive when switching
1065 * to shutw */
1066 EV_FD_SET(t->srv_fd, DIR_RD);
1067 tv_add_ifset(&rep->rex, &now, &rep->rto);
1068 t->srv_state = SV_STSHUTW;
1069 if (!(t->flags & SN_ERR_MASK))
1070 t->flags |= SN_ERR_SRVTO;
1071 if (!(t->flags & SN_FINST_MASK))
1072 t->flags |= SN_FINST_D;
1073 return 1;
1074 }
1075
1076 /* recompute request time-outs */
1077 if (req->l == 0) {
1078 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
1079 /* stop writing */
1080 tv_eternity(&req->wex);
1081 }
1082 }
1083 else { /* buffer not empty, there are still data to be transferred */
1084 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
1085 /* restart writing */
1086 if (tv_add_ifset(&req->wex, &now, &req->wto)) {
1087 /* FIXME: to prevent the server from expiring read timeouts during writes,
1088 * we refresh it. */
1089 rep->rex = req->wex;
1090 }
1091 else
1092 tv_eternity(&req->wex);
1093 }
1094 }
1095
1096 /* recompute response time-outs */
1097 if (rep->l == BUFSIZE) { /* no room to read more data */
1098 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
1099 tv_eternity(&rep->rex);
1100 }
1101 }
1102 else {
1103 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
1104 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
1105 tv_eternity(&rep->rex);
1106 }
1107 }
1108
1109 return 0; /* other cases change nothing */
1110 }
1111 else if (s == SV_STSHUTR) {
1112 if (req->flags & BF_WRITE_ERROR) {
1113 //EV_FD_CLR(t->srv_fd, DIR_WR);
1114 buffer_shutw(req);
1115 fd_delete(t->srv_fd);
1116 if (t->srv) {
1117 t->srv->cur_sess--;
1118 t->srv->failed_resp++;
1119 }
1120 t->be->failed_resp++;
1121 //close(t->srv_fd);
1122 t->srv_state = SV_STCLOSE;
1123 if (!(t->flags & SN_ERR_MASK))
1124 t->flags |= SN_ERR_SRVCL;
1125 if (!(t->flags & SN_FINST_MASK))
1126 t->flags |= SN_FINST_D;
1127 /* We used to have a free connection slot. Since we'll never use it,
1128 * we have to inform the server that it may be used by another session.
1129 */
1130 if (may_dequeue_tasks(t->srv, t->be))
1131 task_wakeup(t->srv->queue_mgt);
1132
1133 return 1;
1134 }
1135 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
1136 //EV_FD_CLR(t->srv_fd, DIR_WR);
1137 buffer_shutw(req);
1138 fd_delete(t->srv_fd);
1139 if (t->srv)
1140 t->srv->cur_sess--;
1141 //close(t->srv_fd);
1142 t->srv_state = SV_STCLOSE;
1143 /* We used to have a free connection slot. Since we'll never use it,
1144 * we have to inform the server that it may be used by another session.
1145 */
1146 if (may_dequeue_tasks(t->srv, t->be))
1147 task_wakeup(t->srv->queue_mgt);
1148
1149 return 1;
1150 }
1151 else if (tv_isle(&req->wex, &now)) {
1152 //EV_FD_CLR(t->srv_fd, DIR_WR);
1153 buffer_shutw(req);
1154 fd_delete(t->srv_fd);
1155 if (t->srv)
1156 t->srv->cur_sess--;
1157 //close(t->srv_fd);
1158 t->srv_state = SV_STCLOSE;
1159 if (!(t->flags & SN_ERR_MASK))
1160 t->flags |= SN_ERR_SRVTO;
1161 if (!(t->flags & SN_FINST_MASK))
1162 t->flags |= SN_FINST_D;
1163 /* We used to have a free connection slot. Since we'll never use it,
1164 * we have to inform the server that it may be used by another session.
1165 */
1166 if (may_dequeue_tasks(t->srv, t->be))
1167 task_wakeup(t->srv->queue_mgt);
1168
1169 return 1;
1170 }
1171 else if (req->l == 0) {
1172 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
1173 /* stop writing */
1174 tv_eternity(&req->wex);
1175 }
1176 }
1177 else { /* buffer not empty */
1178 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
1179 /* restart writing */
1180 if (!tv_add_ifset(&req->wex, &now, &req->wto))
1181 tv_eternity(&req->wex);
1182 }
1183 }
1184 return 0;
1185 }
1186 else if (s == SV_STSHUTW) {
1187 if (rep->flags & BF_READ_ERROR) {
1188 //EV_FD_CLR(t->srv_fd, DIR_RD);
1189 buffer_shutr(rep);
1190 fd_delete(t->srv_fd);
1191 if (t->srv) {
1192 t->srv->cur_sess--;
1193 t->srv->failed_resp++;
1194 }
1195 t->be->failed_resp++;
1196 //close(t->srv_fd);
1197 t->srv_state = SV_STCLOSE;
1198 if (!(t->flags & SN_ERR_MASK))
1199 t->flags |= SN_ERR_SRVCL;
1200 if (!(t->flags & SN_FINST_MASK))
1201 t->flags |= SN_FINST_D;
1202 /* We used to have a free connection slot. Since we'll never use it,
1203 * we have to inform the server that it may be used by another session.
1204 */
1205 if (may_dequeue_tasks(t->srv, t->be))
1206 task_wakeup(t->srv->queue_mgt);
1207
1208 return 1;
1209 }
1210 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
1211 //EV_FD_CLR(t->srv_fd, DIR_RD);
1212 buffer_shutr(rep);
1213 fd_delete(t->srv_fd);
1214 if (t->srv)
1215 t->srv->cur_sess--;
1216 //close(t->srv_fd);
1217 t->srv_state = SV_STCLOSE;
1218 /* We used to have a free connection slot. Since we'll never use it,
1219 * we have to inform the server that it may be used by another session.
1220 */
1221 if (may_dequeue_tasks(t->srv, t->be))
1222 task_wakeup(t->srv->queue_mgt);
1223
1224 return 1;
1225 }
1226 else if (tv_isle(&rep->rex, &now)) {
1227 //EV_FD_CLR(t->srv_fd, DIR_RD);
1228 buffer_shutr(rep);
1229 fd_delete(t->srv_fd);
1230 if (t->srv)
1231 t->srv->cur_sess--;
1232 //close(t->srv_fd);
1233 t->srv_state = SV_STCLOSE;
1234 if (!(t->flags & SN_ERR_MASK))
1235 t->flags |= SN_ERR_SRVTO;
1236 if (!(t->flags & SN_FINST_MASK))
1237 t->flags |= SN_FINST_D;
1238 /* We used to have a free connection slot. Since we'll never use it,
1239 * we have to inform the server that it may be used by another session.
1240 */
1241 if (may_dequeue_tasks(t->srv, t->be))
1242 task_wakeup(t->srv->queue_mgt);
1243
1244 return 1;
1245 }
1246 else if (rep->l == BUFSIZE) { /* no room to read more data */
1247 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
1248 tv_eternity(&rep->rex);
1249 }
1250 }
1251 else {
1252 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
1253 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
1254 tv_eternity(&rep->rex);
1255 }
1256 }
1257 return 0;
1258 }
1259 else { /* SV_STCLOSE : nothing to do */
1260 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1261 int len;
1262 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
1263 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1264 write(1, trash, len);
1265 }
1266 return 0;
1267 }
1268 return 0;
1269}
1270
1271/* Processes the client and server jobs of a session task, then
1272 * puts it back to the wait queue in a clean state, or
1273 * cleans up its resources if it must be deleted. Returns
1274 * the time the task accepts to wait, or TIME_ETERNITY for
1275 * infinity.
1276 */
1277void process_uxst_session(struct task *t, struct timeval *next)
1278{
1279 struct session *s = t->context;
1280 int fsm_resync = 0;
1281
1282 do {
1283 fsm_resync = 0;
1284 fsm_resync |= process_uxst_cli(s);
1285 if (s->srv_state == SV_STIDLE) {
1286 if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) {
1287 s->srv_state = SV_STCLOSE;
1288 fsm_resync |= 1;
1289 continue;
1290 }
1291 if (s->cli_state == CL_STSHUTR ||
1292 (s->req->l >= s->req->rlim - s->req->data)) {
1293 if (s->req->l == 0) {
1294 s->srv_state = SV_STCLOSE;
1295 fsm_resync |= 1;
1296 continue;
1297 }
1298 /* OK we have some remaining data to process */
1299 /* Just as an exercice, we copy the req into the resp,
1300 * and flush the req.
1301 */
1302 memcpy(s->rep->data, s->req->data, sizeof(s->rep->data));
1303 s->rep->l = s->req->l;
1304 s->rep->rlim = s->rep->data + BUFSIZE;
1305 s->rep->w = s->rep->data;
1306 s->rep->lr = s->rep->r = s->rep->data + s->rep->l;
1307
1308 s->req->l = 0;
1309 s->srv_state = SV_STCLOSE;
1310
1311 fsm_resync |= 1;
1312 continue;
1313 }
1314 }
1315 } while (fsm_resync);
1316
1317 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
1318 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1319 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1320
1321 t->expire = s->req->rex;
1322 tv_min(&t->expire, &s->req->rex, &s->req->wex);
1323 tv_bound(&t->expire, &s->req->cex);
1324 tv_bound(&t->expire, &s->rep->rex);
1325 tv_bound(&t->expire, &s->rep->wex);
1326
1327 /* restore t to its place in the task list */
1328 task_queue(t);
1329
1330 *next = t->expire;
1331 return; /* nothing more to do */
1332 }
1333
1334 if (s->fe)
1335 s->fe->feconn--;
1336 if (s->be && (s->flags & SN_BE_ASSIGNED))
1337 s->be->beconn--;
1338 actconn--;
1339
1340 if (unlikely((global.mode & MODE_DEBUG) &&
1341 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
1342 int len;
1343 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
1344 s->uniq_id, s->be->id,
1345 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
1346 write(1, trash, len);
1347 }
1348
1349 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
1350 if (s->req != NULL)
1351 s->logs.bytes_in = s->req->total;
1352 if (s->rep != NULL)
1353 s->logs.bytes_out = s->rep->total;
1354
1355 if (s->fe) {
1356 s->fe->bytes_in += s->logs.bytes_in;
1357 s->fe->bytes_out += s->logs.bytes_out;
1358 }
1359 if (s->be && (s->be != s->fe)) {
1360 s->be->bytes_in += s->logs.bytes_in;
1361 s->be->bytes_out += s->logs.bytes_out;
1362 }
1363 if (s->srv) {
1364 s->srv->bytes_in += s->logs.bytes_in;
1365 s->srv->bytes_out += s->logs.bytes_out;
1366 }
1367
1368 /* let's do a final log if we need it */
1369 if (s->logs.logwait &&
1370 !(s->flags & SN_MONITOR) &&
1371 (s->req->total || !(s->fe && s->fe->options & PR_O_NULLNOLOG))) {
1372 //uxst_sess_log(s);
1373 }
1374
1375 /* the task MUST not be in the run queue anymore */
1376 task_delete(t);
1377 session_free(s);
1378 task_free(t);
1379 tv_eternity(next);
1380}
1381#endif /* not converted */
1382
1383
1384/* Processes data exchanges on the statistics socket. The client processing
1385 * is called and the task is put back in the wait queue or it is cleared.
1386 * In order to ease the transition, we simply simulate the server status
Willy Tarreau3e76e722007-10-17 18:57:38 +02001387 * for now. It only knows states SV_STIDLE, SV_STDATA and SV_STCLOSE. Returns
1388 * in <next> the task's expiration date.
Willy Tarreau92fb9832007-10-16 17:34:28 +02001389 */
1390void process_uxst_stats(struct task *t, struct timeval *next)
1391{
1392 struct session *s = t->context;
1393 struct listener *listener;
1394 int fsm_resync = 0;
1395
Willy Tarreau3e76e722007-10-17 18:57:38 +02001396 /* we need to be in DATA phase on the "server" side */
1397 if (s->srv_state == SV_STIDLE) {
1398 s->srv_state = SV_STDATA;
1399 s->data_source = DATA_SRC_STATS;
1400 }
1401
Willy Tarreau92fb9832007-10-16 17:34:28 +02001402 do {
Willy Tarreau3e76e722007-10-17 18:57:38 +02001403 fsm_resync = process_uxst_cli(s);
1404 if (s->srv_state != SV_STDATA)
1405 continue;
1406
1407 if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) {
1408 s->srv_state = SV_STCLOSE;
1409 fsm_resync |= 1;
1410 continue;
1411 }
1412
1413 if (s->data_state == DATA_ST_INIT) {
1414 if ((s->req->l >= 10) && (memcmp(s->req->data, "show stat\n", 10) == 0)) {
1415 /* send the stats, and changes the data_state */
1416 if (stats_dump_raw(s, NULL, 0) != 0) {
Willy Tarreau92fb9832007-10-16 17:34:28 +02001417 s->srv_state = SV_STCLOSE;
1418 fsm_resync |= 1;
1419 continue;
1420 }
Willy Tarreau3e76e722007-10-17 18:57:38 +02001421 }
1422 else if (s->cli_state == CL_STSHUTR || (s->req->l >= s->req->rlim - s->req->data)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +02001423 s->srv_state = SV_STCLOSE;
Willy Tarreau92fb9832007-10-16 17:34:28 +02001424 fsm_resync |= 1;
1425 continue;
1426 }
1427 }
Willy Tarreau3e76e722007-10-17 18:57:38 +02001428
1429 if (s->data_state == DATA_ST_INIT)
1430 continue;
1431
1432 /* OK we have some remaining data to process. Just for the
1433 * sake of an exercice, we copy the req into the resp,
1434 * and flush the req. This produces a simple echo function.
1435 */
1436 if (stats_dump_raw(s, NULL, 0) != 0) {
1437 s->srv_state = SV_STCLOSE;
1438 fsm_resync |= 1;
1439 continue;
1440 }
Willy Tarreau92fb9832007-10-16 17:34:28 +02001441 } while (fsm_resync);
1442
1443 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
1444 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1445 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1446
1447 t->expire = s->req->rex;
1448 tv_min(&t->expire, &s->req->rex, &s->req->wex);
1449 tv_bound(&t->expire, &s->req->cex);
1450 tv_bound(&t->expire, &s->rep->rex);
1451 tv_bound(&t->expire, &s->rep->wex);
1452
1453 /* restore t to its place in the task list */
1454 task_queue(t);
1455
1456 *next = t->expire;
1457 return; /* nothing more to do */
1458 }
1459
1460 actconn--;
1461 listener = fdtab[s->cli_fd].listener;
1462 if (listener) {
1463 listener->nbconn--;
1464 if (listener->state == LI_FULL &&
1465 listener->nbconn < listener->maxconn) {
1466 /* we should reactivate the listener */
1467 EV_FD_SET(listener->fd, DIR_RD);
1468 listener->state = LI_READY;
1469 }
1470 }
1471
1472 /* the task MUST not be in the run queue anymore */
1473 task_delete(t);
1474 session_free(s);
1475 task_free(t);
1476 tv_eternity(next);
1477}
1478
Willy Tarreau92fb9832007-10-16 17:34:28 +02001479__attribute__((constructor))
1480static void __uxst_protocol_init(void)
1481{
1482 protocol_register(&proto_unix);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001483}
1484
1485
1486/*
1487 * Local variables:
1488 * c-indent-level: 8
1489 * c-basic-offset: 8
1490 * End:
1491 */