2015-05-13 23:41:11 -07:00
|
|
|
/* 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/>.
|
|
|
|
*/
|
|
|
|
|
2017-06-04 06:11:16 -07:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
#define EFL_BETA_API_SUPPORT 1
|
|
|
|
#define EFL_EO_API_SUPPORT 1
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
#include <fcntl.h>
|
2017-05-09 00:36:15 -07:00
|
|
|
#include "eina_debug_private.h"
|
2016-11-26 21:48:10 -08:00
|
|
|
|
|
|
|
#include <Eina.h>
|
|
|
|
#include <Ecore.h>
|
2017-06-08 15:25:52 -07:00
|
|
|
#include <Ecore_Con.h>
|
|
|
|
|
|
|
|
static int _log_dom = -1;
|
|
|
|
#ifdef ERR
|
|
|
|
# undef ERR
|
|
|
|
#endif
|
|
|
|
#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
|
|
|
|
|
|
|
|
#ifdef DBG
|
|
|
|
# undef DBG
|
|
|
|
#endif
|
|
|
|
#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
|
2016-11-26 21:48:10 -08:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
#ifdef INF
|
|
|
|
# undef INF
|
|
|
|
#endif
|
|
|
|
#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
|
|
|
|
|
|
|
|
#ifdef WRN
|
|
|
|
# undef WRN
|
|
|
|
#endif
|
|
|
|
#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
|
|
|
|
|
|
|
|
#ifdef CRI
|
|
|
|
# undef CRI
|
|
|
|
#endif
|
|
|
|
#define CRI(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__)
|
2017-06-03 09:33:58 -07:00
|
|
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
|
|
|
#define SWAP_64(x) x
|
|
|
|
#define SWAP_32(x) x
|
|
|
|
#define SWAP_16(x) x
|
|
|
|
#else
|
|
|
|
#define SWAP_64(x) eina_swap64(x)
|
|
|
|
#define SWAP_32(x) eina_swap32(x)
|
|
|
|
#define SWAP_16(x) eina_swap16(x)
|
|
|
|
#endif
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
#define STORE(_buf, pval, sz) \
|
|
|
|
{ \
|
|
|
|
memcpy(_buf, pval, sz); \
|
|
|
|
_buf += sz; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define EXTRACT(_buf, pval, sz) \
|
|
|
|
{ \
|
|
|
|
memcpy(pval, _buf, sz); \
|
|
|
|
_buf += sz; \
|
|
|
|
}
|
2015-05-04 19:35:16 -07:00
|
|
|
|
|
|
|
typedef struct _Client Client;
|
|
|
|
|
|
|
|
struct _Client
|
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
Eo * client;
|
2016-11-26 21:48:10 -08:00
|
|
|
Eina_Stringshare *app_name;
|
2015-05-08 03:48:26 -07:00
|
|
|
|
|
|
|
int version;
|
2016-11-26 21:48:10 -08:00
|
|
|
int cid;
|
2015-05-08 03:48:26 -07:00
|
|
|
pid_t pid;
|
2016-11-26 21:48:10 -08:00
|
|
|
|
|
|
|
Eina_Bool cl_stat_obs : 1;
|
|
|
|
Eina_Bool is_master : 1;
|
2015-05-04 19:35:16 -07:00
|
|
|
};
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static Eina_List *_clients = NULL;
|
2017-06-08 15:25:52 -07:00
|
|
|
static int _retval;
|
|
|
|
|
|
|
|
static Eo *_local_server = NULL, *_remote_server = NULL;
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
typedef Eina_Bool (*Opcode_Cb)(Client *client, void *buffer, int size);
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static Eina_Hash *_string_to_opcode_hash = NULL;
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static int _free_cid = 1;
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
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;
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
int opcode;
|
|
|
|
Eina_Stringshare *opcode_string;
|
|
|
|
Opcode_Cb cb;
|
|
|
|
} Opcode_Information;
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
#define MAX_OPCODES 1000
|
|
|
|
Opcode_Information *_opcodes[MAX_OPCODES];
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2015-05-08 03:48:26 -07:00
|
|
|
static Client *
|
2016-11-26 21:48:10 -08:00
|
|
|
_client_find_by_cid(int cid)
|
2015-05-08 03:48:26 -07:00
|
|
|
{
|
|
|
|
Client *c;
|
|
|
|
Eina_List *l;
|
2016-11-26 21:48:10 -08:00
|
|
|
EINA_LIST_FOREACH(_clients, l, c)
|
|
|
|
if (c->cid == cid) return c;
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-05-08 03:48:26 -07:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
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;
|
|
|
|
}
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2017-05-09 00:36:15 -07:00
|
|
|
static void
|
2016-11-26 21:48:10 -08:00
|
|
|
_send(Client *dest, int opcode, void *payload, int payload_size)
|
2015-05-10 03:05:54 -07:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
Eina_Error err;
|
|
|
|
Eina_Slice s, r;
|
|
|
|
Eina_Debug_Packet_Header hdr;
|
2016-11-26 21:48:10 -08:00
|
|
|
int size = sizeof(Eina_Debug_Packet_Header) + payload_size;
|
2015-05-10 03:05:54 -07:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
hdr.size = SWAP_32(size);
|
|
|
|
hdr.cid = 0;
|
|
|
|
hdr.opcode = SWAP_32(opcode);
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
s.mem = &hdr;
|
|
|
|
s.len = sizeof(hdr);
|
2016-11-26 21:48:10 -08:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
err = efl_io_writer_write(dest->client, &s, &r);
|
|
|
|
if (err || r.len) goto end;
|
2016-11-26 21:48:10 -08:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
if (!payload_size) goto end;
|
|
|
|
|
|
|
|
s.mem = payload;
|
|
|
|
s.len = payload_size;
|
|
|
|
err = efl_io_writer_write(dest->client, &s, &r);
|
|
|
|
|
|
|
|
INF("Send packet (size = %d, opcode %s) to %s", size,
|
|
|
|
_opcodes[opcode]->opcode_string,
|
|
|
|
dest->app_name);
|
|
|
|
|
|
|
|
end:
|
|
|
|
if (err)
|
2015-05-04 19:35:16 -07:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
fprintf(stderr, "ERROR: could not queue message '%d': %s\n", opcode, eina_error_msg_get(err));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (r.len)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "ERROR: could not queue message '%d': out of memory\n", opcode);
|
2015-05-04 19:35:16 -07:00
|
|
|
}
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2017-06-08 15:25:52 -07:00
|
|
|
_dispatch(Client *src, void *buffer)
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
|
|
|
Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)buffer;
|
|
|
|
if (hdr->cid)
|
2015-05-04 19:35:16 -07:00
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
/* If the client id is given, we forward */
|
|
|
|
Client *dest = _client_find_by_cid(hdr->cid);
|
|
|
|
if (dest)
|
2015-05-08 03:48:26 -07:00
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
if (dest->is_master != src->is_master)
|
2016-11-25 13:39:01 -08:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
Eina_Slice s;
|
|
|
|
s.mem = buffer;
|
|
|
|
s.len = hdr->size;
|
2017-06-03 09:33:58 -07:00
|
|
|
hdr->cid = SWAP_32(src->cid);
|
2017-06-08 15:25:52 -07:00
|
|
|
hdr->size = SWAP_32(hdr->size);
|
|
|
|
hdr->opcode = SWAP_32(hdr->opcode);
|
2017-09-28 19:21:37 -07:00
|
|
|
if (efl_io_writer_write(dest->client, &s, NULL) !=
|
|
|
|
EINA_ERROR_NO_ERROR)
|
|
|
|
ERR("Cannot write to client [%s:%i]", dest->app_name, (int)dest->pid);
|
2017-06-08 15:25:52 -07:00
|
|
|
INF("Transfer of %d bytes from %s(%d) to %s(%d): operation %s\n",
|
2017-05-27 10:44:19 -07:00
|
|
|
hdr->size,
|
|
|
|
src->app_name, src->pid,
|
|
|
|
dest->app_name, dest->pid,
|
|
|
|
_opcodes[hdr->opcode]->opcode_string);
|
2016-11-25 13:39:01 -08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
/*
|
|
|
|
* Packets Master -> Master or Slave -> Slave are forbidden
|
|
|
|
* Only Master <-> Slave packets are allowed.
|
|
|
|
*/
|
2017-06-08 15:25:52 -07:00
|
|
|
ERR("Packet from %d to %d: denied (same type)\n", hdr->cid, dest->cid);
|
2016-11-25 13:39:01 -08:00
|
|
|
}
|
2015-05-08 03:48:26 -07:00
|
|
|
}
|
2015-05-04 19:35:16 -07:00
|
|
|
}
|
2016-11-26 21:48:10 -08:00
|
|
|
else
|
2015-05-10 03:05:54 -07:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
INF("Invoke %s\n", _opcodes[hdr->opcode]->opcode_string);
|
2016-11-26 21:48:10 -08:00
|
|
|
if (_opcodes[hdr->opcode]->cb)
|
|
|
|
return _opcodes[hdr->opcode]->cb(src,
|
2017-06-08 15:25:52 -07:00
|
|
|
(char *)buffer + sizeof(Eina_Debug_Packet_Header),
|
|
|
|
hdr->size - sizeof(Eina_Debug_Packet_Header));
|
2015-05-10 03:05:54 -07:00
|
|
|
}
|
2016-11-26 21:48:10 -08:00
|
|
|
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)
|
2015-05-10 03:05:54 -07:00
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
op_info = calloc(1, sizeof(*op_info));
|
|
|
|
if (op_id == EINA_DEBUG_OPCODE_INVALID)
|
2015-05-10 03:05:54 -07:00
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
do
|
2015-05-10 03:05:54 -07:00
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
free_opcode = (free_opcode + 1) % MAX_OPCODES;
|
|
|
|
op_id = free_opcode;
|
2015-05-10 03:05:54 -07:00
|
|
|
}
|
2016-11-26 21:48:10 -08:00
|
|
|
while(_opcodes[op_id]);
|
2015-05-10 03:05:54 -07:00
|
|
|
}
|
2016-11-26 21:48:10 -08:00
|
|
|
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;
|
2015-05-10 03:05:54 -07:00
|
|
|
}
|
2017-06-08 15:25:52 -07:00
|
|
|
INF("Register %s -> opcode %d\n", op_name, op_info->opcode);
|
2016-11-26 21:48:10 -08:00
|
|
|
return op_info->opcode;
|
|
|
|
}
|
2015-05-10 20:28:18 -07:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static Eina_Bool
|
|
|
|
_hello_cb(Client *c, void *buffer, int size)
|
|
|
|
{
|
|
|
|
Eina_List *itr;
|
|
|
|
char *buf = (char *)buffer, *tmp;
|
2017-06-03 09:33:58 -07:00
|
|
|
int version, pid, cid;
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2017-06-03 09:33:58 -07:00
|
|
|
EXTRACT(buf, &version, 4);
|
|
|
|
EXTRACT(buf, &pid, 4);
|
|
|
|
c->version = SWAP_32(version);
|
|
|
|
c->pid = SWAP_32(pid);
|
2016-11-26 21:48:10 -08:00
|
|
|
size -= 8;
|
2016-12-01 10:23:23 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
c->cid = _free_cid++;
|
2017-06-03 09:33:58 -07:00
|
|
|
cid = SWAP_32(c->cid);
|
2016-11-26 21:48:10 -08:00
|
|
|
if (size > 1)
|
|
|
|
{
|
|
|
|
c->app_name = eina_stringshare_add_length(buf, size);
|
2015-05-10 03:05:54 -07:00
|
|
|
}
|
2017-06-08 15:25:52 -07:00
|
|
|
INF("Connection of %s: pid %d - name %s -> cid %d\n",
|
2016-11-26 21:48:10 -08:00
|
|
|
c->is_master ? "Master" : "Slave",
|
2017-05-27 10:44:19 -07:00
|
|
|
c->pid, c->app_name, c->cid);
|
2016-11-26 21:48:10 -08:00
|
|
|
|
|
|
|
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;
|
2017-06-03 09:33:58 -07:00
|
|
|
STORE(tmp, &cid, sizeof(int));
|
|
|
|
STORE(tmp, &pid, sizeof(int));
|
2016-11-26 21:48:10 -08:00
|
|
|
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)
|
2015-05-04 19:35:16 -07:00
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
if (c->cl_stat_obs) _send(c, _slave_added_opcode, buf, size);
|
2015-05-04 19:35:16 -07:00
|
|
|
}
|
2016-11-26 21:48:10 -08:00
|
|
|
return EINA_TRUE;
|
2015-05-04 19:35:16 -07:00
|
|
|
}
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static Eina_Bool
|
|
|
|
_cid_get_cb(Client *src, void *buffer, int size EINA_UNUSED)
|
2016-11-25 13:39:01 -08:00
|
|
|
{
|
2017-06-03 09:33:58 -07:00
|
|
|
int pid = SWAP_32(*(int *)buffer);
|
2016-11-26 21:48:10 -08:00
|
|
|
Client *c = _client_find_by_pid(pid);
|
2017-06-03 09:33:58 -07:00
|
|
|
int cid = c ? SWAP_32(c->cid) : 0;
|
2016-11-26 21:48:10 -08:00
|
|
|
_send(src, _cid_from_pid_opcode, &cid, sizeof(int));
|
|
|
|
return EINA_TRUE;
|
2016-11-25 13:39:01 -08:00
|
|
|
}
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static Eina_Bool
|
|
|
|
_data_test_cb(Client *src, void *buffer, int size)
|
2015-05-04 19:35:16 -07:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
DBG("Data test: loop packet of %d bytes\n", size);
|
2016-11-26 21:48:10 -08:00
|
|
|
_send(src, _test_loop_opcode, buffer, size);
|
|
|
|
return EINA_TRUE;
|
2016-11-25 13:39:01 -08:00
|
|
|
}
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static Eina_Bool
|
|
|
|
_cl_stat_obs_register_cb(Client *src, void *buffer, int size)
|
2016-11-25 13:39:01 -08:00
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
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;
|
2017-06-03 09:33:58 -07:00
|
|
|
int cid, pid;
|
2016-11-26 21:48:10 -08:00
|
|
|
if (c->is_master) continue;
|
|
|
|
size = 2 * sizeof(int) + (c->app_name ? strlen(c->app_name) : 0) + 1;
|
|
|
|
buffer = alloca(size);
|
|
|
|
tmp = buffer;
|
2017-06-03 09:33:58 -07:00
|
|
|
cid = SWAP_32(c->cid);
|
|
|
|
pid = SWAP_32(c->pid);
|
|
|
|
STORE(tmp, &cid, sizeof(int));
|
|
|
|
STORE(tmp, &pid, sizeof(int));
|
2016-11-26 21:48:10 -08:00
|
|
|
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;
|
2016-11-25 13:39:01 -08:00
|
|
|
}
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static Eina_Bool
|
|
|
|
_opcode_register_cb(Client *src, void *buffer, int size)
|
2016-11-25 13:39:01 -08:00
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
char *buf = (char *)buffer;
|
|
|
|
char *ops_buf = buf;
|
|
|
|
int ops_size = size;
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
ops_buf += sizeof(uint64_t);
|
|
|
|
ops_size -= sizeof(uint64_t);
|
|
|
|
int *opcodes = (int *)ops_buf;
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
while (ops_size > 0)
|
2015-05-04 19:35:16 -07:00
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
int len = strlen(ops_buf) + 1;
|
2017-06-03 09:33:58 -07:00
|
|
|
*opcodes++ = SWAP_32(_opcode_register(ops_buf, EINA_DEBUG_OPCODE_INVALID, NULL));
|
2016-11-26 21:48:10 -08:00
|
|
|
ops_buf += len;
|
|
|
|
ops_size -= len;
|
2016-11-25 13:39:01 -08:00
|
|
|
}
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
_send(src, EINA_DEBUG_OPCODE_REGISTER, buf, (char *)opcodes - (char *)buf);
|
2015-05-08 03:48:26 -07:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
return EINA_TRUE;
|
2016-11-25 13:39:01 -08:00
|
|
|
}
|
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
static void
|
|
|
|
_client_data(void *data, const Efl_Event *event)
|
2016-11-25 13:39:01 -08:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
static unsigned char *buffer = NULL;
|
2017-05-09 00:36:15 -07:00
|
|
|
unsigned int size = 0;
|
2017-06-08 15:25:52 -07:00
|
|
|
Eina_Debug_Packet_Header *hdr;
|
|
|
|
Client *c = data;
|
|
|
|
Eina_Slice slice;
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
if (!c) return;
|
|
|
|
|
|
|
|
if (!buffer) buffer = malloc(EINA_DEBUG_MAX_PACKET_SIZE);
|
|
|
|
|
|
|
|
slice = efl_io_buffered_stream_slice_get(c->client);
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
if (slice.len < sizeof(*hdr)) return;
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
hdr = (Eina_Debug_Packet_Header *)slice.mem;
|
|
|
|
size = SWAP_32(hdr->size);
|
|
|
|
if (size < sizeof(*hdr)) /* must contain at least the header */
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
fprintf(stderr, "ERROR: invalid message header, size=%u\n", hdr->size);
|
|
|
|
goto err;
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
2017-06-08 15:25:52 -07:00
|
|
|
|
|
|
|
if (size > EINA_DEBUG_MAX_PACKET_SIZE)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "ERROR: packet too big (max: %d), size=%u\n",
|
|
|
|
EINA_DEBUG_MAX_PACKET_SIZE, hdr->size);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Incomplete packet: need to wait */
|
|
|
|
if (size > slice.len) return;
|
|
|
|
|
|
|
|
memcpy(buffer, slice.mem, size);
|
|
|
|
hdr = (Eina_Debug_Packet_Header *)buffer;
|
|
|
|
hdr->size = SWAP_32(hdr->size);
|
|
|
|
hdr->opcode = SWAP_32(hdr->opcode);
|
|
|
|
hdr->cid = SWAP_32(hdr->cid);
|
|
|
|
|
|
|
|
if(!_dispatch(c, buffer))
|
|
|
|
{
|
|
|
|
// something we don't understand
|
|
|
|
fprintf(stderr, "Dispatch: unknown command: %d\n", hdr->opcode);
|
|
|
|
}
|
|
|
|
efl_io_buffered_stream_discard(c->client, size);
|
|
|
|
return;
|
|
|
|
err:
|
|
|
|
if (!efl_io_closer_closed_get(event->object))
|
|
|
|
efl_io_closer_close(event->object);
|
|
|
|
fprintf(stderr, "INFO: client %p [pid: %d] sent invalid data\n", c, (int)c->pid);
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static void
|
2017-06-08 15:25:52 -07:00
|
|
|
_client_error(void *data, const Efl_Event *event)
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
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));
|
|
|
|
}
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
static void
|
|
|
|
_client_eos(void *data, const Efl_Event *event EINA_UNUSED)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
static void
|
|
|
|
_client_write_finished(void *data, const Efl_Event *event EINA_UNUSED)
|
|
|
|
{
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_client_read_finished(void *data, const Efl_Event *event EINA_UNUSED)
|
|
|
|
{
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
|
|
|
static Efl_Callback_Array_Item *_client_cbs(void);
|
|
|
|
|
|
|
|
static void
|
|
|
|
_client_finished(void *data, const Efl_Event *event EINA_UNUSED)
|
|
|
|
{
|
|
|
|
Eina_List *itr;
|
|
|
|
Client *c = data, *c2;
|
|
|
|
int cid = SWAP_32(c->cid);
|
|
|
|
efl_event_callback_array_del(c->client, _client_cbs(), c);
|
|
|
|
INF("finished client %p (%p) [pid:%d]", c, c->client, c->pid);
|
|
|
|
_clients = eina_list_remove(_clients, c);
|
|
|
|
efl_unref(c->client);
|
|
|
|
|
|
|
|
/* Don't update the observers if the client is a master */
|
|
|
|
if (c->is_master) return;
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(_clients, itr, c2)
|
|
|
|
{
|
|
|
|
if (c2->cl_stat_obs) _send(c2, _slave_deleted_opcode, &cid, sizeof(int));
|
2015-05-04 19:35:16 -07:00
|
|
|
}
|
2017-06-08 15:25:52 -07:00
|
|
|
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));
|
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN(c);
|
|
|
|
c->client = efl_ref(event->info);
|
|
|
|
c->is_master = (event->object == _remote_server);
|
|
|
|
_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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_error(void *data EINA_UNUSED, const Efl_Event *event)
|
|
|
|
{
|
|
|
|
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;
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2017-05-09 00:36:15 -07:00
|
|
|
static char *
|
2017-06-05 09:59:23 -07:00
|
|
|
_socket_home_get(void)
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
|
|
|
// get possible debug daemon socket directory base
|
2017-05-09 00:36:15 -07:00
|
|
|
char *ret = NULL;
|
2016-11-26 21:48:10 -08:00
|
|
|
const char *dir = getenv("XDG_RUNTIME_DIR");
|
|
|
|
if (!dir) dir = eina_environment_home_get();
|
|
|
|
if (!dir) dir = eina_environment_tmp_get();
|
2017-05-09 00:36:15 -07:00
|
|
|
if (dir)
|
|
|
|
{
|
|
|
|
ret = calloc(1024, 1);
|
|
|
|
strncpy(ret, dir, 1023);
|
|
|
|
}
|
|
|
|
return ret;
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
static Eina_Bool
|
|
|
|
_local_server_create(void)
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
Eo *loop;
|
|
|
|
Eina_Error err;
|
2017-05-25 03:26:41 -07:00
|
|
|
char *socket_path = _socket_home_get();
|
|
|
|
mode_t mask = 0;
|
2017-06-08 15:25:52 -07:00
|
|
|
char path[512];
|
2017-05-25 03:26:41 -07:00
|
|
|
Eina_Bool ret = EINA_FALSE;
|
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
snprintf(path, sizeof(path) - 1, "%s/%s", socket_path, LOCAL_SERVER_PATH);
|
|
|
|
if (mkdir(path, S_IRWXU) < 0 && errno != EEXIST)
|
2017-05-25 03:26:41 -07:00
|
|
|
{
|
|
|
|
perror("mkdir SERVER_PATH");
|
|
|
|
goto end;
|
|
|
|
}
|
2017-06-08 15:25:52 -07:00
|
|
|
snprintf(path, sizeof(path) - 1, "%s/%s/%s", socket_path, LOCAL_SERVER_PATH, LOCAL_SERVER_NAME);
|
|
|
|
if (mkdir(path, S_IRWXU) < 0 && errno != EEXIST)
|
2017-05-25 03:26:41 -07:00
|
|
|
{
|
|
|
|
perror("mkdir SERVER_NAME");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
mask = umask(S_IRWXG | S_IRWXO);
|
2017-06-08 15:25:52 -07:00
|
|
|
snprintf(path, sizeof(path) - 1, "%s/%s/%s/%i", socket_path,
|
2017-05-25 03:26:41 -07:00
|
|
|
LOCAL_SERVER_PATH, LOCAL_SERVER_NAME, LOCAL_SERVER_PORT);
|
2017-06-08 15:25:52 -07:00
|
|
|
|
2018-01-01 22:41:46 -08:00
|
|
|
loop = efl_main_loop_get();
|
2017-06-08 15:25:52 -07:00
|
|
|
|
|
|
|
#ifdef EFL_NET_SERVER_UNIX_CLASS
|
|
|
|
_local_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");
|
|
|
|
#endif
|
|
|
|
if (!_local_server)
|
2017-05-25 03:26:41 -07:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
fprintf(stderr, "ERROR: could not create communication server\n");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
efl_event_callback_add(_local_server, EFL_NET_SERVER_EVENT_CLIENT_ADD, _client_add, NULL);
|
|
|
|
efl_event_callback_add(_local_server, EFL_NET_SERVER_EVENT_ERROR, _error, NULL);
|
|
|
|
|
|
|
|
#ifdef EFL_NET_SERVER_UNIX_CLASS
|
|
|
|
{
|
|
|
|
Eo *inner_server = efl_net_server_simple_inner_server_get(_local_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);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
err = efl_net_server_serve(_local_server, path);
|
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "ERROR: could not serve '%s': %s\n", path, eina_error_msg_get(err));
|
2017-05-25 03:26:41 -07:00
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = EINA_TRUE;
|
|
|
|
end:
|
|
|
|
umask(mask);
|
2017-06-08 15:25:52 -07:00
|
|
|
if (!ret)
|
2017-05-25 03:26:41 -07:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
efl_del(_local_server);
|
|
|
|
_local_server = NULL;
|
2017-05-25 03:26:41 -07:00
|
|
|
}
|
|
|
|
free(socket_path);
|
2017-06-08 15:25:52 -07:00
|
|
|
return ret;
|
2017-05-25 03:26:41 -07:00
|
|
|
}
|
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
static Eina_Bool
|
|
|
|
_remote_server_create(void)
|
2017-05-25 03:26:41 -07:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
Eo *loop;
|
|
|
|
Eina_Error err;
|
|
|
|
mode_t mask = 0;
|
|
|
|
Eina_Bool ret = EINA_FALSE;
|
|
|
|
char address[256];
|
|
|
|
|
2018-01-01 22:41:46 -08:00
|
|
|
loop = efl_main_loop_get();
|
2017-06-08 15:25:52 -07:00
|
|
|
|
|
|
|
_remote_server = efl_add(EFL_NET_SERVER_SIMPLE_CLASS, loop,
|
|
|
|
efl_net_server_simple_inner_class_set(efl_added, EFL_NET_SERVER_TCP_CLASS));
|
|
|
|
if (!_remote_server)
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
fprintf(stderr, "ERROR: could not create communication server\n");
|
|
|
|
goto end;
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
2017-06-08 15:25:52 -07:00
|
|
|
|
|
|
|
{
|
|
|
|
Eo *inner_server = efl_net_server_simple_inner_server_get(_remote_server);
|
|
|
|
efl_net_server_fd_reuse_address_set(inner_server, EINA_TRUE);
|
|
|
|
}
|
|
|
|
efl_event_callback_add(_remote_server, EFL_NET_SERVER_EVENT_CLIENT_ADD, _client_add, NULL);
|
|
|
|
efl_event_callback_add(_remote_server, EFL_NET_SERVER_EVENT_ERROR, _error, NULL);
|
|
|
|
|
|
|
|
sprintf(address, "127.0.0.1:%d", REMOTE_SERVER_PORT);
|
|
|
|
err = efl_net_server_serve(_remote_server, address);
|
|
|
|
if (err)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "ERROR: could not serve port '%d': %s\n",
|
|
|
|
REMOTE_SERVER_PORT, eina_error_msg_get(err));
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
ret = EINA_TRUE;
|
|
|
|
end:
|
|
|
|
umask(mask);
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
efl_del(_remote_server);
|
|
|
|
_remote_server = NULL;
|
|
|
|
}
|
|
|
|
return ret;
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static Eina_Bool
|
2017-06-05 09:59:23 -07:00
|
|
|
_server_launch(void)
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
2017-06-08 15:25:52 -07:00
|
|
|
if (_local_server_create() <= 0) goto err;
|
|
|
|
if (_remote_server_create() <= 0) goto err;
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
return EINA_TRUE;
|
|
|
|
err:
|
2017-06-08 15:25:52 -07:00
|
|
|
efl_del(_local_server);
|
|
|
|
efl_del(_remote_server);
|
2016-11-26 21:48:10 -08:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
|
|
|
|
{
|
|
|
|
eina_debug_disable();
|
2017-06-08 15:25:52 -07:00
|
|
|
ecore_app_no_system_modules();
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
eina_init();
|
|
|
|
ecore_init();
|
2017-06-08 15:25:52 -07:00
|
|
|
ecore_con_init();
|
|
|
|
|
|
|
|
_retval = EXIT_SUCCESS;
|
|
|
|
_log_dom = eina_log_domain_register("efl_debugd", EINA_COLOR_CYAN);
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
_string_to_opcode_hash = eina_hash_string_superfast_new(NULL);
|
2017-05-27 13:08:36 -07:00
|
|
|
_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/Client/register_observer", EINA_DEBUG_OPCODE_INVALID, _cl_stat_obs_register_cb);
|
|
|
|
_slave_added_opcode = _opcode_register("Daemon/Client/added", EINA_DEBUG_OPCODE_INVALID, NULL);
|
|
|
|
_slave_deleted_opcode = _opcode_register("Daemon/Client/deleted", EINA_DEBUG_OPCODE_INVALID, NULL);
|
|
|
|
_cid_from_pid_opcode = _opcode_register("Daemon/Client/cid_from_pid", EINA_DEBUG_OPCODE_INVALID, _cid_get_cb);
|
2017-05-04 00:17:05 -07:00
|
|
|
_test_loop_opcode = _opcode_register("Test/data_loop", EINA_DEBUG_OPCODE_INVALID, _data_test_cb);
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
if (_server_launch()) ecore_main_loop_begin();
|
|
|
|
else _retval = EXIT_FAILURE;
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
ecore_con_shutdown();
|
2015-05-04 19:35:16 -07:00
|
|
|
ecore_shutdown();
|
|
|
|
eina_shutdown();
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2017-06-08 15:25:52 -07:00
|
|
|
return _retval;
|
2015-05-04 19:35:16 -07:00
|
|
|
}
|