Changed socket interface to support fallbacks.

Now we support a list of fallback targets when opening the socket, and
socket binding/connect is done inside socket.* instead of luaa.c or
awesome-client.c

Signed-off-by: Alex Cornejo <acornejo@gmail.com>
Signed-off-by: Julien Danjou <julien@danjou.info>
This commit is contained in:
Alex Cornejo 2009-03-19 20:59:40 -04:00 committed by Julien Danjou
parent f0bb0b374b
commit 2689852e45
4 changed files with 65 additions and 50 deletions

View File

@ -56,17 +56,9 @@ sockets_init(void)
if((csfd = socket_getclient()) < 0) if((csfd = socket_getclient()) < 0)
return false; return false;
if(!(addr = socket_getaddr(getenv("HOME"), display))) if(!(addr = socket_open(csfd, display, SOCKET_MODE_CONNECT)))
return false; return false;
if(connect(csfd, addr, sizeof(struct sockaddr_un)) == -1)
{
if(!(addr = socket_getaddr("/tmp", display)))
return false;
if(connect(csfd, addr, sizeof(struct sockaddr_un)) == -1)
return false;
}
return true; return true;
} }

View File

@ -24,6 +24,7 @@
#include <errno.h> #include <errno.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <unistd.h>
#include <xcb/xcb.h> #include <xcb/xcb.h>
@ -32,41 +33,75 @@
#define CONTROL_UNIX_SOCKET_PATH ".awesome_ctl." #define CONTROL_UNIX_SOCKET_PATH ".awesome_ctl."
/** Get a sockaddr_un struct with information feeded for opening a /** Open a communication socket with awesome for a given display.
* communication to the awesome socket for given display * \param csfd The socket file descriptor.
* \param directory Where socket is created.
* \param display the display number * \param display the display number
* \return sockaddr_un struct ready to be used or NULL if a problem occured * \param mode The open mode, either Bind or Connect.
* \return sockaddr_un Struct ready to be used or NULL if a problem ocurred.
*/ */
struct sockaddr_un * struct sockaddr_un *
socket_getaddr(const char *directory, const char *display) socket_open(int csfd, const char *display, const socket_mode_t mode)
{ {
char *host = NULL; char *host = NULL;
int screenp = 0, displayp = 0; int screenp = 0, displayp = 0;
bool is_socket_opened = false;
ssize_t path_len, len; ssize_t path_len, len;
struct sockaddr_un *addr; struct sockaddr_un *addr;
const char *fallback[] = { ":HOME", ":TMPDIR", "/tmp", NULL }, *directory;
addr = p_new(struct sockaddr_un, 1); addr = p_new(struct sockaddr_un, 1);
addr->sun_family = AF_UNIX;
xcb_parse_display(NULL, &host, &displayp, &screenp); xcb_parse_display(NULL, &host, &displayp, &screenp);
len = a_strlen(host); len = a_strlen(host);
/* + 2 for / and . and \0 */ for(int i = 0; fallback[i] && !is_socket_opened; i++)
path_len = snprintf(addr->sun_path, sizeof(addr->sun_path), {
"%s/" CONTROL_UNIX_SOCKET_PATH "%s%s%d", if(fallback[i][0] == ':')
directory, len ? host : "", len ? "." : "", {
displayp); if(!(directory = getenv(fallback[i] + 1)))
continue;
}
else
directory = fallback[i];
/* + 2 for / and . and \0 */
path_len = snprintf(addr->sun_path, sizeof(addr->sun_path),
"%s/" CONTROL_UNIX_SOCKET_PATH "%s%s%d",
directory, len ? host : "", len ? "." : "",
displayp);
if(path_len < ssizeof(addr->sun_path))
switch(mode)
{
case SOCKET_MODE_BIND:
/* Needed for some OSes like Solaris */
#ifndef SUN_LEN
#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen ((ptr)->sun_path))
#endif
if(!bind(csfd, (const struct sockaddr *) addr, SUN_LEN(addr)))
is_socket_opened = true;
else if(errno == EADDRINUSE)
{
if(unlink(addr->sun_path))
warn("error unlinking existing file: %s", strerror(errno));
if(!bind(csfd, (const struct sockaddr *)addr, SUN_LEN(addr)))
is_socket_opened = true;
}
break;
case SOCKET_MODE_CONNECT:
if(!connect(csfd, (const struct sockaddr *)addr, sizeof(struct sockaddr_un)))
is_socket_opened = true;
break;
}
else
warn("error: path (using %s) of control UNIX domain socket is too long", directory);
}
p_delete(&host); p_delete(&host);
if(path_len >= ssizeof(addr->sun_path)) if(!is_socket_opened)
{ p_delete(&addr);
fprintf(stderr, "error: path of control UNIX domain socket is too long");
return NULL;
}
addr->sun_family = AF_UNIX;
return addr; return addr;
} }

View File

@ -22,7 +22,13 @@
#ifndef AWESOME_COMMON_SOCKET_H #ifndef AWESOME_COMMON_SOCKET_H
#define AWESOME_COMMON_SOCKET_H #define AWESOME_COMMON_SOCKET_H
struct sockaddr_un * socket_getaddr(const char *, const char *); typedef enum
{
SOCKET_MODE_BIND,
SOCKET_MODE_CONNECT
} socket_mode_t;
struct sockaddr_un *socket_open(const int, const char *, const socket_mode_t);
int socket_getclient(void); int socket_getclient(void);
#endif #endif

26
luaa.c
View File

@ -1115,31 +1115,13 @@ luaA_cs_init(void)
if (csfd < 0 || fcntl(csfd, F_SETFD, FD_CLOEXEC) == -1) if (csfd < 0 || fcntl(csfd, F_SETFD, FD_CLOEXEC) == -1)
return; return;
addr = socket_getaddr(getenv("HOME"), getenv("DISPLAY")); if(!(addr = socket_open(csfd, getenv("DISPLAY"), SOCKET_MODE_BIND)))
/* Needed for some OSes like Solaris */
#ifndef SUN_LEN
#define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path) + strlen ((ptr)->sun_path))
#endif
if(bind(csfd, (const struct sockaddr *) addr, SUN_LEN(addr)))
{ {
if(errno == EADDRINUSE) warn("error binding UNIX domain socket: %s", strerror(errno));
{ return;
if(unlink(addr->sun_path))
warn("error unlinking existing file: %s", strerror(errno));
if(bind(csfd, (const struct sockaddr *) addr, SUN_LEN(addr)))
return warn("error binding UNIX domain socket: %s", strerror(errno));
}
else
{
addr = socket_getaddr("/tmp", getenv("DISPLAY"));
if (bind(csfd, (const struct sockaddr *) addr, SUN_LEN(addr)))
return warn("error binding UNIX domain socket: %s", strerror(errno));
}
} }
listen(csfd, 10);
listen(csfd, 10);
ev_io_init(&csio, &luaA_conn_cb, csfd, EV_READ); ev_io_init(&csio, &luaA_conn_cb, csfd, EV_READ);
ev_io_start(EV_DEFAULT_UC_ &csio); ev_io_start(EV_DEFAULT_UC_ &csio);
ev_unref(EV_DEFAULT_UC); ev_unref(EV_DEFAULT_UC);