forked from enlightenment/efl
Eina Debug: rewrite efl_debugd for portability
The previous version of the daemon was using functions specific to Linux, such as epoll... The daemon communication part has been rewritten to use Ecore functionalities. Sorry for the inconvenience guys
This commit is contained in:
parent
0e947166aa
commit
ae50dec3e5
|
@ -20,29 +20,41 @@
|
||||||
# include <config.h>
|
# include <config.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <unistd.h>
|
#define EFL_BETA_API_SUPPORT 1
|
||||||
#ifdef HAVE_SYS_EPOLL_H
|
#define EFL_EO_API_SUPPORT 1
|
||||||
# include <sys/epoll.h>
|
|
||||||
#endif
|
|
||||||
#include <sys/types.h>
|
|
||||||
#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
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include "eina_debug_private.h"
|
#include "eina_debug_private.h"
|
||||||
|
|
||||||
#include <Eina.h>
|
#include <Eina.h>
|
||||||
#include <Ecore.h>
|
#include <Ecore.h>
|
||||||
|
#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__)
|
||||||
|
|
||||||
|
#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__)
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
#define SWAP_64(x) x
|
#define SWAP_64(x) x
|
||||||
#define SWAP_32(x) x
|
#define SWAP_32(x) x
|
||||||
|
@ -69,10 +81,10 @@ typedef struct _Client Client;
|
||||||
|
|
||||||
struct _Client
|
struct _Client
|
||||||
{
|
{
|
||||||
|
Eo * client;
|
||||||
Eina_Stringshare *app_name;
|
Eina_Stringshare *app_name;
|
||||||
|
|
||||||
int version;
|
int version;
|
||||||
int fd;
|
|
||||||
int cid;
|
int cid;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
|
@ -81,6 +93,9 @@ struct _Client
|
||||||
};
|
};
|
||||||
|
|
||||||
static Eina_List *_clients = NULL;
|
static Eina_List *_clients = NULL;
|
||||||
|
static int _retval;
|
||||||
|
|
||||||
|
static Eo *_local_server = NULL, *_remote_server = NULL;
|
||||||
|
|
||||||
typedef Eina_Bool (*Opcode_Cb)(Client *client, void *buffer, int size);
|
typedef Eina_Bool (*Opcode_Cb)(Client *client, void *buffer, int size);
|
||||||
|
|
||||||
|
@ -104,11 +119,6 @@ typedef struct
|
||||||
#define MAX_OPCODES 1000
|
#define MAX_OPCODES 1000
|
||||||
Opcode_Information *_opcodes[MAX_OPCODES];
|
Opcode_Information *_opcodes[MAX_OPCODES];
|
||||||
|
|
||||||
/* epoll stuff */
|
|
||||||
#ifndef _WIN32
|
|
||||||
static int _epfd = -1, _listening_unix_fd = -1, _listening_tcp_fd = -1;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static Client *
|
static Client *
|
||||||
_client_find_by_cid(int cid)
|
_client_find_by_cid(int cid)
|
||||||
{
|
{
|
||||||
|
@ -129,54 +139,48 @@ _client_find_by_pid(int pid)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 void
|
static void
|
||||||
_send(Client *dest, int opcode, void *payload, int payload_size)
|
_send(Client *dest, int opcode, void *payload, int payload_size)
|
||||||
{
|
{
|
||||||
|
Eina_Error err;
|
||||||
|
Eina_Slice s, r;
|
||||||
|
Eina_Debug_Packet_Header hdr;
|
||||||
int size = sizeof(Eina_Debug_Packet_Header) + payload_size;
|
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 = SWAP_32(size);
|
||||||
hdr->size = SWAP_32(size);
|
hdr.cid = 0;
|
||||||
hdr->cid = 0;
|
hdr.opcode = SWAP_32(opcode);
|
||||||
hdr->opcode = SWAP_32(opcode);
|
|
||||||
memcpy(buf + sizeof(Eina_Debug_Packet_Header), payload, payload_size);
|
s.mem = &hdr;
|
||||||
printf("Send packet (size = %d, opcode %s) to %s\n", size,
|
s.len = sizeof(hdr);
|
||||||
_opcodes[hdr->opcode]->opcode_string,
|
|
||||||
|
err = efl_io_writer_write(dest->client, &s, &r);
|
||||||
|
if (err || r.len) goto end;
|
||||||
|
|
||||||
|
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);
|
dest->app_name);
|
||||||
if (send(dest->fd, buf, size, 0) != size) perror("send");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
end:
|
||||||
_client_del(Client *c)
|
if (err)
|
||||||
{
|
|
||||||
Client *c2;
|
|
||||||
if (!c) return;
|
|
||||||
Eina_List *itr;
|
|
||||||
|
|
||||||
_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)
|
|
||||||
{
|
{
|
||||||
int cid = SWAP_32(c->cid);
|
fprintf(stderr, "ERROR: could not queue message '%d': %s\n", opcode, eina_error_msg_get(err));
|
||||||
if (c2->cl_stat_obs) _send(c2, _slave_deleted_opcode, &cid, sizeof(int));
|
}
|
||||||
|
|
||||||
|
if (r.len)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "ERROR: could not queue message '%d': out of memory\n", opcode);
|
||||||
}
|
}
|
||||||
free(c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Eina_Bool
|
static Eina_Bool
|
||||||
_dispatch(Client *src, void *buffer, unsigned int size)
|
_dispatch(Client *src, void *buffer)
|
||||||
{
|
{
|
||||||
Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)buffer;
|
Eina_Debug_Packet_Header *hdr = (Eina_Debug_Packet_Header *)buffer;
|
||||||
if (hdr->cid)
|
if (hdr->cid)
|
||||||
|
@ -187,9 +191,14 @@ _dispatch(Client *src, void *buffer, unsigned int size)
|
||||||
{
|
{
|
||||||
if (dest->is_master != src->is_master)
|
if (dest->is_master != src->is_master)
|
||||||
{
|
{
|
||||||
|
Eina_Slice s;
|
||||||
|
s.mem = buffer;
|
||||||
|
s.len = hdr->size;
|
||||||
hdr->cid = SWAP_32(src->cid);
|
hdr->cid = SWAP_32(src->cid);
|
||||||
if (send(dest->fd, buffer, size, 0) != size) perror("send");
|
hdr->size = SWAP_32(hdr->size);
|
||||||
printf("Transfer of %d bytes from %s(%d) to %s(%d): operation %s\n",
|
hdr->opcode = SWAP_32(hdr->opcode);
|
||||||
|
efl_io_writer_write(dest->client, &s, NULL);
|
||||||
|
INF("Transfer of %d bytes from %s(%d) to %s(%d): operation %s\n",
|
||||||
hdr->size,
|
hdr->size,
|
||||||
src->app_name, src->pid,
|
src->app_name, src->pid,
|
||||||
dest->app_name, dest->pid,
|
dest->app_name, dest->pid,
|
||||||
|
@ -201,16 +210,17 @@ _dispatch(Client *src, void *buffer, unsigned int size)
|
||||||
* Packets Master -> Master or Slave -> Slave are forbidden
|
* Packets Master -> Master or Slave -> Slave are forbidden
|
||||||
* Only Master <-> Slave packets are allowed.
|
* Only Master <-> Slave packets are allowed.
|
||||||
*/
|
*/
|
||||||
printf("Packet from %d to %d: denied (same type)\n", hdr->cid, dest->cid);
|
ERR("Packet from %d to %d: denied (same type)\n", hdr->cid, dest->cid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("Invoke %s\n", _opcodes[hdr->opcode]->opcode_string);
|
INF("Invoke %s\n", _opcodes[hdr->opcode]->opcode_string);
|
||||||
if (_opcodes[hdr->opcode]->cb)
|
if (_opcodes[hdr->opcode]->cb)
|
||||||
return _opcodes[hdr->opcode]->cb(src,
|
return _opcodes[hdr->opcode]->cb(src,
|
||||||
(char *)buffer + sizeof(Eina_Debug_Packet_Header), size - sizeof(Eina_Debug_Packet_Header));
|
(char *)buffer + sizeof(Eina_Debug_Packet_Header),
|
||||||
|
hdr->size - sizeof(Eina_Debug_Packet_Header));
|
||||||
}
|
}
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -238,7 +248,7 @@ _opcode_register(const char *op_name, int op_id, Opcode_Cb cb)
|
||||||
eina_hash_add(_string_to_opcode_hash, op_name, op_info);
|
eina_hash_add(_string_to_opcode_hash, op_name, op_info);
|
||||||
_opcodes[op_id] = op_info;
|
_opcodes[op_id] = op_info;
|
||||||
}
|
}
|
||||||
printf("Register %s -> opcode %d\n", op_name, op_info->opcode);
|
INF("Register %s -> opcode %d\n", op_name, op_info->opcode);
|
||||||
return op_info->opcode;
|
return op_info->opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +271,7 @@ _hello_cb(Client *c, void *buffer, int size)
|
||||||
{
|
{
|
||||||
c->app_name = eina_stringshare_add_length(buf, size);
|
c->app_name = eina_stringshare_add_length(buf, size);
|
||||||
}
|
}
|
||||||
printf("Connection of %s: pid %d - name %s -> cid %d\n",
|
INF("Connection of %s: pid %d - name %s -> cid %d\n",
|
||||||
c->is_master ? "Master" : "Slave",
|
c->is_master ? "Master" : "Slave",
|
||||||
c->pid, c->app_name, c->cid);
|
c->pid, c->app_name, c->cid);
|
||||||
|
|
||||||
|
@ -302,7 +312,7 @@ _cid_get_cb(Client *src, void *buffer, int size EINA_UNUSED)
|
||||||
static Eina_Bool
|
static Eina_Bool
|
||||||
_data_test_cb(Client *src, void *buffer, int size)
|
_data_test_cb(Client *src, void *buffer, int size)
|
||||||
{
|
{
|
||||||
printf("Data test: loop packet of %d bytes\n", size);
|
DBG("Data test: loop packet of %d bytes\n", size);
|
||||||
_send(src, _test_loop_opcode, buffer, size);
|
_send(src, _test_loop_opcode, buffer, size);
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
@ -369,133 +379,150 @@ _opcode_register_cb(Client *src, void *buffer, int size)
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
_data_receive(Client *c, unsigned char *buffer)
|
_client_data(void *data, const Efl_Event *event)
|
||||||
{
|
{
|
||||||
int rret;
|
static unsigned char *buffer = NULL;
|
||||||
unsigned int size = 0;
|
unsigned int size = 0;
|
||||||
|
Eina_Debug_Packet_Header *hdr;
|
||||||
|
Client *c = data;
|
||||||
|
Eina_Slice slice;
|
||||||
|
|
||||||
if (!c) return -1;
|
if (!c) return;
|
||||||
|
|
||||||
rret = recv(c->fd, &size, sizeof(int), MSG_PEEK);
|
if (!buffer) buffer = malloc(EINA_DEBUG_MAX_PACKET_SIZE);
|
||||||
|
|
||||||
if (rret == -1 || !size) goto error;
|
slice = efl_io_buffered_stream_slice_get(c->client);
|
||||||
if (rret == sizeof(int))
|
|
||||||
|
if (slice.len < sizeof(*hdr)) return;
|
||||||
|
|
||||||
|
hdr = (Eina_Debug_Packet_Header *)slice.mem;
|
||||||
|
size = SWAP_32(hdr->size);
|
||||||
|
if (size < sizeof(*hdr)) /* must contain at least the header */
|
||||||
{
|
{
|
||||||
Eina_Debug_Packet_Header *hdr;
|
fprintf(stderr, "ERROR: invalid message header, size=%u\n", hdr->size);
|
||||||
unsigned int cur_packet_size = 0;
|
goto err;
|
||||||
size = SWAP_32(size);
|
|
||||||
if (size > EINA_DEBUG_MAX_PACKET_SIZE) goto error;
|
|
||||||
while (cur_packet_size < size)
|
|
||||||
{
|
|
||||||
rret = recv(c->fd, buffer + cur_packet_size, size - cur_packet_size, 0);
|
|
||||||
if (rret <= 0) goto error;
|
|
||||||
cur_packet_size += rret;
|
|
||||||
}
|
|
||||||
hdr = (Eina_Debug_Packet_Header *) buffer;
|
|
||||||
hdr->size = SWAP_32(hdr->size);
|
|
||||||
hdr->opcode = SWAP_32(hdr->opcode);
|
|
||||||
hdr->cid = SWAP_32(hdr->cid);
|
|
||||||
}
|
}
|
||||||
//printf("%d bytes received from client %s fd %d\n", size, c->app_name, c->fd);
|
|
||||||
return size;
|
if (size > EINA_DEBUG_MAX_PACKET_SIZE)
|
||||||
error:
|
{
|
||||||
if (rret == -1) perror("Read from socket");
|
fprintf(stderr, "ERROR: packet too big (max: %d), size=%u\n",
|
||||||
return -1;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_monitor(void)
|
_client_error(void *data, const Efl_Event *event)
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
Client *c = data;
|
||||||
#define MAX_EVENTS 1000
|
Eina_Error *perr = event->info;
|
||||||
int ret = 0;
|
WRN("client %p [pid: %d] error: %s",
|
||||||
struct epoll_event events[MAX_EVENTS];
|
c, (int)c->pid, eina_error_msg_get(*perr));
|
||||||
unsigned char *buffer = malloc(EINA_DEBUG_MAX_PACKET_SIZE);
|
fprintf(stderr, "INFO: client %p [pid: %d] error: %s\n",
|
||||||
Client *c;
|
c, (int)c->pid, eina_error_msg_get(*perr));
|
||||||
|
}
|
||||||
|
|
||||||
// sit forever processing commands or timeouts
|
static void
|
||||||
for (; ret != -1;)
|
_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
ret = epoll_wait (_epfd, events, MAX_EVENTS, -1);
|
if (c2->cl_stat_obs) _send(c2, _slave_deleted_opcode, &cid, sizeof(int));
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
printf("Closing client %s/%d\n", c->app_name, c->pid);
|
|
||||||
_client_del(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (events[i].events & EPOLLIN)
|
|
||||||
{
|
|
||||||
// Someone wants to connect
|
|
||||||
if(events[i].data.fd == _listening_unix_fd || events[i].data.fd == _listening_tcp_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_tcp_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;
|
|
||||||
}
|
|
||||||
|
|
||||||
c = _client_find_by_fd(events[i].data.fd);
|
|
||||||
if (c)
|
|
||||||
{
|
|
||||||
int size;
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// major failure on debug daemon control fd - get out of here.
|
|
||||||
// else goto fail;
|
|
||||||
close(events[i].data.fd);
|
|
||||||
_client_del(c);
|
|
||||||
//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
|
|
||||||
}
|
}
|
||||||
free(buffer);
|
free(c);
|
||||||
#endif
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
|
@ -514,127 +541,134 @@ _socket_home_get(void)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
static Eina_Bool
|
||||||
#define LENGTH_OF_SOCKADDR_UN(s) \
|
_local_server_create(void)
|
||||||
(strlen((s)->sun_path) + (size_t)(((struct sockaddr_un *)NULL)->sun_path))
|
|
||||||
static int
|
|
||||||
_listening_unix_socket_create(void)
|
|
||||||
{
|
{
|
||||||
char buf[1048];
|
Eo *loop;
|
||||||
struct sockaddr_un socket_unix;
|
Eina_Error err;
|
||||||
int socket_unix_len, curstate = 0;
|
|
||||||
char *socket_path = _socket_home_get();
|
char *socket_path = _socket_home_get();
|
||||||
mode_t mask = 0;
|
mode_t mask = 0;
|
||||||
// create the socket
|
char path[512];
|
||||||
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
Eina_Bool ret = EINA_FALSE;
|
Eina_Bool ret = EINA_FALSE;
|
||||||
|
|
||||||
if (fd < 0) goto end;
|
snprintf(path, sizeof(path) - 1, "%s/%s", socket_path, LOCAL_SERVER_PATH);
|
||||||
// set the socket to close when we exec things so they don't inherit it
|
if (mkdir(path, S_IRWXU) < 0 && errno != EEXIST)
|
||||||
if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) goto end;
|
|
||||||
// set up some socket options on addr re-use
|
|
||||||
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate,
|
|
||||||
sizeof(curstate)) < 0)
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf) - 1, "%s/%s", socket_path, LOCAL_SERVER_PATH);
|
|
||||||
if (mkdir(buf, S_IRWXU) < 0 && errno != EEXIST)
|
|
||||||
{
|
{
|
||||||
perror("mkdir SERVER_PATH");
|
perror("mkdir SERVER_PATH");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
snprintf(buf, sizeof(buf) - 1, "%s/%s/%s", socket_path, LOCAL_SERVER_PATH, LOCAL_SERVER_NAME);
|
snprintf(path, sizeof(path) - 1, "%s/%s/%s", socket_path, LOCAL_SERVER_PATH, LOCAL_SERVER_NAME);
|
||||||
if (mkdir(buf, S_IRWXU) < 0 && errno != EEXIST)
|
if (mkdir(path, S_IRWXU) < 0 && errno != EEXIST)
|
||||||
{
|
{
|
||||||
perror("mkdir SERVER_NAME");
|
perror("mkdir SERVER_NAME");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
mask = umask(S_IRWXG | S_IRWXO);
|
mask = umask(S_IRWXG | S_IRWXO);
|
||||||
snprintf(buf, sizeof(buf) - 1, "%s/%s/%s/%i", socket_path,
|
snprintf(path, sizeof(path) - 1, "%s/%s/%s/%i", socket_path,
|
||||||
LOCAL_SERVER_PATH, LOCAL_SERVER_NAME, LOCAL_SERVER_PORT);
|
LOCAL_SERVER_PATH, LOCAL_SERVER_NAME, LOCAL_SERVER_PORT);
|
||||||
// sa that it's a unix socket and where the path is
|
|
||||||
socket_unix.sun_family = AF_UNIX;
|
loop = ecore_main_loop_get();
|
||||||
strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path) - 1);
|
|
||||||
socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
|
#ifdef EFL_NET_SERVER_UNIX_CLASS
|
||||||
unlink(socket_unix.sun_path);
|
_local_server = efl_add(EFL_NET_SERVER_SIMPLE_CLASS, loop,
|
||||||
if (bind(fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
|
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)
|
||||||
{
|
{
|
||||||
perror("ERROR on binding");
|
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));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
listen(fd, 5);
|
|
||||||
ret = EINA_TRUE;
|
ret = EINA_TRUE;
|
||||||
end:
|
end:
|
||||||
umask(mask);
|
umask(mask);
|
||||||
if (!ret && fd >= 0)
|
if (!ret)
|
||||||
{
|
{
|
||||||
close(fd);
|
efl_del(_local_server);
|
||||||
fd = -1;
|
_local_server = NULL;
|
||||||
}
|
}
|
||||||
free(socket_path);
|
free(socket_path);
|
||||||
return fd;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
static int
|
static Eina_Bool
|
||||||
_listening_tcp_socket_create(void)
|
_remote_server_create(void)
|
||||||
{
|
{
|
||||||
struct sockaddr_in server;
|
Eo *loop;
|
||||||
int curstate = 1;
|
Eina_Error err;
|
||||||
// create the socket
|
mode_t mask = 0;
|
||||||
int fd = socket(AF_INET, SOCK_STREAM, 0);
|
Eina_Bool ret = EINA_FALSE;
|
||||||
if (fd < 0) goto err;
|
char address[256];
|
||||||
// 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
|
loop = ecore_main_loop_get();
|
||||||
memset(&server, 0, sizeof(server));
|
|
||||||
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)
|
_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)
|
||||||
{
|
{
|
||||||
perror("ERROR on binding");
|
fprintf(stderr, "ERROR: could not create communication server\n");
|
||||||
goto err;
|
goto end;
|
||||||
}
|
}
|
||||||
listen(fd, 5);
|
|
||||||
return fd;
|
{
|
||||||
err:
|
Eo *inner_server = efl_net_server_simple_inner_server_get(_remote_server);
|
||||||
if (fd >= 0) close(fd);
|
efl_net_server_fd_close_on_exec_set(inner_server, EINA_TRUE);
|
||||||
return -1;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Eina_Bool
|
static Eina_Bool
|
||||||
_server_launch(void)
|
_server_launch(void)
|
||||||
{
|
{
|
||||||
#ifndef _WIN32
|
if (_local_server_create() <= 0) goto err;
|
||||||
struct epoll_event event = {0};
|
if (_remote_server_create() <= 0) goto err;
|
||||||
|
|
||||||
_epfd = epoll_create (MAX_EVENTS);
|
|
||||||
|
|
||||||
_listening_unix_fd = _listening_unix_socket_create();
|
|
||||||
if (_listening_unix_fd <= 0) goto err;
|
|
||||||
event.data.fd = _listening_unix_fd;
|
|
||||||
event.events = EPOLLIN;
|
|
||||||
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;
|
|
||||||
event.events = EPOLLIN;
|
|
||||||
epoll_ctl (_epfd, EPOLL_CTL_ADD, _listening_tcp_fd, &event);
|
|
||||||
return EINA_TRUE;
|
return EINA_TRUE;
|
||||||
err:
|
err:
|
||||||
if (_listening_unix_fd >= 0) close(_listening_unix_fd);
|
efl_del(_local_server);
|
||||||
_listening_unix_fd = -1;
|
efl_del(_remote_server);
|
||||||
if (_listening_tcp_fd >= 0) close(_listening_tcp_fd);
|
|
||||||
_listening_tcp_fd = -1;
|
|
||||||
#endif
|
|
||||||
return EINA_FALSE;
|
return EINA_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,8 +676,14 @@ int
|
||||||
main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
|
main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
|
||||||
{
|
{
|
||||||
eina_debug_disable();
|
eina_debug_disable();
|
||||||
|
ecore_app_no_system_modules();
|
||||||
|
|
||||||
eina_init();
|
eina_init();
|
||||||
ecore_init();
|
ecore_init();
|
||||||
|
ecore_con_init();
|
||||||
|
|
||||||
|
_retval = EXIT_SUCCESS;
|
||||||
|
_log_dom = eina_log_domain_register("efl_debugd", EINA_COLOR_CYAN);
|
||||||
|
|
||||||
_string_to_opcode_hash = eina_hash_string_superfast_new(NULL);
|
_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/opcode_register", EINA_DEBUG_OPCODE_REGISTER, _opcode_register_cb);
|
||||||
|
@ -654,11 +694,12 @@ main(int argc EINA_UNUSED, char **argv EINA_UNUSED)
|
||||||
_cid_from_pid_opcode = _opcode_register("Daemon/Client/cid_from_pid", EINA_DEBUG_OPCODE_INVALID, _cid_get_cb);
|
_cid_from_pid_opcode = _opcode_register("Daemon/Client/cid_from_pid", EINA_DEBUG_OPCODE_INVALID, _cid_get_cb);
|
||||||
_test_loop_opcode = _opcode_register("Test/data_loop", EINA_DEBUG_OPCODE_INVALID, _data_test_cb);
|
_test_loop_opcode = _opcode_register("Test/data_loop", EINA_DEBUG_OPCODE_INVALID, _data_test_cb);
|
||||||
|
|
||||||
_server_launch();
|
if (_server_launch()) ecore_main_loop_begin();
|
||||||
_monitor();
|
else _retval = EXIT_FAILURE;
|
||||||
|
|
||||||
|
ecore_con_shutdown();
|
||||||
ecore_shutdown();
|
ecore_shutdown();
|
||||||
eina_shutdown();
|
eina_shutdown();
|
||||||
|
|
||||||
return 0;
|
return _retval;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue