udhcp源码剖析(四)——DHCP服务器的superloop

本文详细介绍了udhcpd_main的Super loop,包括建立Socket监听、信号处理器、报文处理和根据不同状态响应报文的流程。讨论了DHCPDISCOVER和DHCPREQUEST两种消息的处理策略,如DHCPOFFER的发送和REQUEST消息的复杂处理。此外,还提到了DHCPDECLINE、DHCPRELEASE和DHCPINFORM的消息响应机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

udhcpd_main的Super loop

到这一步,DHCP服务器开始提供具体的服务,super loop主要包括建立socket监听及信号处理、获取并提取报文、根据state和报文内容做出响应。

建立Socket监听和signal处理器

若未建立本地socket监听或监听意外关闭,重新建立,若建立失败,则打印log并退出。本地监听地址端口:SERVER_PORT (67),监听硬件接口:server_config.interface,监听地址:INADDR_ANY(所有地址)

if (server_socket < 0) {
            server_socket = listen_socket(/*INADDR_ANY,*/ SERVER_PORT,
                    server_config.interface);
        }

使用select+FD模型,对socket和socketpair进行监控

/* 添加server_socket和signal_pipe进rfds集合*/
max_sock = udhcp_sp_fd_set(&rfds, server_socket);
/* int udhcp_sp_fd_set(fd_set *rfds, int extra_fd)
{
FD_ZERO(rfds);
FD_SET(signal_pipe[0], rfds);
if (extra_fd >= 0) {
fcntl(extra_fd, F_SETFD, FD_CLOEXEC);
FD_SET(extra_fd, rfds);
}
return signal_pipe[0] > extra_fd ? signal_pipe[0] : extra_fd;*/
/* 如果auto_time不为0,更新等待时间tv.tv_sec为auto_time的剩余时间 */
if (server_config.auto_time) {
    tv.tv_sec = timeout_end - monotonic_sec();
    tv.tv_usec = 0;
}
/* 如果auto_time为0,或tv_sec大于0时,建立select等待server_socket和signal_pipe的信号 */
if (!server_config.auto_time || tv.tv_sec > 0) {
    max_sock = server_socket > signal_pipe[0] ? server_socket : signal_pipe[0];
    /* 对两个fd都进行可读性检测 */
retval = select(max_sock + 1, &rfds, NULL, NULL, 
            /*如果auto_time不为0,则非阻塞,超时时间为上述的剩余时间;如果为0,则time设为NULL,select将一直阻塞直到某个fd上接收到信号*/
server_config.auto_time ? &tv : NULL);
} else retval = 0; /* If we already timed out, fall through */
/* 若直到超时都没有接收到信号,则立即写lease文件,并更新time_end */
if (retval == 0) {
    write_leases();
    timeout_end = monotonic_sec() + server_config.auto_time;
    continue;
}
if (retval < 0 && errno != EINTR) {
    DEBUG("error on select");
    continue;
}

    /* 若signal_pipe接收到可读signal(signal_handler将signal写入signal_pipe[1],根据socketpair的特性,此时signal_pipe[0]将可读,产生一个可读的信号) */
switch (udhcp_sp_read(&rfds)) {
/* 接收到SIGUSR1,立即写leases,并更新time_end */
    case SIGUSR1:
        bb_info_msg("Received a SIGUSR1");
        write_leases();
        /* why not just reset the timeout, eh */
        timeout_end = monotonic_sec() + server_config.auto_time;
    continue;
    case SIGTERM:
        bb_info_msg("Received a SIGTERM");
        goto ret0;
    case 0: break;      /* no signal */
    default: continue;  /* signal or error (probably EINTR) */
}

这一步的主要目的就是对server_socket和socketpair建立监听,并根据对socketpair的信号情况及leases结构的内容,执行write_leases函数,该函数将最新的leases结构体里的内容写入lease_file,根据yiaddr、remaining和当前时间来更新lease_time,每次执行完write_leases函数和,都有更新time_end时刻,write_leases定义于files.c中。

获取和提取报文

调用udhcp_get_packet函数从server_socket接收数据报文填充到packet,注意该函数在调用read读取报文之后,会对报文内的数据进行简单校验,包

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值