/* -*- mode: C; c-file-style: "gnu" -*- */
/* dbus-server-unix.c Server implementation for Unix network protocols.
*
- * Copyright (C) 2002 Red Hat Inc.
+ * Copyright (C) 2002, 2003 Red Hat Inc.
*
* Licensed under the Academic Free License version 1.2
*
#include "dbus-connection-internal.h"
#include <sys/types.h>
#include <unistd.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <errno.h>
-#include <fcntl.h>
/**
* @defgroup DBusServerUnix DBusServer implementations for UNIX
*/
struct DBusServerUnix
{
- DBusServer base; /**< Parent class members. */
- int fd; /**< File descriptor or -1 if disconnected. */
- DBusWatch *watch; /**< File descriptor watch. */
+ DBusServer base; /**< Parent class members. */
+ int fd; /**< File descriptor or -1 if disconnected. */
+ DBusWatch *watch; /**< File descriptor watch. */
+ char *socket_name; /**< Name of domain socket, to unlink if appropriate */
};
static void
unix_finalize (DBusServer *server)
{
DBusServerUnix *unix_server = (DBusServerUnix*) server;
-
- _dbus_server_finalize_base (server);
if (unix_server->watch)
_dbus_watch_unref (unix_server->watch);
+
+ dbus_free (unix_server->socket_name);
+
+ _dbus_server_finalize_base (server);
dbus_free (server);
}
-static void
+/**
+ * @todo unreffing the connection at the end may cause
+ * us to drop the last ref to the connection before
+ * disconnecting it. That is invalid.
+ */
+/* Return value is just for memory, not other failures. */
+static dbus_bool_t
handle_new_client_fd (DBusServer *server,
int client_fd)
{
_dbus_verbose ("Creating new client connection with fd %d\n", client_fd);
if (!_dbus_set_fd_nonblocking (client_fd, NULL))
- return;
+ return TRUE;
- transport = _dbus_transport_new_for_fd (client_fd);
+ transport = _dbus_transport_new_for_fd (client_fd, TRUE, NULL);
if (transport == NULL)
{
close (client_fd);
- return;
+ return FALSE;
}
+ if (!_dbus_transport_set_auth_mechanisms (transport,
+ (const char **) server->auth_mechanisms))
+ {
+ _dbus_transport_unref (transport);
+ return FALSE;
+ }
+
/* note that client_fd is now owned by the transport, and will be
* closed on transport disconnection/finalization
*/
_dbus_transport_unref (transport);
if (connection == NULL)
- return;
-
+ return FALSE;
+
/* See if someone wants to handle this new connection,
* self-referencing for paranoia
*/
/* If no one grabbed a reference, the connection will die. */
dbus_connection_unref (connection);
+
+ return TRUE;
}
-static void
-unix_handle_watch (DBusServer *server,
- DBusWatch *watch,
- unsigned int flags)
+static dbus_bool_t
+unix_handle_watch (DBusWatch *watch,
+ unsigned int flags,
+ void *data)
{
- DBusServerUnix *unix_server = (DBusServerUnix*) server;
+ DBusServer *server = data;
+ DBusServerUnix *unix_server = data;
_dbus_assert (watch == unix_server->watch);
listen_fd = dbus_watch_get_fd (watch);
- retry:
- client_fd = accept (listen_fd, NULL, NULL);
+ client_fd = _dbus_accept (listen_fd);
if (client_fd < 0)
{
- if (errno == EINTR)
- goto retry;
- else if (errno == EAGAIN || errno == EWOULDBLOCK)
+ /* EINTR handled for us */
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
_dbus_verbose ("No client available to accept after all\n");
else
_dbus_verbose ("Failed to accept a client connection: %s\n",
}
else
{
- handle_new_client_fd (server, client_fd);
+ _dbus_fd_set_close_on_exec (client_fd);
+
+ if (!handle_new_client_fd (server, client_fd))
+ _dbus_verbose ("Rejected client connection due to lack of memory\n");
}
}
if (flags & DBUS_WATCH_HANGUP)
_dbus_verbose ("Hangup on server listening socket\n");
+
+ return TRUE;
}
static void
close (unix_server->fd);
unix_server->fd = -1;
+
+ if (unix_server->socket_name != NULL)
+ {
+ DBusString tmp;
+ _dbus_string_init_const (&tmp, unix_server->socket_name);
+ _dbus_delete_file (&tmp, NULL);
+ }
}
static DBusServerVTable unix_vtable = {
unix_finalize,
- unix_handle_watch,
unix_disconnect
};
* accept new client connections.
*
* @param fd the file descriptor.
+ * @param address the server's address
* @returns the new server, or #NULL if no memory.
*
*/
DBusServer*
-_dbus_server_new_for_fd (int fd)
+_dbus_server_new_for_fd (int fd,
+ const DBusString *address)
{
DBusServerUnix *unix_server;
DBusWatch *watch;
-
- watch = _dbus_watch_new (fd,
- DBUS_WATCH_READABLE);
- if (watch == NULL)
- return NULL;
unix_server = dbus_new0 (DBusServerUnix, 1);
if (unix_server == NULL)
+ return NULL;
+
+ watch = _dbus_watch_new (fd,
+ DBUS_WATCH_READABLE,
+ TRUE,
+ unix_handle_watch, unix_server,
+ NULL);
+ if (watch == NULL)
{
- _dbus_watch_unref (watch);
+ dbus_free (unix_server);
return NULL;
}
if (!_dbus_server_init_base (&unix_server->base,
- &unix_vtable))
+ &unix_vtable, address))
{
_dbus_watch_unref (watch);
dbus_free (unix_server);
* Creates a new server listening on the given Unix domain socket.
*
* @param path the path for the domain socket.
- * @param result location to store reason for failure.
+ * @param error location to store reason for failure.
* @returns the new server, or #NULL on failure.
*/
DBusServer*
_dbus_server_new_for_domain_socket (const char *path,
- DBusResultCode *result)
+ DBusError *error)
{
DBusServer *server;
+ DBusServerUnix *unix_server;
int listen_fd;
- struct sockaddr_un addr;
-
- listen_fd = socket (AF_LOCAL, SOCK_STREAM, 0);
+ DBusString address;
+ char *path_copy;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
- if (listen_fd < 0)
+ if (!_dbus_string_init (&address))
{
- dbus_set_result (result, _dbus_result_from_errno (errno));
- _dbus_verbose ("Failed to create socket \"%s\": %s\n",
- path, _dbus_strerror (errno));
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
- if (!_dbus_set_fd_nonblocking (listen_fd, result))
+ if (!_dbus_string_append (&address, "unix:path=") ||
+ !_dbus_string_append (&address, path))
{
- close (listen_fd);
- return NULL;
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ goto failed_0;
}
- _DBUS_ZERO (addr);
- addr.sun_family = AF_LOCAL;
- strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
- addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH] = '\0';
+ path_copy = _dbus_strdup (path);
+ if (path_copy == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ goto failed_0;
+ }
+
+ listen_fd = _dbus_listen_unix_socket (path, error);
+ _dbus_fd_set_close_on_exec (listen_fd);
- if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0)
+ if (listen_fd < 0)
{
- dbus_set_result (result, _dbus_result_from_errno (errno));
- _dbus_verbose ("Failed to bind socket \"%s\": %s\n",
- path, _dbus_strerror (errno));
- close (listen_fd);
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ goto failed_1;
+ }
+
+ server = _dbus_server_new_for_fd (listen_fd, &address);
+ if (server == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ goto failed_2;
+ }
+
+ unix_server = (DBusServerUnix*) server;
+ unix_server->socket_name = path_copy;
+
+ _dbus_string_free (&address);
+
+ return server;
+
+ failed_2:
+ _dbus_close (listen_fd, NULL);
+ failed_1:
+ dbus_free (path_copy);
+ failed_0:
+ _dbus_string_free (&address);
+
+ return NULL;
+}
+
+/**
+ * Creates a new server listening on the given hostname and port.
+ * If the hostname is NULL, listens on localhost.
+ *
+ * @param host the hostname to listen on.
+ * @param port the port to listen on.
+ * @param error location to store reason for failure.
+ * @returns the new server, or #NULL on failure.
+ */
+DBusServer*
+_dbus_server_new_for_tcp_socket (const char *host,
+ dbus_uint32_t port,
+ DBusError *error)
+{
+ DBusServer *server;
+ int listen_fd;
+ DBusString address;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ if (!_dbus_string_init (&address))
+ {
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
- if (listen (listen_fd, 30 /* backlog */) < 0)
+ if (!_dbus_string_append (&address, "tcp:host=") ||
+ !_dbus_string_append (&address, host) ||
+ !_dbus_string_append (&address, ",port=") ||
+ !_dbus_string_append_int (&address, port))
{
- dbus_set_result (result, _dbus_result_from_errno (errno));
- _dbus_verbose ("Failed to listen on socket \"%s\": %s\n",
- path, _dbus_strerror (errno));
- close (listen_fd);
+ _dbus_string_free (&address);
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
return NULL;
}
- server = _dbus_server_new_for_fd (listen_fd);
+ listen_fd = _dbus_listen_tcp_socket (host, port, error);
+ _dbus_fd_set_close_on_exec (listen_fd);
+
+ if (listen_fd < 0)
+ {
+ _dbus_string_free (&address);
+ return NULL;
+ }
+
+ server = _dbus_server_new_for_fd (listen_fd, &address);
if (server == NULL)
{
- dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
close (listen_fd);
+ _dbus_string_free (&address);
return NULL;
}
+ _dbus_string_free (&address);
+
return server;
+
+
}
/** @} */