varnish-cache/bin/varnishd/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 37305
 * sess fields, for instance ->fd being negative ->reason.
35 465
 *
36 225
 */
37 75
//lint --e{766}
38 350
39 2296
#include "config.h"
40 451
41 125
#include "cache_varnishd.h"
42 275
43 500
#include <stdio.h>
44 154
#include <stdlib.h>
45 1075
46 250
#include "cache_pool.h"
47 3250
#include "cache_transport.h"
48 0
49 25
#include "vsa.h"
50 50
#include "vtcp.h"
51 3375
#include "vtim.h"
52 50
#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(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(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(nm, stat, err, desc) \
89
        [SCE_##nm] = SC_##nm,
90
#include "tbl/sess_close.h"
91
};
92
93
/*--------------------------------------------------------------------*/
94
95
void
96 55130
SES_SetTransport(struct worker *wrk, struct sess *sp, struct req *req,
97
    const struct transport *xp)
98
{
99
100 55130
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
101 55130
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
102 55130
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
103 55130
        CHECK_OBJ_NOTNULL(xp, TRANSPORT_MAGIC);
104 55130
        assert(xp->number > 0);
105
106 55130
        sp->sattr[SA_TRANSPORT] = xp->number;
107 55130
        req->transport = xp;
108 55130
        wrk->task->func = xp->new_session;
109 55130
        wrk->task->priv = req;
110 55130
}
111
112
/*--------------------------------------------------------------------*/
113
114
#define SES_NOATTR_OFFSET 0xffff
115
116
static int
117 510119
ses_get_attr(const struct sess *sp, enum sess_attr a, void **dst)
118
{
119 510119
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
120 510119
        assert(a < SA_LAST);
121 510119
        AN(dst);
122
123 510119
        if (sp->sattr[a] == SES_NOATTR_OFFSET) {
124 0
                *dst = NULL;
125 0
                return (-1);
126
        }
127 510119
        *dst = WS_AtOffset(sp->ws, sp->sattr[a], 0);
128 510119
        return (0);
129 510119
}
130
131
static int
132 275039
ses_set_attr(const struct sess *sp, enum sess_attr a, const void *src, int sz)
133
{
134
        void *dst;
135 275039
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
136 275039
        assert(a < SA_LAST);
137 275039
        AN(src);
138 275039
        assert(sz > 0);
139
140 275039
        if (sp->sattr[a] == SES_NOATTR_OFFSET)
141 0
                return (-1);
142 275039
        dst = WS_AtOffset(sp->ws, sp->sattr[a], sz);
143 275039
        AN(dst);
144 275039
        memcpy(dst, src, sz);
145 275039
        return (0);
146 275039
}
147
148
static int
149 250827
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 250827
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
155 250827
        assert(a < SA_LAST);
156 250827
        AN(dst);
157 250827
        sz = *szp;
158 250827
        *szp = 0;
159 250827
        assert(sz >= 0);
160 250827
        if (WS_ReserveSize(sp->ws, sz) == 0)
161 25
                return (0);
162 250802
        o = WS_ReservationOffset(sp->ws);
163 250802
        if (o >= SES_NOATTR_OFFSET) {
164 0
                WS_Release(sp->ws, 0);
165 0
                return (0);
166
        }
167 250802
        *dst = WS_Reservation(sp->ws);
168 250802
        *szp = sz;
169 250802
        sp->sattr[a] = (uint16_t)o;
170 250802
        WS_Release(sp->ws, sz);
171 250802
        return (1);
172 250827
}
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 103220
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 103220
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
207 103220
        AN(src);
208
209 103220
        assert(a <  SA_LAST);
210 103220
        if (strcmp(sess_attr[a].type, "char"))
211 0
                WRONG("wrong sess_attr: not char");
212
213 103220
        l = sz = strlen(src) + 1;
214 103220
        if (! ses_res_attr(sp, a, &q, &sz))
215 0
                return (0);
216 103220
        assert(l == sz);
217 103220
        strcpy(q, src);
218 103220
        return (1);
219 103220
}
220
221
const char *
222 176471
SES_Get_String_Attr(const struct sess *sp, enum sess_attr a)
223
{
224
        void *q;
225
226 176471
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
227
228 176471
        assert(a <  SA_LAST);
229 176471
        if (strcmp(sess_attr[a].type, "char"))
230 0
                WRONG("wrong sess_attr: not char");
231
232 176471
        if (ses_get_attr(sp, a, &q) < 0)
233 0
                return (NULL);
234 176471
        return (q);
235 176471
}
236
237
/*--------------------------------------------------------------------*/
238
239
void
240 351
HTC_Status(enum htc_status_e e, const char **name, const char **desc)
241
{
242
243 351
        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 0
        }
253 351
}
254
255
/*--------------------------------------------------------------------*/
256
257
void
258 191640
HTC_RxInit(struct http_conn *htc, struct ws *ws)
259
{
260
        unsigned l;
261
262 191640
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
263 191640
        htc->ws = ws;
264
265 191640
        l = WS_ReqPipeline(htc->ws, htc->pipeline_b, htc->pipeline_e);
266 191640
        htc->rxbuf_b = WS_Reservation(ws);
267 191640
        htc->rxbuf_e = htc->rxbuf_b + l;
268 191640
        htc->pipeline_b = NULL;
269 191640
        htc->pipeline_e = NULL;
270 191640
}
271
272
void
273 148573
HTC_RxPipeline(struct http_conn *htc, char *p)
274
{
275
276 148573
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
277 148573
        assert(p >= htc->rxbuf_b);
278 148573
        assert(p <= htc->rxbuf_e);
279 148573
        if (p == htc->rxbuf_e) {
280 111637
                htc->pipeline_b = NULL;
281 111637
                htc->pipeline_e = NULL;
282 111637
        } else {
283 36936
                htc->pipeline_b = p;
284 36936
                htc->pipeline_e = htc->rxbuf_e;
285
        }
286 148573
}
287
288
/*----------------------------------------------------------------------
289
 * Receive a request/packet/whatever, with timeouts
290
 *
291
 * maxbytes is the maximum number of bytes the caller expects to need to
292
 * reach a complete work unit. Note that due to pipelining the actual
293
 * number of bytes passed to func in htc->rxbuf_b through htc->rxbuf_e may
294
 * be larger.
295
 *
296
 * t0 is when we start
297
 * *t1 becomes time of first non-idle rx
298
 * *t2 becomes time of complete rx
299
 * ti is when we return IDLE if nothing has arrived
300
 * tn is when we timeout on non-complete (total timeout)
301
 * td is max timeout between reads
302
 */
303
304
enum htc_status_e
305 191567
HTC_RxStuff(struct http_conn *htc, htc_complete_f *func,
306
    vtim_real *t1, vtim_real *t2, vtim_real ti, vtim_real tn, vtim_dur td,
307
    int maxbytes)
308
{
309
        vtim_dur tmo;
310
        vtim_real now;
311
        enum htc_status_e hs;
312
        unsigned l, r;
313
        ssize_t z;
314
315 191567
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
316 191567
        AN(htc->rfd);
317 191567
        assert(*htc->rfd > 0);
318 191567
        AN(htc->rxbuf_b);
319 191567
        AN(WS_Reservation(htc->ws));
320
321 191567
        l = pdiff(htc->rxbuf_b, htc->rxbuf_e);
322 191567
        r = WS_ReservationSize(htc->ws);
323 191567
        assert(l <= r);
324
325 191567
        AZ(isnan(tn) && isnan(td));
326 191567
        if (t1 != NULL)
327 116714
                assert(isnan(*t1));
328
329 191567
        if (l == r) {
330
                /* Can't work with a zero size buffer */
331 50
                WS_ReleaseP(htc->ws, htc->rxbuf_b);
332 50
                return (HTC_S_OVERFLOW);
333
        }
334 191517
        z = r;
335 191517
        if (z < maxbytes)
336 3200
                maxbytes = z;   /* Cap maxbytes at available WS */
337
338 345601
        while (1) {
339 345601
                now = VTIM_real();
340 345601
                AZ(htc->pipeline_b);
341 345601
                AZ(htc->pipeline_e);
342 345601
                l = pdiff(htc->rxbuf_b, htc->rxbuf_e);
343 345601
                assert(l <= r);
344
345 345601
                hs = func(htc);
346 345601
                if (hs == HTC_S_OVERFLOW || hs == HTC_S_JUNK) {
347 100
                        WS_ReleaseP(htc->ws, htc->rxbuf_b);
348 100
                        return (hs);
349
                }
350 345501
                if (hs == HTC_S_COMPLETE) {
351 149595
                        WS_ReleaseP(htc->ws, htc->rxbuf_e);
352
                        /* Got it, run with it */
353 149595
                        if (t1 != NULL && isnan(*t1))
354 74811
                                *t1 = now;
355 149595
                        if (t2 != NULL)
356 78383
                                *t2 = now;
357 149595
                        return (HTC_S_COMPLETE);
358
                }
359 195906
                if (hs == HTC_S_MORE) {
360
                        /* Working on it */
361 30125
                        if (t1 != NULL && isnan(*t1))
362 3696
                                *t1 = now;
363 195906
                } else if (hs == HTC_S_EMPTY)
364 165781
                        htc->rxbuf_e = htc->rxbuf_b;
365
                else
366 0
                        WRONG("htc_status_e");
367
368 195906
                if (hs == HTC_S_EMPTY && !isnan(ti) && (isnan(tn) || ti < tn))
369 165704
                        tmo = ti - now;
370 30204
                else if (isnan(tn))
371 913
                        tmo = td;
372 29291
                else if (isnan(td))
373 29291
                        tmo = tn - now;
374 0
                else if (td < tn - now)
375 0
                        tmo = td;
376
                else
377 0
                        tmo = tn - now;
378
379 195908
                AZ(isnan(tmo));
380 195908
                z = maxbytes - (htc->rxbuf_e - htc->rxbuf_b);
381 195908
                if (z <= 0) {
382
                        /* maxbytes reached but not HTC_S_COMPLETE. Return
383
                         * overflow. */
384 500
                        WS_ReleaseP(htc->ws, htc->rxbuf_b);
385 500
                        return (HTC_S_OVERFLOW);
386
                }
387 195408
                if (tmo <= 0.0)
388 3676
                        tmo = 1e-3;
389 195408
                z = VTCP_read(*htc->rfd, htc->rxbuf_e, z, tmo);
390 195408
                if (z == 0 || z == -1) {
391 36815
                        WS_ReleaseP(htc->ws, htc->rxbuf_b);
392 36815
                        return (HTC_S_EOF);
393 158593
                } else if (z > 0)
394 154084
                        htc->rxbuf_e += z;
395 4509
                else if (z == -2) {
396 4509
                        WS_ReleaseP(htc->ws, htc->rxbuf_b);
397 4509
                        if (hs == HTC_S_EMPTY)
398 4371
                                return (HTC_S_IDLE);
399
                        else
400 138
                                return (HTC_S_TIMEOUT);
401
                }
402
        }
403 191569
}
404
405
/*--------------------------------------------------------------------
406
 * Get a new session, preferably by recycling an already ready one
407
 *
408
 * Layout is:
409
 *      struct sess
410
 *      workspace
411
 */
412
413
struct sess *
414 50465
SES_New(struct pool *pp)
415
{
416
        struct sess *sp;
417
        unsigned sz;
418
        char *p, *e;
419
420 50465
        CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
421 50465
        sp = MPL_Get(pp->mpl_sess, &sz);
422 50465
        AN(sp);
423 50465
        INIT_OBJ(sp, SESS_MAGIC);
424 50465
        sp->pool = pp;
425 50465
        sp->refcnt = 1;
426 50465
        memset(sp->sattr, 0xff, sizeof sp->sattr);
427
428 50465
        e = (char*)sp + sz;
429 50465
        p = (char*)(sp + 1);
430 50465
        p = (void*)PRNDUP(p);
431 50465
        assert(p < e);
432 50465
        WS_Init(sp->ws, "ses", p, e - p);
433
434 50465
        sp->t_open = NAN;
435 50465
        sp->t_idle = NAN;
436 50465
        sp->timeout_idle = NAN;
437 50465
        sp->timeout_linger = NAN;
438 50465
        sp->send_timeout = NAN;
439 50465
        sp->idle_send_timeout = NAN;
440 50465
        Lck_New(&sp->mtx, lck_sess);
441 50465
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
442 50465
        return (sp);
443
}
444
445
/*--------------------------------------------------------------------
446
 * Handle a session (from waiter)
447
 */
448
449
static void v_matchproto_(waiter_handle_f)
450 4086
ses_handle(struct waited *wp, enum wait_event ev, vtim_real now)
451
{
452
        struct sess *sp;
453
        struct pool *pp;
454
        struct pool_task *tp;
455
        const struct transport *xp;
456
457 4086
        CHECK_OBJ_NOTNULL(wp, WAITED_MAGIC);
458 4086
        CAST_OBJ_NOTNULL(sp, wp->priv1, SESS_MAGIC);
459 4086
        CAST_OBJ_NOTNULL(xp, wp->priv2, TRANSPORT_MAGIC);
460 4086
        assert(WS_Reservation(sp->ws) == wp);
461 4086
        FINI_OBJ(wp);
462
463
        /* The WS was reserved in SES_Wait() */
464 4086
        WS_Release(sp->ws, 0);
465
466 4086
        switch (ev) {
467
        case WAITER_TIMEOUT:
468 275
                SES_Delete(sp, SC_RX_CLOSE_IDLE, now);
469 275
                break;
470
        case WAITER_REMCLOSE:
471 435
                SES_Delete(sp, SC_REM_CLOSE, now);
472 435
                break;
473
        case WAITER_ACTION:
474 3376
                pp = sp->pool;
475 3376
                CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
476
                /* SES_Wait() guarantees the next will not assert. */
477 3376
                assert(sizeof *tp <= WS_ReserveSize(sp->ws, sizeof *tp));
478 3376
                tp = WS_Reservation(sp->ws);
479 3376
                tp->func = xp->unwait;
480 3376
                tp->priv = sp;
481 3376
                if (Pool_Task(pp, tp, TASK_QUEUE_REQ))
482 0
                        SES_Delete(sp, SC_OVERLOAD, now);
483 3376
                break;
484
        case WAITER_CLOSE:
485 0
                WRONG("Should not see WAITER_CLOSE on client side");
486 0
                break;
487
        default:
488 0
                WRONG("Wrong event in ses_handle");
489 0
        }
490 4086
}
491
492
/*--------------------------------------------------------------------
493
 */
494
495
void
496 4261
SES_Wait(struct sess *sp, const struct transport *xp)
497
{
498
        struct pool *pp;
499
        struct waited *wp;
500
        unsigned u;
501
502 4261
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
503 4261
        CHECK_OBJ_NOTNULL(xp, TRANSPORT_MAGIC);
504 4261
        pp = sp->pool;
505 4261
        CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
506 4261
        assert(sp->fd > 0);
507
        /*
508
         * XXX: waiter_epoll prevents us from zeroing the struct because
509
         * XXX: it keeps state across calls.
510
         */
511 4261
        VTCP_nonblocking(sp->fd);
512
513
        /*
514
         * Put struct waited on the workspace. Make sure that the
515
         * workspace can hold enough space for both struct waited
516
         * and pool_task, as pool_task will be needed when coming
517
         * off the waiter again.
518
         */
519 4261
        u = WS_ReserveAll(sp->ws);
520 4261
        if (u < sizeof (struct waited) || u < sizeof(struct pool_task)) {
521 0
                WS_MarkOverflow(sp->ws);
522 0
                SES_Delete(sp, SC_OVERLOAD, NAN);
523 0
                return;
524
        }
525
526 4261
        wp = WS_Reservation(sp->ws);
527 4261
        INIT_OBJ(wp, WAITED_MAGIC);
528 4261
        wp->fd = sp->fd;
529 4261
        wp->priv1 = sp;
530 4261
        wp->priv2 = xp;
531 4261
        wp->idle = sp->t_idle;
532 4261
        wp->func = ses_handle;
533 4261
        wp->tmo = SESS_TMO(sp, timeout_idle);
534 4261
        if (Wait_Enter(pp->waiter, wp))
535 0
                SES_Delete(sp, SC_PIPE_OVERFLOW, NAN);
536 4261
}
537
538
/*--------------------------------------------------------------------
539
 * Update sc_ counters by reason
540
 *
541
 * assuming that the approximation of non-atomic global counters is sufficient.
542
 * if not: update to per-wrk
543
 */
544
545
static void
546 49945
ses_close_acct(stream_close_t reason)
547
{
548
549 49945
        CHECK_OBJ_NOTNULL(reason, STREAM_CLOSE_MAGIC);
550 49945
        switch (reason->idx) {
551
#define SESS_CLOSE(reason, stat, err, desc)             \
552
        case SCE_ ## reason:                            \
553
                VSC_C_main->sc_ ## stat++;              \
554
                break;
555
#include "tbl/sess_close.h"
556
557
        default:
558 0
                WRONG("Wrong event in ses_close_acct");
559 0
        }
560 49945
        if (reason->is_err)
561 10075
                VSC_C_main->sess_closed_err++;
562 49945
}
563
564
/*--------------------------------------------------------------------
565
 * Close a session's connection.
566
 * XXX: Technically speaking we should catch a t_end timestamp here
567
 * XXX: for SES_Delete() to use.
568
 */
569
570
void
571 49950
SES_Close(struct sess *sp, stream_close_t reason)
572
{
573
        int i;
574
575 49950
        CHECK_OBJ_NOTNULL(reason, STREAM_CLOSE_MAGIC);
576 49950
        assert(reason->idx > 0);
577 49950
        assert(sp->fd > 0);
578 49950
        i = close(sp->fd);
579 49950
        assert(i == 0 || errno != EBADF); /* XXX EINVAL seen */
580 49950
        sp->fd = -reason->idx;
581 49950
        ses_close_acct(reason);
582 49950
}
583
584
/*--------------------------------------------------------------------
585
 * Report and dismantle a session.
586
 */
587
588
void
589 49947
SES_Delete(struct sess *sp, stream_close_t reason, vtim_real now)
590
{
591
592 49947
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
593 49947
        CHECK_OBJ_NOTNULL(reason, STREAM_CLOSE_MAGIC);
594
595 49947
        if (reason != SC_NULL)
596 38710
                SES_Close(sp, reason);
597 49947
        assert(sp->fd < 0);
598
599 49947
        if (isnan(now))
600 49234
                now = VTIM_real();
601 49947
        AZ(isnan(sp->t_open));
602 49947
        if (now < sp->t_open) {
603 0
                VSL(SLT_Debug, sp->vxid,
604
                    "Clock step (now=%f < t_open=%f)",
605 0
                    now, sp->t_open);
606 0
                if (now + cache_param->clock_step < sp->t_open)
607 0
                        WRONG("Clock step detected");
608 0
                now = sp->t_open; /* Do not log negatives */
609 0
        }
610
611 49947
        if (reason == SC_NULL) {
612 11240
                assert(sp->fd < 0 && -sp->fd < SCE_MAX);
613 11240
                reason = sc_lookup[-sp->fd];
614 11240
        }
615
616 49947
        CHECK_OBJ_NOTNULL(reason, STREAM_CLOSE_MAGIC);
617 49947
        VSL(SLT_SessClose, sp->vxid, "%s %.3f", reason->name, now - sp->t_open);
618 49947
        VSL(SLT_End, sp->vxid, "%s", "");
619 49947
        if (WS_Overflowed(sp->ws))
620 100
                VSC_C_main->ws_session_overflow++;
621 49947
        SES_Rel(sp);
622 49947
}
623
624
void
625 34165
SES_DeleteHS(struct sess *sp, enum htc_status_e hs, vtim_real now)
626
{
627
        stream_close_t reason;
628
629 34165
        switch (hs) {
630
        case HTC_S_JUNK:
631 25
                reason = SC_RX_JUNK;
632 25
                break;
633
        case HTC_S_CLOSE:
634 0
                reason = SC_REM_CLOSE;
635 0
                break;
636
        case HTC_S_TIMEOUT:
637 25
                reason = SC_RX_TIMEOUT;
638 25
                break;
639
        case HTC_S_OVERFLOW:
640 100
                reason = SC_RX_OVERFLOW;
641 100
                break;
642
        case HTC_S_EOF:
643 34015
                reason = SC_REM_CLOSE;
644 34015
                break;
645
        default:
646 0
                WRONG("htc_status (bad)");
647 0
        }
648 34165
        SES_Delete(sp, reason, now);
649 34165
}
650
651
652
/*--------------------------------------------------------------------
653
 */
654
655
void
656 54349
SES_Ref(struct sess *sp)
657
{
658
659 54349
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
660 54349
        Lck_Lock(&sp->mtx);
661 54349
        assert(sp->refcnt > 0);
662 54349
        sp->refcnt++;
663 54349
        Lck_Unlock(&sp->mtx);
664 54349
}
665
666
void
667 104250
SES_Rel(struct sess *sp)
668
{
669
        int i;
670
        struct pool *pp;
671
672 104250
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
673 104250
        pp = sp->pool;
674 104250
        CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
675
676 104250
        Lck_Lock(&sp->mtx);
677 104250
        assert(sp->refcnt > 0);
678 104250
        i = --sp->refcnt;
679 104250
        Lck_Unlock(&sp->mtx);
680 104250
        if (i)
681 54325
                return;
682 49925
        Lck_Delete(&sp->mtx);
683
#ifdef ENABLE_WORKSPACE_EMULATOR
684
        WS_Rollback(sp->ws, 0);
685
#endif
686 49925
        MPL_Free(sp->pool->mpl_sess, sp);
687 104250
}
688
689
/*--------------------------------------------------------------------
690
 * Create and delete pools
691
 */
692
693
void
694 43944
SES_NewPool(struct pool *pp, unsigned pool_no)
695
{
696
        char nb[8];
697
698 43944
        CHECK_OBJ_NOTNULL(pp, POOL_MAGIC);
699 43944
        bprintf(nb, "req%u", pool_no);
700 87888
        pp->mpl_req = MPL_New(nb, &cache_param->pool_req,
701 43944
            &cache_param->workspace_client);
702 43944
        bprintf(nb, "sess%u", pool_no);
703 87888
        pp->mpl_sess = MPL_New(nb, &cache_param->pool_sess,
704 43944
            &cache_param->workspace_session);
705
706 43944
        pp->waiter = Waiter_New();
707 43944
}
708
709
void
710 50
SES_DestroyPool(struct pool *pp)
711
{
712 50
        MPL_Destroy(&pp->mpl_req);
713 50
        MPL_Destroy(&pp->mpl_sess);
714 50
        Waiter_Destroy(&pp->waiter);
715 50
}