h2_rxframe(struct worker *wrk, struct h2_sess *h2)
{
	enum htc_status_e hs;
	h2_frame h2f;
	h2_error h2e;
	char b[8];

	ASSERT_RXTHR(h2);
	VTCP_blocking(*h2->htc->rfd);
	h2->sess->t_idle = VTIM_real();
	hs = HTC_RxStuff(h2->htc, h2_frame_complete,
	    NULL, NULL, NAN,
	    h2->sess->t_idle + SESS_TMO(h2->sess, timeout_idle),
	    NAN, h2->local_settings.max_frame_size + 9);
	switch (hs) {
	case HTC_S_COMPLETE:
		break;
	case HTC_S_TIMEOUT:
		if (h2_sweep(wrk, h2))
			return (1);

		/* FALLTHROUGH */
	default:
		/* XXX: HTC_S_OVERFLOW / FRAME_SIZE_ERROR handling */
		Lck_Lock(&h2->sess->mtx);
		VSLb(h2->vsl, SLT_Debug, "H2: No frame (hs=%d)", hs);
		h2->error = H2CE_NO_ERROR;
		Lck_Unlock(&h2->sess->mtx);
		return (0);
	}

	if (h2->do_sweep)
		(void)h2_sweep(wrk, h2);

	h2->rxf_len =  vbe32dec(h2->htc->rxbuf_b) >> 8;
	h2->rxf_type =  h2->htc->rxbuf_b[3];
	h2->rxf_flags = h2->htc->rxbuf_b[4];
	h2->rxf_stream = vbe32dec(h2->htc->rxbuf_b + 5);
	h2->rxf_stream &= ~(1LU<<31);			// rfc7540,l,690,692
	h2->rxf_data = (void*)(h2->htc->rxbuf_b + 9);
	/* XXX: later full DATA will not be rx'ed yet. */
	HTC_RxPipeline(h2->htc, h2->htc->rxbuf_b + h2->rxf_len + 9);

	h2_vsl_frame(h2, h2->htc->rxbuf_b, 9L + h2->rxf_len);
	h2->srq->acct.req_hdrbytes += 9;

	if (h2->rxf_type >= H2FMAX) {
		// rfc7540,l,679,681
		// XXX: later, drain rest of frame
		h2->bogosity++;
		Lck_Lock(&h2->sess->mtx);
		VSLb(h2->vsl, SLT_Debug,
		    "H2: Unknown frame type 0x%02x (ignored)",
		    (uint8_t)h2->rxf_type);
		Lck_Unlock(&h2->sess->mtx);
		h2->srq->acct.req_bodybytes += h2->rxf_len;
		return (1);
	}
	h2f = h2flist[h2->rxf_type];

	AN(h2f->name);
	AN(h2f->rxfunc);
	if (h2f->overhead)
		h2->srq->acct.req_bodybytes += h2->rxf_len;

	if (h2->rxf_flags & ~h2f->flags) {
		// rfc7540,l,687,688
		h2->bogosity++;
		Lck_Lock(&h2->sess->mtx);
		VSLb(h2->vsl, SLT_Debug,
		    "H2: Unknown flags 0x%02x on %s (ignored)",
		    (uint8_t)h2->rxf_flags & ~h2f->flags, h2f->name);
		Lck_Unlock(&h2->sess->mtx);
		h2->rxf_flags &= h2f->flags;
	}

	h2e = h2_procframe(wrk, h2, h2f);
	if (h2->error == 0 && h2e) {
		h2->error = h2e;
		vbe32enc(b, h2->highest_stream);
		vbe32enc(b + 4, h2e->val);
		H2_Send_Get(wrk, h2, h2->req0);
		H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b);
		H2_Send_Rel(h2, h2->req0);
	}
	return (h2->error ? 0 : 1);
}
h2_rxframe(struct worker *wrk, struct h2_sess *h2)
{
	enum htc_status_e hs;
	h2_frame h2f;
	h2_error h2e;
	char b[8];

	ASSERT_RXTHR(h2);
	VTCP_blocking(*h2->htc->rfd);
	h2->sess->t_idle = VTIM_real();
	hs = HTC_RxStuff(h2->htc, h2_frame_complete,
	    NULL, NULL, NAN,
	    h2->sess->t_idle + SESS_TMO(h2->sess, timeout_idle),
	    NAN, h2->local_settings.max_frame_size + 9);
	switch (hs) {
	case HTC_S_COMPLETE:
		break;
	case HTC_S_TIMEOUT:
		if (h2_sweep(wrk, h2))
			return (1);

		 
	default:
		 
		Lck_Lock(&h2->sess->mtx);
		VSLb(h2->vsl, SLT_Debug, "H2: No frame (hs=%d)", hs);
		h2->error = H2CE_NO_ERROR;
		Lck_Unlock(&h2->sess->mtx);
		return (0);
	}

	if (h2->do_sweep)
		(void)h2_sweep(wrk, h2);

	h2->rxf_len =  vbe32dec(h2->htc->rxbuf_b) >> 8;
	h2->rxf_type =  h2->htc->rxbuf_b[3];
	h2->rxf_flags = h2->htc->rxbuf_b[4];
	h2->rxf_stream = vbe32dec(h2->htc->rxbuf_b + 5);
	h2->rxf_stream &= ~(1LU<<31);			 
	h2->rxf_data = (void*)(h2->htc->rxbuf_b + 9);
	 
	HTC_RxPipeline(h2->htc, h2->htc->rxbuf_b + h2->rxf_len + 9);

	h2_vsl_frame(h2, h2->htc->rxbuf_b, 9L + h2->rxf_len);
	h2->srq->acct.req_hdrbytes += 9;

	if (h2->rxf_type >= H2FMAX) {
		 
		 
		h2->bogosity++;
		Lck_Lock(&h2->sess->mtx);
		VSLb(h2->vsl, SLT_Debug,
		    "H2: Unknown frame type 0x%02x (ignored)",
		    (uint8_t)h2->rxf_type);
		Lck_Unlock(&h2->sess->mtx);
		h2->srq->acct.req_bodybytes += h2->rxf_len;
		return (1);
	}
	h2f = h2flist[h2->rxf_type];

	AN(h2f->name);
	AN(h2f->rxfunc);
	if (h2f->overhead)
		h2->srq->acct.req_bodybytes += h2->rxf_len;

	if (h2->rxf_flags & ~h2f->flags) {
		 
		h2->bogosity++;
		Lck_Lock(&h2->sess->mtx);
		VSLb(h2->vsl, SLT_Debug,
		    "H2: Unknown flags 0x%02x on %s (ignored)",
		    (uint8_t)h2->rxf_flags & ~h2f->flags, h2f->name);
		Lck_Unlock(&h2->sess->mtx);
		h2->rxf_flags &= h2f->flags;
	}

	h2e = h2_procframe(wrk, h2, h2f);
	if (h2->error == 0 && h2e) {
		h2->error = h2e;
		vbe32enc(b, h2->highest_stream);
		vbe32enc(b + 4, h2e->val);
		H2_Send_Get(wrk, h2, h2->req0);
		H2_Send_Frame(wrk, h2, H2_F_GOAWAY, 0, 8, 0, b);
		H2_Send_Rel(h2, h2->req0);
	}
	return (h2->error ? 0 : 1);
}