/* Return value is just for memory, not other failures. */
static dbus_bool_t
handle_new_client_fd_and_unlock (DBusServer *server,
                                 int         client_fd)
{
  DBusConnection *connection;
  DBusTransport *transport;
  DBusNewConnectionFunction new_connection_function;
  DBusServerSocket* socket_server;
  void *new_connection_data;

  socket_server = (DBusServerSocket*)server;
  _dbus_verbose ("Creating new client connection with fd %d\n", client_fd);

  HAVE_LOCK_CHECK (server);

  if (!_dbus_set_fd_nonblocking (client_fd, NULL))
    {
      SERVER_UNLOCK (server);
      return TRUE;
    }

  transport = _dbus_transport_new_for_socket (client_fd, &server->guid_hex, FALSE);
  if (transport == NULL)
    {
      _dbus_close_socket (client_fd, NULL);
      SERVER_UNLOCK (server);
      return FALSE;
    }

  if (!_dbus_transport_set_auth_mechanisms (transport,
                                            (const char **) server->auth_mechanisms))
    {
      _dbus_transport_unref (transport);
      SERVER_UNLOCK (server);
      return FALSE;
    }

  /* note that client_fd is now owned by the transport, and will be
   * closed on transport disconnection/finalization
   */

  connection = _dbus_connection_new_for_transport (transport);
  _dbus_transport_unref (transport);
  transport = NULL; /* now under the connection lock */

  if (connection == NULL)
    {
      SERVER_UNLOCK (server);
      return FALSE;
    }

  /* See if someone wants to handle this new connection, self-referencing
   * for paranoia.
   */
  new_connection_function = server->new_connection_function;
  new_connection_data = server->new_connection_data;

  _dbus_server_ref_unlocked (server);
  SERVER_UNLOCK (server);

  if (new_connection_function)
    {
      (* new_connection_function) (server, connection,
                                   new_connection_data);
    }
  dbus_server_unref (server);

  /* If no one grabbed a reference, the connection will die. */
  _dbus_connection_close_if_only_one_ref (connection);
  dbus_connection_unref (connection);

  return TRUE;
}
/**
 * Creates the client-side transport for
 * a debug-pipe connection connected to the
 * given debug-pipe server name.
 *
 * @param server_name name of server to connect to
 * @param error address where an error can be returned.
 * @returns #NULL on no memory or transport
 */
DBusTransport*
_dbus_transport_debug_pipe_new (const char     *server_name,
                                DBusError      *error)
{
    DBusTransport *client_transport;
    DBusTransport *server_transport;
    DBusConnection *connection;
    int client_fd, server_fd;
    DBusServer *server;
    DBusString address;

    _DBUS_ASSERT_ERROR_IS_CLEAR (error);

    if (server_pipe_hash == NULL)
    {
        dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL);
        return NULL;
    }

    server = _dbus_hash_table_lookup_string (server_pipe_hash,
             server_name);
    if (server == NULL ||
            ((DBusServerDebugPipe*)server)->disconnected)
    {
        dbus_set_error (error, DBUS_ERROR_NO_SERVER, NULL);
        return NULL;
    }

    if (!_dbus_string_init (&address))
    {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        return NULL;
    }

    if (!_dbus_string_append (&address, "debug-pipe:name=") ||
            !_dbus_string_append (&address, server_name))
    {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        _dbus_string_free (&address);
        return NULL;
    }

    if (!_dbus_full_duplex_pipe (&client_fd, &server_fd, FALSE,
                                 NULL))
    {
        _dbus_verbose ("failed to create full duplex pipe\n");
        dbus_set_error (error, DBUS_ERROR_FAILED, "Could not create full-duplex pipe");
        _dbus_string_free (&address);
        return NULL;
    }

    _dbus_fd_set_close_on_exec (client_fd);
    _dbus_fd_set_close_on_exec (server_fd);

    client_transport = _dbus_transport_new_for_socket (client_fd,
                       NULL, &address);
    if (client_transport == NULL)
    {
        _dbus_close_socket (client_fd, NULL);
        _dbus_close_socket (server_fd, NULL);
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        _dbus_string_free (&address);
        return NULL;
    }

    _dbus_string_free (&address);

    client_fd = -1;

    server_transport = _dbus_transport_new_for_socket (server_fd,
                       &server->guid_hex, NULL);
    if (server_transport == NULL)
    {
        _dbus_transport_unref (client_transport);
        _dbus_close_socket (server_fd, NULL);
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        return NULL;
    }

    server_fd = -1;

    if (!_dbus_transport_set_auth_mechanisms (server_transport,
            (const char**) server->auth_mechanisms))
    {
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        _dbus_transport_unref (server_transport);
        _dbus_transport_unref (client_transport);
        return NULL;
    }

    connection = _dbus_connection_new_for_transport (server_transport);
    _dbus_transport_unref (server_transport);
    server_transport = NULL;

    if (connection == NULL)
    {
        _dbus_transport_unref (client_transport);
        dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
        return NULL;
    }

    /* See if someone wants to handle this new connection,
     * self-referencing for paranoia
     */
    if (server->new_connection_function)
    {
        dbus_server_ref (server);
        (* server->new_connection_function) (server, connection,
                                             server->new_connection_data);
        dbus_server_unref (server);
    }

    /* If no one grabbed a reference, the connection will die,
     * and the client transport will get an immediate disconnect
     */
    _dbus_connection_close_if_only_one_ref (connection);
    dbus_connection_unref (connection);

    return client_transport;
}