From 3da0797427ca31459fc5763e503412c01bf55834 Mon Sep 17 00:00:00 2001 From: Sean Robinson Date: Sat, 29 Mar 2014 14:35:44 -0700 Subject: [PATCH] Re-factor scanner function This simplifies and better documents the regular expression matching while looking for various AP profile information. Signed-off-by: Sean Robinson --- test/unit/connections.py | 15 ++++++------ wifiradar/connections.py | 62 ++++++++++++++++++++++++++---------------------- 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/test/unit/connections.py b/test/unit/connections.py index 40f536a..985e1c5 100644 --- a/test/unit/connections.py +++ b/test/unit/connections.py @@ -40,9 +40,9 @@ class TestScanner(unittest.TestCase): # Prepare the profile information to test against mock scan data. profiles = list() profile = get_new_profile() - profile.update({'protocol': 'bg', 'bssid': '10:A8:08:4C:18:26', - 'encrypted': False, 'signal': '-54', 'essid': 'tractorsenslave', - 'channel': '11', 'mode': 'Managed'}) + profile.update({'protocol': 'bg', 'bssid': '10:15:54:9E:2E:AA', + 'encrypted': True, 'signal': '-58', 'essid': 'startingenlivening', + 'channel': '2', 'mode': 'Master'}) profiles.append(profile) profile = get_new_profile() profile.update({'protocol': 'bg', 'bssid': 'B2:B0:03:1A:8F:6B', @@ -50,14 +50,13 @@ class TestScanner(unittest.TestCase): 'channel': '3', 'mode': 'Master'}) profiles.append(profile) profile = get_new_profile() - profile.update({'protocol': 'bg', 'bssid': '10:15:54:9E:2E:AA', - 'encrypted': True, 'signal': '-58', 'essid': 'startingenlivening', - 'channel': '2', 'mode': 'Master'}) + profile.update({'protocol': 'bg', 'bssid': '10:A8:08:4C:18:26', + 'encrypted': False, 'signal': '-54', 'essid': 'tractorsenslave', + 'channel': '11', 'mode': 'Managed'}) profiles.append(profile) # Read mock scan data from file. - with open('./test/data/mock-scan-001.txt', 'r') as f: - mock_popen.return_value.stdout = f.read() + mock_popen.return_value.stdout = open('./test/data/mock-scan-001.txt', 'r') # Create control Pipe a, b = Pipe() diff --git a/wifiradar/connections.py b/wifiradar/connections.py index 88e47dc..5395a3a 100644 --- a/wifiradar/connections.py +++ b/wifiradar/connections.py @@ -68,14 +68,18 @@ def scanner(config_manager, msg_pipe): :data:`msg_pipe` is a :class:`multiprocessing.Connection` object used to receive commands and report AP profiles. """ - # Setup our essid pattern matcher - essid_pattern = re.compile("ESSID\s*(:|=)\s*\"([^\"]+)\"", re.I | re.M | re.S) - bssid_pattern = re.compile("Address\s*(:|=)\s*([a-zA-Z0-9:]+)", re.I | re.M | re.S) - protocol_pattern = re.compile("Protocol\s*(:|=)\s*IEEE 802.11\s*([abgn]+)", re.I | re.M | re.S) - mode_pattern = re.compile("Mode\s*(:|=)\s*([^\n]+)", re.I | re.M | re.S) - channel_pattern = re.compile("Channel\s*(:|=)*\s*(\d+)", re.I | re.M | re.S) - enckey_pattern = re.compile("Encryption key\s*(:|=)\s*(on|off)", re.I | re.M | re.S) - signal_pattern = re.compile("Signal level\s*(:|=)\s*(-?[0-9]+)", re.I | re.M | re.S) + # Setup our pattern matchers. The important value must be the second + # regular expression group in the pattern. + patterns = dict() + patterns['essid'] = re.compile("ESSID\s*(:|=)\s*\"([^\"]+)\"", re.I | re.M | re.S) + patterns['bssid'] = re.compile("Address\s*(:|=)\s*([a-zA-Z0-9:]+)", re.I | re.M | re.S) + patterns['protocol'] = re.compile("Protocol\s*(:|=)\s*IEEE 802.11\s*([abgn]+)", re.I | re.M | re.S) + patterns['mode'] = re.compile("Mode\s*(:|=)\s*([^\n]+)", re.I | re.M | re.S) + patterns['channel'] = re.compile("Channel\s*(:|=)*\s*(\d+)", re.I | re.M | re.S) + patterns['encrypted'] = re.compile("Encryption key\s*(:|=)\s*(on|off)", re.I | re.M | re.S) + patterns['signal'] = re.compile("Signal level\s*(:|=)\s*(-?[0-9]+)", re.I | re.M | re.S) + + trans_enc = dict(on=True, off=False) running = True scan = True @@ -118,28 +122,28 @@ def scanner(config_manager, msg_pipe): running = False scan = False else: - # Split the scan data based on the address line. - hits = scandata.split(' - ') - for hit in hits: - # set the defaults for profile template - profile = misc.get_new_profile() - m = essid_pattern.search(hit) - if m: - # we found an essid - profile['essid'] = m.groups()[1] - m = bssid_pattern.search(hit) # get BSSID from scan - if m: profile['bssid'] = m.groups()[1] - m = protocol_pattern.search(hit) # get protocol from scan - if m: profile['protocol'] = m.groups()[1] - m = mode_pattern.search(hit) # get mode from scan - if m: profile['mode'] = m.groups()[1] - m = channel_pattern.search(hit) # get channel from scan - if m: profile['channel'] = m.groups()[1] - m = enckey_pattern.search(hit) # get encryption key from scan - if m: profile['encrypted'] = (m.groups()[1] == 'on') - m = signal_pattern.search(hit) # get signal strength from scan - if m: profile['signal'] = m.groups()[1] + # Start with a blank profile to fill in. + profile = misc.get_new_profile() + # It's cleaner to code the gathering of AP profiles + # from bottom to top with the iwlist output. + for line in reversed(list(scandata)): + line = line.strip() + for pattern in patterns: + m = patterns[pattern].search(line) + if m is not None: + profile[pattern] = m.group(2) + # Stop looking for more matches on this line. + break + + if line.startswith('Cell '): + # Each AP starts with the keyword "Cell", + # which mean we now have one whole profile. + # But, first translate the 'encrypted' + # property to a boolean value. + profile['encrypted'] = trans_enc[profile['encrypted']] msg_pipe.send(Message('ACCESSPOINT', profile)) + # Restart with a blank profile to fill in. + profile = misc.get_new_profile() class ConnectionManager(object): -- 2.11.4.GIT