00001
00002
00003 import interface
00004 import event
00005 from twisted.internet import reactor
00006 from twisted.internet.defer import inlineCallbacks
00007 import ip_rule
00008 import config
00009 import time
00010 import sys
00011 import radio_manager
00012 import logging_config
00013 import socket
00014 import system
00015 from netlink_monitor import netlink_monitor, IFSTATE
00016 from async_helpers import mainThreadCallback
00017
00018 summary_logger = logging_config.get_logger_stream_for_file('console.summary')
00019
00020 class RULEID:
00021 LOCAL=100
00022 FIRST_IFACE=50
00023 TUNNEL=150
00024 BLOCK_TUNNEL=175
00025 DEFAULT=200
00026 BLOCK_NON_TUNNEL=250
00027
00028 class InterfaceSelector:
00029 def __init__(self):
00030 self.interfaces = {}
00031 self.update_event = event.Event()
00032 self.update_interval = 1
00033 self.radio_manager = radio_manager.RadioManager()
00034 self.inactive_penalty = config.get_parameter('inactive_penalty', 50)
00035 self.forced_interface = ""
00036 self.use_tunnel = True
00037 self.tunnel_interface = config.get_parameter('tunnel_interface', "")
00038 self.active_interfaces = []
00039
00040 print "Resolving basestation IP. (Blocking operation.)"
00041 self.basestation_ip = socket.gethostbyname(config.get_parameter('base_station'))
00042
00043
00044 local_net_rule = ip_rule.IpRule(RULEID.LOCAL)
00045 for subnet in config.get_parameter('local_networks'):
00046 local_net_rule.add('to', subnet, 'lookup', 'main')
00047
00048
00049 if self.tunnel_interface:
00050 self.vpn_rule = ip_rule.IpRule(RULEID.DEFAULT)
00051
00052
00053 system.system('ip', 'route', 'flush', 'table', str(RULEID.DEFAULT))
00054 netlink_monitor.get_state_publisher(self.tunnel_interface,
00055 IFSTATE.LINK).subscribe(self._refresh_default_route)
00056
00057
00058
00059 interface_names = config.get_parameter('interfaces').keys()
00060 ifaceid = RULEID.FIRST_IFACE
00061 for iface in interface_names:
00062 try:
00063 new_iface = self.interfaces[iface] = interface.construct(iface, ifaceid)
00064 ifaceid += 1
00065 except interface.NoType:
00066 print >> sys.stderr, "Interface %s has no type."%iface
00067 sys.exit(1)
00068 except interface.UnknownType, e:
00069 print >> sys.stderr, "Interface %s has unknown type %s."%(iface, e)
00070 sys.exit(1)
00071 except:
00072 print >> sys.stderr, "Error creating interface %s."%iface
00073 raise
00074
00075
00076 for i in self.interfaces.itervalues():
00077 if isinstance(i, interface.WirelessInterface):
00078 self.radio_manager.add_iface(i)
00079
00080
00081 self.tun_ip_rules = [ip_rule.IpRule(RULEID.TUNNEL+i) for i in range(len(self.interfaces))]
00082
00083
00084 self.shutting_down = False
00085 self._periodic_update()
00086 reactor.addSystemEventTrigger('before', 'shutdown', self._shutdown)
00087
00088 def _shutdown(self):
00089 self.shut_down = True
00090
00091 @mainThreadCallback
00092 def set_mode(self, ssid = "", bssid = "", sel_interface = "", use_tunnel = True, band = 3):
00093 self.goodness_weight = config.get_parameter('ping_weighting', 0.5)
00094 self.radio_manager.set_mode(ssid, bssid, band)
00095 self.forced_interface = sel_interface
00096 self.use_tunnel = use_tunnel
00097 if use_tunnel:
00098 self.vpn_rule.set('lookup', str(RULEID.DEFAULT))
00099 else:
00100 self.vpn_rule.set()
00101
00102 def _refresh_default_route(self, old_state, new_state):
00103 if new_state:
00104 system.system('ip', 'route', 'replace', 'table', str(RULEID.DEFAULT), 'default', "dev", self.tunnel_interface)
00105
00106 def _periodic_update(self):
00107 if self.shutting_down:
00108 return
00109 self.periodic_update_handle = reactor.callLater(self.update_interval, self._periodic_update)
00110
00111
00112 for iface in self.interfaces.values():
00113 iface.update(self.update_interval)
00114
00115
00116 self.radio_manager.update()
00117
00118
00119 self.rank_interfaces()
00120
00121
00122 self.update_event.trigger()
00123
00124 @inlineCallbacks
00125 def set_tun_rules(self, selected_interfaces):
00126
00127 for i, iface in enumerate(selected_interfaces):
00128 if self.use_tunnel:
00129 self.tun_ip_rules[i].set('to', self.basestation_ip, 'lookup', iface.tableid)
00130 else:
00131 self.tun_ip_rules[i].set('lookup', iface.tableid)
00132
00133
00134 for tir in self.tun_ip_rules[len(selected_interfaces):]:
00135 yield tir.set()
00136
00137 TERRIBLE_INTERFACE = -1e1000
00138
00139 def score_interface(self, iface):
00140
00141
00142
00143
00144 if iface.goodness <= 0 and (self.forced_interface != iface.iface):
00145 iface.prescore = iface.score = InterfaceSelector.TERRIBLE_INTERFACE
00146 return
00147
00148
00149
00150 if self.forced_interface and self.forced_interface != iface.iface:
00151 iface.prescore = iface.score = InterfaceSelector.TERRIBLE_INTERFACE
00152 return
00153
00154 iface.prescore = iface.score = self.goodness_weight * iface.goodness + (1 - self.goodness_weight) * iface.reliability + iface.priority
00155 if not iface.active:
00156 iface.score -= self.inactive_penalty
00157
00158 def rank_interfaces(self):
00159
00160 interfaces = self.interfaces.values()
00161 for iface in interfaces:
00162 self.score_interface(iface)
00163
00164
00165 interfaces.sort(key = lambda iface: iface.score, reverse = True)
00166 active_interfaces = [ iface for iface in interfaces if iface.score != self.TERRIBLE_INTERFACE ]
00167
00168
00169 self.set_tun_rules(active_interfaces)
00170
00171
00172 now = time.time()
00173 print >> summary_logger
00174 print >> summary_logger, time.ctime(now), now
00175
00176 for rank, iface in enumerate(interfaces):
00177
00178 iface.timeout_time = now
00179 active = "active" if iface.active else ""
00180 rule = "rule " if iface in active_interfaces else "norule"
00181 print >> summary_logger, "#% 2i %10.10s %7.1f %7.3f %7.3f %17.17s %7.3f %3.0f %s %s"% \
00182 (rank, iface.prettyname, (iface.timeout_time - now), iface.score, iface.prescore, iface.bssid, iface.goodness, iface.reliability, rule, active)
00183
00184 self.active_interfaces = active_interfaces