$search
00001 #! /usr/bin/env python 00002 00003 import command_with_output 00004 import state_publisher 00005 import threading 00006 import time 00007 import traceback 00008 import pythonwifi.iwlibs 00009 import async_helpers 00010 from twisted.internet.defer import inlineCallbacks 00011 00012 # TODO 00013 # Make this autoshutdown when there are no references. 00014 00015 # FIXME Move this elsewhere. 00016 import subprocess 00017 class RunCommand: 00018 def __init__(self, *args): 00019 proc = subprocess.Popen(list(args), stdout = subprocess.PIPE, stderr = subprocess.PIPE, close_fds = True) 00020 (self.stdout, self.stderr) = proc.communicate() 00021 00022 class IFSTATE: 00023 PLUGGED = 0 00024 UP = 1 00025 LINK = 2 00026 LINK_ADDR = 3 00027 ADDR = 4 00028 NUM_STATES = 5 00029 00030 class NetlinkMonitor(command_with_output.CommandWithOutput): 00031 def __init__(self): 00032 self.lock = threading.RLock() 00033 self.raw_state_publishers = [ {} for i in range(0, IFSTATE.NUM_STATES)] 00034 self.state_publishers = [ {} for i in range(0, IFSTATE.NUM_STATES)] 00035 self.status_publishers = {} 00036 self.cur_iface = None 00037 self.deleted = None 00038 command_with_output.CommandWithOutput.__init__(self, ['ip', 'monitor', 'link', 'addr'], 'ip_monitor') 00039 00040 @inlineCallbacks 00041 def child_restart(self): 00042 yield async_helpers.async_sleep(0.2) # Limit race conditions on getting the startup state. 00043 current_state = RunCommand('ip', 'addr') 00044 with self.lock: 00045 old_cur_iface = self.cur_iface 00046 old_deleted = self.deleted 00047 for line in current_state.stdout.split('\n'): 00048 self.got_line(line) 00049 self.deleted = old_deleted 00050 self.cur_iface = old_cur_iface 00051 00052 def get_state_publisher(self, interface, level): 00053 if level == 0: 00054 return self.get_raw_state_publisher(interface, level) 00055 pubs = self.state_publishers[level] 00056 if not interface in pubs: 00057 pubs[interface] = state_publisher.CompositeStatePublisher(lambda l: l[0] and l[1], [ 00058 self.get_state_publisher(interface, level - 1), 00059 self.get_raw_state_publisher(interface, level), 00060 ]) 00061 return pubs[interface] 00062 00063 def get_raw_state_publisher(self, interface, level): 00064 pubs = self.raw_state_publishers[level] 00065 if not interface in pubs: 00066 pubs[interface] = state_publisher.StatePublisher(False) 00067 #pubs[interface].subscribe(self.debug_print, interface, level) 00068 return pubs[interface] 00069 00070 def debug_print(self, interface, level, old_state, new_state): 00071 print "Netlink transition", interface, level, "from", old_state, "to", new_state 00072 00073 def get_status_publisher(self, interface): 00074 if not interface in self.status_publishers: 00075 def lowest_nonzero(args): 00076 best = -1 00077 for arg in args: 00078 if not arg: 00079 break 00080 else: 00081 best += 1 00082 return best 00083 raw_pubs = [ self.get_raw_state_publisher(interface, level) for level in range(IFSTATE.NUM_STATES) ] 00084 self.status_publishers[interface] = state_publisher.CompositeStatePublisher(lowest_nonzero, raw_pubs) 00085 return self.status_publishers[interface] 00086 00087 def got_line(self, line): 00088 with self.lock: 00089 try: 00090 # Figure out the interface, and whether this is a delete 00091 # event. 00092 00093 if len(line) == 0 or (line[0] == ' ' and self.cur_iface == None): 00094 return 00095 tokens = line.rstrip().split() 00096 link_info = False 00097 if line[0] != ' ': 00098 if tokens[0] == 'Deleted': 00099 self.deleted = True 00100 tokens.pop(0) 00101 else: 00102 self.deleted = False 00103 self.cur_iface = tokens[1].rstrip(':') 00104 if tokens[1][-1] == ':': 00105 link_info = True 00106 tokens.pop(0) 00107 tokens.pop(0) 00108 00109 if link_info: 00110 # Plugged or not? 00111 self.get_raw_state_publisher(self.cur_iface, IFSTATE.PLUGGED).set(not self.deleted) 00112 00113 # Up or not? 00114 flags = tokens[0].strip('<>').split(',') 00115 self.get_raw_state_publisher(self.cur_iface, IFSTATE.UP).set('UP' in flags) 00116 00117 # Have a link? 00118 try: 00119 state_idx = tokens.index('state') 00120 state = tokens[state_idx + 1] 00121 if state != 'DOWN': 00122 try: 00123 link_state = pythonwifi.iwlibs.Wireless(self.cur_iface).getAPaddr() 00124 except IOError, e: 00125 if e.errno == 95 or e.errno == 22: 00126 link_state = 'Wired' 00127 else: 00128 raise 00129 else: 00130 link_state = False 00131 self.get_raw_state_publisher(self.cur_iface, IFSTATE.LINK).set(link_state) 00132 except ValueError: 00133 pass # Sometimes state is not listed. 00134 00135 else: 00136 # Find the address. 00137 if tokens[0] == 'inet': 00138 if self.deleted: 00139 addr_state = False 00140 else: 00141 addr_state = tokens[1].split('/') 00142 self.get_raw_state_publisher(self.cur_iface, IFSTATE.ADDR).set(addr_state) 00143 00144 if tokens[0].startswith('link/') and len(tokens) > 1: 00145 if self.deleted: 00146 addr_state = False 00147 else: 00148 addr_state = tokens[1] 00149 self.get_raw_state_publisher(self.cur_iface, IFSTATE.LINK_ADDR).set(addr_state) 00150 00151 except Exception, e: 00152 print "Caught exception in NetlinkMonitor.run:", e 00153 traceback.print_exc(10) 00154 print 00155 00156 monitor = netlink_monitor = NetlinkMonitor() 00157 00158 def print_status(iface): 00159 from twisted.internet import reactor 00160 print monitor.get_status_publisher(iface).get(), ' : ', 00161 for i in range(0,IFSTATE.NUM_STATES): 00162 print monitor.get_raw_state_publisher(iface, i).get(), 00163 print monitor.get_state_publisher(iface, i).get(), ' / ', 00164 print 00165 reactor.callLater(1, print_status, iface) 00166 00167 def main(): 00168 from twisted.internet import reactor 00169 iface = 'wlan0' 00170 try: 00171 print_status(iface) 00172 reactor.run() 00173 except KeyboardInterrupt: 00174 print "Shutting down on CTRL+C" 00175 #monitor.shutdown() 00176 00177 if __name__ == "__main__": 00178 main()