diff --git a/btpd/cli_if.c b/btpd/cli_if.c index 50e9d7a..100c6b4 100644 --- a/btpd/cli_if.c +++ b/btpd/cli_if.c @@ -11,7 +11,7 @@ struct cli { static struct event m_cli_incoming; static int -write_buffer(struct cli *cli, struct io_buffer *iob) +write_buffer(struct cli *cli, struct iobuf *iob) { int err = 0; if (!iob->error) { @@ -20,107 +20,107 @@ write_buffer(struct cli *cli, struct io_buffer *iob) err = write_fully(cli->sd, iob->buf, iob->off); } else btpd_err("Out of memory.\n"); - buf_free(iob); + iobuf_free(iob); return err; } static int write_code_buffer(struct cli *cli, enum ipc_err code) { - struct io_buffer iob = buf_init(16); - buf_print(&iob, "d4:codei%uee", code); + struct iobuf iob = iobuf_init(16); + iobuf_print(&iob, "d4:codei%uee", code); return write_buffer(cli, &iob); } static int write_add_buffer(struct cli *cli, unsigned num) { - struct io_buffer iob = buf_init(32); - buf_print(&iob, "d4:codei%ue3:numi%uee", IPC_OK, num); + struct iobuf iob = iobuf_init(32); + iobuf_print(&iob, "d4:codei%ue3:numi%uee", IPC_OK, num); return write_buffer(cli, &iob); } static void -write_ans(struct io_buffer *iob, struct tlib *tl, enum ipc_tval val) +write_ans(struct iobuf *iob, struct tlib *tl, enum ipc_tval val) { enum ipc_tstate ts = IPC_TSTATE_INACTIVE; switch (val) { case IPC_TVAL_CGOT: - buf_print(iob, "i%dei%llde", IPC_TYPE_NUM, + iobuf_print(iob, "i%dei%llde", IPC_TYPE_NUM, tl->tp == NULL ? tl->content_have : (long long)cm_content(tl->tp)); return; case IPC_TVAL_CSIZE: - buf_print(iob, "i%dei%llde", IPC_TYPE_NUM, + iobuf_print(iob, "i%dei%llde", IPC_TYPE_NUM, (long long)tl->content_size); return; case IPC_TVAL_PCCOUNT: if (tl->tp == NULL) - buf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_ETINACTIVE); + iobuf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_ETINACTIVE); else - buf_print(iob, "i%dei%lue", IPC_TYPE_NUM, + iobuf_print(iob, "i%dei%lue", IPC_TYPE_NUM, (unsigned long)tl->tp->npieces); return; case IPC_TVAL_PCGOT: if (tl->tp == NULL) - buf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_ETINACTIVE); + iobuf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_ETINACTIVE); else - buf_print(iob, "i%dei%lue", IPC_TYPE_NUM, + iobuf_print(iob, "i%dei%lue", IPC_TYPE_NUM, (unsigned long)cm_pieces(tl->tp)); return; case IPC_TVAL_PCSEEN: if (tl->tp == NULL) - buf_print(iob, "i%dei%de", IPC_TYPE_NUM, 0); + iobuf_print(iob, "i%dei%de", IPC_TYPE_NUM, 0); else { unsigned long pcseen = 0; for (unsigned long i = 0; i < tl->tp->npieces; i++) if (tl->tp->net->piece_count[i] > 0) pcseen++; - buf_print(iob, "i%dei%lue", IPC_TYPE_NUM, pcseen); + iobuf_print(iob, "i%dei%lue", IPC_TYPE_NUM, pcseen); } return; case IPC_TVAL_RATEDWN: - buf_print(iob, "i%dei%lue", IPC_TYPE_NUM, + iobuf_print(iob, "i%dei%lue", IPC_TYPE_NUM, tl->tp == NULL ? 0UL : tl->tp->net->rate_dwn / RATEHISTORY); return; case IPC_TVAL_RATEUP: - buf_print(iob, "i%dei%lue", IPC_TYPE_NUM, + iobuf_print(iob, "i%dei%lue", IPC_TYPE_NUM, tl->tp == NULL ? 0UL : tl->tp->net->rate_up / RATEHISTORY); return; case IPC_TVAL_SESSDWN: - buf_print(iob, "i%dei%llde", IPC_TYPE_NUM, + iobuf_print(iob, "i%dei%llde", IPC_TYPE_NUM, tl->tp == NULL ? 0LL : tl->tp->net->downloaded); return; case IPC_TVAL_SESSUP: - buf_print(iob, "i%dei%llde", IPC_TYPE_NUM, + iobuf_print(iob, "i%dei%llde", IPC_TYPE_NUM, tl->tp == NULL ? 0LL : tl->tp->net->uploaded); return; case IPC_TVAL_DIR: if (tl->dir != NULL) - buf_print(iob, "i%de%d:%s", IPC_TYPE_STR, (int)strlen(tl->dir), + iobuf_print(iob, "i%de%d:%s", IPC_TYPE_STR, (int)strlen(tl->dir), tl->dir); else - buf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_EBADTENT); + iobuf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_EBADTENT); return; case IPC_TVAL_NAME: if (tl->name != NULL) - buf_print(iob, "i%de%d:%s", IPC_TYPE_STR, (int)strlen(tl->name), + iobuf_print(iob, "i%de%d:%s", IPC_TYPE_STR, (int)strlen(tl->name), tl->name); else - buf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_EBADTENT); + iobuf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_EBADTENT); return; case IPC_TVAL_IHASH: - buf_print(iob, "i%de20:", IPC_TYPE_BIN); - buf_write(iob, tl->hash, 20); + iobuf_print(iob, "i%de20:", IPC_TYPE_BIN); + iobuf_write(iob, tl->hash, 20); return; case IPC_TVAL_NUM: - buf_print(iob, "i%dei%ue", IPC_TYPE_NUM, tl->num); + iobuf_print(iob, "i%dei%ue", IPC_TYPE_NUM, tl->num); return; case IPC_TVAL_PCOUNT: - buf_print(iob, "i%dei%ue", IPC_TYPE_NUM, + iobuf_print(iob, "i%dei%ue", IPC_TYPE_NUM, tl->tp == NULL ? 0 : tl->tp->net->npeers); return; case IPC_TVAL_STATE: - buf_print(iob, "i%de", IPC_TYPE_NUM); + iobuf_print(iob, "i%de", IPC_TYPE_NUM); if (tl->tp != NULL) { switch (tl->tp->state) { case T_STARTING: @@ -137,24 +137,24 @@ write_ans(struct io_buffer *iob, struct tlib *tl, enum ipc_tval val) break; } } - buf_print(iob, "i%de", ts); + iobuf_print(iob, "i%de", ts); return; case IPC_TVAL_TOTDWN: - buf_print(iob, "i%dei%llde", IPC_TYPE_NUM, tl->tot_down + + iobuf_print(iob, "i%dei%llde", IPC_TYPE_NUM, tl->tot_down + (tl->tp == NULL ? 0 : tl->tp->net->downloaded)); return; case IPC_TVAL_TOTUP: - buf_print(iob, "i%dei%llde", IPC_TYPE_NUM, tl->tot_up + + iobuf_print(iob, "i%dei%llde", IPC_TYPE_NUM, tl->tot_up + (tl->tp == NULL ? 0 : tl->tp->net->uploaded)); return; case IPC_TVAL_TRERR: - buf_print(iob, "i%dei%ue", IPC_TYPE_NUM, + iobuf_print(iob, "i%dei%ue", IPC_TYPE_NUM, tl->tp == NULL ? 0 : tr_errors(tl->tp)); return; case IPC_TVALCOUNT: break; } - buf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_ENOKEY); + iobuf_print(iob, "i%dei%de", IPC_TYPE_ERR, IPC_ENOKEY); } static int @@ -166,7 +166,7 @@ cmd_tget(struct cli *cli, int argc, const char *args) size_t nkeys; const char *keys, *p; enum ipc_tval *opts; - struct io_buffer iob; + struct iobuf iob; if ((keys = benc_dget_lst(args, "keys")) == NULL) return IPC_COMMERR; @@ -178,8 +178,8 @@ cmd_tget(struct cli *cli, int argc, const char *args) for (int i = 0; i < nkeys; i++) opts[i] = benc_int(p, &p); - iob = buf_init(1 << 15); - buf_swrite(&iob, "d4:codei0e6:resultl"); + iob = iobuf_init(1 << 15); + iobuf_swrite(&iob, "d4:codei0e6:resultl"); p = benc_dget_any(args, "from"); if (benc_isint(p)) { enum ipc_twc from = benc_int(p, NULL); @@ -189,10 +189,10 @@ cmd_tget(struct cli *cli, int argc, const char *args) if ((from == IPC_TWC_ALL || (tlv[i]->tp == NULL && from == IPC_TWC_INACTIVE) || (tlv[i]->tp != NULL && from == IPC_TWC_ACTIVE))) { - buf_swrite(&iob, "l"); + iobuf_swrite(&iob, "l"); for (int k = 0; k < nkeys; k++) write_ans(&iob, tlv[i], opts[k]); - buf_swrite(&iob, "e"); + iobuf_swrite(&iob, "e"); } } } else if (benc_islst(p)) { @@ -203,20 +203,20 @@ cmd_tget(struct cli *cli, int argc, const char *args) else if (benc_isstr(p) && benc_strlen(p) == 20) tl = tlib_by_hash(benc_mem(p, NULL, NULL)); else { - buf_free(&iob); + iobuf_free(&iob); free(opts); return IPC_COMMERR; } if (tl != NULL) { - buf_swrite(&iob, "l"); + iobuf_swrite(&iob, "l"); for (int i = 0; i < nkeys; i++) write_ans(&iob, tl, opts[i]); - buf_swrite(&iob, "e"); + iobuf_swrite(&iob, "e"); } else - buf_print(&iob, "i%de", IPC_ENOTENT); + iobuf_print(&iob, "i%de", IPC_ENOTENT); } } - buf_swrite(&iob, "ee"); + iobuf_swrite(&iob, "ee"); free(opts); return write_buffer(cli, &iob); } diff --git a/btpd/tlib.c b/btpd/tlib.c index 9a2c3af..362139d 100644 --- a/btpd/tlib.c +++ b/btpd/tlib.c @@ -156,9 +156,9 @@ save_info(struct tlib *tl) { FILE *fp; char relpath[SHAHEXSIZE], path[PATH_MAX], wpath[PATH_MAX]; - struct io_buffer iob = buf_init(1 << 10); + struct iobuf iob = iobuf_init(1 << 10); - buf_print(&iob, + iobuf_print(&iob, "d4:infod" "12:content havei%llde12:content sizei%llde" "3:dir%d:%s4:name%d:%s" @@ -177,7 +177,7 @@ save_info(struct tlib *tl) if ((fp = fopen(wpath, "w")) == NULL) btpd_err("failed to open '%s' (%s).\n", wpath, strerror(errno)); dct_subst_save(fp, "de", iob.buf); - buf_free(&iob); + iobuf_free(&iob); if ((fflush(fp) == EOF || fsync(fileno(fp)) != 0 || ferror(fp) || fclose(fp) != 0)) btpd_err("failed to write '%s'.\n", wpath); diff --git a/cli/add.c b/cli/add.c index 4f55b9d..c91bf41 100644 --- a/cli/add.c +++ b/cli/add.c @@ -74,21 +74,21 @@ cmd_add(int argc, char **argv) size_t mi_size; enum ipc_err code; char dpath[PATH_MAX]; - struct io_buffer iob; + struct iobuf iob; if ((mi = mi_load(argv[0], &mi_size)) == NULL) err(1, "error loading '%s'", argv[0]); - iob = buf_init(PATH_MAX); - buf_write(&iob, dir, dirlen); + iob = iobuf_init(PATH_MAX); + iobuf_write(&iob, dir, dirlen); if (topdir && !mi_simple(mi)) { size_t tdlen; const char *td = benc_dget_mem(benc_dget_dct(mi, "info"), "name", &tdlen); - buf_swrite(&iob, "/"); - buf_write(&iob, td, tdlen); + iobuf_swrite(&iob, "/"); + iobuf_write(&iob, td, tdlen); } - buf_swrite(&iob, "\0"); + iobuf_swrite(&iob, "\0"); if ((errno = make_abs_path(iob.buf, dpath)) != 0) err(1, "make_abs_path '%s'", dpath); code = btpd_add(ipc, mi, mi_size, dpath, name); diff --git a/misc/btpd_if.c b/misc/btpd_if.c index 6705963..0d43924 100644 --- a/misc/btpd_if.c +++ b/misc/btpd_if.c @@ -129,7 +129,7 @@ ipc_req_res(struct ipc *ipc, const char *req, uint32_t qlen, char **res, } static enum ipc_err -ipc_buf_req_res(struct ipc *ipc, struct io_buffer *iob, char **res, +ipc_buf_req_res(struct ipc *ipc, struct iobuf *iob, char **res, uint32_t *rlen) { enum ipc_err err; @@ -137,12 +137,12 @@ ipc_buf_req_res(struct ipc *ipc, struct io_buffer *iob, char **res, err = IPC_COMMERR; else err = ipc_req_res(ipc, iob->buf, iob->off, res, rlen); - buf_free(iob); + iobuf_free(iob); return err; } static enum ipc_err -ipc_buf_req_code(struct ipc *ipc, struct io_buffer *iob) +ipc_buf_req_code(struct ipc *ipc, struct iobuf *iob) { enum ipc_err err; char *res; @@ -158,11 +158,11 @@ ipc_buf_req_code(struct ipc *ipc, struct io_buffer *iob) enum ipc_err btpd_die(struct ipc *ipc, int seconds) { - struct io_buffer iob = buf_init(16); + struct iobuf iob = iobuf_init(16); if (seconds >= 0) - buf_print(&iob, "l3:diei%dee", seconds); + iobuf_print(&iob, "l3:diei%dee", seconds); else - buf_swrite(&iob, "l3:diee"); + iobuf_swrite(&iob, "l3:diee"); return ipc_buf_req_code(ipc, &iob); } @@ -219,24 +219,24 @@ btpd_tget(struct ipc *ipc, struct ipc_torrent *tps, size_t ntps, char *res; uint32_t rlen; enum ipc_err err; - struct io_buffer iob; + struct iobuf iob; if (nkeys == 0 || ntps == 0) return IPC_COMMERR; - iob = buf_init(1 << 14); - buf_swrite(&iob, "l4:tgetd4:froml"); + iob = iobuf_init(1 << 14); + iobuf_swrite(&iob, "l4:tgetd4:froml"); for (int i = 0; i < ntps; i++) { if (tps[i].by_hash) { - buf_swrite(&iob, "20:"); - buf_write(&iob, tps[i].u.hash, 20); + iobuf_swrite(&iob, "20:"); + iobuf_write(&iob, tps[i].u.hash, 20); } else - buf_print(&iob, "i%ue", tps[i].u.num); + iobuf_print(&iob, "i%ue", tps[i].u.num); } - buf_swrite(&iob, "e4:keysl"); + iobuf_swrite(&iob, "e4:keysl"); for (int k = 0; k < nkeys; k++) - buf_print(&iob, "i%de", keys[k]); - buf_swrite(&iob, "eee"); + iobuf_print(&iob, "i%de", keys[k]); + iobuf_swrite(&iob, "eee"); if ((err = ipc_buf_req_res(ipc, &iob, &res, &rlen)) == 0) err = tget_common(res, keys, nkeys, cb, arg); @@ -249,17 +249,17 @@ btpd_tget_wc(struct ipc *ipc, enum ipc_twc twc, enum ipc_tval *keys, { char *res; uint32_t rlen; - struct io_buffer iob; + struct iobuf iob; enum ipc_err err; if (nkeys == 0) return IPC_COMMERR; - iob = buf_init(1 << 14); - buf_print(&iob, "l4:tgetd4:fromi%de4:keysl", twc); + iob = iobuf_init(1 << 14); + iobuf_print(&iob, "l4:tgetd4:fromi%de4:keysl", twc); for (int i = 0; i < nkeys; i++) - buf_print(&iob, "i%de", keys[i]); - buf_swrite(&iob, "eee"); + iobuf_print(&iob, "i%de", keys[i]); + iobuf_swrite(&iob, "eee"); if ((err = ipc_buf_req_res(ipc, &iob, &res, &rlen)) == 0) err = tget_common(res, keys, nkeys, cb, arg); @@ -270,27 +270,27 @@ enum ipc_err btpd_add(struct ipc *ipc, const char *mi, size_t mi_size, const char *content, const char *name) { - struct io_buffer iob = buf_init(1 << 10); - buf_print(&iob, "l3:addd7:content%d:%s", (int)strlen(content), + struct iobuf iob = iobuf_init(1 << 10); + iobuf_print(&iob, "l3:addd7:content%d:%s", (int)strlen(content), content); if (name != NULL) - buf_print(&iob, "4:name%d:%s", (int)strlen(name), name); - buf_print(&iob, "7:torrent%lu:", (unsigned long)mi_size); - buf_write(&iob, mi, mi_size); - buf_swrite(&iob, "ee"); + iobuf_print(&iob, "4:name%d:%s", (int)strlen(name), name); + iobuf_print(&iob, "7:torrent%lu:", (unsigned long)mi_size); + iobuf_write(&iob, mi, mi_size); + iobuf_swrite(&iob, "ee"); return ipc_buf_req_code(ipc, &iob); } static enum ipc_err simple_treq(struct ipc *ipc, char *cmd, struct ipc_torrent *tp) { - struct io_buffer iob = buf_init(32); + struct iobuf iob = iobuf_init(32); if (tp->by_hash) { - buf_print(&iob, "l%d:%s20:", (int)strlen(cmd), cmd); - buf_write(&iob, tp->u.hash, 20); - buf_swrite(&iob, "e"); + iobuf_print(&iob, "l%d:%s20:", (int)strlen(cmd), cmd); + iobuf_write(&iob, tp->u.hash, 20); + iobuf_swrite(&iob, "e"); } else - buf_print(&iob, "l%d:%si%uee", (int)strlen(cmd), cmd, tp->u.num); + iobuf_print(&iob, "l%d:%si%uee", (int)strlen(cmd), cmd, tp->u.num); return ipc_buf_req_code(ipc, &iob); } @@ -315,7 +315,7 @@ btpd_stop(struct ipc *ipc, struct ipc_torrent *tp) enum ipc_err btpd_stop_all(struct ipc *ipc) { - struct io_buffer iob = buf_init(16); - buf_swrite(&iob, "l8:stop-alle"); + struct iobuf iob = iobuf_init(16); + iobuf_swrite(&iob, "l8:stop-alle"); return ipc_buf_req_code(ipc, &iob); } diff --git a/misc/iobuf.c b/misc/iobuf.c index 45918ab..fa5e33f 100644 --- a/misc/iobuf.c +++ b/misc/iobuf.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -5,44 +6,66 @@ #include #include "iobuf.h" +#include "subr.h" -#define GROWLEN (1 << 14) - -struct io_buffer -buf_init(size_t size) +struct iobuf +iobuf_init(size_t size) { - struct io_buffer iob; + struct iobuf iob; + iob.size = size; iob.off = 0; - iob.len = size; + iob.skip = 0; iob.error = (iob.buf = malloc(size)) == NULL ? 1 : 0; return iob; } void -buf_free(struct io_buffer *iob) +iobuf_free(struct iobuf *iob) { if (iob->buf != NULL) - free(iob->buf); + free(iob->buf - iob->skip); + iob->buf = NULL; + iob->error = 1; +} + +void +iobuf_consumed(struct iobuf *iob, size_t count) +{ + if (iob->error) + return; + assert(count <= iob->off); + iob->skip += count; + iob->buf += count; + iob->off -= count; } int -buf_grow(struct io_buffer *iob, size_t addlen) +iobuf_accommodate(struct iobuf *iob, size_t count) { if (iob->error) - return iob->error; - char *nbuf = realloc(iob->buf, iob->len + addlen); - if (nbuf == NULL) { - iob->error = 1; return 0; + size_t esize = iob->size - (iob->skip + iob->off); + if (esize >= count) + return 1; + else if (esize + iob->skip >= count) { + bcopy(iob->buf, iob->buf - iob->skip, iob->off); + iob->buf -= iob->skip; + iob->skip = 0; + return 1; } else { - iob->buf = nbuf; - iob->len += addlen; + uint8_t *nbuf = realloc(iob->buf - iob->skip, iob->size + count); + if (nbuf == NULL) { + iob->error = 1; + return 0; + } + iob->buf = nbuf + iob->skip; + iob->size += count; return 1; } } int -buf_print(struct io_buffer *iob, const char *fmt, ...) +iobuf_print(struct iobuf *iob, const char *fmt, ...) { if (iob->error) return 0; @@ -51,9 +74,8 @@ buf_print(struct io_buffer *iob, const char *fmt, ...) va_start(ap, fmt); np = vsnprintf(NULL, 0, fmt, ap); va_end(ap); - if (np + 1 > iob->len - iob->off) - if (!buf_grow(iob, (1 + (np + 1) / GROWLEN) * GROWLEN)) - return 0; + if (!iobuf_accommodate(iob, np + 1)) + return 0; va_start(ap, fmt); vsnprintf(iob->buf + iob->off, np + 1, fmt, ap); va_end(ap); @@ -62,14 +84,19 @@ buf_print(struct io_buffer *iob, const char *fmt, ...) } int -buf_write(struct io_buffer *iob, const void *buf, size_t len) +iobuf_write(struct iobuf *iob, const void *buf, size_t count) { if (iob->error) return 0; - if (len > iob->len - iob->off) - if (!buf_grow(iob, (1 + len / GROWLEN) * GROWLEN)) - return 0; - bcopy(buf, iob->buf + iob->off, len); - iob->off += len; + if (!iobuf_accommodate(iob, count)) + return 0; + bcopy(buf, iob->buf + iob->off, count); + iob->off += count; return 1; } + +void * +iobuf_find(struct iobuf *iob, const void *p, size_t plen) +{ + return iob->error ? NULL : memfind(p, plen, iob->buf, iob->off); +} diff --git a/misc/iobuf.h b/misc/iobuf.h index ccd2028..fb14835 100644 --- a/misc/iobuf.h +++ b/misc/iobuf.h @@ -1,20 +1,23 @@ #ifndef BTPD_IOBUF_H #define BTPD_IOBUF_H -struct io_buffer { +struct iobuf { + uint8_t *buf; + size_t size; size_t off; - size_t len; - char *buf; + size_t skip; int error; }; -struct io_buffer buf_init(size_t size); -void buf_free(struct io_buffer *iob); -int buf_grow(struct io_buffer *iob, size_t size); -int buf_write(struct io_buffer *iob, const void *data, size_t size); +struct iobuf iobuf_init(size_t size); +void iobuf_free(struct iobuf *iob); +int iobuf_accommodate(struct iobuf *iob, size_t size); +int iobuf_write(struct iobuf *iob, const void *data, size_t size); __attribute__((format (printf, 2, 3))) -int buf_print(struct io_buffer *iob, const char *fmt, ...); +int iobuf_print(struct iobuf *iob, const char *fmt, ...); +void *iobuf_find(struct iobuf *iob, const void *p, size_t plen); +void iobuf_consumed(struct iobuf *iob, size_t count); -#define buf_swrite(iob, s) buf_write(iob, s, sizeof(s) - 1) +#define iobuf_swrite(iob, s) iobuf_write(iob, s, sizeof(s) - 1) #endif