#include "mrklib_priv.h" struct _Mrk_Serve { const char *listen; int port; const char *repodir; const char *bldsh; Ecore_Ipc_Server *server; Eina_List *handlers; Eina_Inlist *clients; Mrk_Repodb *rdb; }; typedef struct { EINA_INLIST; Mrk_Serve *server; Ecore_Ipc_Client *client; const char *uuid; const char *arch; const char *version; const char *file; const char *dir; FILE *f; Ecore_Exe *exe; } Client; static void client_upload_cancel(Client *c) { if (c->f) fclose(c->f); if (c->file) eina_stringshare_del(c->file); if (c->dir) { ecore_file_recursive_rm(c->dir); eina_stringshare_del(c->dir); } c->f = NULL; c->file = NULL; c->dir = NULL; } static void client_upload_new(Client *c, const char *file) { char tmp[PATH_MAX]; Eina_Tmpstr *s = NULL; if (c->f) client_upload_cancel(c); c->file = eina_stringshare_add(file); if (!c->file) return; if (eina_file_mkdtemp("marrekesh-up-XXXXXX", &s)) { c->dir = eina_stringshare_add(s); eina_tmpstr_del(s); if (c->dir) { snprintf(tmp, sizeof(tmp), "%s/%s", c->dir, c->file); c->f = fopen(tmp, "wb"); } } } static void client_upload_data(Client *c, void *data, int size) { if (c->f) fwrite(data, size, 1, c->f); } static void client_upload_end(Client *c) { char tmp[PATH_MAX]; if (c->f) { fclose(c->f); c->f = NULL; snprintf(tmp, sizeof(tmp), "%s %s %s", c->server->bldsh, c->dir, c->server->repodir); c->exe = ecore_exe_pipe_run(tmp, ECORE_EXE_TERM_WITH_PARENT | ECORE_EXE_NOT_LEADER, c); if (c->exe) ecore_exe_tag_set(c->exe, "-=# mrk serve - build exe #=-"); } } static void client_send(Client *c, const char *subrepo, const char *name, int op_start, int op_data, int op_end) { char tmp[PATH_MAX]; char *lnk; snprintf(tmp, sizeof(tmp), "%s/%s/%s", c->server->repodir, subrepo, name); lnk = ecore_file_readlink(tmp); if (!lnk) ecore_ipc_client_send(c->client, M_OP, op_start, 0, 0, 0, NULL, 0); else { FILE *f = fopen(tmp, "rb"); if (!f) ecore_ipc_client_send(c->client, M_OP, op_start, 0, 0, 0, NULL, 0); else { long sz, pos; fseek(f, 0, SEEK_END); sz = ftell(f); fseek(f, 0, SEEK_SET); ecore_ipc_client_send(c->client, M_OP, op_start, (int)sz, 0, 0, lnk, strlen(lnk)); for (pos = 0; pos < sz;) { size_t size; char buf[10000]; size = fread(buf, 1, 10000, f); if (size <= 0) break; pos += size; ecore_ipc_client_send(c->client, M_OP, op_data, (int)pos, (int)sz, 0, buf, size); } ecore_ipc_client_send(c->client, M_OP, op_end, 0, 0, 0, NULL, 0); fclose(f); } free(lnk); } } static Eina_Bool _mrk_id_data(Mrk_Serve *server EINA_UNUSED, Client *c, Ecore_Ipc_Event_Client_Data *e) { if (e->minor == M_ID_UUID) { char *str = _mrk_util_proto_cli_string(e); if (str) { eina_stringshare_replace(&(c->uuid), str); free(str); } return EINA_TRUE; } else if (e->minor == M_ID_VERSION) { char *str = _mrk_util_proto_cli_string(e); if (str) { eina_stringshare_replace(&(c->version), str); free(str); } return EINA_TRUE; } else if (e->minor == M_ID_ARCH) { char *str = _mrk_util_proto_cli_string(e); if (str) { if (_mrk_util_arch_ok(str)) eina_stringshare_replace(&(c->arch), str); free(str); } return EINA_TRUE; } return EINA_FALSE; } static Eina_Bool _mrk_upload_data(Mrk_Serve *server EINA_UNUSED, Client *c, Ecore_Ipc_Event_Client_Data *e) { if ((!c->uuid) || (!c->version) || (!c->arch)) return EINA_FALSE; if (e->minor == M_UP_START) { char *str = _mrk_util_proto_cli_string(e); if (str) { if (_mrk_util_plain_file_check(str)) client_upload_new(c, str); free(str); } return EINA_TRUE; } else if (e->minor == M_UP_DATA) { if ((e->data) && (e->size <= 10000)) client_upload_data(c, e->data, e->size); return EINA_TRUE; } else if (e->minor == M_UP_END) { client_upload_end(c); return EINA_TRUE; } return EINA_FALSE; } static Eina_Bool _mrk_query_data(Mrk_Serve *server EINA_UNUSED, Client *c, Ecore_Ipc_Event_Client_Data *e) { if ((!c->uuid) || (!c->version) || (!c->arch)) return EINA_FALSE; if (e->minor == M_QRY_LIST) { const Eina_List *list = NULL, *l; ecore_ipc_client_send(c->client, M_OP, M_ANS_START, 0, 0, 0, NULL, 0); if (!e->data) list = mrk_repodb_category_list(c->server->rdb, c->arch, NULL); else { char *str = _mrk_util_proto_cli_string(e); if (str) { list = mrk_repodb_category_list(c->server->rdb, c->arch, str); free(str); } } if (list) { const char *s; EINA_LIST_FOREACH(list, l, s) { ecore_ipc_client_send(c->client, M_OP, M_ANS_DATA, 0, 0, 0, s, strlen(s)); } } ecore_ipc_client_send(c->client, M_OP, M_ANS_END, 0, 0, 0, NULL, 0); return EINA_TRUE; } else if (e->minor == M_QRY_SEARCH) { ecore_ipc_client_send(c->client, M_OP, M_ANS_START, 0, 0, 0, NULL, 0); if (e->data) { char *str = _mrk_util_proto_cli_string(e); if (str) { Eina_List *list; const char *s; list = mrk_repodb_search(c->server->rdb, c->arch, str); EINA_LIST_FREE(list, s) { ecore_ipc_client_send(c->client, M_OP, M_ANS_DATA, 0, 0, 0, s, strlen(s)); eina_stringshare_del(s); } free(str); } } ecore_ipc_client_send(c->client, M_OP, M_ANS_END, 0, 0, 0, NULL, 0); return EINA_TRUE; } else if (e->minor == M_QRY_GET) { char *str = _mrk_util_proto_cli_string(e); if (str) { if (_mrk_util_plain_file_check(str)) client_send(c, c->arch, str, M_DOWN_START, M_DOWN_DATA, M_DOWN_END); free(str); } return EINA_TRUE; } else if (e->minor == M_QRY_GETSRC) { char *str = _mrk_util_proto_cli_string(e); if (str) { if (_mrk_util_plain_file_check(str)) client_send(c, "src", str, M_SRC_START, M_SRC_DATA, M_SRC_END); free(str); } return EINA_TRUE; } return EINA_FALSE; } static Eina_Bool _mrk_inf_data(Mrk_Serve *server EINA_UNUSED, Client *c, Ecore_Ipc_Event_Client_Data *e) { if ((!c->uuid) || (!c->version) || (!c->arch)) return EINA_FALSE; if (e->minor == M_INF_GET_IC) { char *str = _mrk_util_proto_cli_string(e); if (str) { if (_mrk_util_plain_file_check(str)) { char *str2 = malloc(strlen(str) + 1 + 8); if (str2) { strcpy(str2, str); strcat(str2, ".icn.png"); client_send(c, "src", str2, M_INF_START, M_INF_DATA, M_INF_END); free(str2); } } free(str); } return EINA_TRUE; } return EINA_FALSE; } static Eina_Bool _mrk_data_handle(Mrk_Serve *server, Client *c, Ecore_Ipc_Event_Client_Data *e) { if ((e->minor > M_UP_B) && (e->minor < M_UP_E)) return _mrk_upload_data(server, c, e); else if ((e->minor > M_QRY_B) && (e->minor < M_QRY_E)) return _mrk_query_data(server, c, e); else if ((e->minor > M_ID_B) && (e->minor < M_ID_E)) return _mrk_id_data(server, c, e); else if ((e->minor > M_INF_B) && (e->minor < M_INF_E)) return _mrk_inf_data(server, c, e); return EINA_FALSE; } static Eina_Bool _mrk_cb_add(void *data, int type EINA_UNUSED, void *event) { Ecore_Ipc_Event_Client_Add *e = event; Mrk_Serve *server = data; Client *c; if (server->server != ecore_ipc_client_server_get(e->client)) return EINA_TRUE; c = calloc(1, sizeof(Client)); c->server = server; c->client = e->client; ecore_ipc_client_data_set(e->client, c); server->clients = eina_inlist_append(server->clients, EINA_INLIST_GET(c)); return EINA_FALSE; } static Eina_Bool _mrk_cb_del(void *data, int type EINA_UNUSED, void *event) { Ecore_Ipc_Event_Client_Del *e = event; Mrk_Serve *server = data; Client *c; if (server->server != ecore_ipc_client_server_get(e->client)) return EINA_TRUE; c = ecore_ipc_client_data_get(e->client); if (c) { client_upload_cancel(c); eina_stringshare_del(c->uuid); eina_stringshare_del(c->arch); eina_stringshare_del(c->version); if (c->exe) ecore_exe_free(c->exe); server->clients = eina_inlist_remove(server->clients, EINA_INLIST_GET(c)); free(c); } return EINA_FALSE; } static Eina_Bool _mrk_cb_data(void *data, int type EINA_UNUSED, void *event) { Ecore_Ipc_Event_Client_Data *e = event; Mrk_Serve *server = data; Client *c; if (server->server != ecore_ipc_client_server_get(e->client)) return EINA_TRUE; c = ecore_ipc_client_data_get(e->client); if (!c) return EINA_TRUE; if (e->major != M_OP) return EINA_TRUE; if (!_mrk_data_handle(server, c, e)) return EINA_TRUE; return EINA_FALSE; } static Eina_Bool _mrk_cb_exe_del(void *data, int type EINA_UNUSED, void *event) { Ecore_Exe_Event_Del *e = event; Mrk_Serve *server = data; Client *c; const char *tag; if (!e->exe) return EINA_TRUE; tag = ecore_exe_tag_get(e->exe); if (!tag) return EINA_TRUE; if (!strcmp(tag, "-=# mrk serve - build exe #=-")) { c = ecore_exe_data_get(e->exe); if (!c) return EINA_TRUE; if (c->exe != e->exe) return EINA_TRUE; c->exe = NULL; if (e->exit_code == 0) { ecore_ipc_client_send(c->client, M_OP, M_UP_OK, 0, 0, 0, NULL, 0); mrk_repodb_update(server->rdb); } else ecore_ipc_client_send(c->client, M_OP, M_UP_FAIL, 0, 0, 0, NULL, 0); return EINA_FALSE; } return EINA_TRUE; } EAPI Mrk_Serve * mrk_serve(const char *listen, int port, const char *repodir, const char *bldsh) { Mrk_Serve *server; server = calloc(1, sizeof(Mrk_Serve)); if (!server) return server; if (!listen) listen = "0.0.0.0"; if (port <= 0) port = MRK_SERVER_PORT; server->listen = eina_stringshare_add(listen); server->port = port; server->repodir = eina_stringshare_add(repodir); server->bldsh = eina_stringshare_add(bldsh); server->handlers = eina_list_append(server->handlers, ecore_event_handler_add (ECORE_IPC_EVENT_CLIENT_ADD, _mrk_cb_add, server)); server->handlers = eina_list_append(server->handlers, ecore_event_handler_add (ECORE_IPC_EVENT_CLIENT_DEL, _mrk_cb_del, server)); server->handlers = eina_list_append(server->handlers, ecore_event_handler_add (ECORE_IPC_EVENT_CLIENT_DATA, _mrk_cb_data, server)); server->handlers = eina_list_append(server->handlers, ecore_event_handler_add (ECORE_EXE_EVENT_DEL, _mrk_cb_exe_del, server)); server->server = ecore_ipc_server_add(ECORE_IPC_REMOTE_SYSTEM, server->listen, server->port, server); server->rdb = mrk_repodb_load(repodir); return server; } EAPI void mrk_unserve(Mrk_Serve *server) { Ecore_Event_Handler *hnd; mrk_repodb_free(server->rdb); ecore_ipc_server_del(server->server); EINA_LIST_FREE(server->handlers, hnd) ecore_event_handler_del(hnd); eina_stringshare_del(server->listen); eina_stringshare_del(server->repodir); eina_stringshare_del(server->bldsh); if (!server) return; free(server); }