dbus源码走读-2 BusContext的创建

BusContext的创建是调用bus_context_new()函数完成的,它的源代码在bus/bus.c中, line 767.

该函数的入参包括:

const DBusString *config_file//配置文件
BusContextFlags flags//由命令行参数生成的flags标志
DBusPipe *print_addr_pipe//
DBusPipe *print_pid_pipe//
const DBusString *address//地址字符串

输出参数:
DBusError *error//错误信息

返回值

BusContext *。

flags 是一个枚举类型,定义了以下位:

BUS_CONTEXT_FLAG_NONE = 0,
BUS_CONTEXT_FLAG_FORK_ALWAYS = (1 << 1),
BUS_CONTEXT_FLAG_FORK_NEVER = (1 << 2),
BUS_CONTEXT_FLAG_WRITE_PID_FILE = (1 << 3),
BUS_CONTEXT_FLAG_SYSTEMD_ACTIVATION = (1 << 4),
BUS_CONTEXT_FLAG_SYSLOG_ALWAYS = (1 << 5),
BUS_CONTEXT_FLAG_SYSLOG_NEVER = (1 << 6),
BUS_CONTEXT_FLAG_SYSLOG_ONLY = (1 << 7)

返回类型BusContext是一个很复杂的结构体,先浏览一下大概内容吧。

struct BusContext
{
int refcount;
DBusGUID uuid;
char *config_file;
char *type;
char *servicehelper;
char *address;
char *pidfile;
char *user;
char *log_prefix;
DBusLoop *loop;
DBusList *servers;
BusConnections *connections;
BusActivation *activation;
BusRegistry *registry;
BusPolicy *policy;
BusMatchmaker *matchmaker;
BusLimits limits;
DBusRLimit *initial_fd_limit;
BusContainers *containers;
unsigned int fork : 1;
unsigned int syslog : 1;
unsigned int keep_umask : 1;
unsigned int allow_anonymous : 1;
unsigned int systemd_activation : 1;
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
unsigned int quiet_log : 1;
#endif
dbus_bool_t watches_enabled;
};

 bus_context_new首先定义了两个指针,BusContext *context 和 BusConfigParser *parser。要创建一个新的BusContext需要解析BusConfig,于是要创建一个BusConfigParser,这是很自然的。

接下来的一步令人费解,调用dbus_server_allocate_data_slot (&server_data_slot) 分配了一个data slot。什么是data slot?看server_data_slot的类型只是一个32位的整型值。估计这里面有一种类型的抽象或者一种机制,具体的功能是什么还不清楚。暂时不深究,继续往下读。[TODO]

下一步比较好理解,就是给BusContext分配内存。context = dbus_new0 (BusContext, 1);

然后是把context的引用计数设置为1. 并生成uuid。_dbus_generate_uuid (&context->uuid, error)

然后把配置文件路径拷贝到context的config_file中。

然后是调用context->loop = _dbus_loop_new ();创建了DBusLoop对象。这应该又是一个比较重要的对象,需要进一步研究。[TODO]

然后把watches_enabled设置为真。context->watches_enabled = TRUE; watches_enabled表示什么意思?[TODO]

下面是创建另一个重要的结构体: context->registry = bus_registry_new (context);它的工作机制是什么?[TODO]

接下来是创建了配置解析器。parser = bus_config_load (config_file, TRUE, NULL, error);可以预测要解析配置参数了。

配置参数分两类,

第一类是只需要处理一次的项: process_config_first_time_only (context, parser, address, flags, error)。

第二类是每次加载(比如kill -1)都要处理的参数:process_config_every_time (context, parser, FALSE, error)。

然后再次调用dbus_server_allocate_data_slot (&server_data_slot)。这次并没有真正分配data slot,只是对前面调用的data slot的引用数加1。为什么需要做这一步?[TODO]

line 854~891就是从context中读出address,加上换行符后写入print_addr_pipe中。

下面是几个重要的步骤:

1. 创建了Connection结构体: context->connections = bus_connections_new (context). [TODO]待后续深究。

2. 创建MatchMaker对象: context->matchmaker = bus_matchmaker_new ()

3. 创建Container对象: context->containers = bus_containers_new ()

然后做了一个小检查,检查配置的用户是否有效,否则fork或切换用户的时候会失败。

_dbus_verify_daemon_user (context->user)

紧接着就要做进入daemon的操作了。因为dbus server是作为daemon进程运行的。有两种方式切换为daemon进程。

1.如果允许fork一个新进程,则调用如下函数变成daemon进程。

_dbus_become_daemon (context->pidfile ? &u : NULL,print_pid_pipe,error,context->keep_umask)

2. 否则,只是把pid写入pidfile和print_pid_pipe管道。[TODO: 这样就变成daemon进程了?]

然后是修改描述符限制和切换为daemon user。

raise_file_descriptor_limit (context)

_dbus_change_to_daemon_user (context->user, error)

初始化审计系统: bus_audit_init (context)

初始化安全模块:

bus_selinux_full_init (context, error)

bus_apparmor_full_init (error)

以及安全模块初始化后的一些处理: process_config_postinit (context, parser, error)

最后是资源释放并返回context指针。

dbus_server_free_data_slot (&server_data_slot);

return context;

纵观整个bus_context_new()过程,不难发现,它很像设计模式中的Builder pattern中的构建器。它负责BusContext各个模块的创建和初始化。

这里采用广度优先的方式浏览了bus_context_new()的大致过程。下面将对BusContext中几个重点对象的构造进行浏览,以进一步窥探dbus server的内部原理。

下面是主要的流程图:

 

 

posted @ 2022-10-14 13:56  耕读编码  阅读(593)  评论(0)    收藏  举报