static void vca_kev(const struct kevent *kp) { int i, j; struct sess *sp; struct sess *ss[NKEV]; AN(kp->udata); if (kp->udata == vca_pipes) { j = 0; i = read(vca_pipes[0], ss, sizeof ss); if (i == -1 && errno == EAGAIN) return; while (i >= sizeof ss[0]) { CHECK_OBJ_NOTNULL(ss[j], SESS_MAGIC); assert(ss[j]->sp_fd >= 0); AZ(ss[j]->obj); VTAILQ_INSERT_TAIL(&sesshead, ss[j], list); vca_kq_sess(ss[j], EV_ADD | EV_ONESHOT); j++; i -= sizeof ss[0]; } assert(i == 0); return; } CAST_OBJ_NOTNULL(sp, kp->udata, SESS_MAGIC); DSL(0x04, SLT_Debug, sp->id, "KQ: sp %p kev data %lu flags 0x%x%s", sp, (unsigned long)kp->data, kp->flags, (kp->flags & EV_EOF) ? " EOF" : ""); assert(sp->id == kp->ident); assert(sp->sp_fd == sp->id); if (kp->data > 0) { i = HTC_Rx(sp->htc); if (i == 0) { vca_kq_sess(sp, EV_ADD | EV_ONESHOT); return; /* more needed */ } VTAILQ_REMOVE(&sesshead, sp, list); vca_handover(sp, i); return; } else if (kp->flags & EV_EOF) { VTAILQ_REMOVE(&sesshead, sp, list); vca_close_session(sp, "EOF"); SES_Delete(sp); return; } else { VSL(SLT_Debug, sp->id, "KQ: sp %p kev data %lu flags 0x%x%s", sp, (unsigned long)kp->data, kp->flags, (kp->flags & EV_EOF) ? " EOF" : ""); } }
static inline void vca_port_ev(port_event_t *ev) { struct sess *sp; if(ev->portev_source == PORT_SOURCE_USER) { CAST_OBJ_NOTNULL(sp, ev->portev_user, SESS_MAGIC); assert(sp->fd >= 0); AZ(sp->obj); VTAILQ_INSERT_TAIL(&sesshead, sp, list); vca_add(sp->fd, sp); } else { int i; assert(ev->portev_source == PORT_SOURCE_FD); CAST_OBJ_NOTNULL(sp, ev->portev_user, SESS_MAGIC); assert(sp->fd >= 0); if(ev->portev_events & POLLERR) { vca_del(sp->fd); VTAILQ_REMOVE(&sesshead, sp, list); vca_close_session(sp, "EOF"); SES_Delete(sp); return; } i = HTC_Rx(sp->htc); if (i == 0) { /* incomplete header, wait for more data */ vca_add(sp->fd, sp); return; } /* * note: the original man page for port_associate(3C) states: * * When an event for a PORT_SOURCE_FD object is retrieved, * the object no longer has an association with the port. * * This can be read along the lines of sparing the * port_dissociate after port_getn(), but in fact, * port_dissociate should be used * * Ref: http://opensolaris.org/jive/thread.jspa?threadID=129476&tstart=0 */ vca_del(sp->fd); VTAILQ_REMOVE(&sesshead, sp, list); /* vca_handover will also handle errors */ vca_handover(sp, i); } return; }
static void vca_eev(const struct epoll_event *ep) { struct sess *ss[NEEV], *sp; int i, j; AN(ep->data.ptr); if (ep->data.ptr == vca_pipes) { if (ep->events & EPOLLIN || ep->events & EPOLLPRI) { j = 0; i = read(vca_pipes[0], ss, sizeof ss); if (i == -1 && errno == EAGAIN) return; while (i >= sizeof ss[0]) { CHECK_OBJ_NOTNULL(ss[j], SESS_MAGIC); assert(ss[j]->fd >= 0); AZ(ss[j]->obj); VTAILQ_INSERT_TAIL(&sesshead, ss[j], list); vca_cond_modadd(ss[j]->fd, ss[j]); j++; i -= sizeof ss[0]; } assert(i == 0); } } else { CAST_OBJ_NOTNULL(sp, ep->data.ptr, SESS_MAGIC); if (ep->events & EPOLLIN || ep->events & EPOLLPRI) { i = HTC_Rx(sp->htc); if (i == 0) { vca_modadd(sp->fd, sp, EPOLL_CTL_MOD); return; /* more needed */ } VTAILQ_REMOVE(&sesshead, sp, list); vca_handover(sp, i); } else if (ep->events & EPOLLERR) { VTAILQ_REMOVE(&sesshead, sp, list); vca_close_session(sp, "ERR"); SES_Delete(sp); } else if (ep->events & EPOLLHUP) { VTAILQ_REMOVE(&sesshead, sp, list); vca_close_session(sp, "HUP"); SES_Delete(sp); } else if (ep->events & EPOLLRDHUP) { VTAILQ_REMOVE(&sesshead, sp, list); vca_close_session(sp, "RHUP"); SES_Delete(sp); } } }
static int cnt_wait(struct sess *sp) { int i; struct pollfd pfd[1]; struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); AZ(sp->vcl); AZ(wrk->obj); AZ(sp->esi_level); assert(sp->xid == 0); i = HTC_Complete(sp->htc); if (i == 0 && cache_param->session_linger > 0) { pfd[0].fd = sp->fd; pfd[0].events = POLLIN; pfd[0].revents = 0; i = poll(pfd, 1, cache_param->session_linger); if (i) i = HTC_Rx(sp->htc); } if (i == 0) { WSP(sp, SLT_Debug, "herding"); wrk->stats.sess_herd++; SES_Charge(sp); Pool_Wait(sp); return (1); } if (i == 1) { sp->step = STP_START; return (0); } if (i == -2) { SES_Close(sp, "overflow"); } else if (i == -1 && Tlen(sp->htc->rxbuf) == 0 && (errno == 0 || errno == ECONNRESET)) SES_Close(sp, "EOF"); else SES_Close(sp, "error"); sp->step = STP_DONE; return (0); }
static int cnt_wait(struct sess *sp) { int i; struct pollfd pfd[1]; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); AZ(sp->vcl); AZ(sp->obj); assert(sp->xid == 0); i = HTC_Complete(sp->htc); while (i == 0) { if (params->session_linger > 0) { pfd[0].fd = sp->fd; pfd[0].events = POLLIN; pfd[0].revents = 0; i = poll(pfd, 1, params->session_linger); if (i == 0) { WSL(sp->wrk, SLT_Debug, sp->fd, "herding"); VSL_stats->sess_herd++; sp->wrk = NULL; vca_return_session(sp); return (1); } } i = HTC_Rx(sp->htc); } if (i == 1) { sp->step = STP_START; } else { if (i == -2) vca_close_session(sp, "overflow"); else if (i == -1 && Tlen(sp->htc->rxbuf) == 0 && (errno == 0 || errno == ECONNRESET)) vca_close_session(sp, "EOF"); else vca_close_session(sp, "error"); sp->step = STP_DONE; } return (0); }
int FetchHdr(struct sess *sp, int need_host_hdr) { struct vbc *vc; struct worker *wrk; struct http *hp; int retry = -1; int i; struct http_conn *htc; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC); htc = &wrk->busyobj->htc; AN(sp->req->director); AZ(sp->req->obj); if (sp->req->objcore != NULL) { /* pass has no objcore */ CHECK_OBJ_NOTNULL(sp->req->objcore, OBJCORE_MAGIC); AN(sp->req->objcore->flags & OC_F_BUSY); } hp = wrk->busyobj->bereq; sp->wrk->busyobj->vbc = VDI_GetFd(NULL, sp); if (sp->wrk->busyobj->vbc == NULL) { WSP(sp, SLT_FetchError, "no backend connection"); return (-1); } vc = sp->wrk->busyobj->vbc; if (vc->recycled) retry = 1; /* * Now that we know our backend, we can set a default Host: * header if one is necessary. This cannot be done in the VCL * because the backend may be chosen by a director. */ if (need_host_hdr) VDI_AddHostHeader(sp->wrk, vc); (void)VTCP_blocking(vc->fd); /* XXX: we should timeout instead */ WRW_Reserve(wrk, &vc->fd); (void)http_Write(wrk, vc->vsl_id, hp, 0); /* XXX: stats ? */ /* Deal with any message-body the request might have */ i = FetchReqBody(sp); if (WRW_FlushRelease(wrk) || i > 0) { WSP(sp, SLT_FetchError, "backend write error: %d (%s)", errno, strerror(errno)); VDI_CloseFd(sp->wrk, &sp->wrk->busyobj->vbc); /* XXX: other cleanup ? */ return (retry); } /* Checkpoint the vsl.here */ WSL_Flush(wrk, 0); /* XXX is this the right place? */ VSC_C_main->backend_req++; /* Receive response */ HTC_Init(htc, wrk->ws, vc->fd, vc->vsl_id, cache_param->http_resp_size, cache_param->http_resp_hdr_len); VTCP_set_read_timeout(vc->fd, vc->first_byte_timeout); i = HTC_Rx(htc); if (i < 0) { WSP(sp, SLT_FetchError, "http first read error: %d %d (%s)", i, errno, strerror(errno)); VDI_CloseFd(sp->wrk, &sp->wrk->busyobj->vbc); /* XXX: other cleanup ? */ /* Retryable if we never received anything */ return (i == -1 ? retry : -1); } VTCP_set_read_timeout(vc->fd, vc->between_bytes_timeout); while (i == 0) { i = HTC_Rx(htc); if (i < 0) { WSP(sp, SLT_FetchError, "http first read error: %d %d (%s)", i, errno, strerror(errno)); VDI_CloseFd(sp->wrk, &sp->wrk->busyobj->vbc); /* XXX: other cleanup ? */ return (-1); } } hp = wrk->busyobj->beresp; if (http_DissectResponse(wrk, htc, hp)) { WSP(sp, SLT_FetchError, "http format error"); VDI_CloseFd(sp->wrk, &sp->wrk->busyobj->vbc); /* XXX: other cleanup ? */ return (-1); } return (0); }