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
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
#include <unistd.h>
|
2017-06-04 06:11:16 -07:00
|
|
|
#ifdef HAVE_SYS_EPOLL_H
|
|
|
|
# include <sys/epoll.h>
|
|
|
|
#endif
|
2016-11-26 21:48:10 -08:00
|
|
|
#include <sys/types.h>
|
2017-06-04 06:11:16 -07:00
|
|
|
#ifdef HAVE_SYS_SOCKET_H
|
|
|
|
# include <sys/socket.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_UN_H
|
|
|
|
# include <sys/un.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_NETINET_IN_H
|
|
|
|
# include <netinet/in.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_ARPA_INET_H
|
|
|
|
# include <arpa/inet.h>
|
|
|
|
#endif
|
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-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
|
|
|
|
{
|
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 fd;
|
|
|
|
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;
|
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
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
/* epoll stuff */
|
|
|
|
#ifndef _WIN32
|
2017-05-25 03:26:41 -07:00
|
|
|
static int _epfd = -1, _listening_unix_fd = -1, _listening_tcp_fd = -1;
|
2016-11-25 13:39:01 -08:00
|
|
|
#endif
|
|
|
|
|
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
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
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;
|
2015-05-08 03:48:26 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
int size = sizeof(Eina_Debug_Packet_Header) + payload_size;
|
|
|
|
char *buf = alloca(size);
|
|
|
|
Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)buf;
|
2017-06-03 09:33:58 -07:00
|
|
|
hdr->size = SWAP_32(size);
|
2016-11-26 21:48:10 -08:00
|
|
|
hdr->cid = 0;
|
2017-06-03 09:33:58 -07:00
|
|
|
hdr->opcode = SWAP_32(opcode);
|
2016-11-26 21:48:10 -08:00
|
|
|
memcpy(buf + sizeof(Eina_Debug_Packet_Header), payload, payload_size);
|
2017-05-27 11:58:13 -07:00
|
|
|
printf("Send packet (size = %d, opcode %s) to %s\n", size,
|
|
|
|
_opcodes[hdr->opcode]->opcode_string,
|
|
|
|
dest->app_name);
|
2017-05-09 00:36:15 -07:00
|
|
|
if (send(dest->fd, buf, size, 0) != size) perror("send");
|
2015-05-10 03:05:54 -07:00
|
|
|
}
|
|
|
|
|
2015-05-04 19:35:16 -07:00
|
|
|
static void
|
2016-11-26 21:48:10 -08:00
|
|
|
_client_del(Client *c)
|
2015-05-04 19:35:16 -07:00
|
|
|
{
|
2015-05-08 03:48:26 -07:00
|
|
|
Client *c2;
|
2016-11-26 21:48:10 -08:00
|
|
|
if (!c) return;
|
|
|
|
Eina_List *itr;
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
_clients = eina_list_remove(_clients, c);
|
|
|
|
|
|
|
|
/* Don't update the observers if the client is a master */
|
|
|
|
if (c->is_master) return;
|
|
|
|
|
|
|
|
EINA_LIST_FOREACH(_clients, itr, c2)
|
2015-05-04 19:35:16 -07:00
|
|
|
{
|
2017-06-03 09:33:58 -07:00
|
|
|
int cid = SWAP_32(c->cid);
|
|
|
|
if (c2->cl_stat_obs) _send(c2, _slave_deleted_opcode, &cid, sizeof(int));
|
2015-05-04 19:35:16 -07:00
|
|
|
}
|
2016-11-26 21:48:10 -08:00
|
|
|
free(c);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Bool
|
2017-05-09 00:36:15 -07:00
|
|
|
_dispatch(Client *src, void *buffer, unsigned int size)
|
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-03 09:33:58 -07:00
|
|
|
hdr->cid = SWAP_32(src->cid);
|
2017-05-09 00:36:15 -07:00
|
|
|
if (send(dest->fd, buffer, size, 0) != size) perror("send");
|
2017-05-27 10:44:19 -07:00
|
|
|
printf("Transfer of %d bytes from %s(%d) to %s(%d): operation %s\n",
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
printf("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
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
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));
|
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
|
|
|
}
|
2016-11-26 21:48:10 -08:00
|
|
|
printf("Register %s -> opcode %d\n", op_name, op_info->opcode);
|
|
|
|
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-05-27 10:44:19 -07:00
|
|
|
printf("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
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
printf("Data test: loop packet of %d bytes\n", size);
|
|
|
|
_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
|
|
|
}
|
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static int
|
2017-05-09 00:36:15 -07:00
|
|
|
_data_receive(Client *c, unsigned char *buffer)
|
2016-11-25 13:39:01 -08:00
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
int rret;
|
2017-05-09 00:36:15 -07:00
|
|
|
unsigned int size = 0;
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
if (!c) return -1;
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
rret = recv(c->fd, &size, sizeof(int), MSG_PEEK);
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2017-05-27 10:44:50 -07:00
|
|
|
if (rret == -1 || !size) goto error;
|
2016-11-26 21:48:10 -08:00
|
|
|
if (rret == sizeof(int))
|
|
|
|
{
|
2017-06-03 09:33:58 -07:00
|
|
|
Eina_Debug_Packet_Header *hdr;
|
2017-05-09 00:36:15 -07:00
|
|
|
unsigned int cur_packet_size = 0;
|
2017-06-03 09:33:58 -07:00
|
|
|
size = SWAP_32(size);
|
2017-05-09 00:36:15 -07:00
|
|
|
if (size > EINA_DEBUG_MAX_PACKET_SIZE) goto error;
|
2016-11-26 21:48:10 -08:00
|
|
|
while (cur_packet_size < size)
|
|
|
|
{
|
2017-05-09 00:36:15 -07:00
|
|
|
rret = recv(c->fd, buffer + cur_packet_size, size - cur_packet_size, 0);
|
2016-11-26 21:48:10 -08:00
|
|
|
if (rret <= 0) goto error;
|
|
|
|
cur_packet_size += rret;
|
|
|
|
}
|
2017-06-03 09:33:58 -07:00
|
|
|
hdr = (Eina_Debug_Packet_Header *) buffer;
|
|
|
|
hdr->size = SWAP_32(hdr->size);
|
|
|
|
hdr->opcode = SWAP_32(hdr->opcode);
|
|
|
|
hdr->cid = SWAP_32(hdr->cid);
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
|
|
|
//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");
|
|
|
|
return -1;
|
|
|
|
}
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static void
|
|
|
|
_monitor()
|
|
|
|
{
|
|
|
|
#ifndef _WIN32
|
|
|
|
#define MAX_EVENTS 1000
|
|
|
|
int ret = 0;
|
|
|
|
struct epoll_event events[MAX_EVENTS];
|
2017-05-09 00:36:15 -07:00
|
|
|
unsigned char *buffer = malloc(EINA_DEBUG_MAX_PACKET_SIZE);
|
2016-11-26 21:48:10 -08:00
|
|
|
Client *c;
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
// sit forever processing commands or timeouts
|
|
|
|
for (; ret != -1;)
|
2016-11-25 13:39:01 -08:00
|
|
|
{
|
2016-11-26 21:48:10 -08:00
|
|
|
ret = epoll_wait (_epfd, events, MAX_EVENTS, -1);
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
// 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);
|
2017-05-27 11:58:13 -07:00
|
|
|
if (c)
|
|
|
|
{
|
|
|
|
printf("Closing client %s/%d\n", c->app_name, c->pid);
|
|
|
|
_client_del(c);
|
|
|
|
}
|
2016-11-26 21:48:10 -08:00
|
|
|
}
|
|
|
|
if (events[i].events & EPOLLIN)
|
|
|
|
{
|
|
|
|
// Someone wants to connect
|
2017-05-25 03:26:41 -07:00
|
|
|
if(events[i].data.fd == _listening_unix_fd || events[i].data.fd == _listening_tcp_fd)
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
|
|
|
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;
|
2017-05-25 03:26:41 -07:00
|
|
|
c->is_master = (events[i].data.fd == _listening_tcp_fd);
|
2016-11-26 21:48:10 -08:00
|
|
|
_clients = eina_list_append(_clients, c);
|
|
|
|
event.data.fd = new_fd;
|
|
|
|
event.events = EPOLLIN;
|
|
|
|
epoll_ctl (_epfd, EPOLL_CTL_ADD, new_fd, &event);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
c = _client_find_by_fd(events[i].data.fd);
|
|
|
|
if (c)
|
|
|
|
{
|
|
|
|
int size;
|
2017-05-09 00:36:15 -07:00
|
|
|
size = _data_receive(c, buffer);
|
2016-11-26 21:48:10 -08:00
|
|
|
// if not negative - we have a real message
|
2017-05-09 00:36:15 -07:00
|
|
|
if (size >= 0)
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
|
|
|
if(!_dispatch(c, buffer, size))
|
|
|
|
{
|
|
|
|
// something we don't understand
|
|
|
|
fprintf(stderr, "Dispatch: unknown command");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// major failure on debug daemon control fd - get out of here.
|
|
|
|
// else goto fail;
|
|
|
|
close(events[i].data.fd);
|
2017-05-27 11:58:13 -07:00
|
|
|
_client_del(c);
|
2016-11-26 21:48:10 -08:00
|
|
|
//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;
|
|
|
|
}
|
|
|
|
}
|
2016-11-25 13:39:01 -08:00
|
|
|
#endif
|
2015-05-04 19:35:16 -07:00
|
|
|
}
|
2017-05-09 00:36:15 -07:00
|
|
|
free(buffer);
|
2016-11-26 21:48:10 -08:00
|
|
|
#endif
|
|
|
|
}
|
2015-05-04 19:35:16 -07:00
|
|
|
|
2017-05-09 00:36:15 -07:00
|
|
|
static char *
|
2016-11-26 21:48:10 -08:00
|
|
|
_socket_home_get()
|
|
|
|
{
|
|
|
|
// 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
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
#ifndef _WIN32
|
|
|
|
#define LENGTH_OF_SOCKADDR_UN(s) \
|
|
|
|
(strlen((s)->sun_path) + (size_t)(((struct sockaddr_un *)NULL)->sun_path))
|
|
|
|
static int
|
2017-05-25 03:26:41 -07:00
|
|
|
_listening_unix_socket_create()
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
2017-05-25 03:26:41 -07:00
|
|
|
char buf[1048];
|
2016-11-26 21:48:10 -08:00
|
|
|
struct sockaddr_un socket_unix;
|
|
|
|
int socket_unix_len, curstate = 0;
|
2017-05-25 03:26:41 -07:00
|
|
|
char *socket_path = _socket_home_get();
|
|
|
|
mode_t mask = 0;
|
2016-11-26 21:48:10 -08:00
|
|
|
// create the socket
|
|
|
|
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
2017-05-25 03:26:41 -07:00
|
|
|
Eina_Bool ret = EINA_FALSE;
|
|
|
|
|
|
|
|
if (fd < 0) goto end;
|
2016-11-26 21:48:10 -08:00
|
|
|
// set the socket to close when we exec things so they don't inherit it
|
2017-05-25 03:26:41 -07:00
|
|
|
if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) goto end;
|
2016-11-26 21:48:10 -08:00
|
|
|
// set up some socket options on addr re-use
|
|
|
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate,
|
|
|
|
sizeof(curstate)) < 0)
|
2017-05-25 03:26:41 -07:00
|
|
|
goto end;
|
|
|
|
|
2017-05-30 06:04:24 -07:00
|
|
|
snprintf(buf, sizeof(buf) - 1, "%s/%s", socket_path, LOCAL_SERVER_PATH);
|
2017-05-25 03:26:41 -07:00
|
|
|
if (mkdir(buf, S_IRWXU) < 0 && errno != EEXIST)
|
|
|
|
{
|
|
|
|
perror("mkdir SERVER_PATH");
|
|
|
|
goto end;
|
|
|
|
}
|
2017-05-30 06:04:24 -07:00
|
|
|
snprintf(buf, sizeof(buf) - 1, "%s/%s/%s", socket_path, LOCAL_SERVER_PATH, LOCAL_SERVER_NAME);
|
2017-05-25 03:26:41 -07:00
|
|
|
if (mkdir(buf, S_IRWXU) < 0 && errno != EEXIST)
|
|
|
|
{
|
|
|
|
perror("mkdir SERVER_NAME");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
mask = umask(S_IRWXG | S_IRWXO);
|
2017-05-30 06:04:24 -07:00
|
|
|
snprintf(buf, sizeof(buf) - 1, "%s/%s/%s/%i", socket_path,
|
2017-05-25 03:26:41 -07:00
|
|
|
LOCAL_SERVER_PATH, LOCAL_SERVER_NAME, LOCAL_SERVER_PORT);
|
2016-11-26 21:48:10 -08:00
|
|
|
// sa that it's a unix socket and where the path is
|
|
|
|
socket_unix.sun_family = AF_UNIX;
|
2017-05-25 03:26:41 -07:00
|
|
|
strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path) - 1);
|
2016-11-26 21:48:10 -08:00
|
|
|
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)
|
2017-05-25 03:26:41 -07:00
|
|
|
{
|
|
|
|
perror("ERROR on binding");
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
listen(fd, 5);
|
|
|
|
ret = EINA_TRUE;
|
|
|
|
end:
|
|
|
|
umask(mask);
|
|
|
|
if (!ret && fd >= 0)
|
|
|
|
{
|
|
|
|
close(fd);
|
|
|
|
fd = -1;
|
|
|
|
}
|
|
|
|
free(socket_path);
|
|
|
|
return fd;
|
|
|
|
}
|
2017-06-03 09:33:58 -07:00
|
|
|
#endif
|
2017-05-25 03:26:41 -07:00
|
|
|
|
|
|
|
static int
|
|
|
|
_listening_tcp_socket_create()
|
|
|
|
{
|
|
|
|
struct sockaddr_in server;
|
2017-05-27 10:44:50 -07:00
|
|
|
int curstate = 1;
|
2017-05-25 03:26:41 -07:00
|
|
|
// create the socket
|
|
|
|
int fd = socket(AF_INET, 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;
|
|
|
|
|
|
|
|
//Prepare the sockaddr_in structure
|
2017-05-30 06:04:24 -07:00
|
|
|
memset(&server, 0, sizeof(server));
|
2017-05-25 03:26:41 -07:00
|
|
|
server.sin_family = AF_INET;
|
|
|
|
inet_pton(AF_INET, "127.0.0.1", &server.sin_addr.s_addr);
|
|
|
|
server.sin_port = htons(REMOTE_SERVER_PORT);
|
|
|
|
|
|
|
|
if (bind(fd, (struct sockaddr *)&server, sizeof(server)) < 0)
|
2016-11-26 21:48:10 -08:00
|
|
|
{
|
|
|
|
perror("ERROR on binding");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
listen(fd, 5);
|
|
|
|
return fd;
|
|
|
|
err:
|
|
|
|
if (fd >= 0) close(fd);
|
|
|
|
return -1;
|
|
|
|
}
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
static Eina_Bool
|
|
|
|
_server_launch()
|
|
|
|
{
|
2017-06-04 06:11:16 -07:00
|
|
|
#ifndef _WIN32
|
2016-11-26 21:48:10 -08:00
|
|
|
struct epoll_event event = {0};
|
2017-05-25 03:26:41 -07:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
_epfd = epoll_create (MAX_EVENTS);
|
|
|
|
|
2017-05-25 03:26:41 -07:00
|
|
|
_listening_unix_fd = _listening_unix_socket_create();
|
|
|
|
if (_listening_unix_fd <= 0) goto err;
|
|
|
|
event.data.fd = _listening_unix_fd;
|
2016-11-26 21:48:10 -08:00
|
|
|
event.events = EPOLLIN;
|
2017-05-25 03:26:41 -07:00
|
|
|
epoll_ctl (_epfd, EPOLL_CTL_ADD, _listening_unix_fd, &event);
|
|
|
|
|
|
|
|
_listening_tcp_fd = _listening_tcp_socket_create();
|
|
|
|
if (_listening_tcp_fd <= 0) goto err;
|
|
|
|
event.data.fd = _listening_tcp_fd;
|
2016-11-26 21:48:10 -08:00
|
|
|
event.events = EPOLLIN;
|
2017-05-25 03:26:41 -07:00
|
|
|
epoll_ctl (_epfd, EPOLL_CTL_ADD, _listening_tcp_fd, &event);
|
2016-11-26 21:48:10 -08:00
|
|
|
return EINA_TRUE;
|
|
|
|
err:
|
2017-05-25 03:26:41 -07:00
|
|
|
if (_listening_unix_fd >= 0) close(_listening_unix_fd);
|
|
|
|
_listening_unix_fd = -1;
|
|
|
|
if (_listening_tcp_fd >= 0) close(_listening_tcp_fd);
|
|
|
|
_listening_tcp_fd = -1;
|
2017-06-04 06:11:16 -07:00
|
|
|
#endif
|
2016-11-26 21:48:10 -08:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
|
|
|
|
{
|
|
|
|
eina_debug_disable();
|
|
|
|
eina_init();
|
|
|
|
ecore_init();
|
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
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
_server_launch();
|
|
|
|
_monitor();
|
2015-05-04 19:35:16 -07:00
|
|
|
|
|
|
|
ecore_shutdown();
|
|
|
|
eina_shutdown();
|
2016-11-25 13:39:01 -08:00
|
|
|
|
2016-11-26 21:48:10 -08:00
|
|
|
return 0;
|
2015-05-04 19:35:16 -07:00
|
|
|
}
|