<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>