aboutsummaryrefslogtreecommitdiff
path: root/src/lib/libkogata/gip.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libkogata/gip.c')
-rw-r--r--src/lib/libkogata/gip.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/lib/libkogata/gip.c b/src/lib/libkogata/gip.c
new file mode 100644
index 0000000..3b6084c
--- /dev/null
+++ b/src/lib/libkogata/gip.c
@@ -0,0 +1,207 @@
+#include <string.h>
+#include <malloc.h>
+
+#include <gip.h>
+
+typedef struct {
+ gip_reply_callback_t cb;
+ void* data;
+} gip_cmd_t;
+
+void giph_msg_header(mainloop_fd_t *fd);
+void giph_buffer_info(mainloop_fd_t *fd);
+void giph_mode_info(mainloop_fd_t *fd);
+void giph_buffer_damage(mainloop_fd_t *fd);
+
+void gip_error(mainloop_fd_t *fd);
+
+gip_handler_t *new_gip_handler(gip_handler_callbacks_t *cb, void* data) {
+ gip_handler_t *h = (gip_handler_t*)malloc(sizeof(gip_handler_t));
+ if (h == 0) return 0;
+
+ memset(h, 0, sizeof(gip_handler_t));
+
+ h->cb = cb;
+ h->data = data;
+
+ h->requests_in_progress = create_hashtbl(id_key_eq_fun, id_hash_fun, free_val);
+ if (h->requests_in_progress == 0) {
+ free(h);
+ return 0;
+ }
+
+ h->mainloop_item.data = h;
+ h->mainloop_item.on_error = &gip_error;
+ h->next_req_id = 1;
+
+ mainloop_expect(&h->mainloop_item, &h->msg_buf, sizeof(gip_msg_header), giph_msg_header);
+
+ return h;
+}
+
+void delete_gip_handler(gip_handler_t *h) {
+ delete_hashtbl(h->requests_in_progress);
+ free(h);
+}
+
+bool gip_send_msg(gip_handler_t *h, gip_msg_header *msg, void* msg_data) {
+ // ---- Write message
+ size_t extra_size = 0;
+ if (msg->code == GIPN_BUFFER_INFO) extra_size = sizeof(gip_buffer_info_msg);
+ if (msg->code == GIPR_MODE_INFO) extra_size = sizeof(gip_mode_info_msg);
+ if (msg->code == GIPN_BUFFER_DAMAGE) extra_size = sizeof(gip_buffer_damage_msg);
+
+ bool ok = false;
+
+ char* buf = (char*)malloc(sizeof(gip_msg_header) + extra_size);
+
+ if (buf != 0) {
+ memcpy(buf, msg, sizeof(gip_msg_header));
+ if (extra_size) memcpy(buf + sizeof(gip_msg_header), msg_data, extra_size);
+ ok = mainloop_nonblocking_write(&h->mainloop_item, buf, sizeof(gip_msg_header) + extra_size, true);
+ }
+
+ if (!ok) {
+ dbg_printf("GIP warning: failed to send message (type %d)\n", msg->code);
+ if (buf) free(buf);
+ }
+
+ return ok;
+}
+
+bool gip_cmd(gip_handler_t *h, gip_msg_header *msg, void* msg_data, gip_reply_callback_t cb, void* cb_data) {
+ msg->req_id = 0;
+
+ // ---- Add callback handler
+ if (cb != 0) {
+ gip_cmd_t *c = (gip_cmd_t*)malloc(sizeof(gip_cmd_t));
+ if (c == 0) return false;
+
+ c->cb = cb;
+ c->data = cb_data;
+
+ while(msg->req_id == 0) msg->req_id = (h->next_req_id++);
+
+ bool add_ok = hashtbl_add(h->requests_in_progress, (void*)msg->req_id, c);
+ if (!add_ok) {
+ free(c);
+ return false;
+ }
+ }
+
+ bool ok = gip_send_msg(h, msg, msg_data);
+ if (!ok && msg->req_id != 0) hashtbl_remove(h->requests_in_progress, (void*)msg->req_id);
+
+ return ok;
+}
+
+bool gip_reply(gip_handler_t *h, gip_msg_header *orig_request, gip_msg_header *msg, void* msg_data) {
+ msg->req_id = orig_request->req_id;
+ return gip_send_msg(h, msg, msg_data);
+}
+
+bool gip_reply_fail(gip_handler_t *h, gip_msg_header *o) {
+ gip_msg_header m = {
+ .code = GIPR_FAILURE,
+ .arg = 0,
+ };
+ return gip_reply(h, o, &m, 0);
+}
+
+bool gip_reply_ok(gip_handler_t *h, gip_msg_header *o) {
+ gip_msg_header m = {
+ .code = GIPR_OK,
+ .arg = 0,
+ };
+ return gip_reply(h, o, &m, 0);
+}
+
+bool gip_notify(gip_handler_t *h, gip_msg_header *msg, void* msg_data) {
+ msg->req_id = 0;
+ return gip_send_msg(h, msg, msg_data);
+}
+
+// ---- Message handlers
+
+void giph_got_reply(gip_handler_t *h, gip_msg_header *msg) {
+ gip_cmd_t *c = (gip_cmd_t*)hashtbl_find(h->requests_in_progress, (void*)msg->req_id);;
+ if (c != 0) {
+ c->cb(h, msg, c->data);
+ hashtbl_remove(h->requests_in_progress, (void*)msg->req_id);
+ }
+}
+
+void giph_msg_header(mainloop_fd_t *fd) {
+ gip_handler_t *h = (gip_handler_t*)fd->data;
+
+ int code = h->msg_buf.code;
+ noarg_gip_callback_t use_cb = 0;
+ if (code == GIPC_RESET) {
+ use_cb = h->cb->reset;
+ } else if (code == GIPR_INITIATE) {
+ use_cb = h->cb->initiate;
+ giph_got_reply(h, &h->msg_buf);
+ } else if (code == GIPR_OK) {
+ use_cb = h->cb->ok;
+ giph_got_reply(h, &h->msg_buf);
+ } else if (code == GIPR_FAILURE) {
+ use_cb = h->cb->failure;
+ giph_got_reply(h, &h->msg_buf);
+ } else if (code == GIPC_ENABLE_FEATURES) {
+ use_cb = h->cb->enable_features;
+ } else if (code == GIPC_DISABLE_FEATURES) {
+ use_cb = h->cb->disable_features;
+ } else if (code == GIPC_QUERY_MODE) {
+ use_cb = h->cb->query_mode;
+ } else if (code == GIPC_SET_MODE) {
+ use_cb = h->cb->set_mode;
+ } else if (code == GIPC_SWITCH_BUFFER) {
+ use_cb = h->cb->switch_buffer;
+ } else if (code == GIPN_BUFFER_INFO) {
+ mainloop_expect(fd, &h->buffer_info_msg_buf, sizeof(gip_buffer_info_msg), giph_buffer_info);
+ } else if (code == GIPR_MODE_INFO) {
+ mainloop_expect(fd, &h->mode_info_msg_buf, sizeof(gip_mode_info_msg), giph_mode_info);
+ // this is a reply but we cannot call giph_got_reply immediately since more data is needed
+ // giph_got_reply(h, id);
+ } else if (code == GIPN_BUFFER_DAMAGE) {
+ mainloop_expect(fd, &h->buffer_damage_msg_buf, sizeof(gip_buffer_damage_msg), giph_buffer_damage);
+ } else {
+ use_cb = h->cb->unknown_msg;
+ }
+
+ if (use_cb) use_cb(h, &h->msg_buf);
+}
+
+void giph_buffer_info(mainloop_fd_t *fd) {
+ gip_handler_t *h = (gip_handler_t*)fd->data;
+
+ if (h->cb->buffer_info) h->cb->buffer_info(h, &h->msg_buf, &h->buffer_info_msg_buf);
+
+ mainloop_expect(&h->mainloop_item, &h->msg_buf, sizeof(gip_msg_header), giph_msg_header);
+}
+
+void giph_mode_info(mainloop_fd_t *fd) {
+ gip_handler_t *h = (gip_handler_t*)fd->data;
+
+ if (h->cb->mode_info) h->cb->mode_info(h, &h->msg_buf, &h->mode_info_msg_buf);
+
+ // call giph_got_reply with more data ?
+
+ mainloop_expect(&h->mainloop_item, &h->msg_buf, sizeof(gip_msg_header), giph_msg_header);
+}
+
+void giph_buffer_damage(mainloop_fd_t *fd) {
+ gip_handler_t *h = (gip_handler_t*)fd->data;
+
+ if (h->cb->buffer_damage) h->cb->buffer_damage(h, &h->msg_buf, &h->buffer_damage_msg_buf);
+
+ mainloop_expect(&h->mainloop_item, &h->msg_buf, sizeof(gip_msg_header), giph_msg_header);
+}
+
+void gip_error(mainloop_fd_t *fd) {
+ gip_handler_t *h = (gip_handler_t*)fd->data;
+
+ if (h->cb->fd_error) h->cb->fd_error(h);
+}
+
+/* vim: set ts=4 sw=4 tw=0 noet :*/