vinyl-cache/bin/vinyld/cache/cache_session.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 * Session management
31
 *
32
 * The overall goal here is to hold as little state as possible for an
33
 * idle session.  This leads to various nasty-ish overloads of struct
34
 * sess fields, for instance ->fd being negative ->reason.
35
 *
36
 */
37
//lint --e{766}
38
39
#include "config.h"
40
41
#include "cache_int.h"
42
43
#include <stdio.h>
44
#include <stdlib.h>
45
46
#include "cache_pool.h"
47
#include "cache_transport.h"
48
49
#include "vsa.h"
50
#include "vtcp.h"
51
#include "vtim.h"
52
#include "waiter/waiter.h"
53
54
static const struct {
55
        const char              *type;
56
} sess_attr[SA_LAST] = {
57
#define SESS_ATTR(UC, lc, typ, len) [SA_##UC] = { #typ },
58
#include "tbl/sess_attr.h"
59
};
60
61
enum sess_close {
62
        SCE_NULL = 0,
63
#define SESS_CLOSE_C(nm, stat, err, desc) SCE_##nm,
64
#include "tbl/sess_close.h"
65
        SCE_MAX,
66
};
67
68
const struct stream_close SC_NULL[1] = {{
69
        .magic = STREAM_CLOSE_MAGIC,
70
        .idx = SCE_NULL,
71
        .is_err = 0,
72
        .name = "null",
73
        .desc = "Not Closing",
74
}};
75
76
#define SESS_CLOSE_C(nm, stat, err, text) \
77
        const struct stream_close SC_##nm[1] = {{ \
78
                .magic = STREAM_CLOSE_MAGIC, \
79
                .idx = SCE_##nm, \
80
                .is_err = err, \
81
                .name = #nm, \
82
                .desc = text, \
83
        }};
84
#include "tbl/sess_close.h"
85
86
static const stream_close_t sc_lookup[SCE_MAX] = {
87
        [SCE_NULL] = SC_NULL,
88
#define SESS_CLOSE_C(nm, stat, err, desc) \
89
        [SCE_##nm] = SC_##nm,
90
#include "tbl/sess_close.h"
91
};
92
93
/*--------------------------------------------------------------------*/
94
95
void
96 53692
SES_SetTransport(struct worker *wrk, struct sess *sp, struct req *req,
97
    const struct transport *xp)
98
{
99
100 53692
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
101 53692
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
102 53692
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
103 53692
        CHECK_OBJ_NOTNULL(xp, TRANSPORT_MAGIC);
104 53692
        assert(xp->number > 0);
105
106 53692
        sp->sattr[SA_TRANSPORT] = xp->number;
107 53692
        req->transport = xp;
108 53692
        wrk->task->func = xp->new_session;
109 53692
        wrk->task->priv = req;
110 53692
}
111
112
/*--------------------------------------------------------------------*/
113
114
#define SES_NOATTR_OFFSET 0xffff
115
116
static int
117 569014
ses_get_attr(const struct sess *sp, enum sess_attr a, void **dst)
118
{
119 569014
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
120 569014
        assert(a < SA_LAST);
121 569014
        AN(dst);
122
123 569014
        if (sp->sattr[a] == SES_NOATTR_OFFSET) {
124 48664
                *dst = NULL;
125 48664
                return (-1);
126
        }
127 520350
        *dst = WS_AtOffset(sp->ws, sp->sattr[a], 0);
128 520350
        return (0);
129 569014
}
130
131
static int
132 279623
ses_set_attr(const struct sess *sp, enum sess_attr a, const void *src, int sz)
133
{
134
        void *dst;
135 279623
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
136 279623
        assert(a < SA_LAST);
137 279623
        AN(src);
138 279623
        assert(sz > 0);
139
140 279623
        if (sp->sattr[a] == SES_NOATTR_OFFSET)
141 0
                return (-1);
142 279623
        dst = WS_AtOffset(sp->ws, sp->sattr[a], sz);
143 279623
        AN(dst);
144 279623
        vmemcpy(dst, src, sz);
145 279623
        return (0);
146 279623
}
147
148
static int
149 242777
ses_res_attr(struct sess *sp, enum sess_attr a, void **dst, ssize_t *szp)
150
{
151
        unsigned o;
152
        ssize_t sz;
153
154 242777
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
155 242777
        assert(a < SA_LAST);
156 242777
        AN(dst);
157 242777
        sz = *szp;
158 242777
        *szp = 0;
159 242777
        assert(sz >= 0);
160 242777
        if (WS_ReserveSize(sp->ws, sz) == 0)
161 21
                return (0);
162 242756
        o = WS_ReservationOffset(sp->ws);
163 242756
        if (o >= SES_NOATTR_OFFSET) {
164 0
                WS_Release(sp->ws, 0);
165 0
                return (0);
166
        }
167 242756
        *dst = WS_Reservation(sp->ws);
168 242756
        *szp = sz;
169 242756
        sp->sattr[a] = (uint16_t)o;
170 242756
        WS_Release(sp->ws, sz);
171 242756
        return (1);
172 242777
}
173
174
#define SESS_ATTR(UP, low, typ, len)                                    \
175
        int                                                             \
176
        SES_Set_##low(const struct sess *sp, const typ *src)            \
177
        {                                                               \
178
                assert(len > 0);                                        \
179
                return (ses_set_attr(sp, SA_##UP, src, len));           \
180
        }                                                               \
181
                                                                        \
182
        int                                                             \
183
        SES_Get_##low(const struct sess *sp, typ **dst)                 \
184
        {                                                               \
185
                assert(len > 0);                                        \
186
                return (ses_get_attr(sp, SA_##UP, (void**)dst));        \
187
        }                                                               \
188
                                                                        \
189
        int                                                             \
190
        SES_Reserve_##low(struct sess *sp, typ **dst, ssize_t *sz)      \
191
        {                                                               \
192
                assert(len > 0);                                        \
193
                AN(sz);                                                 \
194
                *sz = len;                                              \
195
                return (ses_res_attr(sp, SA_##UP, (void**)dst, sz));    \
196
        }
197
198
#include "tbl/sess_attr.h"
199
200
int
201 100422
SES_Set_String_Attr(struct sess *sp, enum sess_attr a, const char *src)
202
{
203
        void *q;
204
        ssize_t l, sz;
205
206 100422
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
207 100422
        AN(src);
208
209 100422
        assert(a <  SA_LAST);
210 100422
        if (vstrcmp(sess_attr[a].type, "char"))
211 0
                WRONG("wrong sess_attr: not char");
212
213 100422
        l = sz = vstrlen(src) + 1;
214 100422
        if (! ses_res_attr(sp, a, &q, &sz))
215 0
                return (0);
216 100422
        assert(l == sz);
217 100422
        strcpy(q, src);
218 100422
        return (1);
219 100422
}
220
221
const char *
222 177092
SES_Get_String_Attr(const struct sess *sp, enum sess_attr a)
223
{
224
        void *q;
225
226 177092
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
227
228 177092
        assert(a <  SA_LAST);
229 177092
        if (vstrcmp(sess_attr[a].type, "char"))
230 0
                WRONG("wrong sess_attr: not char");
231
232 177092
        if (ses_get_attr(sp, a, &q) < 0)
233 0
                return (NULL);
234 177092
        return (q);
235 177092
}
236
237
/*--------------------------------------------------------------------*/
238
239
void
240 2352
HTC_Status(enum htc_status_e e, const char **name, const char **desc)
241
{
242
243 2352
        switch (e) {
244
#define HTC_STATUS(e, n, s, l)                          \
245
        case HTC_S_ ## e:                               \
246
                *name = s;                              \
247
                *desc = l;                              \
248
                return;
249
#include "tbl/htc.h"
250
        default:
251 0
                WRONG("HTC_Status");
252
        }
253 2352
}
254
255
/*--------------------------------------------------------------------*/
256
257
void
258 188293
HTC_RxInit(struct http_conn *htc, struct ws *ws)
259
{
260
        unsigned rollback;
261
        int l;
262
263 188293
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
264 188293
        htc->ws = ws;
265
266
        /* NB: HTTP/1 keep-alive triggers a rollback, so does the first
267
         * request of a session or an h2 request where the rollback is a
268
         * no-op in terms of workspace usage.
269
         */
270 188293
        rollback = !strcasecmp(ws->id, "req") && htc->body_status == NULL;
271 188293
        l = WS_Pipeline(htc->ws, htc->pipeline_b, htc->pipeline_e, rollback);
272 188293
        xxxassert(l >= 0);
273
274 188293
        htc->rxbuf_b = WS_Reservation(ws);
275 188293
        htc->rxbuf_e = htc->rxbuf_b + l;
276 188293
        htc->pipeline_b = NULL;
277 188293
        htc->pipeline_e = NULL;
278 188293
}
279
280
void
281 145994
HTC_RxPipeline(struct http_conn *htc, char *p)
282
{
283
284 145994
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
285 145994
        assert(p >= htc->rxbuf_b);
286 145994
        assert(p <= htc->rxbuf_e);
287 145994
        if (p == htc->rxbuf_e) {
288 109375
                htc->pipeline_b = NULL;
289 109375
                htc->pipeline_e = NULL;
290 109375
        } else {
291 36619
                htc->pipeline_b = p;
292 36619
                htc->pipeline_e = htc->rxbuf_e;
293
        }
294 145994
}
295
296
/*----------------------------------------------------------------------
297
 * Receive a request/packet/whatever, with timeouts
298
 *
299
 * maxbytes is the maximum number of bytes the caller expects to need to
300
 * reach a complete work unit. Note that due to pipelining the actual
301
 * number of bytes passed to func in htc->rxbuf_b through htc->rxbuf_e may
302
 * be larger.
303
 *
304
 * *t1 becomes time of first non-idle rx
305
 * *t2 becomes time of complete rx
306
 * ti is when we return IDLE if nothing has arrived
307
 * tn is when we timeout on non-complete (total timeout)
308
 * td is max timeout between reads
309
 */
310
311
enum htc_status_e
312 188233
HTC_RxStuff(struct http_conn *htc, htc_complete_f *func,
313
    vtim_real *t1, vtim_real *t2, vtim_real ti, vtim_real tn, vtim_dur td,
314
    int maxbytes)
315
{
316
        vtim_dur tmo;
317
        vtim_real now;
318
        enum htc_status_e hs;
319
        unsigned l, r;
320
        ssize_t z;
321
322 188233
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
323 188233
        AN(htc->rfd);
324 188233
        assert(*htc->rfd > 0);
325 188233
        AN(htc->rxbuf_b);
326 188233
        AN(WS_Reservation(htc->ws));
327
328 188233
        l = pdiff(htc->rxbuf_b, htc->rxbuf_e);
329 188233
        r = WS_ReservationSize(htc->ws);
330 188233
        assert(l <= r);
331
332 188233
        AZ(isnan(tn) && isnan(td));
333 188233
        if (t1 != NULL)
334 138752
                assert(isnan(*t1));
335
336 188233
        if (l == r) {
337
                /* Can't work with a zero size buffer */
338 63
                WS_ReleaseP(htc->ws, htc->rxbuf_b);
339 63
                return (HTC_S_OVERFLOW);
340
        }
341 188170
        z = r;
342 188170
        if (z < maxbytes)
343 2331
                maxbytes = z;   /* Cap maxbytes at available WS */
344
345 340931
        while (1) {
346 340931
                now = VTIM_real();
347 340931
                AZ(htc->pipeline_b);
348 340931
                AZ(htc->pipeline_e);
349 340931
                l = pdiff(htc->rxbuf_b, htc->rxbuf_e);
350 340931
                assert(l <= r);
351
352 340931
                hs = func(htc);
353 340931
                if (hs == HTC_S_OVERFLOW || hs == HTC_S_JUNK) {
354 105
                        WS_ReleaseP(htc->ws, htc->rxbuf_b);
355 105
                        return (hs);
356
                }
357 340826
                if (hs == HTC_S_COMPLETE) {
358 146860
                        WS_ReleaseP(htc->ws, htc->rxbuf_e);
359
                        /* Got it, run with it */
360 146860
                        if (t1 != NULL && isnan(*t1))
361 79740
                                *t1 = now;
362 146860
                        if (t2 != NULL)
363 79674
                                *t2 = now;
364 146860
                        return (HTC_S_COMPLETE);
365
                }
366 193966
                if (hs == HTC_S_MORE) {
367
                        /* Working on it */
368 30127
                        if (t1 != NULL && isnan(*t1))
369 21291
                                *t1 = now;
370 193966
                } else if (hs == HTC_S_EMPTY)
371 163839
                        htc->rxbuf_e = htc->rxbuf_b;
372
                else
373 0
                        WRONG("htc_status_e");
374
375
                // htc_complete_f can not return HTC_S_EOF
376
                //
377
                // all but HTC_S_EMPTY and HTC_S_MORE have been handled
378
379 193966
                if (hs == HTC_S_EMPTY && !isnan(ti) && (isnan(tn) || ti < tn))
380 163702
                        tmo = ti - now;
381 30264
                else if (isnan(tn))
382 874
                        tmo = td;
383 29390
                else if (isnan(td))
384 29390
                        tmo = tn - now;
385 0
                else if (td < tn - now)
386 0
                        tmo = td;
387
                else
388 0
                        tmo = tn - now;
389
390 193966
                AZ(isnan(tmo));
391 193966
                z = maxbytes - (htc->rxbuf_e - htc->rxbuf_b);
392 193966
                if (z <= 0) {
393
                        /* maxbytes reached but not HTC_S_COMPLETE. Return
394
                         * overflow. */
395 420
                        WS_ReleaseP(htc->ws, htc->rxbuf_b);
396 420
                        return (HTC_S_OVERFLOW);
397
                }
398 193546
                if (tmo <= 0.0)
399 4328
                        tmo = 1e-3;
400 193546
                z = VTCP_read(*htc->rfd, htc->rxbuf_e, z, tmo);
401 193546
                if (z == 0 || z == -1) {
402 35332
                        WS_ReleaseP(htc->ws, htc->rxbuf_b);
403 35332
                        return (HTC_S_EOF);
404 158214
                } else if (z > 0)
405 152761
                        htc->rxbuf_e += z;
406 5453
                else if (z == -2) {
407 5453
                        WS_ReleaseP(htc->ws, htc->rxbuf_b);
408 5453
                        switch (hs) {
409
                        case HTC_S_EMPTY:
410
                        case HTC_S_MORE:
411 5453
                                return (hs);
412
                        default:
413 0
                                WRONG("htc_status_e (read timeout)");
414 0
                        }
415 0
                }
416
        }
417 188233
}
418
419
/*--------------------------------------------------------------------
420
 * Get a new session, preferably by recycling an already ready one
421
 *
422
 * Layout is:
423
 *      struct sess
424
 *      workspace
425
 */
426
427
struct sess *
428 49191
SES_New(struct pool *pp)
429
{
430
        struct sess *sp;
431
        unsigned sz;
432
        char *p, *e;
433
434 49191
        CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
435 49191
        sp = MPL_Get(pp->mpl_sess, &sz);
436 49191
        AN(sp);
437 49191
        INIT_OBJ(sp, SESS_MAGIC);
438 49191
        sp->pool = pp;
439 49191
        sp->refcnt = 1;
440 49191
        memset(sp->sattr, 0xff, sizeof sp->sattr);
441
442 49191
        e = (char*)sp + sz;
443 49191
        p = (char*)(sp + 1);
444 49191
        p = (void*)PRNDUP(p);
445 49191
        assert(p < e);
446 49191
        WS_Init(sp->ws, "ses", p, e - p);
447
448 49191
        sp->t_open = NAN;
449 49191
        sp->t_idle = NAN;
450 49191
        sp->timeout_idle = NAN;
451 49191
        sp->timeout_linger = NAN;
452 49191
        sp->send_timeout = NAN;
453 49191
        sp->idle_send_timeout = NAN;
454 49191
        Lck_New(&sp->mtx, lck_sess);
455 49191
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
456 49191
        return (sp);
457
}
458
459
/*--------------------------------------------------------------------
460
 * Handle a session (from waiter)
461
 */
462
463
static void v_matchproto_(waiter_handle_f)
464 5221
ses_handle(struct waited *wp, enum wait_event ev, vtim_real now)
465
{
466
        struct sess *sp;
467
        struct pool *pp;
468
        struct pool_task *tp;
469
        const struct transport *xp;
470
471 5221
        CHECK_OBJ_NOTNULL(wp, WAITED_MAGIC);
472 5221
        CAST_OBJ_NOTNULL(sp, wp->priv1, SESS_MAGIC);
473 5221
        CAST_OBJ_NOTNULL(xp, wp->priv2, TRANSPORT_MAGIC);
474 5221
        assert(WS_Reservation(sp->ws) == wp);
475 5221
        FINI_OBJ(wp);
476
477
        /* The WS was reserved in SES_Wait() */
478 5221
        WS_Release(sp->ws, 0);
479
480 5221
        switch (ev) {
481
        case WAITER_TIMEOUT:
482 420
                SES_Delete(sp, SC_RX_CLOSE_IDLE, now);
483 420
                break;
484
        case WAITER_REMCLOSE:
485 581
                SES_Delete(sp, SC_REM_CLOSE, now);
486 581
                break;
487
        case WAITER_ACTION:
488 4220
                pp = sp->pool;
489 4220
                CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
490
                /* SES_Wait() guarantees the next will not assert. */
491 4220
                assert(sizeof *tp <= WS_ReserveSize(sp->ws, sizeof *tp));
492 4220
                tp = WS_Reservation(sp->ws);
493 4220
                tp->func = xp->unwait;
494 4220
                tp->priv = sp;
495 4220
                if (Pool_Task(pp, tp, TASK_QUEUE_REQ))
496 144
                        SES_Delete(sp, SC_OVERLOAD, now);
497 4220
                break;
498
        case WAITER_CLOSE:
499 0
                WRONG("Should not see WAITER_CLOSE on client side");
500 0
                break;
501
        default:
502 0
                WRONG("Wrong event in ses_handle");
503 0
        }
504 5221
}
505
506
/*--------------------------------------------------------------------
507
 */
508
509
void
510 5218
SES_Wait(struct sess *sp, const struct transport *xp)
511
{
512
        struct pool *pp;
513
        struct waited *wp;
514
        unsigned u;
515
516 5218
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
517 5218
        CHECK_OBJ_NOTNULL(xp, TRANSPORT_MAGIC);
518 5218
        pp = sp->pool;
519 5218
        CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
520 5218
        assert(sp->fd > 0);
521
        /*
522
         * XXX: waiter_epoll prevents us from zeroing the struct because
523
         * XXX: it keeps state across calls.
524
         */
525 5218
        VTCP_nonblocking(sp->fd);
526
527
        /*
528
         * Put struct waited on the workspace. Make sure that the
529
         * workspace can hold enough space for both struct waited
530
         * and pool_task, as pool_task will be needed when coming
531
         * off the waiter again.
532
         */
533 5218
        u = WS_ReserveAll(sp->ws);
534 5218
        if (u < sizeof (struct waited) || u < sizeof(struct pool_task)) {
535 2
                WS_MarkOverflow(sp->ws);
536 2
                SES_Delete(sp, SC_OVERLOAD, NAN);
537 2
                return;
538
        }
539
540 5218
        wp = WS_Reservation(sp->ws);
541 5218
        INIT_OBJ(wp, WAITED_MAGIC);
542 5218
        wp->fd = sp->fd;
543 5218
        wp->priv1 = sp;
544 5218
        wp->priv2 = xp;
545 5218
        wp->idle = sp->t_idle;
546 5218
        wp->func = ses_handle;
547 5218
        wp->tmo = SESS_TMO(sp, timeout_idle);
548 5218
        if (Wait_Enter(pp->waiter, wp))
549 0
                SES_Delete(sp, SC_PIPE_OVERFLOW, NAN);
550 5218
}
551
552
/*--------------------------------------------------------------------
553
 * Update sc_ counters by reason
554
 *
555
 * assuming that the approximation of non-atomic global counters is sufficient.
556
 * if not: update to per-wrk
557
 */
558
559
static void
560 49036
ses_close_acct(stream_close_t reason)
561
{
562
563 49036
        CHECK_OBJ_NOTNULL(reason, STREAM_CLOSE_MAGIC);
564 49036
        switch (reason->idx) {
565
#define SESS_CLOSE_C(reason, stat, err, desc)           \
566
        case SCE_ ## reason:                            \
567
                VSC_C_main->sc_ ## stat++;              \
568
                break;
569
#include "tbl/sess_close.h"
570
571
        default:
572 0
                WRONG("Wrong event in ses_close_acct");
573
        }
574 49036
        if (reason->is_err)
575 8170
                VSC_C_main->sess_closed_err++;
576 49036
}
577
578
/*--------------------------------------------------------------------
579
 * Close a session's connection.
580
 * XXX: Technically speaking we should catch a t_end timestamp here
581
 * XXX: for SES_Delete() to use.
582
 */
583
584
void
585 49044
SES_Close(struct sess *sp, stream_close_t reason)
586
{
587
        int i;
588
589 49044
        CHECK_OBJ_NOTNULL(reason, STREAM_CLOSE_MAGIC);
590 49044
        assert(reason->idx > 0);
591 49044
        assert(sp->fd > 0);
592 49044
        i = close(sp->fd);
593 49044
        assert(i == 0 || errno != EBADF); /* XXX EINVAL seen */
594 49044
        sp->fd = -reason->idx;
595 49044
        ses_close_acct(reason);
596 49044
}
597
598
/*--------------------------------------------------------------------
599
 * Report and dismantle a session.
600
 */
601
602
void
603 49036
SES_Delete(struct sess *sp, stream_close_t reason, vtim_real now)
604
{
605
606 49036
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
607 49036
        CHECK_OBJ_NOTNULL(reason, STREAM_CLOSE_MAGIC);
608
609 49036
        if (reason != SC_NULL)
610 37632
                SES_Close(sp, reason);
611 49036
        assert(sp->fd < 0);
612
613 49036
        if (isnan(now))
614 47889
                now = VTIM_real();
615 49036
        AZ(isnan(sp->t_open));
616 49036
        if (now < sp->t_open) {
617 0
                VSL(SLT_Debug, sp->vxid,
618
                    "Clock step (now=%f < t_open=%f)",
619 0
                    now, sp->t_open);
620 0
                if (now + cache_param->clock_step < sp->t_open)
621 0
                        WRONG("Clock step detected");
622 0
                now = sp->t_open; /* Do not log negatives */
623 0
        }
624
625 49036
        if (reason == SC_NULL) {
626 11412
                assert(sp->fd < 0 && -sp->fd < SCE_MAX);
627 11412
                reason = sc_lookup[-sp->fd];
628 11412
        }
629
630 49036
        CHECK_OBJ_NOTNULL(reason, STREAM_CLOSE_MAGIC);
631 49036
        VSL(SLT_SessClose, sp->vxid, "%s %.3f", reason->name, now - sp->t_open);
632 49036
        VSL(SLT_End, sp->vxid, "%s", "");
633 49036
        if (WS_Overflowed(sp->ws))
634 84
                VSC_C_main->ws_session_overflow++;
635 49036
        SES_Rel(sp);
636 49036
}
637
638
void
639 32707
SES_DeleteHS(struct sess *sp, enum htc_status_e hs, vtim_real now)
640
{
641
        stream_close_t reason;
642
643 32707
        switch (hs) {
644
        case HTC_S_JUNK:
645 21
                reason = SC_RX_JUNK;
646 21
                break;
647
        case HTC_S_MORE:
648 21
                reason = SC_RX_TIMEOUT;
649 21
                break;
650
        case HTC_S_OVERFLOW:
651 126
                reason = SC_RX_OVERFLOW;
652 126
                break;
653
        case HTC_S_EOF:
654 32539
                reason = SC_REM_CLOSE;
655 32539
                break;
656
        default:
657 0
                WRONG("htc_status (bad)");
658 0
        }
659 32707
        SES_Delete(sp, reason, now);
660 32707
}
661
662
663
/*--------------------------------------------------------------------
664
 */
665
666
void
667 51806
SES_Ref(struct sess *sp)
668
{
669
670 51806
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
671 51806
        Lck_Lock(&sp->mtx);
672 51806
        assert(sp->refcnt > 0);
673 51806
        sp->refcnt++;
674 51806
        Lck_Unlock(&sp->mtx);
675 51806
}
676
677
void
678 100827
SES_Rel(struct sess *sp)
679
{
680
        int i;
681
682 100827
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
683 100827
        CHECK_OBJ_NOTNULL(sp->pool, POOL_MAGIC);
684
685 100827
        Lck_Lock(&sp->mtx);
686 100827
        assert(sp->refcnt > 0);
687 100827
        i = --sp->refcnt;
688 100827
        Lck_Unlock(&sp->mtx);
689 100827
        if (i)
690 51783
                return;
691 49044
        Lck_Delete(&sp->mtx);
692
#ifdef ENABLE_WORKSPACE_EMULATOR
693
        WS_Rollback(sp->ws, 0);
694
#endif
695 49044
        MPL_Free(sp->pool->mpl_sess, sp);
696 100827
}
697
698
/*--------------------------------------------------------------------
699
 * Create and delete pools
700
 */
701
702
void
703 41479
SES_NewPool(struct pool *pp, unsigned pool_no)
704
{
705
        char nb[4 /* "sess" */ + 10 /* "%u" */ + 1];
706
707 41479
        CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
708 41479
        bprintf(nb, "req%u", pool_no);
709 82958
        pp->mpl_req = MPL_New(nb, &cache_param->pool_req,
710 41479
            &cache_param->workspace_client);
711 41479
        bprintf(nb, "sess%u", pool_no);
712 82958
        pp->mpl_sess = MPL_New(nb, &cache_param->pool_sess,
713 41479
            &cache_param->workspace_session);
714
715 41479
        bprintf(nb, "pool%u", pool_no);
716 41479
        pp->waiter = Waiter_New(nb);
717 41479
}
718
719
void
720 40950
SES_DestroyPool(struct pool *pp)
721
{
722 40950
        Waiter_Destroy(&pp->waiter);
723 40950
        MPL_Destroy(&pp->mpl_req);
724 40950
        MPL_Destroy(&pp->mpl_sess);
725 40950
}