知识为进步之母,而进步又为富强之源泉。这篇文章主要讲述android DHCP流程相关的知识,希望能为你提供帮助。
本文转载自:http://blog.csdn.net/myvest/article/details/51483647
版权声明:本文为博主原创文章,未经博主允许不得转载。
目录(?)[+]
1、问题背景最近遇到一个问题,在一个项目中,无论静态或是DHCP,都无法成功修改DNS。
最后发现,是因为/etc/dhcpcd/dhcpcd-hooks/20-dns.conf 这个脚本中,将DNS写死了,如下代码片,每次设置完以后,还去在设置一次。
setprop dhcp.${intf}.dns${dnsvalue} 203.82.48.3 setprop dhcp.${intf}.dns${standydnsvalue} 203.82.48.4
# Set net.<
iface>
.dnsN properties that contain the
# DNS server addresses given by the DHCP server.if [[ $interface == p2p* ]]
then
intf=p2p
else
intf=$interface
fiset_dns_props()
{
case "${new_domain_name_servers}" in
"")return 0;
;
esaccount=1
for i in 1 2 3 4;
do
setprop dhcp.${intf}.dns${i} ""
donecount=1
for dnsaddr in ${new_domain_name_servers};
do
setprop dhcp.${intf}.dns${count} ${dnsaddr}
count=$(($count + 1))
donednsvalue=https://www.songbingjia.com/android/1
standydnsvalue=2
setprop dhcp.${intf}.dns${dnsvalue} 203.82.48.3
setprop dhcp.${intf}.dns${standydnsvalue} 203.82.48.4separator=" "
if [ -z "$new_domain_name" ];
then
separator=""
else
if [ -z "$new_domain_search" ];
then
separator=""
fi
fi
setprop dhcp.${interface}.domain "${new_domain_name}$separator${new_domain_search}"
}unset_dns_props()
{
for i in 1 2 3 4;
do
setprop dhcp.${intf}.dns${i} ""
donesetprop dhcp.${interface}.domain ""
}case "${reason}" in
BOUND|INFORM|REBIND|REBOOT|RENEW|TIMEOUT)set_dns_props;
;
EXPIRE|FAIL|IPV4LL|RELEASE|STOP)unset_dns_props;
;
esac
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
这是因为android中,DHCP分为两个部分,一个是DHCP Client端,一个是server端。
2、Dhcp客户端client端就是我们从上层APP到framework后发出的DHCP请求。这个流程不难,一般是最后会调用runDhcp函数,其JNI在
frameworks\base\core\jni\android_net_NetUtils.cpp
中的android_net_utils_runDhcpCommon。然后会在调用dhcp_do_request函数。到这里,framework的部分就完了,接下来会调用到system/core/libnetutils中去。
在dhcp_do_request函数中,当[dhcp.eth0.result]属性变为[ok]时,会调用fill_ip_info函数,这个函数的作用,就是去读取IP信息而已。
static void fill_ip_info(const char *interface, in_addr_t *ipaddr, in_addr_t *gateway, in_addr_t *mask, in_addr_t *dns1, in_addr_t *dns2, in_addr_t *server, uint32_t*lease)
{property_get(“
dhcp.eth0. ipaddress”
, prop_value,NULL);
property_get(“
dhcp.eth0. gateway”
, prop_value,NULL);
property_get(“
dhcp.eth0. mask”
, prop_value,NULL);
property_get(“
dhcp.eth0. dns1”
, prop_value,NULL);
property_get(“
dhcp.eth0. dns2”
, prop_value,NULL);
property_get(“
dhcp.eth0. server”
, prop_value,NULL);
property_get(“
dhcp.eth0. leasetime”
, prop_value,NULL);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
大概流程如下面:
3、Dhcp server端dhcpcd 调用过程:
代码在external/dhcpcd下,
=>
main
# define SYSCONFDIR "/system/etc/dhcpcd"
#define PACKAGE "dhcpcd"
# define CONFIG SYSCONFDIR "/" PACKAGE ".conf"
# define LIBEXECDIR "/system/etc/dhcpcd"
# define SCRIPT LIBEXECDIR "/" PACKAGE "-run-hooks"
=>
strlcpy(options->
script, SCRIPT, sizeof(options->
script));
//默认的options->
script="/system/etc/dhcpcd /dhcpcd-run-hooks"
=>
f = fopen(cf ? cf : CONFIG, "r");
//如果没有指定.conf文件,那么使用默认.conf文件
=>
parse_config_line//解析"/system/etc/dhcpcd/dhcpcd.conf"默认配置文件
=>
parse_option
=>
如果在"/system/etc/dhcpcd/dhcpcd.conf"有"script"这个节
=>
那么执行strlcpy(options->
script, oarg, sizeof(options->
script));
直接拷贝
/*
{"script", required_argument, NULL, ‘c‘},
{"option", required_argument, NULL, ‘o‘},
"/system/etc/dhcpcd/dhcpcd.conf"中的部分内容如下:
...
option domain_name_servers, domain_name, domain_search, host_name
...
*/
=>
dhcp_run
=>
handle_dhcp_packet
=>
handle_dhcp
=>
bind_dhcp
reason = "TIMEOUT";
reason = "BOUND";
reason = "REBIND";
reason = "RENEW";
system/extra/dhcpcd-4.0.0-beta9/configure.c
=>
configure(iface, reason, state->
new, state->
old, &
state->
lease, options, 1);
//如果dhcp超时或者dhcp成功,都会调用exec_script来执行脚本,
//执行setprop dhcp.${interface}.result "failed"或者
//执行setprop dhcp.${interface}.result "ok"
=>
exec_script(options, iface->
name, reason, NULL, old);
=>
然后configure_env通过环境变量将reason传递到脚本中
int exec_script(const struct options *options, const char *iface, const char *reason,
const struct dhcp_message *dhcpn, const struct dhcp_message *dhcpo)
=>
pid = fork();
=>
if(pid == 0)execve(options->
script, argv, env);
//子进程执行脚本,默认"/system/etc/dhcpcd/dhcpcd-run-hooks"
//dhcpcd-run-hooks脚本会根据level值,决定是否执行system/etc/dhcpcd/dhcpcd-hook/*目录下的相应文件
//我们的系统在该system/etc/dhcpcd/dhcpcd-hook/*目录下有如下2个文件
//95-configured
//20-dns.conf
=>
父进程返回while (waitpid(pid, &
status, 0) == -1)等待子进程脚本执行完成
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
(1)DHCPDISCOVER(0× 01),此为Client开始DHCP过程的第一个报文;
(2)DHCPOFFER(0× 02),此为Server对DHCPDISCOVER报文的响应;
(3)DHCPREQUEST(0× 03),此报文是Slient开始DHCP过程中对server的DHCPOFFER报文的回应,或者是client续延IP地址租期时发出的报文;
(4)DHCPDECLINE(0× 04),当Client发现Server分配给它的IP地址无法使用,如IP地址冲突时,将发出此报文,通知Server禁止使用IP地址;
(5)DHCPACK(0× 05),Server对Client的DHCPREQUEST报文的确认响应报文,Client收到此报文后,才真正获得了IP地址和相关的配置信息;
(6)DHCPNAK(0× 06),Server对Client的DHCPREQUEST报文的拒绝响应报文,Client收到此报文后,一般会重新开始新的DHCP过程;
(7)DHCPRELEASE(0× 07),Client主动释放server分配给它的IP地址的报文,当Server收到此报文后,就可以回收这个IP地址,能够分配给其他的Client;
【android DHCP流程】(8)DHCPINFORM(0× 08),Client已经获得了IP地址,发送此报文,只是为了从DHCPSERVER处获取其他的一些网络配置信息,如routeip,DNSIp等,这种报文的应用非常少见。
推荐阅读
- Dapper+Sqlite执行增删改查功能
- Linux mkdir | Linux创建目录
- LINQ转XML
- Linux路径完成
- Linux绝对路径和相对路径
- Linux cd命令
- Linux pwd命令
- Linux目录
- LINQ转ADO.Net