Network: Add a BNetworkDevice::GetNetworks() method and use it in the GUI.
The GetNextNetwork() method is really inefficient: it fetches all the networks at once from the kernel every single time and then winds up returning only one of them. In parts of the GUI that iterate over all networks more than once per refresh (sometimes within a loop, even!) this was often a noticeable lag on the GUI, especially with OpenBSD drivers which have extra overhead to do struct translation in the ioctl handler. Now, we have a way to fetch all scan results at once and just iterate over them as many times as we need, and this is what NetworkStatus and Network preferences now do, saving lots of time and effort.
This commit is contained in:
parent
65c155bede
commit
b2c77ad27a
@ -114,6 +114,8 @@ public:
|
||||
|
||||
status_t GetNextNetwork(uint32& cookie,
|
||||
wireless_network& network);
|
||||
status_t GetNetworks(wireless_network*& networks,
|
||||
uint32& count);
|
||||
status_t GetNetwork(const char* name,
|
||||
wireless_network& network);
|
||||
status_t GetNetwork(const BNetworkAddress& address,
|
||||
|
@ -401,14 +401,15 @@ NetworkStatusView::MouseDown(BPoint point)
|
||||
if (!wifiInterface.IsEmpty()) {
|
||||
std::set<BNetworkAddress> associated;
|
||||
BNetworkAddress address;
|
||||
wireless_network network;
|
||||
uint32 cookie = 0;
|
||||
while (device.GetNextAssociatedNetwork(cookie, address) == B_OK)
|
||||
associated.insert(address);
|
||||
|
||||
int32 wifiCount = 0;
|
||||
cookie = 0;
|
||||
while (device.GetNextNetwork(cookie, network) == B_OK) {
|
||||
uint32 networksCount = 0;
|
||||
wireless_network* networks = NULL;
|
||||
device.GetNetworks(networks, networksCount);
|
||||
for (uint32 i = 0; i < networksCount; i++) {
|
||||
const wireless_network& network = networks[i];
|
||||
BMessage* message = new BMessage(kMsgJoinNetwork);
|
||||
message->AddString("device", wifiInterface);
|
||||
message->AddString("name", network.name);
|
||||
@ -416,12 +417,12 @@ NetworkStatusView::MouseDown(BPoint point)
|
||||
|
||||
BMenuItem* item = new WirelessNetworkMenuItem(network, message);
|
||||
menu->AddItem(item);
|
||||
wifiCount++;
|
||||
if (associated.find(network.address) != associated.end())
|
||||
item->SetMarked(true);
|
||||
}
|
||||
delete[] networks;
|
||||
|
||||
if (wifiCount == 0) {
|
||||
if (networksCount == 0) {
|
||||
BMenuItem* item = new BMenuItem(
|
||||
B_TRANSLATE("<no wireless networks found>"), NULL);
|
||||
item->SetEnabled(false);
|
||||
|
@ -423,6 +423,59 @@ fill_wireless_network(wireless_network& network, const char* networkName,
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
get_scan_results(const char* device, wireless_network*& networks, uint32& count)
|
||||
{
|
||||
if (networks != NULL)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
// TODO: Find some way to reduce code duplication with the following function!
|
||||
const size_t kBufferSize = 64 * 1024;
|
||||
uint8* buffer = (uint8*)malloc(kBufferSize);
|
||||
if (buffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
MemoryDeleter deleter(buffer);
|
||||
|
||||
int32 length = kBufferSize;
|
||||
status_t status = get_80211(device, IEEE80211_IOC_SCAN_RESULTS, buffer,
|
||||
length);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
BObjectList<wireless_network> networksList(true);
|
||||
|
||||
int32 bytesLeft = length;
|
||||
uint8* entry = buffer;
|
||||
|
||||
while (bytesLeft > (int32)sizeof(struct ieee80211req_scan_result)) {
|
||||
ieee80211req_scan_result* result
|
||||
= (ieee80211req_scan_result*)entry;
|
||||
|
||||
char networkName[32];
|
||||
strlcpy(networkName, (char*)(result + 1),
|
||||
min_c((int)sizeof(networkName), result->isr_ssid_len + 1));
|
||||
|
||||
wireless_network* network = new wireless_network;
|
||||
fill_wireless_network(*network, networkName, *result);
|
||||
networksList.AddItem(network);
|
||||
|
||||
entry += result->isr_len;
|
||||
bytesLeft -= result->isr_len;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
if (!networksList.IsEmpty()) {
|
||||
networks = new wireless_network[networksList.CountItems()];
|
||||
for (int32 i = 0; i < networksList.CountItems(); i++) {
|
||||
networks[i] = *networksList.ItemAt(i);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
get_scan_result(const char* device, wireless_network& network, uint32 index,
|
||||
const BNetworkAddress* address, const char* name)
|
||||
@ -430,7 +483,8 @@ get_scan_result(const char* device, wireless_network& network, uint32 index,
|
||||
if (address != NULL && address->Family() != AF_LINK)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
const size_t kBufferSize = 65535;
|
||||
// TODO: Find some way to reduce code duplication with the preceding function!
|
||||
const size_t kBufferSize = 64 * 1024;
|
||||
uint8* buffer = (uint8*)malloc(kBufferSize);
|
||||
if (buffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
@ -787,6 +841,13 @@ BNetworkDevice::GetNextNetwork(uint32& cookie, wireless_network& network)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BNetworkDevice::GetNetworks(wireless_network*& networks, uint32& count)
|
||||
{
|
||||
return get_scan_results(Name(), networks, count);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BNetworkDevice::GetNetwork(const char* name, wireless_network& network)
|
||||
{
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include <net/if_media.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <Button.h>
|
||||
#include <Catalog.h>
|
||||
#include <ControlLook.h>
|
||||
@ -270,10 +271,11 @@ InterfaceView::_Update(bool updateWirelessNetworks)
|
||||
while (device.GetNextAssociatedNetwork(cookie, address) == B_OK)
|
||||
associated.insert(address);
|
||||
|
||||
wireless_network network;
|
||||
cookie = 0;
|
||||
if ((fPulseCount % 15) == 0
|
||||
&& device.GetNextNetwork(cookie, network) != B_OK) {
|
||||
wireless_network* networks = NULL;
|
||||
uint32 networksCount = 0;
|
||||
device.GetNetworks(networks, networksCount);
|
||||
|
||||
if ((fPulseCount % 15) == 0 && networksCount == 0) {
|
||||
// We don't seem to know of any networks, and it's been long
|
||||
// enough since the last scan, so trigger one to try and
|
||||
// find some networks.
|
||||
@ -286,8 +288,12 @@ InterfaceView::_Update(bool updateWirelessNetworks)
|
||||
// to merit such a wait. It's only just over ~4 vertical
|
||||
// retraces, anyway.
|
||||
snooze(50 * 1000);
|
||||
|
||||
device.GetNetworks(networks, networksCount);
|
||||
}
|
||||
|
||||
ArrayDeleter networksDeleter(networks);
|
||||
|
||||
// go through menu items and remove networks that have dropped out
|
||||
for (int32 index = 0; index < count; index++) {
|
||||
WirelessNetworkMenuItem* networkItem =
|
||||
@ -297,9 +303,8 @@ InterfaceView::_Update(bool updateWirelessNetworks)
|
||||
break;
|
||||
|
||||
bool networkFound = false;
|
||||
cookie = 0;
|
||||
while (device.GetNextNetwork(cookie, network) == B_OK) {
|
||||
if (networkItem->Network() == network) {
|
||||
for (uint32 i = 0; i < networksCount; i++) {
|
||||
if (networkItem->Network() == networks[i]) {
|
||||
networkFound = true;
|
||||
break;
|
||||
}
|
||||
@ -312,8 +317,9 @@ InterfaceView::_Update(bool updateWirelessNetworks)
|
||||
}
|
||||
|
||||
// go through networks and add new ones to menu
|
||||
cookie = 0;
|
||||
while (device.GetNextNetwork(cookie, network) == B_OK) {
|
||||
for (uint32 i = 0; i < networksCount; i++) {
|
||||
const wireless_network& network = networks[i];
|
||||
|
||||
bool networkFound = false;
|
||||
for (int32 index = 0; index < count; index++) {
|
||||
WirelessNetworkMenuItem* networkItem =
|
||||
|
Loading…
Reference in New Issue
Block a user