static void *
exp_timer(struct sess *sp, void *priv)
{
	struct objcore *oc;
	struct object *o;
	double t;
	struct objcore_head *lru;

	(void)priv;
	AZ(sleep(10));		/* XXX: Takes time for VCL to arrive */
	VCL_Get(&sp->vcl);
	t = TIM_real();
	while (1) {
		Lck_Lock(&exp_mtx);
		oc = binheap_root(exp_heap);
		CHECK_OBJ_ORNULL(oc, OBJCORE_MAGIC);
		if (oc == NULL || oc->timer_when > t) { /* XXX: > or >= ? */
			Lck_Unlock(&exp_mtx);
			WSL_Flush(sp->wrk, 0);
			WRK_SumStat(sp->wrk);
			AZ(sleep(1));
			VCL_Refresh(&sp->vcl);
			t = TIM_real();
			continue;
		}

		o = oc->obj;
		CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
		CHECK_OBJ_NOTNULL(o->objhead, OBJHEAD_MAGIC);
		assert(oc->flags & OC_F_ONLRU);
		assert(oc->timer_idx != BINHEAP_NOIDX);
		binheap_delete(exp_heap, oc->timer_idx);
		assert(oc->timer_idx == BINHEAP_NOIDX);
		lru = STV_lru(o->objstore);
		AN(lru);
		VTAILQ_REMOVE(lru, o->objcore, lru_list);
		oc->flags &= ~OC_F_ONLRU;

		{	/* Sanity checking */
			struct objcore *oc2 = binheap_root(exp_heap);
			if (oc2 != NULL) {
				assert(oc2->timer_idx != BINHEAP_NOIDX);
				assert(oc2->timer_when >= oc->timer_when);
			}
		}

		VSL_stats->n_expired++;
		Lck_Unlock(&exp_mtx);
		WSL(sp->wrk, SLT_ExpKill, 0, "%u %d",
		    o->xid, (int)(o->ttl - t));
		HSH_Deref(sp->wrk, &o);
	}
}
Example #2
0
double
VRT_r_now(const struct sess *sp)
{

	(void)sp;
	return (TIM_real());
}
static void *
vca_kqueue_main(void *arg)
{
    struct kevent ke[NKEV], *kp;
    int j, n, dotimer;
    double deadline;
    struct sess *sp;

    THR_SetName("cache-kqueue");
    (void)arg;

    kq = kqueue();
    assert(kq >= 0);

    j = 0;
    EV_SET(&ke[j], 0, EVFILT_TIMER, EV_ADD, 0, 100, NULL);
    j++;
    EV_SET(&ke[j], vca_pipes[0], EVFILT_READ, EV_ADD, 0, 0, vca_pipes);
    j++;
    AZ(kevent(kq, ke, j, NULL, 0, NULL));

    nki = 0;
    while (1) {
        dotimer = 0;
        n = kevent(kq, ki, nki, ke, NKEV, NULL);
        assert(n >= 1 && n <= NKEV);
        nki = 0;
        for (kp = ke, j = 0; j < n; j++, kp++) {
            if (kp->filter == EVFILT_TIMER) {
                dotimer = 1;
                continue;
            }
            assert(kp->filter == EVFILT_READ);
            vca_kev(kp);
        }
        if (!dotimer)
            continue;
        /*
         * Make sure we have no pending changes for the fd's
         * we are about to close, in case the accept(2) in the
         * other thread creates new fd's betwen our close and
         * the kevent(2) at the top of this loop, the kernel
         * would not know we meant "the old fd of this number".
         */
        vca_kq_flush();
        deadline = TIM_real() - params->sess_timeout;
        for (;;) {
            sp = VTAILQ_FIRST(&sesshead);
            if (sp == NULL)
                break;
            if (sp->t_open > deadline)
                break;
            VTAILQ_REMOVE(&sesshead, sp, list);
            // XXX: not yet (void)TCP_linger(sp->fd, 0);
            vca_close_session(sp, "timeout");
            SES_Delete(sp);
        }
    }
}
static int
cnt_error(struct sess *sp)
{
    struct worker *w;
    struct http *h;
    char date[40];

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);

    w = sp->wrk;
    if (sp->obj == NULL) {
        HSH_Prealloc(sp);
        sp->obj = HSH_NewObject(sp, 1);
        sp->obj->xid = sp->xid;
        sp->obj->entered = sp->t_req;
    } else {
        /* XXX: Null the headers ? */
    }
    CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
    h = sp->obj->http;

    http_PutProtocol(w, sp->fd, h, "HTTP/1.1");
    http_PutStatus(w, sp->fd, h, sp->err_code);
    TIM_format(TIM_real(), date);
    http_PrintfHeader(w, sp->fd, h, "Date: %s", date);
    http_PrintfHeader(w, sp->fd, h, "Server: Varnish");
    http_PrintfHeader(w, sp->fd, h, "Retry-After: %d", params->err_ttl);

    if (sp->err_reason != NULL)
        http_PutResponse(w, sp->fd, h, sp->err_reason);
    else
        http_PutResponse(w, sp->fd, h,
                         http_StatusMessage(sp->err_code));
    VCL_error_method(sp);

    if (sp->handling == VCL_RET_RESTART) {
        HSH_Drop(sp);
        sp->director = NULL;
        sp->restarts++;
        sp->step = STP_RECV;
        return (0);
    }

    /* We always close when we take this path */
    sp->doclose = "error";
    sp->wantbody = 1;

    assert(sp->handling == VCL_RET_DELIVER);
    sp->err_code = 0;
    sp->err_reason = NULL;
    sp->wrk->bereq = NULL;
    sp->step = STP_DELIVER;
    return (0);
}
Example #5
0
static void
tst_delta()
{
	double m_begin, m_end;
	double r_begin, r_end;
	const double ref = 1;
	int err = 0;

	r_begin = TIM_real();
	m_begin = TIM_mono();
	TIM_sleep(ref);
	r_end = TIM_real();
	m_end = TIM_mono();

	err += tst_delta_check("TIM_mono", m_begin, m_end, ref);
	err += tst_delta_check("TIM_real", r_begin, r_end, ref);

	if (err) {
		printf("%d time delta test errrors\n", err);
		exit (2);
	}
}
static void *
vca_main(void *arg)
{
	struct epoll_event ev[NEEV], *ep;
	struct sess *sp;
	char junk;
	double deadline;
	int dotimer, i, n;

	THR_SetName("cache-epoll");
	(void)arg;

	epfd = epoll_create(1);
	assert(epfd >= 0);

	vca_modadd(vca_pipes[0], vca_pipes, EPOLL_CTL_ADD);
	vca_modadd(dotimer_pipe[0], dotimer_pipe, EPOLL_CTL_ADD);

	while (1) {
		dotimer = 0;
		n = epoll_wait(epfd, ev, NEEV, -1);
		for (ep = ev, i = 0; i < n; i++, ep++) {
			if (ep->data.ptr == dotimer_pipe &&
			    (ep->events == EPOLLIN || ep->events == EPOLLPRI))
			{
				assert(read(dotimer_pipe[0], &junk, 1));
				dotimer = 1;
			} else
				vca_eev(ep);
		}
		if (!dotimer)
			continue;

		/* check for timeouts */
		deadline = TIM_real() - params->sess_timeout;
		for (;;) {
			sp = VTAILQ_FIRST(&sesshead);
			if (sp == NULL)
				break;
			if (sp->t_open > deadline)
				break;
			VTAILQ_REMOVE(&sesshead, sp, list);
			// XXX: not yet VTCP_linger(sp->fd, 0);
			vca_close_session(sp, "timeout");
			SES_Delete(sp);
		}
	}
	return NULL;
}
Example #7
0
static enum pipe_status
pie_first(struct pipe *dp)
{
	struct sess *sp;
	struct vbe_conn *vc;

	CHECK_OBJ_NOTNULL(dp, PIPE_MAGIC);
	CAST_OBJ_NOTNULL(sp, dp->sess, SESS_MAGIC);
	CAST_OBJ_NOTNULL(vc, sp->vc, VBE_CONN_MAGIC);

	dp->t_last = TIM_real();
	dp->t_updated = dp->t_last;
	TCP_hisname(vc->vc_fd, dp->addr, sizeof(dp->addr), dp->port,
	    sizeof(dp->port));

	dp->step = PIE_RECV;
	return (PIPE_CONTINUE);
}
static int
cnt_deliver(struct sess *sp)
{

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
    CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);

    sp->t_resp = TIM_real();
    if (sp->obj->objhead != NULL) {
        if ((sp->t_resp - sp->obj->last_lru) > params->lru_timeout &&
                EXP_Touch(sp->obj))
            sp->obj->last_lru = sp->t_resp;	/* XXX: locking ? */
        sp->obj->last_use = sp->t_resp;	/* XXX: locking ? */
    }
    sp->wrk->resp = &sp->wrk->http[2];
    http_Setup(sp->wrk->resp, sp->wrk->ws);
    RES_BuildHttp(sp);
    VCL_deliver_method(sp);
    switch (sp->handling) {
    case VCL_RET_DELIVER:
        break;
    case VCL_RET_RESTART:
        INCOMPL();
        break;
    default:
        WRONG("Illegal action in vcl_deliver{}");
    }

    sp->director = NULL;
    sp->restarts = 0;

    RES_WriteObj(sp);
    AZ(sp->wrk->wfd);
    HSH_Deref(sp->wrk, &sp->obj);
    sp->wrk->resp = NULL;
    sp->step = STP_DONE;
    return (0);
}
Example #9
0
static enum pipe_status
pie_recv_frombackend(struct pipe *dp)
{
	struct sess *sp;
	struct vbe_conn *vc;
	int i;

	CAST_OBJ_NOTNULL(sp, dp->sess, SESS_MAGIC);
	CAST_OBJ_NOTNULL(vc, sp->vc, VBE_CONN_MAGIC);

	i = CFD_read(&vc->fds, dp->buf[1], dp->bufsize);
	if (i == -2) {
		SEPTUM_PIPEEVENT(dp, vc->vc_fd, vc->vc_want,
		    CALLOUT_SECTOTICKS(params->pipe_timeout));
		return (PIPE_WAIT);
	}
	if (i <= 0) {
		if (i == -1)
			WSP(sp, SLT_Error, "%s: read(2) %d %s", __func__, errno,
			    strerror(errno));
		else
			WSP(sp, SLT_Error, "%s: read(2) eof", __func__);
		dp->flags |= PIPE_F_PIPEDONE;
		if ((dp->flags & PIPE_F_SESSDONE) != 0) {
			dp->step = PIE_END;
			return (PIPE_CONTINUE);
		}
		(void)shutdown(vc->vc_fd, SHUT_RD);	/* XXX */
		(void)shutdown(sp->sp_fd, SHUT_WR);	/* XXX */
		dp->step = PIE_END;
		return (PIPE_CONTINUE);
	}
	assert(i > 0);
	dp->buflen[1] = i;
	dp->t_updated = TIM_real();
	dp->step = PIE_SEND;
	return (PIPE_CONTINUE);
}
Example #10
0
static enum pipe_status
pie_timeout(struct pipe *dp)
{
	struct sess *sp;
	struct vbe_conn *vc;
	double now;

	CAST_OBJ_NOTNULL(sp, dp->sess, SESS_MAGIC);
	CAST_OBJ_NOTNULL(vc, sp->vc, VBE_CONN_MAGIC);

	/* Need to handle a edge case if only one direction is used. */
	switch (dp->prevstep) {
	case PIE_RECV_FROMBACKEND:
		now = TIM_real();
		if ((now - dp->t_updated) < (double)params->pipe_timeout) {
			dp->step = dp->prevstep;
			return (PIPE_CONTINUE);
		}
		break;
	default:
		break;
	}

	sp->acct_tmp.sess_timeout++;
	if ((sp->flags & SESS_T_SOCKS) != 0)
		VSL_stats->socks_timeout++;

	dp->flags |= PIPE_F_PIPEDONE;
	if ((dp->flags & PIPE_F_SESSDONE) != 0) {
		dp->step = PIE_END;
		return (PIPE_CONTINUE);
	}
	(void)shutdown(vc->vc_fd, SHUT_RD);	/* XXX */
	(void)shutdown(sp->sp_fd, SHUT_WR);	/* XXX */
	dp->step = PIE_END;
	return (PIPE_CONTINUE);
}
static void *
vca_main(void *arg)
{
	struct sess *sp;

	/*
	 * timeouts:
	 *
	 * min_ts : Minimum timeout for port_getn
	 * min_t  : ^ equivalent in floating point representation
	 *
	 * max_ts : Maximum timeout for port_getn
	 * max_t  : ^ equivalent in floating point representation
	 *
	 * with (nevents == 1), we should always choose the correct port_getn
	 * timeout to check session timeouts, so max is just a safety measure
	 * (if this implementation is correct, it could be set to an "infinte"
	 *  value)
	 *
	 * with (nevents > 1), min and max define the acceptable range for
	 * - additional latency of keep-alive connections and
	 * - additional tolerance for handling session timeouts
	 *
	 */
	static struct timespec min_ts = {0L,    100L /*ms*/  * 1000L /*us*/  * 1000L /*ns*/};
	static double          min_t  = 0.1; /* 100    ms*/
	static struct timespec max_ts = {1L, 0L}; 		/* 1 second */
	static double	       max_t  = 1.0;			/* 1 second */

	struct timespec ts;
	struct timespec *timeout;

	(void)arg;

	solaris_dport = port_create();
	assert(solaris_dport >= 0);

	timeout = &max_ts;

	while (1) {
		port_event_t ev[MAX_EVENTS];
		int nevents, ei, ret;
		double now, deadline;

		/*
		 * XXX Do we want to scale this up dynamically to increase
		 *     efficiency in high throughput situations? - would need to
		 *     start with one to keep latency low at any rate
		 *
		 *     Note: when increasing nevents, we must lower min_ts
		 *	     and max_ts
		 */
		nevents = 1;

		/*
		 * see disucssion in
		 * - https://issues.apache.org/bugzilla/show_bug.cgi?id=47645
		 * - http://mail.opensolaris.org/pipermail/networking-discuss/2009-August/011979.html
		 *
		 * comment from apr/poll/unix/port.c :
		 *
		 * This confusing API can return an event at the same time
		 * that it reports EINTR or ETIME.
		 *
		 */

		ret = port_getn(solaris_dport, ev, MAX_EVENTS, &nevents, timeout);

		if (ret < 0)
			assert((errno == EINTR) || (errno == ETIME));

		for (ei=0; ei<nevents; ei++) {
			vca_port_ev(ev + ei);
		}

		/* check for timeouts */
		now = TIM_real();
		deadline = now - params->sess_timeout;

		/*
		 * This loop assumes that the oldest sessions are always at the
		 * beginning of the list (which is the case if we guarantee to
		 * enqueue at the tail only
		 *
		 */

		for (;;) {
			sp = VTAILQ_FIRST(&sesshead);
			if (sp == NULL)
				break;
			if (sp->t_open > deadline) {
				break;
			}
			VTAILQ_REMOVE(&sesshead, sp, list);
			if(sp->fd != -1) {
				vca_del(sp->fd);
			}
			vca_close_session(sp, "timeout");
			SES_Delete(sp);
		}

		/*
		 * Calculate the timeout for the next get_portn
		 */

		if (sp) {
			double tmo = (sp->t_open + params->sess_timeout) - now;

			/* we should have removed all sps whose timeout has passed */
			assert(tmo > 0.0);

			if (tmo < min_t) {
				timeout = &min_ts;
			} else if (tmo > max_t) {
				timeout = &max_ts;
			} else {
				/* TIM_t2ts() ? see #630 */
				ts.tv_sec = (int)floor(tmo);
				ts.tv_nsec = 1e9 * (tmo - ts.tv_sec);
				timeout = &ts;
			}
		} else {
			timeout = &max_ts;
		}
	}
}
static int
cnt_fetch(struct sess *sp)
{
    int i, transient;
    struct http *hp, *hp2;
    char *b;
    unsigned handling;

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);

    AN(sp->director);
    AZ(sp->vbe);

    /* sp->wrk->http[0] is (still) bereq */
    sp->wrk->beresp = &sp->wrk->http[1];
    http_Setup(sp->wrk->beresp, sp->wrk->ws);

    i = FetchHdr(sp);

    /*
     * Save a copy before it might get mangled in VCL.  When it comes to
     * dealing with the body, we want to see the unadultered headers.
     */
    sp->wrk->beresp1 = &sp->wrk->http[2];
    *sp->wrk->beresp1 = *sp->wrk->beresp;

    if (i) {
        if (sp->objhead) {
            CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC);
            CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC);
            HSH_DerefObjCore(sp);
        }
        AZ(sp->obj);
        sp->wrk->bereq = NULL;
        sp->wrk->beresp = NULL;
        sp->wrk->beresp1 = NULL;
        sp->err_code = 503;
        sp->step = STP_ERROR;
        return (0);
    }

    sp->err_code = http_GetStatus(sp->wrk->beresp);

    /*
     * Initial cacheability determination per [RFC2616, 13.4]
     * We do not support ranges yet, so 206 is out.
     */
    switch (sp->err_code) {
    case 200: /* OK */
    case 203: /* Non-Authoritative Information */
    case 300: /* Multiple Choices */
    case 301: /* Moved Permanently */
    case 302: /* Moved Temporarily */
    case 410: /* Gone */
    case 404: /* Not Found */
        sp->wrk->cacheable = 1;
        break;
    default:
        sp->wrk->cacheable = 0;
        break;
    }

    sp->wrk->entered = TIM_real();
    sp->wrk->age = 0;
    sp->wrk->ttl = RFC2616_Ttl(sp);

    if (sp->wrk->ttl == 0.)
        sp->wrk->cacheable = 0;

    sp->wrk->do_esi = 0;
    sp->wrk->grace = NAN;

    VCL_fetch_method(sp);

    /*
     * When we fetch the body, we may hit the LRU cleanup and that
     * will overwrite sp->handling, so we have to save our plans
     * here.
     */
    handling = sp->handling;

    if (sp->objhead == NULL)
        transient = 1;
    else if (sp->handling == VCL_RET_DELIVER)
        transient = 0;
    else
        transient = 1;

    /*
     * XXX: If we have a Length: header, we should allocate the body
     * XXX: also.
     */
    sp->obj = HSH_NewObject(sp, transient);

    if (sp->objhead != NULL) {
        CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC);
        CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC);
        sp->objcore->obj = sp->obj;
        sp->obj->objcore = sp->objcore;
        sp->obj->objhead = sp->objhead;
        sp->objhead = NULL;	/* refcnt follows pointer. */
        sp->objcore = NULL;	/* refcnt follows pointer. */
    }

    BAN_NewObj(sp->obj);

    sp->obj->xid = sp->xid;
    sp->obj->response = sp->err_code;
    sp->obj->cacheable = sp->wrk->cacheable;
    sp->obj->ttl = sp->wrk->ttl;
    sp->obj->grace = sp->wrk->grace;
    if (sp->obj->ttl == 0. && sp->obj->grace == 0.)
        sp->obj->cacheable = 0;
    sp->obj->age = sp->wrk->age;
    sp->obj->entered = sp->wrk->entered;
    WS_Assert(sp->obj->ws_o);

    /* Filter into object */
    hp = sp->wrk->beresp;
    hp2 = sp->obj->http;

    hp2->logtag = HTTP_Obj;
    http_CopyResp(hp2, hp);
    http_FilterFields(sp->wrk, sp->fd, hp2, hp, HTTPH_A_INS);
    http_CopyHome(sp->wrk, sp->fd, hp2);

    if (http_GetHdr(hp, H_Last_Modified, &b))
        sp->obj->last_modified = TIM_parse(b);

    i = FetchBody(sp);
    AZ(sp->wrk->wfd);
    AZ(sp->vbe);
    AN(sp->director);

    if (i) {
        HSH_Drop(sp);
        AZ(sp->obj);
        sp->wrk->bereq = NULL;
        sp->wrk->beresp = NULL;
        sp->wrk->beresp1 = NULL;
        sp->err_code = 503;
        sp->step = STP_ERROR;
        return (0);
    }

    if (!transient)
        HSH_Object(sp);

    if (sp->wrk->do_esi)
        ESI_Parse(sp);

    switch (handling) {
    case VCL_RET_RESTART:
        HSH_Drop(sp);
        sp->director = NULL;
        sp->restarts++;
        sp->wrk->bereq = NULL;
        sp->wrk->beresp = NULL;
        sp->wrk->beresp1 = NULL;
        sp->step = STP_RECV;
        return (0);
    case VCL_RET_PASS:
        if (sp->obj->objcore != NULL)
            sp->obj->objcore->flags |= OC_F_PASS;
        if (sp->obj->ttl - sp->t_req < params->default_ttl)
            sp->obj->ttl = sp->t_req + params->default_ttl;
        break;
    case VCL_RET_DELIVER:
        break;
    case VCL_RET_ERROR:
        HSH_Drop(sp);
        sp->wrk->bereq = NULL;
        sp->wrk->beresp = NULL;
        sp->wrk->beresp1 = NULL;
        sp->step = STP_ERROR;
        return (0);
    default:
        WRONG("Illegal action in vcl_fetch{}");
    }

    sp->obj->cacheable = 1;
    if (sp->obj->objhead != NULL) {
        VRY_Create(sp);
        EXP_Insert(sp->obj);
        AN(sp->obj->ban);
        HSH_Unbusy(sp);
    }
    sp->acct_req.fetch++;
    sp->wrk->bereq = NULL;
    sp->wrk->beresp = NULL;
    sp->wrk->beresp1 = NULL;
    sp->step = STP_DELIVER;
    return (0);
}
static int
cnt_done(struct sess *sp)
{
    double dh, dp, da;
    int i;

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    CHECK_OBJ_ORNULL(sp->vcl, VCL_CONF_MAGIC);

    AZ(sp->obj);
    AZ(sp->vbe);
    sp->director = NULL;
    sp->restarts = 0;

    if (sp->vcl != NULL && sp->esis == 0) {
        if (sp->wrk->vcl != NULL)
            VCL_Rel(&sp->wrk->vcl);
        sp->wrk->vcl = sp->vcl;
        sp->vcl = NULL;
    }

    sp->t_end = TIM_real();
    sp->wrk->lastused = sp->t_end;
    if (sp->xid == 0) {
        sp->t_req = sp->t_end;
        sp->t_resp = sp->t_end;
    }
    dp = sp->t_resp - sp->t_req;
    da = sp->t_end - sp->t_resp;
    dh = sp->t_req - sp->t_open;
    WSL(sp->wrk, SLT_ReqEnd, sp->id, "%u %.9f %.9f %.9f %.9f %.9f",
        sp->xid, sp->t_req, sp->t_end, dh, dp, da);

    sp->xid = 0;
    sp->t_open = sp->t_end;
    sp->t_resp = NAN;
    WSL_Flush(sp->wrk, 0);

    /* If we did an ESI include, don't mess up our state */
    if (sp->esis > 0)
        return (1);

    sp->t_req = NAN;

    if (sp->fd >= 0 && sp->doclose != NULL) {
        /*
         * This is an orderly close of the connection; ditch nolinger
         * before we close, to get queued data transmitted.
         */
        TCP_linger(sp->fd, 0);
        vca_close_session(sp, sp->doclose);
    }
    if (sp->fd < 0) {
        SES_Charge(sp);
        VSL_stats->sess_closed++;
        sp->wrk = NULL;
        SES_Delete(sp);
        return (1);
    }

    /* Reset the workspace to the session-watermark */
    WS_Reset(sp->ws, sp->ws_ses);

    i = HTC_Reinit(sp->htc);
    if (i == 1) {
        VSL_stats->sess_pipeline++;
        sp->step = STP_START;
        return (0);
    }
    if (Tlen(sp->htc->rxbuf)) {
        VSL_stats->sess_readahead++;
        sp->step = STP_WAIT;
        return (0);
    }
    if (params->session_linger > 0) {
        VSL_stats->sess_linger++;
        sp->step = STP_WAIT;
        return (0);
    }
    VSL_stats->sess_herd++;
    SES_Charge(sp);
    sp->wrk = NULL;
    vca_return_session(sp);
    return (1);
}
static int
cnt_start(struct sess *sp)
{
    int done;
    char *p;
    const char *r = "HTTP/1.1 100 Continue\r\n\r\n";

    CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
    AZ(sp->restarts);
    AZ(sp->obj);
    AZ(sp->vcl);

    /* Update stats of various sorts */
    VSL_stats->client_req++;			/* XXX not locked */
    sp->t_req = TIM_real();
    sp->wrk->lastused = sp->t_req;
    sp->acct_req.req++;

    /* Assign XID and log */
    sp->xid = ++xids;				/* XXX not locked */
    WSP(sp, SLT_ReqStart, "%s %s %u", sp->addr, sp->port,  sp->xid);

    /* Borrow VCL reference from worker thread */
    VCL_Refresh(&sp->wrk->vcl);
    sp->vcl = sp->wrk->vcl;
    sp->wrk->vcl = NULL;

    http_Setup(sp->http, sp->ws);
    done = http_DissectRequest(sp);

    /* Catch request snapshot */
    sp->ws_req = WS_Snapshot(sp->ws);

    /* Catch original request, before modification */
    *sp->http0 = *sp->http;

    if (done != 0) {
        sp->err_code = done;
        sp->step = STP_ERROR;
        return (0);
    }

    sp->doclose = http_DoConnection(sp->http);

    /* XXX: Handle TRACE & OPTIONS of Max-Forwards = 0 */

    /*
     * Handle Expect headers
     */
    if (http_GetHdr(sp->http, H_Expect, &p)) {
        if (strcmp(p, "100-continue")) {
            sp->err_code = 417;
            sp->step = STP_ERROR;
            return (0);
        }

        /* XXX: Don't bother with write failures for now */
        (void)write(sp->fd, r, strlen(r));
        /* XXX: When we do ESI includes, this is not removed
         * XXX: because we use http0 as our basis.  Believed
         * XXX: safe, but potentially confusing.
         */
        http_Unset(sp->http, H_Expect);
    }

    sp->step = STP_RECV;
    return (0);
}
Example #15
0
void
PipeSession(struct sess *sp)
{
	struct vbe_conn *vc;
	struct worker *w;
	struct pollfd fds[2];
	int i;

	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
	CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
	w = sp->wrk;

	sp->vbe = VBE_GetFd(NULL, sp);
	if (sp->vbe == NULL)
		return;
	vc = sp->vbe;
	(void)TCP_blocking(vc->fd);

	WRW_Reserve(w, &vc->fd);
	sp->acct_req.hdrbytes += http_Write(w, sp->wrk->bereq, 0);

	if (sp->htc->pipeline.b != NULL)
		sp->acct_req.bodybytes +=
		    WRW_Write(w, sp->htc->pipeline.b, Tlen(sp->htc->pipeline));

	i = WRW_FlushRelease(w);

	if (i) {
		vca_close_session(sp, "pipe");
		VBE_ClosedFd(sp);
		return;
	}

	sp->t_resp = TIM_real();

	memset(fds, 0, sizeof fds);

	// XXX: not yet (void)TCP_linger(vc->fd, 0);
	fds[0].fd = vc->fd;
	fds[0].events = POLLIN | POLLERR;

	// XXX: not yet (void)TCP_linger(sp->fd, 0);
	fds[1].fd = sp->fd;
	fds[1].events = POLLIN | POLLERR;

	while (fds[0].fd > -1 || fds[1].fd > -1) {
		fds[0].revents = 0;
		fds[1].revents = 0;
		i = poll(fds, 2, params->pipe_timeout * 1000);
		if (i < 1)
			break;
		if (fds[0].revents && rdf(vc->fd, sp->fd)) {
			(void)shutdown(vc->fd, SHUT_RD);
			(void)shutdown(sp->fd, SHUT_WR);
			fds[0].events = 0;
			fds[0].fd = -1;
		}
		if (fds[1].revents && rdf(sp->fd, vc->fd)) {
			(void)shutdown(sp->fd, SHUT_RD);
			(void)shutdown(vc->fd, SHUT_WR);
			fds[1].events = 0;
			fds[1].fd = -1;
		}
	}
	if (fds[0].fd >= 0) {
		(void)shutdown(vc->fd, SHUT_RD);
		(void)shutdown(sp->fd, SHUT_WR);
	}
	if (fds[1].fd >= 0) {
		(void)shutdown(sp->fd, SHUT_RD);
		(void)shutdown(vc->fd, SHUT_WR);
	}
	vca_close_session(sp, "pipe");
	VBE_ClosedFd(sp);
}