static void mlog_close(int s) { struct mlogsock *obj = hdata(s, msock_type); dsock_assert(obj && obj->vfptrs.type == mlog_type); int rc = hclose(obj->s); dsock_assert(rc == 0); free(obj); }
static void bthrottler_close(int s) { struct bthrottlersock *obj = hdata(s, bsock_type); dsock_assert(obj && obj->vfptrs.type == bthrottler_type); int rc = hclose(obj->s); dsock_assert(rc == 0); free(obj); }
static int lz4_msendv(struct msock_vfs *mvfs, const struct iovec *iov, size_t iovlen, int64_t deadline) { struct lz4_sock *obj = dsock_cont(mvfs, struct lz4_sock, mvfs); /* Adjust the buffer size as needed. */ size_t len = iov_size(iov, iovlen); size_t maxlen = LZ4F_compressFrameBound(len, NULL); if(obj->outlen < maxlen) { uint8_t *newbuf = realloc(obj->outbuf, maxlen); if(dsock_slow(!newbuf)) {errno = ENOMEM; return -1;} obj->outbuf = newbuf; obj->outlen = maxlen; } /* Compress the data. */ /* TODO: Avoid the extra allocations and copies. */ uint8_t *buf = malloc(len); if(dsock_slow(!buf)) {errno = ENOMEM; return -1;} iov_copyallfrom(buf, iov, iovlen); LZ4F_preferences_t prefs = {0}; prefs.frameInfo.contentSize = len; size_t dstlen = LZ4F_compressFrame(obj->outbuf, obj->outlen, buf, len, &prefs); dsock_assert(!LZ4F_isError(dstlen)); dsock_assert(dstlen <= obj->outlen); free(buf); /* Send the compressed frame. */ return msend(obj->s, obj->outbuf, dstlen, deadline); }
static void lz4_hclose(struct hvfs *hvfs) { struct lz4_sock *obj = (struct lz4_sock*)hvfs; size_t ec = LZ4F_freeDecompressionContext(obj->dctx); dsock_assert(!LZ4F_isError(ec)); free(obj->inbuf); free(obj->outbuf); int rc = hclose(obj->s); dsock_assert(rc == 0); free(obj); }
static void nagle_hclose(struct hvfs *hvfs) { struct nagle_sock *obj = (struct nagle_sock*)hvfs; int rc = hclose(obj->sender); dsock_assert(rc == 0); rc = hclose(obj->ackch); dsock_assert(rc == 0); rc = hclose(obj->sendch); dsock_assert(rc == 0); free(obj->buf); rc = hclose(obj->s); dsock_assert(rc == 0); free(obj); }
int nagle_stop(int s, int64_t deadline) { struct nagle_sock *obj = hquery(s, nagle_type); if(dsock_slow(!obj)) return -1; /* TODO: Flush the data from the buffer! */ int rc = hclose(obj->sender); dsock_assert(rc == 0); rc = hclose(obj->ackch); dsock_assert(rc == 0); rc = hclose(obj->sendch); dsock_assert(rc == 0); free(obj->buf); int u = obj->s; free(obj); return u; }
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(); } }
int lz4_start(int s) { int err; /* Check whether underlying socket is message-based. */ if(dsock_slow(!hquery(s, msock_type))) {err = errno; goto error1;} /* Create the object. */ struct lz4_sock *obj = malloc(sizeof(struct lz4_sock)); if(dsock_slow(!obj)) {errno = ENOMEM; goto error1;} obj->hvfs.query = lz4_hquery; obj->hvfs.close = lz4_hclose; obj->mvfs.msendv = lz4_msendv; obj->mvfs.mrecvv = lz4_mrecvv; obj->s = s; obj->outbuf = NULL; obj->outlen = 0; obj->inbuf = NULL; obj->inlen = 0; size_t ec = LZ4F_createDecompressionContext(&obj->dctx, LZ4F_VERSION); if(dsock_slow(LZ4F_isError(ec))) {err = EFAULT; goto error2;} /* Create the handle. */ int h = hcreate(&obj->hvfs); if(dsock_slow(h < 0)) {err = errno; goto error3;} return h; error3: ec = LZ4F_freeDecompressionContext(obj->dctx); dsock_assert(!LZ4F_isError(ec)); error2: free(obj); error1: errno = err; return -1; }
int nagle_start(int s, size_t batch, int64_t interval) { int rc; int err; /* Check whether underlying socket is a bytestream. */ if(dsock_slow(!hquery(s, bsock_type))) {err = errno; goto error1;} /* Create the object. */ struct nagle_sock *obj = malloc(sizeof(struct nagle_sock)); if(dsock_slow(!obj)) {err = ENOMEM; goto error1;} obj->hvfs.query = nagle_hquery; obj->hvfs.close = nagle_hclose; obj->bvfs.bsendv = nagle_bsendv; obj->bvfs.brecvv = nagle_brecvv; obj->s = s; obj->buf = malloc(batch); if(dsock_slow(!obj->buf)) {errno = ENOMEM; goto error2;} obj->sendch = channel(sizeof(struct nagle_vec), 0); if(dsock_slow(obj->sendch < 0)) {err = errno; goto error3;} obj->ackch = channel(sizeof(int), 0); if(dsock_slow(obj->ackch < 0)) {err = errno; goto error4;} obj->sender = go(nagle_sender(s, batch, interval, obj->buf, obj->sendch, obj->ackch)); if(dsock_slow(obj->sender < 0)) {err = errno; goto error5;} /* Create the handle. */ int h = hcreate(&obj->hvfs); if(dsock_slow(h < 0)) {err = errno; goto error6;} return h; error6: rc = hclose(obj->sender); dsock_assert(rc == 0); error5: rc = hclose(obj->ackch); dsock_assert(rc == 0); error4: rc = hclose(obj->sendch); dsock_assert(rc == 0); error3: free(obj->buf); error2: free(obj); error1: errno = err; return -1; }
static int mlog_msend(int s, const void *buf, size_t len, int64_t deadline) { struct mlogsock *obj = hdata(s, msock_type); dsock_assert(obj->vfptrs.type == mlog_type); fprintf(stderr, "send %8zuB: 0x", len); size_t i; for(i = 0; i != len; ++i) fprintf(stderr, "%02x", (int)((uint8_t*)buf)[i]); fprintf(stderr, "\n"); return msend(obj->s, buf, len, deadline); }
int lz4_stop(int s) { struct lz4_sock *obj = hquery(s, lz4_type); if(dsock_slow(!obj)) return -1; size_t ec = LZ4F_freeDecompressionContext(obj->dctx); dsock_assert(!LZ4F_isError(ec)); free(obj->inbuf); free(obj->outbuf); int u = obj->s; free(obj); return u; }
static ssize_t mlog_mrecv(int s, void *buf, size_t len, int64_t deadline) { struct mlogsock *obj = hdata(s, msock_type); dsock_assert(obj->vfptrs.type == mlog_type); ssize_t sz = mrecv(obj->s, buf, len, deadline); if(dsock_slow(sz < 0)) return -1; fprintf(stderr, "recv %8zuB: 0x", len); size_t i; for(i = 0; i != sz && i != len; ++i) fprintf(stderr, "%02x", (int)((uint8_t*)buf)[i]); fprintf(stderr, "\n"); return sz; }
static ssize_t mthrottler_mrecv(int s, void *buf, size_t len, int64_t deadline) { struct mthrottlersock *obj = hdata(s, msock_type); dsock_assert(obj->vfptrs.type == mthrottler_type); /* If recv-throttling is off forward the call. */ if(obj->recv_full == 0) return mrecv(obj->s, buf, len, deadline); /* If there's no quota wait till it is renewed. */ if(!obj->recv_remaining) { int rc = msleep(obj->recv_last + obj->recv_interval); if(dsock_slow(rc < 0)) return -1; obj->recv_remaining = obj->recv_full; obj->recv_last = now(); } /* Receive the message. */ int rc = mrecv(obj->s, buf, len, deadline); if(dsock_slow(rc < 0)) return -1; --obj->recv_remaining; return 0; }
static ssize_t lz4_mrecvv(struct msock_vfs *mvfs, const struct iovec *iov, size_t iovlen, int64_t deadline) { struct lz4_sock *obj = dsock_cont(mvfs, struct lz4_sock, mvfs); /* Adjust the buffer size as needed. */ size_t len = iov_size(iov, iovlen); size_t maxlen = LZ4F_compressFrameBound(len, NULL); if(obj->inlen < maxlen) { uint8_t *newbuf = realloc(obj->inbuf, maxlen); if(dsock_slow(!newbuf)) {errno = ENOMEM; return -1;} obj->inbuf = newbuf; obj->inlen = maxlen; } /* Get the compressed message. */ ssize_t sz = mrecv(obj->s, obj->inbuf, obj->inlen, deadline); if(dsock_slow(sz < 0)) return -1; /* Extract size of the uncompressed message from LZ4 frame header. */ LZ4F_frameInfo_t info; size_t infolen = sz; size_t ec = LZ4F_getFrameInfo(obj->dctx, &info, obj->inbuf, &infolen); if(dsock_slow(LZ4F_isError(ec))) {errno = EPROTO; return -1;} /* Size is a required field. */ if(dsock_slow(info.contentSize == 0)) {errno = EPROTO; return -1;} /* Decompressed message would exceed the buffer size. */ if(dsock_slow(info.contentSize > len)) {errno = EMSGSIZE; return -1;} /* Decompress. */ /* TODO: Avoid the extra allocations and copies. */ uint8_t *buf = malloc(len); if(dsock_slow(!buf)) {errno = ENOMEM; return -1;} size_t dstlen = len; size_t srclen = sz - infolen; ec = LZ4F_decompress(obj->dctx, buf, &dstlen, obj->inbuf + infolen, &srclen, NULL); if(dsock_slow(LZ4F_isError(ec))) {errno = EPROTO; return -1;} if(dsock_slow(ec != 0)) {errno = EPROTO; return -1;} dsock_assert(srclen == sz - infolen); iov_copyallto(iov, iovlen, buf); free(buf); return dstlen; }
static void mthrottler_hclose(struct hvfs *hvfs) { struct mthrottler_sock *obj = (struct mthrottler_sock*)hvfs; int rc = hclose(obj->s); dsock_assert(rc == 0); free(obj); }
static coroutine void nagle_sender(int s, size_t batch, int64_t interval, uint8_t *buf, int sendch, int ackch) { /* Amount of data in the buffer. */ size_t len = 0; /* Last time at least one byte was sent. */ int64_t last = now(); while(1) { /* Get data to send from the user coroutine. */ struct nagle_vec vec; int rc = chrecv(sendch, &vec, sizeof(vec), interval >= 0 && len ? last + interval : -1); if(dsock_slow(rc < 0 && errno == ECANCELED)) return; /* Timeout expired. Flush the data in the buffer. */ if(dsock_slow(rc < 0 && errno == ETIMEDOUT)) { rc = bsend(s, buf, len, -1); if(dsock_slow(rc < 0 && errno == ECANCELED)) return; dsock_assert(rc == 0); len = 0; last = now(); continue; } dsock_assert(rc == 0); /* If data fit into the buffer, store them there. */ size_t bytes = iov_size(vec.iov, vec.iovlen); if(len + bytes < batch) { iov_copyallfrom(buf + len, vec.iov, vec.iovlen); len += bytes; int err = 0; rc = chsend(ackch, &err, sizeof(err), -1); if(dsock_slow(rc < 0 && errno == ECANCELED)) return; dsock_assert(rc == 0); continue; } if(len > 0) { /* Flush the buffer. */ rc = bsend(s, buf, len, -1); if(dsock_slow(rc < 0 && errno == ECANCELED)) return; /* Pass the error to the user. */ if(dsock_slow(rc < 0)) { int err = errno; rc = chsend(ackch, &err, sizeof(err), -1); if(dsock_slow(rc < 0 && errno == ECANCELED)) return; dsock_assert(rc == 0); return; } len = 0; last = now(); } /* Once again: If data fit into buffer store them there. */ if(bytes < batch) { iov_copyallfrom(buf, vec.iov, vec.iovlen); len = bytes; int err = 0; rc = chsend(ackch, &err, sizeof(err), -1); if(dsock_slow(rc < 0 && errno == ECANCELED)) return; dsock_assert(rc == 0); continue; } /* This is a big chunk of data, no need to Nagle it. We'll send it straight away. */ rc = bsendv(s, vec.iov, vec.iovlen, -1); if(dsock_slow(rc < 0 && errno == ECANCELED)) return; dsock_assert(rc == 0); last = now(); int err = 0; rc = chsend(ackch, &err, sizeof(err), -1); if(dsock_slow(rc < 0 && errno == ECANCELED)) return; dsock_assert(rc == 0); } }