summaryrefslogtreecommitdiff
path: root/src/bin/efl
diff options
context:
space:
mode:
authorDaniel Zaoui <daniel.zaoui@yahoo.com>2016-11-27 07:48:10 +0200
committerDaniel Zaoui <daniel.zaoui@yahoo.com>2017-06-05 08:51:49 +0300
commit5f268ec26a76b130a78ab182981dde372951f075 (patch)
tree4aa3adb9ffa7fddcb2d87b5d16798381456a595f /src/bin/efl
parente53b77d6ce9848bdb274b428c33e6848c8620443 (diff)
downloadefl-5f268ec26a76b130a78ab182981dde372951f075.tar.gz
First patch of the Eina Debug layer rewriting
Eina Debug is a new layer aimed for EFL debugging. It offers scalability by allowing registration of operations not specific to EFL core. The protocol is simple and the APIs try to provide as much functionalities/freedom as possible.
Diffstat (limited to 'src/bin/efl')
-rw-r--r--src/bin/efl/efl_debug.c397
-rw-r--r--src/bin/efl/efl_debug_common.c87
-rw-r--r--src/bin/efl/efl_debug_common.h55
-rw-r--r--src/bin/efl/efl_debugd.c811
4 files changed, 645 insertions, 705 deletions
diff --git a/src/bin/efl/efl_debug.c b/src/bin/efl/efl_debug.c
index 28cdb39d24..7876a08c18 100644
--- a/src/bin/efl/efl_debug.c
+++ b/src/bin/efl/efl_debug.c
@@ -16,269 +16,250 @@
* if not, see <http://www.gnu.org/licenses/>.
*/
-#define DECLARE_OPS
-#include "efl_debug_common.h"
+#include <Eina.h>
+#include <Ecore.h>
-static Eo *dialer;
+# ifdef HAVE_CONFIG_H
+# include "config.h"
+# endif
-static Eina_List *waiting;
+#define EXTRACT(_buf, pval, sz) \
+{ \
+ memcpy(pval, _buf, sz); \
+ _buf += sz; \
+}
+#define _EVLOG_INTERVAL 0.2
-static int retval = EXIT_SUCCESS;
+static int _evlog_max_times = 0;
+static Ecore_Timer *_evlog_fetch_timer = NULL;
+static FILE *_evlog_file = NULL;
-static void
-_process_reply(void *data EINA_UNUSED, const char op[static 4], const Eina_Slice payload)
-{
- if (IS_OP(CLST))
- {
- int mypid = getpid();
- size_t offset;
+static int _cl_stat_reg_opcode = EINA_DEBUG_OPCODE_INVALID;
+static int _cid_from_pid_opcode = EINA_DEBUG_OPCODE_INVALID;
+static int _prof_on_opcode = EINA_DEBUG_OPCODE_INVALID;
+static int _prof_off_opcode = EINA_DEBUG_OPCODE_INVALID;
+static int _cpufreq_on_opcode = EINA_DEBUG_OPCODE_INVALID;
+static int _cpufreq_off_opcode = EINA_DEBUG_OPCODE_INVALID;
+static int _evlog_get_opcode = EINA_DEBUG_OPCODE_INVALID;
- waiting = eina_list_remove(waiting, OP_CLST);
+static Eina_Debug_Session *_session = NULL;
- for (offset = 0; offset + sizeof(int) <= payload.len; offset += sizeof(int))
- {
- int p;
+static int _cid = 0;
- memcpy(&p, payload.bytes + offset, sizeof(int));
+static int my_argc = 0;
+static char **my_argv = NULL;
- if (p == mypid) continue;
- if (p > 0) printf("%i\n", p);
+static Eina_Debug_Error
+_evlog_get_cb(Eina_Debug_Session *session EINA_UNUSED, int src EINA_UNUSED, void *buffer, int size)
+{
+ static int received_times = 0;
+ unsigned char *d = buffer;
+ unsigned int *overflow = (unsigned int *)(d + 0);
+ unsigned char *p = d + 4;
+ unsigned int blocksize = size - 4;
+
+ if(++received_times <= _evlog_max_times)
+ {
+ if ((_evlog_file) && (blocksize > 0))
+ {
+ unsigned int header[3];
+
+ header[0] = 0xffee211;
+ header[1] = blocksize;
+ header[2] = *overflow;
+ if (fwrite(header, 1, 12, _evlog_file) < 12 ||
+ fwrite(p, 1, blocksize, _evlog_file) < blocksize)
+ printf("Error writing bytes to evlog file\n");
}
}
- else
+
+ if(received_times == _evlog_max_times)
{
- fprintf(stderr, "ERROR: unexpected server reply: %.4s\n", op);
- retval = EXIT_FAILURE;
+ printf("Received last evlog response\n");
+ if (_evlog_file) fclose(_evlog_file);
+ _evlog_file = NULL;
+ ecore_main_loop_quit();
}
- if (!waiting) ecore_main_loop_quit();
+ return EINA_DEBUG_OK;
}
-static void
-_on_data(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
+static Eina_Bool
+_cb_evlog(void *data EINA_UNUSED)
{
- if (!received_data(dialer, _process_reply, NULL))
+ static int sent_times = 0;
+ Eina_Bool ret = ECORE_CALLBACK_RENEW;
+ if(++sent_times <= _evlog_max_times)
+ eina_debug_session_send(_session, _cid, _evlog_get_opcode, NULL, 0);
+
+ if(sent_times == _evlog_max_times)
{
- retval = EXIT_FAILURE;
- ecore_main_loop_quit();
+ eina_debug_session_send(_session, _cid, _cpufreq_off_opcode, NULL, 0);
+ ecore_timer_del(_evlog_fetch_timer);
+ _evlog_fetch_timer = NULL;
+ ret = ECORE_CALLBACK_CANCEL;
}
+
+ return ret;
}
-static Eina_Bool
-_command_send(const char op[static 4], const void *data, unsigned int len)
+static Eina_Debug_Error
+_cid_get_cb(Eina_Debug_Session *session EINA_UNUSED, int cid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
{
- if (!send_data(dialer, op, data, len))
+ _cid = *(int *)buffer;
+
+ const char *op_str = my_argv[1];
+ Eina_Bool quit = EINA_TRUE;
+
+ if ((!strcmp(op_str, "pon")) && (3 <= (my_argc - 1)))
+ {
+ int freq = atoi(my_argv[3]);
+ eina_debug_session_send(_session, _cid, _prof_on_opcode, &freq, sizeof(int));
+ }
+ else if (!strcmp(op_str, "poff"))
+ eina_debug_session_send(_session, _cid, _prof_off_opcode, NULL, 0);
+ else if (!strcmp(op_str, "evlogon") && (3 <= (my_argc - 1)))
{
- retval = EXIT_FAILURE;
- return EINA_FALSE;
+ double max_time;
+ sscanf(my_argv[3], "%lf", &max_time);
+ _evlog_max_times = max_time > 0 ? (max_time/_EVLOG_INTERVAL+1) : 1;
+ eina_debug_session_send(_session, 0, _cl_stat_reg_opcode, NULL, 0);
+ printf("Evlog request will be sent %d times\n", _evlog_max_times);
+ eina_debug_session_send(_session, _cid, _cpufreq_on_opcode, NULL, 0);
+
+ /* Creating the evlog file and setting the timer */
+ char path[4096];
+ int pid = atoi(my_argv[2]);
+ snprintf(path, sizeof(path), "%s/efl_debug_evlog-%ld.log",
+ getenv("HOME"), (long)pid);
+ _evlog_file = fopen(path, "wb");
+ _evlog_fetch_timer = ecore_timer_add(_EVLOG_INTERVAL, _cb_evlog, NULL);
+
+ quit = EINA_FALSE;
}
+ else if (!strcmp(op_str, "evlogoff"))
+ eina_debug_session_send(_session, _cid, _cpufreq_off_opcode, NULL, 0);
- return EINA_TRUE;
-}
+ if(quit)
+ ecore_main_loop_quit();
-#define command_send(op, data, len) _command_send(OP_ ## op, data, len)
+ return EINA_DEBUG_OK;
+}
-static void
-_write_finished(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
+static Eina_Debug_Error
+_clients_info_added_cb(Eina_Debug_Session *session EINA_UNUSED, int src EINA_UNUSED, void *buffer, int size)
{
- if (!waiting) ecore_main_loop_quit();
+ char *buf = buffer;
+ while(size)
+ {
+ int cid, pid, len;
+ EXTRACT(buf, &cid, sizeof(int));
+ EXTRACT(buf, &pid, sizeof(int));
+ /* We dont need client notifications on evlog */
+ if(!_evlog_fetch_timer)
+ printf("Added: CID: %d - PID: %d - Name: %s\n", cid, pid, buf);
+ len = strlen(buf) + 1;
+ buf += len;
+ size -= (2 * sizeof(int) + len);
+ }
+ return EINA_DEBUG_OK;
}
-static void
-_finished(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
+static Eina_Debug_Error
+_clients_info_deleted_cb(Eina_Debug_Session *session EINA_UNUSED, int src EINA_UNUSED, void *buffer, int size)
{
- ecore_main_loop_quit();
+ char *buf = buffer;
+ while(size)
+ {
+ int cid;
+ EXTRACT(buf, &cid, sizeof(int));
+ size -= sizeof(int);
+
+ /* If client deleted dont send anymore evlog requests */
+ if(_evlog_fetch_timer)
+ {
+ if(_cid == cid)
+ {
+ printf("Evlog debugged App closed (CID: %d), stopping evlog\n", cid);
+ ecore_timer_del(_evlog_fetch_timer);
+ _evlog_fetch_timer = NULL;
+ fclose(_evlog_file);
+ _evlog_file = NULL;
+ ecore_main_loop_quit();
+ }
+ }
+ else
+ printf("Deleted: CID: %d\n", cid);
+ }
+ return EINA_DEBUG_OK;
}
static void
-_error(void *data EINA_UNUSED, const Efl_Event *event)
+_ecore_thread_dispatcher(void *data)
{
- Eina_Error *perr = event->info;
+ eina_debug_dispatch(_session, data);
+}
- fprintf(stderr, "ERROR: error communicating to %s: %s\n",
- efl_net_dialer_address_dial_get(dialer),
- eina_error_msg_get(*perr));
- retval = EXIT_FAILURE;
- ecore_main_loop_quit();
+Eina_Debug_Error
+_disp_cb(Eina_Debug_Session *session EINA_UNUSED, void *buffer)
+{
+ ecore_main_loop_thread_safe_call_async(_ecore_thread_dispatcher, buffer);
+ return EINA_DEBUG_OK;
}
-int
-main(int argc, char **argv)
+static void
+_args_handle(Eina_Bool flag)
{
- Eo *loop;
- char *path;
- Eina_Error err;
- int i;
+ if (!flag) exit(0);
+ eina_debug_session_dispatch_override(_session, _disp_cb);;
- if (argc < 2)
+ const char *op_str = my_argv[1];
+ if (op_str && !strcmp(op_str, "list"))
{
- fprintf(stderr, "ERROR: missing argument.\n");
- return EXIT_FAILURE;
+ eina_debug_session_send(_session, 0, _cl_stat_reg_opcode, NULL, 0);
}
- for (i = 1; i < argc; i++)
+ else if (2 <= my_argc - 1)
{
- if ((strcmp(argv[i], "-h") != 0) &&
- (strcmp(argv[i], "--help") != 0))
- continue;
-
- printf("Usage:\n"
- "\n"
- "\t%s <command> [arguments]\n"
- "\n"
- "where <command> is one of:\n"
- "\tlist list connected process (pid)\n"
- "\tpon <pid> <freq> enable profiling for <pid> at frequency <freq> in microseconds.\n"
- "\tpoff <pid> disable profiling for <pid>\n"
- "\tevlogon <pid> start logging events to ~/efl_debug_evlog-<pid>.log\n"
- "\tevlogoff <pid> stop logging events from <pid>\n",
- argv[0]);
-
- return EXIT_SUCCESS;
+ int pid = atoi(my_argv[2]);
+ eina_debug_session_send(_session, 0, _cid_from_pid_opcode, &pid, sizeof(int));
}
+}
- ecore_app_no_system_modules();
+static const Eina_Debug_Opcode ops[] =
+{
+ {"daemon/observer/client/register", &_cl_stat_reg_opcode, NULL},
+ {"daemon/observer/slave_added", NULL, &_clients_info_added_cb},
+ {"daemon/observer/slave_deleted", NULL, &_clients_info_deleted_cb},
+ {"daemon/info/cid_from_pid", &_cid_from_pid_opcode, &_cid_get_cb},
+ {"profiler/on", &_prof_on_opcode, NULL},
+ {"profiler/off", &_prof_off_opcode, NULL},
+ {"cpufreq/on", &_cpufreq_on_opcode, NULL},
+ {"cpufreq/off", &_cpufreq_off_opcode, NULL},
+ {"evlog/get", &_evlog_get_opcode, _evlog_get_cb},
+ {NULL, NULL, NULL}
+};
+int
+main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
+{
eina_init();
ecore_init();
- ecore_con_init();
-
- path = ecore_con_local_path_new(EINA_FALSE, "efl_debug", 0);
- if (!path)
- {
- fprintf(stderr, "ERROR: could not get local communication path\n");
- retval = EXIT_FAILURE;
- goto end;
- }
- loop = ecore_main_loop_get();
-
-#ifdef EFL_NET_DIALER_UNIX_CLASS
- dialer = efl_add(EFL_NET_DIALER_SIMPLE_CLASS, loop,
- efl_net_dialer_simple_inner_class_set(efl_added, EFL_NET_DIALER_UNIX_CLASS));
-#elif defined(EFL_NET_DIALER_WINDOWS_CLASS)
- dialer = efl_add(EFL_NET_DIALER_SIMPLE_CLASS, loop,
- efl_net_dialer_simple_inner_class_set(efl_added, EFL_NET_DIALER_WINDOWS_CLASS));
-#else
- /* TODO: maybe start a TCP using locahost:12345?
- * Right now eina_debug_monitor is only for AF_UNIX, so not an issue.
- */
- fprintf(stderr, "ERROR: your platform doesn't support Efl.Net.Dialer.*\n");
-#endif
- if (!dialer)
- {
- fprintf(stderr, "ERROR: could not create communication dialer\n");
- retval = EXIT_FAILURE;
- goto end;
- }
- efl_event_callback_add(dialer, EFL_IO_BUFFERED_STREAM_EVENT_ERROR, _error, NULL);
- efl_event_callback_add(dialer, EFL_IO_BUFFERED_STREAM_EVENT_SLICE_CHANGED, _on_data, NULL);
- efl_event_callback_add(dialer, EFL_IO_BUFFERED_STREAM_EVENT_WRITE_FINISHED, _write_finished, NULL);
- efl_event_callback_add(dialer, EFL_IO_BUFFERED_STREAM_EVENT_FINISHED, _finished, NULL);
-
- for (i = 1; i < argc; i++)
- {
- const char *cmd = argv[i];
-
- if (strcmp(cmd, "list") == 0)
- {
- if (!command_send(LIST, NULL, 0))
- goto end;
- waiting = eina_list_append(waiting, OP_CLST);
- }
- else if (strcmp(cmd, "pon") == 0)
- {
- if (i + 2 >= argc)
- {
- fprintf(stderr, "ERROR: missing argument: pon <pid> <freq>\n");
- retval = EXIT_FAILURE;
- goto end;
- }
- else
- {
- int data[2] = {atoi(argv[i + 1]), atoi(argv[1 + 2])};
- if (!command_send(PLON, data, sizeof(data)))
- goto end;
- i += 2;
- }
- }
- else if (strcmp(cmd, "poff") == 0)
- {
- if (i + 1 >= argc)
- {
- fprintf(stderr, "ERROR: missing argument: poff <pid>\n");
- retval = EXIT_FAILURE;
- goto end;
- }
- else
- {
- int data[1] = {atoi(argv[i + 1])};
- if (!command_send(PLOF, data, sizeof(data)))
- goto end;
- i++;
- }
- }
- else if (strcmp(cmd, "evlogon") == 0)
- {
- if (i + 1 >= argc)
- {
- fprintf(stderr, "ERROR: missing argument: evlogon <pid>\n");
- retval = EXIT_FAILURE;
- goto end;
- }
- else
- {
- int data[1] = {atoi(argv[i + 1])};
- if (!command_send(EVON, data, sizeof(data)))
- goto end;
- i++;
- }
- }
- else if (strcmp(cmd, "evlogoff") == 0)
- {
- if (i + 1 >= argc)
- {
- fprintf(stderr, "ERROR: missing argument: evlogoff <pid>\n");
- retval = EXIT_FAILURE;
- goto end;
- }
- else
- {
- int data[1] = {atoi(argv[i + 1])};
- if (!command_send(EVOF, data, sizeof(data)))
- goto end;
- i++;
- }
- }
- else
- {
- fprintf(stderr, "ERROR: unknown command: %s\n", argv[i]);
- retval = EXIT_FAILURE;
- goto end;
- }
- }
- efl_io_buffered_stream_eos_mark(dialer);
+ my_argc = argc;
+ my_argv = argv;
- err = efl_net_dialer_dial(dialer, path);
- if (err)
+ _session = eina_debug_local_connect(EINA_TRUE);
+ if (!_session)
{
- fprintf(stderr, "ERROR: could not connect '%s': %s\n", path, eina_error_msg_get(err));
- retval = EXIT_FAILURE;
- goto end;
+ fprintf(stderr, "ERROR: Cannot connect to debug daemon.\n");
+ return -1;
}
+ eina_debug_opcodes_register(_session, ops, _args_handle);
ecore_main_loop_begin();
- end:
- eina_list_free(waiting);
- efl_del(dialer);
- free(path);
-
- ecore_con_shutdown();
ecore_shutdown();
eina_shutdown();
- (void) OP_HELO;
- (void) OP_EVLG;
-
- return retval;
+ return 0;
}
diff --git a/src/bin/efl/efl_debug_common.c b/src/bin/efl/efl_debug_common.c
deleted file mode 100644
index f37f17f16b..0000000000
--- a/src/bin/efl/efl_debug_common.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/* EINA - EFL data type library
- * Copyright (C) 2015 Carsten Haitzler
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library;
- * if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "efl_debug_common.h"
-
-Eina_Bool
-received_data(Eo *sock, void (*handle)(void *data, const char op[static 4], const Eina_Slice payload), const void *data)
-{
- Eina_Slice slice, payload;
- Efl_Debug_Message_Header msgheader;
-
- slice = efl_io_buffered_stream_slice_get(sock);
- if (slice.len < sizeof(msgheader))
- return EINA_TRUE;
-
- memcpy(&msgheader, slice.mem, sizeof(msgheader));
- if (msgheader.size < 4) /* must contain at last 4 byte opcode */
- {
- fprintf(stderr, "ERROR: invalid message header, size=%u\n", msgheader.size);
- return EINA_FALSE;
- }
-
- if (msgheader.size + 4 > slice.len)
- return EINA_TRUE;
-
- payload.bytes = slice.bytes + sizeof(msgheader);
- payload.len = msgheader.size - 4;
-
- handle((void *)data, msgheader.op, payload);
-
- efl_io_buffered_stream_discard(sock, sizeof(msgheader) + payload.len);
- return EINA_TRUE;
-}
-
-Eina_Bool
-send_data(Eo *sock, const char op[static 4], const void *data, unsigned int len)
-{
- Eina_Error err;
- Efl_Debug_Message_Header msghdr = {
- .size = 4 + len,
- };
- Eina_Slice s, r;
-
- memcpy(msghdr.op, op, 4);
-
- s.mem = &msghdr;
- s.len = sizeof(msghdr);
-
- err = efl_io_writer_write(sock, &s, &r);
- if (err || r.len) goto end;
-
- if (!len) goto end;
-
- s.mem = data;
- s.len = len;
- err = efl_io_writer_write(sock, &s, &r);
-
- end:
- if (err)
- {
- fprintf(stderr, "ERROR: could not queue message '%.4s': %s\n", op, eina_error_msg_get(err));
- return EINA_FALSE;
- }
-
- if (r.len)
- {
- fprintf(stderr, "ERROR: could not queue message '%.4s': out of memory\n", op);
- return EINA_FALSE;
- }
-
- return EINA_TRUE;
-}
diff --git a/src/bin/efl/efl_debug_common.h b/src/bin/efl/efl_debug_common.h
deleted file mode 100644
index 6a0ba0b416..0000000000
--- a/src/bin/efl/efl_debug_common.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/* EINA - EFL data type library
- * Copyright (C) 2015 Carsten Haitzler
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library;
- * if not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef EFL_DEBUG_COMMON_H
-#define EFL_DEBUG_COMMON_H 1
-
-#define EFL_BETA_API_SUPPORT 1
-#define EFL_EO_API_SUPPORT 1
-
-#include <Eina.h>
-#include <Ecore.h>
-#include <Ecore_Con.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-
-typedef struct _Efl_Debug_Message_Header {
- unsigned int size;
- char op[4];
-} Efl_Debug_Message_Header;
-
-#define IS_OP(x) memcmp(op, OP_ ## x, 4) == 0
-
-#define DECLARE_OP(x) static char OP_ ## x[4] = #x
-#ifdef DECLARE_OPS
-DECLARE_OP(LIST);
-DECLARE_OP(CLST);
-DECLARE_OP(PLON);
-DECLARE_OP(PLOF);
-DECLARE_OP(EVON);
-DECLARE_OP(EVOF);
-DECLARE_OP(EVLG);
-DECLARE_OP(HELO);
-#endif
-
-Eina_Bool send_data(Eo *sock, const char op[static 4], const void *data, unsigned int len);
-Eina_Bool received_data(Eo *sock, void (*handle)(void *data, const char op[static 4], const Eina_Slice payload), const void *data);
-
-#endif
diff --git a/src/bin/efl/efl_debugd.c b/src/bin/efl/efl_debugd.c
index dfe175ce51..9da2648723 100644
--- a/src/bin/efl/efl_debugd.c
+++ b/src/bin/efl/efl_debugd.c
@@ -16,470 +16,571 @@
* if not, see <http://www.gnu.org/licenses/>.
*/
-#define DECLARE_OPS
-#include "efl_debug_common.h"
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <fcntl.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+
+#define STORE(_buf, pval, sz) \
+{ \
+ memcpy(_buf, pval, sz); \
+ _buf += sz; \
+}
+
+#define EXTRACT(_buf, pval, sz) \
+{ \
+ memcpy(pval, _buf, sz); \
+ _buf += sz; \
+}
typedef struct _Client Client;
struct _Client
{
- Eo *client;
-
- unsigned char *buf;
- unsigned int buf_size;
+ Eina_Stringshare *app_name;
Ecore_Timer *evlog_fetch_timer;
int evlog_on;
FILE *evlog_file;
int version;
+ int fd;
+ int cid;
pid_t pid;
+
+ Eina_Bool cl_stat_obs : 1;
+ Eina_Bool is_master : 1;
};
-static Eo *server;
+static Eina_List *_clients = NULL;
-static Eina_List *clients = NULL;
+typedef Eina_Bool (*Opcode_Cb)(Client *client, void *buffer, int size);
-static int retval;
+static Eina_Hash *_string_to_opcode_hash = NULL;
-static int _log_dom = -1;
+static int _free_cid = 1;
-#ifdef ERR
-# undef ERR
-#endif
-#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
+static int _clients_stat_register_opcode = EINA_DEBUG_OPCODE_INVALID;
+static int _slave_added_opcode = EINA_DEBUG_OPCODE_INVALID;
+static int _slave_deleted_opcode = EINA_DEBUG_OPCODE_INVALID;
+static int _cid_from_pid_opcode = EINA_DEBUG_OPCODE_INVALID;
+static int _test_loop_opcode = EINA_DEBUG_OPCODE_INVALID;
-#ifdef DBG
-# undef DBG
-#endif
-#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
-
-#ifdef INF
-# undef INF
-#endif
-#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
+typedef struct
+{
+ int opcode;
+ Eina_Stringshare *opcode_string;
+ Opcode_Cb cb;
+} Opcode_Information;
-#ifdef WRN
-# undef WRN
-#endif
-#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
+#define MAX_OPCODES 1000
+Opcode_Information *_opcodes[MAX_OPCODES];
-#ifdef CRI
-# undef CRI
+/* epoll stuff */
+#ifndef _WIN32
+static int _epfd = -1, _listening_master_fd = -1, _listening_slave_fd = -1;
#endif
-#define CRI(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__)
-
-
-#define send_cli(cl, op, data, len) \
- do \
- { \
- if (!send_data(cl->client, OP_ ## op, data, len)) \
- { \
- if (!efl_io_closer_closed_get(cl->client)) \
- efl_io_closer_close(cl->client); \
- } \
- } \
- while (0)
static Client *
-_client_pid_find(int pid)
+_client_find_by_cid(int cid)
{
Client *c;
Eina_List *l;
+ EINA_LIST_FOREACH(_clients, l, c)
+ if (c->cid == cid) return c;
+ return NULL;
+}
- if (pid <= 0) return NULL;
- EINA_LIST_FOREACH(clients, l, c)
- {
- if (c->pid == pid) return c;
- }
+static Client *
+_client_find_by_pid(int pid)
+{
+ Client *c;
+ Eina_List *l;
+ EINA_LIST_FOREACH(_clients, l, c)
+ if (c->pid == pid) return c;
+ return NULL;
+}
- WRN("no client pid=%d", pid);
+static Client *
+_client_find_by_fd(int fd)
+{
+ Eina_List *itr;
+ Client *c;
+ EINA_LIST_FOREACH(_clients, itr, c)
+ if (c->fd == fd) return c;
return NULL;
}
-static Eina_Bool
-_cb_evlog(void *data)
+static int
+_send(Client *dest, int opcode, void *payload, int payload_size)
{
- Client *c = data;
- send_cli(c, EVLG, NULL, 0);
- return EINA_TRUE;
+ int size = sizeof(Eina_Debug_Packet_Header) + payload_size;
+ char *buf = alloca(size);
+ Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)buf;
+ hdr->size = size;
+ hdr->cid = 0;
+ hdr->thread_id = 0;
+ hdr->opcode = opcode;
+ memcpy(buf + sizeof(Eina_Debug_Packet_Header), payload, payload_size);
+ //printf("%d bytes sent (opcode %s) to %s fd %d\n", size, _opcodes[opcode]->opcode_string, dest->app_name, dest->fd);
+ return send(dest->fd, buf, size, 0);
}
static void
-_process_command(void *data, const char op[static 4], const Eina_Slice payload)
+_client_del(Client *c)
{
- Client *c = data;
Client *c2;
- Eina_List *l;
-
- DBG("client %p (%p) [pid:%d] op=%.4s payload=%zd", c, c->client, c->pid, op, payload.len);
+ if (!c) return;
+ Eina_List *itr;
- if (IS_OP(HELO))
+ _clients = eina_list_remove(_clients, c);
+ if (c->evlog_fetch_timer)
{
- if (payload.len < sizeof(int) * 2)
- {
- fprintf(stderr, "INFO: client %p [pid: %d] sent invalid HELO\n", c, (int)c->pid);
- if (!efl_io_closer_closed_get(c->client))
- efl_io_closer_close(c->client);
- }
- else
- {
- memcpy(&c->version, payload.bytes, sizeof(int));
- memcpy(&c->pid, payload.bytes + sizeof(int), sizeof(int));
- INF("client %p (%p) HELO version=%d, pid=%d", c, c->client, c->version, c->pid);
- }
+ ecore_timer_del(c->evlog_fetch_timer);
+ c->evlog_fetch_timer = NULL;
}
- else if (IS_OP(LIST))
+ if (c->evlog_file)
{
- int n = eina_list_count(clients);
- unsigned int *pids = malloc(n * sizeof(int));
- if (pids)
- {
- int i = 0;
-
- EINA_LIST_FOREACH(clients, l, c2)
- {
- if (c2->pid == 0) continue; /* no HELO yet */
- pids[i] = c2->pid;
- i++;
- }
- send_cli(c, CLST, pids, i * sizeof(int));
- free(pids);
- }
+ fclose(c->evlog_file);
+ c->evlog_file = NULL;
}
- else if (IS_OP(PLON))
+
+ /* Don't update the observers if the client is a master */
+ if (c->is_master) return;
+
+ EINA_LIST_FOREACH(_clients, itr, c2)
{
- if (payload.len < sizeof(int) * 2)
- fprintf(stderr, "INFO: client %p [pid: %d] sent invalid PLON\n", c, (int)c->pid);
- else
- {
- int pid;
- unsigned int freq;
- memcpy(&pid, payload.bytes, sizeof(int));
- memcpy(&freq, payload.bytes + sizeof(int), sizeof(int));
- c2 = _client_pid_find(pid);
- if (!c2)
- {
- fprintf(stderr, "INFO: client %p [pid: %d] sent PLON %d: no such client\n", c, (int)c->pid, pid);
- }
- else
- {
- DBG("client %p (%p) [pid:%d] requested PLON on %p (%p) [pid:%d]",
- c, c->client, c->pid,
- c2, c2->client, c2->pid);
- send_cli(c2, PLON, &freq, sizeof(freq));
- }
- }
+ if (c2->cl_stat_obs) _send(c2, _slave_deleted_opcode, &c->cid, sizeof(int));
}
- else if (IS_OP(PLOF))
+ free(c);
+}
+
+static Eina_Bool
+_dispatch(Client *src, void *buffer, int size)
+{
+ Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)buffer;
+ if (hdr->cid)
{
- if (payload.len < sizeof(int))
- fprintf(stderr, "INFO: client %p [pid: %d] sent invalid PLOF\n", c, (int)c->pid);
- else
+ /* If the client id is given, we forward */
+ Client *dest = _client_find_by_cid(hdr->cid);
+ if (dest)
{
- int pid;
- memcpy(&pid, payload.bytes, sizeof(int));
- c2 = _client_pid_find(pid);
- if (!c2)
+ if (dest->is_master != src->is_master)
{
- fprintf(stderr, "INFO: client %p [pid: %d] sent PLOF %d: no such client\n", c, (int)c->pid, pid);
+ hdr->cid = src->cid;
+ send(dest->fd, buffer, size, 0);
}
else
{
- DBG("client %p (%p) [pid:%d] requested PLOF on %p (%p) [pid:%d]",
- c, c->client, c->pid,
- c2, c2->client, c2->pid);
- send_cli(c2, PLOF, NULL, 0);
+ /*
+ * Packets Master -> Master or Slave -> Slave are forbidden
+ * Only Master <-> Slave packets are allowed.
+ */
+ printf("Packet from %d to %d: denied (same type)\n", hdr->cid, dest->cid);
}
}
}
- else if (IS_OP(EVON))
+ else
{
- if (payload.len < sizeof(int))
- fprintf(stderr, "INFO: client %p [pid: %d] sent invalid EVON\n", c, (int)c->pid);
- else
- {
- int pid;
- memcpy(&pid, payload.bytes, sizeof(int));
- c2 = _client_pid_find(pid);
- if (!c2)
- {
- fprintf(stderr, "INFO: client %p [pid: %d] sent EVON %d: no such client\n", c, (int)c->pid, pid);
- }
- else
- {
- c2->evlog_on++;
- DBG("client %p (%p) [pid:%d] requested EVON (%d) on %p (%p) [pid:%d]",
- c, c->client, c->pid,
- c2->evlog_on,
- c2, c2->client, c2->pid);
- if (c2->evlog_on == 1)
- {
- char buf[4096];
-
- send_cli(c2, EVON, NULL, 0);
- c2->evlog_fetch_timer = ecore_timer_add(0.2, _cb_evlog, c2);
- snprintf(buf, sizeof(buf), "%s/efl_debug_evlog-%d.log",
- getenv("HOME"), c2->pid);
- c2->evlog_file = fopen(buf, "wb");
- DBG("client %p (%p) [pid:%d] logging to %s [%p]",
- c2, c2->client, c2->pid, buf, c2->evlog_file);
- }
- }
- }
+ printf("Invoke %s\n", _opcodes[hdr->opcode]->opcode_string);
+ if (_opcodes[hdr->opcode]->cb)
+ return _opcodes[hdr->opcode]->cb(src,
+ (char *)buffer + sizeof(Eina_Debug_Packet_Header), size - sizeof(Eina_Debug_Packet_Header));
}
- else if (IS_OP(EVOF))
+ return EINA_TRUE;
+}
+
+static int
+_opcode_register(const char *op_name, int op_id, Opcode_Cb cb)
+{
+ static int free_opcode = 0;
+ Opcode_Information *op_info = eina_hash_find(_string_to_opcode_hash, op_name);
+ if (!op_info)
{
- if (payload.len < sizeof(int))
- fprintf(stderr, "INFO: client %p [pid: %d] sent invalid EVOF\n", c, (int)c->pid);
- else
+ op_info = calloc(1, sizeof(*op_info));
+ if (op_id == EINA_DEBUG_OPCODE_INVALID)
{
- int pid;
- memcpy(&pid, payload.bytes, sizeof(int));
- c2 = _client_pid_find(pid);
- if (!c2)
+ do
{
- fprintf(stderr, "INFO: client %p [pid: %d] sent EVOF %d: no such client\n", c, (int)c->pid, pid);
- }
- else
- {
- c2->evlog_on--;
- DBG("client %p (%p) [pid:%d] requested EVOF (%d) on %p (%p) [pid:%d]",
- c, c->client, c->pid,
- c2->evlog_on,
- c2, c2->client, c2->pid);
- if (c2->evlog_on == 0)
- {
- send_cli(c2, EVOF, NULL, 0);
- if (c2->evlog_fetch_timer)
- {
- ecore_timer_del(c2->evlog_fetch_timer);
- c2->evlog_fetch_timer = NULL;
- }
- if (c2->evlog_file)
- {
- DBG("client %p (%p) [pid:%d] finished logged to %p",
- c2, c2->client, c2->pid, c2->evlog_file);
- fclose(c2->evlog_file);
- c2->evlog_file = NULL;
- }
- }
- else if (c2->evlog_on < 0)
- c2->evlog_on = 0;
+ free_opcode = (free_opcode + 1) % MAX_OPCODES;
+ op_id = free_opcode;
}
+ while(_opcodes[op_id]);
}
+ op_info->opcode = op_id;
+ op_info->opcode_string = eina_stringshare_add(op_name);
+ op_info->cb = cb;
+ eina_hash_add(_string_to_opcode_hash, op_name, op_info);
+ _opcodes[op_id] = op_info;
}
- else if (IS_OP(EVLG))
- {
- if (payload.len < sizeof(int))
- fprintf(stderr, "INFO: client %p [pid: %d] sent invalid EVLG\n", c, (int)c->pid);
- else if (!c->evlog_file)
- fprintf(stderr, "INFO: client %p [pid: %d] no matching EVON\n", c, (int)c->pid);
- else
- {
- unsigned int blocksize = payload.len - sizeof(int);
- if (blocksize > 0)
- {
- unsigned int header[3];
+ printf("Register %s -> opcode %d\n", op_name, op_info->opcode);
+ return op_info->opcode;
+}
- header[0] = 0xffee211;
- header[1] = blocksize;
- memcpy(header + 2, payload.mem, sizeof(int));
+static Eina_Bool
+_hello_cb(Client *c, void *buffer, int size)
+{
+ Eina_List *itr;
+ char *buf = (char *)buffer, *tmp;
- if ((fwrite(header, 12, 1, c->evlog_file) != 1) ||
- (fwrite(payload.bytes + sizeof(int), blocksize, 1, c->evlog_file) != 1))
- {
- fprintf(stderr, "INFO: failed to write log file for client %p [pid: %d]\n", c, (int)c->pid);
- fclose(c->evlog_file);
- c->evlog_file = NULL;
- c->evlog_on = 0;
+ EXTRACT(buf, &c->version, 4);
+ EXTRACT(buf, &c->pid, 4);
+ size -= 8;
- send_cli(c, EVOF, NULL, 0);
- if (c->evlog_fetch_timer)
- {
- ecore_timer_del(c->evlog_fetch_timer);
- c->evlog_fetch_timer = NULL;
- }
- }
- }
- }
+ c->cid = _free_cid++;
+ if (size > 1)
+ {
+ c->app_name = eina_stringshare_add_length(buf, size);
}
-}
-
-static void
-_client_data(void *data, const Efl_Event *event)
-{
- Client *c = data;
- if (!received_data(event->object, _process_command, c))
+ printf("Connection from %s: pid %d - name %s\n",
+ c->is_master ? "Master" : "Slave",
+ c->pid, c->app_name);
+
+ if (c->is_master) return EINA_TRUE;
+
+ /* Update the observers */
+ size = 2 * sizeof(int) + (c->app_name ? strlen(c->app_name) : 0) + 1; /* cid + pid + name + \0 */
+ buf = alloca(size);
+ tmp = buf;
+ STORE(tmp, &c->cid, sizeof(int));
+ STORE(tmp, &c->pid, sizeof(int));
+ if (c->app_name)
+ {
+ STORE(tmp, c->app_name, strlen(c->app_name) + 1);
+ }
+ else
+ {
+ char end = '\0';
+ STORE(tmp, &end, 1);
+ }
+ EINA_LIST_FOREACH(_clients, itr, c)
{
- fprintf(stderr, "INFO: client %p [pid: %d] sent invalid data\n", c, (int)c->pid);
- if (!efl_io_closer_closed_get(event->object))
- efl_io_closer_close(event->object);
- return;
+ if (c->cl_stat_obs) _send(c, _slave_added_opcode, buf, size);
}
+ return EINA_TRUE;
}
-static void
-_client_error(void *data, const Efl_Event *event)
+static Eina_Bool
+_cid_get_cb(Client *src, void *buffer, int size EINA_UNUSED)
{
- Client *c = data;
- Eina_Error *perr = event->info;
- WRN("client %p [pid: %d] error: %s",
- c, (int)c->pid, eina_error_msg_get(*perr));
- fprintf(stderr, "INFO: client %p [pid: %d] error: %s\n",
- c, (int)c->pid, eina_error_msg_get(*perr));
+ int pid = *(int *)buffer;
+ Client *c = _client_find_by_pid(pid);
+ int cid = c ? c->cid : 0;
+ _send(src, _cid_from_pid_opcode, &cid, sizeof(int));
+ return EINA_TRUE;
}
-static void
-_client_eos(void *data, const Efl_Event *event EINA_UNUSED)
+static Eina_Bool
+_data_test_cb(Client *src, void *buffer, int size)
{
- Client *c = data;
- DBG("client %p (%p) [pid: %d] closed, pending read %zu, write %zu",
- c, c->client, (int)c->pid,
- efl_io_buffered_stream_pending_read_get(c->client),
- efl_io_buffered_stream_pending_write_get(c->client));
- efl_io_closer_close(c->client);
+ printf("Data test: loop packet of %d bytes\n", size);
+ _send(src, _test_loop_opcode, buffer, size);
+ return EINA_TRUE;
}
-static void
-_client_write_finished(void *data, const Efl_Event *event EINA_UNUSED)
+static Eina_Bool
+_cl_stat_obs_register_cb(Client *src, void *buffer, int size)
{
- Client *c = data;
- DBG("client %p (%p) [pid: %d] finished writing, pending read %zu",
- c, c->client, (int)c->pid, efl_io_buffered_stream_pending_read_get(c->client));
+ Client *c;
+ if (!src) return EINA_FALSE;
+ if (!src->is_master) return EINA_FALSE;
+ if (!src->cl_stat_obs)
+ {
+ Eina_List *itr;
+ src->cl_stat_obs = EINA_TRUE;
+ size = 0;
+ EINA_LIST_FOREACH(_clients, itr, c)
+ {
+ char *tmp;
+ if (c->is_master) continue;
+ size = 2 * sizeof(int) + (c->app_name ? strlen(c->app_name) : 0) + 1;
+ buffer = alloca(size);
+ tmp = buffer;
+ STORE(tmp, &c->cid, sizeof(int));
+ STORE(tmp, &c->pid, sizeof(int));
+ if (c->app_name)
+ {
+ STORE(tmp, c->app_name, strlen(c->app_name) + 1);
+ }
+ else
+ {
+ char end = '\0';
+ STORE(tmp, &end, 1);
+ }
+ _send(src, _slave_added_opcode, buffer, size);
+ }
+ }
+ return EINA_TRUE;
}
-static void
-_client_read_finished(void *data, const Efl_Event *event EINA_UNUSED)
+static Eina_Bool
+_opcode_register_cb(Client *src, void *buffer, int size)
{
- Client *c = data;
- DBG("client %p (%p) [pid: %d] finished reading, pending write %zu",
- c, c->client, (int)c->pid, efl_io_buffered_stream_pending_write_get(c->client));
-}
+ char *buf = (char *)buffer;
+ char *ops_buf = buf;
+ int ops_size = size;
-static Efl_Callback_Array_Item *_client_cbs(void);
+ ops_buf += sizeof(uint64_t);
+ ops_size -= sizeof(uint64_t);
+ int *opcodes = (int *)ops_buf;
-static void
-_client_finished(void *data, const Efl_Event *event EINA_UNUSED)
-{
- Client *c = data;
-
- clients = eina_list_remove(clients, c);
- if (c->evlog_fetch_timer)
+ while (ops_size > 0)
{
- ecore_timer_del(c->evlog_fetch_timer);
- c->evlog_fetch_timer = NULL;
+ int len = strlen(ops_buf) + 1;
+ *opcodes++ = _opcode_register(ops_buf, EINA_DEBUG_OPCODE_INVALID, NULL);
+ ops_buf += len;
+ ops_size -= len;
}
- if (c->evlog_file)
- {
- fclose(c->evlog_file);
- c->evlog_file = NULL;
- }
- efl_event_callback_array_del(c->client, _client_cbs(), c);
- INF("finished client %p (%p) [pid:%d]", c, c->client, c->pid);
- efl_unref(c->client);
- free(c);
-}
-
-EFL_CALLBACKS_ARRAY_DEFINE(_client_cbs,
- { EFL_IO_READER_EVENT_EOS, _client_eos },
- { EFL_IO_BUFFERED_STREAM_EVENT_ERROR, _client_error },
- { EFL_IO_BUFFERED_STREAM_EVENT_READ_FINISHED, _client_read_finished },
- { EFL_IO_BUFFERED_STREAM_EVENT_WRITE_FINISHED, _client_write_finished },
- { EFL_IO_BUFFERED_STREAM_EVENT_FINISHED, _client_finished },
- { EFL_IO_BUFFERED_STREAM_EVENT_SLICE_CHANGED, _client_data });
-static void
-_client_add(void *data EINA_UNUSED, const Efl_Event *event)
-{
- Client *c = calloc(1, sizeof(Client));
+ _send(src, EINA_DEBUG_OPCODE_REGISTER, buf, (char *)opcodes - (char *)buf);
- EINA_SAFETY_ON_NULL_RETURN(c);
- c->client = efl_ref(event->info);
- clients = eina_list_append(clients, c);
- efl_event_callback_array_add(c->client, _client_cbs(), c);
- INF("server %p new client %p (%p)", event->object, c, c->client);
+ return EINA_TRUE;
}
-static void
-_error(void *data EINA_UNUSED, const Efl_Event *event)
+static int
+_data_receive(Client *c, unsigned char **buffer)
{
- Eina_Error *perr = event->info;
- ERR("server %p error: %s", event->object, eina_error_msg_get(*perr));
- fprintf(stderr, "ERROR: %s\n", eina_error_msg_get(*perr));
- ecore_main_loop_quit();
- retval = EXIT_FAILURE;
-}
+ unsigned char *recv_buf = NULL;
+ int rret;
+ int size = 0;
-int
-main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
-{
- Eo *loop;
- char *path;
- Eina_Error err;
+ if (!c) return -1;
- ecore_app_no_system_modules();
+ rret = recv(c->fd, &size, sizeof(int), MSG_PEEK);
- eina_init();
- ecore_init();
- ecore_con_init();
+ if (rret == sizeof(int))
+ {
+ int cur_packet_size = 0;
+ // allocate a buffer for the next bytes to receive
+ recv_buf = malloc(size);
+ if (!recv_buf) goto error;
+ while (cur_packet_size < size)
+ {
+ rret = recv(c->fd, recv_buf + cur_packet_size, size - cur_packet_size, 0);
+ if (rret <= 0) goto error;
+ cur_packet_size += rret;
+ }
+ }
+ if (buffer) *buffer = recv_buf;
+ //printf("%d bytes received from client %s fd %d\n", size, c->app_name, c->fd);
+ return size;
+error:
+ if (rret == -1) perror("Read from socket");
+ if (recv_buf) free(recv_buf);
+ return -1;
+}
- _log_dom = eina_log_domain_register("efl_debugd", EINA_COLOR_CYAN);
+static void
+_monitor()
+{
+#ifndef _WIN32
+#define MAX_EVENTS 1000
+ int ret = 0;
+ struct epoll_event events[MAX_EVENTS];
+ Client *c;
- path = ecore_con_local_path_new(EINA_FALSE, "efl_debug", 0);
- if (!path)
+ // sit forever processing commands or timeouts
+ for (; ret != -1;)
{
- fprintf(stderr, "ERROR: could not get local communication path\n");
- retval = EXIT_FAILURE;
- goto end;
- }
+ ret = epoll_wait (_epfd, events, MAX_EVENTS, -1);
- loop = ecore_main_loop_get();
+ // if the fd for debug daemon says it's alive, process it
+ if (ret > 0)
+ {
+ int i;
+ //check which fd are set/ready for read
+ for (i = 0; i < ret; i++)
+ {
+ if (events[i].events & EPOLLHUP)
+ {
+ c = _client_find_by_fd(events[i].data.fd);
+ close(events[i].data.fd);
+ if (c) _client_del(c);
+ }
+ if (events[i].events & EPOLLIN)
+ {
+ // Someone wants to connect
+ if(events[i].data.fd == _listening_master_fd || events[i].data.fd == _listening_slave_fd)
+ {
+ int new_fd = accept(events[i].data.fd, NULL, NULL);
+ if (new_fd < 0) perror("Accept");
+ else
+ {
+ struct epoll_event event;
+ c = calloc(1, sizeof(*c));
+ c->fd = new_fd;
+ c->is_master = (events[i].data.fd == _listening_master_fd);
+ _clients = eina_list_append(_clients, c);
+ event.data.fd = new_fd;
+ event.events = EPOLLIN;
+ epoll_ctl (_epfd, EPOLL_CTL_ADD, new_fd, &event);
+ }
+ continue;
+ }
-#ifdef EFL_NET_SERVER_UNIX_CLASS
- server = efl_add(EFL_NET_SERVER_SIMPLE_CLASS, loop,
- efl_net_server_simple_inner_class_set(efl_added, EFL_NET_SERVER_UNIX_CLASS));
-#else
- /* TODO: maybe start a TCP using locahost:12345?
- * Right now eina_debug_monitor is only for AF_UNIX, so not an issue.
- */
- fprintf(stderr, "ERROR: your platform doesn't support Efl.Net.Server.Unix\n");
+ c = _client_find_by_fd(events[i].data.fd);
+ if (c)
+ {
+ int size;
+ unsigned char *buffer;
+ size = _data_receive(c, &buffer);
+ // if not negative - we have a real message
+ if (size > 0)
+ {
+ if(!_dispatch(c, buffer, size))
+ {
+ // something we don't understand
+ fprintf(stderr, "Dispatch: unknown command");
+ }
+ free(buffer);
+ }
+ else
+ {
+ // major failure on debug daemon control fd - get out of here.
+ // else goto fail;
+ close(events[i].data.fd);
+ //TODO if its not main session we will tell the main_loop
+ //that it disconneted
+ }
+ }
+ }
+ }
+ }
+#if 0
+ else
+ {
+ if (poll_time && poll_timer_cb)
+ {
+ if (!poll_timer_cb()) poll_time = 0;
+ }
+ }
#endif
- if (!server)
- {
- fprintf(stderr, "ERROR: could not create communication server\n");
- retval = EXIT_FAILURE;
- goto end;
}
+#endif
+}
- efl_event_callback_add(server, EFL_NET_SERVER_EVENT_CLIENT_ADD, _client_add, NULL);
- efl_event_callback_add(server, EFL_NET_SERVER_EVENT_ERROR, _error, NULL);
+static const char *
+_socket_home_get()
+{
+ // get possible debug daemon socket directory base
+ const char *dir = getenv("XDG_RUNTIME_DIR");
+ if (!dir) dir = eina_environment_home_get();
+ if (!dir) dir = eina_environment_tmp_get();
+ return dir;
+}
-#ifdef EFL_NET_SERVER_UNIX_CLASS
- {
- Eo *inner_server = efl_net_server_simple_inner_server_get(server);
- efl_net_server_unix_unlink_before_bind_set(inner_server, EINA_TRUE);
- efl_net_server_unix_leading_directories_create_set(inner_server, EINA_TRUE, 0700);
- }
+#ifndef _WIN32
+#define LENGTH_OF_SOCKADDR_UN(s) \
+ (strlen((s)->sun_path) + (size_t)(((struct sockaddr_un *)NULL)->sun_path))
+static int
+_local_listening_socket_create(const char *path)
+{
+ struct sockaddr_un socket_unix;
+ int socket_unix_len, curstate = 0;
+ // create the socket
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) goto err;
+ // set the socket to close when we exec things so they don't inherit it
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) goto err;
+ // set up some socket options on addr re-use
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate,
+ sizeof(curstate)) < 0)
+ goto err;
+ // sa that it's a unix socket and where the path is
+ socket_unix.sun_family = AF_UNIX;
+ strncpy(socket_unix.sun_path, path, sizeof(socket_unix.sun_path) - 1);
+ socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
+ unlink(socket_unix.sun_path);
+ if (bind(fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
+ {
+ perror("ERROR on binding");
+ goto err;
+ }
+ listen(fd, 5);
+ return fd;
+err:
+ if (fd >= 0) close(fd);
+ return -1;
+}
#endif
- err = efl_net_server_serve(server, path);
- if (err)
+static Eina_Bool
+_server_launch()
+{
+#ifndef _WIN32
+ char buf[4096];
+ struct epoll_event event = {0};
+ mode_t mask = 0;
+ const char *socket_home_path = _socket_home_get();
+ char *socket_path = NULL;
+ if (!socket_home_path) return EINA_FALSE;
+ _epfd = epoll_create (MAX_EVENTS);
+ socket_path = strdup(socket_home_path);
+
+ snprintf(buf, sizeof(buf), "%s/%s", socket_path, SERVER_PATH);
+ if (mkdir(buf, S_IRWXU) < 0 && errno != EEXIST)
+ {
+ perror("mkdir SERVER_PATH");
+ goto err;
+ }
+ snprintf(buf, sizeof(buf), "%s/%s/%s", socket_path, SERVER_PATH, SERVER_NAME);
+ if (mkdir(buf, S_IRWXU) < 0 && errno != EEXIST)
{
- fprintf(stderr, "ERROR: could not serve '%s': %s\n", path, eina_error_msg_get(err));
- retval = EXIT_FAILURE;
- goto end;
+ perror("mkdir SERVER_NAME");
+ goto err;
}
+ mask = umask(S_IRWXG | S_IRWXO);
+ snprintf(buf, sizeof(buf), "%s/%s/%s/%i", socket_path, SERVER_PATH, SERVER_NAME, SERVER_MASTER_PORT);
+ _listening_master_fd = _local_listening_socket_create(buf);
+ if (_listening_master_fd <= 0) goto err;
+ event.data.fd = _listening_master_fd;
+ event.events = EPOLLIN;
+ epoll_ctl (_epfd, EPOLL_CTL_ADD, _listening_master_fd, &event);
+ snprintf(buf, sizeof(buf), "%s/%s/%s/%i", socket_path, SERVER_PATH, SERVER_NAME, SERVER_SLAVE_PORT);
+ _listening_slave_fd = _local_listening_socket_create(buf);
+ if (_listening_slave_fd <= 0) goto err;
+ event.data.fd = _listening_slave_fd;
+ event.events = EPOLLIN;
+ epoll_ctl (_epfd, EPOLL_CTL_ADD, _listening_slave_fd, &event);
+ umask(mask);
+ return EINA_TRUE;
+err:
+ if (mask) umask(mask);
+ if (_listening_master_fd >= 0) close(_listening_master_fd);
+ _listening_master_fd = -1;
+ if (_listening_slave_fd >= 0) close(_listening_slave_fd);
+ _listening_slave_fd = -1;
+ free(socket_path);
+#endif
+ return EINA_FALSE;
+}
+
+int
+main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
+{
+ eina_debug_disable();
+ eina_init();
+ ecore_init();
- ecore_main_loop_begin();
+ _string_to_opcode_hash = eina_hash_string_superfast_new(NULL);
+ _opcode_register("daemon/opcode/register", EINA_DEBUG_OPCODE_REGISTER, _opcode_register_cb);
+ _opcode_register("daemon/greet", EINA_DEBUG_OPCODE_HELLO, _hello_cb);
+ _clients_stat_register_opcode = _opcode_register("daemon/observer/client/register", EINA_DEBUG_OPCODE_INVALID, _cl_stat_obs_register_cb);
+ _slave_added_opcode = _opcode_register("daemon/observer/slave_added", EINA_DEBUG_OPCODE_INVALID, NULL);
+ _slave_deleted_opcode = _opcode_register("daemon/observer/slave_deleted", EINA_DEBUG_OPCODE_INVALID, NULL);
+ _cid_from_pid_opcode = _opcode_register("daemon/info/cid_from_pid", EINA_DEBUG_OPCODE_INVALID, _cid_get_cb);
+ _test_loop_opcode = _opcode_register("daemon/test/loop", EINA_DEBUG_OPCODE_INVALID, _data_test_cb);
- end:
- efl_del(server);
- free(path);
+ _server_launch();
+ _monitor();
- ecore_con_shutdown();
ecore_shutdown();
eina_shutdown();
- return retval;
+ return 0;
}