<p>Neels Hofmeyr has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/13610">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">contrib/voicecall-shark<br><br>Change-Id: Ia3cdefe16b9e929d2836ca837db6f6107f7ed9eb<br>---<br>A contrib/voicecall-shark<br>1 file changed, 669 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/10/13610/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/contrib/voicecall-shark b/contrib/voicecall-shark</span><br><span>new file mode 100755</span><br><span>index 0000000..54600d0</span><br><span>--- /dev/null</span><br><span>+++ b/contrib/voicecall-shark</span><br><span>@@ -0,0 +1,669 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#!/usr/bin/env python3</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+doc = '''voicecall-shark: get grips on voice call MGCP and RTP'''</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+import pyshark</span><br><span style="color: hsl(120, 100%, 40%);">+import pprint</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+verbose = False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def vprint(*args):</span><br><span style="color: hsl(120, 100%, 40%);">+ if not verbose:</span><br><span style="color: hsl(120, 100%, 40%);">+               return</span><br><span style="color: hsl(120, 100%, 40%);">+        print(*args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def error(*args):</span><br><span style="color: hsl(120, 100%, 40%);">+     raise Exception(''.join(*args))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def pget(p, *field, ifnone=None):</span><br><span style="color: hsl(120, 100%, 40%);">+  tokens = ('.'.join(field)).split('.')</span><br><span style="color: hsl(120, 100%, 40%);">+ if p is None or len(tokens) < 1:</span><br><span style="color: hsl(120, 100%, 40%);">+           return ifnone</span><br><span style="color: hsl(120, 100%, 40%);">+ first = tokens[0]</span><br><span style="color: hsl(120, 100%, 40%);">+     if not hasattr(p, first):</span><br><span style="color: hsl(120, 100%, 40%);">+             return ifnone</span><br><span style="color: hsl(120, 100%, 40%);">+ p_field = getattr(p, first)</span><br><span style="color: hsl(120, 100%, 40%);">+   if p_field is None:</span><br><span style="color: hsl(120, 100%, 40%);">+           return ifnone</span><br><span style="color: hsl(120, 100%, 40%);">+ if len(tokens) > 1:</span><br><span style="color: hsl(120, 100%, 40%);">+                return pget(p_field, *tokens[1:])</span><br><span style="color: hsl(120, 100%, 40%);">+     return p_field</span><br><span style="color: hsl(120, 100%, 40%);">+                </span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class LogEntry:</span><br><span style="color: hsl(120, 100%, 40%);">+   def __init__(s, p, message, obj):</span><br><span style="color: hsl(120, 100%, 40%);">+             s.p = p</span><br><span style="color: hsl(120, 100%, 40%);">+               s.message = message</span><br><span style="color: hsl(120, 100%, 40%);">+           s.obj = obj</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class HasLog:</span><br><span style="color: hsl(120, 100%, 40%);">+        def __init__(s, parent=None):</span><br><span style="color: hsl(120, 100%, 40%);">+         s.log_entries = []</span><br><span style="color: hsl(120, 100%, 40%);">+            s.parents = []</span><br><span style="color: hsl(120, 100%, 40%);">+                s.children = []</span><br><span style="color: hsl(120, 100%, 40%);">+               if parent is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+                        s.log_parent(parent)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        def log_child(s, child):</span><br><span style="color: hsl(120, 100%, 40%);">+              s.children.append(child)</span><br><span style="color: hsl(120, 100%, 40%);">+              child.parents.append(s)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     def log_parent(s, parent):</span><br><span style="color: hsl(120, 100%, 40%);">+            parent.log_child(s)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def log(s, p, message):</span><br><span style="color: hsl(120, 100%, 40%);">+               s.log_entries.append(LogEntry(p, message, s))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class Domino(HasLog):</span><br><span style="color: hsl(120, 100%, 40%);">+        def __init__(s, left, right, *refs):</span><br><span style="color: hsl(120, 100%, 40%);">+          s.left = left</span><br><span style="color: hsl(120, 100%, 40%);">+         s.right = right</span><br><span style="color: hsl(120, 100%, 40%);">+               s.refs = list(refs)</span><br><span style="color: hsl(120, 100%, 40%);">+           s.reversed = [ False ] * len(s.refs)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        def absorb(s, domino):</span><br><span style="color: hsl(120, 100%, 40%);">+                s.refs.extend(domino.refs)</span><br><span style="color: hsl(120, 100%, 40%);">+            s.reversed.extend(domino.reversed)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  def reverse(s):</span><br><span style="color: hsl(120, 100%, 40%);">+               x = s.left</span><br><span style="color: hsl(120, 100%, 40%);">+            s.left = s.right</span><br><span style="color: hsl(120, 100%, 40%);">+              s.right = x</span><br><span style="color: hsl(120, 100%, 40%);">+           s.reversed = list(map(lambda x: not x, s.reversed))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def matches(s, label):</span><br><span style="color: hsl(120, 100%, 40%);">+                if s.left == label:</span><br><span style="color: hsl(120, 100%, 40%);">+                   return -1</span><br><span style="color: hsl(120, 100%, 40%);">+             if s.right == label:</span><br><span style="color: hsl(120, 100%, 40%);">+                  return 1</span><br><span style="color: hsl(120, 100%, 40%);">+              return 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def __str__(s):</span><br><span style="color: hsl(120, 100%, 40%);">+               return s.str('[','|',']')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   def __repr__(s):</span><br><span style="color: hsl(120, 100%, 40%);">+              return str(s)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       def str(s, left='[', mid='|', right=']', reverse=False):</span><br><span style="color: hsl(120, 100%, 40%);">+              if reverse:</span><br><span style="color: hsl(120, 100%, 40%);">+                   return '%s%s%s%s%s' % (left, s.right, mid, s.left, right)</span><br><span style="color: hsl(120, 100%, 40%);">+             else:</span><br><span style="color: hsl(120, 100%, 40%);">+                 return '%s%s%s%s%s' % (left, s.left, mid, s.right, right)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   def __eq__(s, other):</span><br><span style="color: hsl(120, 100%, 40%);">+         o = other.str()</span><br><span style="color: hsl(120, 100%, 40%);">+               return s.str() == o or s.str(reverse=True) == o</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class Dominoes(HasLog):</span><br><span style="color: hsl(120, 100%, 40%);">+    def __init__(s, *pieces):</span><br><span style="color: hsl(120, 100%, 40%);">+             s.pieces = list(pieces)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     def has(s, piece):</span><br><span style="color: hsl(120, 100%, 40%);">+            for p in s.pieces:</span><br><span style="color: hsl(120, 100%, 40%);">+                    if p is piece:</span><br><span style="color: hsl(120, 100%, 40%);">+                                return True</span><br><span style="color: hsl(120, 100%, 40%);">+           return False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        def add(s, piece):</span><br><span style="color: hsl(120, 100%, 40%);">+            if s.has(piece):</span><br><span style="color: hsl(120, 100%, 40%);">+                      return</span><br><span style="color: hsl(120, 100%, 40%);">+                s.pieces.append(piece)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      def find_piece(s, label, in_list=None):</span><br><span style="color: hsl(120, 100%, 40%);">+               if in_list is None:</span><br><span style="color: hsl(120, 100%, 40%);">+                   in_list = s.pieces</span><br><span style="color: hsl(120, 100%, 40%);">+            for piece in in_list:</span><br><span style="color: hsl(120, 100%, 40%);">+                 if piece.matches(label):</span><br><span style="color: hsl(120, 100%, 40%);">+                              return piece</span><br><span style="color: hsl(120, 100%, 40%);">+          return None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def find_match(s, for_piece, in_list=None):</span><br><span style="color: hsl(120, 100%, 40%);">+           if in_list is None:</span><br><span style="color: hsl(120, 100%, 40%);">+                   in_list = s.pieces</span><br><span style="color: hsl(120, 100%, 40%);">+            match = s.find_piece(for_piece.left, in_list)</span><br><span style="color: hsl(120, 100%, 40%);">+         if not match:</span><br><span style="color: hsl(120, 100%, 40%);">+                 match = s.find_piece(for_piece.right, in_list)</span><br><span style="color: hsl(120, 100%, 40%);">+                return match</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        def dedup(loose_pieces):</span><br><span style="color: hsl(120, 100%, 40%);">+              pieces = []</span><br><span style="color: hsl(120, 100%, 40%);">+           loose_pieces = list(loose_pieces)</span><br><span style="color: hsl(120, 100%, 40%);">+             while loose_pieces:</span><br><span style="color: hsl(120, 100%, 40%);">+                   l = loose_pieces.pop(0)</span><br><span style="color: hsl(120, 100%, 40%);">+                       for p in pieces:</span><br><span style="color: hsl(120, 100%, 40%);">+                              if l == p:</span><br><span style="color: hsl(120, 100%, 40%);">+                                    p.absorb(l)</span><br><span style="color: hsl(120, 100%, 40%);">+                                   l = None</span><br><span style="color: hsl(120, 100%, 40%);">+                                      break</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                       if l:</span><br><span style="color: hsl(120, 100%, 40%);">+                         pieces.append(l)</span><br><span style="color: hsl(120, 100%, 40%);">+              return pieces</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       def arrange(loose_pieces):</span><br><span style="color: hsl(120, 100%, 40%);">+            if not loose_pieces:</span><br><span style="color: hsl(120, 100%, 40%);">+                  return []</span><br><span style="color: hsl(120, 100%, 40%);">+             pieces_remain = list(loose_pieces)</span><br><span style="color: hsl(120, 100%, 40%);">+            groups = [Dominoes(pieces_remain.pop(0))]</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           which_end = -1</span><br><span style="color: hsl(120, 100%, 40%);">+                failed = 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          while pieces_remain:</span><br><span style="color: hsl(120, 100%, 40%);">+                  which_end = 0 if which_end == -1 else -1</span><br><span style="color: hsl(120, 100%, 40%);">+                      found_match = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                       p = None</span><br><span style="color: hsl(120, 100%, 40%);">+                      for group in groups:</span><br><span style="color: hsl(120, 100%, 40%);">+                          p = group.pieces[which_end]</span><br><span style="color: hsl(120, 100%, 40%);">+                           match = group.find_match(p, pieces_remain)</span><br><span style="color: hsl(120, 100%, 40%);">+                            if not match:</span><br><span style="color: hsl(120, 100%, 40%);">+                                 continue</span><br><span style="color: hsl(120, 100%, 40%);">+                              if which_end == -1:</span><br><span style="color: hsl(120, 100%, 40%);">+                                   found_match = match.matches(p.right)</span><br><span style="color: hsl(120, 100%, 40%);">+                                  if found_match == 1:</span><br><span style="color: hsl(120, 100%, 40%);">+                                          match.reverse()</span><br><span style="color: hsl(120, 100%, 40%);">+                               else:</span><br><span style="color: hsl(120, 100%, 40%);">+                                 found_match = match.matches(p.left)</span><br><span style="color: hsl(120, 100%, 40%);">+                                   if found_match == -1:</span><br><span style="color: hsl(120, 100%, 40%);">+                                         match.reverse()</span><br><span style="color: hsl(120, 100%, 40%);">+                               if found_match:</span><br><span style="color: hsl(120, 100%, 40%);">+                                       break</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                       if found_match:</span><br><span style="color: hsl(120, 100%, 40%);">+                               failed = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                            pieces_remain.remove(match)</span><br><span style="color: hsl(120, 100%, 40%);">+                           if which_end == -1:</span><br><span style="color: hsl(120, 100%, 40%);">+                                   group.pieces.append(match)</span><br><span style="color: hsl(120, 100%, 40%);">+                            else:</span><br><span style="color: hsl(120, 100%, 40%);">+                                 group.pieces.insert(0, match)</span><br><span style="color: hsl(120, 100%, 40%);">+                 else:</span><br><span style="color: hsl(120, 100%, 40%);">+                         failed += 1</span><br><span style="color: hsl(120, 100%, 40%);">+                           if failed < 2:</span><br><span style="color: hsl(120, 100%, 40%);">+                                     continue</span><br><span style="color: hsl(120, 100%, 40%);">+                              # chain is broken. Create another group.</span><br><span style="color: hsl(120, 100%, 40%);">+                              groups.append(Dominoes(pieces_remain.pop(0)))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               return groups</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       def str(s, piece_left_edge='[', piece_mid='|', piece_right_edge=']'):</span><br><span style="color: hsl(120, 100%, 40%);">+         r = []</span><br><span style="color: hsl(120, 100%, 40%);">+                for p in s.pieces:</span><br><span style="color: hsl(120, 100%, 40%);">+                    r.append(p.str(piece_left_edge, piece_mid, piece_right_edge))</span><br><span style="color: hsl(120, 100%, 40%);">+         return ''.join(r)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   def __str__(s):</span><br><span style="color: hsl(120, 100%, 40%);">+               return s.str()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      def chain_str(s, sep=', '):</span><br><span style="color: hsl(120, 100%, 40%);">+           if not s.pieces:</span><br><span style="color: hsl(120, 100%, 40%);">+                      return ''</span><br><span style="color: hsl(120, 100%, 40%);">+             r = [s.pieces[0].left]</span><br><span style="color: hsl(120, 100%, 40%);">+                for p in s.pieces:</span><br><span style="color: hsl(120, 100%, 40%);">+                    if r[-1] != p.left:</span><br><span style="color: hsl(120, 100%, 40%);">+                           r.append(p.left)</span><br><span style="color: hsl(120, 100%, 40%);">+                      if r[-1] != p.right:</span><br><span style="color: hsl(120, 100%, 40%);">+                          r.append(p.right)</span><br><span style="color: hsl(120, 100%, 40%);">+             return sep.join(r)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class RtpIpPort(HasLog):</span><br><span style="color: hsl(120, 100%, 40%);">+        def __init__(s, ip=None, port=None):</span><br><span style="color: hsl(120, 100%, 40%);">+          s.ip = ip</span><br><span style="color: hsl(120, 100%, 40%);">+             s.port = port</span><br><span style="color: hsl(120, 100%, 40%);">+ </span><br><span style="color: hsl(120, 100%, 40%);">+      def from_sdp(p):</span><br><span style="color: hsl(120, 100%, 40%);">+              ip = pget(p, 'sdp.connection_info_address')</span><br><span style="color: hsl(120, 100%, 40%);">+           port = pget(p, 'sdp.media_port')</span><br><span style="color: hsl(120, 100%, 40%);">+              return RtpIpPort(ip, port)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  def from_rtp_source(p):</span><br><span style="color: hsl(120, 100%, 40%);">+               ip = pget(p, 'ip.src')</span><br><span style="color: hsl(120, 100%, 40%);">+                port = pget(p, 'udp.srcport')</span><br><span style="color: hsl(120, 100%, 40%);">+         return RtpIpPort(ip, port)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  def from_rtp_dest(p):</span><br><span style="color: hsl(120, 100%, 40%);">+         ip = pget(p, 'ip.dst')</span><br><span style="color: hsl(120, 100%, 40%);">+                port = pget(p, 'udp.dstport')</span><br><span style="color: hsl(120, 100%, 40%);">+         return RtpIpPort(ip, port)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  def __str__(s):</span><br><span style="color: hsl(120, 100%, 40%);">+               return '%s:%s' % (s.ip, s.port)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     def __eq__(s, other):</span><br><span style="color: hsl(120, 100%, 40%);">+         return str(s) == str(other)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class MgcpConn(HasLog):</span><br><span style="color: hsl(120, 100%, 40%);">+      def __init__(s, crcx_p, endpoint, conn_id=None):</span><br><span style="color: hsl(120, 100%, 40%);">+              s.endpoint = None</span><br><span style="color: hsl(120, 100%, 40%);">+             endpoint.add_conn(s)</span><br><span style="color: hsl(120, 100%, 40%);">+          s.conn_id = conn_id</span><br><span style="color: hsl(120, 100%, 40%);">+           s.crcx = crcx_p</span><br><span style="color: hsl(120, 100%, 40%);">+               s.crcx_ok = None</span><br><span style="color: hsl(120, 100%, 40%);">+              s.mdcx = []</span><br><span style="color: hsl(120, 100%, 40%);">+           s.dlcx = None</span><br><span style="color: hsl(120, 100%, 40%);">+         s.dlcx_ok = None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            s.rtp_local = None</span><br><span style="color: hsl(120, 100%, 40%);">+            s.rtp_remote = None</span><br><span style="color: hsl(120, 100%, 40%);">+           s.payload_type = None</span><br><span style="color: hsl(120, 100%, 40%);">+         s.codec = None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              s.rtp_tx = 0</span><br><span style="color: hsl(120, 100%, 40%);">+          s.rtp_tx_err = 0</span><br><span style="color: hsl(120, 100%, 40%);">+              s.rtp_rx = 0</span><br><span style="color: hsl(120, 100%, 40%);">+          s.rtp_rx_err = 0</span><br><span style="color: hsl(120, 100%, 40%);">+              super().__init__(endpoint)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  def rx_verb(s, p):</span><br><span style="color: hsl(120, 100%, 40%);">+            v = p.mgcp.req_verb</span><br><span style="color: hsl(120, 100%, 40%);">+           vprint("VERB %r" % v)</span><br><span style="color: hsl(120, 100%, 40%);">+               if v == 'CRCX':</span><br><span style="color: hsl(120, 100%, 40%);">+                       if hasattr(p, 'sdp'):</span><br><span style="color: hsl(120, 100%, 40%);">+                         s.rtp_remote = RtpIpPort.from_sdp(p)</span><br><span style="color: hsl(120, 100%, 40%);">+          elif v == 'MDCX':</span><br><span style="color: hsl(120, 100%, 40%);">+                     s.mdcx.append(p)</span><br><span style="color: hsl(120, 100%, 40%);">+                      new_remote = RtpIpPort.from_sdp(p)</span><br><span style="color: hsl(120, 100%, 40%);">+                    if s.rtp_remote != new_remote:</span><br><span style="color: hsl(120, 100%, 40%);">+                                s.rtp_remote = RtpIpPort.from_sdp(p)</span><br><span style="color: hsl(120, 100%, 40%);">+                          s.log(p, 'MDCX to %s' % new_remote)</span><br><span style="color: hsl(120, 100%, 40%);">+                   else:</span><br><span style="color: hsl(120, 100%, 40%);">+                         s.log(p, 'MDCX')</span><br><span style="color: hsl(120, 100%, 40%);">+                                      </span><br><span style="color: hsl(120, 100%, 40%);">+              elif v == 'DLCX':</span><br><span style="color: hsl(120, 100%, 40%);">+                     s.log(p, 'DLCX')</span><br><span style="color: hsl(120, 100%, 40%);">+                      s.dlcx = p</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          s.get_media(p)</span><br><span style="color: hsl(120, 100%, 40%);">+        </span><br><span style="color: hsl(120, 100%, 40%);">+      def get_media(s, p):</span><br><span style="color: hsl(120, 100%, 40%);">+          s.codec = pget(p, 'sdp.media_proto', ifnone=s.codec)</span><br><span style="color: hsl(120, 100%, 40%);">+          s.payload_type = pget(p, 'sdp.media_format', ifnone=s.payload_type)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def rx_verb_ok(s, p, verb_p):</span><br><span style="color: hsl(120, 100%, 40%);">+         verb = verb_p.mgcp.req_verb</span><br><span style="color: hsl(120, 100%, 40%);">+           vprint("VERB OK %r" % verb)</span><br><span style="color: hsl(120, 100%, 40%);">+         if verb == 'CRCX':</span><br><span style="color: hsl(120, 100%, 40%);">+                    s.crcx_ok = p</span><br><span style="color: hsl(120, 100%, 40%);">+                 if hasattr(p.mgcp, 'param_specificendpointid'):</span><br><span style="color: hsl(120, 100%, 40%);">+                               s.endpoint.name = p.mgcp.param_specificendpointid</span><br><span style="color: hsl(120, 100%, 40%);">+                     s.conn_id = p.mgcp.param_connectionid</span><br><span style="color: hsl(120, 100%, 40%);">+                 s.rtp_local = RtpIpPort.from_sdp(p)</span><br><span style="color: hsl(120, 100%, 40%);">+                   s.log(p, "CRCX OK")</span><br><span style="color: hsl(120, 100%, 40%);">+         elif verb == 'MDCX':</span><br><span style="color: hsl(120, 100%, 40%);">+                  s.mdcx.append(p)</span><br><span style="color: hsl(120, 100%, 40%);">+                      s.log(p, "MDCX OK")</span><br><span style="color: hsl(120, 100%, 40%);">+         elif verb == 'DLCX':</span><br><span style="color: hsl(120, 100%, 40%);">+                  s.dlcx_ok = p</span><br><span style="color: hsl(120, 100%, 40%);">+                 s.log(p, "DLCX OK")</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       def is_open(s):</span><br><span style="color: hsl(120, 100%, 40%);">+               return s.dlcx is None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       def summary(s, remote_first=False):</span><br><span style="color: hsl(120, 100%, 40%);">+           label = ''</span><br><span style="color: hsl(120, 100%, 40%);">+            if not s.is_open():</span><br><span style="color: hsl(120, 100%, 40%);">+                   label = 'DLCXd '</span><br><span style="color: hsl(120, 100%, 40%);">+              rtp1 = s.rtp_local</span><br><span style="color: hsl(120, 100%, 40%);">+            rtp2 = s.rtp_remote</span><br><span style="color: hsl(120, 100%, 40%);">+           if remote_first:</span><br><span style="color: hsl(120, 100%, 40%);">+                      rtpx = rtp1</span><br><span style="color: hsl(120, 100%, 40%);">+                   rtp1 = rtp2</span><br><span style="color: hsl(120, 100%, 40%);">+                   rtp2 = rtpx</span><br><span style="color: hsl(120, 100%, 40%);">+           err_label = ''</span><br><span style="color: hsl(120, 100%, 40%);">+                if s.rtp_tx_err:</span><br><span style="color: hsl(120, 100%, 40%);">+                      err_label = err_label + ' tx-ERR:%d' % s.rtp_tx_err</span><br><span style="color: hsl(120, 100%, 40%);">+           if s.rtp_rx_err:</span><br><span style="color: hsl(120, 100%, 40%);">+                      err_label = err_label + ' rx-ERR:%d' % s.rtp_rx_err</span><br><span style="color: hsl(120, 100%, 40%);">+           return '%s%s: %s <-> %s %r %r tx:%d rx:%d' % (</span><br><span style="color: hsl(120, 100%, 40%);">+                          label, s.conn_id, rtp1, rtp2, s.payload_type, s.codec, s.rtp_tx, s.rtp_rx)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class MgcpEndpoint(HasLog):</span><br><span style="color: hsl(120, 100%, 40%);">+   def __init__(s, name):</span><br><span style="color: hsl(120, 100%, 40%);">+                s.name = name</span><br><span style="color: hsl(120, 100%, 40%);">+         s.conns = []</span><br><span style="color: hsl(120, 100%, 40%);">+          super().__init__()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  def name_is(s, name):</span><br><span style="color: hsl(120, 100%, 40%);">+         return s.name == name</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       def add_conn(s, mgcp_conn):</span><br><span style="color: hsl(120, 100%, 40%);">+           s.conns.append(mgcp_conn)</span><br><span style="color: hsl(120, 100%, 40%);">+             mgcp_conn.endpoint = s</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      def is_open(s):</span><br><span style="color: hsl(120, 100%, 40%);">+               return any(c.is_open() for c in s.conns)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def get_conn(s, p):</span><br><span style="color: hsl(120, 100%, 40%);">+           conn_id = pget(p, 'mgcp.param_connectionid')</span><br><span style="color: hsl(120, 100%, 40%);">+          if not conn_id:</span><br><span style="color: hsl(120, 100%, 40%);">+                       return None</span><br><span style="color: hsl(120, 100%, 40%);">+           vprint('get conn_id %r' % conn_id)</span><br><span style="color: hsl(120, 100%, 40%);">+            for c in s.conns:</span><br><span style="color: hsl(120, 100%, 40%);">+                     vprint('  conn_id %r' % c.conn_id)</span><br><span style="color: hsl(120, 100%, 40%);">+                    if c.conn_id == conn_id:</span><br><span style="color: hsl(120, 100%, 40%);">+                              return c</span><br><span style="color: hsl(120, 100%, 40%);">+              print('ERROR: unknown conn id %r' % conn_id)</span><br><span style="color: hsl(120, 100%, 40%);">+          return None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def as_dominoes(s):</span><br><span style="color: hsl(120, 100%, 40%);">+           pieces = []</span><br><span style="color: hsl(120, 100%, 40%);">+           for i in range(len(s.conns)):</span><br><span style="color: hsl(120, 100%, 40%);">+                 c = s.conns[i]</span><br><span style="color: hsl(120, 100%, 40%);">+                        if not c.is_open():</span><br><span style="color: hsl(120, 100%, 40%);">+                           continue</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    left = str(c.rtp_remote)</span><br><span style="color: hsl(120, 100%, 40%);">+                      right = str(c.rtp_local)</span><br><span style="color: hsl(120, 100%, 40%);">+                      pieces.append(Domino(left, right, s))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                       for j in range(i+1, len(s.conns)):</span><br><span style="color: hsl(120, 100%, 40%);">+                            c2 = s.conns[j]</span><br><span style="color: hsl(120, 100%, 40%);">+                               if not c2.is_open():</span><br><span style="color: hsl(120, 100%, 40%);">+                                  continue</span><br><span style="color: hsl(120, 100%, 40%);">+                              left = str(c.rtp_local)</span><br><span style="color: hsl(120, 100%, 40%);">+                               right = str(c2.rtp_local)</span><br><span style="color: hsl(120, 100%, 40%);">+                             pieces.append(Domino(left, right, s))</span><br><span style="color: hsl(120, 100%, 40%);">+         return pieces</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       def reverse(s):</span><br><span style="color: hsl(120, 100%, 40%);">+               s.conns = list(reversed(s.conns))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   def seen_rtp(s, src, dst):</span><br><span style="color: hsl(120, 100%, 40%);">+            handled = False</span><br><span style="color: hsl(120, 100%, 40%);">+               for c in s.conns:</span><br><span style="color: hsl(120, 100%, 40%);">+                     if c.rtp_local == src:</span><br><span style="color: hsl(120, 100%, 40%);">+                                handled = True</span><br><span style="color: hsl(120, 100%, 40%);">+                                if c.rtp_remote == dst:</span><br><span style="color: hsl(120, 100%, 40%);">+                                       c.rtp_tx += 1</span><br><span style="color: hsl(120, 100%, 40%);">+                         else:</span><br><span style="color: hsl(120, 100%, 40%);">+                                 c.rtp_tx_err += 1</span><br><span style="color: hsl(120, 100%, 40%);">+                     if c.rtp_remote == src:</span><br><span style="color: hsl(120, 100%, 40%);">+                               handled = True</span><br><span style="color: hsl(120, 100%, 40%);">+                                if c.rtp_local == dst:</span><br><span style="color: hsl(120, 100%, 40%);">+                                        c.rtp_rx += 1</span><br><span style="color: hsl(120, 100%, 40%);">+                         else:</span><br><span style="color: hsl(120, 100%, 40%);">+                                 c.rtp_rx_err += 1</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           return handled</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      def summary(s):</span><br><span style="color: hsl(120, 100%, 40%);">+               r = [s.name]</span><br><span style="color: hsl(120, 100%, 40%);">+          remote_first = True</span><br><span style="color: hsl(120, 100%, 40%);">+           for c in s.conns:</span><br><span style="color: hsl(120, 100%, 40%);">+                     r.append(' | %s' % c.summary(remote_first))</span><br><span style="color: hsl(120, 100%, 40%);">+                   remote_first = False</span><br><span style="color: hsl(120, 100%, 40%);">+          return '\n'.join(r)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class MgcpTrans:</span><br><span style="color: hsl(120, 100%, 40%);">+       def __init__(s, p, obj):</span><br><span style="color: hsl(120, 100%, 40%);">+              s.p = p</span><br><span style="color: hsl(120, 100%, 40%);">+               s.obj = obj</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class RtpStream(HasLog):</span><br><span style="color: hsl(120, 100%, 40%);">+       all_rtp_streams = []</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        def find(rtp_ip_port):</span><br><span style="color: hsl(120, 100%, 40%);">+                for rtps in all_rtp_streams:</span><br><span style="color: hsl(120, 100%, 40%);">+                  if rtps.has(rtp_ip_port):</span><br><span style="color: hsl(120, 100%, 40%);">+                             return rtps</span><br><span style="color: hsl(120, 100%, 40%);">+           return None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def find_or_create(rtp_ip_ports):</span><br><span style="color: hsl(120, 100%, 40%);">+             rtps = None</span><br><span style="color: hsl(120, 100%, 40%);">+           for rtp_ip_port in rtp_ip_ports:</span><br><span style="color: hsl(120, 100%, 40%);">+                      rtps = RtpStream.find(rtp_ip_port)</span><br><span style="color: hsl(120, 100%, 40%);">+                    if rtps:</span><br><span style="color: hsl(120, 100%, 40%);">+                              break</span><br><span style="color: hsl(120, 100%, 40%);">+         rtps.add(*rtp_ip_ports)</span><br><span style="color: hsl(120, 100%, 40%);">+               return rtps</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def __init__(s, rtp_ip_ports=[]):</span><br><span style="color: hsl(120, 100%, 40%);">+             s.call_leg = None</span><br><span style="color: hsl(120, 100%, 40%);">+             s.rtp_ip_ports = rtp_ip_ports</span><br><span style="color: hsl(120, 100%, 40%);">+         s.rtp_packets_left = 0</span><br><span style="color: hsl(120, 100%, 40%);">+                s.rtp_packets_right = 0</span><br><span style="color: hsl(120, 100%, 40%);">+               super().__init__()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  def has(s, rtp_ip_port):</span><br><span style="color: hsl(120, 100%, 40%);">+              for ipp in s.rtp_ip_ports:</span><br><span style="color: hsl(120, 100%, 40%);">+                    if ipp == rtp_ip_port:</span><br><span style="color: hsl(120, 100%, 40%);">+                                return True</span><br><span style="color: hsl(120, 100%, 40%);">+           return False</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        def add(s, *rtp_ip_ports):</span><br><span style="color: hsl(120, 100%, 40%);">+            for rtp_ip_port in rtp_ip_ports:</span><br><span style="color: hsl(120, 100%, 40%);">+                      if s.has(rtp_ip_port):</span><br><span style="color: hsl(120, 100%, 40%);">+                                continue</span><br><span style="color: hsl(120, 100%, 40%);">+                      if len(s.rtp_ip_ports) > 1:</span><br><span style="color: hsl(120, 100%, 40%);">+                                error('RtpStream can have only two RtpIpPorts')</span><br><span style="color: hsl(120, 100%, 40%);">+                       s.rtp_ip_ports.append(rtp_ip_port)</span><br><span style="color: hsl(120, 100%, 40%);">+    </span><br><span style="color: hsl(120, 100%, 40%);">+      def reverse(s):</span><br><span style="color: hsl(120, 100%, 40%);">+               s.rtp_ip_ports = list(reversed(s.rtp_ip_ports))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     def left(s):</span><br><span style="color: hsl(120, 100%, 40%);">+          if len(s.rtp_ip_ports):</span><br><span style="color: hsl(120, 100%, 40%);">+                       return s.rtp_ip_ports[0]</span><br><span style="color: hsl(120, 100%, 40%);">+              return None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def right(s):</span><br><span style="color: hsl(120, 100%, 40%);">+         if len(s.rtp_ip_ports) > 1:</span><br><span style="color: hsl(120, 100%, 40%);">+                        return s.rtp_ip_ports[1]</span><br><span style="color: hsl(120, 100%, 40%);">+              return None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class CallLeg(HasLog):</span><br><span style="color: hsl(120, 100%, 40%);">+       def tie(rtp_ip_port_a, rtp_ip_port_b):</span><br><span style="color: hsl(120, 100%, 40%);">+                rtps_a = RtpStream.find(rtp_ip_port_a)</span><br><span style="color: hsl(120, 100%, 40%);">+                rtps_b = RtpStream.find(rtp_ip_port_b)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def __init__(s):</span><br><span style="color: hsl(120, 100%, 40%);">+              self.rtp_streams = []</span><br><span style="color: hsl(120, 100%, 40%);">+         super().__init__()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  def add_rtp_stream(s, tie_to_rtp_ip_port, rtp_stream):</span><br><span style="color: hsl(120, 100%, 40%);">+                self.rtp_streams.append(rtp_stream)</span><br><span style="color: hsl(120, 100%, 40%);">+           s.log_child(edge)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+class Results:</span><br><span style="color: hsl(120, 100%, 40%);">+ def __init__(s, call_legs = []):</span><br><span style="color: hsl(120, 100%, 40%);">+              s.call_legs = call_legs</span><br><span style="color: hsl(120, 100%, 40%);">+               s.mgw_endpoints = []</span><br><span style="color: hsl(120, 100%, 40%);">+          s.mgcp_transactions = []</span><br><span style="color: hsl(120, 100%, 40%);">+              s.stray_rtp = 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     def mgcp_trans_new(s, p, obj):</span><br><span style="color: hsl(120, 100%, 40%);">+                s.mgcp_transactions.append(MgcpTrans(p, obj))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       def mgcp_trans_res(s, p):</span><br><span style="color: hsl(120, 100%, 40%);">+             for t in s.mgcp_transactions:</span><br><span style="color: hsl(120, 100%, 40%);">+                 if t.p.mgcp.transid == p.mgcp.transid:</span><br><span style="color: hsl(120, 100%, 40%);">+                                o = t.obj</span><br><span style="color: hsl(120, 100%, 40%);">+                             s.mgcp_transactions.remove(t)</span><br><span style="color: hsl(120, 100%, 40%);">+                         return t</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def new_endpoint(s, p):</span><br><span style="color: hsl(120, 100%, 40%);">+               ep = MgcpEndpoint(p.mgcp.req_endpoint)</span><br><span style="color: hsl(120, 100%, 40%);">+                s.mgw_endpoints.append(ep)</span><br><span style="color: hsl(120, 100%, 40%);">+            return ep</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   def find_endpoint(s, endpoint, still_open=False):</span><br><span style="color: hsl(120, 100%, 40%);">+             for ep in s.mgw_endpoints:</span><br><span style="color: hsl(120, 100%, 40%);">+                    if not ep.name_is(endpoint):</span><br><span style="color: hsl(120, 100%, 40%);">+                          continue</span><br><span style="color: hsl(120, 100%, 40%);">+                      if still_open and not ep.is_open():</span><br><span style="color: hsl(120, 100%, 40%);">+                           continue</span><br><span style="color: hsl(120, 100%, 40%);">+                      return ep</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   def process_mgcp(s, p):</span><br><span style="color: hsl(120, 100%, 40%);">+               m = p.mgcp</span><br><span style="color: hsl(120, 100%, 40%);">+            if verbose:</span><br><span style="color: hsl(120, 100%, 40%);">+                   print('----')</span><br><span style="color: hsl(120, 100%, 40%);">+                 print(p.pretty_print())</span><br><span style="color: hsl(120, 100%, 40%);">+                       print('MGCP:')</span><br><span style="color: hsl(120, 100%, 40%);">+                        pprint.pprint(p.mgcp.field_names)</span><br><span style="color: hsl(120, 100%, 40%);">+                     if hasattr(p, 'sdp'):</span><br><span style="color: hsl(120, 100%, 40%);">+                         print('SDP:')</span><br><span style="color: hsl(120, 100%, 40%);">+                         pprint.pprint(p.sdp.field_names)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            ep = None</span><br><span style="color: hsl(120, 100%, 40%);">+             label = None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                if 'req_verb' in m.field_names:</span><br><span style="color: hsl(120, 100%, 40%);">+                       v = m.req_verb</span><br><span style="color: hsl(120, 100%, 40%);">+                        label = v</span><br><span style="color: hsl(120, 100%, 40%);">+                     ci = None</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   ep = s.find_endpoint(m.req_endpoint, True)</span><br><span style="color: hsl(120, 100%, 40%);">+                    if ep is None:</span><br><span style="color: hsl(120, 100%, 40%);">+                                ep = s.new_endpoint(p)</span><br><span style="color: hsl(120, 100%, 40%);">+                        vprint('VERB ep %r' % ep.name)</span><br><span style="color: hsl(120, 100%, 40%);">+                        if ci is None:</span><br><span style="color: hsl(120, 100%, 40%);">+                                ci = ep.get_conn(p)</span><br><span style="color: hsl(120, 100%, 40%);">+                   if ci is None:</span><br><span style="color: hsl(120, 100%, 40%);">+                                ci = MgcpConn(p, ep)</span><br><span style="color: hsl(120, 100%, 40%);">+                  ci.rx_verb(p)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                       s.mgcp_trans_new(p, ci)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             elif 'rsp' in m.field_names:</span><br><span style="color: hsl(120, 100%, 40%);">+                  t = s.mgcp_trans_res(p)</span><br><span style="color: hsl(120, 100%, 40%);">+                       ci = t.obj</span><br><span style="color: hsl(120, 100%, 40%);">+                    ci.rx_verb_ok(p, t.p)</span><br><span style="color: hsl(120, 100%, 40%);">+                 label = '%s OK' % t.p.mgcp.req_verb</span><br><span style="color: hsl(120, 100%, 40%);">+                   ep = ci.endpoint</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            if ep is not None:</span><br><span style="color: hsl(120, 100%, 40%);">+                    print('----- %s' % label)</span><br><span style="color: hsl(120, 100%, 40%);">+                     print(ep.summary())</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def process_rtp(s, p):</span><br><span style="color: hsl(120, 100%, 40%);">+                src = RtpIpPort.from_rtp_source(p)</span><br><span style="color: hsl(120, 100%, 40%);">+            dst = RtpIpPort.from_rtp_dest(p)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            handled = False</span><br><span style="color: hsl(120, 100%, 40%);">+               for ep in s.mgw_endpoints:</span><br><span style="color: hsl(120, 100%, 40%);">+                    if ep.seen_rtp(src, dst):</span><br><span style="color: hsl(120, 100%, 40%);">+                             handled = True</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              if not handled:</span><br><span style="color: hsl(120, 100%, 40%);">+                       s.stray_rtp += 1</span><br><span style="color: hsl(120, 100%, 40%);">+                      print("Stray RTP: %s -> %s" % (src, dst))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    def process_cap(s, cap):</span><br><span style="color: hsl(120, 100%, 40%);">+              last_time = None</span><br><span style="color: hsl(120, 100%, 40%);">+              refresh = False</span><br><span style="color: hsl(120, 100%, 40%);">+               last_stray_rtp = 0</span><br><span style="color: hsl(120, 100%, 40%);">+            for p in cap:</span><br><span style="color: hsl(120, 100%, 40%);">+                 if hasattr(p, 'mgcp'):</span><br><span style="color: hsl(120, 100%, 40%);">+                                s.process_mgcp(p)</span><br><span style="color: hsl(120, 100%, 40%);">+                             refresh = True</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      if hasattr(p, 'rtp'):</span><br><span style="color: hsl(120, 100%, 40%);">+                         s.process_rtp(p)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                    if hasattr(p, 'udp'):</span><br><span style="color: hsl(120, 100%, 40%);">+                         time = float(pget(p, 'udp.time_relative', ifnone='0'))</span><br><span style="color: hsl(120, 100%, 40%);">+                                if last_time is None or time > last_time + 1:</span><br><span style="color: hsl(120, 100%, 40%);">+                                      last_time = time</span><br><span style="color: hsl(120, 100%, 40%);">+                                      refresh = True</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      if refresh:</span><br><span style="color: hsl(120, 100%, 40%);">+                           refresh = False</span><br><span style="color: hsl(120, 100%, 40%);">+                               s.correlate_endpoints()</span><br><span style="color: hsl(120, 100%, 40%);">+                               if last_stray_rtp != s.stray_rtp:</span><br><span style="color: hsl(120, 100%, 40%);">+                                     print('stray_rtp: %d' % (s.stray_rtp - last_stray_rtp))</span><br><span style="color: hsl(120, 100%, 40%);">+                                       last_stray_rtp = s.stray_rtp</span><br><span style="color: hsl(120, 100%, 40%);">+                          print(time)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   def correlate_endpoints(s):</span><br><span style="color: hsl(120, 100%, 40%);">+           pieces = []</span><br><span style="color: hsl(120, 100%, 40%);">+           for ep in s.mgw_endpoints:</span><br><span style="color: hsl(120, 100%, 40%);">+                    pieces.extend(ep.as_dominoes())</span><br><span style="color: hsl(120, 100%, 40%);">+               groups = Dominoes.arrange(Dominoes.dedup(pieces))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           i = 0</span><br><span style="color: hsl(120, 100%, 40%);">+         for g in groups:</span><br><span style="color: hsl(120, 100%, 40%);">+                      i += 1</span><br><span style="color: hsl(120, 100%, 40%);">+                        print('\n--- Call chain %d' % i)</span><br><span style="color: hsl(120, 100%, 40%);">+                      print(g.chain_str('<->'))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     endp_chain = []</span><br><span style="color: hsl(120, 100%, 40%);">+                       for piece in g.pieces:</span><br><span style="color: hsl(120, 100%, 40%);">+                                for i in range(len(piece.refs)):</span><br><span style="color: hsl(120, 100%, 40%);">+                                      ref = piece.refs[i]</span><br><span style="color: hsl(120, 100%, 40%);">+                                   reversd = piece.reversed[i]</span><br><span style="color: hsl(120, 100%, 40%);">+                                   if type(ref) is not MgcpEndpoint:</span><br><span style="color: hsl(120, 100%, 40%);">+                                             continue</span><br><span style="color: hsl(120, 100%, 40%);">+                                      if ref in endp_chain:</span><br><span style="color: hsl(120, 100%, 40%);">+                                         continue</span><br><span style="color: hsl(120, 100%, 40%);">+                                      endp_chain.append(ref)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                      prev_rtp = g.pieces[0].left</span><br><span style="color: hsl(120, 100%, 40%);">+                   for ep in endp_chain:</span><br><span style="color: hsl(120, 100%, 40%);">+                         if not len(ep.conns):</span><br><span style="color: hsl(120, 100%, 40%);">+                                 continue</span><br><span style="color: hsl(120, 100%, 40%);">+                              if str(ep.conns[0].rtp_remote) != prev_rtp:</span><br><span style="color: hsl(120, 100%, 40%);">+                                   ep.reverse()</span><br><span style="color: hsl(120, 100%, 40%);">+                          print(ep.summary())</span><br><span style="color: hsl(120, 100%, 40%);">+                           prev_rtp = str(ep.conns[-1].rtp_local)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              print('\n')</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ def process_file(s, path):</span><br><span style="color: hsl(120, 100%, 40%);">+            vprint(repr(path))</span><br><span style="color: hsl(120, 100%, 40%);">+            cap = pyshark.FileCapture(path)</span><br><span style="color: hsl(120, 100%, 40%);">+               s.process_cap(cap)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  def summary(s):</span><br><span style="color: hsl(120, 100%, 40%);">+               r = []</span><br><span style="color: hsl(120, 100%, 40%);">+                still_open = 0</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              for ep in s.mgw_endpoints:</span><br><span style="color: hsl(120, 100%, 40%);">+                    if not ep.is_open():</span><br><span style="color: hsl(120, 100%, 40%);">+                          continue</span><br><span style="color: hsl(120, 100%, 40%);">+                      r.append(ep.summary())</span><br><span style="color: hsl(120, 100%, 40%);">+                        still_open += 1</span><br><span style="color: hsl(120, 100%, 40%);">+               r.append('open mgcp endpoints: %d' % still_open)</span><br><span style="color: hsl(120, 100%, 40%);">+              return '\n'.join(r)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def parse_args():</span><br><span style="color: hsl(120, 100%, 40%);">+    import argparse</span><br><span style="color: hsl(120, 100%, 40%);">+       parser = argparse.ArgumentParser(description=doc)</span><br><span style="color: hsl(120, 100%, 40%);">+     parser.add_argument('--pcap-file', '-f')</span><br><span style="color: hsl(120, 100%, 40%);">+      return parser.parse_args()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+def dominoes_test():</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  d = [</span><br><span style="color: hsl(120, 100%, 40%);">+ Domino('hat', 'hut'),</span><br><span style="color: hsl(120, 100%, 40%);">+ Domino('ape', 'dog'),</span><br><span style="color: hsl(120, 100%, 40%);">+ Domino('moo', 'foo'),</span><br><span style="color: hsl(120, 100%, 40%);">+ Domino('cat', 'dog'),</span><br><span style="color: hsl(120, 100%, 40%);">+ Domino('ape', 'cow'),</span><br><span style="color: hsl(120, 100%, 40%);">+ Domino('axe', 'hop'),</span><br><span style="color: hsl(120, 100%, 40%);">+ Domino('hat', 'cat'),</span><br><span style="color: hsl(120, 100%, 40%);">+ Domino('moo', 'foo'),</span><br><span style="color: hsl(120, 100%, 40%);">+ Domino('axe', 'bin'),</span><br><span style="color: hsl(120, 100%, 40%);">+ Domino('axe', 'dog'),</span><br><span style="color: hsl(120, 100%, 40%);">+ ]</span><br><span style="color: hsl(120, 100%, 40%);">+     groups = Dominoes.arrange(d)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        for g in groups:</span><br><span style="color: hsl(120, 100%, 40%);">+              print(str(g))</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+if __name__ == '__main__':</span><br><span style="color: hsl(120, 100%, 40%);">+   opts = parse_args()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ r = Results()</span><br><span style="color: hsl(120, 100%, 40%);">+ r.process_file(opts.pcap_file)</span><br><span style="color: hsl(120, 100%, 40%);">+        print(r.summary())</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/13610">change 13610</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/13610"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: Ia3cdefe16b9e929d2836ca837db6f6107f7ed9eb </div>
<div style="display:none"> Gerrit-Change-Number: 13610 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>