summary refs log tree commit diff
path: root/cli/btpd_if.c
diff options
context:
space:
mode:
Diffstat (limited to 'cli/btpd_if.c')
-rw-r--r--cli/btpd_if.c221
1 files changed, 221 insertions, 0 deletions
diff --git a/cli/btpd_if.c b/cli/btpd_if.c
new file mode 100644
index 0000000..9990446
--- /dev/null
+++ b/cli/btpd_if.c
@@ -0,0 +1,221 @@
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "benc.h"
+#include "iobuf.h"
+#include "btpd_if.h"
+
+int
+ipc_open(const char *key, struct ipc **out)
+{
+    size_t plen;
+    size_t keylen;
+    struct ipc *res;
+
+    if (key == NULL)
+	key = "default";
+    keylen = strlen(key);
+    for (int i = 0; i < keylen; i++)
+	if (!isalnum(key[i]))
+	    return EINVAL;
+
+    res = malloc(sizeof(*res));
+    if (res == NULL)
+	return ENOMEM;
+
+    plen = sizeof(res->addr.sun_path);
+    if (snprintf(res->addr.sun_path, plen,
+		 "/tmp/btpd_%u_%s", geteuid(), key) >= plen) {
+	free(res);
+	return ENAMETOOLONG;
+    }
+    res->addr.sun_family = AF_UNIX;
+    *out = res;
+    return 0;
+}
+
+int
+ipc_close(struct ipc *ipc)
+{
+    free(ipc);
+    return 0;
+}
+
+static int
+ipc_connect(struct ipc *ipc, FILE **out)
+{
+    FILE *fp;
+    int sd;
+    int error;
+
+    if ((sd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
+	return errno;
+
+    if (connect(sd, (struct sockaddr *)&ipc->addr, sizeof(ipc->addr)) == -1)
+	goto error;
+
+    if ((fp = fdopen(sd, "r+")) == NULL)
+	goto error;
+
+    *out = fp;
+    return 0;
+error:
+    error = errno;
+    close(sd);
+    return error;
+}
+
+static int
+ipc_response(FILE *fp, char **out, uint32_t *len)
+{
+    uint32_t size;
+    char *buf;
+
+    if (fread(&size, sizeof(size), 1, fp) != 1) {
+	if (ferror(fp))
+	    return errno;
+	else
+	    return ECONNRESET;
+    }
+
+    if (size == 0)
+	return EINVAL;
+
+    if ((buf = malloc(size)) == NULL)
+	return ENOMEM;
+
+    if (fread(buf, 1, size, fp) != size) {
+	if (ferror(fp))
+	    return errno;
+	else
+	    return ECONNRESET;
+    }
+
+    *out = buf;
+    *len = size;
+    return 0;
+}
+
+static int
+ipc_req_res(struct ipc *ipc,
+	    const char *req, uint32_t qlen,
+	    char **res, uint32_t *rlen)
+{
+    FILE *fp;
+    int error;
+
+    if ((error = ipc_connect(ipc, &fp)) != 0)
+	return error;
+
+    if (fwrite(&qlen, sizeof(qlen), 1, fp) != 1)
+	goto error;
+    if (fwrite(req, 1, qlen, fp) != qlen)
+	goto error;
+    if (fflush(fp) != 0)
+	goto error;
+    if ((errno = ipc_response(fp, res, rlen)) != 0)
+	goto error;
+    if ((errno = benc_validate(*res, *rlen)) != 0)
+	goto error;
+
+    fclose(fp);
+    return 0;
+error:
+    error = errno;
+    fclose(fp);
+    return error;
+}
+
+int
+btpd_die(struct ipc *ipc)
+{
+    int error;
+    char *response = NULL;
+    const char shutdown[] = "l3:diee";
+    uint32_t size = sizeof(shutdown) - 1;
+    uint32_t rsiz;
+
+    if ((error = ipc_req_res(ipc, shutdown, size, &response, &rsiz)) != 0)
+	return error;
+
+    error = benc_validate(response, rsiz);
+
+    if (error == 0) {
+	int64_t tmp;
+        benc_dget_int64(response, "code", &tmp);
+	error = tmp;
+    }
+
+    free(response);
+    return error;
+}
+
+int
+btpd_add(struct ipc *ipc, char **paths, unsigned npaths, char **out)
+{
+    int error;
+    struct io_buffer iob;
+    char *res = NULL;
+    uint32_t reslen;
+
+    buf_init(&iob, 1024);
+    buf_print(&iob, "l3:add");
+    for (unsigned i = 0; i < npaths; i++) {
+        int plen = strlen(paths[i]);
+        buf_print(&iob, "%d:", plen);
+        buf_write(&iob, paths[i], plen);
+    }
+    buf_print(&iob, "e");
+    
+    error = ipc_req_res(ipc, iob.buf, iob.buf_off, &res, &reslen);
+    free(iob.buf);
+    if (error == 0)
+	*out = res;
+    
+    return error;
+}
+
+int
+btpd_stat(struct ipc *ipc, char **out)
+{
+    const char cmd[] = "l4:state";
+    uint32_t cmdlen = sizeof(cmd) - 1;
+    char *res;
+    uint32_t reslen;
+
+    if ((errno = ipc_req_res(ipc, cmd, cmdlen, &res, &reslen)) != 0)
+        return errno;
+    *out = res;
+    return 0;
+}
+
+int
+btpd_del(struct ipc *ipc, uint8_t (*hash)[20], unsigned nhashes, char **out)
+{
+    int error;
+    struct io_buffer iob;
+    char *res = NULL;
+    uint32_t reslen;
+
+    buf_init(&iob, 1024);
+    buf_write(&iob, "l3:del", 6);
+    for (unsigned i = 0; i < nhashes; i++) {
+        buf_write(&iob, "20:", 3);
+        buf_write(&iob, hash[i], 20);
+    }
+    buf_write(&iob, "e", 1);
+    
+    error = ipc_req_res(ipc, iob.buf, iob.buf_off, &res, &reslen);
+    free(iob.buf);
+    if (error != 0)
+	return error;
+
+    *out = res;
+    return 0;
+}