00001
00002
00003 import interface_upper
00004 import ping_tester
00005 import dhcp
00006 from dhcp_apply_config import DhcpAddressSetter, DhcpRouteSetter, DhcpSourceRuleSetter
00007 import config
00008 from netlink_monitor import netlink_monitor, IFSTATE
00009 import radio_sm
00010 import traceback
00011 import pythonwifi.iwlibs
00012 import mac_addr
00013 import socket
00014 import state_publisher
00015 import ipaddr
00016
00017 class Interface:
00018 def __init__(self, iface, tableid, cfgname):
00019 self.iface = iface
00020 self.cfgname = cfgname
00021 self.prettyname = config.get_interface_parameter(self.cfgname, 'name', self.cfgname)
00022 self.active = True
00023 self.priority = config.get_interface_parameter(self.cfgname, 'priority', 0)
00024 src_rule_setter = DhcpSourceRuleSetter(iface, tableid, tableid)
00025 self.tableid = str(tableid)
00026 base_station = config.get_parameter('base_station')
00027 ping_port = config.get_parameter('ping_port')
00028 self.ping_tester = ping_tester.PingTester(iface, 20, (base_station, ping_port), src_rule_setter.state_pub)
00029
00030 def update(self, interval):
00031 self.diags = []
00032 self.status = netlink_monitor.get_status_publisher(self.iface).get()
00033
00034 self._update_specialized()
00035
00036 (bins, latency1, latency2) = self.ping_tester.update(interval)
00037 self.ping_latency = latency2
00038 self.ping_loss = 100 - 100 * bins[0]
00039 if self.status < IFSTATE.ADDR:
00040 self.goodness = self.status - IFSTATE.ADDR
00041 self.reliability = self.status - IFSTATE.ADDR
00042 else:
00043 self.goodness = 100 * bins[0] - latency2
00044
00045 if self.status < IFSTATE.LINK_ADDR:
00046 self.bssid = "NoLink"
00047
00048 class DhcpInterface(Interface):
00049 def __init__(self, iface, tableid):
00050 Interface.__init__(self, iface, tableid, iface)
00051 self.interface_upper = interface_upper.InterfaceUpper(iface)
00052 self.dhcpdata = dhcp.dhcp_client(iface)
00053 DhcpAddressSetter(iface, self.dhcpdata.binding_publisher)
00054 DhcpRouteSetter(iface, tableid, self.dhcpdata.binding_publisher)
00055
00056
00057
00058
00059 class WiredInterface(DhcpInterface):
00060 def __init__(self, iface, tableid):
00061 DhcpInterface.__init__(self, iface, tableid)
00062
00063 def _update_specialized(self):
00064 self.reliability = 100
00065 self.bssid = "Wired"
00066
00067 class WirelessInterface(DhcpInterface):
00068 def __init__(self, iface, tableid):
00069 DhcpInterface.__init__(self, iface, tableid)
00070 self.wifi = pythonwifi.iwlibs.Wireless(iface)
00071 self.iwinfo = pythonwifi.iwlibs.WirelessInfo(iface)
00072 self.radio_sm = radio_sm.radio_sm(iface)
00073 self.ping_monitor = ping_tester.PingMonitor(self)
00074 self.had_exception_last_time = False
00075
00076 def _update_specialized(self):
00077 has_link = self.status > IFSTATE.LINK_ADDR
00078 had_exception_this_time = False
00079 try:
00080 self.essid = self.wifi.getEssid()
00081 self.diags.append(('ESSID', self.essid))
00082 except Exception, e:
00083 if has_link:
00084 had_exception_this_time = True
00085 if self.had_exception_last_time:
00086 traceback.print_exc(10)
00087 print
00088 self.diags.append(('ESSID', 'Error collecting data.'))
00089 self.essid = "###ERROR-COLLECTING-DATA###"
00090
00091 try:
00092 self.bssid = mac_addr.pretty(self.wifi.getAPaddr())
00093 self.diags.append(('BSSID', self.bssid))
00094 except Exception, e:
00095 if has_link:
00096 had_exception_this_time = True
00097 if self.had_exception_last_time:
00098 traceback.print_exc(10)
00099 print
00100 self.bssid = "00:00:00:00:00:00"
00101 self.diags.append(('BSSID', 'Error collecting data.'))
00102
00103 try:
00104 self.wifi_txpower = 10**(self.wifi.wireless_info.getTXPower().value/10.)
00105 self.diags.append(('TX Power (mW)', self.wifi_txpower))
00106 self.wifi_txpower = "%.1f mW"%self.wifi_txpower
00107 except Exception, e:
00108 if str(e).find("Operation not supported") == -1 and has_link:
00109 had_exception_this_time = True
00110 if self.had_exception_last_time:
00111 traceback.print_exc(10)
00112 print
00113 self.diags.append(('TX Power (mW)', 'Error collecting data.'))
00114 self.wifi_txpower = "unknown"
00115
00116 try:
00117 self.wifi_frequency = self.wifi.wireless_info.getFrequency().getFrequency()
00118 self.diags.append(('Frequency (Gz)', "%.4f"%(self.wifi_frequency/1e9)))
00119 except Exception, e:
00120 if has_link:
00121 had_exception_this_time = True
00122 if self.had_exception_last_time:
00123 traceback.print_exc(10)
00124 print
00125 self.wifi_frequency = 0
00126 self.diags.append(('Frequency', 'Error collecting data.'))
00127
00128 got_stats = False
00129 if has_link:
00130 try:
00131 stat, qual, discard, missed_beacon = self.wifi.getStatistics()
00132 max_quality = self.wifi.getQualityMax().quality
00133 quality = qual.quality * 100 / max_quality
00134 self.diags.append(('Quality', quality))
00135 self.diags.append(('Signal (dB)', qual.siglevel))
00136 self.diags.append(('Noise (dB)', qual.nlevel))
00137 self.diags.append(('SNR (dB)', qual.siglevel - qual.nlevel))
00138 self.wifi_signal = qual.siglevel
00139 self.wifi_noise = qual.nlevel
00140 self.wifi_quality = quality
00141 self.reliability = quality
00142 got_stats = True
00143 except Exception, e:
00144 print "Error getting wireless stats on interface %s: %s"%(self.iface, str(e))
00145
00146 if not got_stats:
00147
00148 print
00149 self.reliability = 0
00150 self.wifi_quality = -1
00151 self.wifi_noise = 10000
00152 self.wifi_signal = -10000
00153 for s in [ 'Quality', 'Signal', 'Noise' ]:
00154 if has_link:
00155 self.diags.append((s, 'Error collecting data.'))
00156 else:
00157 self.diags.append((s, 'Unknown'))
00158
00159 self.wifi_rate = None
00160 if has_link:
00161 try:
00162 self.wifi_rate = self.wifi.wireless_info.getBitrate().value
00163 except:
00164 pass
00165 if self.wifi_rate is None:
00166 try:
00167 self.wifi_rate = self.iwinfo.getBitrate().value
00168 except:
00169 pass
00170 if self.wifi_rate is not None:
00171 self.diags.append(('TX Rate (Mbps)', self.wifi_rate / 1e6))
00172 self.wifi_rate = self.wifi._formatBitrate(self.wifi_rate)
00173 else:
00174 if has_link:
00175 print "Unable to determine TX rate on interface", self.iface
00176 self.diags.append(('TX Rate (Mbps)', 'Error collecting data.'))
00177 else:
00178 self.diags.append(('TX Rate (Mbps)', 'Unknown'))
00179 self.wifi_rate = "Unknown"
00180
00181 self.had_exception_last_time = had_exception_this_time
00182
00183 class StaticRouteInterface(Interface):
00184 def __init__(self, route, tableid):
00185 gateway, iface = route.split('@')
00186 Interface.__init__(self, iface, tableid, route)
00187 self.gateway = socket.gethostbyname(gateway)
00188 self._fake_binding = state_publisher.StatePublisher(None)
00189 netlink_monitor.get_state_publisher(iface, IFSTATE.ADDR).subscribe(self._publish_binding)
00190 DhcpRouteSetter(iface, tableid, self._fake_binding)
00191
00192 def _publish_binding(self, old_state, new_state):
00193 if new_state:
00194 ip, netbits = new_state
00195 net = ipaddr.IPv4Network("%s/%s"%(ip, netbits))
00196 self._binding = { "ip" : ip, "gateway" : self.gateway, "network_slashed" : "%s/%s"%(net.network, net.prefixlen) }
00197 self._fake_binding.set(self._binding)
00198 else:
00199 self._fake_binding.set(None)
00200
00201 def _update_specialized(self):
00202 self.reliability = 100
00203 self.bssid = "Wired"
00204
00205
00206 class NoType(Exception):
00207 pass
00208
00209 class UnknownType(Exception):
00210 pass
00211
00212 def construct(iface, tableid):
00213 try:
00214 type = config.get_interface_parameter(iface, 'type')
00215 if type == "wired":
00216 return WiredInterface(iface, tableid)
00217 if type == "wireless":
00218 return WirelessInterface(iface, tableid)
00219 if type == "static":
00220 return StaticRouteInterface(iface, tableid)
00221 raise UnknownType(type)
00222 except config.NoDefault:
00223 raise NoType()
00224
00225
00226 if __name__ == "__main__":
00227 try:
00228 DhcpInterface('eth1', 50)
00229 except:
00230 import traceback
00231 traceback.print_exc()
00232 import twisted.internet.reactor as reactor
00233 reactor.run()
00234 import threading
00235 import time
00236 while True:
00237 time.sleep(0.1)
00238 threads = threading.enumerate()
00239 non_daemon = sum(0 if t.daemon else 1 for t in threads)
00240 if non_daemon == 1:
00241 break
00242 print
00243 print "Remaining threads:", non_daemon, len(threads)
00244 for t in threads:
00245 print ("daemon: " if t.daemon else "regular:"), t.name