获取已连接设备
产品有一个需求,获取已连接设备,这个需求经过三次更改,我的实现也随之改了又改,现在记录一下
最初的需求
需求
获取已连接设备的列表,设备有两种方式连接,第一,为通过网线连接,第二为通过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()); } }
|
总结
需求的小更改会导致实现的大变化,最好在一开始就明确需求,减少开发的无效修改和无效工作