source: bin/varnishd/cache_center.c @ 0c80b0

Revision 0c80b0, 34.2 KB checked in by Poul-Henning Kamp <phk@…>, 3 years ago (diff)

Normalize requests Accept-Encoding header if we are not pipe or pass
after vcl_recv{}. This is necessary to get consistent Vary: header
processing.

  • 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, sp->t_resp);
213                sp->obj->last_use = sp->t_resp; /* XXX: locking ? */
214        }
215        sp->wrk->resp = sp->wrk->http[2];
216        http_Setup(sp->wrk->resp, sp->wrk->ws);
217        RES_BuildHttp(sp);
218        VCL_deliver_method(sp);
219        switch (sp->handling) {
220        case VCL_RET_DELIVER:
221                break;
222        case VCL_RET_RESTART:
223                if (sp->restarts >= params->max_restarts)
224                        break;
225                (void)HSH_Deref(sp->wrk, NULL, &sp->obj);
226                AZ(sp->obj);
227                sp->restarts++;
228                sp->director = NULL;
229                sp->wrk->bereq = NULL;
230                sp->wrk->beresp = NULL;
231                sp->wrk->beresp1 = NULL;
232                sp->wrk->resp = NULL;
233                sp->step = STP_RECV;
234                return (0);
235        default:
236                WRONG("Illegal action in vcl_deliver{}");
237        }
238
239        sp->director = NULL;
240        sp->restarts = 0;
241
242        RES_WriteObj(sp);
243
244        AZ(sp->wrk->wfd);
245        (void)HSH_Deref(sp->wrk, NULL, &sp->obj);
246        sp->wrk->resp = NULL;
247        sp->step = STP_DONE;
248        return (0);
249}
250
251/*--------------------------------------------------------------------
252 * This is the final state, figure out if we should close or recycle
253 * the client connection
254 *
255DOT     DONE [
256DOT             shape=hexagon
257DOT             label="Request completed"
258DOT     ]
259 */
260
261static int
262cnt_done(struct sess *sp)
263{
264        double dh, dp, da;
265        int i;
266
267        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
268        CHECK_OBJ_ORNULL(sp->vcl, VCL_CONF_MAGIC);
269
270        AZ(sp->obj);
271        AZ(sp->vbc);
272        sp->director = NULL;
273        sp->restarts = 0;
274
275        if (sp->vcl != NULL && sp->esi_level == 0) {
276                if (sp->wrk->vcl != NULL)
277                        VCL_Rel(&sp->wrk->vcl);
278                sp->wrk->vcl = sp->vcl;
279                sp->vcl = NULL;
280        }
281
282        SES_Charge(sp);
283
284        sp->t_end = TIM_real();
285        sp->wrk->lastused = sp->t_end;
286        if (sp->xid == 0) {
287                sp->t_req = sp->t_end;
288                sp->t_resp = sp->t_end;
289        } else if (sp->esi_level == 0) {
290                dp = sp->t_resp - sp->t_req;
291                da = sp->t_end - sp->t_resp;
292                dh = sp->t_req - sp->t_open;
293                /* XXX: Add StatReq == StatSess */
294                WSP(sp, SLT_Length, "%u", sp->acct_req.bodybytes);
295                WSL(sp->wrk, SLT_ReqEnd, sp->id, "%u %.9f %.9f %.9f %.9f %.9f",
296                    sp->xid, sp->t_req, sp->t_end, dh, dp, da);
297        }
298        sp->xid = 0;
299        sp->t_open = sp->t_end;
300        sp->t_resp = NAN;
301        WSL_Flush(sp->wrk, 0);
302
303        /* If we did an ESI include, don't mess up our state */
304        if (sp->esi_level > 0)
305                return (1);
306
307        memset(&sp->acct_req, 0, sizeof sp->acct_req);
308
309        sp->t_req = NAN;
310        sp->hash_always_miss = 0;
311        sp->hash_ignore_busy = 0;
312
313        if (sp->fd >= 0 && sp->doclose != NULL) {
314                /*
315                 * This is an orderly close of the connection; ditch nolinger
316                 * before we close, to get queued data transmitted.
317                 */
318                // XXX: not yet (void)TCP_linger(sp->fd, 0);
319                vca_close_session(sp, sp->doclose);
320        }
321
322        if (sp->fd < 0) {
323                sp->wrk->stats.sess_closed++;
324                sp->wrk = NULL;
325                SES_Delete(sp);
326                return (1);
327        }
328
329        if (sp->wrk->stats.client_req >= params->wthread_stats_rate)
330                WRK_SumStat(sp->wrk);
331        /* Reset the workspace to the session-watermark */
332        WS_Reset(sp->ws, sp->ws_ses);
333        WS_Reset(sp->wrk->ws, NULL);
334
335        i = HTC_Reinit(sp->htc);
336        if (i == 1) {
337                sp->wrk->stats.sess_pipeline++;
338                sp->step = STP_START;
339                return (0);
340        }
341        if (Tlen(sp->htc->rxbuf)) {
342                sp->wrk->stats.sess_readahead++;
343                sp->step = STP_WAIT;
344                return (0);
345        }
346        if (params->session_linger > 0) {
347                sp->wrk->stats.sess_linger++;
348                sp->step = STP_WAIT;
349                return (0);
350        }
351        sp->wrk->stats.sess_herd++;
352        sp->wrk = NULL;
353        vca_return_session(sp);
354        return (1);
355}
356
357/*--------------------------------------------------------------------
358 * Emit an error
359 *
360DOT subgraph xcluster_error {
361DOT     vcl_error [
362DOT             shape=record
363DOT             label="vcl_error()|resp."
364DOT     ]
365DOT     ERROR -> vcl_error
366DOT     vcl_error-> deliver [label=deliver]
367DOT }
368 */
369
370static int
371cnt_error(struct sess *sp)
372{
373        struct worker *w;
374        struct http *h;
375        char date[40];
376
377        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
378
379        w = sp->wrk;
380        if (sp->obj == NULL) {
381                HSH_Prealloc(sp);
382                sp->wrk->cacheable = 0;
383                /* XXX: 1024 is a pure guess */
384                sp->obj = STV_NewObject(sp, NULL, 1024, 0,
385                     params->http_headers);
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 * We have fetched the headers from the backend, ask the VCL code what
436 * to do next, then head off in that direction.
437 *
438DOT subgraph xcluster_fetch {
439DOT     fetch [
440DOT             shape=ellipse
441DOT             label="fetch from backend\n(find obj.ttl)"
442DOT     ]
443DOT     vcl_fetch [
444DOT             shape=record
445DOT             label="vcl_fetch()|req.\nbereq.\nberesp."
446DOT     ]
447DOT     fetch -> vcl_fetch [style=bold,color=blue,weight=2]
448DOT     fetch_pass [
449DOT             shape=ellipse
450DOT             label="obj.pass=true"
451DOT     ]
452DOT     vcl_fetch -> fetch_pass [label="pass",style=bold,color=red]
453DOT }
454DOT fetch_pass -> deliver [style=bold,color=red]
455DOT vcl_fetch -> deliver [label="deliver",style=bold,color=blue,weight=2]
456DOT vcl_fetch -> recv [label="restart"]
457DOT vcl_fetch -> rstfetch [label="restart",color=purple]
458DOT rstfetch [label="RESTART",shape=plaintext]
459DOT fetch -> errfetch
460DOT vcl_fetch -> errfetch [label="error"]
461DOT errfetch [label="ERROR",shape=plaintext]
462 */
463
464static int
465cnt_fetch(struct sess *sp)
466{
467        int i;
468        struct http *hp, *hp2;
469        char *b;
470        unsigned l, nhttp;
471        int varyl = 0;
472        struct vsb *vary = NULL;
473
474        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
475        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
476
477        AN(sp->director);
478        AZ(sp->vbc);
479
480        /* sp->wrk->http[0] is (still) bereq */
481        sp->wrk->beresp = sp->wrk->http[1];
482        http_Setup(sp->wrk->beresp, sp->wrk->ws);
483
484        i = FetchHdr(sp);
485        /*
486         * If we recycle a backend connection, there is a finite chance
487         * that the backend closed it before we get a request to it.
488         * Do a single retry in that case.
489         */
490        if (i == 1) {
491                VSC_main->backend_retry++;
492                i = FetchHdr(sp);
493        }
494
495        /*
496         * These two headers can be spread over multiple actual headers
497         * and we rely on their content outside of VCL, so collect them
498         * into one line here.
499         */
500        http_CollectHdr(sp->wrk->beresp, H_Cache_Control);
501        http_CollectHdr(sp->wrk->beresp, H_Vary);
502
503        /*
504         * Save a copy before it might get mangled in VCL.  When it comes to
505         * dealing with the body, we want to see the unadultered headers.
506         */
507        sp->wrk->beresp1 = sp->wrk->http[2];
508        *sp->wrk->beresp1 = *sp->wrk->beresp;
509
510        if (i) {
511                if (sp->objcore != NULL) {
512                        CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC);
513                        AZ(HSH_Deref(sp->wrk, sp->objcore, NULL));
514                        sp->objcore = NULL;
515                }
516                AZ(sp->obj);
517                sp->wrk->bereq = NULL;
518                sp->wrk->beresp = NULL;
519                sp->wrk->beresp1 = NULL;
520                sp->err_code = 503;
521                sp->step = STP_ERROR;
522                return (0);
523        }
524
525        sp->err_code = http_GetStatus(sp->wrk->beresp);
526
527        /*
528         * Initial cacheability determination per [RFC2616, 13.4]
529         * We do not support ranges yet, so 206 is out.
530         */
531        switch (sp->err_code) {
532        case 200: /* OK */
533        case 203: /* Non-Authoritative Information */
534        case 300: /* Multiple Choices */
535        case 301: /* Moved Permanently */
536        case 302: /* Moved Temporarily */
537        case 410: /* Gone */
538        case 404: /* Not Found */
539                sp->wrk->cacheable = 1;
540                break;
541        default:
542                sp->wrk->cacheable = 0;
543                break;
544        }
545
546        sp->wrk->entered = TIM_real();
547        sp->wrk->age = 0;
548        sp->wrk->ttl = RFC2616_Ttl(sp);
549
550        if (sp->objcore == NULL)
551                sp->wrk->cacheable = 0;
552
553        sp->wrk->do_esi = 0;
554        sp->wrk->grace = NAN;
555
556        sp->wrk->body_status = RFC2616_Body(sp);
557
558        AZ(sp->wrk->storage_hint);
559
560        VCL_fetch_method(sp);
561
562        if (sp->objcore == NULL) {
563                /* This is a pass from vcl_recv */
564                sp->wrk->cacheable = 0;
565        } else if (!sp->wrk->cacheable && sp->objcore != NULL) {
566                AZ(HSH_Deref(sp->wrk, sp->objcore, NULL));
567                sp->objcore = NULL;
568        }
569
570        /*
571         * At this point we are either committed to flesh out the busy
572         * object we have in the hash or we have let go of it, if we ever
573         * had one.
574         */
575
576        if (sp->wrk->cacheable) {
577                CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC);
578                vary = VRY_Create(sp, sp->wrk->beresp);
579                if (vary != NULL) {
580                        varyl = vsb_len(vary);
581                        assert(varyl > 0);
582                }
583        } else {
584                AZ(sp->objcore);
585        }
586
587        AZ(sp->wrk->vfp);
588
589        /*
590         * The VCL variables beresp.do_g[un]zip tells us how we want the
591         * object stored.
592         *
593         * The backend Content-Encoding header tells us what we are going
594         * to receive, which we classify in the following three classes:
595         *
596         *      "Content-Encoding: gzip"        --> object is gzip'ed.
597         *      no Content-Encoding             --> object is not gzip'ed.
598         *      anything else                   --> do nothing wrt gzip
599         *
600         */
601
602        /* We do nothing unless the param is set */
603        if (!params->http_gzip_support)
604                sp->wrk->do_gzip = sp->wrk->do_gunzip = 0;
605
606        sp->wrk->is_gzip = 
607            http_HdrIs(sp->wrk->beresp, H_Content_Encoding, "gzip");
608
609        sp->wrk->is_gunzip = 
610            !http_GetHdr(sp->wrk->beresp, H_Content_Encoding, NULL);
611
612        /* It can't be both */
613        assert(sp->wrk->is_gzip == 0 || sp->wrk->is_gunzip == 0);
614
615        /* We won't gunzip unless it is gzip'ed */
616        if (sp->wrk->do_gunzip && !sp->wrk->is_gzip)
617                sp->wrk->do_gunzip = 0;
618
619        /* If we do gunzip, remove the C-E header */
620        if (sp->wrk->do_gunzip)
621                http_Unset(sp->wrk->beresp, H_Content_Encoding);
622
623        /* We wont gzip unless it is ungziped */
624        if (sp->wrk->do_gzip && !sp->wrk->is_gunzip)
625                sp->wrk->do_gzip = 0;
626
627        /* If we do gzip, add the C-E header */
628        if (sp->wrk->do_gzip) 
629                http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->beresp,
630                    "Content-Encoding: %s", "gzip");
631
632        /* But we can't do both at the same time */
633        assert(sp->wrk->do_gzip == 0 || sp->wrk->do_gunzip == 0);
634
635        /* ESI takes precedence and handles gzip/gunzip itself */
636        if (sp->wrk->do_esi)
637                sp->wrk->vfp = &vfp_esi;
638        else if (sp->wrk->do_gunzip)
639                sp->wrk->vfp = &vfp_gunzip;
640        else if (sp->wrk->do_gzip)
641                sp->wrk->vfp = &vfp_gzip;
642        else if (sp->wrk->is_gzip)
643                sp->wrk->vfp = &vfp_testgzip;
644
645        l = http_EstimateWS(sp->wrk->beresp,
646            sp->pass ? HTTPH_R_PASS : HTTPH_A_INS, &nhttp);
647
648        if (vary != NULL)
649                l += varyl;
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-Encoding: XxxXxxXxxXxxXxxXxx" + sizeof(void *));
656
657        /*
658         * XXX: VFP's may affect estimate
659         */
660
661        sp->obj = STV_NewObject(sp, sp->wrk->storage_hint, l,
662            sp->wrk->ttl, nhttp);
663        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
664
665        sp->wrk->storage_hint = NULL;
666        sp->obj->gziped = sp->wrk->is_gzip;
667
668        if (vary != NULL) {
669                sp->obj->vary =
670                    (void *)WS_Alloc(sp->obj->http->ws, varyl);
671                AN(sp->obj->vary);
672                memcpy(sp->obj->vary, vsb_data(vary), varyl);
673                vsb_delete(vary);
674                vary = NULL;
675        }
676
677        sp->obj->xid = sp->xid;
678        sp->obj->response = sp->err_code;
679        sp->obj->cacheable = sp->wrk->cacheable;
680        sp->obj->grace = sp->wrk->grace;
681        if (sp->obj->ttl == 0. && sp->obj->grace == 0.)
682                sp->obj->cacheable = 0;
683        sp->obj->age = sp->wrk->age;
684        sp->obj->entered = sp->wrk->entered;
685        WS_Assert(sp->obj->ws_o);
686
687
688        /* Filter into object */
689        hp = sp->wrk->beresp;
690        hp2 = sp->obj->http;
691
692        hp2->logtag = HTTP_Obj;
693        http_CopyResp(hp2, hp);
694        http_FilterFields(sp->wrk, sp->fd, hp2, hp,
695            sp->pass ? HTTPH_R_PASS : HTTPH_A_INS);
696        http_CopyHome(sp->wrk, sp->fd, hp2);
697
698        if (http_GetHdr(hp, H_Last_Modified, &b))
699                sp->obj->last_modified = TIM_parse(b);
700        else
701                sp->obj->last_modified = sp->wrk->entered;
702
703        i = FetchBody(sp);
704        sp->wrk->vfp = NULL;
705        AZ(sp->wrk->wfd);
706        AZ(sp->vbc);
707        AN(sp->director);
708
709        if (i) {
710                HSH_Drop(sp);
711                AZ(sp->obj);
712                sp->wrk->bereq = NULL;
713                sp->wrk->beresp = NULL;
714                sp->wrk->beresp1 = NULL;
715                sp->err_code = 503;
716                sp->step = STP_ERROR;
717                return (0);
718        }
719
720        switch (sp->handling) {
721        case VCL_RET_RESTART:
722                HSH_Drop(sp);
723                sp->director = NULL;
724                sp->restarts++;
725                sp->wrk->bereq = NULL;
726                sp->wrk->beresp = NULL;
727                sp->wrk->beresp1 = NULL;
728                sp->step = STP_RECV;
729                return (0);
730        case VCL_RET_PASS:
731                if (sp->obj->objcore != NULL)
732                        sp->obj->objcore->flags |= OC_F_PASS;
733                if (sp->obj->ttl - sp->t_req < params->default_ttl)
734                        sp->obj->ttl = sp->t_req + params->default_ttl;
735                break;
736        case VCL_RET_DELIVER:
737                break;
738        case VCL_RET_ERROR:
739                HSH_Drop(sp);
740                sp->wrk->bereq = NULL;
741                sp->wrk->beresp = NULL;
742                sp->wrk->beresp1 = NULL;
743                sp->step = STP_ERROR;
744                return (0);
745        default:
746                WRONG("Illegal action in vcl_fetch{}");
747        }
748
749        sp->obj->cacheable = 1;
750        if (sp->wrk->cacheable) {
751                EXP_Insert(sp->obj);
752                AN(sp->obj->objcore);
753                AN(sp->obj->objcore->ban);
754                HSH_Unbusy(sp);
755        }
756        sp->acct_tmp.fetch++;
757        sp->wrk->bereq = NULL;
758        sp->wrk->beresp = NULL;
759        sp->wrk->beresp1 = NULL;
760        sp->step = STP_DELIVER;
761        return (0);
762}
763
764/*--------------------------------------------------------------------
765 * The very first request
766 */
767static int
768cnt_first(struct sess *sp)
769{
770
771        /*
772         * XXX: If we don't have acceptfilters we are somewhat subject
773         * XXX: to DoS'ing here.  One remedy would be to set a shorter
774         * XXX: SO_RCVTIMEO and once we have received something here
775         * XXX: increase it to the normal value.
776         */
777
778        assert(sp->xid == 0);
779        assert(sp->restarts == 0);
780        VCA_Prep(sp);
781
782        /* Record the session watermark */
783        sp->ws_ses = WS_Snapshot(sp->ws);
784
785        /* Receive a HTTP protocol request */
786        HTC_Init(sp->htc, sp->ws, sp->fd);
787        sp->wrk->lastused = sp->t_open;
788        sp->acct_tmp.sess++;
789
790        sp->step = STP_WAIT;
791        return (0);
792}
793
794/*--------------------------------------------------------------------
795 * HIT
796 * We had a cache hit.  Ask VCL, then march off as instructed.
797 *
798DOT subgraph xcluster_hit {
799DOT     hit [
800DOT             shape=record
801DOT             label="vcl_hit()|req.\nobj."
802DOT     ]
803DOT }
804DOT hit -> err_hit [label="error"]
805DOT err_hit [label="ERROR",shape=plaintext]
806DOT hit -> rst_hit [label="restart",color=purple]
807DOT rst_hit [label="RESTART",shape=plaintext]
808DOT hit -> pass [label=pass,style=bold,color=red]
809DOT hit -> deliver [label="deliver",style=bold,color=green,weight=4]
810 */
811
812static int
813cnt_hit(struct sess *sp)
814{
815
816        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
817        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
818        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
819
820        assert(!(sp->obj->objcore->flags & OC_F_PASS));
821
822        VCL_hit_method(sp);
823
824        if (sp->handling == VCL_RET_DELIVER) {
825                /* Dispose of any body part of the request */
826                (void)FetchReqBody(sp);
827                sp->wrk->bereq = NULL;
828                sp->step = STP_DELIVER;
829                return (0);
830        }
831
832        /* Drop our object, we won't need it */
833        (void)HSH_Deref(sp->wrk, NULL, &sp->obj);
834        sp->objcore = NULL;
835
836        switch(sp->handling) {
837        case VCL_RET_PASS:
838                sp->step = STP_PASS;
839                return (0);
840        case VCL_RET_ERROR:
841                sp->step = STP_ERROR;
842                return (0);
843        case VCL_RET_RESTART:
844                sp->director = NULL;
845                sp->restarts++;
846                sp->step = STP_RECV;
847                return (0);
848        default:
849                WRONG("Illegal action in vcl_hit{}");
850        }
851}
852
853/*--------------------------------------------------------------------
854 * LOOKUP
855 * Hash things together and look object up in hash-table.
856 *
857 * LOOKUP consists of two substates so that we can reenter if we
858 * encounter a busy object.
859 *
860DOT subgraph xcluster_lookup {
861DOT     hash [
862DOT             shape=record
863DOT             label="vcl_hash()|req."
864DOT     ]
865DOT     lookup [
866DOT             shape=diamond
867DOT             label="obj in cache ?\ncreate if not"
868DOT     ]
869DOT     lookup2 [
870DOT             shape=diamond
871DOT             label="obj.pass ?"
872DOT     ]
873DOT     hash -> lookup [label="hash",style=bold,color=green,weight=4]
874DOT     lookup -> lookup2 [label="yes",style=bold,color=green,weight=4]
875DOT }
876DOT lookup2 -> hit [label="no", style=bold,color=green,weight=4]
877DOT lookup2 -> pass [label="yes",style=bold,color=red]
878DOT lookup -> miss [label="no",style=bold,color=blue,weight=2]
879 */
880
881static int
882cnt_lookup(struct sess *sp)
883{
884        struct objcore *oc;
885        struct object *o;
886        struct objhead *oh;
887
888        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
889        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
890
891
892        oc = HSH_Lookup(sp, &oh);
893
894        if (oc == NULL) {
895                /*
896                 * We lost the session to a busy object, disembark the
897                 * worker thread.   The hash code to restart the session,
898                 * still in STP_LOOKUP, later when the busy object isn't.
899                 * NB:  Do not access sp any more !
900                 */
901                return (1);
902        }
903
904        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
905        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
906
907        /* If we inserted a new object it's a miss */
908        if (oc->flags & OC_F_BUSY) {
909                sp->wrk->stats.cache_miss++;
910
911                sp->objcore = oc;
912                sp->step = STP_MISS;
913                return (0);
914        }
915
916        o = oc_getobj(sp->wrk, oc);
917        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
918        sp->obj = o;
919
920        if (oc->flags & OC_F_PASS) {
921                sp->wrk->stats.cache_hitpass++;
922                WSP(sp, SLT_HitPass, "%u", sp->obj->xid);
923                (void)HSH_Deref(sp->wrk, NULL, &sp->obj);
924                sp->objcore = NULL;
925                sp->step = STP_PASS;
926                return (0);
927        }
928
929        sp->wrk->stats.cache_hit++;
930        WSP(sp, SLT_Hit, "%u", sp->obj->xid);
931        sp->step = STP_HIT;
932        return (0);
933}
934
935/*--------------------------------------------------------------------
936 * We had a miss, ask VCL, proceed as instructed
937 *
938DOT subgraph xcluster_miss {
939DOT     miss [
940DOT             shape=ellipse
941DOT             label="filter req.->bereq."
942DOT     ]
943DOT     vcl_miss [
944DOT             shape=record
945DOT             label="vcl_miss()|req.\nbereq."
946DOT     ]
947DOT     miss -> vcl_miss [style=bold,color=blue,weight=2]
948DOT }
949DOT vcl_miss -> rst_miss [label="restart",color=purple]
950DOT rst_miss [label="RESTART",shape=plaintext]
951DOT vcl_miss -> err_miss [label="error"]
952DOT err_miss [label="ERROR",shape=plaintext]
953DOT vcl_miss -> fetch [label="fetch",style=bold,color=blue,weight=2]
954DOT vcl_miss -> pass [label="pass",style=bold,color=red]
955DOT
956 */
957
958static int
959cnt_miss(struct sess *sp)
960{
961
962        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
963        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
964
965        AZ(sp->obj);
966        AN(sp->objcore);
967        WS_Reset(sp->wrk->ws, NULL);
968        sp->wrk->bereq = sp->wrk->http[0];
969        http_Setup(sp->wrk->bereq, sp->wrk->ws);
970        http_FilterHeader(sp, HTTPH_R_FETCH);
971        http_ForceGet(sp->wrk->bereq);
972        if (params->http_gzip_support) {
973                /*
974                 * We always ask the backend for gzip, even if the
975                 * client doesn't grok it.  We will uncompress for
976                 * the minority of clients which don't.
977                 */
978                http_Unset(sp->wrk->bereq, H_Accept_Encoding);
979                http_PrintfHeader(sp->wrk, sp->fd, sp->wrk->bereq,
980                    "Accept-Encoding: gzip");
981        }
982        sp->wrk->connect_timeout = 0;
983        sp->wrk->first_byte_timeout = 0;
984        sp->wrk->between_bytes_timeout = 0;
985        VCL_miss_method(sp);
986        switch(sp->handling) {
987        case VCL_RET_ERROR:
988                AZ(HSH_Deref(sp->wrk, sp->objcore, NULL));
989                sp->objcore = NULL;
990                sp->step = STP_ERROR;
991                return (0);
992        case VCL_RET_PASS:
993                AZ(HSH_Deref(sp->wrk, sp->objcore, NULL));
994                sp->objcore = NULL;
995                sp->step = STP_PASS;
996                return (0);
997        case VCL_RET_FETCH:
998                sp->step = STP_FETCH;
999                return (0);
1000        case VCL_RET_RESTART:
1001                AZ(HSH_Deref(sp->wrk, sp->objcore, NULL));
1002                sp->objcore = NULL;
1003                INCOMPL();
1004        default:
1005                WRONG("Illegal action in vcl_miss{}");
1006        }
1007}
1008
1009/*--------------------------------------------------------------------
1010 * Start pass processing by getting headers from backend, then
1011 * continue in passbody.
1012 *
1013DOT subgraph xcluster_pass {
1014DOT     pass [
1015DOT             shape=ellipse
1016DOT             label="deref obj."
1017DOT     ]
1018DOT     pass2 [
1019DOT             shape=ellipse
1020DOT             label="filter req.->bereq."
1021DOT     ]
1022DOT     vcl_pass [
1023DOT             shape=record
1024DOT             label="vcl_pass()|req.\nbereq."
1025DOT     ]
1026DOT     pass_do [
1027DOT             shape=ellipse
1028DOT             label="create anon object\n"
1029DOT     ]
1030DOT     pass -> pass2 [style=bold, color=red]
1031DOT     pass2 -> vcl_pass [style=bold, color=red]
1032DOT     vcl_pass -> pass_do [label="pass"] [style=bold, color=red]
1033DOT }
1034DOT pass_do -> fetch [style=bold, color=red]
1035DOT vcl_pass -> rst_pass [label="restart",color=purple]
1036DOT rst_pass [label="RESTART",shape=plaintext]
1037DOT vcl_pass -> err_pass [label="error"]
1038DOT err_pass [label="ERROR",shape=plaintext]
1039 */
1040
1041static int
1042cnt_pass(struct sess *sp)
1043{
1044
1045        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1046        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
1047        AZ(sp->obj);
1048
1049        WS_Reset(sp->wrk->ws, NULL);
1050        sp->wrk->bereq = sp->wrk->http[0];
1051        http_Setup(sp->wrk->bereq, sp->wrk->ws);
1052        http_FilterHeader(sp, HTTPH_R_PASS);
1053
1054        sp->wrk->connect_timeout = 0;
1055        sp->wrk->first_byte_timeout = 0;
1056        sp->wrk->between_bytes_timeout = 0;
1057        VCL_pass_method(sp);
1058        if (sp->handling == VCL_RET_ERROR) {
1059                sp->step = STP_ERROR;
1060                return (0);
1061        }
1062        assert(sp->handling == VCL_RET_PASS);
1063        sp->acct_tmp.pass++;
1064        sp->sendbody = 1;
1065        sp->step = STP_FETCH;
1066        sp->pass = 1;
1067        return (0);
1068}
1069
1070/*--------------------------------------------------------------------
1071 * Ship the request header to the backend unchanged, then pipe
1072 * until one of the ends close the connection.
1073 *
1074DOT subgraph xcluster_pipe {
1075DOT     pipe [
1076DOT             shape=ellipse
1077DOT             label="Filter req.->bereq."
1078DOT     ]
1079DOT     vcl_pipe [
1080DOT             shape=record
1081DOT             label="vcl_pipe()|req.\nbereq\."
1082DOT     ]
1083DOT     pipe_do [
1084DOT             shape=ellipse
1085DOT             label="send bereq.\npipe until close"
1086DOT     ]
1087DOT     vcl_pipe -> pipe_do [label="pipe",style=bold,color=orange]
1088DOT     pipe -> vcl_pipe [style=bold,color=orange]
1089DOT }
1090DOT pipe_do -> DONE [style=bold,color=orange]
1091DOT vcl_pipe -> err_pipe [label="error"]
1092DOT err_pipe [label="ERROR",shape=plaintext]
1093 */
1094
1095static int
1096cnt_pipe(struct sess *sp)
1097{
1098
1099        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1100        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
1101
1102        sp->acct_tmp.pipe++;
1103        WS_Reset(sp->wrk->ws, NULL);
1104        sp->wrk->bereq = sp->wrk->http[0];
1105        http_Setup(sp->wrk->bereq, sp->wrk->ws);
1106        http_FilterHeader(sp, HTTPH_R_PIPE);
1107
1108        VCL_pipe_method(sp);
1109
1110        if (sp->handling == VCL_RET_ERROR)
1111                INCOMPL();
1112        assert(sp->handling == VCL_RET_PIPE);
1113
1114        PipeSession(sp);
1115        AZ(sp->wrk->wfd);
1116        sp->wrk->bereq = NULL;
1117        sp->step = STP_DONE;
1118        return (0);
1119}
1120
1121/*--------------------------------------------------------------------
1122 * RECV
1123 * We have a complete request, set everything up and start it.
1124 *
1125DOT subgraph xcluster_recv {
1126DOT     recv [
1127DOT             shape=record
1128DOT             label="vcl_recv()|req."
1129DOT     ]
1130DOT }
1131DOT RESTART -> recv
1132DOT recv -> pipe [label="pipe",style=bold,color=orange]
1133DOT recv -> pass2 [label="pass",style=bold,color=red]
1134DOT recv -> err_recv [label="error"]
1135DOT err_recv [label="ERROR",shape=plaintext]
1136DOT recv -> hash [label="lookup",style=bold,color=green,weight=4]
1137 */
1138
1139static int
1140cnt_recv(struct sess *sp)
1141{
1142        unsigned recv_handling;
1143
1144        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1145        CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
1146        AZ(sp->obj);
1147
1148        /* By default we use the first backend */
1149        AZ(sp->director);
1150        sp->director = sp->vcl->director[0];
1151        AN(sp->director);
1152
1153        sp->disable_esi = 0;
1154        sp->pass = 0;
1155        sp->hash_always_miss = 0;
1156        sp->hash_ignore_busy = 0;
1157        sp->client_identity = NULL;
1158
1159        http_CollectHdr(sp->http, H_Cache_Control);
1160
1161        VCL_recv_method(sp);
1162        recv_handling = sp->handling;
1163
1164        if (sp->restarts >= params->max_restarts) {
1165                if (sp->err_code == 0)
1166                        sp->err_code = 503;
1167                sp->step = STP_ERROR;
1168                return (0);
1169        }
1170
1171        if (params->http_gzip_support &&
1172             (recv_handling != VCL_RET_PIPE) &&
1173             (recv_handling != VCL_RET_PASS)) {
1174                if (RFC2616_Req_Gzip(sp)) {
1175                        http_Unset(sp->http, H_Accept_Encoding);
1176                        http_PrintfHeader(sp->wrk, sp->fd, sp->http,
1177                            "Accept-Encoding: gzip");
1178                } else {
1179                        http_Unset(sp->http, H_Accept_Encoding);
1180                }
1181        }
1182
1183        SHA256_Init(sp->wrk->sha256ctx);
1184        VCL_hash_method(sp);
1185        assert(sp->handling == VCL_RET_HASH);
1186        SHA256_Final(sp->digest, sp->wrk->sha256ctx);
1187
1188        if (!strcmp(sp->http->hd[HTTP_HDR_REQ].b, "HEAD"))
1189                sp->wantbody = 0;
1190        else
1191                sp->wantbody = 1;
1192
1193        sp->sendbody = 0;
1194        switch(recv_handling) {
1195        case VCL_RET_LOOKUP:
1196                /* XXX: discard req body, if any */
1197                sp->step = STP_LOOKUP;
1198                return (0);
1199        case VCL_RET_PIPE:
1200                if (sp->esi_level > 0) {
1201                        /* XXX: VSL something */
1202                        INCOMPL();
1203                        /* sp->step = STP_DONE; */
1204                        return (1);
1205                }
1206                sp->step = STP_PIPE;
1207                return (0);
1208        case VCL_RET_PASS:
1209                sp->step = STP_PASS;
1210                return (0);
1211        case VCL_RET_ERROR:
1212                /* XXX: discard req body, if any */
1213                sp->step = STP_ERROR;
1214                return (0);
1215        default:
1216                WRONG("Illegal action in vcl_recv{}");
1217        }
1218}
1219
1220/*--------------------------------------------------------------------
1221 * START
1222 * Handle a request, wherever it came from recv/restart.
1223 *
1224DOT start [shape=box,label="Dissect request"]
1225DOT start -> recv [style=bold,color=green,weight=4]
1226 */
1227
1228static int
1229cnt_start(struct sess *sp)
1230{
1231        int done;
1232        char *p;
1233        const char *r = "HTTP/1.1 100 Continue\r\n\r\n";
1234
1235        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1236        AZ(sp->restarts);
1237        AZ(sp->obj);
1238        AZ(sp->vcl);
1239
1240        /* Update stats of various sorts */
1241        sp->wrk->stats.client_req++;
1242        sp->t_req = TIM_real();
1243        sp->wrk->lastused = sp->t_req;
1244        sp->acct_tmp.req++;
1245
1246        /* Assign XID and log */
1247        sp->xid = ++xids;                               /* XXX not locked */
1248        WSP(sp, SLT_ReqStart, "%s %s %u", sp->addr, sp->port,  sp->xid);
1249
1250        /* Borrow VCL reference from worker thread */
1251        VCL_Refresh(&sp->wrk->vcl);
1252        sp->vcl = sp->wrk->vcl;
1253        sp->wrk->vcl = NULL;
1254
1255        http_Setup(sp->http, sp->ws);
1256        done = http_DissectRequest(sp);
1257
1258        /* If we could not even parse the request, just close */
1259        if (done < 0) {
1260                sp->step = STP_DONE;
1261                vca_close_session(sp, "junk");
1262                return (0);
1263        }
1264
1265        /* Catch request snapshot */
1266        sp->ws_req = WS_Snapshot(sp->ws);
1267
1268        /* Catch original request, before modification */
1269        HTTP_Copy(sp->http0, sp->http);
1270
1271        if (done != 0) {
1272                sp->err_code = done;
1273                sp->step = STP_ERROR;
1274                return (0);
1275        }
1276
1277        sp->doclose = http_DoConnection(sp->http);
1278
1279        /* XXX: Handle TRACE & OPTIONS of Max-Forwards = 0 */
1280
1281        /*
1282         * Handle Expect headers
1283         */
1284        if (http_GetHdr(sp->http, H_Expect, &p)) {
1285                if (strcasecmp(p, "100-continue")) {
1286                        sp->err_code = 417;
1287                        sp->step = STP_ERROR;
1288                        return (0);
1289                }
1290
1291                /* XXX: Don't bother with write failures for now */
1292                (void)write(sp->fd, r, strlen(r));
1293                /* XXX: When we do ESI includes, this is not removed
1294                 * XXX: because we use http0 as our basis.  Believed
1295                 * XXX: safe, but potentially confusing.
1296                 */
1297                http_Unset(sp->http, H_Expect);
1298        }
1299
1300        sp->step = STP_RECV;
1301        return (0);
1302}
1303
1304/*--------------------------------------------------------------------
1305 * Central state engine dispatcher.
1306 *
1307 * Kick the session around until it has had enough.
1308 *
1309 */
1310
1311static void
1312cnt_diag(struct sess *sp, const char *state)
1313{
1314        if (sp->wrk != NULL) {
1315                WSL(sp->wrk, SLT_Debug, sp->id,
1316                    "thr %p STP_%s sp %p obj %p vcl %p",
1317                    pthread_self(), state, sp, sp->obj, sp->vcl);
1318                WSL_Flush(sp->wrk, 0);
1319        } else {
1320                VSL(SLT_Debug, sp->id,
1321                    "thr %p STP_%s sp %p obj %p vcl %p",
1322                    pthread_self(), state, sp, sp->obj, sp->vcl);
1323        }
1324}
1325
1326void
1327CNT_Session(struct sess *sp)
1328{
1329        int done;
1330        struct worker *w;
1331
1332        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1333        w = sp->wrk;
1334        CHECK_OBJ_NOTNULL(w, WORKER_MAGIC);
1335
1336        /*
1337         * Possible entrance states
1338         */
1339        assert(
1340            sp->step == STP_FIRST ||
1341            sp->step == STP_START ||
1342            sp->step == STP_LOOKUP ||
1343            sp->step == STP_RECV);
1344
1345        /*
1346         * Whenever we come in from the acceptor we need to set blocking
1347         * mode, but there is no point in setting it when we come from
1348         * ESI or when a parked sessions returns.
1349         * It would be simpler to do this in the acceptor, but we'd rather
1350         * do the syscall in the worker thread.
1351         */
1352        if (sp->step == STP_FIRST || sp->step == STP_START)
1353                (void)TCP_blocking(sp->fd);
1354
1355        /*
1356         * NB: Once done is set, we can no longer touch sp!
1357         */
1358        for (done = 0; !done; ) {
1359                assert(sp->wrk == w);
1360                /*
1361                 * This is a good place to be paranoid about the various
1362                 * pointers still pointing to the things we expect.
1363                 */
1364                CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
1365                CHECK_OBJ_ORNULL(sp->obj, OBJECT_MAGIC);
1366                CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
1367                CHECK_OBJ_ORNULL(w->nobjhead, OBJHEAD_MAGIC);
1368                WS_Assert(w->ws);
1369                AZ(sp->wrk->storage_hint);
1370                AZ(sp->wrk->storage);
1371
1372                switch (sp->step) {
1373#define STEP(l,u) \
1374                    case STP_##u: \
1375                        if (params->diag_bitmap & 0x01) \
1376                                cnt_diag(sp, #u); \
1377                        done = cnt_##l(sp); \
1378                        break;
1379#include "steps.h"
1380#undef STEP
1381                default:
1382                        WRONG("State engine misfire");
1383                }
1384                WS_Assert(w->ws);
1385                CHECK_OBJ_ORNULL(w->nobjhead, OBJHEAD_MAGIC);
1386        }
1387        WSL_Flush(w, 0);
1388        AZ(w->wfd);
1389}
1390
1391/*
1392DOT }
1393*/
1394
1395/*--------------------------------------------------------------------
1396 * Debugging aids
1397 */
1398
1399static void
1400cli_debug_xid(struct cli *cli, const char * const *av, void *priv)
1401{
1402        (void)priv;
1403        if (av[2] != NULL)
1404                xids = strtoul(av[2], NULL, 0);
1405        cli_out(cli, "XID is %u", xids);
1406}
1407
1408/*
1409 * Default to seed=1, this is the only seed value POSIXl guarantees will
1410 * result in a reproducible random number sequence.
1411 */
1412static void
1413cli_debug_srandom(struct cli *cli, const char * const *av, void *priv)
1414{
1415        (void)priv;
1416        unsigned seed = 1;
1417
1418        if (av[2] != NULL)
1419                seed = strtoul(av[2], NULL, 0);
1420        srandom(seed);
1421        srand48(random());
1422        cli_out(cli, "Random(3) seeded with %lu", seed);
1423}
1424
1425static struct cli_proto debug_cmds[] = {
1426        { "debug.xid", "debug.xid",
1427                "\tExamine or set XID\n", 0, 1, "d", cli_debug_xid },
1428        { "debug.srandom", "debug.srandom",
1429                "\tSeed the random(3) function\n", 0, 1, "d", cli_debug_srandom },
1430        { NULL }
1431};
1432
1433/*--------------------------------------------------------------------
1434 *
1435 */
1436
1437void
1438CNT_Init(void)
1439{
1440
1441        srandomdev();
1442        srand48(random());
1443        xids = random();
1444        CLI_AddFuncs(debug_cmds);
1445}
1446
1447
Note: See TracBrowser for help on using the repository browser.