#ifdef HAVE_CONFIG_H # include #endif #include #include #include #ifdef HAVE_ARPA_INET_H # include #endif #include #include #include #include "Ecore_Ipc.h" #include "ecore_ipc_private.h" #define DLT_ZERO 0 #define DLT_ONE 1 #define DLT_SAME 2 #define DLT_SHL 3 #define DLT_SHR 4 #define DLT_ADD8 5 #define DLT_DEL8 6 #define DLT_ADDU8 7 #define DLT_DELU8 8 #define DLT_ADD16 9 #define DLT_DEL16 10 #define DLT_ADDU16 11 #define DLT_DELU16 12 #define DLT_SET 13 #define DLT_R1 14 #define DLT_R2 15 static int _ecore_ipc_log_dom = -1; /****** This swap function are around just for backward compatibility do not remove *******/ EAPI unsigned short _ecore_ipc_swap_16(unsigned short v) { return eina_swap16(v); } EAPI unsigned int _ecore_ipc_swap_32(unsigned int v) { return eina_swap32(v); } EAPI unsigned long long _ecore_ipc_swap_64(unsigned long long v) { return eina_swap64(v); } /***********************/ static int _ecore_ipc_dlt_int(int out, int prev, int *mode); static int _ecore_ipc_ddlt_int(int in, int prev, int mode); static int _ecore_ipc_dlt_int(int out, int prev, int *mode) { int dlt; /* 0 byte */ if (out == 0) { *mode = DLT_ZERO; return 0; } if (out == (int)0xffffffff) { *mode = DLT_ONE; return 0; } if (out == prev) { *mode = DLT_SAME; return 0; } if (out == prev << 1) { *mode = DLT_SHL; return 0; } if (out == prev >> 1) { *mode = DLT_SHR; return 0; } /* 1 byte */ dlt = out - prev; if (!(dlt & 0xffffff00)) { *mode = DLT_ADD8; return dlt & 0xff; } dlt = prev - out; if (!(dlt & 0xffffff00)) { *mode = DLT_DEL8; return dlt & 0xff; } dlt = out - prev; if (!(dlt & 0x00ffffff)) { *mode = DLT_ADDU8; return (dlt >> 24) & 0xff; } dlt = prev - out; if (!(dlt & 0x00ffffff)) { *mode = DLT_DELU8; return (dlt >> 24) & 0xff; } /* 2 byte */ dlt = out - prev; if (!(dlt & 0xffff0000)) { *mode = DLT_ADD16; return dlt & 0xffff; } dlt = prev - out; if (!(dlt & 0xffff0000)) { *mode = DLT_DEL16; return dlt & 0xffff; } dlt = out - prev; if (!(dlt & 0x0000ffff)) { *mode = DLT_ADDU16; return (dlt >> 16) & 0xffff; } dlt = prev - out; if (!(dlt & 0x0000ffff)) { *mode = DLT_DELU16; return (dlt >> 16) & 0xffff; } /* 4 byte */ *mode = DLT_SET; return out; } static int _ecore_ipc_ddlt_int(int in, int prev, int mode) { switch (mode) { case DLT_ZERO: return 0; break; case DLT_ONE: return 0xffffffff; break; case DLT_SAME: return prev; break; case DLT_SHL: return prev << 1; break; case DLT_SHR: return prev >> 1; break; case DLT_ADD8: return prev + in; break; case DLT_DEL8: return prev - in; break; case DLT_ADDU8: return prev + (in << 24); break; case DLT_DELU8: return prev - (in << 24); break; case DLT_ADD16: return prev + in; break; case DLT_DEL16: return prev - in; break; case DLT_ADDU16: return prev + (in << 16); break; case DLT_DELU16: return prev - (in << 16); break; case DLT_SET: return in; break; case DLT_R1: return 0; break; case DLT_R2: return 0; break; default: break; } return 0; } /* EFL_NET_SERVER_UNIX_CLASS and EFL_NET_DIALER_UNIX_CLASS should be defined at the same time, we're only checking for EFL_NET_SERVER_UNIX_CLASS in shared blocks */ static void _ecore_ipc_event_client_add_free(void *data, void *ev); static void _ecore_ipc_event_client_del_free(void *data, void *ev); static void _ecore_ipc_event_client_data_free(void *data, void *ev); static void _ecore_ipc_event_server_add_free(void *data, void *ev); static void _ecore_ipc_event_server_del_free(void *data, void *ev); static void _ecore_ipc_event_server_data_free(void *data, void *ev); EAPI int ECORE_IPC_EVENT_CLIENT_ADD = 0; EAPI int ECORE_IPC_EVENT_CLIENT_DEL = 0; EAPI int ECORE_IPC_EVENT_SERVER_ADD = 0; EAPI int ECORE_IPC_EVENT_SERVER_DEL = 0; EAPI int ECORE_IPC_EVENT_CLIENT_DATA = 0; EAPI int ECORE_IPC_EVENT_SERVER_DATA = 0; static int _ecore_ipc_init_count = 0; static Eina_List *servers = NULL; static void ecore_ipc_post_event_server_add(Ecore_Ipc_Server *svr) { Ecore_Ipc_Event_Server_Add *ev; if (svr->delete_me) return; ev = calloc(1, sizeof(Ecore_Ipc_Event_Server_Add)); EINA_SAFETY_ON_NULL_RETURN(ev); svr->event_count++; ev->server = svr; ecore_event_add(ECORE_IPC_EVENT_SERVER_ADD, ev, _ecore_ipc_event_server_add_free, NULL); } static void ecore_ipc_post_event_server_del(Ecore_Ipc_Server *svr) { Ecore_Ipc_Event_Server_Del *ev; if (svr->delete_me) return; ev = calloc(1, sizeof(Ecore_Ipc_Event_Server_Del)); EINA_SAFETY_ON_NULL_RETURN(ev); svr->event_count++; ev->server = svr; ecore_event_add(ECORE_IPC_EVENT_SERVER_DEL, ev, _ecore_ipc_event_server_del_free, NULL); } static void ecore_ipc_post_event_client_add(Ecore_Ipc_Client *cl) { Ecore_Ipc_Event_Client_Add *ev; if (cl->delete_me) return; ev = calloc(1, sizeof(Ecore_Ipc_Event_Client_Add)); EINA_SAFETY_ON_NULL_RETURN(ev); cl->event_count++; ev->client = cl; ecore_event_add(ECORE_IPC_EVENT_CLIENT_ADD, ev, _ecore_ipc_event_client_add_free, NULL); } static void ecore_ipc_post_event_client_del(Ecore_Ipc_Client *cl) { Ecore_Ipc_Event_Client_Del *ev; if (cl->delete_me) return; cl->delete_me = EINA_TRUE; ev = calloc(1, sizeof(Ecore_Ipc_Event_Client_Del)); EINA_SAFETY_ON_NULL_RETURN(ev); cl->event_count++; ev->client = cl; ecore_event_add(ECORE_IPC_EVENT_CLIENT_DEL, ev, _ecore_ipc_event_client_del_free, NULL); } static Ecore_Ipc_Client * ecore_ipc_client_add(Ecore_Ipc_Server *svr) { Ecore_Ipc_Client *cl; cl = calloc(1, sizeof(Ecore_Ipc_Client)); EINA_SAFETY_ON_NULL_RETURN_VAL(cl, NULL); cl->svr = svr; cl->max_buf_size = 32 * 1024; ECORE_MAGIC_SET(cl, ECORE_MAGIC_IPC_CLIENT); svr->clients = eina_list_append(svr->clients, cl); return cl; } EAPI int ecore_ipc_init(void) { if (++_ecore_ipc_init_count != 1) return _ecore_ipc_init_count; _ecore_ipc_log_dom = eina_log_domain_register ("ecore_ipc", ECORE_IPC_DEFAULT_LOG_COLOR); if(_ecore_ipc_log_dom < 0) { EINA_LOG_ERR("Impossible to create a log domain for the Ecore IPC module."); return --_ecore_ipc_init_count; } if (!ecore_con_init()) { eina_log_domain_unregister(_ecore_ipc_log_dom); _ecore_ipc_log_dom = -1; return --_ecore_ipc_init_count; } ECORE_IPC_EVENT_CLIENT_ADD = ecore_event_type_new(); ECORE_IPC_EVENT_CLIENT_DEL = ecore_event_type_new(); ECORE_IPC_EVENT_SERVER_ADD = ecore_event_type_new(); ECORE_IPC_EVENT_SERVER_DEL = ecore_event_type_new(); ECORE_IPC_EVENT_CLIENT_DATA = ecore_event_type_new(); ECORE_IPC_EVENT_SERVER_DATA = ecore_event_type_new(); return _ecore_ipc_init_count; } EAPI int ecore_ipc_shutdown(void) { if (--_ecore_ipc_init_count != 0) return _ecore_ipc_init_count; Eina_List *l, *l2; Ecore_Ipc_Server *svr; EINA_LIST_FOREACH_SAFE(servers, l, l2, svr) ecore_ipc_server_del(svr); ecore_event_type_flush(ECORE_IPC_EVENT_CLIENT_ADD, ECORE_IPC_EVENT_CLIENT_DEL, ECORE_IPC_EVENT_SERVER_ADD, ECORE_IPC_EVENT_SERVER_DEL, ECORE_IPC_EVENT_CLIENT_DATA, ECORE_IPC_EVENT_SERVER_DATA); ecore_con_shutdown(); eina_log_domain_unregister(_ecore_ipc_log_dom); _ecore_ipc_log_dom = -1; return _ecore_ipc_init_count; } static void _ecore_ipc_server_del(Ecore_Ipc_Server *svr) { DBG("server %p del", svr); if (svr->server) { efl_del(svr->server); svr->server = NULL; } } static void _ecore_ipc_server_client_add(void *data, const Efl_Event *event); EFL_CALLBACKS_ARRAY_DEFINE(_ecore_ipc_server_cbs, { EFL_NET_SERVER_EVENT_CLIENT_ADD, _ecore_ipc_server_client_add }); /* FIXME: need to add protocol type parameter */ EAPI Ecore_Ipc_Server * ecore_ipc_server_add(Ecore_Ipc_Type type, const char *name, int port, const void *data) { Ecore_Ipc_Server *svr; Eo *loop = efl_main_loop_get(); char *address = NULL; Eina_Error err; #ifdef EFL_NET_SERVER_UNIX_CLASS Eina_Bool local_system = EINA_FALSE; mode_t old_mask = 0, new_mask = 0; #endif EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); svr = calloc(1, sizeof(Ecore_Ipc_Server)); EINA_SAFETY_ON_NULL_RETURN_VAL(svr, NULL); if (0) { } #ifdef EFL_NET_SERVER_UNIX_CLASS if ((type & ECORE_IPC_TYPE) == ECORE_IPC_LOCAL_USER) { address = ecore_con_local_path_new(EINA_FALSE, name, port); EINA_SAFETY_ON_NULL_GOTO(address, error_server); new_mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH; svr->server = efl_add(EFL_NET_SERVER_UNIX_CLASS, efl_main_loop_get(), efl_net_server_unix_leading_directories_create_set(efl_added, EINA_TRUE, S_IRUSR | S_IWUSR | S_IXUSR)); EINA_SAFETY_ON_NULL_GOTO(svr->server, error_server); } else if ((type & ECORE_IPC_TYPE) == ECORE_IPC_LOCAL_SYSTEM) { address = ecore_con_local_path_new(EINA_TRUE, name, port); EINA_SAFETY_ON_NULL_GOTO(address, error_server); /* ecore_con didn't create leading directories for LOCAL_SYSTEM */ new_mask = 0; local_system = EINA_TRUE; svr->server = efl_add(EFL_NET_SERVER_UNIX_CLASS, efl_main_loop_get()); EINA_SAFETY_ON_NULL_GOTO(svr->server, error_server); } #endif /* EFL_NET_SERVER_UNIX_CLASS */ #ifdef EFL_NET_SERVER_WINDOWS_CLASS if ((type & ECORE_IPC_TYPE) == ECORE_IPC_LOCAL_USER) { address = ecore_con_local_path_new(EINA_FALSE, name, port); EINA_SAFETY_ON_NULL_GOTO(address, error_server); // TODO: specify SECURITY_ATTRIBUTES to use or some // Efl_Net_Server_Windows API to limit access svr->server = efl_add(EFL_NET_SERVER_WINDOWS_CLASS, efl_main_loop_get()); EINA_SAFETY_ON_NULL_GOTO(svr->server, error_server); } else if ((type & ECORE_IPC_TYPE) == ECORE_IPC_LOCAL_SYSTEM) { address = ecore_con_local_path_new(EINA_TRUE, name, port); EINA_SAFETY_ON_NULL_GOTO(address, error_server); // TODO: specify SECURITY_ATTRIBUTES to use or some // Efl_Net_Server_Windows API to limit access svr->server = efl_add(EFL_NET_SERVER_WINDOWS_CLASS, efl_main_loop_get()); EINA_SAFETY_ON_NULL_GOTO(svr->server, error_server); } #endif /* EFL_NET_SERVER_WINDOWS_CLASS */ else if ((type & ECORE_IPC_TYPE) == ECORE_IPC_REMOTE_SYSTEM) { char buf[4096]; if (port <= 0) { ERR("remote system requires port>=0, got %d", port); goto error_server; } snprintf(buf, sizeof(buf), "%s:%d", name, port); address = strdup(buf); EINA_SAFETY_ON_NULL_GOTO(address, error_server); if ((type & ECORE_IPC_USE_SSL) == ECORE_IPC_USE_SSL) { svr->server = efl_add(EFL_NET_SERVER_SSL_CLASS, loop); EINA_SAFETY_ON_NULL_GOTO(svr->server, error_server); } else { svr->server = efl_add(EFL_NET_SERVER_TCP_CLASS, loop); EINA_SAFETY_ON_NULL_GOTO(svr->server, error_server); } } else { ERR("IPC Type must be one of: local_user, local_system or remote_system"); goto error_server; } efl_event_callback_array_add(svr->server, _ecore_ipc_server_cbs(), svr); if (efl_isa(svr->server, EFL_NET_SERVER_FD_CLASS)) { efl_net_server_fd_reuse_address_set(svr->server, EINA_TRUE); efl_net_server_fd_reuse_port_set(svr->server, EINA_TRUE); } if (efl_isa(svr->server, EFL_NET_SERVER_TCP_CLASS)) { /* old ecore_con did not map ipv4 to ipv6... */ efl_net_server_ip_ipv6_only_set(svr->server, EINA_TRUE); } #ifdef EFL_NET_SERVER_UNIX_CLASS if (efl_isa(svr->server, EFL_NET_SERVER_UNIX_CLASS)) { old_mask = umask(new_mask); efl_net_server_unix_leading_directories_create_set(svr->server, EINA_TRUE, local_system ? 0755 : 0700); } #endif err = efl_net_server_serve(svr->server, address); #ifdef EFL_NET_SERVER_UNIX_CLASS if (efl_isa(svr->server, EFL_NET_SERVER_UNIX_CLASS)) umask(old_mask); #endif if (err) { WRN("Could not serve %s %s: %s", efl_class_name_get(efl_class_get(svr->server)), address, eina_error_msg_get(err)); goto error; } DBG("will serve %p %s address='%s'", svr->server, efl_class_name_get(efl_class_get(svr->server)), address); svr->max_buf_size = 32 * 1024; svr->data = (void *)data; servers = eina_list_append(servers, svr); ECORE_MAGIC_SET(svr, ECORE_MAGIC_IPC_SERVER); free(address); return svr; error: free(address); _ecore_ipc_server_del(svr); free(svr); return NULL; /* server will trigger all cleanup on its own callbacks */ error_server: free(address); free(svr); return NULL; } static Efl_Callback_Array_Item *_ecore_ipc_dialer_cbs(void); static void _ecore_ipc_dialer_del(Ecore_Ipc_Server *svr) { DBG("dialer %p del", svr); if (svr->dialer.recv_copier) { efl_del(svr->dialer.recv_copier); svr->dialer.recv_copier = NULL; } if (svr->dialer.send_copier) { efl_del(svr->dialer.send_copier); svr->dialer.send_copier = NULL; } if (svr->dialer.input) { efl_del(svr->dialer.input); svr->dialer.input = NULL; } if (svr->dialer.dialer) { efl_event_callback_array_del(svr->dialer.dialer, _ecore_ipc_dialer_cbs(), svr); if (!efl_io_closer_closed_get(svr->dialer.dialer)) efl_io_closer_close(svr->dialer.dialer); efl_del(svr->dialer.dialer); svr->dialer.dialer = NULL; } } static void _ecore_ipc_dialer_eos(void *data, const Efl_Event *event EINA_UNUSED) { Ecore_Ipc_Server *svr = data; DBG("dialer %p %p eos", svr, svr->dialer.dialer); _ecore_ipc_dialer_del(svr); ecore_ipc_post_event_server_del(svr); } static void _ecore_ipc_dialer_error(void *data, const Efl_Event *event) { Ecore_Ipc_Server *svr = data; Eina_Error *perr = event->info; WRN("dialer %p %p error %s", svr, svr->dialer.dialer, eina_error_msg_get(*perr)); if (!efl_io_closer_closed_get(svr->dialer.dialer)) efl_io_closer_close(svr->dialer.dialer); /* triggers EOS */ } static void _ecore_ipc_dialer_connected(void *data, const Efl_Event *event EINA_UNUSED) { Ecore_Ipc_Server *svr = data; DBG("connected to %s %s", efl_class_name_get(efl_class_get(svr->dialer.dialer)), efl_net_dialer_address_dial_get(svr->dialer.dialer)); ecore_ipc_post_event_server_add(svr); } EFL_CALLBACKS_ARRAY_DEFINE(_ecore_ipc_dialer_cbs, { EFL_IO_READER_EVENT_EOS, _ecore_ipc_dialer_eos }, { EFL_NET_DIALER_EVENT_DIALER_ERROR, _ecore_ipc_dialer_error }, { EFL_NET_DIALER_EVENT_DIALER_CONNECTED, _ecore_ipc_dialer_connected }); static Eina_Bool ecore_ipc_server_data_process(Ecore_Ipc_Server *svr, void *data, int size, Eina_Bool *stolen); static void _ecore_ipc_dialer_copier_data(void *data, const Efl_Event *event EINA_UNUSED) { Ecore_Ipc_Server *svr = data; Eina_Binbuf *binbuf; uint8_t *mem; int size; Eina_Bool stolen; DBG("dialer %p recv_copier %p data", svr, svr->dialer.recv_copier); binbuf = efl_io_copier_binbuf_steal(svr->dialer.recv_copier); EINA_SAFETY_ON_NULL_RETURN(binbuf); size = eina_binbuf_length_get(binbuf); mem = eina_binbuf_string_steal(binbuf); eina_binbuf_free(binbuf); ecore_ipc_server_data_process(svr, mem, size, &stolen); if (!stolen) free(mem); } static void _ecore_ipc_dialer_copier_error(void *data, const Efl_Event *event) { Ecore_Ipc_Server *svr = data; Eina_Error *perr = event->info; WRN("dialer %p %p copier %p error %s", svr, svr->dialer.dialer, event->object, eina_error_msg_get(*perr)); if (!efl_io_closer_closed_get(svr->dialer.dialer)) efl_io_closer_close(svr->dialer.dialer); } EFL_CALLBACKS_ARRAY_DEFINE(_ecore_ipc_dialer_copier_cbs, { EFL_IO_COPIER_EVENT_ERROR, _ecore_ipc_dialer_copier_error }); /* FIXME: need to add protocol type parameter */ EAPI Ecore_Ipc_Server * ecore_ipc_server_connect(Ecore_Ipc_Type type, char *name, int port, const void *data) { Ecore_Ipc_Server *svr; Eo *loop = efl_main_loop_get(); char *address = NULL; Eina_Error err; EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); svr = calloc(1, sizeof(Ecore_Ipc_Server)); EINA_SAFETY_ON_NULL_RETURN_VAL(svr, NULL); if (0) { } #ifdef EFL_NET_DIALER_UNIX_CLASS if ((type & ECORE_IPC_TYPE) == ECORE_IPC_LOCAL_USER) { struct stat st; address = ecore_con_local_path_new(EINA_FALSE, name, port); EINA_SAFETY_ON_NULL_GOTO(address, error_dialer); if ((stat(address, &st) != 0) #ifdef S_ISSOCK || (!S_ISSOCK(st.st_mode)) #endif ) { DBG("%s is not a socket", address); goto error_dialer; } svr->dialer.dialer = efl_add(EFL_NET_DIALER_UNIX_CLASS, efl_main_loop_get()); EINA_SAFETY_ON_NULL_GOTO(svr->dialer.dialer, error_dialer); } else if ((type & ECORE_IPC_TYPE) == ECORE_IPC_LOCAL_SYSTEM) { address = ecore_con_local_path_new(EINA_TRUE, name, port); EINA_SAFETY_ON_NULL_GOTO(address, error_dialer); svr->dialer.dialer = efl_add(EFL_NET_DIALER_UNIX_CLASS, efl_main_loop_get()); EINA_SAFETY_ON_NULL_GOTO(svr->dialer.dialer, error_dialer); } #endif /* EFL_NET_DIALER_UNIX_CLASS */ #ifdef EFL_NET_DIALER_WINDOWS_CLASS if ((type & ECORE_IPC_TYPE) == ECORE_IPC_LOCAL_USER) { address = ecore_con_local_path_new(EINA_FALSE, name, port); EINA_SAFETY_ON_NULL_GOTO(address, error_dialer); svr->dialer.dialer = efl_add(EFL_NET_DIALER_WINDOWS_CLASS, efl_main_loop_get()); EINA_SAFETY_ON_NULL_GOTO(svr->dialer.dialer, error_dialer); } else if ((type & ECORE_IPC_TYPE) == ECORE_IPC_LOCAL_SYSTEM) { address = ecore_con_local_path_new(EINA_TRUE, name, port); EINA_SAFETY_ON_NULL_GOTO(address, error_dialer); svr->dialer.dialer = efl_add(EFL_NET_DIALER_WINDOWS_CLASS, efl_main_loop_get()); EINA_SAFETY_ON_NULL_GOTO(svr->dialer.dialer, error_dialer); } #endif /* EFL_NET_DIALER_WINDOWS_CLASS */ else if ((type & ECORE_IPC_TYPE) == ECORE_IPC_REMOTE_SYSTEM) { char buf[4096]; if (port <= 0) { ERR("remote system requires port>=0, got %d", port); goto error_dialer; } snprintf(buf, sizeof(buf), "%s:%d", name, port); address = strdup(buf); EINA_SAFETY_ON_NULL_GOTO(address, error_dialer); if ((type & ECORE_IPC_USE_SSL) == ECORE_IPC_USE_SSL) { svr->dialer.dialer = efl_add(EFL_NET_DIALER_SSL_CLASS, loop); EINA_SAFETY_ON_NULL_GOTO(svr->dialer.dialer, error_dialer); } else { svr->dialer.dialer = efl_add(EFL_NET_DIALER_TCP_CLASS, loop); EINA_SAFETY_ON_NULL_GOTO(svr->dialer.dialer, error_dialer); } if ((type & ECORE_IPC_NO_PROXY) == ECORE_IPC_NO_PROXY) efl_net_dialer_proxy_set(svr->dialer.dialer, ""); } else { ERR("IPC Type must be one of: local_user, local_system or remote_system"); goto error_dialer; } efl_io_closer_close_on_invalidate_set(svr->dialer.dialer, EINA_TRUE); efl_event_callback_array_add(svr->dialer.dialer, _ecore_ipc_dialer_cbs(), svr); svr->dialer.input = efl_add(EFL_IO_QUEUE_CLASS, loop); EINA_SAFETY_ON_NULL_GOTO(svr->dialer.input, error); svr->dialer.send_copier = efl_add(EFL_IO_COPIER_CLASS, loop, efl_io_closer_close_on_invalidate_set(efl_added, EINA_FALSE), efl_io_copier_source_set(efl_added, svr->dialer.input), efl_io_copier_destination_set(efl_added, svr->dialer.dialer), efl_event_callback_array_add(efl_added, _ecore_ipc_dialer_copier_cbs(), svr)); EINA_SAFETY_ON_NULL_GOTO(svr->dialer.send_copier, error); svr->dialer.recv_copier = efl_add(EFL_IO_COPIER_CLASS, loop, efl_io_closer_close_on_invalidate_set(efl_added, EINA_FALSE), efl_io_copier_source_set(efl_added, svr->dialer.dialer), efl_event_callback_array_add(efl_added, _ecore_ipc_dialer_copier_cbs(), svr), efl_event_callback_add(efl_added, EFL_IO_COPIER_EVENT_DATA, _ecore_ipc_dialer_copier_data, svr)); EINA_SAFETY_ON_NULL_GOTO(svr->dialer.recv_copier, error); err = efl_net_dialer_dial(svr->dialer.dialer, address); if (err) { WRN("Could not reach %s %s: %s", efl_class_name_get(efl_class_get(svr->dialer.dialer)), address, eina_error_msg_get(err)); goto error; } DBG("connecting %p %s address='%s'", svr->dialer.dialer, efl_class_name_get(efl_class_get(svr->dialer.dialer)), address); svr->max_buf_size = -1; svr->data = (void *)data; servers = eina_list_append(servers, svr); ECORE_MAGIC_SET(svr, ECORE_MAGIC_IPC_SERVER); free(address); return svr; error: free(address); _ecore_ipc_dialer_del(svr); free(svr); return NULL; /* dialer will trigger all cleanup on its own callbacks */ error_dialer: free(address); free(svr); return NULL; } EAPI void * ecore_ipc_server_del(Ecore_Ipc_Server *svr) { void *data; if (!svr) return NULL; if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) { ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, "ecore_ipc_server_del"); return NULL; } data = svr->data; svr->data = NULL; svr->delete_me = 1; if (svr->event_count == 0) { Ecore_Ipc_Client *cl; EINA_LIST_FREE(svr->clients, cl) { cl->svr = NULL; ecore_ipc_client_del(cl); } if (svr->dialer.dialer) _ecore_ipc_dialer_del(svr); if (svr->server) _ecore_ipc_server_del(svr); servers = eina_list_remove(servers, svr); if (svr->buf) free(svr->buf); eina_list_free(svr->dead_clients); eina_list_free(svr->clients); ECORE_MAGIC_SET(svr, ECORE_MAGIC_NONE); DBG("server %p freed", svr); free(svr); } else DBG("server %p has %d events pending, postpone deletion", svr, svr->event_count); return data; } EAPI void * ecore_ipc_server_data_get(Ecore_Ipc_Server *svr) { if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) { ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, "ecore_ipc_server_data_get"); return NULL; } return svr->data; } EAPI Eina_Bool ecore_ipc_server_connected_get(Ecore_Ipc_Server *svr) { if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) { ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, "ecore_ipc_server_connected_get"); return EINA_FALSE; } if (svr->dialer.dialer) return efl_net_dialer_connected_get(svr->dialer.dialer); else if (svr->server) return EINA_TRUE; return EINA_FALSE; } EAPI Eina_List * ecore_ipc_server_clients_get(Ecore_Ipc_Server *svr) { if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) { ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, "ecore_ipc_server_clients_get"); return NULL; } return svr->clients; } #define SVENC(_member) \ d = _ecore_ipc_dlt_int(msg._member, svr->prev.o._member, &md); \ if (md >= DLT_SET) \ { \ unsigned int v; \ unsigned char *dd; \ dd = (unsigned char *)&v; \ v = d; \ v = eina_htonl(v); \ *(dat + s + 0) = dd[0]; \ *(dat + s + 1) = dd[1]; \ *(dat + s + 2) = dd[2]; \ *(dat + s + 3) = dd[3]; \ s += 4; \ } \ else if (md >= DLT_ADD16) \ { \ unsigned short v; \ unsigned char *dd; \ dd = (unsigned char *)&v; \ v = d; \ v = eina_htons(v); \ *(dat + s + 0) = dd[0]; \ *(dat + s + 1) = dd[1]; \ s += 2; \ } \ else if (md >= DLT_ADD8) \ { \ *(dat + s + 0) = (unsigned char)d; \ s += 1; \ } /* FIXME: this needs to become an ipc message */ EAPI int ecore_ipc_server_send(Ecore_Ipc_Server *svr, int major, int minor, int ref, int ref_to, int response, const void *data, int size) { Ecore_Ipc_Msg_Head msg; int *head, md = 0, d, s; unsigned char dat[sizeof(Ecore_Ipc_Msg_Head)]; if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) { ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, "ecore_ipc_server_send"); return 0; } if (size < 0) size = 0; msg.major = major; msg.minor = minor; msg.ref = ref; msg.ref_to = ref_to; msg.response = response; msg.size = size; head = (int *)dat; s = 4; SVENC(major); *head = md; SVENC(minor); *head |= md << (4 * 1); SVENC(ref); *head |= md << (4 * 2); SVENC(ref_to); *head |= md << (4 * 3); SVENC(response); *head |= md << (4 * 4); SVENC(size); *head |= md << (4 * 5); *head = eina_htonl(*head); svr->prev.o = msg; if (svr->dialer.input) { Eina_Slice slice; Eina_Error err; slice.mem = dat; slice.len = s; err = efl_io_writer_write(svr->dialer.input, &slice, NULL); if (err) { ERR("could not write queue=%p %zd bytes: %s", svr->dialer.input, slice.len, eina_error_msg_get(err)); return 0; } if (slice.len < (size_t)s) { ERR("only wrote %zd of %d bytes to queue %p", slice.len, s, svr->dialer.input); return 0; } if ((data) && (size > 0)) { slice.mem = data; slice.len = size; err = efl_io_writer_write(svr->dialer.input, &slice, NULL); if (err) { ERR("could not write queue=%p %zd bytes: %s", svr->dialer.input, slice.len, eina_error_msg_get(err)); return 0; } if (slice.len < (size_t)size) { ERR("only wrote %zd of %d bytes to queue %p", slice.len, size, svr->dialer.input); return 0; } } return s + size; } else if (svr->server) { ERR("Send data to clients, not the server handle"); return 0; } return 0; } EAPI void ecore_ipc_server_client_limit_set(Ecore_Ipc_Server *svr, int client_limit, char reject_excess_clients) { if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) { ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, "ecore_ipc_server_client_limit_set"); return; } if (svr->server) { efl_net_server_clients_limit_set(svr->server, client_limit, reject_excess_clients); return; } } EAPI void ecore_ipc_server_data_size_max_set(Ecore_Ipc_Server *svr, int size) { if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) { ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, "ecore_ipc_server_data_size_max_set"); return; } svr->max_buf_size = size; } EAPI int ecore_ipc_server_data_size_max_get(Ecore_Ipc_Server *svr) { if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) { ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, "ecore_ipc_server_data_size_max_get"); return -1; } return svr->max_buf_size; } EAPI const char * ecore_ipc_server_ip_get(Ecore_Ipc_Server *svr) { if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) { ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, "ecore_ipc_server_ip_get"); return NULL; } if (svr->dialer.dialer) { if (efl_isa(svr->dialer.dialer, EFL_NET_DIALER_TCP_CLASS) || efl_isa(svr->dialer.dialer, EFL_NET_DIALER_SSL_CLASS)) return efl_net_dialer_address_dial_get(svr->dialer.dialer); /* original IPC just returned IP for remote connections */ return NULL; } else if (svr->server) { if (efl_isa(svr->server, EFL_NET_SERVER_TCP_CLASS) || efl_isa(svr->server, EFL_NET_SERVER_SSL_CLASS)) return efl_net_server_address_get(svr->server); /* original IPC just returned IP for remote connections */ return NULL; } return NULL; } EAPI void ecore_ipc_server_flush(Ecore_Ipc_Server *svr) { if (!ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) { ECORE_MAGIC_FAIL(svr, ECORE_MAGIC_IPC_SERVER, "ecore_ipc_server_server_flush"); return; } if (svr->dialer.input) { while (!efl_io_closer_closed_get(svr->dialer.dialer) && !efl_net_dialer_connected_get(svr->dialer.dialer)) ecore_main_loop_iterate(); while ((efl_io_queue_usage_get(svr->dialer.input) > 0) || (efl_io_copier_pending_size_get(svr->dialer.send_copier) > 0)) efl_io_copier_flush(svr->dialer.send_copier, EINA_TRUE, EINA_TRUE); return; } else if (svr->server) { ERR("Flush clients, not the server handle"); return; } } #define CLENC(_member) \ d = _ecore_ipc_dlt_int(msg._member, cl->prev.o._member, &md); \ if (md >= DLT_SET) \ { \ unsigned int v; \ unsigned char *dd; \ dd = (unsigned char *)&v; \ v = d; \ v = eina_htonl(v); \ *(dat + s + 0) = dd[0]; \ *(dat + s + 1) = dd[1]; \ *(dat + s + 2) = dd[2]; \ *(dat + s + 3) = dd[3]; \ s += 4; \ } \ else if (md >= DLT_ADD16) \ { \ unsigned short v; \ unsigned char *dd; \ dd = (unsigned char *)&v; \ v = d; \ v = eina_htons(v); \ *(dat + s + 0) = dd[0]; \ *(dat + s + 1) = dd[1]; \ s += 2; \ } \ else if (md >= DLT_ADD8) \ { \ *(dat + s) = (unsigned char)d; \ s += 1; \ } /* FIXME: this needs to become an ipc message */ EAPI int ecore_ipc_client_send(Ecore_Ipc_Client *cl, int major, int minor, int ref, int ref_to, int response, const void *data, int size) { Ecore_Ipc_Msg_Head msg; int *head, md = 0, d, s; unsigned char dat[sizeof(Ecore_Ipc_Msg_Head)]; if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) { ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, "ecore_ipc_client_send"); return 0; } if (cl->socket.socket) EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(cl->socket.socket), 0); else { ERR("client %p is not connected", cl); return 0; } if (size < 0) size = 0; msg.major = major; msg.minor = minor; msg.ref = ref; msg.ref_to = ref_to; msg.response = response; msg.size = size; head = (int *)dat; s = 4; CLENC(major); *head = md; CLENC(minor); *head |= md << (4 * 1); CLENC(ref); *head |= md << (4 * 2); CLENC(ref_to); *head |= md << (4 * 3); CLENC(response); *head |= md << (4 * 4); CLENC(size); *head |= md << (4 * 5); *head = eina_htonl(*head); cl->prev.o = msg; if (cl->socket.input) { Eina_Slice slice; Eina_Error err; slice.mem = dat; slice.len = s; err = efl_io_writer_write(cl->socket.input, &slice, NULL); if (err) { ERR("could not write queue=%p %zd bytes: %s", cl->socket.input, slice.len, eina_error_msg_get(err)); return 0; } if (slice.len < (size_t)s) { ERR("only wrote %zd of %d bytes to queue %p", slice.len, s, cl->socket.input); return 0; } if ((data) && (size > 0)) { slice.mem = data; slice.len = size; err = efl_io_writer_write(cl->socket.input, &slice, NULL); if (err) { ERR("could not write queue=%p %zd bytes: %s", cl->socket.input, slice.len, eina_error_msg_get(err)); return 0; } if (slice.len < (size_t)size) { ERR("only wrote %zd of %d bytes to queue %p", slice.len, size, cl->socket.input); return 0; } } return s + size; } return 0; } EAPI Ecore_Ipc_Server * ecore_ipc_client_server_get(Ecore_Ipc_Client *cl) { if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) { ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, "ecore_ipc_client_server_get"); return NULL; } return cl->svr; } static Efl_Callback_Array_Item *_ecore_ipc_socket_cbs(void); static void _ecore_ipc_client_socket_del(Ecore_Ipc_Client *cl) { DBG("client %p socket del", cl); if (cl->socket.recv_copier) { efl_del(cl->socket.recv_copier); cl->socket.recv_copier = NULL; } if (cl->socket.send_copier) { efl_del(cl->socket.send_copier); cl->socket.send_copier = NULL; } if (cl->socket.input) { efl_del(cl->socket.input); cl->socket.input = NULL; } if (cl->socket.socket) { efl_event_callback_array_del(cl->socket.socket, _ecore_ipc_socket_cbs(), cl); /* do not del() as it's owned by srv->server */ if (!efl_io_closer_closed_get(cl->socket.socket)) efl_io_closer_close(cl->socket.socket); efl_unref(cl->socket.socket); cl->socket.socket = NULL; if (!cl->svr) return; cl->svr->clients = eina_list_remove(cl->svr->clients, cl); cl->svr->dead_clients = eina_list_append(cl->svr->dead_clients, cl); } } static void _ecore_ipc_client_socket_eos(void *data, const Efl_Event *event EINA_UNUSED) { Ecore_Ipc_Client *cl = data; DBG("client %p socket %p eos", cl, cl->socket.socket); _ecore_ipc_client_socket_del(cl); ecore_ipc_post_event_client_del(cl); } EFL_CALLBACKS_ARRAY_DEFINE(_ecore_ipc_socket_cbs, { EFL_IO_READER_EVENT_EOS, _ecore_ipc_client_socket_eos }); static Eina_Bool ecore_ipc_client_data_process(Ecore_Ipc_Client *cl, void *data, int size, Eina_Bool *stolen); static void _ecore_ipc_client_socket_copier_data(void *data, const Efl_Event *event EINA_UNUSED) { Ecore_Ipc_Client *cl = data; Eina_Binbuf *binbuf; uint8_t *mem; int size; Eina_Bool stolen; DBG("client %p recv_copier %p data", cl, cl->socket.recv_copier); binbuf = efl_io_copier_binbuf_steal(cl->socket.recv_copier); EINA_SAFETY_ON_NULL_RETURN(binbuf); size = eina_binbuf_length_get(binbuf); mem = eina_binbuf_string_steal(binbuf); eina_binbuf_free(binbuf); ecore_ipc_client_data_process(cl, mem, size, &stolen); if (!stolen) free(mem); } static void _ecore_ipc_client_socket_copier_error(void *data, const Efl_Event *event) { Ecore_Ipc_Client *cl = data; Eina_Error *perr = event->info; WRN("client %p socket %p copier %p error %s", cl, cl->socket.socket, event->object, eina_error_msg_get(*perr)); if (!efl_io_closer_closed_get(cl->socket.socket)) efl_io_closer_close(cl->socket.socket); } EFL_CALLBACKS_ARRAY_DEFINE(_ecore_ipc_client_socket_copier_cbs, { EFL_IO_COPIER_EVENT_ERROR, _ecore_ipc_client_socket_copier_error }); static void _ecore_ipc_server_client_add(void *data, const Efl_Event *event) { Ecore_Ipc_Server *svr = data; Eo *socket = event->info; Ecore_Ipc_Client *cl; Eo *loop; DBG("server %p %p got new client %p (%s)", svr, svr->server, event->object, efl_net_socket_address_remote_get(socket)); cl = ecore_ipc_client_add(svr); EINA_SAFETY_ON_NULL_RETURN(cl); cl->socket.socket = efl_ref(socket); efl_event_callback_array_add(cl->socket.socket, _ecore_ipc_socket_cbs(), cl); loop = efl_loop_get(socket); cl->socket.input = efl_add(EFL_IO_QUEUE_CLASS, loop); EINA_SAFETY_ON_NULL_GOTO(cl->socket.input, error); cl->socket.send_copier = efl_add(EFL_IO_COPIER_CLASS, loop, efl_io_closer_close_on_invalidate_set(efl_added, EINA_FALSE), efl_io_copier_source_set(efl_added, cl->socket.input), efl_io_copier_destination_set(efl_added, cl->socket.socket), efl_event_callback_array_add(efl_added, _ecore_ipc_client_socket_copier_cbs(), cl)); EINA_SAFETY_ON_NULL_GOTO(cl->socket.send_copier, error); cl->socket.recv_copier = efl_add(EFL_IO_COPIER_CLASS, loop, efl_io_closer_close_on_invalidate_set(efl_added, EINA_FALSE), efl_io_copier_source_set(efl_added, cl->socket.socket), efl_event_callback_array_add(efl_added, _ecore_ipc_client_socket_copier_cbs(), cl), efl_event_callback_add(efl_added, EFL_IO_COPIER_EVENT_DATA, _ecore_ipc_client_socket_copier_data, cl)); EINA_SAFETY_ON_NULL_GOTO(cl->socket.recv_copier, error); ecore_ipc_post_event_client_add(cl); return; error: _ecore_ipc_client_socket_del(cl); free(cl); } EAPI void * ecore_ipc_client_del(Ecore_Ipc_Client *cl) { void *data; Ecore_Ipc_Server *svr; if (!cl) return NULL; if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) { ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, "ecore_ipc_client_del"); return NULL; } data = cl->data; cl->data = NULL; cl->delete_me = 1; if (cl->event_count == 0) { svr = cl->svr; if (cl->socket.socket) _ecore_ipc_client_socket_del(cl); if (ECORE_MAGIC_CHECK(svr, ECORE_MAGIC_IPC_SERVER)) svr->dead_clients = eina_list_remove(svr->dead_clients, cl); if (cl->buf) free(cl->buf); ECORE_MAGIC_SET(cl, ECORE_MAGIC_NONE); free(cl); } return data; } EAPI void ecore_ipc_client_data_set(Ecore_Ipc_Client *cl, const void *data) { if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) { ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, "ecore_ipc_client_data_set"); return; } cl->data = (void *)data; } EAPI void * ecore_ipc_client_data_get(Ecore_Ipc_Client *cl) { if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) { ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, "ecore_ipc_client_data_get"); return NULL; } return cl->data; } EAPI void ecore_ipc_client_data_size_max_set(Ecore_Ipc_Client *cl, int size) { if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) { ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, "ecore_ipc_client_data_size_max_set"); return; } cl->max_buf_size = size; } EAPI int ecore_ipc_client_data_size_max_get(Ecore_Ipc_Client *cl) { if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) { ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, "ecore_ipc_client_data_size_max_get"); return -1; } return cl->max_buf_size; } EAPI const char * ecore_ipc_client_ip_get(Ecore_Ipc_Client *cl) { if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) { ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, "ecore_ipc_client_ip_get"); return NULL; } if (cl->socket.socket) { if (efl_isa(cl->socket.socket, EFL_NET_SOCKET_TCP_CLASS) || efl_isa(cl->socket.socket, EFL_NET_SOCKET_SSL_CLASS)) return efl_net_socket_address_remote_get(cl->socket.socket); /* original IPC just returned IP for remote connections, * for unix socket it returned 0.0.0.0 */ return "0.0.0.0"; } return NULL; } EAPI void ecore_ipc_client_flush(Ecore_Ipc_Client *cl) { if (!ECORE_MAGIC_CHECK(cl, ECORE_MAGIC_IPC_CLIENT)) { ECORE_MAGIC_FAIL(cl, ECORE_MAGIC_IPC_CLIENT, "ecore_ipc_client_flush"); return; } if (cl->socket.input) { while (efl_io_queue_usage_get(cl->socket.input) > 0) efl_io_copier_flush(cl->socket.send_copier, EINA_TRUE, EINA_TRUE); return; } } EAPI int ecore_ipc_ssl_available_get(void) { return ecore_con_ssl_available_get(); } #define CLSZ(_n) \ md = ((head >> (4 * _n)) & 0xf); \ if (md >= DLT_SET) s += 4; \ else if (md >= DLT_ADD16) s += 2; \ else if (md >= DLT_ADD8) s += 1; #define CLDEC(_n, _member) \ md = ((head >> (4 * _n)) & 0xf); \ if (md >= DLT_SET) \ { \ unsigned int v; \ unsigned char *dv; \ dv = (unsigned char *)&v; \ dv[0] = *(cl->buf + offset + s + 0); \ dv[1] = *(cl->buf + offset + s + 1); \ dv[2] = *(cl->buf + offset + s + 2); \ dv[3] = *(cl->buf + offset + s + 3); \ d = (int)eina_ntohl(v); \ s += 4; \ } \ else if (md >= DLT_ADD16) \ { \ unsigned short v; \ unsigned char *dv; \ dv = (unsigned char *)&v; \ dv[0] = *(cl->buf + offset + s + 0); \ dv[1] = *(cl->buf + offset + s + 1); \ d = (int)eina_ntohs(v); \ s += 2; \ } \ else if (md >= DLT_ADD8) \ { \ unsigned char v; \ unsigned char *dv; \ dv = (unsigned char *)&v; \ dv[0] = *(cl->buf + offset + s + 0); \ d = (int)v; \ s += 1; \ } \ msg._member = _ecore_ipc_ddlt_int(d, cl->prev.i._member, md); static Eina_Bool ecore_ipc_client_data_process(Ecore_Ipc_Client *cl, void *data, int size, Eina_Bool *stolen) { /* use e->data and e->size to reduce diff to original code */ struct { void *data; int size; } _e = { data, size }, *e = &_e; Ecore_Ipc_Server *svr = ecore_ipc_client_server_get(cl); *stolen = EINA_FALSE; if (1) { /* keep same identation as original code to help verification */ Ecore_Ipc_Msg_Head msg; int offset = 0; unsigned char *buf; if (!cl->buf) { cl->buf_size = e->size; cl->buf = e->data; *stolen = EINA_TRUE; } else { buf = realloc(cl->buf, cl->buf_size + e->size); if (!buf) { free(cl->buf); cl->buf = 0; cl->buf_size = 0; return ECORE_CALLBACK_CANCEL; } cl->buf = buf; memcpy(cl->buf + cl->buf_size, e->data, e->size); cl->buf_size += e->size; } /* examine header */ redo: if ((cl->buf_size - offset) >= (int)sizeof(int)) { int s, md, d = 0, head; unsigned char *dd; dd = (unsigned char *)&head; dd[0] = *(cl->buf + offset + 0); dd[1] = *(cl->buf + offset + 1); dd[2] = *(cl->buf + offset + 2); dd[3] = *(cl->buf + offset + 3); head = eina_ntohl(head); dd = (unsigned char *)&d; s = 4; CLSZ(0); CLSZ(1); CLSZ(2); CLSZ(3); CLSZ(4); CLSZ(5); if ((cl->buf_size - offset) < s) { if (offset > 0) goto scroll; return ECORE_CALLBACK_CANCEL; } s = 4; CLDEC(0, major); CLDEC(1, minor); CLDEC(2, ref); CLDEC(3, ref_to); CLDEC(4, response); CLDEC(5, size); if (msg.size < 0) msg.size = 0; /* there is enough data in the buffer for a full message */ if ((cl->buf_size - offset) >= (s + msg.size)) { Ecore_Ipc_Event_Client_Data *e2; int max, max2; buf = NULL; max = svr->max_buf_size; max2 = cl->max_buf_size; if ((max >= 0) && (max2 >= 0)) { if (max2 < max) max = max2; } else { if (max < 0) max = max2; } if ((max < 0) || (msg.size <= max)) { Eina_Bool need_free = EINA_FALSE; if (msg.size > 0) { buf = malloc(msg.size); if (!buf) return ECORE_CALLBACK_CANCEL; memcpy(buf, cl->buf + offset + s, msg.size); need_free = EINA_TRUE; } if (!cl->delete_me) { e2 = calloc(1, sizeof(Ecore_Ipc_Event_Client_Data)); if (e2) { cl->event_count++; e2->client = cl; e2->major = msg.major; e2->minor = msg.minor; e2->ref = msg.ref; e2->ref_to = msg.ref_to; e2->response = msg.response; e2->size = msg.size; e2->data = buf; ecore_event_add(ECORE_IPC_EVENT_CLIENT_DATA, e2, _ecore_ipc_event_client_data_free, NULL); need_free = EINA_FALSE; } } if (need_free) free(buf); } cl->prev.i = msg; offset += (s + msg.size); if (cl->buf_size == offset) { free(cl->buf); cl->buf = NULL; cl->buf_size = 0; return ECORE_CALLBACK_CANCEL; } goto redo; } else goto scroll; } else { scroll: buf = malloc(cl->buf_size - offset); if (!buf) { free(cl->buf); cl->buf = NULL; cl->buf_size = 0; return ECORE_CALLBACK_CANCEL; } memcpy(buf, cl->buf + offset, cl->buf_size - offset); free(cl->buf); cl->buf = buf; cl->buf_size -= offset; } } return ECORE_CALLBACK_CANCEL; } #define SVSZ(_n) \ md = ((head >> (4 * _n)) & 0xf); \ if (md >= DLT_SET) s += 4; \ else if (md >= DLT_ADD16) s += 2; \ else if (md >= DLT_ADD8) s += 1; #define SVDEC(_n, _member) \ md = ((head >> (4 * _n)) & 0xf); \ if (md >= DLT_SET) \ { \ unsigned int v; \ unsigned char *dv; \ dv = (unsigned char *)&v; \ dv[0] = *(svr->buf + offset + s + 0); \ dv[1] = *(svr->buf + offset + s + 1); \ dv[2] = *(svr->buf + offset + s + 2); \ dv[3] = *(svr->buf + offset + s + 3); \ d = (int)eina_ntohl(v); \ s += 4; \ } \ else if (md >= DLT_ADD16) \ { \ unsigned short v; \ unsigned char *dv; \ dv = (unsigned char *)&v; \ dv[0] = *(svr->buf + offset + s + 0); \ dv[1] = *(svr->buf + offset + s + 1); \ d = (int)eina_ntohs(v); \ s += 2; \ } \ else if (md >= DLT_ADD8) \ { \ unsigned char v; \ unsigned char *dv; \ dv = (unsigned char *)&v; \ dv[0] = *(svr->buf + offset + s + 0); \ d = (int)v; \ s += 1; \ } \ msg._member = _ecore_ipc_ddlt_int(d, svr->prev.i._member, md); static Eina_Bool ecore_ipc_server_data_process(Ecore_Ipc_Server *svr, void *data, int size, Eina_Bool *stolen) { /* use e->data and e->size to reduce diff to original code */ struct { void *data; int size; } _e = { data, size }, *e = &_e; *stolen = EINA_FALSE; if (1) { /* keep same identation as original code to help verification */ Ecore_Ipc_Msg_Head msg; int offset = 0; unsigned char *buf = NULL; if (!svr->buf) { svr->buf_size = e->size; svr->buf = e->data; *stolen = EINA_TRUE; } else { buf = realloc(svr->buf, svr->buf_size + e->size); if (!buf) { free(svr->buf); svr->buf = 0; svr->buf_size = 0; return ECORE_CALLBACK_CANCEL; } svr->buf = buf; memcpy(svr->buf + svr->buf_size, e->data, e->size); svr->buf_size += e->size; } /* examine header */ redo: if ((svr->buf_size - offset) >= (int)sizeof(int)) { int s, md, d = 0, head; unsigned char *dd; dd = (unsigned char *)&head; dd[0] = *(svr->buf + offset + 0); dd[1] = *(svr->buf + offset + 1); dd[2] = *(svr->buf + offset + 2); dd[3] = *(svr->buf + offset + 3); head = eina_ntohl(head); dd = (unsigned char *)&d; s = 4; SVSZ(0); SVSZ(1); SVSZ(2); SVSZ(3); SVSZ(4); SVSZ(5); if ((svr->buf_size - offset) < s) { if (offset > 0) goto scroll; return ECORE_CALLBACK_CANCEL; } s = 4; SVDEC(0, major); SVDEC(1, minor); SVDEC(2, ref); SVDEC(3, ref_to); SVDEC(4, response); SVDEC(5, size); if (msg.size < 0) msg.size = 0; /* there is enough data in the buffer for a full message */ if ((svr->buf_size - offset) >= (s + msg.size)) { Ecore_Ipc_Event_Server_Data *e2; int max; if (buf != svr->buf) free(buf); buf = NULL; max = svr->max_buf_size; if ((max < 0) || (msg.size <= max)) { if (msg.size > 0) { buf = malloc(msg.size); if (!buf) return ECORE_CALLBACK_CANCEL; memcpy(buf, svr->buf + offset + s, msg.size); } if (!svr->delete_me) { e2 = calloc(1, sizeof(Ecore_Ipc_Event_Server_Data)); if (e2) { svr->event_count++; e2->server = svr; e2->major = msg.major; e2->minor = msg.minor; e2->ref = msg.ref; e2->ref_to = msg.ref_to; e2->response = msg.response; e2->size = msg.size; e2->data = buf; if (buf == svr->buf) { svr->buf = NULL; svr->buf_size = 0; } buf = NULL; ecore_event_add(ECORE_IPC_EVENT_SERVER_DATA, e2, _ecore_ipc_event_server_data_free, NULL); } else { free(buf); buf = NULL; } } else { free(buf); buf = NULL; } } svr->prev.i = msg; offset += (s + msg.size); if ((svr->buf_size == offset) && (svr->buf)) { free(svr->buf); svr->buf = NULL; svr->buf_size = 0; return ECORE_CALLBACK_CANCEL; } goto redo; } else goto scroll; } else { scroll: if (buf != svr->buf) free(buf); buf = malloc(svr->buf_size - offset); if (!buf) { free(svr->buf); svr->buf = NULL; svr->buf_size = 0; return ECORE_CALLBACK_CANCEL; } memcpy(buf, svr->buf + offset, svr->buf_size - offset); free(svr->buf); svr->buf = buf; svr->buf_size -= offset; } } return ECORE_CALLBACK_CANCEL; } static void _ecore_ipc_event_client_add_free(void *data EINA_UNUSED, void *ev) { Ecore_Ipc_Event_Client_Add *e; e = ev; e->client->event_count--; if ((e->client->event_count == 0) && (e->client->delete_me)) ecore_ipc_client_del(e->client); free(e); } static void _ecore_ipc_event_client_del_free(void *data EINA_UNUSED, void *ev) { Ecore_Ipc_Event_Client_Del *e; e = ev; e->client->event_count--; if ((e->client->event_count == 0) && (e->client->delete_me)) ecore_ipc_client_del(e->client); free(e); } static void _ecore_ipc_event_client_data_free(void *data EINA_UNUSED, void *ev) { Ecore_Ipc_Event_Client_Data *e; e = ev; e->client->event_count--; if (e->data) free(e->data); if ((e->client->event_count == 0) && (e->client->delete_me)) ecore_ipc_client_del(e->client); free(e); } static void _ecore_ipc_event_server_add_free(void *data EINA_UNUSED, void *ev) { Ecore_Ipc_Event_Server_Add *e; e = ev; e->server->event_count--; if ((e->server->event_count == 0) && (e->server->delete_me)) ecore_ipc_server_del(e->server); free(e); } static void _ecore_ipc_event_server_del_free(void *data EINA_UNUSED, void *ev) { Ecore_Ipc_Event_Server_Del *e; e = ev; e->server->event_count--; if ((e->server->event_count == 0) && (e->server->delete_me)) ecore_ipc_server_del(e->server); free(e); } static void _ecore_ipc_event_server_data_free(void *data EINA_UNUSED, void *ev) { Ecore_Ipc_Event_Server_Data *e; e = ev; if (e->data) free(e->data); e->server->event_count--; if ((e->server->event_count == 0) && (e->server->delete_me)) ecore_ipc_server_del(e->server); free(e); }