DHCP 服务器,客户端代码都采用了统一的事件轮询(event loop),包含了任务处理消息,定时器消息,socke收发消息等等。
1 static struct { 2 isc_appmethods_t methods; 3 4 /*% 5 * The following are defined just for avoiding unused static functions. 6 */ 7 #ifndef BIND9 8 void *run, *shutdown, *start, *onrun, *reload, *finish, 9 *block, *unblock; 10 #endif 11 } appmethods = { 12 { 13 isc__appctx_destroy, 14 isc__app_ctxstart, 15 isc__app_ctxrun, 16 isc__app_ctxsuspend, 17 isc__app_ctxshutdown, 18 isc__app_ctxfinish, 19 isc__appctx_settaskmgr, 20 isc__appctx_setsocketmgr, 21 isc__appctx_settimermgr 22 } 23 #ifndef BIND9 24 , 25 (void *)isc__app_run, (void *)isc__app_shutdown, 26 (void *)isc__app_start, (void *)isc__app_onrun, (void *)isc__app_reload, 27 (void *)isc__app_finish, (void *)isc__app_block, 28 (void *)isc__app_unblock 29 #endif 30 }; 31 (void)isc__taskmgr_dispatch(ctx->taskmgr); 32 33 result = evloop(ctx); 34 if (result != ISC_R_SUCCESS) 35 return (result);
网卡接口对象的收包处理函数注册:
1 for (tmp = interfaces; tmp; tmp = tmp -> next) { 2 /* not if it's been registered before */ 3 if (tmp -> flags & INTERFACE_RUNNING) 4 continue; 5 if (tmp -> rfdesc == -1) 6 continue; 7 switch (local_family) { 8 #ifdef DHCPv6 9 case AF_INET6: 10 status = omapi_register_io_object((omapi_object_t *)tmp, 11 if_readsocket, 12 0, got_one_v6, 0, 0); 13 break; 14 #endif /* DHCPv6 */ 15 case AF_INET: 16 default: 17 status = omapi_register_io_object((omapi_object_t *)tmp, 18 if_readsocket, 19 0, got_one, 0, 0); 20 break; 21 } 22 23 if (status != ISC_R_SUCCESS) 24 log_fatal ("Can't register I/O handle for %s: %s", 25 tmp -> name, isc_result_totext (status)); 26 27 #if defined(DHCPv6) 28 /* Only register the first interface for V6, since they all 29 * use the same socket. XXX: This has some messy side 30 * effects if we start dynamically adding and removing 31 * interfaces, but we're well beyond that point in terms of 32 * mess. 33 */ 34 if (local_family == AF_INET6) 35 break; 36 #endif 37 } /* for (tmp = interfaces; ... */
omapi_register_io_object函数将收包处理函数got_one与对应的接口对象指针关联:
1 status = omapi_object_reference (&obj -> inner, h, MDL); 2 if (status != ISC_R_SUCCESS) { 3 omapi_io_dereference (&obj, MDL); 4 return status; 5 } 6 7 status = omapi_object_reference (&h -> outer, 8 (omapi_object_t *)obj, MDL); 9 if (status != ISC_R_SUCCESS) { 10 omapi_io_dereference (&obj, MDL); 11 return status; 12 } 13 14 ... 15 obj -> reader = reader;
reader 就是指向 got_one 函数的函数指针参数,这样就可以从主流程main函数入口进入到收包处理流程了。
1 isc_result_t got_one (h) 2 omapi_object_t *h; { 3 .... 4 if (bootp_packet_handler) { 5 ifrom.len = 4; 6 memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len); 7 8 (*bootp_packet_handler) (ip, &u.packet, (unsigned)result, 9 from.sin_port, ifrom, &hfrom); 10 } 11 .... 12 }
bootp_packet_handler 即是 main函数设置的包处理函数:
1 /* Set up various hooks. */ 2 dhcp_interface_setup_hook = dhcpd_interface_setup_hook; 3 bootp_packet_handler = do_packet; 4 #ifdef DHCPv6 5 dhcpv6_packet_handler = do_packet6; 6 #endif /* DHCPv6 */