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