forked from enlightenment/efl
529 lines
13 KiB
C
529 lines
13 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <signal.h>
|
|
|
|
#include "evas_cs.h"
|
|
|
|
#ifdef EVAS_CSERVE
|
|
|
|
static Server *cserve = NULL;
|
|
static int csrve_init = 0;
|
|
static int connect_num = 0;
|
|
static int cserve_discon = 0;
|
|
|
|
static void
|
|
pipe_handler(int x __UNUSED__, siginfo_t *info __UNUSED__, void *data __UNUSED__)
|
|
{
|
|
}
|
|
|
|
static void
|
|
pipe_handle(int push)
|
|
{
|
|
static struct sigaction old_action;
|
|
struct sigaction action;
|
|
|
|
if (push)
|
|
{
|
|
action.sa_handler = NULL;
|
|
action.sa_sigaction = pipe_handler;
|
|
action.sa_flags = SA_RESTART | SA_SIGINFO;
|
|
sigemptyset(&action.sa_mask);
|
|
sigaction(SIGPIPE, &action, &old_action);
|
|
}
|
|
else
|
|
{
|
|
sigaction(SIGPIPE, &old_action, &action);
|
|
}
|
|
}
|
|
|
|
static Server *
|
|
server_connect(void)
|
|
{
|
|
Server *s;
|
|
char buf[PATH_MAX];
|
|
int curstate = 0;
|
|
struct sockaddr_un socket_unix;
|
|
int socket_unix_len;
|
|
|
|
s = calloc(1, sizeof(Server));
|
|
if (!s) return NULL;
|
|
s->ch[0].fd = -1;
|
|
s->ch[1].fd = -1;
|
|
snprintf(buf, sizeof(buf), "/tmp/.evas-cserve-%x", getuid());
|
|
s->socket_path = strdup(buf);
|
|
if (!s->socket_path)
|
|
{
|
|
free(s);
|
|
return NULL;
|
|
}
|
|
s->ch[0].fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
if (s->ch[0].fd < 0) goto error;
|
|
if (fcntl(s->ch[0].fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
|
|
if (setsockopt(s->ch[0].fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0)
|
|
goto error;
|
|
socket_unix.sun_family = AF_UNIX;
|
|
strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
|
|
socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
|
|
if (connect(s->ch[0].fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0) goto error;
|
|
|
|
s->ch[1].fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
if (s->ch[1].fd < 0) goto error;
|
|
if (fcntl(s->ch[1].fd, F_SETFD, FD_CLOEXEC) < 0) goto error;
|
|
if (setsockopt(s->ch[1].fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0)
|
|
goto error;
|
|
socket_unix.sun_family = AF_UNIX;
|
|
strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
|
|
socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
|
|
if (connect(s->ch[1].fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0) goto error;
|
|
|
|
return s;
|
|
error:
|
|
if (s->ch[0].fd >= 0) close(s->ch[0].fd);
|
|
if (s->ch[1].fd >= 0) close(s->ch[1].fd);
|
|
free(s->socket_path);
|
|
free(s);
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
server_disconnect(Server *s)
|
|
{
|
|
close(s->ch[0].fd);
|
|
close(s->ch[1].fd);
|
|
free(s->socket_path);
|
|
free(s);
|
|
}
|
|
|
|
static int
|
|
server_send(Server *s, int channel, int opcode, int size, unsigned char *data)
|
|
{
|
|
int ints[3];
|
|
int num;
|
|
|
|
pipe_handle(1);
|
|
ints[0] = size;
|
|
ints[1] = opcode;
|
|
s->ch[channel].req_to++;
|
|
ints[2] = s->ch[channel].req_to;
|
|
num = write(s->ch[channel].fd, ints, (sizeof(int) * 3));
|
|
if (num < 0)
|
|
{
|
|
pipe_handle(0);
|
|
if (cserve) server_disconnect(cserve);
|
|
cserve = NULL;
|
|
return 0;
|
|
}
|
|
num = write(s->ch[channel].fd, data, size);
|
|
if (num < 0)
|
|
{
|
|
pipe_handle(0);
|
|
if (cserve) server_disconnect(cserve);
|
|
cserve = NULL;
|
|
return 0;
|
|
}
|
|
pipe_handle(0);
|
|
return 1;
|
|
}
|
|
|
|
static unsigned char *
|
|
server_read(Server *s, int channel, int *opcode, int *size)
|
|
{
|
|
int ints[3], num, left;
|
|
unsigned char *data;
|
|
|
|
num = read(s->ch[channel].fd, ints, sizeof(int) * 3);
|
|
if (num != (sizeof(int) * 3))
|
|
{
|
|
if (cserve) server_disconnect(cserve);
|
|
cserve = NULL;
|
|
return NULL;
|
|
}
|
|
*size = ints[0];
|
|
*opcode = ints[1];
|
|
if ((*size < 0) || (*size > (1024 * 1024))) return NULL;
|
|
if (ints[2] != (s->ch[channel].req_from + 1))
|
|
{
|
|
ERR("EEK! sequence number mismatch from serer with pid: %i. "
|
|
"---- num %i is not 1 more than %i"
|
|
,
|
|
s->pid, ints[2], s->ch[channel].req_from);
|
|
return NULL;
|
|
}
|
|
s->ch[channel].req_from++;
|
|
data = malloc(*size);
|
|
if (!data) return NULL;
|
|
num = read(s->ch[channel].fd, data, *size);
|
|
if (num < 0)
|
|
{
|
|
free(data);
|
|
return NULL;
|
|
}
|
|
left = *size - num;
|
|
while (left > 0)
|
|
{
|
|
num = read(s->ch[channel].fd, data + (*size - left), left);
|
|
if (num < 0)
|
|
{
|
|
free(data);
|
|
return NULL;
|
|
}
|
|
left -= num;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
static int
|
|
server_init(Server *s)
|
|
{
|
|
Op_Init msg, *rep;
|
|
int opcode;
|
|
int size;
|
|
|
|
msg.pid = getpid();
|
|
msg.server_id = 0;
|
|
msg.handle = NULL;
|
|
if (!server_send(s, 0, OP_INIT, sizeof(msg), (unsigned char *)(&msg)))
|
|
return 0;
|
|
rep = (Op_Init *)server_read(s, 0, &opcode, &size);
|
|
if ((rep) && (opcode == OP_INIT) && (size == sizeof(Op_Init)))
|
|
{
|
|
s->pid = rep->pid;
|
|
s->server_id = rep->server_id;
|
|
s->main_handle = rep->handle;
|
|
connect_num++;
|
|
msg.pid = getpid();
|
|
msg.server_id = 1;
|
|
msg.handle = rep->handle;
|
|
free(rep);
|
|
if (!server_send(s, 1, OP_INIT, sizeof(msg), (unsigned char *)(&msg)))
|
|
return 0;
|
|
rep = (Op_Init *)server_read(s, 1, &opcode, &size);
|
|
if ((rep) && (opcode == OP_INIT) && (size == sizeof(Op_Init)))
|
|
{
|
|
free(rep);
|
|
return 1;
|
|
}
|
|
if (rep) free(rep);
|
|
return 0;
|
|
}
|
|
if (rep) free(rep);
|
|
return 0;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
evas_cserve_init(void)
|
|
{
|
|
csrve_init++;
|
|
if (cserve) return 1;
|
|
cserve = server_connect();
|
|
if (!cserve) return 0;
|
|
if (!server_init(cserve))
|
|
{
|
|
if (cserve) server_disconnect(cserve);
|
|
cserve = NULL;
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
EAPI int
|
|
evas_cserve_use_get(void)
|
|
{
|
|
return csrve_init;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
evas_cserve_have_get(void)
|
|
{
|
|
if (cserve) return 1;
|
|
return 0;
|
|
}
|
|
|
|
EAPI void
|
|
evas_cserve_shutdown(void)
|
|
{
|
|
csrve_init--;
|
|
if (csrve_init > 0) return;
|
|
if (!cserve) return;
|
|
server_disconnect(cserve);
|
|
cserve = NULL;
|
|
}
|
|
|
|
EAPI void
|
|
evas_cserve_discon(void)
|
|
{
|
|
if (cserve)
|
|
{
|
|
server_disconnect(cserve);
|
|
cserve = NULL;
|
|
cserve_discon = 1;
|
|
}
|
|
}
|
|
|
|
static void
|
|
server_reinit(void)
|
|
{
|
|
if (cserve) return;
|
|
if (cserve_discon) return;
|
|
cserve = server_connect();
|
|
if (cserve)
|
|
{
|
|
if (!server_init(cserve))
|
|
{
|
|
if (cserve) server_disconnect(cserve);
|
|
cserve = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
evas_cserve_image_load(Image_Entry *ie, const char *file, const char *key, RGBA_Image_Loadopts *lopt)
|
|
{
|
|
Op_Load msg;
|
|
Op_Load_Reply *rep;
|
|
unsigned char *buf;
|
|
char fbuf[PATH_MAX], wdb[PATH_MAX];
|
|
int flen, klen;
|
|
int opcode;
|
|
int size;
|
|
|
|
if (csrve_init > 0) server_reinit();
|
|
else return 0;
|
|
if (!cserve) return 0;
|
|
if (!key) key = "";
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.lopt.scale_down_by = lopt->scale_down_by;
|
|
msg.lopt.dpi = lopt->dpi;
|
|
msg.lopt.w = lopt->w;
|
|
msg.lopt.h = lopt->h;
|
|
msg.lopt.region.x = lopt->region.x;
|
|
msg.lopt.region.y = lopt->region.y;
|
|
msg.lopt.region.w = lopt->region.w;
|
|
msg.lopt.region.h = lopt->region.h;
|
|
msg.lopt.orientation = lopt->orientation;
|
|
if (file[0] != '/')
|
|
{
|
|
if (getcwd(wdb, sizeof(wdb)))
|
|
{
|
|
snprintf(fbuf, sizeof(buf), "%s/%s", wdb, file);
|
|
file = fbuf;
|
|
}
|
|
}
|
|
if (!realpath(file, wdb)) file = wdb;
|
|
flen = strlen(file) + 1;
|
|
klen = strlen(key) + 1;
|
|
buf = malloc(sizeof(msg) + flen + klen);
|
|
if (!buf) return 0;
|
|
memcpy(buf, &msg, sizeof(msg));
|
|
memcpy(buf + sizeof(msg), file, flen);
|
|
memcpy(buf + sizeof(msg) + flen, key, klen);
|
|
if (!server_send(cserve, ie->channel, OP_LOAD,
|
|
sizeof(msg) + flen + klen,
|
|
buf))
|
|
{
|
|
free(buf);
|
|
return 0;
|
|
}
|
|
free(buf);
|
|
if (!cserve) return 0;
|
|
rep = (Op_Load_Reply *)server_read(cserve, ie->channel, &opcode, &size);
|
|
if ((rep) && (opcode == OP_LOAD) && (size == sizeof(Op_Load_Reply)))
|
|
{
|
|
ie->w = rep->image.w;
|
|
ie->h = rep->image.h;
|
|
ie->flags.alpha = rep->image.alpha;
|
|
ie->data1 = rep->handle;
|
|
}
|
|
if (rep) free(rep);
|
|
if (!ie->data1) return 0;
|
|
ie->connect_num = connect_num;
|
|
if (cserve)
|
|
ie->server_id = cserve->server_id;
|
|
return 1;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
evas_cserve_image_data_load(Image_Entry *ie)
|
|
{
|
|
Op_Loaddata msg;
|
|
Op_Loaddata_Reply *rep;
|
|
int opcode;
|
|
int size;
|
|
if (csrve_init > 0) server_reinit();
|
|
else return 0;
|
|
if (!cserve) return 0;
|
|
if (!ie->data1) return 0;
|
|
if (cserve->server_id != ie->server_id)
|
|
{
|
|
ie->data1 = NULL;
|
|
if (!evas_cserve_image_load(ie, ie->file, ie->key, &(ie->load_opts)))
|
|
return 0;
|
|
}
|
|
if (ie->connect_num != connect_num) return 0;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.handle = ie->data1;
|
|
msg.server_id = cserve->server_id;
|
|
if (!server_send(cserve, ie->channel, OP_LOADDATA, sizeof(msg), (unsigned char *)(&msg)))
|
|
return 0;
|
|
if (!cserve) return 0;
|
|
rep = (Op_Loaddata_Reply *)server_read(cserve, ie->channel, &opcode, &size);
|
|
if ((rep) && (opcode == OP_LOADDATA) && (size == sizeof(Op_Loaddata_Reply)))
|
|
{
|
|
if (rep->mem.size <= 0)
|
|
{
|
|
free(rep);
|
|
return 0;
|
|
}
|
|
ie->data2 = evas_cserve_mem_open(cserve->pid, rep->mem.id, NULL, rep->mem.size, 0);
|
|
free(rep);
|
|
return 1;
|
|
}
|
|
if (rep) free(rep);
|
|
return 0;
|
|
}
|
|
|
|
EAPI void
|
|
evas_cserve_image_free(Image_Entry *ie)
|
|
{
|
|
Op_Unload msg;
|
|
|
|
if (csrve_init > 0) server_reinit();
|
|
else return;
|
|
if (!cserve) return;
|
|
if (!ie->data1) return;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.handle = ie->data1;
|
|
msg.server_id = cserve->server_id;
|
|
if (ie->data2) evas_cserve_image_unload(ie);
|
|
if (cserve)
|
|
{
|
|
if (ie->connect_num == connect_num)
|
|
{
|
|
if (ie->server_id == cserve->server_id)
|
|
server_send(cserve, ie->channel, OP_UNLOAD, sizeof(msg), (unsigned char *)(&msg));
|
|
}
|
|
}
|
|
ie->data1 = NULL;
|
|
ie->data2 = NULL;
|
|
}
|
|
|
|
EAPI void
|
|
evas_cserve_image_unload(Image_Entry *ie)
|
|
{
|
|
Op_Unloaddata msg;
|
|
|
|
if (csrve_init > 0) server_reinit();
|
|
else return;
|
|
if (!cserve) return;
|
|
if (!ie->data1) return;
|
|
if (ie->connect_num != connect_num) return;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.handle = ie->data1;
|
|
msg.server_id = cserve->server_id;
|
|
if (ie->data2) evas_cserve_mem_close(ie->data2);
|
|
ie->data2 = NULL;
|
|
if (ie->connect_num == connect_num)
|
|
{
|
|
if (ie->server_id == cserve->server_id)
|
|
server_send(cserve, ie->channel, OP_UNLOADDATA, sizeof(msg), (unsigned char *)(&msg));
|
|
}
|
|
}
|
|
|
|
EAPI void
|
|
evas_cserve_image_useless(Image_Entry *ie)
|
|
{
|
|
Op_Unloaddata msg;
|
|
|
|
if (csrve_init > 0) server_reinit();
|
|
else return;
|
|
if (!cserve) return;
|
|
if (!ie->data1) return;
|
|
if (ie->connect_num != connect_num) return;
|
|
memset(&msg, 0, sizeof(msg));
|
|
msg.handle = ie->data1;
|
|
msg.server_id = cserve->server_id;
|
|
if (ie->data2) evas_cserve_mem_close(ie->data2);
|
|
ie->data2 = NULL;
|
|
if (ie->connect_num == connect_num)
|
|
{
|
|
if (ie->server_id == cserve->server_id)
|
|
server_send(cserve, ie->channel, OP_USELESSDATA, sizeof(msg), (unsigned char *)(&msg));
|
|
}
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
evas_cserve_raw_config_get(Op_Getconfig_Reply *config)
|
|
{
|
|
Op_Getconfig_Reply *rep;
|
|
int opcode;
|
|
int size;
|
|
if (csrve_init > 0) server_reinit();
|
|
else return 0;
|
|
if (!cserve) return 0;
|
|
if (!server_send(cserve, 0, OP_GETCONFIG, 0, NULL)) return 0;
|
|
rep = (Op_Getconfig_Reply *)server_read(cserve, 0, &opcode, &size);
|
|
if ((rep) && (opcode == OP_GETCONFIG) && (size == sizeof(Op_Getconfig_Reply)))
|
|
{
|
|
memcpy(config, rep, sizeof(Op_Getconfig_Reply));
|
|
free(rep);
|
|
return 1;
|
|
}
|
|
if (rep) free(rep);
|
|
return 0;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
evas_cserve_raw_config_set(Op_Setconfig *config)
|
|
{
|
|
if (csrve_init > 0) server_reinit();
|
|
else return 0;
|
|
if (!cserve) return 0;
|
|
if (!server_send(cserve, 0, OP_SETCONFIG, sizeof(Op_Setconfig), (unsigned char *)config)) return 0;
|
|
return 1;
|
|
}
|
|
|
|
EAPI Eina_Bool
|
|
evas_cserve_raw_stats_get(Op_Getstats_Reply *stats)
|
|
{
|
|
Op_Getstats_Reply *rep;
|
|
int opcode;
|
|
int size;
|
|
if (csrve_init > 0) server_reinit();
|
|
else return 0;
|
|
if (!cserve) return 0;
|
|
if (!server_send(cserve, 0, OP_GETSTATS, 0, NULL)) return 0;
|
|
rep = (Op_Getstats_Reply *)server_read(cserve, 0, &opcode, &size);
|
|
if ((rep) && (opcode == OP_GETSTATS) && (size == sizeof(Op_Getstats_Reply)))
|
|
{
|
|
memcpy(stats, rep, sizeof(Op_Getstats_Reply));
|
|
free(rep);
|
|
return 1;
|
|
}
|
|
if (rep) free(rep);
|
|
return 0;
|
|
}
|
|
|
|
EAPI Op_Getinfo_Reply *
|
|
evas_cserve_raw_info_get(void)
|
|
{
|
|
Op_Getinfo_Reply *rep;
|
|
int opcode;
|
|
int size;
|
|
if (csrve_init > 0) server_reinit();
|
|
else return NULL;
|
|
if (!cserve) return NULL;
|
|
if (!server_send(cserve, 0, OP_GETINFO, 0, NULL)) return NULL;
|
|
rep = (Op_Getinfo_Reply *)server_read(cserve, 0, &opcode, &size);
|
|
if ((rep) && (opcode == OP_GETINFO) &&
|
|
(size >= (int)sizeof(Op_Getinfo_Reply)))
|
|
{
|
|
return rep;
|
|
}
|
|
if (rep) free(rep);
|
|
return NULL;
|
|
}
|
|
|
|
#endif
|