Chinaunix首页 | 论坛 | 博客
  • 博客访问: 15347676
  • 博文数量: 2005
  • 博客积分: 11986
  • 博客等级: 上将
  • 技术积分: 22535
  • 用 户 组: 普通用户
  • 注册时间: 2007-05-17 13:56
文章分类

全部博文(2005)

文章存档

2014年(2)

2013年(2)

2012年(16)

2011年(66)

2010年(368)

2009年(743)

2008年(491)

2007年(317)

分类: LINUX

2009-06-13 19:14:49

浅析dbus server接收一个client连接大体流程

  当一个client向dbus server发送连接之后,dbus server端socket_handle_watch()回调函数被执行,处理此次client发出的主动连接.(对于 socket_handle_watch()分析见
《浅析dbus系统watch函数是如何注册登记的》)

socket_handle_watch
static dbus_bool_t
socket_handle_watch (DBusWatch *watch,
                   unsigned int flags,
                   void *data)
{
    ......
    int client_fd;
    int listen_fd;

    listen_fd = dbus_watch_get_socket (watch); // 该watch对应的fd句柄

    client_fd = _dbus_accept (listen_fd); // 接受client的连接,生成client对应句柄[luther.gliethttp]

    handle_new_client_fd_and_unlock (server, client_fd); //

    ......
}
==>handle_new_client_fd_and_unlock (server, client_fd);
==*>_dbus_transport_new_for_socket (client_fd, &server->guid_hex, NULL);
==**>_dbus_transport_init_base (&socket_transport->base, &socket_vtable, server_guid, address)
==***>_dbus_auth_server_new (server_guid) 或者 _dbus_auth_client_new ()
DBusAuth*
_dbus_auth_server_new (const DBusString *guid)
{
  DBusAuth *auth;
  DBusAuthServer *server_auth;
  DBusString guid_copy;

  if (!_dbus_string_init (&guid_copy))
    return NULL;

  if (!_dbus_string_copy (guid, 0, &guid_copy, 0))
    {
      _dbus_string_free (&guid_copy);
      return NULL;
    }

  auth = _dbus_auth_new (sizeof (DBusAuthServer));
  if (auth == NULL)
    {
      _dbus_string_free (&guid_copy);
      return NULL;
    }
 
  auth->side = auth_side_server;
  auth->state = &server_state_waiting_for_auth; // 等待auth认证


  server_auth = DBUS_AUTH_SERVER (auth);

  server_auth->guid = guid_copy;
 
  /* perhaps this should be per-mechanism with a lower
   * max
   */

  server_auth->failures = 0;
  server_auth->max_failures = 6;
 
  return auth;
}

DBusAuth*
_dbus_auth_client_new (void)
{
  DBusAuth *auth;
  DBusString guid_str;

  if (!_dbus_string_init (&guid_str))
    return NULL;

  auth = _dbus_auth_new (sizeof (DBusAuthClient));
  if (auth == NULL)
    {
      _dbus_string_free (&guid_str);
      return NULL;
    }

  DBUS_AUTH_CLIENT (auth)->guid_from_server = guid_str;

  auth->side = auth_side_client;
  auth->state = &client_state_need_send_auth; // 标识client需要认证


  /* Start the auth conversation by sending AUTH for our default
   * mechanism */

  if (!send_auth (auth, &all_mechanisms[0]))
// 发送认证命令,默认就是将aut->outgoing头部变为:auth->outgoing = "AUTH EXTERNAL 31303030\r\n"

    {
      _dbus_auth_unref (auth);
      return NULL;
    }
 
  return auth;
}

static dbus_bool_t
send_auth (DBusAuth *auth, const DBusAuthMechanismHandler *mech)
{
  DBusString auth_command;

  if (!_dbus_string_init (&auth_command))
    return FALSE;
     
  if (!_dbus_string_append (&auth_command,
                            "AUTH "))
    {
      _dbus_string_free (&auth_command);
      return FALSE;
    }
 
  if (!_dbus_string_append (&auth_command,
                            mech->mechanism))
    {
      _dbus_string_free (&auth_command);
      return FALSE;
    }

  if (mech->client_initial_response_func != NULL)
    {
      if (!_dbus_string_append (&auth_command, " "))
        {
          _dbus_string_free (&auth_command);
          return FALSE;
        }
     // 最终将调用handle_client_initial_response_external_mech(auth, "AUTH EXTERNAL ");

     // handle_client_initial_response_external_mech()函数将geteuid()获得的EUID整数值

     // 转为ascii型hex十六进制值,追加到response字符串结尾[luther.gliethttp]

     // 所以最后auth_command中字符串内容为(假设我们获得的EUID为"1000",即'1' '0' '0' '0'

     // ,即49 48 48 48,即0x31 30 30 30):

     // auth_command = "AUTH EXTERNAL 31303030"

      if (!(* mech->client_initial_response_func) (auth, &auth_command))
        {
          _dbus_string_free (&auth_command);
          return FALSE;
        }
    }
 
  if (!_dbus_string_append (&auth_command,
                            "\r\n"))
    {
      _dbus_string_free (&auth_command);
      return FALSE;
    }

  if (!_dbus_string_copy (&auth_command, 0,
                          &auth->outgoing,
// 这样auth->outgoing = "AUTH EXTERNAL 31303030\r\n"

                          _dbus_string_get_length (&auth->outgoing)))
    {
      _dbus_string_free (&auth_command);
      return FALSE;
    }

  _dbus_string_free (&auth_command);
  shutdown_mech (auth); // 关闭该auth之前获得的认证信息,之后释放auth->mech = NULL;

  auth->mech = mech;
  goto_state (auth, &client_state_waiting_for_data); // 标识client已经认证成功,进入下一个state,等待数据到来.


  return TRUE;
}

static dbus_bool_t
handle_client_initial_response_external_mech (DBusAuth *auth,
                                              DBusString *response)
{
  /* We always append our UID as an initial response, so the server
   * doesn't have to send back an empty challenge to check whether we
   * want to specify an identity. i.e. this avoids a round trip that
   * the spec for the EXTERNAL mechanism otherwise requires.
   */

  DBusString plaintext;

  if (!_dbus_string_init (&plaintext))
    return FALSE;

  if (!_dbus_append_user_from_current_process (&plaintext))
    goto failed;

  if (!_dbus_string_hex_encode (&plaintext, 0,
// 将geteuid()获得的EUID整数值转为ascii型hex十六进制值,追加到response字符串结尾[luther.gliethttp]

                response,
                _dbus_string_get_length (response)))
    goto failed;

  _dbus_string_free (&plaintext);
 
  return TRUE;

 failed:
  _dbus_string_free (&plaintext);
  return FALSE;
}
==>_dbus_transport_set_auth_mechanisms (transport, (const char **) server->auth_mechanisms)
dbus_bool_t
_dbus_transport_set_auth_mechanisms (DBusTransport *transport,
                                     const char **mechanisms)
{
  return _dbus_auth_set_mechanisms (transport->auth, mechanisms);
  // 将server->auth_mechanisms的所有认证复制一份到transport->auth->allowed_mechs中.

  // 那server->auth_mechanisms是什么时候得到数值的呢,

  // main==>bus_context_new

  // ==>parser = bus_config_load (config_file, TRUE, NULL, error); // 解析system.conf这个XML文件内容

  // 我们的system.conf文件定义了如下一条auth认证语句:

  // EXTERNAL

  // ==>process_config_first_time_only

  // ==*>auth_mechanisms[0] = "EXTERNAL";

  // ==*>setup_server (context, server, auth_mechanisms, error)

  // ==**>dbus_server_set_auth_mechanisms (server, (const char**) auth_mechanisms);

  // 这样server->auth_mechanisms就等于auth_mechanisms

  // 所以server->auth_mechanisms[0] = "EXTERNAL";

  // 所以transport->auth->allowed_mechs[0] = "EXTERNAL";

}

==*>connection = _dbus_connection_new_for_transport (transport);
==**>_dbus_transport_set_connection (transport, connection) // 将监控client_fd的socket_transport->write_watch和read_watch添加到context->loop中

dbus_bool_t
_dbus_transport_set_connection (DBusTransport *transport,
                                DBusConnection *connection)
{
  _dbus_assert (transport->vtable->connection_set != NULL);
  _dbus_assert (transport->connection == NULL);
  
  transport->connection = connection;

  _dbus_transport_ref (transport);
  if (!(* transport->vtable->connection_set) (transport)) // 引用socket_connection_set()函数添加client_fd到待poll结构中.

    transport->connection = NULL;
  _dbus_transport_unref (transport);

  return transport->connection != NULL;
}
==***>socket_connection_set
static const DBusTransportVTable socket_vtable = {
  socket_finalize,
  socket_handle_watch,
  socket_disconnect,
  socket_connection_set,
  socket_do_iteration,
  socket_live_messages_changed,
  socket_get_socket_fd
};

static dbus_bool_t
socket_connection_set (DBusTransport *transport)
{
  DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;

  _dbus_watch_set_handler (socket_transport->write_watch,
                           _dbus_connection_handle_watch, // 当dbus有数据需要发送到client_fd时,执行该handler处理

                           transport->connection, NULL);

  _dbus_watch_set_handler (socket_transport->read_watch,
                           _dbus_connection_handle_watch, // 当client_fd有数据发送过来时,执行该handler处理

                           transport->connection, NULL);
  
  if (!_dbus_connection_add_watch_unlocked (transport->connection, // 可以参考
《浅析dbus系统watch函数是如何注册登记的》

                                            socket_transport->write_watch))
    return FALSE;

  if (!_dbus_connection_add_watch_unlocked (transport->connection,
                                            socket_transport->read_watch))
    {
      _dbus_connection_remove_watch_unlocked (transport->connection,
                                              socket_transport->write_watch);
      return FALSE;
    }

  check_read_watch (transport);
  check_write_watch (transport);

  return TRUE;
}
==****>check_read_watch // 检测auth否,如果还没有,那么将执行auth状态机,启动认证流程[luther.gliethttp]

static void
check_read_watch (DBusTransport *transport)
{
  DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
  dbus_bool_t need_read_watch;

  _dbus_verbose ("%s: fd = %d\n",
                 _DBUS_FUNCTION_NAME, socket_transport->fd);
  
  if (transport->connection == NULL)
    return;

  if (transport->disconnected)
    {
      _dbus_assert (socket_transport->read_watch == NULL);
      return;
    }
  
  _dbus_transport_ref (transport);

  if (_dbus_transport_get_is_authenticated (transport))
    need_read_watch =
      _dbus_counter_get_value (transport->live_messages_size) < transport->max_live_messages_size;
  else
    {
      if (transport->receive_credentials_pending)
        need_read_watch = TRUE;
      else
        {
          /* The reason to disable need_read_watch when not WAITING_FOR_INPUT
           * is to avoid spinning on the file descriptor when we're waiting
           * to write or for some other part of the auth process
           */

          DBusAuthState auth_state;
          
          auth_state = _dbus_auth_do_work (transport->auth);

          /* If we need memory we install the read watch just in case,
           * if there's no need for it, it will get de-installed
           * next time we try reading. If we're authenticated we
           * install it since we normally have it installed while
           * authenticated.
           */

          if (auth_state == DBUS_AUTH_STATE_WAITING_FOR_INPUT ||
              auth_state == DBUS_AUTH_STATE_WAITING_FOR_MEMORY ||
              auth_state == DBUS_AUTH_STATE_AUTHENTICATED)
            need_read_watch = TRUE;
          else
            need_read_watch = FALSE;
        }
    }

  _dbus_verbose (" setting read watch enabled = %d\n", need_read_watch);
  _dbus_connection_toggle_watch_unlocked (transport->connection,
                                          socket_transport->read_watch,
                                          need_read_watch);

  _dbus_transport_unref (transport);
}

==*>new_connection_function = server->new_connection_function;

/*
main
==>bus_context_new
==>process_config_first_time_only
==>setup_server
==>dbus_server_set_new_connection_function (server, // 设置回调函数
                                           new_connection_callback,
                                           context, NULL);
最后server->new_connection_function = new_connection_callback;
==>new_connection_callback
*/

==*>(* new_connection_function) (server, connection, new_connection_data);


new_connection_callback

==>bus_connections_setup_connection

==*>dbus_connection_set_watch_functions (connection,
                                            add_connection_watch,
                                            remove_connection_watch,
                                            NULL,
                                            connection,
                                            NULL);

==*>add_connection_watch

static dbus_bool_t
add_connection_watch (DBusWatch      *watch,
                      void           *data)
{
  DBusConnection *connection = data;

  return _dbus_loop_add_watch (connection_get_loop (connection),
                               watch, connection_watch_callback, connection,
                               NULL);
}

==**>_dbus_loop_add_watch

dbus_bool_t
_dbus_loop_add_watch (DBusLoop          *loop,
                      DBusWatch        *watch,
                      DBusWatchFunction  function,
                      void             *data,
                      DBusFreeFunction  free_data_func)
{
  WatchCallback *wcb;

  wcb = watch_callback_new (watch, function, data, free_data_func);
  if (wcb == NULL)
    return FALSE;

  if (!add_callback (loop, (Callback*) wcb)) // 添加到
loop->callbacks链表上
    {
      wcb->callback.free_data_func = NULL; /* don't want to have this side effect */
      callback_unref ((Callback*) wcb);
      return FALSE;
    }
 
  return TRUE;
}

==***>add_callback

==****>_dbus_list_append (&loop->callbacks, cb)

看看什么时候调用loop->callbacks链表上登记的所有watch连接

****> main
****> _dbus_loop_run (bus_context_get_loop (context)) // 执行context->loop为上下文的循环

****> _dbus_loop_iterate
dbus_bool_t
_dbus_loop_iterate (DBusLoop *loop,
                    dbus_bool_t block)
{
#define N_STACK_DESCRIPTORS 64
    ......
  if (loop->callbacks == NULL)
    goto next_iteration;

    if (loop->watch_count > N_STACK_DESCRIPTORS) {
      fds = dbus_new0 (DBusPollFD, loop->watch_count);
      
      while (fds == NULL)
        {
          _dbus_wait_for_memory ();
          fds = dbus_new0 (DBusPollFD, loop->watch_count);
        }
      
      watches_for_fds = dbus_new (WatchCallback*, loop->watch_count);
      while (watches_for_fds == NULL)
        {
          _dbus_wait_for_memory ();
          watches_for_fds = dbus_new (WatchCallback*, loop->watch_count);
        }
    } else {
      fds = stack_fds;
      watches_for_fds = stack_watches_for_fds;
    }
  /* fill our array of fds and watches */
  n_fds = 0;
  link = _dbus_list_get_first_link (&loop->callbacks);
  while (link != NULL)
    {
        ......
              fds[n_fds].fd = dbus_watch_get_socket (wcb->watch);
              fds[n_fds].revents = 0;
              fds[n_fds].events = 0;
              if (flags & DBUS_WATCH_READABLE)
                fds[n_fds].events |= _DBUS_POLLIN;
              if (flags & DBUS_WATCH_WRITABLE)
                fds[n_fds].events |= _DBUS_POLLOUT;
        ......
        n_ready = _dbus_poll (fds, n_fds, timeout);
        // 执行poll,监控_dbus_loop_add_watch函数登记到context->loop->callbacks上的所有watch单元对应的fd.

        // add_server_watch 或者 add_connection_watch 或者 add_babysitter_watch都将调用

        // _dbus_loop_add_watch向context->loop->callbacks追加watch单元.

    }
}
****> server_watch_callback
****> dbus_watch_handle
****> 首先请参考《浅析dbus系统watch函数是如何注册登记的》
****> socket_handle_watch // 感知client链接

阅读(4690) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~