首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >hostapd的分析[通俗易懂]

hostapd的分析[通俗易懂]

作者头像
全栈程序员站长
发布于 2022-08-31 03:41:32
发布于 2022-08-31 03:41:32
2K00
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

Hostapd的功能就是作为AP的认证服务器,负责控制管理stations(通常可以认为带无线网卡的PC)的接入和认证。 通过Hostapd可以将无线网卡切换为AP/Master模式,通过修改配置文件,可以建立一个开放式的(不加密)的,WEP,WPA或WPA2的无线网络。并且通过修改配置文件可以设置无线网卡的各种参数,包括频率,信号,beacon包时间间隔,是否发送beacon包,如果响应探针请求等等。还可以设置mac地址过滤条件等。

hostapd的main函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int main(int argc, char *argv[])
{
    struct hapd_interfaces interfaces;
    int ret = 1;
    size_t i, j;
    int c, debug = 0, daemonize = 0;
    char *pid_file = NULL;
    const char *log_file = NULL;
    const char *entropy_file = NULL;
    char **bss_config = NULL, **tmp_bss;
    size_t num_bss_configs = 0;
#ifdef CONFIG_DEBUG_LINUX_TRACING
    int enable_trace_dbg = 0;
#endif /* CONFIG_DEBUG_LINUX_TRACING */
    int start_ifaces_in_sync = 0;
    char **if_names = NULL;
    size_t if_names_size = 0;

    if (os_program_init())
        return -1;

    os_memset(&interfaces, 0, sizeof(interfaces));
    interfaces.reload_config = hostapd_reload_config;
    interfaces.config_read_cb = hostapd_config_read;
    interfaces.for_each_interface = hostapd_for_each_interface;
    interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
    interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
    interfaces.driver_init = hostapd_driver_init;
    interfaces.global_iface_path = NULL;
    interfaces.global_iface_name = NULL;
    interfaces.global_ctrl_sock = -1;
    dl_list_init(&interfaces.global_ctrl_dst);

    for (;;) {
        c = getopt(argc, argv, "b:Bde:f:hi:KP:STtu:vg:G:");
        if (c < 0)
            break;
        switch (c) {
        case 'h':
            usage();
            break;
        case 'd':
            debug++;
            if (wpa_debug_level > 0)
                wpa_debug_level--;
            break;
        case 'B':
            daemonize++;
            break;
        case 'e':
            entropy_file = optarg;
            break;
        case 'f':
            log_file = optarg;
            break;
        case 'K':
            wpa_debug_show_keys++;
            break;
        case 'P':
            os_free(pid_file);
            pid_file = os_rel2abs_path(optarg);
            break;
        case 't':
            wpa_debug_timestamp++;
            break;
#ifdef CONFIG_DEBUG_LINUX_TRACING
        case 'T':
            enable_trace_dbg = 1;
            break;
#endif /* CONFIG_DEBUG_LINUX_TRACING */
        case 'v':
            show_version();
            exit(1);
            break;
        case 'g':
            if (hostapd_get_global_ctrl_iface(&interfaces, optarg))
                return -1;
            break;
        case 'G':
            if (hostapd_get_ctrl_iface_group(&interfaces, optarg))
                return -1;
            break;
        case 'b':
            tmp_bss = os_realloc_array(bss_config,
                           num_bss_configs + 1,
                           sizeof(char *));
            if (tmp_bss == NULL)
                goto out;
            bss_config = tmp_bss;
            bss_config[num_bss_configs++] = optarg;
            break;
        case 'S':
            start_ifaces_in_sync = 1;
            break;
#ifdef CONFIG_WPS
        case 'u':
            return gen_uuid(optarg);
#endif /* CONFIG_WPS */
        case 'i':
            if (hostapd_get_interface_names(&if_names,
                            &if_names_size, optarg))
                goto out;
            break;
        default:
            usage();
            break;
        }
    }

    if (optind == argc && interfaces.global_iface_path == NULL &&
        num_bss_configs == 0)
        usage();

    wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);

    if (log_file)
        wpa_debug_open_file(log_file);
    else
        wpa_debug_setup_stdout();
#ifdef CONFIG_DEBUG_LINUX_TRACING
    if (enable_trace_dbg) {
        int tret = wpa_debug_open_linux_tracing();
        if (tret) {
            wpa_printf(MSG_ERROR, "Failed to enable trace logging");
            return -1;
        }
    }
#endif /* CONFIG_DEBUG_LINUX_TRACING */

    interfaces.count = argc - optind;
    if (interfaces.count || num_bss_configs) {
        interfaces.iface = os_calloc(interfaces.count + num_bss_configs,
                         sizeof(struct hostapd_iface *));
        if (interfaces.iface == NULL) {
            wpa_printf(MSG_ERROR, "malloc failed");
            return -1;
        }
    }

    if (hostapd_global_init(&interfaces, entropy_file)) {
        wpa_printf(MSG_ERROR, "Failed to initialize global context");
        return -1;
    }

    eloop_register_timeout(HOSTAPD_CLEANUP_INTERVAL, 0,
                   hostapd_periodic, &interfaces, NULL);

    if (fst_global_init()) {
        wpa_printf(MSG_ERROR,
               "Failed to initialize global FST context");
        goto out;
    }

#if defined(CONFIG_FST) && defined(CONFIG_CTRL_IFACE)
    if (!fst_global_add_ctrl(fst_ctrl_cli))
        wpa_printf(MSG_WARNING, "Failed to add CLI FST ctrl");
#endif /* CONFIG_FST && CONFIG_CTRL_IFACE */

    /* Allocate and parse configuration for full interface files */
    for (i = 0; i < interfaces.count; i++) {
        char *if_name = NULL;

        if (i < if_names_size)
            if_name = if_names[i];

        interfaces.iface[i] = hostapd_interface_init(&interfaces,
                                 if_name,
                                 argv[optind + i],
                                 debug);
        if (!interfaces.iface[i]) {
            wpa_printf(MSG_ERROR, "Failed to initialize interface");
            goto out;
        }
        if (start_ifaces_in_sync)
            interfaces.iface[i]->need_to_start_in_sync = 1;
    }

    /* Allocate and parse configuration for per-BSS files */
    for (i = 0; i < num_bss_configs; i++) {
        struct hostapd_iface *iface;
        char *fname;

        wpa_printf(MSG_INFO, "BSS config: %s", bss_config[i]);
        fname = os_strchr(bss_config[i], ':');
        if (fname == NULL) {
            wpa_printf(MSG_ERROR,
                   "Invalid BSS config identifier '%s'",
                   bss_config[i]);
            goto out;
        }
        *fname++ = '\0';
        iface = hostapd_interface_init_bss(&interfaces, bss_config[i],
                           fname, debug);
        if (iface == NULL)
            goto out;
        for (j = 0; j < interfaces.count; j++) {
            if (interfaces.iface[j] == iface)
                break;
        }
        if (j == interfaces.count) {
            struct hostapd_iface **tmp;
            tmp = os_realloc_array(interfaces.iface,
                           interfaces.count + 1,
                           sizeof(struct hostapd_iface *));
            if (tmp == NULL) {
                hostapd_interface_deinit_free(iface);
                goto out;
            }
            interfaces.iface = tmp;
            interfaces.iface[interfaces.count++] = iface;
        }
    }

    /* * Enable configured interfaces. Depending on channel configuration, * this may complete full initialization before returning or use a * callback mechanism to complete setup in case of operations like HT * co-ex scans, ACS, or DFS are needed to determine channel parameters. * In such case, the interface will be enabled from eloop context within * hostapd_global_run(). */
    interfaces.terminate_on_error = interfaces.count;
    for (i = 0; i < interfaces.count; i++) { 
        //根据配置文件设置iface信息
        if (hostapd_driver_init(interfaces.iface[i]) ||
            hostapd_setup_interface(interfaces.iface[i]))  //将配置文件通过写入驱动
            goto out;
    }

    hostapd_global_ctrl_iface_init(&interfaces);

    if (hostapd_global_run(&interfaces, daemonize, pid_file)) {
        wpa_printf(MSG_ERROR, "Failed to start eloop");
        goto out;
    }

    ret = 0;

 out:
    hostapd_global_ctrl_iface_deinit(&interfaces);
    /* Deinitialize all interfaces */
    for (i = 0; i < interfaces.count; i++) {
        if (!interfaces.iface[i])
            continue;
        interfaces.iface[i]->driver_ap_teardown =
            !!(interfaces.iface[i]->drv_flags &
               WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT);
        hostapd_interface_deinit_free(interfaces.iface[i]);
    }
    os_free(interfaces.iface);

    if (interfaces.eloop_initialized)
        eloop_cancel_timeout(hostapd_periodic, &interfaces, NULL);
    hostapd_global_deinit(pid_file, interfaces.eloop_initialized);
    os_free(pid_file);

    if (log_file)
        wpa_debug_close_file();
    wpa_debug_close_linux_tracing();

    os_free(bss_config);

    for (i = 0; i < if_names_size; i++)
        os_free(if_names[i]);
    os_free(if_names);

    fst_global_deinit();

    os_program_deinit();

    return ret;
}

该函数主要分为三部分: 第一部是读取命令行参数作相应的处理。 第二部分主要是根据配置文件设置hapd_interface的参数然后通过一系列的函数调用进入内核态设置相应的内核参数 第三部分是在函数hostapd_global_run中死循环来检测socket或者timeout或者event的相关量是否发生变化进而调用相应的提前注册到该事件上的函数。

在函数hostapd_global_init 中初始化eloop这个全局变量并进入eloop死循环中:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static int hostapd_global_init(struct hapd_interfaces *interfaces, const char *entropy_file) { int i; os_memset(&global, 0, sizeof(global)); //重置global变量 hostapd_logger_register_cb(hostapd_logger_cb); if (eap_server_register_methods()) { //注册eap server的加密方法 wpa_printf(MSG_ERROR, "Failed to register EAP methods"); return -1; } if (eloop_init()) { wpa_printf(MSG_ERROR, "Failed to initialize event loop"); return -1; } interfaces->eloop_initialized = 1; random_init(entropy_file); #ifndef CONFIG_NATIVE_WINDOWS eloop_register_signal(SIGHUP, handle_reload, interfaces); eloop_register_signal(SIGUSR1, handle_dump_state, interfaces); #endif /* CONFIG_NATIVE_WINDOWS */ eloop_register_signal_terminate(handle_term, interfaces); #ifndef CONFIG_NATIVE_WINDOWS openlog("hostapd", 0, LOG_DAEMON); #endif /* CONFIG_NATIVE_WINDOWS */ for (i = 0; wpa_drivers[i]; i++) global.drv_count++; if (global.drv_count == 0) { wpa_printf(MSG_ERROR, "No drivers enabled"); return -1; } global.drv_priv = os_calloc(global.drv_count, sizeof(void *)); if (global.drv_priv == NULL) return -1; return 0; }

使用eap_server_register_methods函数注册eap server支持的安全模式,并存放在一个链表里面。 调用 eloop_init 函数初始化全局变量eloop结构体。 调用 random_init对各个事件注册,

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void random_init(const char *entropy_file) { os_free(random_entropy_file); if (entropy_file) random_entropy_file = os_strdup(entropy_file); else random_entropy_file = NULL; random_read_entropy(); #ifdef __linux__ if (random_fd >= 0) return; random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK); if (random_fd < 0) { wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s", strerror(errno)); return; } wpa_printf(MSG_DEBUG, "random: Trying to read entropy from " "/dev/random"); eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL); #endif /* __linux__ */ random_write_entropy(); }

eloop_register_read_sock 函数继续调用,eloop_register_read_sock,再使用eloop_register_sock 函数来实现注册socket。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int eloop_register_sock(int sock, eloop_event_type type,
            eloop_sock_handler handler,
            void *eloop_data, void *user_data)
{
    struct eloop_sock_table *table;

    assert(sock >= 0);
    table = eloop_get_sock_table(type);
    return eloop_sock_table_add_sock(table, sock, handler,
                     eloop_data, user_data);
}

从代码中可以看到该函数将相应的handler和data放进sock_table表中,实现注册。

回到main函数中,hostapd_interface_init 读取hostapd配置文件并进行分配和解析:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** * hostapd_interface_init - Read configuration file and init BSS data * * This function is used to parse configuration file for a full interface (one * or more BSSes sharing the same radio) and allocate memory for the BSS * interfaces. No actiual driver operations are started. */ static struct hostapd_iface * hostapd_interface_init(struct hapd_interfaces *interfaces, const char *if_name, const char *config_fname, int debug) { struct hostapd_iface *iface; int k; wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname); iface = hostapd_init(interfaces, config_fname); if (!iface) return NULL; if (if_name) { os_strlcpy(iface->conf->bss[0]->iface, if_name, sizeof(iface->conf->bss[0]->iface)); } iface->interfaces = interfaces; for (k = 0; k < debug; k++) { if (iface->bss[0]->conf->logger_stdout_level > 0) iface->bss[0]->conf->logger_stdout_level--; } if (iface->conf->bss[0]->iface[0] == '\0' && !hostapd_drv_none(iface->bss[0])) { wpa_printf(MSG_ERROR, "Interface name not specified in %s, nor by '-i' parameter", config_fname); hostapd_interface_deinit_free(iface); return NULL; } return iface; }

其中调用hostapd_init() 初始化配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** * hostapd_init - Allocate and initialize per-interface data * @config_file: Path to the configuration file * Returns: Pointer to the allocated interface data or %NULL on failure * * This function is used to allocate main data structures for per-interface * data. The allocated data buffer will be freed by calling * hostapd_cleanup_iface(). */ struct hostapd_iface * hostapd_init(struct hapd_interfaces *interfaces, const char *config_file) { struct hostapd_iface *hapd_iface = NULL; struct hostapd_config *conf = NULL; struct hostapd_data *hapd; size_t i; hapd_iface = hostapd_alloc_iface(); if (hapd_iface == NULL) goto fail; hapd_iface->config_fname = os_strdup(config_file); if (hapd_iface->config_fname == NULL) goto fail; conf = interfaces->config_read_cb(hapd_iface->config_fname);//读取配置文件 if (conf == NULL) goto fail; hapd_iface->conf = conf; hapd_iface->num_bss = conf->num_bss; hapd_iface->bss = os_calloc(conf->num_bss, sizeof(struct hostapd_data *)); if (hapd_iface->bss == NULL) goto fail; //根据配置文件中bss的配置个数conf->num_bss的值通过调用hostapd_alloc_bss_data分配空间及相关设置 for (i = 0; i < conf->num_bss; i++) { hapd = hapd_iface->bss[i] = hostapd_alloc_bss_data(hapd_iface, conf, conf->bss[i]); if (hapd == NULL) goto fail; hapd->msg_ctx = hapd; } return hapd_iface; fail: wpa_printf(MSG_ERROR, "Failed to set up interface with %s", config_file); if (conf) hostapd_config_free(conf); if (hapd_iface) { os_free(hapd_iface->config_fname); os_free(hapd_iface->bss); wpa_printf(MSG_DEBUG, "%s: free iface %p", __func__, hapd_iface); os_free(hapd_iface); } return NULL; } 

通过调用函数hostapd_driver_init获取配置信息保存在iface[i]中,然后通过调用函数hostapd_setup_interface函数将其配置信息写入内核。写入通过依次调用一下函数来实现:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
hostapd_setup_interface
------>setup_interface
    ------>hostapd_set_country
    ------>setup_interface2
        ------>hostapd_setup_interface_complete
                ------>hostapd_set_freq
                ------>hostapd_set_rts
    ------>hostapd_set_state
    ------>hostapd_tx_queue_para,   

通过这几个调用进入netlink层。

通过 hostapd_global_run处理socket事件的过程如下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize, const char *pid_file) { #ifdef EAP_SERVER_TNC int tnc = 0; size_t i, k; for (i = 0; !tnc && i < ifaces->count; i++) { for (k = 0; k < ifaces->iface[i]->num_bss; k++) { if (ifaces->iface[i]->bss[0]->conf->tnc) { tnc++; break; } } } if (tnc && tncs_global_init() < 0) { 
   //调用tncs_global_init完成tnc相关的初始化 wpa_printf(MSG_ERROR, "Failed to initialize TNCS"); return -1; } #endif /* EAP_SERVER_TNC */ if (daemonize) { if (os_daemonize(pid_file)) { 
   //调用os_daemonize函数实现将该程序以后台进程运行 wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno)); return -1; } if (eloop_sock_requeue()) { wpa_printf(MSG_ERROR, "eloop_sock_requeue: %s", strerror(errno)); return -1; } } eloop_run(); return 0; }

其中核心函数是eloop_run :

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void eloop_run(void) { #ifdef CONFIG_ELOOP_POLL int num_poll_fds; int timeout_ms = 0; #endif /* CONFIG_ELOOP_POLL */ #ifdef CONFIG_ELOOP_SELECT fd_set *rfds, *wfds, *efds; struct timeval _tv; #endif /* CONFIG_ELOOP_SELECT */ #ifdef CONFIG_ELOOP_EPOLL int timeout_ms = -1; #endif /* CONFIG_ELOOP_EPOLL */ #ifdef CONFIG_ELOOP_KQUEUE struct timespec ts; #endif /* CONFIG_ELOOP_KQUEUE */ int res; struct os_reltime tv, now; #ifdef CONFIG_ELOOP_SELECT  //为三个文件描述符集申请空间 rfds = os_malloc(sizeof(*rfds)); wfds = os_malloc(sizeof(*wfds)); efds = os_malloc(sizeof(*efds)); if (rfds == NULL || wfds == NULL || efds == NULL) goto out; #endif /* CONFIG_ELOOP_SELECT */ while (!eloop.terminate && (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 || eloop.writers.count > 0 || eloop.exceptions.count > 0)) { struct eloop_timeout *timeout; if (eloop.pending_terminate) { /* * This may happen in some corner cases where a signal * is received during a blocking operation. We need to * process the pending signals and exit if requested to * avoid hitting the SIGALRM limit if the blocking * operation took more than two seconds. */ // eloop_process_pending_signals函数对发生的信号进行处理 eloop_process_pending_signals(); if (eloop.terminate) break; } timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, list); if (timeout) { //对超时时间进行设置timeout,主要是为下面调用的select函数会用到超时时间做准备 os_get_reltime(&now); if (os_reltime_before(&now, &timeout->time)) os_reltime_sub(&timeout->time, &now, &tv); else tv.sec = tv.usec = 0; #if defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) timeout_ms = tv.sec * 1000 + tv.usec / 1000; #endif /* defined(CONFIG_ELOOP_POLL) || defined(CONFIG_ELOOP_EPOLL) */ #ifdef CONFIG_ELOOP_SELECT _tv.tv_sec = tv.sec; _tv.tv_usec = tv.usec; #endif /* CONFIG_ELOOP_SELECT */ #ifdef CONFIG_ELOOP_KQUEUE ts.tv_sec = tv.sec; ts.tv_nsec = tv.usec * 1000L; #endif /* CONFIG_ELOOP_KQUEUE */ } #ifdef CONFIG_ELOOP_POLL num_poll_fds = eloop_sock_table_set_fds( &eloop.readers, &eloop.writers, &eloop.exceptions, eloop.pollfds, eloop.pollfds_map, eloop.max_pollfd_map); res = poll(eloop.pollfds, num_poll_fds, timeout ? timeout_ms : -1); #endif /* CONFIG_ELOOP_POLL */ #ifdef CONFIG_ELOOP_SELECT  //将申请的文件描述符集与eloop对象相结合,并调用select函数对这些文件发生异常进行监听 eloop_sock_table_set_fds(&eloop.readers, rfds); eloop_sock_table_set_fds(&eloop.writers, wfds); eloop_sock_table_set_fds(&eloop.exceptions, efds); res = select(eloop.max_sock + 1, rfds, wfds, efds, timeout ? &_tv : NULL); #endif /* CONFIG_ELOOP_SELECT */ #ifdef CONFIG_ELOOP_EPOLL if (eloop.count == 0) { res = 0; } else { res = epoll_wait(eloop.epollfd, eloop.epoll_events, eloop.count, timeout_ms); } #endif /* CONFIG_ELOOP_EPOLL */ #ifdef CONFIG_ELOOP_KQUEUE if (eloop.count == 0) { res = 0; } else { res = kevent(eloop.kqueuefd, NULL, 0, eloop.kqueue_events, eloop.kqueue_nevents, timeout ? &ts : NULL); } #endif /* CONFIG_ELOOP_KQUEUE */ if (res < 0 && errno != EINTR && errno != 0) { wpa_printf(MSG_ERROR, "eloop: %s: %s", #ifdef CONFIG_ELOOP_POLL "poll" #endif /* CONFIG_ELOOP_POLL */ #ifdef CONFIG_ELOOP_SELECT "select" #endif /* CONFIG_ELOOP_SELECT */ #ifdef CONFIG_ELOOP_EPOLL "epoll" #endif /* CONFIG_ELOOP_EPOLL */ #ifdef CONFIG_ELOOP_KQUEUE "kqueue" #endif /* CONFIG_ELOOP_EKQUEUE */ , strerror(errno)); goto out; } eloop.readers.changed = 0; eloop.writers.changed = 0; eloop.exceptions.changed = 0; eloop_process_pending_signals(); /* check if some registered timeouts have occurred */ timeout = dl_list_first(&eloop.timeout, struct eloop_timeout, list); if (timeout) { os_get_reltime(&now); if (!os_reltime_before(&now, &timeout->time)) { void *eloop_data = timeout->eloop_data; void *user_data = timeout->user_data; eloop_timeout_handler handler = timeout->handler; eloop_remove_timeout(timeout); handler(eloop_data, user_data); } } if (res <= 0) continue; if (eloop.readers.changed || eloop.writers.changed || eloop.exceptions.changed) { /* * Sockets may have been closed and reopened with the * same FD in the signal or timeout handlers, so we * must skip the previous results and check again * whether any of the currently registered sockets have * events. */ continue; } #ifdef CONFIG_ELOOP_POLL eloop_sock_table_dispatch(&eloop.readers, &eloop.writers, &eloop.exceptions, eloop.pollfds_map, eloop.max_pollfd_map); #endif /* CONFIG_ELOOP_POLL */ #ifdef CONFIG_ELOOP_SELECT eloop_sock_table_dispatch(&eloop.readers, rfds); eloop_sock_table_dispatch(&eloop.writers, wfds); eloop_sock_table_dispatch(&eloop.exceptions, efds); #endif /* CONFIG_ELOOP_SELECT */ #ifdef CONFIG_ELOOP_EPOLL eloop_sock_table_dispatch(eloop.epoll_events, res); #endif /* CONFIG_ELOOP_EPOLL */ #ifdef CONFIG_ELOOP_KQUEUE eloop_sock_table_dispatch(eloop.kqueue_events, res); #endif /* CONFIG_ELOOP_KQUEUE */ } eloop.terminate = 0; out: #ifdef CONFIG_ELOOP_SELECT os_free(rfds); os_free(wfds); os_free(efds); #endif /* CONFIG_ELOOP_SELECT */ return; }

eloop_process_pending_signals函数对发生的信号进行处理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static void eloop_process_pending_signals(void)
{
    int i;

    if (eloop.signaled == 0)//有没有信号产生,如果有,那么这个标志位将为1,说明有信号需要处理,如果为0,那么没有信号要处理,函数返回 
        return;
    eloop.signaled = 0;//将信号标示为置0,以便下次有信号产生时,置1 

    if (eloop.pending_terminate) { 
    //如果不用处理后面将会产生的信号,则立即向进程发送一个SIGALARM信号,然后将这个标志置0 
#ifndef CONFIG_NATIVE_WINDOWS
        alarm(0);
#endif /* CONFIG_NATIVE_WINDOWS */
        eloop.pending_terminate = 0;
    }

    for (i = 0; i < eloop.signal_count; i++) { //对信号标示进行处理 
        if (eloop.signals[i].signaled) {
            eloop.signals[i].signaled = 0; 
            //调用处理函数对相应的信号进行处理
            eloop.signals[i].handler(eloop.signals[i].sig,
                         eloop.signals[i].user_data);
        }
    }
}

eloop_run 函数的核心将要处理的socket事件添加到相应的表中,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    eloop_sock_table_set_fds(&eloop.readers, rfds);
    eloop_sock_table_set_fds(&eloop.writers, wfds);
    eloop_sock_table_set_fds(&eloop.exceptions, efds);
    res = select(eloop.max_sock + 1, rfds, wfds, efds,
             timeout ? &_tv : NULL); 

最后执行相应的提前注册的函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    eloop_sock_table_dispatch(&eloop.readers, rfds);
    eloop_sock_table_dispatch(&eloop.writers, wfds);
    eloop_sock_table_dispatch(&eloop.exceptions, efds); 

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/143370.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月2,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
从编程语言的角度看中医的【藏像】理论
一、符号和名字 在上一篇 从程序员视角和编程语言角度看【中医】:一种生命健康编程语言 ,我们谈到了变量的命名问题,谈到了语言和文化霸权,这篇短文,将继续探讨名字问题的重要性。 名字事关话语权,事关地位,甚至事关“霸权”,如果不信,你儿子的名字怎么取,跟你老婆姓还是跟你姓?假如你老婆说儿子必须跟她姓,这个名字问题是不是一下子就变成非常重要的问题了? 中医对于名字问题,看的很深入,叫做“藏像”。 变量的符号语义 前一篇同样的问题继续看: vA=""; vB=""; 请问这是一个意思吗? 如果从变量值的语义
用户1177503
2018/05/28
6470
205K+程序员关注过的问题:为什么不应该使用Java的原始类型?
如果大家也被这个问题困扰过,或者正在被困扰,就请随我来,咱们肩并肩手拉手一起梳理一下这个问题,并找出最佳答案。Duang、Duang、Duang,打怪进阶喽!
沉默王二
2019/12/24
5640
205K+程序员关注过的问题:为什么不应该使用Java的原始类型?
防微杜渐,向扁鹊学习治理代码
故而语文老师们在讲授这篇文章时,将其中心思想落脚在“人要正视缺点,切莫讳疾忌医”上。但实际上有些断章取义,作者的中心思想其实是借扁鹊阐述的医理来讲解做事的方法,即要争之于小、蚤(早)从事。
果冻虾仁
2023/10/01
3040
防微杜渐,向扁鹊学习治理代码
[VRPinea首场投融资闭门会]和君资本专场:八家苏州VR/AR厂商齐聚,展示独家实力
8月19日,VRPinea首场投融资闭门会在苏州创意产业园举行。本次闭门会议邀请了国内知名的VR投融资机构和君资本来苏,吸引了虚实之境网络科技、四分卫数字科技、幻境世界等8家苏州地区的VR/AR厂商参
VRPinea
2018/05/14
7560
腾讯数据库专家雷海林分享智能运维架构
点击上方蓝字每天学习数据库 2019年5月8日-10日的DTCC2019年中国数据库大会上,腾讯云数据库专家工程师雷海林首受邀做了主题为《TDSQL智能运维平台-扁鹊架构与实践》的技术分享,以下为大会现场演讲实录。 雷海林在大会现场 关注“腾讯云数据库”官方微信,回复“智能运维”,即可下载本文PPT。 一、扁鹊的基本介绍 扁鹊系统是TDSQL面向云市场推出的一款针对数据库性能/故障等问题的自动化分析并为用户提供优化/解决方案的产品。 1. 扁鹊的需求背景 TDSQL作为腾讯针对金融场景推出的高一致,
腾讯云数据库 TencentDB
2019/05/16
2K0
腾讯数据库专家雷海林分享智能运维架构
腾讯数据库专家雷海林分享智能运维架构
2019年5月8日-10日的DTCC2019年中国数据库大会上,腾讯云数据库专家工程师雷海林首受邀做了主题为《TDSQL智能运维平台-扁鹊架构与实践》的技术分享,以下为大会现场演讲实录。
腾讯云数据库 TencentDB
2019/05/17
12K0
腾讯数据库专家雷海林分享智能运维架构
关于数据库架构的一段旧文
10年前曾经面试过金蝶的数据库架构师,当时好像给到20K左右,Offer已经发了,却因为种种原因没去成,这段材料应该是为当时准备的。
python与大数据分析
2022/03/11
3650
关于数据库架构的一段旧文
芯片工程师的三重境界,不要担心自己被埋没
世人皆以为扁鹊医术最高明,然而扁鹊说他二哥胜过他,因为扁二哥经常给乡邻治小病,在病人小恙之时就干预治疗,所以一生治小病多,治大病少,故而名气大不如扁鹊,然而扁二哥却说他最佩服扁大哥。
白山头
2022/09/22
3290
芯片工程师的三重境界,不要担心自己被埋没
降本增笑P0事故频发,构建持续高可用系统的破局之道
2023年的互联网世界,“草台班子”、“降本增笑”、“开猿节流”成为大家互相调侃的关键词。苦笑过后,问题还在,事故终要复盘,未来仍需规划。从架构角度看,我们应该怎么去认清高可用的本质,并真正在业务场景中做好高可用,这是本文想跟大家探讨的问题。读完全文还可以参加文末龙年红包封面抽奖活动哦!
腾讯云开发者
2024/01/10
6200
降本增笑P0事故频发,构建持续高可用系统的破局之道
程序员的三个阶段与产品开发的两种哲学
这应该是有能力上升到第三个境界的人,才能拥有的境界,对于大多数的人,第一个境界都不会觉醒,更不要说到达第二、第三境界了。
LIYI
2022/11/18
3980
滴滴投资人被司机打?即使给滴滴投资百万美金,也换不回坐车安全
作为国内最大的网约车平台,滴滴目前的估值已经接近了600亿美金。不过,就算如此高的估值,滴滴在乘客坐车安全这个问题上,仍然做的不够好。且不说前一段时间,21岁空姐坐顺风车遇害的事件,引发了网络上激烈的讨论。这次我们重点说一下,滴滴司机打人的事情。相对于空姐遇害的事件来说,滴滴司机打人的事情引发的关注并没有那么高,但这里面有个细节值得关注,那就是被打的是滴滴的投资人。在今年4月28日晚上,投资人张桓叫了一辆滴滴,在等待二十分钟后得知司机拉错人,决定取消订单打第二部车。而该司机拒绝他的取消申请,并在双方碰面时一拳打在张桓左眼角,造成软组织断裂。张桓在拨打滴滴客服无人接听的情况下,只能向110求助。然而事发到29号上午,依然没能找到这位打人的滴滴司机。
光荣与梦想1987
2018/09/11
3020
浅谈预测性维护,看ZETA-LPWAN如何切入“泛工业”物联网
纵行科技推出ZETA Edge-AI智能终端产品,结合ZETA窄带通信和边缘智能的优势,旨在打造“轻量瘦身”的预测性维护应用,即用20%的成本覆盖80%的典型旋转设备故障模式。此外,在“泛工业”场景,ZETA Edge-AI通过将工业AI算法前置到智能终端,并充分发挥ZETA通信在成本、功耗、数据安全和底层技术创新等方面的优势,助力企业突破万物互联的数据采集和传输壁垒,提供差异化的数字增值服务。
ZETA开发者
2021/01/03
6150
我认识最优秀却默默无闻的程序员
答案是显而易见的,宇宙的真理是熵增,系统的复杂度总会持续增大,最终陷入一个混乱无序的状态,要么爆炸要么重构。
腾讯云开发者
2025/06/09
1561
我认识最优秀却默默无闻的程序员
用C++跟你聊聊“适配器模式”
何为适配器?大家都知道,我国的标准电压是220V,但是我们平时使用的电器可接受不了这个电压,比方说电脑、手机,认真去看他们的充电器,还有一个名字,叫电源适配器适配器是干嘛用的?就是将功能相似或相同、但是接口不同的东西,使得他们可以对接。就像电插座和电器插口,功能都是通电,但是电压不同,适配器就起这么一个中间人的作用。又比如翻译,两个不同语言的人进行通话,相同点都是在讲话和听话,但是不同的是语言,翻译就起到中间转换的作用。
看、未来
2020/08/26
4800
用C++跟你聊聊“适配器模式”
腾讯数据库专家雷海林分享智能运维架构PPT下载
2019年5月8日-10日的DTCC2019年中国数据库大会上,腾讯云数据库专家工程师雷海林首受邀做了主题为《TDSQL智能运维平台-扁鹊架构与实践》的技术分享,以下为大会现场演讲实录。
腾讯云开发者社区
2019/05/16
1.2K0
腾讯数据库专家雷海林分享智能运维架构PPT下载
关于推特30天地图挑战全部7.6k+图片的颜色可视化
上篇文章古柳写了下关于念念不忘三年的颜色可视化的超长文,整个流程涉及: python 爬b站 api 李子柒数据、搭配 you-get 下载视频、ffmpeg 批量视频抽帧、node.js get-image-colors 模块抽图片颜色,d3.js 颜色可视化。
古柳_DesertsX
2020/12/16
7750
关于推特30天地图挑战全部7.6k+图片的颜色可视化
直播回顾 | 数据库运维不再难,数据库“自动驾驶”技术已到来
腾讯云数据库国产数据库专题线上技术沙龙正在火热进行中,3月26日郝志刚的分享已经结束,没来得及参与的小伙伴不用担心,以下就是直播的视频和文字回顾。 关注“腾讯云数据库”公众号,回复“0326郝志刚”,即可下载直播分享PPT。 1 前言 “赤兔”平台是TDSQL提供的产品服务之一,它从管理员视角提供TDSQL的全部运维功能和上百项数据库状态监控指标的展示,让数据库管理员日常90%以上的操作均可通过界面化完成,同时更方便定位排查问题。 扁鹊系统是TDSQL面向云市场推出的一款针对数据库性能/故障等问题的自动
腾讯云数据库 TencentDB
2020/05/16
6750
面试为什么需要了解JVM
随着互联网的发展,高并发高可用、快速响应成为软件的必须,而JVM与这些有着密切关联。之前JVM系列好多都是一些由于STW影响到快速响应问题,忽然网站慢一下(抖动下)等问题,下面谈谈最近通过JVM排查到的高并发高可用问题。(在高可用高并发下面问题原因可能会很多,比如cpu异常高、磁盘IO高、SWAP空间等,有可能很多问题都是综合性的问题)
纯洁的微笑
2018/08/16
5100
DBA上班也能轻松喝咖啡,数据库“智能驾驶”技术全解密
为帮助开发者更好地了解和学习分布式数据库技术,2020年3月,腾讯云数据库、云加社区联合腾讯TEG数据库工作组特推出为期3个月的国产数据库专题线上技术沙龙《你想了解的国产数据库秘密,都在这!》,邀请数十位鹅厂资深数据库专家每周二和周四晚上在线深入解读TDSQL、CynosDB/CDB、TBase三款鹅厂自研数据库的核心架构、技术实现原理和最佳实践等。本文将带来直播回顾第四篇《亿级并发丝毫不虚,TDSQL-SQL引擎架构演进与查询实战》。
分布式数据库TDSQL
2020/07/02
8350
DBA上班也能轻松喝咖啡,数据库“智能驾驶”技术全解密
大话AdaBoost算法
AI 39年(公元1995年),扁鹊成立了一家专治某疑难杂症的医院,经过半年的精心筹备,硬件设施已全部到位,只缺经验丰富的医生前来坐诊。找几个猎头打听了一下,乖乖,请一个资深专家(总监头衔的),一年的工资就得250万。这恐怕还不够去知名搜索引擎投放广告!
SIGAI学习与实践平台
2018/08/07
6800
大话AdaBoost算法
推荐阅读
相关推荐
从编程语言的角度看中医的【藏像】理论
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档