sippy 2.2.1__tar.gz → 2.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sippy-2.2.2/MANIFEST.in +4 -0
- {sippy-2.2.1/sippy.egg-info → sippy-2.2.2}/PKG-INFO +1 -1
- {sippy-2.2.1 → sippy-2.2.2}/setup.py +2 -4
- sippy-2.2.1/sippy/B2BRoute.py → sippy-2.2.2/sippy/B2B/Route.py +1 -1
- sippy-2.2.2/sippy/B2B/SimpleAPI.py +142 -0
- sippy-2.2.2/sippy/B2B/States.py +36 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/CLIManager.py +7 -4
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Core/EventDispatcher.py +32 -5
- {sippy-2.2.1 → sippy-2.2.2}/sippy/MsgBody.py +1 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/MultipartMixBody.py +20 -5
- {sippy-2.2.1 → sippy-2.2.2}/sippy/MyConfigParser.py +1 -1
- sippy-2.2.1/sippy/Rtp_proxy/Client/stream.py → sippy-2.2.2/sippy/Rtp_proxy/Client/Worker/external.py +6 -98
- sippy-2.2.2/sippy/Rtp_proxy/Client/Worker/internal.py +95 -0
- sippy-2.2.2/sippy/Rtp_proxy/Client/internal.py +67 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/Client/local.py +4 -16
- sippy-2.2.2/sippy/Rtp_proxy/Client/stream.py +103 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/Client/udp.py +9 -19
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/Session/side.py +5 -5
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/Session/update.py +1 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/client.py +102 -68
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/session.py +27 -23
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipContentType.py +2 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipTransactionManager.py +20 -4
- sippy-2.2.2/sippy/Time/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UA.py +16 -6
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UaStateDead.py +3 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/b2bua.py +45 -129
- {sippy-2.2.1 → sippy-2.2.2/sippy.egg-info}/PKG-INFO +1 -1
- {sippy-2.2.1 → sippy-2.2.2}/sippy.egg-info/SOURCES.txt +9 -2
- sippy-2.2.2/tests/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/tests/test_B2BRoute.py +1 -1
- {sippy-2.2.1 → sippy-2.2.2}/tests/test_B2BTransforms.py +1 -1
- sippy-2.2.1/MANIFEST.in +0 -1
- {sippy-2.2.1 → sippy-2.2.2}/LICENSE +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/README.md +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/pyproject.toml +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/requirements.txt +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/setup.cfg +0 -0
- /sippy-2.2.1/sippy/B2BTransforms.py → /sippy-2.2.2/sippy/B2B/Transforms.py +0 -0
- {sippy-2.2.1/sippy/Core → sippy-2.2.2/sippy/B2B}/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/CCEvents.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Core/Exceptions.py +0 -0
- {sippy-2.2.1/sippy/Exceptions → sippy-2.2.2/sippy/Core}/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/ESipHeaderCSV.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/ESipHeaderIgnore.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Exceptions/RtpProxyError.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Exceptions/SdpParseError.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Exceptions/SipHandlingError.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Exceptions/SipParseError.py +0 -0
- {sippy-2.2.1/sippy/Math → sippy-2.2.2/sippy/Exceptions}/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/External_command.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/FakeAccounting.py +0 -0
- {sippy-2.2.1/sippy/Security → sippy-2.2.2/sippy/Math}/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Math/recfilter.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Network_server.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/RadiusAccounting.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/RadiusAuthorisation.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Radius_client.py +0 -0
- {sippy-2.2.1/sippy/Time → sippy-2.2.2/sippy/Rtp_proxy/Client/Worker}/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/Client/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/Client/net.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/Cmd/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/Cmd/sequencer.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/Session/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/Session/subcommand.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/Session/subcommand_ice.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/Session/webrtc.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Rtp_proxy/cmd.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SdpBody.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SdpConnecton.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SdpGeneric.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SdpMedia.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SdpMediaDescription.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SdpOrigin.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Security/SipNonce.py +0 -0
- {sippy-2.2.1/tests → sippy-2.2.2/sippy/Security}/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Signal.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipAddress.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipAddressHF.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipAllow.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipAlso.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipAuthorization.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipCCDiversion.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipCSeq.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipCallId.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipCiscoGUID.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipConf.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipContact.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipContentLength.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipDiversion.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipExpires.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipFrom.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipGenericHF.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipHeader.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipLogger.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipMaxForwards.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipMsg.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipNumericHF.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipPAssertedIdentity.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipPath.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipProxyAuthenticate.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipProxyAuthorization.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipRAck.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipRSeq.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipReason.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipRecordRoute.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipReferTo.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipReferredBy.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipRegistrationAgent.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipReplaces.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipRequest.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipResponse.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipRoute.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipServer.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipSupported.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipTo.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipURL.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipUserAgent.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipVia.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipWWWAuthenticate.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/SipWarning.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/StatefulProxy.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Time/MonoTime.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Time/Timeout.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Time/clock_dtime.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UaStateConnected.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UaStateDisconnected.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UaStateFailed.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UaStateGeneric.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UacStateCancelling.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UacStateIdle.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UacStateRinging.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UacStateTrying.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UacStateUpdating.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UasStateIdle.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UasStateRinging.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UasStateTrying.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/UasStateUpdating.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Udp_server.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/Wss_server.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/XMPP_server.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/__init__.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/b2bua_simple.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/dictionary +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy/misc.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy.egg-info/dependency_links.txt +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy.egg-info/entry_points.txt +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy.egg-info/requires.txt +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/sippy.egg-info/top_level.txt +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/tests/test_Multipart.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/tests/test_SdbBody.py +0 -0
- {sippy-2.2.1 → sippy-2.2.2}/tests/test_Udp_server.py +0 -0
sippy-2.2.2/MANIFEST.in
ADDED
|
@@ -8,13 +8,11 @@ with open("README.md", "r") as fh:
|
|
|
8
8
|
|
|
9
9
|
setup(
|
|
10
10
|
name = "sippy",
|
|
11
|
-
version = "2.2.
|
|
11
|
+
version = "2.2.2",
|
|
12
12
|
packages = find_packages(),
|
|
13
13
|
|
|
14
14
|
install_requires = requirements,
|
|
15
|
-
|
|
16
|
-
'': ['dictionary', '*.md']
|
|
17
|
-
},
|
|
15
|
+
include_package_data=True,
|
|
18
16
|
test_suite = 'tests',
|
|
19
17
|
|
|
20
18
|
entry_points = {
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
|
|
2
|
+
# Copyright (c) 2006-2025 Sippy Software, Inc. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
|
5
|
+
# are permitted provided that the following conditions are met:
|
|
6
|
+
#
|
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
# list of conditions and the following disclaimer.
|
|
9
|
+
#
|
|
10
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
# this list of conditions and the following disclaimer in the documentation and/or
|
|
12
|
+
# other materials provided with the distribution.
|
|
13
|
+
#
|
|
14
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
15
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
16
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
17
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
18
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
19
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
20
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
21
|
+
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
22
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
23
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
24
|
+
|
|
25
|
+
from ..CLIManager import CLIConnectionManager, CLIManager
|
|
26
|
+
from ..Time.MonoTime import MonoTime
|
|
27
|
+
from .States import CCStateConnected, CCStateARComplete
|
|
28
|
+
|
|
29
|
+
class B2BSimpleAPI(CLIConnectionManager):
|
|
30
|
+
global_config = None
|
|
31
|
+
|
|
32
|
+
def __init__(self, global_config):
|
|
33
|
+
cmdfile = global_config['b2bua_socket']
|
|
34
|
+
self.global_config = global_config
|
|
35
|
+
if cmdfile.startswith('tcp:'):
|
|
36
|
+
parts = cmdfile[4:].split(':', 1)
|
|
37
|
+
if len(parts) == 1:
|
|
38
|
+
address = (parts[0], 12345)
|
|
39
|
+
else:
|
|
40
|
+
address = (parts[0], int(parts[1]))
|
|
41
|
+
super().__init__(self.recvCommand, address, tcp = True)
|
|
42
|
+
else:
|
|
43
|
+
if cmdfile.startswith('unix:'):
|
|
44
|
+
cmdfile = cmdfile[5:]
|
|
45
|
+
super().__init__(self.recvCommand, cmdfile)
|
|
46
|
+
|
|
47
|
+
def recvCommand(self, clim, cmd):
|
|
48
|
+
ccm = self.global_config['_cmap']
|
|
49
|
+
args = cmd.split()
|
|
50
|
+
cmd = args.pop(0).lower()
|
|
51
|
+
if cmd == 'q':
|
|
52
|
+
clim.close()
|
|
53
|
+
return False
|
|
54
|
+
if cmd == 'l':
|
|
55
|
+
res = 'In-memory calls:\n'
|
|
56
|
+
total = 0
|
|
57
|
+
for (cid, sname), uaast, uaost in ccm.listActiveCalls():
|
|
58
|
+
res += f'{cid}: {sname} ('
|
|
59
|
+
if uaast is not None:
|
|
60
|
+
_s, _t, _h, _p, _cld, _cli = uaast
|
|
61
|
+
res += f'{_s} {_t}:{_h}:{_p} {_cld} {_cli} -> '
|
|
62
|
+
else:
|
|
63
|
+
res += 'N/A -> '
|
|
64
|
+
if uaost is not None:
|
|
65
|
+
_s, _t, _h, _p, _cld, _cli = uaost
|
|
66
|
+
res += f'{_s} {_t}:{_h}:{_p} {_cld} {_cli})\n'
|
|
67
|
+
else:
|
|
68
|
+
res += 'N/A)\n'
|
|
69
|
+
total += 1
|
|
70
|
+
res += 'Total: %d\n' % total
|
|
71
|
+
clim.send(res)
|
|
72
|
+
return False
|
|
73
|
+
if cmd == 'lt':
|
|
74
|
+
res = 'In-memory server transactions:\n'
|
|
75
|
+
for tid, t in self.global_config['_sip_tm'].tserver.iteritems():
|
|
76
|
+
res += '%s %s %s\n' % (tid, t.method, t.state)
|
|
77
|
+
res += 'In-memory client transactions:\n'
|
|
78
|
+
for tid, t in self.global_config['_sip_tm'].tclient.iteritems():
|
|
79
|
+
res += '%s %s %s\n' % (tid, t.method, t.state)
|
|
80
|
+
clim.send(res)
|
|
81
|
+
return False
|
|
82
|
+
if cmd in ('lt', 'llt'):
|
|
83
|
+
if cmd == 'llt':
|
|
84
|
+
mindur = 60.0
|
|
85
|
+
else:
|
|
86
|
+
mindur = 0.0
|
|
87
|
+
ctime = MonoTime()
|
|
88
|
+
res = 'In-memory server transactions:\n'
|
|
89
|
+
for tid, t in self.global_config['_sip_tm'].tserver.iteritems():
|
|
90
|
+
duration = ctime - t.rtime
|
|
91
|
+
if duration < mindur:
|
|
92
|
+
continue
|
|
93
|
+
res += '%s %s %s %s\n' % (tid, t.method, t.state, duration)
|
|
94
|
+
res += 'In-memory client transactions:\n'
|
|
95
|
+
for tid, t in self.global_config['_sip_tm'].tclient.iteritems():
|
|
96
|
+
duration = ctime - t.rtime
|
|
97
|
+
if duration < mindur:
|
|
98
|
+
continue
|
|
99
|
+
res += '%s %s %s %s\n' % (tid, t.method, t.state, duration)
|
|
100
|
+
clim.send(res)
|
|
101
|
+
return False
|
|
102
|
+
if cmd == 'd':
|
|
103
|
+
if len(args) != 1:
|
|
104
|
+
clim.send('ERROR: syntax error: d <call-id>\n')
|
|
105
|
+
return False
|
|
106
|
+
if args[0] == '*':
|
|
107
|
+
self.discAll()
|
|
108
|
+
clim.send('OK\n')
|
|
109
|
+
return False
|
|
110
|
+
dlist = [x for x in ccm.ccmap if str(x.cId) == args[0]]
|
|
111
|
+
if len(dlist) == 0:
|
|
112
|
+
clim.send('ERROR: no call with id of %s has been found\n' % args[0])
|
|
113
|
+
return False
|
|
114
|
+
for cc in dlist:
|
|
115
|
+
cc.disconnect()
|
|
116
|
+
clim.send('OK\n')
|
|
117
|
+
return False
|
|
118
|
+
if cmd == 'r':
|
|
119
|
+
if len(args) != 1:
|
|
120
|
+
clim.send('ERROR: syntax error: r [<id>]\n')
|
|
121
|
+
return False
|
|
122
|
+
idx = int(args[0])
|
|
123
|
+
dlist = [x for x in ccm.ccmap if x.id == idx]
|
|
124
|
+
if len(dlist) == 0:
|
|
125
|
+
clim.send('ERROR: no call with id of %d has been found\n' % idx)
|
|
126
|
+
return False
|
|
127
|
+
for cc in dlist:
|
|
128
|
+
if not cc.proxied:
|
|
129
|
+
continue
|
|
130
|
+
if cc.state == CCStateConnected:
|
|
131
|
+
cc.disconnect(MonoTime().getOffsetCopy(-60), origin = 'media_timeout')
|
|
132
|
+
continue
|
|
133
|
+
if cc.state == CCStateARComplete:
|
|
134
|
+
cc.uaO.disconnect(MonoTime().getOffsetCopy(-60), origin = 'media_timeout')
|
|
135
|
+
continue
|
|
136
|
+
clim.send('OK\n')
|
|
137
|
+
return False
|
|
138
|
+
clim.send('ERROR: unknown command\n')
|
|
139
|
+
return False
|
|
140
|
+
|
|
141
|
+
def set_rtp_io_socket(self, rtpp_nsock, rtpp_nsock_spec):
|
|
142
|
+
CLIManager(rtpp_nsock, self.recvCommand)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
|
|
2
|
+
# Copyright (c) 2006-2025 Sippy Software, Inc. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
|
5
|
+
# are permitted provided that the following conditions are met:
|
|
6
|
+
#
|
|
7
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
8
|
+
# list of conditions and the following disclaimer.
|
|
9
|
+
#
|
|
10
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
11
|
+
# this list of conditions and the following disclaimer in the documentation and/or
|
|
12
|
+
# other materials provided with the distribution.
|
|
13
|
+
#
|
|
14
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
15
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
16
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
17
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
18
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
19
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
20
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
21
|
+
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
22
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
23
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
24
|
+
|
|
25
|
+
class CCStateIdle(object):
|
|
26
|
+
sname = 'Idle'
|
|
27
|
+
class CCStateWaitRoute(object):
|
|
28
|
+
sname = 'WaitRoute'
|
|
29
|
+
class CCStateARComplete(object):
|
|
30
|
+
sname = 'ARComplete'
|
|
31
|
+
class CCStateConnected(object):
|
|
32
|
+
sname = 'Connected'
|
|
33
|
+
class CCStateDead(object):
|
|
34
|
+
sname = 'Dead'
|
|
35
|
+
class CCStateDisconnecting(object):
|
|
36
|
+
sname = 'Disconnecting'
|
|
@@ -125,7 +125,7 @@ class CLIConnectionManager(object):
|
|
|
125
125
|
conn.close()
|
|
126
126
|
return
|
|
127
127
|
try:
|
|
128
|
-
cm = CLIManager(conn, self.command_cb
|
|
128
|
+
cm = CLIManager(conn, self.command_cb)
|
|
129
129
|
except Exception as e:
|
|
130
130
|
dump_exception('CLIConnectionManager: unhandled exception when setting up incoming connection handler')
|
|
131
131
|
conn.close()
|
|
@@ -174,6 +174,11 @@ class _CLIManager_w(Thread):
|
|
|
174
174
|
except BrokenPipeError:
|
|
175
175
|
self.clim = None
|
|
176
176
|
return
|
|
177
|
+
except socket.error as why:
|
|
178
|
+
if why.errno != EBADF:
|
|
179
|
+
raise
|
|
180
|
+
self.clim = None
|
|
181
|
+
return
|
|
177
182
|
if res == len(wbuffer):
|
|
178
183
|
break
|
|
179
184
|
if res > 0:
|
|
@@ -239,14 +244,12 @@ class CLIManager(object):
|
|
|
239
244
|
clientsock = None
|
|
240
245
|
command_cb = None
|
|
241
246
|
close_pendind = False
|
|
242
|
-
raddr = None
|
|
243
247
|
wthr = None
|
|
244
248
|
rthr = None
|
|
245
249
|
|
|
246
|
-
def __init__(self, clientsock, command_cb
|
|
250
|
+
def __init__(self, clientsock, command_cb):
|
|
247
251
|
self.clientsock = clientsock
|
|
248
252
|
self.command_cb = command_cb
|
|
249
|
-
self.raddr = raddr
|
|
250
253
|
self.wthr = _CLIManager_w(clientsock, self)
|
|
251
254
|
self.rthr = _CLIManager_r(clientsock, self)
|
|
252
255
|
|
|
@@ -29,12 +29,13 @@ from __future__ import print_function
|
|
|
29
29
|
from functools import partial
|
|
30
30
|
from datetime import datetime
|
|
31
31
|
from heapq import heappush, heappop, heapify
|
|
32
|
-
from threading import Lock
|
|
32
|
+
from threading import Lock, local as t_local
|
|
33
33
|
from random import random
|
|
34
34
|
import sys, traceback, signal
|
|
35
35
|
from _thread import get_ident
|
|
36
36
|
from sippy.Time.MonoTime import MonoTime
|
|
37
37
|
from sippy.Core.Exceptions import dump_exception, StdException
|
|
38
|
+
from queue import Queue
|
|
38
39
|
|
|
39
40
|
from elperiodic.ElPeriodic import ElPeriodic
|
|
40
41
|
|
|
@@ -123,6 +124,8 @@ class EventDispatcher2(Singleton):
|
|
|
123
124
|
ed_inum = 0
|
|
124
125
|
elp = None
|
|
125
126
|
bands = None
|
|
127
|
+
_exception = None
|
|
128
|
+
tloc_data = None
|
|
126
129
|
|
|
127
130
|
def __init__(self, freq = 100.0):
|
|
128
131
|
EventDispatcher2.state_lock.acquire()
|
|
@@ -140,6 +143,7 @@ class EventDispatcher2(Singleton):
|
|
|
140
143
|
self.elp = ElPeriodic(freq)
|
|
141
144
|
self.elp.CFT_enable(signal.SIGURG)
|
|
142
145
|
self.bands = [(freq, 0),]
|
|
146
|
+
self.tloc_data = t_local()
|
|
143
147
|
|
|
144
148
|
def signal(self, signum, frame):
|
|
145
149
|
self.signals_pending.append(signum)
|
|
@@ -233,16 +237,35 @@ class EventDispatcher2(Singleton):
|
|
|
233
237
|
def dispatchThreadCallback(self, thread_cb, cb_params):
|
|
234
238
|
try:
|
|
235
239
|
thread_cb(*cb_params)
|
|
236
|
-
except
|
|
237
|
-
if isinstance(ex, SystemExit):
|
|
238
|
-
|
|
240
|
+
except BaseException as ex:
|
|
241
|
+
if isinstance(ex, (SystemExit, KeyboardInterrupt)):
|
|
242
|
+
self._exception = ex
|
|
243
|
+
return
|
|
239
244
|
dump_exception('EventDispatcher2: unhandled exception when processing from-thread-call')
|
|
240
|
-
|
|
245
|
+
|
|
246
|
+
def dispatchThreadCallbackSync(self, res_cb_q, thread_cb, cb_params):
|
|
247
|
+
try:
|
|
248
|
+
res = thread_cb(*cb_params)
|
|
249
|
+
except BaseException as ex:
|
|
250
|
+
rval = (None, ex)
|
|
251
|
+
else:
|
|
252
|
+
rval = (res, None)
|
|
253
|
+
res_cb_q.put(rval)
|
|
241
254
|
|
|
242
255
|
def callFromThread(self, thread_cb, *cb_params):
|
|
243
256
|
self.elp.call_from_thread(self.dispatchThreadCallback, thread_cb, cb_params)
|
|
244
257
|
#print('EventDispatcher2.callFromThread completed', str(self), thread_cb, cb_params)
|
|
245
258
|
|
|
259
|
+
def callFromThreadSync(self, thread_cb, *cb_params):
|
|
260
|
+
if not hasattr(self.tloc_data, 'res_cb_q'):
|
|
261
|
+
self.tloc_data.res_cb_q = Queue()
|
|
262
|
+
res_cb_q = self.tloc_data.res_cb_q
|
|
263
|
+
self.elp.call_from_thread(self.dispatchThreadCallbackSync, res_cb_q, thread_cb, cb_params)
|
|
264
|
+
res, ex = res_cb_q.get()
|
|
265
|
+
if ex is not None:
|
|
266
|
+
raise ex
|
|
267
|
+
return res
|
|
268
|
+
|
|
246
269
|
def loop(self, timeout = None, freq = None):
|
|
247
270
|
if freq != None and self.bands[0][0] != freq:
|
|
248
271
|
for fb in self.bands:
|
|
@@ -274,6 +297,10 @@ class EventDispatcher2(Singleton):
|
|
|
274
297
|
break
|
|
275
298
|
self.elp.procrastinate()
|
|
276
299
|
self.last_ts = MonoTime()
|
|
300
|
+
if self._exception is not None:
|
|
301
|
+
ex = self._exception
|
|
302
|
+
self._exception = None
|
|
303
|
+
raise ex
|
|
277
304
|
return self.el_rval
|
|
278
305
|
|
|
279
306
|
def breakLoop(self, rval=0):
|
|
@@ -23,14 +23,22 @@
|
|
|
23
23
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
24
24
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
25
25
|
|
|
26
|
+
from secrets import token_hex
|
|
27
|
+
|
|
26
28
|
from sippy.SipHeader import SipHeader
|
|
29
|
+
from sippy.SipContentType import SipContentType
|
|
27
30
|
|
|
28
31
|
class MultipartMixBody():
|
|
29
32
|
parts = None
|
|
30
33
|
boundary = None
|
|
34
|
+
mtype = SipContentType('multipart/mixed')
|
|
35
|
+
mtype.parse()
|
|
31
36
|
|
|
32
37
|
def __init__(self, body = None, ctype = None):
|
|
38
|
+
self.parts = []
|
|
39
|
+
self.part_headers = []
|
|
33
40
|
if body is None:
|
|
41
|
+
self.setBoundary(token_hex(16))
|
|
34
42
|
return
|
|
35
43
|
sep = f'--{ctype.params["boundary"]}'
|
|
36
44
|
bparts = body.split(sep)
|
|
@@ -38,8 +46,6 @@ class MultipartMixBody():
|
|
|
38
46
|
assert len(bparts[0]) == 0
|
|
39
47
|
assert bparts[-1].strip() == '--'
|
|
40
48
|
parts = [p.lstrip() for p in bparts[1:-1]]
|
|
41
|
-
self.parts = []
|
|
42
|
-
self.part_headers = []
|
|
43
49
|
for sect in parts:
|
|
44
50
|
headers = []
|
|
45
51
|
ct = None
|
|
@@ -55,18 +61,24 @@ class MultipartMixBody():
|
|
|
55
61
|
sect = MsgBody(sect, ct)
|
|
56
62
|
self.parts.append(sect)
|
|
57
63
|
self.part_headers.append(headers)
|
|
58
|
-
self.
|
|
64
|
+
self.setBoundary(ctype.params["boundary"])
|
|
65
|
+
|
|
66
|
+
def setBoundary(self, bnd):
|
|
67
|
+
self.boundary = bnd
|
|
68
|
+
mtype = self.mtype.getCopy()
|
|
69
|
+
mtype.params["boundary"] = bnd
|
|
70
|
+
self.mtype = mtype
|
|
59
71
|
|
|
60
72
|
def __str__(self):
|
|
61
73
|
bnd = f'--{self.boundary}\r\n'
|
|
62
|
-
parts = [f'{bnd}Content-Type: {p.mtype}\r\n{p}' for p in self.parts]
|
|
74
|
+
parts = [f'{bnd}Content-Type: {p.mtype}\r\n\r\n{p}' for p in self.parts]
|
|
63
75
|
s = ''.join(parts)
|
|
64
76
|
s += f'{bnd[:-2]}--\r\n'
|
|
65
77
|
return s
|
|
66
78
|
|
|
67
79
|
def localStr(self, local_addr = None):
|
|
68
80
|
bnd = f'--{self.boundary}\r\n'
|
|
69
|
-
parts = [f'{bnd}Content-Type: {p.mtype}\r\n{p.localStr(local_addr)}'
|
|
81
|
+
parts = [f'{bnd}Content-Type: {p.mtype}\r\n\r\n{p.localStr(local_addr)}'
|
|
70
82
|
for p in self.parts]
|
|
71
83
|
s = ''.join(parts)
|
|
72
84
|
s += f'{bnd[:-2]}--\r\n'
|
|
@@ -78,5 +90,8 @@ class MultipartMixBody():
|
|
|
78
90
|
cself.boundary = self.boundary
|
|
79
91
|
return cself
|
|
80
92
|
|
|
93
|
+
def getContentType(self):
|
|
94
|
+
return self.mtype.getCopy()
|
|
95
|
+
|
|
81
96
|
if 'MsgBody' not in globals():
|
|
82
97
|
from sippy.MsgBody import MsgBody
|
|
@@ -33,7 +33,7 @@ except ImportError:
|
|
|
33
33
|
from configparser import RawConfigParser
|
|
34
34
|
_boolean_states = RawConfigParser.BOOLEAN_STATES
|
|
35
35
|
from sippy.SipConf import SipConf
|
|
36
|
-
from sippy.
|
|
36
|
+
from sippy.B2B.Transforms import getTransProc
|
|
37
37
|
|
|
38
38
|
SUPPORTED_OPTIONS = { \
|
|
39
39
|
'acct_enable': ('B', 'enable or disable Radius accounting'), \
|
sippy-2.2.1/sippy/Rtp_proxy/Client/stream.py → sippy-2.2.2/sippy/Rtp_proxy/Client/Worker/external.py
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
|
|
2
|
-
# Copyright (c) 2006-
|
|
2
|
+
# Copyright (c) 2006-2025 Sippy Software, Inc. All rights reserved.
|
|
3
3
|
#
|
|
4
4
|
# All rights reserved.
|
|
5
5
|
#
|
|
@@ -24,24 +24,17 @@
|
|
|
24
24
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
25
25
|
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
26
26
|
|
|
27
|
-
from queue import Queue
|
|
28
|
-
|
|
29
|
-
from sippy.Time.Timeout import Timeout
|
|
30
27
|
from threading import Thread
|
|
31
28
|
from errno import EINTR, EPIPE, ENOTCONN, ECONNRESET
|
|
32
|
-
from sippy.Time.MonoTime import MonoTime
|
|
33
|
-
from sippy.Math.recfilter import recfilter
|
|
34
|
-
from sippy.Rtp_proxy.Client.net import Rtp_proxy_client_net
|
|
35
|
-
from sippy.Rtp_proxy.cmd import Rtp_proxy_cmd
|
|
36
|
-
|
|
37
29
|
import socket
|
|
38
30
|
|
|
31
|
+
from sippy.Time.MonoTime import MonoTime
|
|
39
32
|
from sippy.Core.Exceptions import dump_exception
|
|
40
33
|
from sippy.Core.EventDispatcher import ED2
|
|
41
34
|
|
|
42
35
|
_MAX_RECURSE = 10
|
|
43
36
|
|
|
44
|
-
class
|
|
37
|
+
class RTPPLWorker_external(Thread):
|
|
45
38
|
daemon = True
|
|
46
39
|
userv = None
|
|
47
40
|
s = None
|
|
@@ -84,7 +77,7 @@ class _RTPPLWorker(Thread):
|
|
|
84
77
|
rval = self.s.recv(1024)
|
|
85
78
|
if len(rval) == 0:
|
|
86
79
|
self.s = None
|
|
87
|
-
return self.send_raw(command, _recurse, stime
|
|
80
|
+
return self.send_raw(command, _recurse, stime)
|
|
88
81
|
rval = rval.decode('ascii').strip()
|
|
89
82
|
break
|
|
90
83
|
except socket.error as why:
|
|
@@ -113,7 +106,7 @@ class _RTPPLWorker(Thread):
|
|
|
113
106
|
if len(data) == 0:
|
|
114
107
|
data, rtpc_delay = None, None
|
|
115
108
|
except Exception as e:
|
|
116
|
-
dump_exception('
|
|
109
|
+
dump_exception('RTPPLWorker_external: unhandled exception I/O RTPproxy')
|
|
117
110
|
data, rtpc_delay = None, None
|
|
118
111
|
if result_callback != None:
|
|
119
112
|
ED2.callFromThread(self.dispatch, result_callback, data, callback_parameters)
|
|
@@ -125,89 +118,4 @@ class _RTPPLWorker(Thread):
|
|
|
125
118
|
try:
|
|
126
119
|
result_callback(data, *callback_parameters)
|
|
127
120
|
except:
|
|
128
|
-
dump_exception('
|
|
129
|
-
|
|
130
|
-
class Rtp_proxy_client_stream(Rtp_proxy_client_net):
|
|
131
|
-
is_local = None
|
|
132
|
-
wi = None
|
|
133
|
-
nworkers = None
|
|
134
|
-
nworkers_act = None
|
|
135
|
-
workers = None
|
|
136
|
-
delay_flt = None
|
|
137
|
-
family = None
|
|
138
|
-
sock_type = socket.SOCK_STREAM
|
|
139
|
-
|
|
140
|
-
def __init__(self, global_config, address = '/var/run/rtpproxy.sock', \
|
|
141
|
-
bind_address = None, nworkers = 1, family = socket.AF_UNIX):
|
|
142
|
-
#print('Rtp_proxy_client_stream.__init__', address, bind_address, nworkers, family)
|
|
143
|
-
if family == socket.AF_UNIX:
|
|
144
|
-
self.is_local = True
|
|
145
|
-
self.address = address
|
|
146
|
-
else:
|
|
147
|
-
self.is_local = False
|
|
148
|
-
self.address = self.getdestbyaddr(address, family)
|
|
149
|
-
self.family = family
|
|
150
|
-
self.wi = Queue()
|
|
151
|
-
self.nworkers = nworkers
|
|
152
|
-
self.workers = []
|
|
153
|
-
for i in range(0, self.nworkers):
|
|
154
|
-
try:
|
|
155
|
-
self.workers.append(_RTPPLWorker(self))
|
|
156
|
-
except:
|
|
157
|
-
break
|
|
158
|
-
self.nworkers_act = i + 1
|
|
159
|
-
self.delay_flt = recfilter(0.95, 0.25)
|
|
160
|
-
|
|
161
|
-
def send_command(self, command, result_callback = None, *callback_parameters):
|
|
162
|
-
if self.nworkers_act == 0:
|
|
163
|
-
self.rtpp_class._reconnect(self, self.address)
|
|
164
|
-
if isinstance(command, Rtp_proxy_cmd):
|
|
165
|
-
command = str(command)
|
|
166
|
-
elif not command.endswith('\n'):
|
|
167
|
-
command += '\n'
|
|
168
|
-
self.wi.put((command, result_callback, callback_parameters))
|
|
169
|
-
|
|
170
|
-
def reconnect(self, address, bind_address = None):
|
|
171
|
-
if not self.is_local:
|
|
172
|
-
address = self.getdestbyaddr(address, self.family)
|
|
173
|
-
self.rtpp_class._reconnect(self, address, bind_address)
|
|
174
|
-
|
|
175
|
-
def _reconnect(self, address, bind_address = None):
|
|
176
|
-
Rtp_proxy_client_stream.shutdown(self)
|
|
177
|
-
self.address = address
|
|
178
|
-
self.workers = []
|
|
179
|
-
for i in range(0, self.nworkers):
|
|
180
|
-
try:
|
|
181
|
-
self.workers.append(_RTPPLWorker(self))
|
|
182
|
-
except:
|
|
183
|
-
break
|
|
184
|
-
self.nworkers_act = i + 1
|
|
185
|
-
self.delay_flt = recfilter(0.95, 0.25)
|
|
186
|
-
|
|
187
|
-
def shutdown(self):
|
|
188
|
-
self.wi.put(None)
|
|
189
|
-
for rworker in self.workers:
|
|
190
|
-
rworker.join()
|
|
191
|
-
self.workers = None
|
|
192
|
-
|
|
193
|
-
def register_delay(self, rtpc_delay):
|
|
194
|
-
self.delay_flt.apply(rtpc_delay)
|
|
195
|
-
|
|
196
|
-
def get_rtpc_delay(self):
|
|
197
|
-
return self.delay_flt.lastval
|
|
198
|
-
|
|
199
|
-
if __name__ == '__main__':
|
|
200
|
-
class robj(object):
|
|
201
|
-
rval = None
|
|
202
|
-
r = robj()
|
|
203
|
-
def display(res, ro, arg):
|
|
204
|
-
print(res, arg)
|
|
205
|
-
ro.rval = (res, arg)
|
|
206
|
-
ED2.breakLoop()
|
|
207
|
-
r = Rtp_proxy_client_stream({'_sip_address':'1.2.3.4'})
|
|
208
|
-
r.send_command('VF 123456', display, r, 'abcd')
|
|
209
|
-
ED2.loop()
|
|
210
|
-
r.shutdown()
|
|
211
|
-
print(r.rval)
|
|
212
|
-
assert(r.rval == (u'0', 'abcd'))
|
|
213
|
-
print('passed')
|
|
121
|
+
dump_exception('RTPPLWorker_external: unhandled exception when processing RTPproxy reply')
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Copyright (c) 2003-2005 Maxim Sobolev. All rights reserved.
|
|
2
|
+
# Copyright (c) 2006-2025 Sippy Software, Inc. All rights reserved.
|
|
3
|
+
#
|
|
4
|
+
# All rights reserved.
|
|
5
|
+
#
|
|
6
|
+
# Redistribution and use in source and binary forms, with or without modification,
|
|
7
|
+
# are permitted provided that the following conditions are met:
|
|
8
|
+
#
|
|
9
|
+
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
# list of conditions and the following disclaimer.
|
|
11
|
+
#
|
|
12
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
# this list of conditions and the following disclaimer in the documentation and/or
|
|
14
|
+
# other materials provided with the distribution.
|
|
15
|
+
#
|
|
16
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
17
|
+
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
18
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
19
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
20
|
+
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
21
|
+
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
22
|
+
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
23
|
+
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
24
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
25
|
+
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
26
|
+
|
|
27
|
+
from threading import Thread
|
|
28
|
+
from errno import EINTR
|
|
29
|
+
import socket
|
|
30
|
+
|
|
31
|
+
from sippy.Time.MonoTime import MonoTime
|
|
32
|
+
from sippy.Core.Exceptions import dump_exception
|
|
33
|
+
from sippy.Core.EventDispatcher import ED2
|
|
34
|
+
|
|
35
|
+
class RTPPLWorker_internal(Thread):
|
|
36
|
+
daemon = True
|
|
37
|
+
userv = None
|
|
38
|
+
s = None
|
|
39
|
+
|
|
40
|
+
def __init__(self, userv):
|
|
41
|
+
Thread.__init__(self)
|
|
42
|
+
self.userv = userv
|
|
43
|
+
self.s = userv.address
|
|
44
|
+
self.start()
|
|
45
|
+
|
|
46
|
+
def send_raw(self, command, stime = None):
|
|
47
|
+
#print('%s.send_raw(%s)' % (id(self), command))
|
|
48
|
+
if stime == None:
|
|
49
|
+
stime = MonoTime()
|
|
50
|
+
while True:
|
|
51
|
+
try:
|
|
52
|
+
self.s.send(command.encode())
|
|
53
|
+
except socket.error as why:
|
|
54
|
+
if why.errno == EINTR:
|
|
55
|
+
continue
|
|
56
|
+
raise why
|
|
57
|
+
else: break
|
|
58
|
+
while True:
|
|
59
|
+
try:
|
|
60
|
+
rval = self.s.recv(1024)
|
|
61
|
+
if len(rval) == 0:
|
|
62
|
+
raise socket.error('Connection closed')
|
|
63
|
+
rval = rval.decode('ascii').strip()
|
|
64
|
+
except socket.error as why:
|
|
65
|
+
if why.errno == EINTR:
|
|
66
|
+
continue
|
|
67
|
+
raise why
|
|
68
|
+
else: break
|
|
69
|
+
rtpc_delay = stime.offsetFromNow()
|
|
70
|
+
return (rval, rtpc_delay)
|
|
71
|
+
|
|
72
|
+
def run(self):
|
|
73
|
+
#print(self.run, 'enter')
|
|
74
|
+
while True:
|
|
75
|
+
#print(self.run, 'spin')
|
|
76
|
+
wi = self.userv.wi.get()
|
|
77
|
+
if wi == None:
|
|
78
|
+
# Shutdown request, relay it further
|
|
79
|
+
self.userv.wi.put(None)
|
|
80
|
+
if wi == None:
|
|
81
|
+
break
|
|
82
|
+
command, result_callback, callback_parameters = wi
|
|
83
|
+
try:
|
|
84
|
+
data, rtpc_delay = self.send_raw(command)
|
|
85
|
+
if len(data) == 0:
|
|
86
|
+
data, rtpc_delay = None, None
|
|
87
|
+
except Exception as e:
|
|
88
|
+
dump_exception('RTPPLWorker_internal: unhandled exception I/O RTPproxy')
|
|
89
|
+
data, rtpc_delay = None, None
|
|
90
|
+
if result_callback != None:
|
|
91
|
+
ED2.callFromThread(result_callback, data, *callback_parameters)
|
|
92
|
+
if rtpc_delay != None:
|
|
93
|
+
ED2.callFromThread(self.userv.register_delay, rtpc_delay)
|
|
94
|
+
self.userv = None
|
|
95
|
+
self.s = None
|