source: bin/varnishd/cache_center.c @ 0956e0

Revision 0956e0, 34.0 KB checked in by Poul-Henning Kamp <phk@…>, 3 years ago (diff)

white space cleanup

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2010 Redpill Linpro AS
4 * All rights reserved.
5 *
6 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * This file contains the central state machine for pushing requests.
30 *
31 * We cannot just use direct calls because it is possible to kick a
32 * request back to the lookup stage (usually after a rewrite).  The
33 * state engine also allows us to break the processing up into some
34 * logical chunks which improves readability a little bit.
35 *
36 * Since the states are rather nasty in detail, I have decided to embedd
37 * a dot(1) graph in the source code comments.  So to see the big picture,
38 * extract the DOT lines and run though dot(1), for instance with the
39 * command:
40 *      sed -n '/^DOT/s///p' cache_center.c | dot -Tps > /tmp/_.ps
41 */
42
43/*
44DOT digraph vcl_center {
45xDOT    page="8.2,11.5"
46DOT     size="7.2,10.5"
47DOT     margin="0.5"
48DOT     center="1"
49DOT acceptor [
50DOT     shape=hexagon
51DOT     label="Request received"
52DOT ]
53DOT ERROR [shape=plaintext]
54DOT RESTART [shape=plaintext]
55DOT acceptor -> start [style=bold,color=green,weight=4]
56 */
57
58#include "config.h"
59
60#include "svnid.h"
61SVNID("$Id$")
62
63#include <stdio.h>
64#include <errno.h>
65#include <math.h>
66#include <poll.h>
67#include <stdlib.h>
68#include <string.h>
69#include <unistd.h>
70
71#ifndef HAVE_SRANDOMDEV
72#include "compat/srandomdev.h"
73#endif
74
75#include "vcl.h"
76#include "cli_priv.h"
77#include "cache.h"
78#include "hash_slinger.h"
79#include "stevedore.h"
80#include "vsha256.h"
81
82static unsigned xids;
83
84/*--------------------------------------------------------------------
85 * WAIT
86 * Wait (briefly) until we have a full request in our htc.
87 */
88
89static int
90cnt_wait(struct sess *sp)
91{
92        int i;
93        struct pollfd pfd[1];
94
95        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
96        AZ(sp->vcl);
97        AZ(sp->obj);
98        assert(sp->xid == 0);
99
100        i = HTC_Complete(sp->htc);
101        if (i == 0 && params->session_linger > 0) {
102                pfd[0].fd = sp->fd;
103                pfd[0].events = POLLIN;
104                pfd[0].revents = 0;
105                i = poll(pfd, 1, params->session_linger);
106                if (i)
107                        i = HTC_Rx(sp->htc);
108        }
109        if (i == 0) {
110                WSL(sp->wrk, SLT_Debug, sp->fd, "herding");
111                sp->wrk->stats.sess_herd++;
112                SES_Charge(sp);
113                sp->wrk = NULL;
114                vca_return_session(sp);
115                return (1);
116        }
117        if (i == 1) {
118                sp->step = STP_START;
119                return (0);
120        }
121        if (i == -2) {
122                vca_close_session(sp, "overflow");
123                return (0);
124        }
125        if (i == -1 && Tlen(sp->htc->rxbuf) == 0 &&
126            (errno == 0 || errno == ECONNRESET))
127                vca_close_session(sp, "EOF");
128        else
129                vca_close_session(sp, "error");
130        sp->step = STP_DONE;
131        return (0);
132}
133
134/*--------------------------------------------------------------------
135 * We have a refcounted object on the session, now deliver it.
136 *
137DOT subgraph xcluster_deliver {
138DOT     deliver [
139DOT             shape=ellipse
140DOT             label="Filter obj.->resp."
141DOT     ]
142DOT     vcl_deliver [
143DOT             shape=record
144DOT             label="vcl_deliver()|resp."
145DOT     ]
146DOT     deliver2 [
147DOT             shape=ellipse
148DOT             label="Send resp + body"
149DOT     ]
150DOT     deliver -> vcl_deliver [style=bold,color=green,weight=4]
151DOT     vcl_deliver -> deliver2 [style=bold,color=green,weight=4,label=deliver]
152DOT     vcl_deliver -> errdeliver [label="error"]
153DOT     errdeliver [label="ERROR",shape=plaintext]
154DOT     vcl_deliver -> rstdeliver [label="restart",color=purple]
155DOT     rstdeliver [label="RESTART",shape=plaintext]
156DOT }
157DOT deliver2 -> DONE [style=bold,color=green,weight=4]
158 *
159 */
160
161static int
162cnt_deliver(struct sess *sp)
163{
164
165        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
166        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
167        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
168
169        sp->wrk->res_mode = RES_LEN;
170
171        if (!sp->disable_esi && sp->obj->esidata != NULL) {
172                /* In ESI mode, we don't know the aggregate length */
173                sp->wrk->res_mode &= ~RES_LEN;
174                sp->wrk->res_mode |= RES_ESI;
175        }
176
177        if (sp->esi_level > 0) {
178                sp->wrk->res_mode &= ~RES_LEN;
179                sp->wrk->res_mode |= RES_ESI_CHILD;
180        }
181
182        if (params->http_gzip_support && sp->obj->gziped &&
183            !RFC2616_Req_Gzip(sp)) {
184                /*
185                 * We don't know what it uncompresses to
186                 * XXX: we could cache that
187                 */
188                sp->wrk->res_mode &= ~RES_LEN;
189                sp->wrk->res_mode |= RES_GUNZIP;
190        }
191
192        if (!(sp->wrk->res_mode & (RES_LEN|RES_CHUNKED|RES_EOF))) {
193                if (sp->obj->len == 0)
194                        /*
195                         * If the object is empty, neither ESI nor GUNZIP
196                         * can make it any different size
197                         */
198                        sp->wrk->res_mode |= RES_LEN;
199                else if (!sp->wantbody) {
200                        /* Nothing */
201                } else if (sp->http->protover >= 1.1) {
202                        sp->wrk->res_mode |= RES_CHUNKED;
203                } else {
204                        sp->wrk->res_mode |= RES_EOF;
205                        sp->doclose = "EOF mode";
206                }
207        }
208
209        sp->t_resp = TIM_real();
210        if (sp->obj->objcore != NULL) {
211                if ((sp->t_resp - sp->obj->last_lru) > params->lru_timeout &&
212                    EXP_Touch(sp->obj->objcore))
213                        sp->obj->last_lru = sp->t_resp;
214                sp->obj->last_use = sp->t_resp; /* XXX: locking ? */
215        }
216        sp->wrk->resp = sp->wrk->http[2];
217        http_Setup(sp->wrk->resp, sp->wrk->ws);
218        RES_BuildHttp(sp);
219        VCL_deliver_method(sp);
220        switch (sp->handling) {
221        case VCL_RET_DELIVER:
222                break;
223        case VCL_RET_RESTART:
224                if (sp->restarts >= params->max_restarts)
225                        break;
226                (void)HSH_Deref(sp->wrk, NULL, &sp->obj);
227                AZ(sp->obj);
228                sp->restarts++;
229                sp->director = NULL;
230                sp->wrk->bereq = NULL;
231                sp->wrk->beresp = NULL;
232                sp->wrk->beresp1 = NULL;
233                sp->wrk->resp = NULL;
234                sp->step = STP_RECV;
235                return (0);
236        default:
237                WRONG("Illegal action in vcl_deliver{}");
238        }
239
240        sp->director = NULL;
241        sp->restarts = 0;
242
243        RES_WriteObj(sp);
244
245        AZ(sp->wrk->wfd);
246        (void)HSH_Deref(sp->wrk, NULL, &sp->obj);
247        sp->wrk->resp = NULL;
248        sp->step = STP_DONE;
249        return (0);
250}
251
252/*--------------------------------------------------------------------
253 * This is the final state, figure out if we should close or recycle
254 * the client connection
255 *
256DOT     DONE [
257DOT             shape=hexagon
258DOT             label="Request completed"
259DOT     ]
260 */
261
262static int
263cnt_done(struct sess *sp)
264{
265        double dh, dp, da;
266        int i;
267
268        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
269        CHECK_OBJ_ORNULL(sp->vcl, VCL_CONF_MAGIC);
270
271        AZ(sp->obj);
272        AZ(sp->vbc);
273        sp->director = NULL;
274        sp->restarts = 0;
275
276        if (sp->vcl != NULL && sp->esi_level == 0) {
277                if (sp->wrk->vcl != NULL)
278                        VCL_Rel(&sp->wrk->vcl);
279                sp->wrk->vcl = sp->vcl;
280                sp->vcl = NULL;
281        }
282
283        SES_Charge(sp);
284
285        sp->t_end = TIM_real();
286        sp->wrk->lastused = sp->t_end;
287        if (sp->xid == 0) {
288                sp->t_req = sp->t_end;
289                sp->t_resp = sp->t_end;
290        } else if (sp->esi_level == 0) {
291                dp = sp->t_resp - sp->t_req;
292                da = sp->t_end - sp->t_resp;
293                dh = sp->t_req - sp->t_open;
294                /* XXX: Add StatReq == StatSess */
295                WSP(sp, SLT_Length, "%u", sp->acct_req.bodybytes);
296                WSL(sp->wrk, SLT_ReqEnd, sp->id, "%u %.9f %.9f %.9f %.9f %.9f",
297                    sp->xid, sp->t_req, sp->t_end, dh, dp, da);
298        }
299        sp->xid = 0;
300        sp->t_open = sp->t_end;
301        sp->t_resp = NAN;
302        WSL_Flush(sp->wrk, 0);
303
304        /* If we did an ESI include, don't mess up our state */
305        if (sp->esi_level > 0)
306                return (1);
307
308        memset(&sp->acct_req, 0, sizeof sp->acct_req);
309
310        sp->t_req = NAN;
311        sp->hash_always_miss = 0;
312        sp->hash_ignore_busy = 0;
313
314        if (sp->fd >= 0 && sp->doclose != NULL) {
315                /*
316                 * This is an orderly close of the connection; ditch nolinger
317                 * before we close, to get queued data transmitted.
318                 */
319                // XXX: not yet (void)TCP_linger(sp->fd, 0);
320                vca_close_session(sp, sp->doclose);
321        }
322
323        if (sp->fd < 0) {
324                sp->wrk->stats.sess_closed++;
325                sp->wrk = NULL;
326                SES_Delete(sp);
327                return (1);
328        }
329
330        if (sp->wrk->stats.client_req >= params->wthread_stats_rate)
331                WRK_SumStat(sp->wrk);
332        /* Reset the workspace to the session-watermark */
333        WS_Reset(sp->ws, sp->ws_ses);
334        WS_Reset(sp->wrk->ws, NULL);
335
336        i = HTC_Reinit(sp->htc);
337        if (i == 1) {
338                sp->wrk->stats.sess_pipeline++;
339                sp->step = STP_START;
340                return (0);
341        }
342        if (Tlen(sp->htc->rxbuf)) {
343                sp->wrk->stats.sess_readahead++;
344                sp->step = STP_WAIT;
345                return (0);
346        }
347        if (params->session_linger > 0) {
348                sp->wrk->stats.sess_linger++;
349                sp->step = STP_WAIT;
350                return (0);
351        }
352        sp->wrk->stats.sess_herd++;
353        sp->wrk = NULL;
354        vca_return_session(sp);
355        return (1);
356}
357
358/*--------------------------------------------------------------------
359 * Emit an error
360 *
361DOT subgraph xcluster_error {
362DOT     vcl_error [
363DOT             shape=record
364DOT             label="vcl_error()|resp."
365DOT     ]
366DOT     ERROR -> vcl_error
367DOT     vcl_error-> deliver [label=deliver]
368DOT }
369 */
370
371static int
372cnt_error(struct sess *sp)
373{
374        struct worker *w;
375        struct http *h;
376        char date[40];
377
378        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
379
380        w = sp->wrk;
381        if (sp->obj == NULL) {
382                HSH_Prealloc(sp);
383                /* XXX: 1024 is a pure guess */
384                sp->obj = STV_NewObject(sp, NULL, 1024, 0,
385                     params->http_max_hdr);
386                sp->obj->xid = sp->xid;
387                sp->obj->entered = sp->t_req;
388        } else {
389                /* XXX: Null the headers ? */
390        }
391        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
392        h = sp->obj->http;
393
394        if (sp->err_code < 100 || sp->err_code > 999)
395                sp->err_code = 501;
396
397        http_PutProtocol(w, sp->fd, h, "HTTP/1.1");
398        http_PutStatus(h, sp->err_code);
399        TIM_format(TIM_real(), date);
400        http_PrintfHeader(w, sp->fd, h, "Date: %s", date);
401        http_PrintfHeader(w, sp->fd, h, "Server: Varnish");
402        http_PrintfHeader(w, sp->fd, h, "Retry-After: %d", params->err_ttl);
403
404        if (sp->err_reason != NULL)
405                http_PutResponse(w, sp->fd, h, sp->err_reason);
406        else
407                http_PutResponse(w, sp->fd, h,
408                    http_StatusMessage(sp->err_code));
409        VCL_error_method(sp);
410
411        if (sp->handling == VCL_RET_RESTART &&
412            sp->restarts <  params->max_restarts) {
413                HSH_Drop(sp);
414                sp->director = NULL;
415                sp->restarts++;
416                sp->step = STP_RECV;
417                return (0);
418        } else if (sp->handling == VCL_RET_RESTART)
419                sp->handling = VCL_RET_DELIVER;
420
421
422        /* We always close when we take this path */
423        sp->doclose = "error";
424        sp->wantbody = 1;
425
426        assert(sp->handling == VCL_RET_DELIVER);
427        sp->err_code = 0;
428        sp->err_reason = NULL;
429        sp->wrk->bereq = NULL;
430        sp->step = STP_DELIVER;
431        return (0);
432}
433
434/*--------------------------------------------------------------------
435 * Fetch an object from the backend, either for pass or for caching.
436 *
437DOT subgraph xcluster_fetch {
438DOT     fetch [
439DOT             shape=ellipse
440DOT             label="fetch from backend\n(find obj.ttl)"
441DOT     ]
442DOT     vcl_fetch [
443DOT             shape=record
444DOT             label="vcl_fetch()|req.\nbereq.\nberesp."
445DOT     ]
446DOT     fetch -> vcl_fetch [style=bold,color=blue,weight=2]
447DOT     fetch_pass [
448DOT             shape=ellipse
449DOT             label="obj.pass=true"
450DOT     ]
451DOT     vcl_fetch -> fetch_pass [label="pass",style=bold,color=red]
452DOT }
453DOT fetch_pass -> deliver [style=bold,color=red]
454DOT vcl_fetch -> deliver [label="deliver",style=bold,color=blue,weight=2]
455DOT vcl_fetch -> recv [label="restart"]
456DOT vcl_fetch -> rstfetch [label="restart",color=purple]
457DOT rstfetch [label="RESTART",shape=plaintext]
458DOT fetch -> errfetch
459DOT vcl_fetch -> errfetch [label="error"]
460DOT errfetch [label="ERROR",shape=plaintext]
461 */
462
463static int
464cnt_fetch(struct sess *sp)
465{
466        int i;
467        struct http *hp, *hp2;
468        char *b;
469        unsigned l, nhttp;
470        int varyl = 0, pass;
471        struct vsb *vary = NULL;
472
473        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
474        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
475
476        AN(sp->director);
477        AZ(sp->vbc);
478
479        /* sp->wrk->http[0] is (still) bereq */
480        sp->wrk->beresp = sp->wrk->http[1];
481        http_Setup(sp->wrk->beresp, sp->wrk->ws);
482
483        i = FetchHdr(sp);
484        /*
485         * If we recycle a backend connection, there is a finite chance
486         * that the backend closed it before we get a request to it.
487         * Do a single retry in that case.
488         */
489        if (i == 1) {
490                VSC_main->backend_retry++;
491                i = FetchHdr(sp);
492        }
493
494        /*
495         * These two headers can be spread over multiple actual headers
496         * and we rely on their content outside of VCL, so collect them
497         * into one line here.
498         */
499        http_CollectHdr(sp->wrk->beresp, H_Cache_Control);
500        http_CollectHdr(sp->wrk->beresp, H_Vary);
501
502        /*
503         * Save a copy before it might get mangled in VCL.  When it comes to
504         * dealing with the body, we want to see the unadultered headers.
505         */
506        sp->wrk->beresp1 = sp->wrk->http[2];
507        *sp->wrk->beresp1 = *sp->wrk->beresp;
508
509        if (i) {
510                if (sp->objcore != NULL) {
511                        CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC);
512                        AZ(HSH_Deref(sp->wrk, sp->objcore, NULL));
513                        sp->objcore = NULL;
514                }
515                AZ(sp->obj);
516                sp->wrk->bereq = NULL;
517                sp->wrk->beresp = NULL;
518                sp->wrk->beresp1 = NULL;
519                sp->err_code = 503;
520                sp->step = STP_ERROR;
521                return (0);
522        }
523
524        sp->err_code = http_GetStatus(sp->wrk->beresp);
525
526        /*
527         * What does RFC2616 think about TTL ?
528         */
529        sp->wrk->entered = TIM_real();
530        sp->wrk->age = 0;
531        sp->wrk->ttl = RFC2616_Ttl(sp);
532
533        /*
534         * Initial cacheability determination per [RFC2616, 13.4]
535         * We do not support ranges yet, so 206 is out.
536         */
537        switch (sp->err_code) {
538        case 200: /* OK */
539        case 203: /* Non-Authoritative Information */
540        case 300: /* Multiple Choices */
541        case 301: /* Moved Permanently */
542        case 302: /* Moved Temporarily */
543        case 410: /* Gone */
544        case 404: /* Not Found */
545                break;
546        default:
547                sp->wrk->ttl = sp->t_req - 1.;
548                break;
549        }
550
551        /* pass from vclrecv{} has negative TTL */
552        if (sp->objcore == NULL)
553                sp->wrk->ttl = sp->t_req - 1.;
554
555        sp->wrk->do_esi = 0;
556        sp->wrk->grace = NAN;
557
558        sp->wrk->body_status = RFC2616_Body(sp);
559
560        AZ(sp->wrk->storage_hint);
561
562        VCL_fetch_method(sp);
563
564        if (sp->objcore == NULL) {
565                /* This is a pass from vcl_recv */
566                pass = 1;
567                /* VCL may have fiddled this, but that doesn't help */
568                sp->wrk->ttl = sp->t_req - 1.;
569        } else if (sp->handling == VCL_RET_HIT_FOR_PASS) {
570                /* pass from vcl_fetch{} -> hit-for-pass */
571                /* XXX: the bereq was not filtered pass... */
572                pass = 1;
573                sp->objcore->flags |= OC_F_PASS;
574        } else {
575                /* regular object */
576                pass = 0;
577        }
578
579        /*
580         * The VCL variables beresp.do_g[un]zip tells us how we want the
581         * object processed before it is stored.
582         *
583         * The backend Content-Encoding header tells us what we are going
584         * to receive, which we classify in the following three classes:
585         *
586         *      "Content-Encoding: gzip"        --> object is gzip'ed.
587         *      no Content-Encoding             --> object is not gzip'ed.
588         *      anything else                   --> do nothing wrt gzip
589         *
590         */
591
592        AZ(sp->wrk->vfp);
593
594        /* We do nothing unless the param is set */
595        if (!params->http_gzip_support)
596                sp->wrk->do_gzip = sp->wrk->do_gunzip = 0;
597
598        sp->wrk->is_gzip =
599            http_HdrIs(sp->wrk->beresp, H_Content_Encoding, "gzip");
600
601        sp->wrk->is_gunzip =
602            !http_GetHdr(sp->wrk->beresp, H_Content_Encoding, NULL);
603
604        /* It can't be both */
605        assert(sp->wrk->is_gzip == 0 || sp->wrk->is_gunzip == 0);
606
607        /* We won't gunzip unless it is gzip'ed */
608        if (sp->wrk->do_gunzip && !sp->wrk->is_gzip)
609                sp->wrk->do_gunzip = 0;
610
611        /* If we do gunzip, remove the C-E header */
612        if (sp->wrk->do_gunzip)
613                http_Unset(sp->wrk->beresp, H_Content_Encoding);
614
615        /* We wont gzip unless it is ungziped */
616        if (sp->wrk->do_gzip && !sp->wrk->is_gunzip)
617                sp->wrk->do_gzip = 0;
618
619        /* If we do gzip, add the C-E header */
620        if (sp->wrk->do_gzip)
621                http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->beresp,
622                    "Content-Encoding: %s", "gzip");
623
624        /* But we can't do both at the same time */
625        assert(sp->wrk->do_gzip == 0 || sp->wrk->do_gunzip == 0);
626
627        /* ESI takes precedence and handles gzip/gunzip itself */
628        if (sp->wrk->do_esi)
629                sp->wrk->vfp = &vfp_esi;
630        else if (sp->wrk->do_gunzip)
631                sp->wrk->vfp = &vfp_gunzip;
632        else if (sp->wrk->do_gzip)
633                sp->wrk->vfp = &vfp_gzip;
634        else if (sp->wrk->is_gzip)
635                sp->wrk->vfp = &vfp_testgzip;
636
637        l = http_EstimateWS(sp->wrk->beresp,
638            pass ? HTTPH_R_PASS : HTTPH_A_INS, &nhttp);
639
640        /* Create Vary instructions */
641        if (sp->objcore != NULL) {
642                CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC);
643                vary = VRY_Create(sp, sp->wrk->beresp);
644                if (vary != NULL) {
645                        varyl = vsb_len(vary);
646                        assert(varyl > 0);
647                        l += varyl;
648                }
649        }
650
651        /*
652         * Space for producing a Content-Length: header including padding
653         * A billion gigabytes is enough for anybody.
654         */
655        l += strlen("Content-Length: XxxXxxXxxXxxXxxXxx") + sizeof(void *);
656
657        if (sp->wrk->ttl < sp->t_req + params->shortlived ||
658            sp->objcore == NULL)
659                sp->wrk->storage_hint = TRANSIENT_STORAGE;
660
661        sp->obj = STV_NewObject(sp, sp->wrk->storage_hint, l,
662            sp->wrk->ttl, nhttp);
663        /* XXX: -> 513 */
664        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
665
666        sp->wrk->storage_hint = NULL;
667
668        /* VFP will update as needed */
669        sp->obj->gziped = sp->wrk->is_gzip;
670
671        if (vary != NULL) {
672                sp->obj->vary =
673                    (void *)WS_Alloc(sp->obj->http->ws, varyl);
674                AN(sp->obj->vary);
675                memcpy(sp->obj->vary, vsb_data(vary), varyl);
676                vsb_delete(vary);
677                vary = NULL;
678        }
679
680        sp->obj->xid = sp->xid;
681        sp->obj->response = sp->err_code;
682        sp->obj->grace = sp->wrk->grace;
683        sp->obj->age = sp->wrk->age;
684        sp->obj->entered = sp->wrk->entered;
685        WS_Assert(sp->obj->ws_o);
686
687        /* Filter into object */
688        hp = sp->wrk->beresp;
689        hp2 = sp->obj->http;
690
691        hp2->logtag = HTTP_Obj;
692        http_CopyResp(hp2, hp);
693        http_FilterFields(sp->wrk, sp->fd, hp2, hp,
694            pass ? HTTPH_R_PASS : HTTPH_A_INS);
695        http_CopyHome(sp->wrk, sp->fd, hp2);
696
697        if (http_GetHdr(hp, H_Last_Modified, &b))
698                sp->obj->last_modified = TIM_parse(b);
699        else
700                sp->obj->last_modified = sp->wrk->entered;
701
702        /* Use unmodified headers*/
703        i = FetchBody(sp, sp->wrk->beresp1);
704
705        sp->wrk->bereq = NULL;
706        sp->wrk->beresp = NULL;
707        sp->wrk->beresp1 = NULL;
708        sp->wrk->vfp = NULL;
709        AZ(sp->wrk->wfd);
710        AZ(sp->vbc);
711        AN(sp->director);
712
713        if (i) {
714                HSH_Drop(sp);
715                AZ(sp->obj);
716                sp->err_code = 503;
717                sp->step = STP_ERROR;
718                return (0);
719        }
720
721        switch (sp->handling) {
722        case VCL_RET_RESTART:
723                HSH_Drop(sp);
724                sp->director = NULL;
725                sp->restarts++;
726                sp->step = STP_RECV;
727                return (0);
728        case VCL_RET_HIT_FOR_PASS:
729        case VCL_RET_DELIVER:
730                break;
731        case VCL_RET_ERROR:
732                HSH_Drop(sp);
733                sp->step = STP_ERROR;
734                return (0);
735        default:
736                WRONG("Illegal action in vcl_fetch{}");
737        }
738
739        if (sp->obj->objcore != NULL) {
740                EXP_Insert(sp->obj);
741                AN(sp->obj->objcore);
742                AN(sp->obj->objcore->ban);
743                HSH_Unbusy(sp);
744        }
745        sp->acct_tmp.fetch++;
746        sp->step = STP_DELIVER;
747        return (0);
748}
749
750/*--------------------------------------------------------------------
751 * The very first request
752 */
753static int
754cnt_first(struct sess *sp)
755{
756
757        /*
758         * XXX: If we don't have acceptfilters we are somewhat subject
759         * XXX: to DoS'ing here.  One remedy would be to set a shorter
760         * XXX: SO_RCVTIMEO and once we have received something here
761         * XXX: increase it to the normal value.
762         */
763
764        assert(sp->xid == 0);
765        assert(sp->restarts == 0);
766        VCA_Prep(sp);
767
768        /* Record the session watermark */
769        sp->ws_ses = WS_Snapshot(sp->ws);
770
771        /* Receive a HTTP protocol request */
772        HTC_Init(sp->htc, sp->ws, sp->fd, params->http_req_size,
773            params->http_req_hdr_len);
774        sp->wrk->lastused = sp->t_open;
775        sp->acct_tmp.sess++;
776
777        sp->step = STP_WAIT;
778        return (0);
779}
780
781/*--------------------------------------------------------------------
782 * HIT
783 * We had a cache hit.  Ask VCL, then march off as instructed.
784 *
785DOT subgraph xcluster_hit {
786DOT     hit [
787DOT             shape=record
788DOT             label="vcl_hit()|req.\nobj."
789DOT     ]
790DOT }
791DOT hit -> err_hit [label="error"]
792DOT err_hit [label="ERROR",shape=plaintext]
793DOT hit -> rst_hit [label="restart",color=purple]
794DOT rst_hit [label="RESTART",shape=plaintext]
795DOT hit -> pass [label=pass,style=bold,color=red]
796DOT hit -> deliver [label="deliver",style=bold,color=green,weight=4]
797 */
798
799static int
800cnt_hit(struct sess *sp)
801{
802
803        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
804        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
805        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
806
807        assert(!(sp->obj->objcore->flags & OC_F_PASS));
808
809        VCL_hit_method(sp);
810
811        if (sp->handling == VCL_RET_DELIVER) {
812                /* Dispose of any body part of the request */
813                (void)FetchReqBody(sp);
814                sp->wrk->bereq = NULL;
815                sp->step = STP_DELIVER;
816                return (0);
817        }
818
819        /* Drop our object, we won't need it */
820        (void)HSH_Deref(sp->wrk, NULL, &sp->obj);
821        sp->objcore = NULL;
822
823        switch(sp->handling) {
824        case VCL_RET_PASS:
825                sp->step = STP_PASS;
826                return (0);
827        case VCL_RET_ERROR:
828                sp->step = STP_ERROR;
829                return (0);
830        case VCL_RET_RESTART:
831                sp->director = NULL;
832                sp->restarts++;
833                sp->step = STP_RECV;
834                return (0);
835        default:
836                WRONG("Illegal action in vcl_hit{}");
837        }
838}
839
840/*--------------------------------------------------------------------
841 * LOOKUP
842 * Hash things together and look object up in hash-table.
843 *
844 * LOOKUP consists of two substates so that we can reenter if we
845 * encounter a busy object.
846 *
847DOT subgraph xcluster_lookup {
848DOT     hash [
849DOT             shape=record
850DOT             label="vcl_hash()|req."
851DOT     ]
852DOT     lookup [
853DOT             shape=diamond
854DOT             label="obj in cache ?\ncreate if not"
855DOT     ]
856DOT     lookup2 [
857DOT             shape=diamond
858DOT             label="obj.pass ?"
859DOT     ]
860DOT     hash -> lookup [label="hash",style=bold,color=green,weight=4]
861DOT     lookup -> lookup2 [label="yes",style=bold,color=green,weight=4]
862DOT }
863DOT lookup2 -> hit [label="no", style=bold,color=green,weight=4]
864DOT lookup2 -> pass [label="yes",style=bold,color=red]
865DOT lookup -> miss [label="no",style=bold,color=blue,weight=2]
866 */
867
868static int
869cnt_lookup(struct sess *sp)
870{
871        struct objcore *oc;
872        struct object *o;
873        struct objhead *oh;
874
875        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
876        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
877
878
879        oc = HSH_Lookup(sp, &oh);
880
881        if (oc == NULL) {
882                /*
883                 * We lost the session to a busy object, disembark the
884                 * worker thread.   The hash code to restart the session,
885                 * still in STP_LOOKUP, later when the busy object isn't.
886                 * NB:  Do not access sp any more !
887                 */
888                return (1);
889        }
890
891        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
892        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
893
894        /* If we inserted a new object it's a miss */
895        if (oc->flags & OC_F_BUSY) {
896                sp->wrk->stats.cache_miss++;
897
898                sp->objcore = oc;
899                sp->step = STP_MISS;
900                return (0);
901        }
902
903        o = oc_getobj(sp->wrk, oc);
904        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
905        sp->obj = o;
906
907        if (oc->flags & OC_F_PASS) {
908                sp->wrk->stats.cache_hitpass++;
909                WSP(sp, SLT_HitPass, "%u", sp->obj->xid);
910                (void)HSH_Deref(sp->wrk, NULL, &sp->obj);
911                sp->objcore = NULL;
912                sp->step = STP_PASS;
913                return (0);
914        }
915
916        sp->wrk->stats.cache_hit++;
917        WSP(sp, SLT_Hit, "%u", sp->obj->xid);
918        sp->step = STP_HIT;
919        return (0);
920}
921
922/*--------------------------------------------------------------------
923 * We had a miss, ask VCL, proceed as instructed
924 *
925DOT subgraph xcluster_miss {
926DOT     miss [
927DOT             shape=ellipse
928DOT             label="filter req.->bereq."
929DOT     ]
930DOT     vcl_miss [
931DOT             shape=record
932DOT             label="vcl_miss()|req.\nbereq."
933DOT     ]
934DOT     miss -> vcl_miss [style=bold,color=blue,weight=2]
935DOT }
936DOT vcl_miss -> rst_miss [label="restart",color=purple]
937DOT rst_miss [label="RESTART",shape=plaintext]
938DOT vcl_miss -> err_miss [label="error"]
939DOT err_miss [label="ERROR",shape=plaintext]
940DOT vcl_miss -> fetch [label="fetch",style=bold,color=blue,weight=2]
941DOT vcl_miss -> pass [label="pass",style=bold,color=red]
942DOT
943 */
944
945static int
946cnt_miss(struct sess *sp)
947{
948
949        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
950        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
951
952        AZ(sp->obj);
953        AN(sp->objcore);
954        WS_Reset(sp->wrk->ws, NULL);
955        sp->wrk->bereq = sp->wrk->http[0];
956        http_Setup(sp->wrk->bereq, sp->wrk->ws);
957        http_FilterHeader(sp, HTTPH_R_FETCH);
958        http_ForceGet(sp->wrk->bereq);
959        if (params->http_gzip_support) {
960                /*
961                 * We always ask the backend for gzip, even if the
962                 * client doesn't grok it.  We will uncompress for
963                 * the minority of clients which don't.
964                 */
965                http_Unset(sp->wrk->bereq, H_Accept_Encoding);
966                http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->bereq,
967                    "Accept-Encoding: gzip");
968        }
969        sp->wrk->connect_timeout = 0;
970        sp->wrk->first_byte_timeout = 0;
971        sp->wrk->between_bytes_timeout = 0;
972        VCL_miss_method(sp);
973        switch(sp->handling) {
974        case VCL_RET_ERROR:
975                AZ(HSH_Deref(sp->wrk, sp->objcore, NULL));
976                sp->objcore = NULL;
977                sp->step = STP_ERROR;
978                return (0);
979        case VCL_RET_PASS:
980                AZ(HSH_Deref(sp->wrk, sp->objcore, NULL));
981                sp->objcore = NULL;
982                sp->step = STP_PASS;
983                return (0);
984        case VCL_RET_FETCH:
985                sp->step = STP_FETCH;
986                return (0);
987        case VCL_RET_RESTART:
988                AZ(HSH_Deref(sp->wrk, sp->objcore, NULL));
989                sp->objcore = NULL;
990                INCOMPL();
991        default:
992                WRONG("Illegal action in vcl_miss{}");
993        }
994}
995
996/*--------------------------------------------------------------------
997 * Start pass processing by getting headers from backend, then
998 * continue in passbody.
999 *
1000DOT subgraph xcluster_pass {
1001DOT     pass [
1002DOT             shape=ellipse
1003DOT             label="deref obj."
1004DOT     ]
1005DOT     pass2 [
1006DOT             shape=ellipse
1007DOT             label="filter req.->bereq."
1008DOT     ]
1009DOT     vcl_pass [
1010DOT             shape=record
1011DOT             label="vcl_pass()|req.\nbereq."
1012DOT     ]
1013DOT     pass_do [
1014DOT             shape=ellipse
1015DOT             label="create anon object\n"
1016DOT     ]
1017DOT     pass -> pass2 [style=bold, color=red]
1018DOT     pass2 -> vcl_pass [style=bold, color=red]
1019DOT     vcl_pass -> pass_do [label="pass"] [style=bold, color=red]
1020DOT }
1021DOT pass_do -> fetch [style=bold, color=red]
1022DOT vcl_pass -> rst_pass [label="restart",color=purple]
1023DOT rst_pass [label="RESTART",shape=plaintext]
1024DOT vcl_pass -> err_pass [label="error"]
1025DOT err_pass [label="ERROR",shape=plaintext]
1026 */
1027
1028static int
1029cnt_pass(struct sess *sp)
1030{
1031
1032        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1033        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
1034        AZ(sp->obj);
1035
1036        WS_Reset(sp->wrk->ws, NULL);
1037        sp->wrk->bereq = sp->wrk->http[0];
1038        http_Setup(sp->wrk->bereq, sp->wrk->ws);
1039        http_FilterHeader(sp, HTTPH_R_PASS);
1040
1041        sp->wrk->connect_timeout = 0;
1042        sp->wrk->first_byte_timeout = 0;
1043        sp->wrk->between_bytes_timeout = 0;
1044        VCL_pass_method(sp);
1045        if (sp->handling == VCL_RET_ERROR) {
1046                sp->step = STP_ERROR;
1047                return (0);
1048        }
1049        assert(sp->handling == VCL_RET_PASS);
1050        sp->acct_tmp.pass++;
1051        sp->sendbody = 1;
1052        sp->step = STP_FETCH;
1053        return (0);
1054}
1055
1056/*--------------------------------------------------------------------
1057 * Ship the request header to the backend unchanged, then pipe
1058 * until one of the ends close the connection.
1059 *
1060DOT subgraph xcluster_pipe {
1061DOT     pipe [
1062DOT             shape=ellipse
1063DOT             label="Filter req.->bereq."
1064DOT     ]
1065DOT     vcl_pipe [
1066DOT             shape=record
1067DOT             label="vcl_pipe()|req.\nbereq\."
1068DOT     ]
1069DOT     pipe_do [
1070DOT             shape=ellipse
1071DOT             label="send bereq.\npipe until close"
1072DOT     ]
1073DOT     vcl_pipe -> pipe_do [label="pipe",style=bold,color=orange]
1074DOT     pipe -> vcl_pipe [style=bold,color=orange]
1075DOT }
1076DOT pipe_do -> DONE [style=bold,color=orange]
1077DOT vcl_pipe -> err_pipe [label="error"]
1078DOT err_pipe [label="ERROR",shape=plaintext]
1079 */
1080
1081static int
1082cnt_pipe(struct sess *sp)
1083{
1084
1085        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1086        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
1087
1088        sp->acct_tmp.pipe++;
1089        WS_Reset(sp->wrk->ws, NULL);
1090        sp->wrk->bereq = sp->wrk->http[0];
1091        http_Setup(sp->wrk->bereq, sp->wrk->ws);
1092        http_FilterHeader(sp, HTTPH_R_PIPE);
1093
1094        VCL_pipe_method(sp);
1095
1096        if (sp->handling == VCL_RET_ERROR)
1097                INCOMPL();
1098        assert(sp->handling == VCL_RET_PIPE);
1099
1100        PipeSession(sp);
1101        AZ(sp->wrk->wfd);
1102        sp->wrk->bereq = NULL;
1103        sp->step = STP_DONE;
1104        return (0);
1105}
1106
1107/*--------------------------------------------------------------------
1108 * RECV
1109 * We have a complete request, set everything up and start it.
1110 *
1111DOT subgraph xcluster_recv {
1112DOT     recv [
1113DOT             shape=record
1114DOT             label="vcl_recv()|req."
1115DOT     ]
1116DOT }
1117DOT RESTART -> recv
1118DOT recv -> pipe [label="pipe",style=bold,color=orange]
1119DOT recv -> pass2 [label="pass",style=bold,color=red]
1120DOT recv -> err_recv [label="error"]
1121DOT err_recv [label="ERROR",shape=plaintext]
1122DOT recv -> hash [label="lookup",style=bold,color=green,weight=4]
1123 */
1124
1125static int
1126cnt_recv(struct sess *sp)
1127{
1128        unsigned recv_handling;
1129
1130        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1131        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
1132        AZ(sp->obj);
1133
1134        /* By default we use the first backend */
1135        AZ(sp->director);
1136        sp->director = sp->vcl->director[0];
1137        AN(sp->director);
1138
1139        sp->disable_esi = 0;
1140        sp->hash_always_miss = 0;
1141        sp->hash_ignore_busy = 0;
1142        sp->client_identity = NULL;
1143
1144        http_CollectHdr(sp->http, H_Cache_Control);
1145
1146        VCL_recv_method(sp);
1147        recv_handling = sp->handling;
1148
1149        if (sp->restarts >= params->max_restarts) {
1150                if (sp->err_code == 0)
1151                        sp->err_code = 503;
1152                sp->step = STP_ERROR;
1153                return (0);
1154        }
1155
1156        sp->wrk->is_gzip = 0;
1157        sp->wrk->is_gunzip = 0;
1158        sp->wrk->do_gzip = 0;
1159        sp->wrk->do_gunzip = 0;
1160
1161        if (params->http_gzip_support &&
1162             (recv_handling != VCL_RET_PIPE) &&
1163             (recv_handling != VCL_RET_PASS)) {
1164                if (RFC2616_Req_Gzip(sp)) {
1165                        http_Unset(sp->http, H_Accept_Encoding);
1166                        http_PrintfHeader(sp->wrk, sp->fd, sp->http,
1167                            "Accept-Encoding: gzip");
1168                } else {
1169                        http_Unset(sp->http, H_Accept_Encoding);
1170                }
1171        }
1172
1173        SHA256_Init(sp->wrk->sha256ctx);
1174        VCL_hash_method(sp);
1175        assert(sp->handling == VCL_RET_HASH);
1176        SHA256_Final(sp->digest, sp->wrk->sha256ctx);
1177
1178        if (!strcmp(sp->http->hd[HTTP_HDR_REQ].b, "HEAD"))
1179                sp->wantbody = 0;
1180        else
1181                sp->wantbody = 1;
1182
1183        sp->sendbody = 0;
1184        switch(recv_handling) {
1185        case VCL_RET_LOOKUP:
1186                /* XXX: discard req body, if any */
1187                sp->step = STP_LOOKUP;
1188                return (0);
1189        case VCL_RET_PIPE:
1190                if (sp->esi_level > 0) {
1191                        /* XXX: VSL something */
1192                        INCOMPL();
1193                        /* sp->step = STP_DONE; */
1194                        return (1);
1195                }
1196                sp->step = STP_PIPE;
1197                return (0);
1198        case VCL_RET_PASS:
1199                sp->step = STP_PASS;
1200                return (0);
1201        case VCL_RET_ERROR:
1202                /* XXX: discard req body, if any */
1203                sp->step = STP_ERROR;
1204                return (0);
1205        default:
1206                WRONG("Illegal action in vcl_recv{}");
1207        }
1208}
1209
1210/*--------------------------------------------------------------------
1211 * START
1212 * Handle a request, wherever it came from recv/restart.
1213 *
1214DOT start [shape=box,label="Dissect request"]
1215DOT start -> recv [style=bold,color=green,weight=4]
1216 */
1217
1218static int
1219cnt_start(struct sess *sp)
1220{
1221        int done;
1222        char *p;
1223        const char *r = "HTTP/1.1 100 Continue\r\n\r\n";
1224
1225        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1226        AZ(sp->restarts);
1227        AZ(sp->obj);
1228        AZ(sp->vcl);
1229
1230        /* Update stats of various sorts */
1231        sp->wrk->stats.client_req++;
1232        sp->t_req = TIM_real();
1233        sp->wrk->lastused = sp->t_req;
1234        sp->acct_tmp.req++;
1235
1236        /* Assign XID and log */
1237        sp->xid = ++xids;                               /* XXX not locked */
1238        WSP(sp, SLT_ReqStart, "%s %s %u", sp->addr, sp->port,  sp->xid);
1239
1240        /* Borrow VCL reference from worker thread */
1241        VCL_Refresh(&sp->wrk->vcl);
1242        sp->vcl = sp->wrk->vcl;
1243        sp->wrk->vcl = NULL;
1244
1245        http_Setup(sp->http, sp->ws);
1246        done = http_DissectRequest(sp);
1247
1248        /* If we could not even parse the request, just close */
1249        if (done < 0) {
1250                sp->step = STP_DONE;
1251                vca_close_session(sp, "junk");
1252                return (0);
1253        }
1254
1255        /* Catch request snapshot */
1256        sp->ws_req = WS_Snapshot(sp->ws);
1257
1258        /* Catch original request, before modification */
1259        HTTP_Copy(sp->http0, sp->http);
1260
1261        if (done != 0) {
1262                sp->err_code = done;
1263                sp->step = STP_ERROR;
1264                return (0);
1265        }
1266
1267        sp->doclose = http_DoConnection(sp->http);
1268
1269        /* XXX: Handle TRACE & OPTIONS of Max-Forwards = 0 */
1270
1271        /*
1272         * Handle Expect headers
1273         */
1274        if (http_GetHdr(sp->http, H_Expect, &p)) {
1275                if (strcasecmp(p, "100-continue")) {
1276                        sp->err_code = 417;
1277                        sp->step = STP_ERROR;
1278                        return (0);
1279                }
1280
1281                /* XXX: Don't bother with write failures for now */
1282                (void)write(sp->fd, r, strlen(r));
1283                /* XXX: When we do ESI includes, this is not removed
1284                 * XXX: because we use http0 as our basis.  Believed
1285                 * XXX: safe, but potentially confusing.
1286                 */
1287                http_Unset(sp->http, H_Expect);
1288        }
1289
1290        sp->step = STP_RECV;
1291        return (0);
1292}
1293
1294/*--------------------------------------------------------------------
1295 * Central state engine dispatcher.
1296 *
1297 * Kick the session around until it has had enough.
1298 *
1299 */
1300
1301static void
1302cnt_diag(struct sess *sp, const char *state)
1303{
1304        if (sp->wrk != NULL) {
1305                WSL(sp->wrk, SLT_Debug, sp->id,
1306                    "thr %p STP_%s sp %p obj %p vcl %p",
1307                    pthread_self(), state, sp, sp->obj, sp->vcl);
1308                WSL_Flush(sp->wrk, 0);
1309        } else {
1310                VSL(SLT_Debug, sp->id,
1311                    "thr %p STP_%s sp %p obj %p vcl %p",
1312                    pthread_self(), state, sp, sp->obj, sp->vcl);
1313        }
1314}
1315
1316void
1317CNT_Session(struct sess *sp)
1318{
1319        int done;
1320        struct worker *w;
1321
1322        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1323        w = sp->wrk;
1324        CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
1325
1326        /*
1327         * Possible entrance states
1328         */
1329        assert(
1330            sp->step == STP_FIRST ||
1331            sp->step == STP_START ||
1332            sp->step == STP_LOOKUP ||
1333            sp->step == STP_RECV);
1334
1335        /*
1336         * Whenever we come in from the acceptor we need to set blocking
1337         * mode, but there is no point in setting it when we come from
1338         * ESI or when a parked sessions returns.
1339         * It would be simpler to do this in the acceptor, but we'd rather
1340         * do the syscall in the worker thread.
1341         */
1342        if (sp->step == STP_FIRST || sp->step == STP_START)
1343                (void)TCP_blocking(sp->fd);
1344
1345        /*
1346         * NB: Once done is set, we can no longer touch sp!
1347         */
1348        for (done = 0; !done; ) {
1349                assert(sp->wrk == w);
1350                /*
1351                 * This is a good place to be paranoid about the various
1352                 * pointers still pointing to the things we expect.
1353                 */
1354                CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1355                CHECK_OBJ_ORNULL(sp->obj, OBJECT_MAGIC);
1356                CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
1357                CHECK_OBJ_ORNULL(w->nobjhead, OBJHEAD_MAGIC);
1358                WS_Assert(w->ws);
1359                AZ(sp->wrk->storage_hint);
1360
1361                switch (sp->step) {
1362#define STEP(l,u) \
1363                    case STP_##u: \
1364                        if (params->diag_bitmap & 0x01) \
1365                                cnt_diag(sp, #u); \
1366                        done = cnt_##l(sp); \
1367                        break;
1368#include "steps.h"
1369#undef STEP
1370                default:
1371                        WRONG("State engine misfire");
1372                }
1373                WS_Assert(w->ws);
1374                CHECK_OBJ_ORNULL(w->nobjhead, OBJHEAD_MAGIC);
1375        }
1376        WSL_Flush(w, 0);
1377        AZ(w->wfd);
1378}
1379
1380/*
1381DOT }
1382*/
1383
1384/*--------------------------------------------------------------------
1385 * Debugging aids
1386 */
1387
1388static void
1389cli_debug_xid(struct cli *cli, const char * const *av, void *priv)
1390{
1391        (void)priv;
1392        if (av[2] != NULL)
1393                xids = strtoul(av[2], NULL, 0);
1394        cli_out(cli, "XID is %u", xids);
1395}
1396
1397/*
1398 * Default to seed=1, this is the only seed value POSIXl guarantees will
1399 * result in a reproducible random number sequence.
1400 */
1401static void
1402cli_debug_srandom(struct cli *cli, const char * const *av, void *priv)
1403{
1404        (void)priv;
1405        unsigned seed = 1;
1406
1407        if (av[2] != NULL)
1408                seed = strtoul(av[2], NULL, 0);
1409        srandom(seed);
1410        srand48(random());
1411        cli_out(cli, "Random(3) seeded with %lu", seed);
1412}
1413
1414static struct cli_proto debug_cmds[] = {
1415        { "debug.xid", "debug.xid",
1416                "\tExamine or set XID\n", 0, 1, "d", cli_debug_xid },
1417        { "debug.srandom", "debug.srandom",
1418                "\tSeed the random(3) function\n", 0, 1, "d", cli_debug_srandom },
1419        { NULL }
1420};
1421
1422/*--------------------------------------------------------------------
1423 *
1424 */
1425
1426void
1427CNT_Init(void)
1428{
1429
1430        srandomdev();
1431        srand48(random());
1432        xids = random();
1433        CLI_AddFuncs(debug_cmds);
1434}
1435
1436
Note: See TracBrowser for help on using the repository browser.