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