获取已连接设备

获取已连接设备

产品有一个需求,获取已连接设备,这个需求经过三次更改,我的实现也随之改了又改,现在记录一下

最初的需求

需求

获取已连接设备的列表,设备有两种方式连接,第一,为通过网线连接,第二为通过WiFi连接

实现

因为如果有设备连接到DUT,DUT会给已连接设备分配IP,分配ip的操作是由dnsmasq来完成的,关于dnsmasq的配置可以参考之前的文章 dnsmasq的配置

dnsmasq在分配IP时会更新租期文件,租期文件的路径就是我们自己配置的,此次实现就是读取租期文件,获取hostname,ip以及mac地址:

1
2
cat dnsmasq.leases
1642514042 ca:32:8b:3e:ff:f7 192.168.1.137 DESKTOP-S48TNAG 01:ca:32:8b:3e:ff:f7

这几个字段的意义分别为:租约到期时间 MAC地址 IP地址 Hostname client-ID

所以可以很容易的获取到已连接设备的列表:

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
typedef struct ms_lan_list_info
{
char ipaddr[64];
char mac[48];
char host_name[48];
} ms_lan_list_info;

int read_leases_file()
{
int len = -1;
ifstream in("/tmp/dnsmasq.leases");
string line;
char ip[32] = {0}, mac[64] = {0}, name[64] = {0}, time[64]={0}, id[64] = {0};
ms_lan_list_info info;
if(in)
{
m_lan_list.clear();
len = 0;
while (getline (in, line))
{
memset(&info,0,sizeof(info));

sscanf(line.c_str(),"%s %s %s %s %s",time, mac, ip, name, id);
strncpy(info.ipaddr, ip, 64);
strncpy(info.mac, mac, 48);
strncpy(info.host_name, name, 48);
m_lan_list.push_back(info);
len++;
}
}

in.close();
return len;
}

如果设备断开连接,只有租期到了才会删除记录,所以已连接设备列表不会实时更新,此为遗留问题

获取已连接设备并区分连接类型

需求

获取已连接设备,区分是LAN,2.4G WIFI还是5G WIFI连接,并可以实时更新连接状态

实现

wifi驱动会更新其sta列表,表中会有已连接设备的mac,根据此mac向当前的列表打标记,可以区分连接类型:

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
typedef struct ms_lan_list_info
{
char ipaddr[64];
char mac[48];
char host_name[48];
int type;
} ms_lan_list_info;

enum CLIENT_TYPE{
MS_CLIENT_TYPE_LAN = 1,
MS_CLIENT_TYPE_WIFI24G = 2,
MS_CLIENT_TYPE_WIFI5G = 3
};

int read_leases_file()
{
int len = -1;
ifstream in("/tmp/dnsmasq.leases");
string line;
char ip[32] = {0}, mac[64] = {0}, name[64] = {0}, time[64]={0}, id[64] = {0};
ms_lan_list_info info;
if(in)
{
m_lan_list.clear();
len = 0;
while (getline (in, line))
{
memset(&info,0,sizeof(info));
sscanf(line.c_str(),"%s %s %s %s %s",time, mac, ip, name, id);
info.type = MS_CLIENT_TYPE_LAN;
strncpy(info.ipaddr, ip, 64);
strncpy(info.mac, mac, 48);
strncpy(info.host_name, name, 48);
m_lan_list.push_back(info);
len++;
}
}

in.close();
set_client_type(MS_CLIENT_TYPE_WIFI5G, m_lan_list);
set_client_type(MS_CLIENT_TYPE_WIFI24G, m_lan_list);
return len;
}

void set_client_type(int type,list<ms_lan_list_info> *list)
{
string filename;
string line;
string mark = ":";
if (type == MS_CLIENT_TYPE_WIFI24G)
{
filename = "/proc/wlan0/sta_info";
}
else if (type == MS_CLIENT_TYPE_WIFI5G)
{
filename = "/proc/wlan1/sta_info";
}
else
{
return;
}
ifstream in(filename);
if(in)
{
while (getline (in, line))
{
size_t pos = line.find("hwaddr: ");
if (pos != -1)
{
string value = line.substr(pos + 8);
if (list->size() > 0)
{
for(auto list_iterator = list->begin(); list_iterator != list->end(); list_iterator++)
{
string macaddr = list_iterator->mac;
delete_mark(macaddr, mark);
if (macaddr == value)
{
list_iterator->type = type;
break;
}
}
}
}
}
in.close();
}
else
{
printf("open [%s] fail",filename.c_str());
}
}

实时更新使用arping来检测列表中的设备,将无响应的设备从列表中移除:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void ms_lan_service::flush_list(void)
{
list<ms_lan_list_info>::iterator list_iterator;
int len = -1;
len = read_leases_file();
if (len > 0)
{
for(list_iterator = m_lan_list.begin(); list_iterator != m_lan_list.end();)
{
string cmd = "arping -f -w 1 -I br-lan ", result;
cmd += list_iterator->ipaddr;
execute_cmd(cmd, result);
if (result.rfind("Received 1 response") == string::npos)
{
m_lan_list.erase(list_iterator++);
}
else
{
list_iterator++;
}
}
}
}

如果离线设备过多,每个设备都需要1s的超时时间arping才会返回,严重影响DUT性能

最终需求

需求

可以从已连接设备中将设备拉入黑名单,只关心通过WiFi连接的设备,所以已连接设备只需要获取WiFi连接的设备,并添加拉黑功能(此功能在此不做讨论)

实现

优化上一版,只需返回wifi的sta列表中的设备,由于wifi驱动会实时更新sta列表,所以不需要arping的操作:

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
int read_leases_file()
{
int len = -1;
ifstream in("/tmp/dnsmasq.leases");
string line;
char ip[32] = {0}, mac[64] = {0}, name[64] = {0}, time[64]={0}, id[64] = {0};
ms_lan_list_info info;
list<ms_lan_list_info> list;
if(in)
{
m_lan_list.clear();
len = 0;
while (getline (in, line))
{
memset(&info,0,sizeof(info));

sscanf(line.c_str(),"%s %s %s %s %s",time, mac, ip, name, id);
info.type = MS_CLIENT_TYPE_LAN;
strncpy(info.ipaddr, ip, 64);
strncpy(info.mac, mac, 48);
strncpy(info.host_name, name, 48);
list.push_back(info);
len++;
}
}

in.close();
set_client_type(MS_CLIENT_TYPE_WIFI5G, &list);
set_client_type(MS_CLIENT_TYPE_WIFI24G, &list);
return len;
}

void set_client_type(int type,list<ms_lan_list_info> *list)
{
string filename;
string line;
string mark = ":";
if (type == MS_CLIENT_TYPE_WIFI24G)
{
filename = "/proc/wlan0/sta_info";
}
else if (type == MS_CLIENT_TYPE_WIFI5G)
{
filename = "/proc/wlan1/sta_info";
}
else
{
return;
}

ifstream in(filename);

if(in)
{
while (getline (in, line))
{
size_t pos = line.find("hwaddr: ");
if (pos != -1)
{
string value = line.substr(pos + 8);
if (list->size() > 0)
{
for(auto list_iterator = list->begin(); list_iterator != list->end(); list_iterator++)
{
string macaddr = list_iterator->mac;
delete_mark(macaddr, mark);
ALOGI("lan mac[%s] - mac[%s]",value.c_str(), macaddr.c_str());
if (macaddr == value)
{
list_iterator->type = type;
m_lan_list.push_back(*list_iterator);
break;
}
}
}
}
}

in.close();
}
else
{
printf("open [%s] fail",filename.c_str());
}
}

总结

需求的小更改会导致实现的大变化,最好在一开始就明确需求,减少开发的无效修改和无效工作


获取已连接设备
https://carl-5535.github.io/2022/02/16/工作总结/获取已连接设备/
作者
Carl Chen
发布于
2022年2月16日
许可协议