From 68ded67067372a69e2febb549ab07e6ee5bd5a0b Mon Sep 17 00:00:00 2001 From: Maksym Sobolyev Date: Mon, 5 Aug 2024 12:09:11 -0700 Subject: [PATCH] Extend routing specification to allow inserting arbitrary pre-call-originate ("po_proc") routine to do various conditioning, such is in this case appending arbitrary attributes into accounting request. 3 such functions are provided: - VAL2Xattrs: append to both originate and answering accounting requests; - VAL2XattrsO: append to originate request only; - VAL2XattrsA: append to answering request only. PR: #38 --- sippy/B2BRoute.py | 3 +++ sippy/B2BTransforms.py | 27 ++++++++++++++++++++++++++- sippy/RadiusAccounting.py | 4 ++++ sippy/b2bua_radius.py | 3 +++ tests/test_B2BTransforms.py | 3 +++ 5 files changed, 39 insertions(+), 1 deletion(-) diff --git a/sippy/B2BRoute.py b/sippy/B2BRoute.py index 6d22221..9bcb1e9 100644 --- a/sippy/B2BRoute.py +++ b/sippy/B2BRoute.py @@ -26,6 +26,7 @@ from sippy.SipHeader import SipHeader from sippy.SipConf import SipConf +from sippy.B2BTransforms import getTransProc try: from urllib import unquote @@ -163,6 +164,8 @@ def __init__(self, sroute = None, cself = None): self.params['outbound_proxy'] = (v, 5060) else: self.params['outbound_proxy'] = (host_port[0], int(host_port[1])) + elif a == 'po_proc': + self.params['po_proc'] = getTransProc(v) else: self.params[a] = v if len(extra_headers) > 0: diff --git a/sippy/B2BTransforms.py b/sippy/B2BTransforms.py index 35c18d7..a9e4609 100644 --- a/sippy/B2BTransforms.py +++ b/sippy/B2BTransforms.py @@ -26,6 +26,7 @@ import sys from sippy.SipRequest import SipRequest +from sippy.CCEvents import CCEventTry class HDR2Xattrs(): # Source: https://github.com/sippy/b2bua/pull/38 @@ -55,10 +56,34 @@ def __call__(self, cc:'CallController', req:SipRequest): else: cc.extra_attributes.extend(extra_attributes) +class VAL2Xattrs(): + # Source: https://github.com/sippy/b2bua/pull/39 + # Author: @twmobius + doO: bool = True + doA: bool = True + radius_parameters: list + def __init__(self, v:str): + radius_parameters = [] + pairs = v.split(';') + for pair in pairs: + [key, _, value] = pair.partition("=") + if value == '': continue + radius_parameters.append((key, value)) + self.radius_parameters = radius_parameters + + def __call__(self, cc:'CallController', _:CCEventTry): + if self.doO and cc.acctO is not None: + cc.acctO.addAttributes(self.radius_parameters) + if self.doA and cc.acctA is not None: + cc.acctA.addAttributes(self.radius_parameters) + class Nop(): def __init__(self, v:str): pass def __call__(self, *a, **kwa): pass +class VAL2XattrsA(VAL2Xattrs): doO = False +class VAL2XattrsO(VAL2Xattrs): doA = False + def getTransProc(value:str): rparts = value.split('[', 1) if not len(rparts) == 2 or not value.endswith(']'): @@ -70,5 +95,5 @@ def getTransProc(value:str): return fclass(farg) if __name__ == '__main__': - for t in ('HDR2Xattrs[X-foo-hdr]',): + for t in ('HDR2Xattrs[X-foo-hdr]', 'VAL2Xattrs[foo=bar;baz=xxx]', 'VAL2XattrsA[foo=bar;baz=xxx]', 'VAL2XattrsO[foo=bar;baz=xxx]'): p = getTransProc(t) diff --git a/sippy/RadiusAccounting.py b/sippy/RadiusAccounting.py index 38df498..e3a910c 100644 --- a/sippy/RadiusAccounting.py +++ b/sippy/RadiusAccounting.py @@ -188,3 +188,7 @@ def _process_result(self, results, sip_cid, btime): else: message = 'Error sending Acct/%s request (delay is %.3f)\n' % (self.origin, delay) self.global_config['_sip_logger'].write(message, call_id = sip_cid) + + def addAttributes(self, attributes): + self._attributes.extend(tuple(x) for x in attributes \ + if tuple(x) not in self._attributes) diff --git a/sippy/b2bua_radius.py b/sippy/b2bua_radius.py index 2314ae2..8b52125 100755 --- a/sippy/b2bua_radius.py +++ b/sippy/b2bua_radius.py @@ -374,6 +374,9 @@ def placeOriginate(self, oroute): self.state = CCStateDead return event.reason = self.eTry.reason + po_proc = oroute.params.get('po_proc', None) + if po_proc is not None: + po_proc(self, event) self.uaO.recvEvent(event) def disconnect(self, rtime = None): diff --git a/tests/test_B2BTransforms.py b/tests/test_B2BTransforms.py index a90b0e2..edac7a0 100644 --- a/tests/test_B2BTransforms.py +++ b/tests/test_B2BTransforms.py @@ -19,6 +19,9 @@ class TestB2BTransforms(unittest.TestCase): def test_getTransProc(self): transformations = [ ('HDR2Xattrs[X-foo-hdr]', (FakeCC(), FakeRequest(self))), + ('VAL2Xattrs[foo=bar;baz=xxx]', (FakeCC(), FakeEvent())), + ('VAL2XattrsA[foo=bar;baz=xxx]', (FakeCC(), FakeEvent())), + ('VAL2XattrsO[foo=bar;baz=xxx]', (FakeCC(), FakeEvent())), ('Nop[]', (None, None)), ]