00001
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
00013
00014
00015
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)
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
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
00091
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
00111 self.get_raw_state_publisher(self.cur_iface, IFSTATE.PLUGGED).set(not self.deleted)
00112
00113
00114 flags = tokens[0].strip('<>').split(',')
00115 self.get_raw_state_publisher(self.cur_iface, IFSTATE.UP).set('UP' in flags)
00116
00117
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
00134
00135 else:
00136
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
00176
00177 if __name__ == "__main__":
00178 main()