From: Martin Mares Date: Wed, 19 Jul 2017 10:27:58 +0000 (+0200) Subject: Elementary client and passing of JSON back and forth X-Git-Tag: v0.9~49 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=413289ddd7cc9711a763eab811e807649a921a25;p=subauth.git Elementary client and passing of JSON back and forth --- diff --git a/Makefile b/Makefile index fedb3da..7ce559d 100644 --- a/Makefile +++ b/Makefile @@ -17,15 +17,15 @@ include $(BUILDSYS)/Maketop EXTRA_RUNDIRS=run # Add the detected flags to all the global flags -CFLAGS+=$(LIBUCW_CFLAGS) -LIBS+=$(LIBUCW_LIBS) +CFLAGS+=$(LIBUCW_CFLAGS) $(LIBUCW_JSON_CFLAGS) +LIBS+=$(LIBUCW_LIBS) $(LIBUCW_JSON_LIBS) # Programs we want to compile PROGS+=$(o)/subauthd $(o)/subauth # And how they are created -$(o)/subauthd: $(o)/subauthd.o $(LIBUCW) -$(o)/subauth: $(o)/subauth.o $(LIBUCW) +$(o)/subauthd: $(o)/subauthd.o +$(o)/subauth: $(o)/subauth.o # Configuration files CONFIGS+=subauthd diff --git a/configure b/configure index 3d741cd..a964476 100755 --- a/configure +++ b/configure @@ -38,7 +38,8 @@ require UCW::Configure::C; require UCW::Configure::Pkg; # Get some libraries -UCW::Configure::Pkg::PkgConfig("libucw") or Fail("libUCW is required"); +UCW::Configure::Pkg::PkgConfig("libucw") or Fail("libucw is required"); +UCW::Configure::Pkg::PkgConfig("libucw-json") or Fail("libucw-json is required"); Finish(); Log "\nConfigured, run `make' to build everything.\n"; diff --git a/subauth.c b/subauth.c index cb64f94..e597b76 100644 --- a/subauth.c +++ b/subauth.c @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -45,9 +46,35 @@ int main(int argc UNUSED, char **argv) if (connect(sk, (struct sockaddr *) &sun, sizeof(sun)) < 0) die("Cannot connect to %s: %m", socket_path); - char msg[] = "Brum!"; - if (send(sk, msg, sizeof(msg), 0) < 0) - die("Send failed: %m"); + struct fastbuf *out = bfdopen(1, 4096); + + struct json_context *js = json_new(); + struct json_node *rq = json_new_object(js); + + bprintf(out, ">>> Request:\n"); + json_write(js, out, rq); + bflush(out); + + struct fastbuf *rq_fb = fbgrow_create(4096); + json_write(js, rq_fb, rq); + byte *rq_buf; + uint rq_len = fbgrow_get_buf(rq_fb, &rq_buf); + if (send(sk, rq_buf, rq_len, 0) < 0) + die("Cannot send request: %m"); + bclose(rq_fb); + + byte rp_buf[4096]; // FIXME + int rp_len = recv(sk, rp_buf, sizeof(rp_buf), 0); + if (rp_len < 0) + die("Cannot receive reply: %m"); + + puts("Parsing reply"); + struct fastbuf rp_fb; + fbbuf_init_read(&rp_fb, rp_buf, rp_len, 0); + struct json_node *rp = json_parse(js, &rp_fb); + bprintf(out, "<<< Reply:\n"); + json_write(js, out, rp); + bflush(out); return 0; } diff --git a/subauthd.c b/subauthd.c index d8ee471..bc76ef5 100644 --- a/subauthd.c +++ b/subauthd.c @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include #include @@ -25,23 +27,38 @@ static struct main_file listen_socket; static uint num_connections; #define SOCKET_TIMEOUT 60000 // in ms -#define MAX_PACKET_SIZE 4096 +#define MAX_PACKET_SIZE 16384 #define MAX_OOB_DATA_SIZE 4096 struct client { struct main_file socket; struct main_timer timer; + int uid; + struct json_context *json; + struct json_node *request; + struct json_node *reply; }; static byte packet_buffer[MAX_PACKET_SIZE]; static byte oob_data_buffer[MAX_OOB_DATA_SIZE]; +static int socket_read_handler(struct main_file *fi); +static int socket_write_handler(struct main_file *fi); + static void client_close(struct client *c) { msg(L_INFO, "Closing connection"); file_del(&c->socket); timer_del(&c->timer); close(c->socket.fd); + json_delete(c->json); + xfree(c); + num_connections--; +} + +static void cmd_error(struct client *c, const char *err) +{ + json_object_set(c->reply, "error", json_new_string(c->json, err)); } static void socket_timeout_handler(struct main_timer *tm) @@ -53,6 +70,84 @@ static void socket_timeout_handler(struct main_timer *tm) client_close(c); } +static void try_send_reply(struct client *c) +{ + struct fastbuf fb; + fbbuf_init_write(&fb, packet_buffer, MAX_PACKET_SIZE); + + TRANS_TRY + { + json_write(c->json, &fb, c->reply); + } + TRANS_CATCH(x) + { + msg(L_ERROR, "Unable to construct reply, it is probably too long"); + fbbuf_init_write(&fb, packet_buffer, MAX_PACKET_SIZE); + bputs(&fb, "{ \"error\": \"Reply too long\" }\n"); + } + TRANS_END; + + int len = fbbuf_count_written(&fb); + msg(L_INFO, "Sending reply of %d bytes", len); + if (send(c->socket.fd, packet_buffer, len, 0) < 0) + { + if (errno == EAGAIN || errno == EINTR) + { + msg(L_INFO, "Postponed send"); + c->socket.write_handler = socket_write_handler; + file_chg(&c->socket); + } + msg(L_ERROR, "Client write error: %m"); + client_close(c); + } + else + { + msg(L_INFO, "Reply sent"); + c->socket.read_handler = socket_read_handler; + c->socket.write_handler = NULL; + file_chg(&c->socket); + timer_add_rel(&c->timer, SOCKET_TIMEOUT); + } +} + +static void send_reply(struct client *c) +{ + timer_add_rel(&c->timer, SOCKET_TIMEOUT); + try_send_reply(c); +} + +static void received_packet(struct client *c, byte *pkt, int len) +{ + json_reset(c->json); + + struct fastbuf fb; + fbbuf_init_read(&fb, pkt, len, 0); + + c->reply = json_new_object(c->json); + + TRANS_TRY + { + c->request = json_parse(c->json, &fb); + } + TRANS_CATCH(x) + { + cmd_error(c, "Parse error"); + send_reply(c); + return; + } + TRANS_END; + + cmd_error(c, "OK"); + send_reply(c); +} + +static int socket_write_handler(struct main_file *fi) +{ + struct client *c = fi->data; + try_send_reply(c); + return HOOK_IDLE; +} + static int socket_read_handler(struct main_file *fi) { struct client *c = fi->data; @@ -83,8 +178,6 @@ static int socket_read_handler(struct main_file *fi) return HOOK_IDLE; } - msg(L_INFO, "Got packet: len=%zd", len); - struct ucred *cred = NULL; for (struct cmsghdr *cm = CMSG_FIRSTHDR(&mh); cm; cm = CMSG_NXTHDR(&mh, cm)) { @@ -114,8 +207,13 @@ static int socket_read_handler(struct main_file *fi) return HOOK_RETRY; } - msg(L_INFO, "Credentials: pid=%d uid=%d gid=%d", (int) cred->pid, (int) cred->uid, (int) cred->gid); + msg(L_INFO, "Got message from UID %d", (int) cred->uid); + c->uid = cred->uid; + fi->read_handler = NULL; + file_chg(fi); + + received_packet(c, packet_buffer, len); return HOOK_RETRY; } @@ -146,6 +244,8 @@ static int listen_read_handler(struct main_file *fi) die("Cannot set O_NONBLOCK: %m"); struct client *c = xmalloc_zero(sizeof(*c)); + c->json = json_new(); + c->socket.fd = new_sk; c->socket.read_handler = socket_read_handler; c->socket.data = c;