]> mj.ucw.cz Git - subauth.git/commitdiff
Elementary client and passing of JSON back and forth
authorMartin Mares <mj@ucw.cz>
Wed, 19 Jul 2017 10:27:58 +0000 (12:27 +0200)
committerMartin Mares <mj@ucw.cz>
Wed, 19 Jul 2017 10:27:58 +0000 (12:27 +0200)
Makefile
configure
subauth.c
subauthd.c

index fedb3daeca032b76178c324143971ed54b1f5fa8..7ce559d24e36ffb424d680e01d857ff4ec7befa8 100644 (file)
--- 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
index 3d741cdbd04583d25dde67dc2ea220c9b1637fa4..a9644766cacf664f9da2fc33cc66bf80abf4b312 100755 (executable)
--- 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";
index cb64f94dd2c3b36875edac9bb91b72d6208f560c..e597b768efaa8aa54e67e6e87b8d5d61f42e8904 100644 (file)
--- a/subauth.c
+++ b/subauth.c
@@ -6,6 +6,7 @@
 
 #include <ucw/lib.h>
 #include <ucw/opt.h>
+#include <ucw-json/json.h>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -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;
 }
index d8ee471fb5c4d6a8a01376a20e398a375517d1df..bc76ef5bddbb39d9660e6b73d5c002d484751eaf 100644 (file)
@@ -9,6 +9,8 @@
 #include <ucw/log.h>
 #include <ucw/mainloop.h>
 #include <ucw/opt.h>
+#include <ucw/trans.h>
+#include <ucw-json/json.h>
 
 #include <errno.h>
 #include <fcntl.h>
@@ -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;