/**
 * Creates a new server listening on the given file descriptor.  The
 * file descriptor should be nonblocking (use
 * _dbus_set_fd_nonblocking() to make it so). The file descriptor
 * should be listening for connections, that is, listen() should have
 * been successfully invoked on it. The server will use accept() to
 * accept new client connections.
 *
 * @param fds list of file descriptors.
 * @param n_fds number of file descriptors
 * @param address the server's address
 * @param noncefile to be used for authentication (NULL if not needed)
 * @returns the new server, or #NULL if no memory.
 *
 */
DBusServer*
_dbus_server_new_for_socket (int              *fds,
                             int               n_fds,
                             const DBusString *address,
                             DBusNonceFile    *noncefile)
{
  DBusServerSocket *socket_server;
  DBusServer *server;
  int i;

  socket_server = dbus_new0 (DBusServerSocket, 1);
  if (socket_server == NULL)
    return NULL;

  socket_server->noncefile = noncefile;

  socket_server->fds = dbus_new (int, n_fds);
  if (!socket_server->fds)
    goto failed_0;

  socket_server->watch = dbus_new0 (DBusWatch *, n_fds);
  if (!socket_server->watch)
    goto failed_1;

  for (i = 0 ; i < n_fds ; i++)
    {
      DBusWatch *watch;

      watch = _dbus_watch_new (fds[i],
                               DBUS_WATCH_READABLE,
                               TRUE,
                               socket_handle_watch, socket_server,
                               NULL);
      if (watch == NULL)
        goto failed_2;

      socket_server->n_fds++;
      socket_server->fds[i] = fds[i];
      socket_server->watch[i] = watch;
    }

  if (!_dbus_server_init_base (&socket_server->base,
                               &socket_vtable, address))
    goto failed_2;

  server = (DBusServer*)socket_server;

  SERVER_LOCK (server);

  for (i = 0 ; i < n_fds ; i++)
    {
      if (!_dbus_server_add_watch (&socket_server->base,
                                   socket_server->watch[i]))
        {
          int j;
          for (j = 0 ; j < i ; j++)
            _dbus_server_remove_watch (server,
                                       socket_server->watch[j]);

          SERVER_UNLOCK (server);
          _dbus_server_finalize_base (&socket_server->base);
          goto failed_2;
        }
    }

  SERVER_UNLOCK (server);

  return (DBusServer*) socket_server;

 failed_2:
  for (i = 0 ; i < n_fds ; i++)
    {
      if (socket_server->watch[i] != NULL)
        {
          _dbus_watch_unref (socket_server->watch[i]);
          socket_server->watch[i] = NULL;
        }
    }
  dbus_free (socket_server->watch);

 failed_1:
  dbus_free (socket_server->fds);

 failed_0:
  dbus_free (socket_server);
  return NULL;
}
/**
 * Creates a new debug server using an in-process pipe
 *
 * @param server_name the name of the server.
 * @param error address where an error can be returned.
 * @returns a new server, or #NULL on failure.
 */
DBusServer*
_dbus_server_debug_pipe_new (const char     *server_name,
                             DBusError      *error)
{
    DBusServerDebugPipe *debug_server;
    DBusString address;
    DBusString name_str;

    _DBUS_ASSERT_ERROR_IS_CLEAR (error);

    if (!pipe_hash_ref ())
        return NULL;

    if (_dbus_hash_table_lookup_string (server_pipe_hash, server_name) != NULL)
    {
        dbus_set_error (error, DBUS_ERROR_ADDRESS_IN_USE, NULL);
        pipe_hash_unref ();
        return NULL;
    }

    debug_server = dbus_new0 (DBusServerDebugPipe, 1);
    if (debug_server == NULL)
        goto nomem_0;

    if (!_dbus_string_init (&address))
        goto nomem_1;

    _dbus_string_init_const (&name_str, server_name);
    if (!_dbus_string_append (&address, "debug-pipe:name=") ||
            !_dbus_address_append_escaped (&address, &name_str))
        goto nomem_2;

    debug_server->name = _dbus_strdup (server_name);
    if (debug_server->name == NULL)
        goto nomem_2;

    if (!_dbus_server_init_base (&debug_server->base,
                                 &debug_vtable, &address))
        goto nomem_3;

    if (!_dbus_hash_table_insert_string (server_pipe_hash,
                                         debug_server->name,
                                         debug_server))
        goto nomem_4;

    _dbus_string_free (&address);

    /* server keeps the pipe hash ref */

    return (DBusServer *)debug_server;

nomem_4:
    _dbus_server_finalize_base (&debug_server->base);
nomem_3:
    dbus_free (debug_server->name);
nomem_2:
    _dbus_string_free (&address);
nomem_1:
    dbus_free (debug_server);
nomem_0:
    pipe_hash_unref ();
    dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
    return NULL;
}