svc/conntrack.in: Introduce a function for parsing address strings.
[tripe] / svc / conntrack.in
index 3368295..061d6d7 100644 (file)
@@ -94,6 +94,9 @@ def toposort(cmp, things):
     if done:
       break
 
+def parse_address(addrstr):
+  return unpack('>L', S.inet_aton(addrstr))[0]
+
 ###--------------------------------------------------------------------------
 ### Parse the configuration file.
 
@@ -170,12 +173,12 @@ class Config (object):
         ## and MASK is either a dotted-quad or a single integer N indicating
         ## a mask with N leading ones followed by trailing zeroes.
         slash = net.index('/')
-        addr, = unpack('>L', S.inet_aton(net[:slash]))
-        if net.find('.', slash + 1) >= 0:
-          mask, = unpack('>L', S.inet_aton(net[:slash]))
-        else:
+        addr = parse_address(net[:slash])
+        if net[slash + 1:].isdigit():
           n = int(net[slash + 1:], 10)
           mask = (1 << 32) - (1 << 32 - n)
+        else:
+          mask = parse_address(net[slash + 1:])
         pats.append((tag, peer, addr & mask, mask))
 
       ## Annoyingly, RawConfigParser doesn't preserve the order of options.
@@ -197,7 +200,7 @@ CF = None
 def straddr(a): return a is None and '#<none>' or S.inet_ntoa(pack('>L', a))
 def strmask(m):
   for i in xrange(33):
-    if m == 0xffffffff ^ ((1 << (32 - i)) - 1): return i
+    if m == 0xffffffff ^ ((1 << (32 - i)) - 1): return str(i)
   return straddr(m)
 
 def cmd_showconfig():
@@ -229,7 +232,7 @@ def localaddr(peer):
     try:
       sk.connect((peer, 1))
       addr, _ = sk.getsockname()
-      addr, = unpack('>L', S.inet_aton(addr))
+      addr = parse_address(addr)
       return addr
     except S.error:
       return None
@@ -237,11 +240,42 @@ def localaddr(peer):
     sk.close()
 
 _kick = T.Queue()
+_delay = None
+
+def cancel_delay():
+  global _delay
+  if _delay is not None:
+    if T._debug: print '# cancel delayed kick'
+    G.source_remove(_delay)
+    _delay = None
+
+def netupdown(upness, reason):
+  """
+  Add or kill peers according to whether the network is up or down.
+
+  UPNESS is true if the network is up, or false if it's down.
+  """
+
+  _kick.put((upness, reason))
+
+def delay_netupdown(upness, reason):
+  global _delay
+  cancel_delay()
+  def _func():
+    global _delay
+    if T._debug: print '# delayed %s: %s' % (upness, reason)
+    _delay = None
+    netupdown(upness, reason)
+    return False
+  if T._debug: print '# delaying %s: %s' % (upness, reason)
+  _delay = G.timeout_add(2000, _func)
+
 def kickpeers():
   while True:
     upness, reason = _kick.get()
     if T._debug: print '# kickpeers %s: %s' % (upness, reason)
     select = []
+    cancel_delay()
 
     ## Make sure the configuration file is up-to-date.  Don't worry if we
     ## can't do anything useful.
@@ -332,15 +366,6 @@ def kickpeers():
       SM.notify('conntrack', upness and 'up' or 'down', *select + reason)
       for c in changes: c()
 
-def netupdown(upness, reason):
-  """
-  Add or kill peers according to whether the network is up or down.
-
-  UPNESS is true if the network is up, or false if it's down.
-  """
-
-  _kick.put((upness, reason))
-
 ###--------------------------------------------------------------------------
 ### NetworkManager monitor.
 
@@ -391,13 +416,13 @@ class NetworkManagerMonitor (object):
 
   def _nm_state(me, state):
     if state in NM_CONNSTATES:
-      netupdown(True, ['nm', 'connected'])
+      delay_netupdown(True, ['nm', 'connected'])
     else:
-      netupdown(False, ['nm', 'disconnected'])
+      delay_netupdown(False, ['nm', 'disconnected'])
 
   def _nm_connchange(me, props):
-    if props.get('Default', False):
-      netupdown(True, ['nm', 'default-connection-change'])
+    if props.get('Default', False) or props.get('Default6', False):
+      delay_netupdown(True, ['nm', 'default-connection-change'])
 
 ##--------------------------------------------------------------------------
 ### Connman monitor.
@@ -429,7 +454,7 @@ class ConnManMonitor (object):
 
   def _cm_state(me, prop, value):
     if prop != 'State': return
-    netupdown(value == 'online', ['connman', value])
+    delay_netupdown(value == 'online', ['connman', value])
 
 ###--------------------------------------------------------------------------
 ### Maemo monitor.
@@ -470,10 +495,10 @@ class MaemoICdMonitor (object):
   def _icd_state(me, iap, ty, state, hunoz):
     if state == 'CONNECTED':
       me._iap = iap
-      netupdown(True, ['icd', 'connected', iap])
+      delay_netupdown(True, ['icd', 'connected', iap])
     elif state == 'IDLE' and iap == me._iap:
       me._iap = None
-      netupdown(False, ['icd', 'idle'])
+      delay_netupdown(False, ['icd', 'idle'])
 
 ###--------------------------------------------------------------------------
 ### D-Bus connection tracking.
@@ -585,8 +610,9 @@ def init():
   DBM.addmon(NetworkManagerMonitor())
   DBM.addmon(ConnManMonitor())
   DBM.addmon(MaemoICdMonitor())
-  G.timeout_add_seconds(30, lambda: (netupdown(True, ['interval-timer'])
-                                     or True))
+  G.timeout_add_seconds(30, lambda: (_delay is not None or
+                                     netupdown(True, ['interval-timer']) or
+                                     True))
 
 def parse_options():
   """