efl/legacy/evas/src/lib/cserve/evas_cs_client.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