efl/legacy/ecore/src/lib/ecore_con/ecore_con_local.c

239 lines
6.7 KiB
C
Raw Normal View History

/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <Ecore.h>
#include <ecore_private.h>
#include "Ecore_Con.h"
#include "ecore_con_private.h"
#define LENGTH_OF_SOCKADDR_UN(s) (strlen((s)->sun_path) + (size_t)(((struct sockaddr_un *)NULL)->sun_path))
#define LENGTH_OF_ABSTRACT_SOCKADDR_UN(s, path) (strlen(path) + 1 + (size_t)(((struct sockaddr_un *)NULL)->sun_path))
static int _ecore_con_local_init_count = 0;
int
ecore_con_local_init(void)
{
if (++_ecore_con_local_init_count != 1)
return _ecore_con_local_init_count;
return _ecore_con_local_init_count;
}
int
ecore_con_local_shutdown(void)
{
if (--_ecore_con_local_init_count != 0)
return _ecore_con_local_init_count;
return _ecore_con_local_init_count;
}
int
ecore_con_local_connect(Ecore_Con_Server *svr,
int (*cb_done)(void *data, Ecore_Fd_Handler *fd_handler),
void *data,
void (*cb_free)(void *data, void *ev))
{
char buf[4096];
struct sockaddr_un socket_unix;
int curstate = 0;
const char *homedir;
int socket_unix_len;
if (svr->type == ECORE_CON_LOCAL_USER)
{
homedir = getenv("HOME");
if (!homedir) homedir = getenv("TMP");
if (!homedir) homedir = "/tmp";
snprintf(buf, sizeof(buf), "%s/.ecore/%s/%i", homedir, svr->name, svr->port);
}
else if (svr->type == ECORE_CON_LOCAL_SYSTEM)
{
if (svr->port < 0)
{
if (svr->name[0] == '/')
strncpy(buf, svr->name, sizeof(buf));
else
snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s", svr->name);
}
else
{
if (svr->name[0] == '/')
snprintf(buf, sizeof(buf), "%s|%i", svr->name, svr->port);
else
snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s|%i", svr->name, svr->port);
}
}
else if (svr->type == ECORE_CON_LOCAL_ABSTRACT)
strncpy(buf, svr->name, sizeof(buf));
svr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (svr->fd < 0) return 0;
if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) return 0;
if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) return 0;
if (setsockopt(svr->fd, SOL_SOCKET, SO_REUSEADDR, &curstate, sizeof(curstate)) < 0) return 0;
socket_unix.sun_family = AF_UNIX;
if (svr->type == ECORE_CON_LOCAL_ABSTRACT)
{
#ifdef HAVE_ABSTRACT_SOCKETS
/* copy name insto sun_path, prefixed by null to indicate abstract namespace */
snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s", svr->name);
socket_unix.sun_path[0] = '\0';
socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, svr->name);
#else
WRN("Your system does not support abstract sockets!");
return 0;
#endif
}
else
{
strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
}
if (connect(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
return 0;
svr->path = strdup(buf);
if (!svr->path) return 0;
if (svr->type & ECORE_CON_SSL)
ecore_con_ssl_server_init(svr);
svr->fd_handler =
ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
cb_done, svr, NULL, NULL);
if (!svr->fd_handler) return 0;
if (!svr->delete_me)
{
/* we got our server! */
Ecore_Con_Event_Server_Add *e;
e = calloc(1, sizeof(Ecore_Con_Event_Server_Add));
if (e)
{
svr->event_count++;
e->server = svr;
ecore_event_add(ECORE_CON_EVENT_SERVER_ADD, e,
cb_free, NULL);
}
}
return 1;
}
int
ecore_con_local_listen(Ecore_Con_Server *svr,
int (*cb_listen)(void *data, Ecore_Fd_Handler *fd_handler),
void *data)
{
char buf[4096];
struct sockaddr_un socket_unix;
struct linger lin;
mode_t pmode;
const char *homedir;
struct stat st;
mode_t mask;
int socket_unix_len;
mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
if (svr->type == ECORE_CON_LOCAL_USER)
{
homedir = getenv("HOME");
if (!homedir) homedir = getenv("TMP");
if (!homedir) homedir = "/tmp";
mask = S_IRUSR | S_IWUSR | S_IXUSR;
snprintf(buf, sizeof(buf), "%s/.ecore", homedir);
if (stat(buf, &st) < 0) mkdir(buf, mask);
snprintf(buf, sizeof(buf), "%s/.ecore/%s", homedir, svr->name);
if (stat(buf, &st) < 0) mkdir(buf, mask);
snprintf(buf, sizeof(buf), "%s/.ecore/%s/%i", homedir, svr->name, svr->port);
mask = S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH;
}
else if (svr->type == ECORE_CON_LOCAL_SYSTEM)
{
mask = 0;
if (svr->name[0] == '/')
{
if (svr->port >= 0)
snprintf(buf, sizeof(buf), "%s|%i", svr->name, svr->port);
else
snprintf(buf, sizeof(buf), "%s", svr->name);
}
else
snprintf(buf, sizeof(buf), "/tmp/.ecore_service|%s|%i", svr->name, svr->port);
}
else if (svr->type == ECORE_CON_LOCAL_ABSTRACT)
strncpy(buf, svr->name, sizeof(buf));
pmode = umask(mask);
start:
svr->fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (svr->fd < 0) goto error_umask;
if (fcntl(svr->fd, F_SETFL, O_NONBLOCK) < 0) goto error_umask;
if (fcntl(svr->fd, F_SETFD, FD_CLOEXEC) < 0) goto error_umask;
lin.l_onoff = 1;
lin.l_linger = 0;
if (setsockopt(svr->fd, SOL_SOCKET, SO_LINGER, &lin, sizeof(struct linger)) < 0) goto error_umask;
socket_unix.sun_family = AF_UNIX;
if (svr->type == ECORE_CON_LOCAL_ABSTRACT)
{
#ifdef HAVE_ABSTRACT_SOCKETS
/* . is a placeholder */
snprintf(socket_unix.sun_path, sizeof(socket_unix.sun_path), ".%s", svr->name);
/* first char null indicates abstract namespace */
socket_unix.sun_path[0] = '\0';
socket_unix_len = LENGTH_OF_ABSTRACT_SOCKADDR_UN(&socket_unix, svr->name);
#else
ERR("Your system does not support abstract sockets!");
goto error_umask;
#endif
}
else
{
strncpy(socket_unix.sun_path, buf, sizeof(socket_unix.sun_path));
socket_unix_len = LENGTH_OF_SOCKADDR_UN(&socket_unix);
}
if (bind(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0)
{
if (((svr->type == ECORE_CON_LOCAL_USER) || (svr->type == ECORE_CON_LOCAL_SYSTEM)) &&
(connect(svr->fd, (struct sockaddr *)&socket_unix, socket_unix_len) < 0) &&
(unlink(buf) >= 0))
goto start;
else
goto error_umask;
}
if (listen(svr->fd, 4096) < 0) goto error_umask;
svr->path = strdup(buf);
if (!svr->path) goto error_umask;
svr->fd_handler =
ecore_main_fd_handler_add(svr->fd, ECORE_FD_READ,
cb_listen, svr, NULL, NULL);
umask(pmode);
if (!svr->fd_handler) goto error;
return 1;
error_umask:
umask(pmode);
error:
return 0;
}