static int bthrottler_brecv(int s, void *buf, size_t len, int64_t deadline) { struct bthrottlersock *obj = hdata(s, bsock_type); dsock_assert(obj->vfptrs.type == bthrottler_type); /* If recv-throttling is off forward the call. */ if(obj->recv_full == 0) return brecv(obj->s, buf, len, deadline); /* Get rid of the corner case. */ if(dsock_slow(len == 0)) return 0; while(1) { /* If there's capacity receive as much data as possible. */ if(obj->recv_remaining) { size_t torecv = len < obj->recv_remaining ? len : obj->recv_remaining; int rc = brecv(obj->s, buf, torecv, deadline); if(dsock_slow(rc < 0)) return -1; obj->recv_remaining -= torecv; buf = (char*)buf + torecv; len -= torecv; if(len == 0) return 0; } /* Wait till capacity can be renewed. */ int rc = msleep(obj->recv_last + obj->recv_interval); if(dsock_slow(rc < 0)) return -1; /* Renew the capacity. */ obj->recv_remaining = obj->recv_full; obj->recv_last = now(); } }
static coroutine void sf_iworker(struct sf *conn) { struct msg msg = {NULL, 0}; while(1) { uint64_t hdr; int rc = brecv(conn->u, &hdr, sizeof(hdr), -1); CHECKRC(ires) if(dill_slow(hdr == sf_termsequence)) {conn->ires = SF_DONE; break;} msg.len = (size_t)dill_getll((uint8_t*)&hdr); msg.buf = malloc(msg.len); dill_assert(msg.buf); rc = brecv(conn->u, msg.buf, msg.len, -1); CHECKRC(ires) rc = chsend(conn->ichan, &msg, sizeof(msg), -1); if(dill_slow(rc < 0 && errno == ECANCELED)) break; dill_assert(rc == 0); msg.buf = NULL; msg.len = 0; } free(msg.buf); int rc = chdone(conn->ichan); dill_assert(rc == 0); }
coroutine void client1(int u) { int s = tls_attach_client(u, -1); errno_assert(s >= 0); int rc = bsend(s, "ABC", 3, -1); errno_assert(rc == 0); rc = tls_done(s, -1); errno_assert(rc == 0); char buf[3]; rc = brecv(s, buf, sizeof(buf), -1); errno_assert(rc == 0); assert(buf[0] == 'D' && buf[1] == 'E' && buf[2] == 'F'); u = tls_detach(s, -1); errno_assert(u >= 0); rc = hclose(u); errno_assert(rc == 0); }
int main(void) { char buf[16]; /* Test simple data exchange, with explicit handshake. */ int u[2]; int rc = ipc_pair(u); errno_assert(rc == 0); int cr = go(client1(u[1])); errno_assert(cr >= 0); int s = tls_attach_server(u[0], "tests/cert.pem", "tests/key.pem", -1); errno_assert(s >= 0); rc = brecv(s, buf, 3, -1); errno_assert(rc == 0); assert(buf[0] == 'A' && buf[1] == 'B' && buf[2] == 'C'); rc = brecv(s, buf, 3, -1); errno_assert(rc == -1 && errno == EPIPE); rc = bsend(s, "DEF", 3, -1); errno_assert(rc == 0); rc = tls_done(s, -1); errno_assert(rc == 0); u[0] = tls_detach(s, -1); errno_assert(u[0] >= 0); rc = hclose(u[0]); errno_assert(rc == 0); rc = bundle_wait(cr, -1); errno_assert(rc == 0); rc = hclose(cr); errno_assert(rc == 0); /* Test simple data transfer, terminated by tls_detach(). Then send some data over undelying IPC connection. */ rc = ipc_pair(u); errno_assert(rc == 0); cr = go(client2(u[1])); errno_assert(cr >= 0); s = tls_attach_server(u[0], "tests/cert.pem", "tests/key.pem", -1); errno_assert(s >= 0); rc = brecv(s, buf, 3, -1); errno_assert(rc == 0); assert(buf[0] == 'A' && buf[1] == 'B' && buf[2] == 'C'); u[0] = tls_detach(s, -1); errno_assert(u[0] >= 0); rc = brecv(u[0], buf, 3, -1); errno_assert(rc == 0); assert(buf[0] == 'D' && buf[1] == 'E' && buf[2] == 'F'); rc = ipc_close(u[0], -1); errno_assert(rc == 0); rc = bundle_wait(cr, -1); errno_assert(rc == 0); rc = hclose(cr); errno_assert(rc == 0); /* Transfer large amount of data. */ rc = ipc_pair(u); errno_assert(rc == 0); cr = go(client3(u[1])); errno_assert(cr >= 0); s = tls_attach_server(u[0], "tests/cert.pem", "tests/key.pem", -1); errno_assert(s >= 0); uint8_t c = 0; int i; for(i = 0; i != 2777; ++i) { uint8_t b[257]; rc = brecv(s, b, sizeof(b), -1); errno_assert(rc == 0); int j; for(j = 0; j != sizeof(b); ++j) { assert(b[j] == c); c++; } } u[0] = tls_detach(s, -1); errno_assert(u[0] >= 0); rc = bundle_wait(cr, -1); errno_assert(rc == 0); rc = hclose(cr); errno_assert(rc == 0); rc = hclose(u[0]); errno_assert(rc == 0); return 0; }