diff --git a/src/frontend/sock.c b/src/frontend/sock.c
index 0c4829e2efc4d3737fb9cf4a5f21cf3df5fa59b5..860fb8ee62a5063ce021b9006ea1a90266ce3418 100644 (file)
--- a/src/frontend/sock.c
+++ b/src/frontend/sock.c
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
#include "sysdb.h"
#include "core/object.h"
#include "frontend/connection-private.h"
#include "utils/channel.h"
#include "utils/error.h"
#include "utils/llist.h"
+#include "utils/os.h"
#include "utils/strbuf.h"
#include <assert.h>
#include <sys/socket.h>
#include <sys/un.h>
+#include <libgen.h>
+
#include <pthread.h>
/*
int type;
int sock_fd;
+ int (*accept)(sdb_conn_t *);
} listener_t;
typedef struct {
int type;
const char *prefix;
- int (*opener)(listener_t *);
- void (*closer)(listener_t *);
+ int (*open)(listener_t *);
+ void (*close)(listener_t *);
} fe_listener_impl_t;
struct sdb_fe_socket {
*/
static int
-open_unix_sock(listener_t *listener)
+open_unixsock(listener_t *listener)
{
+ char *addr_copy;
+ char *base_dir;
struct sockaddr_un sa;
int status;
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_UNIX;
- strncpy(sa.sun_path, listener->address + strlen("unix:"),
- sizeof(sa.sun_path));
+ strncpy(sa.sun_path, listener->address, sizeof(sa.sun_path));
+
+ addr_copy = strdup(listener->address);
+ if (! addr_copy) {
+ char errbuf[1024];
+ sdb_log(SDB_LOG_ERR, "frontend: strdup failed: %s",
+ sdb_strerror(errno, errbuf, sizeof(errbuf)));
+ return -1;
+ }
+ base_dir = dirname(addr_copy);
- if (unlink(listener->address + strlen("unix:")) && (errno != ENOENT)) {
+ /* ensure that the directory exists */
+ if (sdb_mkdir_all(base_dir, 0777)) {
+ char errbuf[1024];
+ sdb_log(SDB_LOG_ERR, "frontend: Failed to create directory '%s': %s",
+ base_dir, sdb_strerror(errno, errbuf, sizeof(errbuf)));
+ free(addr_copy);
+ return -1;
+ }
+ free(addr_copy);
+
+ if (unlink(listener->address) && (errno != ENOENT)) {
char errbuf[1024];
sdb_log(SDB_LOG_WARNING, "frontend: Failed to remove stale UNIX "
- "socket %s: %s", listener->address + strlen("unix:"),
+ "socket %s: %s", listener->address,
sdb_strerror(errno, errbuf, sizeof(errbuf)));
}
return -1;
}
return 0;
-} /* open_unix_sock */
+} /* open_unixsock */
static void
-close_unix_sock(listener_t *listener)
+close_unixsock(listener_t *listener)
{
assert(listener);
+
if (! listener->address)
return;
close(listener->sock_fd);
listener->sock_fd = -1;
- unlink(listener->address + strlen("unix:"));
-} /* close_unix_sock */
+ unlink(listener->address);
+} /* close_unixsock */
/*
* private variables
/* the enum has to be sorted the same as the implementations array
* to ensure that the type may be used as index into the array */
enum {
- LISTENER_UNIXSOCK = 0,
+ LISTENER_UNIXSOCK = 0, /* this is the default */
};
static fe_listener_impl_t listener_impls[] = {
- { LISTENER_UNIXSOCK, "unix", open_unix_sock, close_unix_sock },
+ { LISTENER_UNIXSOCK, "unix", open_unixsock, close_unixsock },
};
/*
/* try to reopen */
if (listener->sock_fd < 0)
- if (listener_impls[listener->type].opener(listener))
+ if (listener_impls[listener->type].open(listener))
return -1;
assert(listener->sock_fd >= 0);
{
assert(listener);
- if (listener_impls[listener->type].closer)
- listener_impls[listener->type].closer(listener);
+ if (listener_impls[listener->type].close)
+ listener_impls[listener->type].close(listener);
if (listener->sock_fd >= 0)
close(listener->sock_fd);
sep = strchr(address, (int)':');
if (! sep)
- return -1;
+ return listener_impls[0].type;
assert(sep > address);
len = (size_t)(sep - address);
listener_create(sdb_fe_socket_t *sock, const char *address)
{
listener_t *listener;
+ size_t len;
int type;
type = get_type(address);
}
listener = realloc(sock->listeners,
- sock->listeners_num * sizeof(*sock->listeners));
+ (sock->listeners_num + 1) * sizeof(*sock->listeners));
if (! listener) {
char buf[1024];
sdb_log(SDB_LOG_ERR, "frontend: Failed to allocate memory: %s",
sock->listeners = listener;
listener = sock->listeners + sock->listeners_num;
+ len = strlen(listener_impls[type].prefix);
+ if ((! strncmp(address, listener_impls[type].prefix, len))
+ && (address[len] == ':'))
+ address += strlen(listener_impls[type].prefix) + 1;
+
listener->sock_fd = -1;
listener->address = strdup(address);
if (! listener->address) {
return NULL;
}
listener->type = type;
+ listener->accept = NULL;
- if (listener_impls[type].opener(listener)) {
+ if (listener_impls[type].open(listener)) {
/* prints error */
listener_destroy(listener);
return NULL;
return listener;
} /* listener_create */
+static void
+socket_clear(sdb_fe_socket_t *sock)
+{
+ size_t i;
+
+ assert(sock);
+ for (i = 0; i < sock->listeners_num; ++i)
+ listener_destroy(sock->listeners + i);
+ if (sock->listeners)
+ free(sock->listeners);
+ sock->listeners = NULL;
+ sock->listeners_num = 0;
+} /* socket_clear */
+
static void
socket_close(sdb_fe_socket_t *sock)
{
continue;
}
- status = (int)sdb_connection_read(conn);
+ status = (int)sdb_connection_handle(conn);
if (status <= 0) {
/* error or EOF -> close connection */
sdb_object_deref(SDB_OBJ(conn));
if (! obj)
return -1;
+ if (listener->accept && listener->accept(CONN(obj))) {
+ /* accept() is expected to log an error */
+ sdb_object_deref(obj);
+ return -1;
+ }
+
status = sdb_llist_append(sock->open_connections, obj);
if (status)
sdb_log(SDB_LOG_ERR, "frontend: Failed to append "
while (sdb_llist_iter_has_next(iter)) {
sdb_object_t *obj = sdb_llist_iter_get_next(iter);
- if (FD_ISSET(CONN(obj)->fd, exceptions))
+ if (FD_ISSET(CONN(obj)->fd, exceptions)) {
sdb_log(SDB_LOG_INFO, "Exception on fd %d",
CONN(obj)->fd);
+ /* close the connection */
+ sdb_llist_iter_remove_current(iter);
+ sdb_object_deref(obj);
+ continue;
+ }
if (FD_ISSET(CONN(obj)->fd, ready)) {
sdb_llist_iter_remove_current(iter);
void
sdb_fe_sock_destroy(sdb_fe_socket_t *sock)
{
- size_t i;
-
if (! sock)
return;
- for (i = 0; i < sock->listeners_num; ++i) {
- listener_destroy(sock->listeners + i);
- }
- if (sock->listeners)
- free(sock->listeners);
- sock->listeners = NULL;
+ socket_clear(sock);
sdb_llist_destroy(sock->open_connections);
sock->open_connections = NULL;
return 0;
} /* sdb_fe_sock_add_listener */
+void
+sdb_fe_sock_clear_listeners(sdb_fe_socket_t *sock)
+{
+ if (! sock)
+ return;
+
+ socket_clear(sock);
+} /* sdb_fe_sock_clear_listeners */
+
int
sdb_fe_sock_listen_and_serve(sdb_fe_socket_t *sock, sdb_fe_loop_t *loop)
{
return -1;
}
- sdb_log(SDB_LOG_INFO, "frontend: Starting %d connection "
- "handler thread%s managing %d listener%s",
+ sdb_log(SDB_LOG_INFO, "frontend: Starting %zu connection "
+ "handler thread%s managing %zu listener%s",
loop->num_threads, loop->num_threads == 1 ? "" : "s",
sock->listeners_num, sock->listeners_num == 1 ? "" : "s");
while (sdb_llist_iter_has_next(iter)) {
sdb_object_t *obj = sdb_llist_iter_get_next(iter);
+
+ if (CONN(obj)->fd < 0) {
+ sdb_llist_iter_remove_current(iter);
+ sdb_object_deref(obj);
+ continue;
+ }
+
FD_SET(CONN(obj)->fd, &ready);
FD_SET(CONN(obj)->fd, &exceptions);