@@ -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); | |||
} | |||
@@ -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); | |||
@@ -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); | |||
@@ -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); | |||
} |
@@ -1,3 +1,4 @@ | |||
#include <assert.h> | |||
#include <inttypes.h> | |||
#include <stdarg.h> | |||
#include <stdio.h> | |||
@@ -5,44 +6,66 @@ | |||
#include <string.h> | |||
#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); | |||
} |
@@ -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 |