blob: ba3da5f6a74c664c83550bfe711d1faa852e24ef [file] [log] [blame]
Willy Tarreau92fb9832007-10-16 17:34:28 +02001/*
2 * UNIX SOCK_STREAM protocol layer (uxst)
3 *
Willy Tarreau7c669d72008-06-20 15:04:11 +02004 * Copyright 2000-2008 Willy Tarreau <w@1wt.eu>
Willy Tarreau92fb9832007-10-16 17:34:28 +02005 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <ctype.h>
14#include <errno.h>
15#include <fcntl.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <syslog.h>
20#include <time.h>
21
22#include <sys/param.h>
23#include <sys/socket.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/un.h>
27
28#include <common/compat.h>
29#include <common/config.h>
30#include <common/debug.h>
Willy Tarreaud740bab2007-10-28 11:14:07 +010031#include <common/errors.h>
Willy Tarreau92fb9832007-10-16 17:34:28 +020032#include <common/memory.h>
33#include <common/mini-clist.h>
34#include <common/standard.h>
Willy Tarreau0c303ee2008-07-07 00:09:58 +020035#include <common/ticks.h>
Willy Tarreau92fb9832007-10-16 17:34:28 +020036#include <common/time.h>
37#include <common/version.h>
38
39#include <types/acl.h>
40#include <types/capture.h>
41#include <types/client.h>
42#include <types/global.h>
43#include <types/polling.h>
44#include <types/proxy.h>
45#include <types/server.h>
46
47#include <proto/acl.h>
48#include <proto/backend.h>
49#include <proto/buffers.h>
Willy Tarreau3e76e722007-10-17 18:57:38 +020050#include <proto/dumpstats.h>
Willy Tarreau92fb9832007-10-16 17:34:28 +020051#include <proto/fd.h>
52#include <proto/log.h>
53#include <proto/protocols.h>
54#include <proto/proto_uxst.h>
55#include <proto/queue.h>
Willy Tarreau3e76e722007-10-17 18:57:38 +020056#include <proto/senddata.h>
Willy Tarreau92fb9832007-10-16 17:34:28 +020057#include <proto/session.h>
58#include <proto/stream_sock.h>
59#include <proto/task.h>
60
61#ifndef MAXPATHLEN
62#define MAXPATHLEN 128
63#endif
64
Willy Tarreaudabf2e22007-10-28 21:59:24 +010065static int uxst_bind_listeners(struct protocol *proto);
66static int uxst_unbind_listeners(struct protocol *proto);
67
68/* Note: must not be declared <const> as its list will be overwritten */
69static struct protocol proto_unix = {
70 .name = "unix_stream",
71 .sock_domain = PF_UNIX,
72 .sock_type = SOCK_STREAM,
73 .sock_prot = 0,
74 .sock_family = AF_UNIX,
75 .sock_addrlen = sizeof(struct sockaddr_un),
76 .l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path),/* path len */
77 .read = &stream_sock_read,
78 .write = &stream_sock_write,
79 .bind_all = uxst_bind_listeners,
80 .unbind_all = uxst_unbind_listeners,
81 .enable_all = enable_all_listeners,
82 .disable_all = disable_all_listeners,
83 .listeners = LIST_HEAD_INIT(proto_unix.listeners),
84 .nb_listeners = 0,
85};
86
87
88/********************************
89 * 1) low-level socket functions
90 ********************************/
91
92
Willy Tarreau92fb9832007-10-16 17:34:28 +020093/* This function creates a named PF_UNIX stream socket at address <path>. Note
Willy Tarreaue6ad2b12007-10-18 12:45:54 +020094 * that the path cannot be NULL nor empty. <uid> and <gid> different of -1 will
95 * be used to change the socket owner. If <mode> is not 0, it will be used to
96 * restrict access to the socket. While it is known not to be portable on every
97 * OS, it's still useful where it works.
Willy Tarreau92fb9832007-10-16 17:34:28 +020098 * It returns the assigned file descriptor, or -1 in the event of an error.
99 */
Willy Tarreaue6ad2b12007-10-18 12:45:54 +0200100static int create_uxst_socket(const char *path, uid_t uid, gid_t gid, mode_t mode)
Willy Tarreau92fb9832007-10-16 17:34:28 +0200101{
102 char tempname[MAXPATHLEN];
103 char backname[MAXPATHLEN];
104 struct sockaddr_un addr;
105
106 int ret, sock;
107
108 /* 1. create socket names */
109 if (!path[0]) {
110 Alert("Invalid name for a UNIX socket. Aborting.\n");
111 goto err_return;
112 }
113
114 ret = snprintf(tempname, MAXPATHLEN, "%s.%d.tmp", path, pid);
115 if (ret < 0 || ret >= MAXPATHLEN) {
116 Alert("name too long for UNIX socket. Aborting.\n");
117 goto err_return;
118 }
119
120 ret = snprintf(backname, MAXPATHLEN, "%s.%d.bak", path, pid);
121 if (ret < 0 || ret >= MAXPATHLEN) {
122 Alert("name too long for UNIX socket. Aborting.\n");
123 goto err_return;
124 }
125
126 /* 2. clean existing orphaned entries */
127 if (unlink(tempname) < 0 && errno != ENOENT) {
128 Alert("error when trying to unlink previous UNIX socket. Aborting.\n");
129 goto err_return;
130 }
131
132 if (unlink(backname) < 0 && errno != ENOENT) {
133 Alert("error when trying to unlink previous UNIX socket. Aborting.\n");
134 goto err_return;
135 }
136
137 /* 3. backup existing socket */
138 if (link(path, backname) < 0 && errno != ENOENT) {
139 Alert("error when trying to preserve previous UNIX socket. Aborting.\n");
140 goto err_return;
141 }
142
143 /* 4. prepare new socket */
144 addr.sun_family = AF_UNIX;
145 strncpy(addr.sun_path, tempname, sizeof(addr.sun_path));
146 addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
147
148 sock = socket(PF_UNIX, SOCK_STREAM, 0);
149 if (sock < 0) {
150 Alert("cannot create socket for UNIX listener. Aborting.\n");
151 goto err_unlink_back;
152 }
153
154 if (sock >= global.maxsock) {
155 Alert("socket(): not enough free sockets for UNIX listener. Raise -n argument. Aborting.\n");
156 goto err_unlink_temp;
157 }
158
159 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
160 Alert("cannot make UNIX socket non-blocking. Aborting.\n");
161 goto err_unlink_temp;
162 }
163
164 if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
165 /* note that bind() creates the socket <tempname> on the file system */
166 Alert("cannot bind socket for UNIX listener. Aborting.\n");
167 goto err_unlink_temp;
168 }
169
Willy Tarreaue6ad2b12007-10-18 12:45:54 +0200170 if (((uid != -1 || gid != -1) && (chown(tempname, uid, gid) == -1)) ||
171 (mode != 0 && chmod(tempname, mode) == -1)) {
172 Alert("cannot change UNIX socket ownership. Aborting.\n");
173 goto err_unlink_temp;
174 }
175
Willy Tarreau92fb9832007-10-16 17:34:28 +0200176 if (listen(sock, 0) < 0) {
177 Alert("cannot listen to socket for UNIX listener. Aborting.\n");
178 goto err_unlink_temp;
179 }
180
181 /* 5. install.
182 * Point of no return: we are ready, we'll switch the sockets. We don't
183 * fear loosing the socket <path> because we have a copy of it in
184 * backname.
185 */
186 if (rename(tempname, path) < 0) {
187 Alert("cannot switch final and temporary sockets for UNIX listener. Aborting.\n");
188 goto err_rename;
189 }
190
191 /* 6. cleanup */
192 unlink(backname); /* no need to keep this one either */
193
194 return sock;
195
196 err_rename:
197 ret = rename(backname, path);
198 if (ret < 0 && errno == ENOENT)
199 unlink(path);
200 err_unlink_temp:
201 unlink(tempname);
202 close(sock);
203 err_unlink_back:
204 unlink(backname);
205 err_return:
206 return -1;
207}
208
209/* Tries to destroy the UNIX stream socket <path>. The socket must not be used
210 * anymore. It practises best effort, and no error is returned.
211 */
212static void destroy_uxst_socket(const char *path)
213{
214 struct sockaddr_un addr;
215 int sock, ret;
216
217 /* We might have been chrooted, so we may not be able to access the
218 * socket. In order to avoid bothering the other end, we connect with a
219 * wrong protocol, namely SOCK_DGRAM. The return code from connect()
220 * is enough to know if the socket is still live or not. If it's live
221 * in mode SOCK_STREAM, we get EPROTOTYPE or anything else but not
222 * ECONNREFUSED. In this case, we do not touch it because it's used
223 * by some other process.
224 */
225 sock = socket(PF_UNIX, SOCK_DGRAM, 0);
226 if (sock < 0)
227 return;
228
229 addr.sun_family = AF_UNIX;
230 strncpy(addr.sun_path, path, sizeof(addr.sun_path));
Willy Tarreau10ae5482007-10-18 16:15:52 +0200231 addr.sun_path[sizeof(addr.sun_path) - 1] = 0;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200232 ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
233 if (ret < 0 && errno == ECONNREFUSED) {
234 /* Connect failed: the socket still exists but is not used
235 * anymore. Let's remove this socket now.
236 */
237 unlink(path);
238 }
239 close(sock);
240}
241
242
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100243/********************************
244 * 2) listener-oriented functions
245 ********************************/
246
247
248/* This function creates the UNIX socket associated to the listener. It changes
249 * the state from ASSIGNED to LISTEN. The socket is NOT enabled for polling.
250 * The return value is composed from ERR_NONE, ERR_RETRYABLE and ERR_FATAL.
251 */
252static int uxst_bind_listener(struct listener *listener)
253{
254 int fd;
255
256 if (listener->state != LI_ASSIGNED)
257 return ERR_NONE; /* already bound */
258
259 fd = create_uxst_socket(((struct sockaddr_un *)&listener->addr)->sun_path,
260 listener->perm.ux.uid,
261 listener->perm.ux.gid,
262 listener->perm.ux.mode);
263 if (fd == -1)
264 return ERR_FATAL;
265
266 /* the socket is now listening */
267 listener->fd = fd;
268 listener->state = LI_LISTEN;
269
270 /* the function for the accept() event */
271 fd_insert(fd);
272 fdtab[fd].cb[DIR_RD].f = listener->accept;
273 fdtab[fd].cb[DIR_WR].f = NULL; /* never called */
274 fdtab[fd].cb[DIR_RD].b = fdtab[fd].cb[DIR_WR].b = NULL;
275 fdtab[fd].owner = (struct task *)listener; /* reference the listener instead of a task */
276 fdtab[fd].state = FD_STLISTEN;
277 fdtab[fd].peeraddr = NULL;
278 fdtab[fd].peerlen = 0;
279 fdtab[fd].listener = NULL;
Willy Tarreaudabf2e22007-10-28 21:59:24 +0100280 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
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +0100420 s->flags = 0;
421
Willy Tarreau92fb9832007-10-16 17:34:28 +0200422 if ((t = pool_alloc2(pool2_task)) == NULL) {
423 Alert("out of memory in uxst_event_accept().\n");
424 close(cfd);
425 pool_free2(pool2_session, s);
426 return 0;
427 }
428
429 s->cli_addr = addr;
430
431 /* FIXME: should be checked earlier */
432 if (cfd >= global.maxsock) {
433 Alert("accept(): not enough free sockets. Raise -n argument. Giving up.\n");
434 close(cfd);
435 pool_free2(pool2_task, t);
436 pool_free2(pool2_session, s);
437 return 0;
438 }
439
440 if (fcntl(cfd, F_SETFL, O_NONBLOCK) == -1) {
441 Alert("accept(): cannot set the socket in non blocking mode. Giving up\n");
442 close(cfd);
443 pool_free2(pool2_task, t);
444 pool_free2(pool2_session, s);
445 return 0;
446 }
447
Willy Tarreau9789f7b2008-06-24 08:17:16 +0200448 task_init(t);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200449 t->process = l->handler;
450 t->context = s;
Willy Tarreau91e99932008-06-30 07:51:00 +0200451 t->nice = -64; /* we want to boost priority for local stats */
Willy Tarreau92fb9832007-10-16 17:34:28 +0200452
453 s->task = t;
454 s->fe = NULL;
455 s->be = NULL;
456
457 s->cli_state = CL_STDATA;
458 s->srv_state = SV_STIDLE;
459 s->req = s->rep = NULL; /* will be allocated later */
460
461 s->cli_fd = cfd;
462 s->srv_fd = -1;
463 s->srv = NULL;
464 s->pend_pos = NULL;
465
466 memset(&s->logs, 0, sizeof(s->logs));
467 memset(&s->txn, 0, sizeof(s->txn));
468
Willy Tarreau3e76e722007-10-17 18:57:38 +0200469 s->data_state = DATA_ST_INIT;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200470 s->data_source = DATA_SRC_NONE;
471 s->uniq_id = totalconn;
472
473 if ((s->req = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */
474 close(cfd); /* nothing can be done for this fd without memory */
475 pool_free2(pool2_task, t);
476 pool_free2(pool2_session, s);
477 return 0;
478 }
479
480 if ((s->rep = pool_alloc2(pool2_buffer)) == NULL) { /* no memory */
481 pool_free2(pool2_buffer, s->req);
482 close(cfd); /* nothing can be done for this fd without memory */
483 pool_free2(pool2_task, t);
484 pool_free2(pool2_session, s);
485 return 0;
486 }
487
488 buffer_init(s->req);
489 buffer_init(s->rep);
490 s->req->rlim += BUFSIZE;
491 s->rep->rlim += BUFSIZE;
492
493 fd_insert(cfd);
494 fdtab[cfd].owner = t;
495 fdtab[cfd].listener = l;
496 fdtab[cfd].state = FD_STREADY;
497 fdtab[cfd].cb[DIR_RD].f = l->proto->read;
498 fdtab[cfd].cb[DIR_RD].b = s->req;
499 fdtab[cfd].cb[DIR_WR].f = l->proto->write;
500 fdtab[cfd].cb[DIR_WR].b = s->rep;
501 fdtab[cfd].peeraddr = (struct sockaddr *)&s->cli_addr;
502 fdtab[cfd].peerlen = sizeof(s->cli_addr);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200503
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200504 s->req->rex = TICK_ETERNITY;
505 s->req->wex = TICK_ETERNITY;
506 s->req->cex = TICK_ETERNITY;
507 s->rep->rex = TICK_ETERNITY;
508 s->rep->wex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200509
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200510 s->req->wto = TICK_ETERNITY;
511 s->req->cto = TICK_ETERNITY;
512 s->req->rto = TICK_ETERNITY;
513 s->rep->rto = TICK_ETERNITY;
514 s->rep->cto = TICK_ETERNITY;
515 s->rep->wto = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200516
517 if (l->timeout)
518 s->req->rto = *l->timeout;
519
520 if (l->timeout)
521 s->rep->wto = *l->timeout;
522
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200523 t->expire = TICK_ETERNITY;
524 if (l->timeout && *l->timeout) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200525 EV_FD_SET(cfd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200526 s->req->rex = tick_add(now_ms, s->req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200527 t->expire = s->req->rex;
528 }
529
Willy Tarreau92fb9832007-10-16 17:34:28 +0200530 task_wakeup(t);
531
532 l->nbconn++; /* warning! right now, it's up to the handler to decrease this */
533 if (l->nbconn >= l->maxconn) {
534 EV_FD_CLR(l->fd, DIR_RD);
535 l->state = LI_FULL;
536 }
537 actconn++;
538 totalconn++;
539
540 //fprintf(stderr, "accepting from %p => %d conn, %d total, task=%p, cfd=%d, maxfd=%d\n", p, actconn, totalconn, t, cfd, maxfd);
541 } /* end of while (p->feconn < p->maxconn) */
542 //fprintf(stderr,"fct %s:%d\n", __FUNCTION__, __LINE__);
543 return 0;
544}
545
546/*
547 * manages the client FSM and its socket. It returns 1 if a state has changed
548 * (and a resync may be needed), otherwise 0.
549 */
550static int process_uxst_cli(struct session *t)
551{
552 int s = t->srv_state;
553 int c = t->cli_state;
554 struct buffer *req = t->req;
555 struct buffer *rep = t->rep;
556 //fprintf(stderr,"fct %s:%d\n", __FUNCTION__, __LINE__);
557 if (c == CL_STDATA) {
558 /* FIXME: this error handling is partly buggy because we always report
559 * a 'DATA' phase while we don't know if the server was in IDLE, CONN
560 * or HEADER phase. BTW, it's not logical to expire the client while
561 * we're waiting for the server to connect.
562 */
563 /* read or write error */
564 if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
565 buffer_shutr(req);
566 buffer_shutw(rep);
567 fd_delete(t->cli_fd);
568 t->cli_state = CL_STCLOSE;
569 if (!(t->flags & SN_ERR_MASK))
570 t->flags |= SN_ERR_CLICL;
571 if (!(t->flags & SN_FINST_MASK)) {
572 if (t->pend_pos)
573 t->flags |= SN_FINST_Q;
574 else if (s == SV_STCONN)
575 t->flags |= SN_FINST_C;
576 else
577 t->flags |= SN_FINST_D;
578 }
579 return 1;
580 }
581 /* last read, or end of server write */
582 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
583 EV_FD_CLR(t->cli_fd, DIR_RD);
584 buffer_shutr(req);
585 t->cli_state = CL_STSHUTR;
586 return 1;
587 }
588 /* last server read and buffer empty */
589 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
590 EV_FD_CLR(t->cli_fd, DIR_WR);
591 buffer_shutw(rep);
592 shutdown(t->cli_fd, SHUT_WR);
593 /* We must ensure that the read part is still alive when switching
594 * to shutw */
595 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200596 req->rex = tick_add_ifset(now_ms, req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200597 t->cli_state = CL_STSHUTW;
598 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
599 return 1;
600 }
601 /* read timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200602 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200603 EV_FD_CLR(t->cli_fd, DIR_RD);
604 buffer_shutr(req);
605 t->cli_state = CL_STSHUTR;
606 if (!(t->flags & SN_ERR_MASK))
607 t->flags |= SN_ERR_CLITO;
608 if (!(t->flags & SN_FINST_MASK)) {
609 if (t->pend_pos)
610 t->flags |= SN_FINST_Q;
611 else if (s == SV_STCONN)
612 t->flags |= SN_FINST_C;
613 else
614 t->flags |= SN_FINST_D;
615 }
616 return 1;
617 }
618 /* write timeout */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200619 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200620 EV_FD_CLR(t->cli_fd, DIR_WR);
621 buffer_shutw(rep);
622 shutdown(t->cli_fd, SHUT_WR);
623 /* We must ensure that the read part is still alive when switching
624 * to shutw */
625 EV_FD_SET(t->cli_fd, DIR_RD);
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200626 req->rex = tick_add_ifset(now_ms, req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200627
628 t->cli_state = CL_STSHUTW;
629 if (!(t->flags & SN_ERR_MASK))
630 t->flags |= SN_ERR_CLITO;
631 if (!(t->flags & SN_FINST_MASK)) {
632 if (t->pend_pos)
633 t->flags |= SN_FINST_Q;
634 else if (s == SV_STCONN)
635 t->flags |= SN_FINST_C;
636 else
637 t->flags |= SN_FINST_D;
638 }
639 return 1;
640 }
641
642 if (req->l >= req->rlim - req->data) {
643 /* no room to read more data */
644 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
645 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200646 req->rex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200647 }
648 } else {
649 /* there's still some space in the buffer */
650 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200651 if (!req->rto ||
652 (t->srv_state < SV_STDATA && req->wto))
Willy Tarreau92fb9832007-10-16 17:34:28 +0200653 /* If the client has no timeout, or if the server not ready yet, and we
654 * know for sure that it can expire, then it's cleaner to disable the
655 * timeout on the client side so that too low values cannot make the
656 * sessions abort too early.
657 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200658 req->rex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200659 else
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200660 req->rex = tick_add(now_ms, req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200661 }
662 }
663
664 if ((rep->l == 0) ||
665 ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) {
666 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
667 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200668 rep->wex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200669 }
670 } else {
671 /* buffer not empty */
672 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
673 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200674 rep->wex = tick_add_ifset(now_ms, rep->wto);
675 if (rep->wex) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200676 /* FIXME: to prevent the client from expiring read timeouts during writes,
677 * we refresh it. */
678 req->rex = rep->wex;
679 }
Willy Tarreau92fb9832007-10-16 17:34:28 +0200680 }
681 }
682 return 0; /* other cases change nothing */
683 }
684 else if (c == CL_STSHUTR) {
685 if (rep->flags & BF_WRITE_ERROR) {
686 buffer_shutw(rep);
687 fd_delete(t->cli_fd);
688 t->cli_state = CL_STCLOSE;
689 if (!(t->flags & SN_ERR_MASK))
690 t->flags |= SN_ERR_CLICL;
691 if (!(t->flags & SN_FINST_MASK)) {
692 if (t->pend_pos)
693 t->flags |= SN_FINST_Q;
694 else if (s == SV_STCONN)
695 t->flags |= SN_FINST_C;
696 else
697 t->flags |= SN_FINST_D;
698 }
699 return 1;
700 }
701 else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) {
702 buffer_shutw(rep);
703 fd_delete(t->cli_fd);
704 t->cli_state = CL_STCLOSE;
705 return 1;
706 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200707 else if (tick_is_expired(rep->wex, now_ms)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200708 buffer_shutw(rep);
709 fd_delete(t->cli_fd);
710 t->cli_state = CL_STCLOSE;
711 if (!(t->flags & SN_ERR_MASK))
712 t->flags |= SN_ERR_CLITO;
713 if (!(t->flags & SN_FINST_MASK)) {
714 if (t->pend_pos)
715 t->flags |= SN_FINST_Q;
716 else if (s == SV_STCONN)
717 t->flags |= SN_FINST_C;
718 else
719 t->flags |= SN_FINST_D;
720 }
721 return 1;
722 }
723
724 if (rep->l == 0) {
725 if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
726 /* stop writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200727 rep->wex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200728 }
729 } else {
730 /* buffer not empty */
731 if (EV_FD_COND_S(t->cli_fd, DIR_WR)) {
732 /* restart writing */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200733 rep->wex = tick_add_ifset(now_ms, rep->wto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200734 }
735 }
736 return 0;
737 }
738 else if (c == CL_STSHUTW) {
739 if (req->flags & BF_READ_ERROR) {
740 buffer_shutr(req);
741 fd_delete(t->cli_fd);
742 t->cli_state = CL_STCLOSE;
743 if (!(t->flags & SN_ERR_MASK))
744 t->flags |= SN_ERR_CLICL;
745 if (!(t->flags & SN_FINST_MASK)) {
746 if (t->pend_pos)
747 t->flags |= SN_FINST_Q;
748 else if (s == SV_STCONN)
749 t->flags |= SN_FINST_C;
750 else
751 t->flags |= SN_FINST_D;
752 }
753 return 1;
754 }
755 else if (req->flags & BF_READ_NULL || s == SV_STSHUTW || s == SV_STCLOSE) {
756 buffer_shutr(req);
757 fd_delete(t->cli_fd);
758 t->cli_state = CL_STCLOSE;
759 return 1;
760 }
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200761 else if (tick_is_expired(req->rex, now_ms)) {
Willy Tarreau92fb9832007-10-16 17:34:28 +0200762 buffer_shutr(req);
763 fd_delete(t->cli_fd);
764 t->cli_state = CL_STCLOSE;
765 if (!(t->flags & SN_ERR_MASK))
766 t->flags |= SN_ERR_CLITO;
767 if (!(t->flags & SN_FINST_MASK)) {
768 if (t->pend_pos)
769 t->flags |= SN_FINST_Q;
770 else if (s == SV_STCONN)
771 t->flags |= SN_FINST_C;
772 else
773 t->flags |= SN_FINST_D;
774 }
775 return 1;
776 }
777 else if (req->l >= req->rlim - req->data) {
778 /* no room to read more data */
779
780 /* FIXME-20050705: is it possible for a client to maintain a session
781 * after the timeout by sending more data after it receives a close ?
782 */
783
784 if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
785 /* stop reading until we get some space */
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200786 req->rex = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +0200787 }
788 } else {
789 /* there's still some space in the buffer */
790 if (EV_FD_COND_S(t->cli_fd, DIR_RD)) {
Willy Tarreau0c303ee2008-07-07 00:09:58 +0200791 req->rex = tick_add_ifset(now_ms, req->rto);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200792 }
793 }
794 return 0;
795 }
796 else { /* CL_STCLOSE: nothing to do */
797 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
798 int len;
799 len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be?t->be->id:"",
800 (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
801 write(1, trash, len);
802 }
803 return 0;
804 }
805 return 0;
806}
807
808#if 0
809 /* FIXME! This part has not been completely converted yet, and it may
810 * still be very specific to TCPv4 ! Also, it relies on some parameters
811 * such as conn_retries which are not set upon accept().
812 */
813/*
814 * Manages the server FSM and its socket. It returns 1 if a state has changed
815 * (and a resync may be needed), otherwise 0.
816 */
817static int process_uxst_srv(struct session *t)
818{
819 int s = t->srv_state;
820 int c = t->cli_state;
821 struct buffer *req = t->req;
822 struct buffer *rep = t->rep;
823 int conn_err;
824
825 if (s == SV_STIDLE) {
826 if (c == CL_STCLOSE || c == CL_STSHUTW ||
827 (c == CL_STSHUTR &&
828 (t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
829 tv_eternity(&req->cex);
830 if (t->pend_pos)
831 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
832 srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C);
833 return 1;
834 }
835 else {
836 /* FIXME: reimplement the TARPIT check here */
837
838 /* Right now, we will need to create a connection to the server.
839 * We might already have tried, and got a connection pending, in
840 * which case we will not do anything till it's pending. It's up
841 * to any other session to release it and wake us up again.
842 */
843 if (t->pend_pos) {
844 if (!tv_isle(&req->cex, &now))
845 return 0;
846 else {
847 /* we've been waiting too long here */
848 tv_eternity(&req->cex);
849 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
850 srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q);
851 if (t->srv)
852 t->srv->failed_conns++;
853 if (t->fe)
854 t->fe->failed_conns++;
855 return 1;
856 }
857 }
858
859 do {
860 /* first, get a connection */
861 if (srv_redispatch_connect(t))
862 return t->srv_state != SV_STIDLE;
863
864 /* try to (re-)connect to the server, and fail if we expire the
865 * number of retries.
866 */
867 if (srv_retryable_connect(t)) {
868 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
869 return t->srv_state != SV_STIDLE;
870 }
871 } while (1);
872 }
873 }
874 else if (s == SV_STCONN) { /* connection in progress */
875 if (c == CL_STCLOSE || c == CL_STSHUTW ||
876 (c == CL_STSHUTR &&
877 ((t->req->l == 0 && !(req->flags & BF_WRITE_STATUS)) ||
878 t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
879 tv_eternity(&req->cex);
880 fd_delete(t->srv_fd);
881 if (t->srv)
882 t->srv->cur_sess--;
883
884 srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C);
885 return 1;
886 }
887 if (!(req->flags & BF_WRITE_STATUS) && !tv_isle(&req->cex, &now)) {
888 //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);
889 return 0; /* nothing changed */
890 }
891 else if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
892 /* timeout, asynchronous connect error or first write error */
893 //fprintf(stderr,"2: c=%d, s=%d\n", c, s);
894
895 fd_delete(t->srv_fd);
896 if (t->srv)
897 t->srv->cur_sess--;
898
899 if (!(req->flags & BF_WRITE_STATUS))
900 conn_err = SN_ERR_SRVTO; // it was a connect timeout.
901 else
902 conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
903
904 /* ensure that we have enough retries left */
905 if (srv_count_retry_down(t, conn_err))
906 return 1;
907
908 if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
909 /* We're on our last chance, and the REDISP option was specified.
910 * We will ignore cookie and force to balance or use the dispatcher.
911 */
912 /* let's try to offer this slot to anybody */
913 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +0200914 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +0200915
916 if (t->srv)
917 t->srv->failed_conns++;
918 t->be->failed_conns++;
919
920 t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
921 t->srv = NULL; /* it's left to the dispatcher to choose a server */
922
923 /* first, get a connection */
924 if (srv_redispatch_connect(t))
925 return t->srv_state != SV_STIDLE;
926 }
927
928 do {
929 /* Now we will try to either reconnect to the same server or
930 * connect to another server. If the connection gets queued
931 * because all servers are saturated, then we will go back to
932 * the SV_STIDLE state.
933 */
934 if (srv_retryable_connect(t)) {
935 t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
936 return t->srv_state != SV_STCONN;
937 }
938
939 /* we need to redispatch the connection to another server */
940 if (srv_redispatch_connect(t))
941 return t->srv_state != SV_STCONN;
942 } while (1);
943 }
944 else { /* no error or write 0 */
945 t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
946
947 //fprintf(stderr,"3: c=%d, s=%d\n", c, s);
948 if (req->l == 0) /* nothing to write */ {
949 EV_FD_CLR(t->srv_fd, DIR_WR);
950 tv_eternity(&req->wex);
951 } else /* need the right to write */ {
952 EV_FD_SET(t->srv_fd, DIR_WR);
953 if (tv_add_ifset(&req->wex, &now, &req->wto)) {
954 /* FIXME: to prevent the server from expiring read timeouts during writes,
955 * we refresh it. */
956 rep->rex = req->wex;
957 }
958 else
959 tv_eternity(&req->wex);
960 }
961
962 EV_FD_SET(t->srv_fd, DIR_RD);
963 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
964 tv_eternity(&rep->rex);
965
966 t->srv_state = SV_STDATA;
967 if (t->srv)
968 t->srv->cum_sess++;
969 rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */
970
971 /* if the user wants to log as soon as possible, without counting
972 bytes from the server, then this is the right moment. */
973 if (t->fe && t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
974 t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
975 //uxst_sess_log(t);
976 }
977 tv_eternity(&req->cex);
978 return 1;
979 }
980 }
981 else if (s == SV_STDATA) {
982 /* read or write error */
983 if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
984 buffer_shutr(rep);
985 buffer_shutw(req);
986 fd_delete(t->srv_fd);
987 if (t->srv) {
988 t->srv->cur_sess--;
989 t->srv->failed_resp++;
990 }
991 t->be->failed_resp++;
992 t->srv_state = SV_STCLOSE;
993 if (!(t->flags & SN_ERR_MASK))
994 t->flags |= SN_ERR_SRVCL;
995 if (!(t->flags & SN_FINST_MASK))
996 t->flags |= SN_FINST_D;
997 /* We used to have a free connection slot. Since we'll never use it,
998 * we have to inform the server that it may be used by another session.
999 */
1000 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001001 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001002
1003 return 1;
1004 }
1005 /* last read, or end of client write */
1006 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
1007 EV_FD_CLR(t->srv_fd, DIR_RD);
1008 buffer_shutr(rep);
1009 t->srv_state = SV_STSHUTR;
1010 //fprintf(stderr,"%p:%s(%d), c=%d, s=%d\n", t, __FUNCTION__, __LINE__, t->cli_state, t->cli_state);
1011 return 1;
1012 }
1013 /* end of client read and no more data to send */
1014 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
1015 EV_FD_CLR(t->srv_fd, DIR_WR);
1016 buffer_shutw(req);
1017 shutdown(t->srv_fd, SHUT_WR);
1018 /* We must ensure that the read part is still alive when switching
1019 * to shutw */
1020 EV_FD_SET(t->srv_fd, DIR_RD);
1021 tv_add_ifset(&rep->rex, &now, &rep->rto);
1022
1023 t->srv_state = SV_STSHUTW;
1024 return 1;
1025 }
1026 /* read timeout */
1027 else if (tv_isle(&rep->rex, &now)) {
1028 EV_FD_CLR(t->srv_fd, DIR_RD);
1029 buffer_shutr(rep);
1030 t->srv_state = SV_STSHUTR;
1031 if (!(t->flags & SN_ERR_MASK))
1032 t->flags |= SN_ERR_SRVTO;
1033 if (!(t->flags & SN_FINST_MASK))
1034 t->flags |= SN_FINST_D;
1035 return 1;
1036 }
1037 /* write timeout */
1038 else if (tv_isle(&req->wex, &now)) {
1039 EV_FD_CLR(t->srv_fd, DIR_WR);
1040 buffer_shutw(req);
1041 shutdown(t->srv_fd, SHUT_WR);
1042 /* We must ensure that the read part is still alive when switching
1043 * to shutw */
1044 EV_FD_SET(t->srv_fd, DIR_RD);
1045 tv_add_ifset(&rep->rex, &now, &rep->rto);
1046 t->srv_state = SV_STSHUTW;
1047 if (!(t->flags & SN_ERR_MASK))
1048 t->flags |= SN_ERR_SRVTO;
1049 if (!(t->flags & SN_FINST_MASK))
1050 t->flags |= SN_FINST_D;
1051 return 1;
1052 }
1053
1054 /* recompute request time-outs */
1055 if (req->l == 0) {
1056 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
1057 /* stop writing */
1058 tv_eternity(&req->wex);
1059 }
1060 }
1061 else { /* buffer not empty, there are still data to be transferred */
1062 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
1063 /* restart writing */
1064 if (tv_add_ifset(&req->wex, &now, &req->wto)) {
1065 /* FIXME: to prevent the server from expiring read timeouts during writes,
1066 * we refresh it. */
1067 rep->rex = req->wex;
1068 }
1069 else
1070 tv_eternity(&req->wex);
1071 }
1072 }
1073
1074 /* recompute response time-outs */
1075 if (rep->l == BUFSIZE) { /* no room to read more data */
1076 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
1077 tv_eternity(&rep->rex);
1078 }
1079 }
1080 else {
1081 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
1082 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
1083 tv_eternity(&rep->rex);
1084 }
1085 }
1086
1087 return 0; /* other cases change nothing */
1088 }
1089 else if (s == SV_STSHUTR) {
1090 if (req->flags & BF_WRITE_ERROR) {
1091 //EV_FD_CLR(t->srv_fd, DIR_WR);
1092 buffer_shutw(req);
1093 fd_delete(t->srv_fd);
1094 if (t->srv) {
1095 t->srv->cur_sess--;
1096 t->srv->failed_resp++;
1097 }
1098 t->be->failed_resp++;
1099 //close(t->srv_fd);
1100 t->srv_state = SV_STCLOSE;
1101 if (!(t->flags & SN_ERR_MASK))
1102 t->flags |= SN_ERR_SRVCL;
1103 if (!(t->flags & SN_FINST_MASK))
1104 t->flags |= SN_FINST_D;
1105 /* We used to have a free connection slot. Since we'll never use it,
1106 * we have to inform the server that it may be used by another session.
1107 */
1108 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001109 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001110
1111 return 1;
1112 }
1113 else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) {
1114 //EV_FD_CLR(t->srv_fd, DIR_WR);
1115 buffer_shutw(req);
1116 fd_delete(t->srv_fd);
1117 if (t->srv)
1118 t->srv->cur_sess--;
1119 //close(t->srv_fd);
1120 t->srv_state = SV_STCLOSE;
1121 /* We used to have a free connection slot. Since we'll never use it,
1122 * we have to inform the server that it may be used by another session.
1123 */
1124 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001125 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001126
1127 return 1;
1128 }
1129 else if (tv_isle(&req->wex, &now)) {
1130 //EV_FD_CLR(t->srv_fd, DIR_WR);
1131 buffer_shutw(req);
1132 fd_delete(t->srv_fd);
1133 if (t->srv)
1134 t->srv->cur_sess--;
1135 //close(t->srv_fd);
1136 t->srv_state = SV_STCLOSE;
1137 if (!(t->flags & SN_ERR_MASK))
1138 t->flags |= SN_ERR_SRVTO;
1139 if (!(t->flags & SN_FINST_MASK))
1140 t->flags |= SN_FINST_D;
1141 /* We used to have a free connection slot. Since we'll never use it,
1142 * we have to inform the server that it may be used by another session.
1143 */
1144 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001145 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001146
1147 return 1;
1148 }
1149 else if (req->l == 0) {
1150 if (EV_FD_COND_C(t->srv_fd, DIR_WR)) {
1151 /* stop writing */
1152 tv_eternity(&req->wex);
1153 }
1154 }
1155 else { /* buffer not empty */
1156 if (EV_FD_COND_S(t->srv_fd, DIR_WR)) {
1157 /* restart writing */
1158 if (!tv_add_ifset(&req->wex, &now, &req->wto))
1159 tv_eternity(&req->wex);
1160 }
1161 }
1162 return 0;
1163 }
1164 else if (s == SV_STSHUTW) {
1165 if (rep->flags & BF_READ_ERROR) {
1166 //EV_FD_CLR(t->srv_fd, DIR_RD);
1167 buffer_shutr(rep);
1168 fd_delete(t->srv_fd);
1169 if (t->srv) {
1170 t->srv->cur_sess--;
1171 t->srv->failed_resp++;
1172 }
1173 t->be->failed_resp++;
1174 //close(t->srv_fd);
1175 t->srv_state = SV_STCLOSE;
1176 if (!(t->flags & SN_ERR_MASK))
1177 t->flags |= SN_ERR_SRVCL;
1178 if (!(t->flags & SN_FINST_MASK))
1179 t->flags |= SN_FINST_D;
1180 /* We used to have a free connection slot. Since we'll never use it,
1181 * we have to inform the server that it may be used by another session.
1182 */
1183 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001184 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001185
1186 return 1;
1187 }
1188 else if (rep->flags & BF_READ_NULL || c == CL_STSHUTW || c == CL_STCLOSE) {
1189 //EV_FD_CLR(t->srv_fd, DIR_RD);
1190 buffer_shutr(rep);
1191 fd_delete(t->srv_fd);
1192 if (t->srv)
1193 t->srv->cur_sess--;
1194 //close(t->srv_fd);
1195 t->srv_state = SV_STCLOSE;
1196 /* We used to have a free connection slot. Since we'll never use it,
1197 * we have to inform the server that it may be used by another session.
1198 */
1199 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001200 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001201
1202 return 1;
1203 }
1204 else if (tv_isle(&rep->rex, &now)) {
1205 //EV_FD_CLR(t->srv_fd, DIR_RD);
1206 buffer_shutr(rep);
1207 fd_delete(t->srv_fd);
1208 if (t->srv)
1209 t->srv->cur_sess--;
1210 //close(t->srv_fd);
1211 t->srv_state = SV_STCLOSE;
1212 if (!(t->flags & SN_ERR_MASK))
1213 t->flags |= SN_ERR_SRVTO;
1214 if (!(t->flags & SN_FINST_MASK))
1215 t->flags |= SN_FINST_D;
1216 /* We used to have a free connection slot. Since we'll never use it,
1217 * we have to inform the server that it may be used by another session.
1218 */
1219 if (may_dequeue_tasks(t->srv, t->be))
Willy Tarreau7c669d72008-06-20 15:04:11 +02001220 process_srv_queue(t->srv);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001221
1222 return 1;
1223 }
1224 else if (rep->l == BUFSIZE) { /* no room to read more data */
1225 if (EV_FD_COND_C(t->srv_fd, DIR_RD)) {
1226 tv_eternity(&rep->rex);
1227 }
1228 }
1229 else {
1230 if (EV_FD_COND_S(t->srv_fd, DIR_RD)) {
1231 if (!tv_add_ifset(&rep->rex, &now, &rep->rto))
1232 tv_eternity(&rep->rex);
1233 }
1234 }
1235 return 0;
1236 }
1237 else { /* SV_STCLOSE : nothing to do */
1238 if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
1239 int len;
1240 len = sprintf(trash, "%08x:%s.srvcls[%04x:%04x]\n",
1241 t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)t->srv_fd);
1242 write(1, trash, len);
1243 }
1244 return 0;
1245 }
1246 return 0;
1247}
1248
1249/* Processes the client and server jobs of a session task, then
1250 * puts it back to the wait queue in a clean state, or
1251 * cleans up its resources if it must be deleted. Returns
1252 * the time the task accepts to wait, or TIME_ETERNITY for
1253 * infinity.
1254 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001255void process_uxst_session(struct task *t, int *next)
Willy Tarreau92fb9832007-10-16 17:34:28 +02001256{
1257 struct session *s = t->context;
1258 int fsm_resync = 0;
1259
1260 do {
1261 fsm_resync = 0;
1262 fsm_resync |= process_uxst_cli(s);
1263 if (s->srv_state == SV_STIDLE) {
1264 if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) {
1265 s->srv_state = SV_STCLOSE;
1266 fsm_resync |= 1;
1267 continue;
1268 }
1269 if (s->cli_state == CL_STSHUTR ||
1270 (s->req->l >= s->req->rlim - s->req->data)) {
1271 if (s->req->l == 0) {
1272 s->srv_state = SV_STCLOSE;
1273 fsm_resync |= 1;
1274 continue;
1275 }
1276 /* OK we have some remaining data to process */
1277 /* Just as an exercice, we copy the req into the resp,
1278 * and flush the req.
1279 */
1280 memcpy(s->rep->data, s->req->data, sizeof(s->rep->data));
1281 s->rep->l = s->req->l;
1282 s->rep->rlim = s->rep->data + BUFSIZE;
1283 s->rep->w = s->rep->data;
1284 s->rep->lr = s->rep->r = s->rep->data + s->rep->l;
1285
1286 s->req->l = 0;
1287 s->srv_state = SV_STCLOSE;
1288
1289 fsm_resync |= 1;
1290 continue;
1291 }
1292 }
1293 } while (fsm_resync);
1294
1295 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +01001296
1297 if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
1298 session_process_counters(s);
1299
Willy Tarreau92fb9832007-10-16 17:34:28 +02001300 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1301 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1302
1303 t->expire = s->req->rex;
1304 tv_min(&t->expire, &s->req->rex, &s->req->wex);
1305 tv_bound(&t->expire, &s->req->cex);
1306 tv_bound(&t->expire, &s->rep->rex);
1307 tv_bound(&t->expire, &s->rep->wex);
1308
1309 /* restore t to its place in the task list */
1310 task_queue(t);
1311
1312 *next = t->expire;
1313 return; /* nothing more to do */
1314 }
1315
1316 if (s->fe)
1317 s->fe->feconn--;
1318 if (s->be && (s->flags & SN_BE_ASSIGNED))
1319 s->be->beconn--;
1320 actconn--;
1321
1322 if (unlikely((global.mode & MODE_DEBUG) &&
1323 (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
1324 int len;
1325 len = sprintf(trash, "%08x:%s.closed[%04x:%04x]\n",
1326 s->uniq_id, s->be->id,
1327 (unsigned short)s->cli_fd, (unsigned short)s->srv_fd);
1328 write(1, trash, len);
1329 }
1330
1331 s->logs.t_close = tv_ms_elapsed(&s->logs.tv_accept, &now);
Krzysztof Piotr Oledzki583bc962007-11-24 22:12:47 +01001332 session_process_counters(s);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001333
1334 /* let's do a final log if we need it */
1335 if (s->logs.logwait &&
1336 !(s->flags & SN_MONITOR) &&
1337 (s->req->total || !(s->fe && s->fe->options & PR_O_NULLNOLOG))) {
1338 //uxst_sess_log(s);
1339 }
1340
1341 /* the task MUST not be in the run queue anymore */
1342 task_delete(t);
1343 session_free(s);
1344 task_free(t);
1345 tv_eternity(next);
1346}
1347#endif /* not converted */
1348
1349
1350/* Processes data exchanges on the statistics socket. The client processing
1351 * is called and the task is put back in the wait queue or it is cleared.
1352 * In order to ease the transition, we simply simulate the server status
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001353 * for now. It only knows states SV_STIDLE, SV_STCONN, SV_STDATA, and
1354 * SV_STCLOSE. Returns in <next> the task's expiration date.
Willy Tarreau92fb9832007-10-16 17:34:28 +02001355 */
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001356void process_uxst_stats(struct task *t, int *next)
Willy Tarreau92fb9832007-10-16 17:34:28 +02001357{
1358 struct session *s = t->context;
1359 struct listener *listener;
1360 int fsm_resync = 0;
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001361 int last_rep_l;
Willy Tarreau92fb9832007-10-16 17:34:28 +02001362
1363 do {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001364 char *args[MAX_UXST_ARGS + 1];
1365 char *line, *p;
1366 int arg;
1367
Willy Tarreau3e76e722007-10-17 18:57:38 +02001368 fsm_resync = process_uxst_cli(s);
Willy Tarreau3e76e722007-10-17 18:57:38 +02001369
1370 if (s->cli_state == CL_STCLOSE || s->cli_state == CL_STSHUTW) {
1371 s->srv_state = SV_STCLOSE;
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001372 break;
Willy Tarreau3e76e722007-10-17 18:57:38 +02001373 }
1374
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001375 switch (s->srv_state) {
1376 case SV_STIDLE:
1377 /* stats output not initialized yet */
1378 memset(&s->data_ctx.stats, 0, sizeof(s->data_ctx.stats));
1379 s->data_source = DATA_SRC_STATS;
1380 s->srv_state = SV_STCONN;
1381 fsm_resync |= 1;
1382 break;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001383
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001384 case SV_STCONN: /* will change to SV_STANALYZE */
1385 /* stats initialized, but waiting for the command */
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001386 line = s->req->data;
1387 p = memchr(line, '\n', s->req->l);
1388
1389 if (!p)
1390 continue;
1391
1392 *p = '\0';
1393
1394 while (isspace((unsigned char)*line))
1395 line++;
1396
1397 arg = 0;
1398 args[arg] = line;
1399
1400 while (*line && arg < MAX_UXST_ARGS) {
1401 if (isspace((unsigned char)*line)) {
1402 *line++ = '\0';
1403
1404 while (isspace((unsigned char)*line))
1405 line++;
1406
1407 args[++arg] = line;
Willy Tarreaua8efd362008-01-03 10:19:15 +01001408 continue;
1409 }
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001410
1411 line++;
Willy Tarreaua8efd362008-01-03 10:19:15 +01001412 }
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001413
1414 while (++arg <= MAX_UXST_ARGS)
1415 args[arg] = line;
1416
1417 if (!strcmp(args[0], "show")) {
1418 if (!strcmp(args[1], "stat")) {
1419 if (*args[2] && *args[3] && *args[4]) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001420 s->data_ctx.stats.flags |= STAT_BOUND;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001421 s->data_ctx.stats.iid = atoi(args[2]);
1422 s->data_ctx.stats.type = atoi(args[3]);
1423 s->data_ctx.stats.sid = atoi(args[4]);
1424 }
1425
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001426 s->data_ctx.stats.flags |= STAT_SHOW_STAT;
1427 s->data_ctx.stats.flags |= STAT_FMT_CSV;
1428 s->srv_state = SV_STDATA;
1429 fsm_resync |= 1;
Willy Tarreau92fb9832007-10-16 17:34:28 +02001430 continue;
1431 }
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001432
1433 if (!strcmp(args[1], "info")) {
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001434 s->data_ctx.stats.flags |= STAT_SHOW_INFO;
1435 s->data_ctx.stats.flags |= STAT_FMT_CSV;
1436 s->srv_state = SV_STDATA;
1437 fsm_resync |= 1;
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001438 continue;
1439 }
Willy Tarreau92fb9832007-10-16 17:34:28 +02001440 }
Willy Tarreau3e76e722007-10-17 18:57:38 +02001441
Krzysztof Piotr Oledzki2c6962c2008-03-02 02:42:14 +01001442 s->srv_state = SV_STCLOSE;
1443 fsm_resync |= 1;
Willy Tarreau3e76e722007-10-17 18:57:38 +02001444 continue;
1445
Willy Tarreau39f7e6d2008-03-17 21:38:24 +01001446 case SV_STDATA:
1447 /* OK we have to process the request. Since it is possible
1448 * that we get there with the client output paused, we
1449 * will simply check that we have really sent some data
1450 * and wake the client up if needed.
1451 */
1452 last_rep_l = s->rep->l;
1453 if (stats_dump_raw(s, NULL) != 0) {
1454 s->srv_state = SV_STCLOSE;
1455 fsm_resync |= 1;
1456 }
1457 if (s->rep->l != last_rep_l)
1458 fsm_resync |= 1;
1459 break;
Willy Tarreau3e76e722007-10-17 18:57:38 +02001460 }
Willy Tarreau92fb9832007-10-16 17:34:28 +02001461 } while (fsm_resync);
1462
1463 if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
1464 s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1465 s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE;
1466
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001467 t->expire = tick_first(tick_first(s->req->rex, s->req->wex),
1468 tick_first(s->rep->rex, s->rep->wex));
1469 t->expire = tick_first(t->expire, s->req->cex);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001470
1471 /* restore t to its place in the task list */
1472 task_queue(t);
1473
1474 *next = t->expire;
1475 return; /* nothing more to do */
1476 }
1477
1478 actconn--;
1479 listener = fdtab[s->cli_fd].listener;
1480 if (listener) {
1481 listener->nbconn--;
1482 if (listener->state == LI_FULL &&
1483 listener->nbconn < listener->maxconn) {
1484 /* we should reactivate the listener */
1485 EV_FD_SET(listener->fd, DIR_RD);
1486 listener->state = LI_READY;
1487 }
1488 }
1489
1490 /* the task MUST not be in the run queue anymore */
1491 task_delete(t);
1492 session_free(s);
1493 task_free(t);
Willy Tarreau0c303ee2008-07-07 00:09:58 +02001494 *next = TICK_ETERNITY;
Willy Tarreau92fb9832007-10-16 17:34:28 +02001495}
1496
Willy Tarreau92fb9832007-10-16 17:34:28 +02001497__attribute__((constructor))
1498static void __uxst_protocol_init(void)
1499{
1500 protocol_register(&proto_unix);
Willy Tarreau92fb9832007-10-16 17:34:28 +02001501}
1502
1503
1504/*
1505 * Local variables:
1506 * c-indent-level: 8
1507 * c-basic-offset: 8
1508 * End:
1509 */