~ubuntu-branches/ubuntu/intrepid/haproxy/intrepid

« back to all changes in this revision

Viewing changes to src/proto_uxst.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Cornet
  • Date: 2008-03-09 21:30:29 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080309213029-8oupnrc607mg5uqw
Tags: 1.3.14.3-1
* New Upstream Version
* Add status argument support to init-script to conform to LSB.
* Cleanup pidfile after stop in init script. Init script return code fixups.

Show diffs side-by-side

added added

removed removed

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