#include <ucw/lib.h>
#include <ucw/opt.h>
+#include <ucw-json/json.h>
#include <errno.h>
#include <fcntl.h>
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;
}
#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>
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)
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;
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))
{
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;
}
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;