blob: 80846196fdd116a47ddfb29a85dfc3f74abcc5b8 [file] [log] [blame]
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import dbus
import httplib
import os
import re
import subprocess
import sys
import time
from autotest_lib.client.cros import flimflam_test_path
import flimflam
_CONNECTION_TIMEOUT_SEC = 15.0
_PING_TIMEOUT_SEC = 15
_SLEEP_INTERVAL_SEC = 0.5
_UNKNOWN_PROC = 'unknown'
_DEFAULT_MANAGER = 'flimflam'
_DEFAULT_PROC_NAME = _UNKNOWN_PROC
_MANAGER_LIST = ['flimflam', 'shill']
_PROC_NAME_LIST = [_UNKNOWN_PROC, 'flimflamd', 'shill']
class ConnectionManagerException(Exception):
pass
class WLAN(object):
'''Class for wireless network settings.'''
def __init__(self, ssid, security, passphrase):
''' Constructor.
Please see 'http://code.google.com/searchframe#wZuuyuB8jKQ/src/third_party/
flimflam/doc/service-api.txt' for a detailed explanation of these
parameters.
Args:
ssid: Wireless network SSID.
security: Wireless network security type.
passphrase: Wireless network password.
'''
self.ssid = ssid
self.security = security
self.passphrase = passphrase
class ConnectionManager():
def __init__(self, wlans=None,
network_manager=_DEFAULT_MANAGER,
process_name=_DEFAULT_PROC_NAME):
'''Constructor.
Args:
wlans: A list of preferred wireless networks and their properties.
Each item should be a WLAN object.
network_manager: The name of the network manager in initctl. It
should be either flimflam(old) or shill(new).
process_name: The name of the network manager process, which should be
flimflamd or shill. If you are not sure about it, you can
use _UNKNOWN_PROC to let the class auto-detect it.
'''
# Black hole for those useless outputs.
self.fnull = open(os.devnull, 'w')
assert network_manager in _MANAGER_LIST
assert process_name in _PROC_NAME_LIST
self.network_manager = network_manager
self.process_name = process_name
# Auto-detect the network manager process name if unknown.
if self.process_name == _UNKNOWN_PROC:
self._DetectProcName()
if wlans is None:
wlans = []
self._ConfigureWifi(wlans)
# Start network manager to get device info.
self.EnableNetworking()
self._GetDeviceInfo()
self.DisableNetworking()
def _DetectProcName(self):
'''Detects the network manager process with pgrep.'''
for process_name in _PROC_NAME_LIST[1:]:
if not subprocess.call("pgrep %s" % process_name,
shell=True, stdout=self.fnull):
self.process_name = process_name
return
raise ConnectionManagerException("Can't find the network manager process")
def _GetDeviceInfo(self):
'''Gets hardware properties of all network devices.'''
flim = flimflam.FlimFlam()
self.device_list = [dev.GetProperties(utf8_strings=True)
for dev in flim.GetObjectList("Device")]
def _ConfigureWifi(self, wlans):
'''Configures the wireless network settings.
The setting will let the network manager auto-connect the preferred
wireless networks.
Args:
wlans: A list of preferred wireless networks and their properties.
Each item should be a WLAN object.
'''
self.wlans = []
for wlan in wlans:
self.wlans.append({
'Type': 'wifi',
'Mode': 'managed',
'AutoConnect': True,
'SSID': wlan.ssid,
'Security': wlan.security,
'Passphrase': wlan.passphrase
})
def EnableNetworking(self):
'''Tells underlying connection manager to try auto-connecting.'''
# Start network manager.
subprocess.call("start %s" % self.network_manager, shell=True,
stdout=self.fnull, stderr=self.fnull)
# Configure the network manager to auto-connect wireless networks.
flim = flimflam.FlimFlam()
for wlan in self.wlans:
flim.manager.ConfigureService(wlan)
def DisableNetworking(self):
'''Tells underlying connection manager to terminate any existing connection.
'''
# Stop network manager.
subprocess.call("stop %s" % self.network_manager, shell=True,
stdout=self.fnull, stderr=self.fnull)
# Turn down drivers for interfaces to really stop the network.
for dev in self.device_list:
subprocess.call("ifconfig %s down" % dev['Interface'],
shell=True, stdout=self.fnull, stderr=self.fnull)
def CheckHost(self, host, timeout=_PING_TIMEOUT_SEC):
'''Checks if we can reach a host.
Args:
host: The host address.
timeout: Timeout in seconds. Integers only.
Returns:
True if host is successfully pinged.
'''
if subprocess.call("ping %s -c 1 -w %d" % (host, int(timeout)), shell=True,
stdout=self.fnull, stderr=self.fnull):
return False
return True
def WaitForConnection(self, timeout=_CONNECTION_TIMEOUT_SEC):
'''A blocking function that waits until any network is connected.
The function will raise an Exception if no network is ready when
the time runs out.
Args:
timeout: Timeout in seconds.
'''
t_start = time.clock()
while not self.IsConnected():
if time.clock() - t_start > timeout:
raise ConnectionManagerException('Not connected')
time.sleep(_SLEEP_INTERVAL_SEC)
def IsConnected(self):
'''Returns (network state == online).'''
# Check if we are connected to any network.
# We can't cache the flimflam object because each time we re-start
# the network some filepaths that flimflam works on will change.
try:
flim = flimflam.FlimFlam()
except dbus.exceptions.DBusException:
# The network manager is not running.
return False
stat = flim.GetSystemState()
return stat != 'offline'