#ifdef HAVE_CONFIG_H # include "config.h" #endif #include #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