From eb3c68ad8d05d0b6b47520016b742a5adc59635b Mon Sep 17 00:00:00 2001 From: Maciej Grzegorczyk Date: Thu, 21 Jul 2022 19:27:52 +0200 Subject: [PATCH] making sip caller example to work under python3 Co-authored-by: Jakub Plonka Contains some further porting to python3 changes. With these changes we have managed to succefully run sip caller example with server and 2 callers. Link to example description: https://github.com/theintencity/rtclite/blob/master/rtclite/app/sip/caller.md Here are commands used for testing: python -m rtclite.app.sip.server -d python -m rtclite.app.sip.caller --listen --register --user=alice --domain=localhost --no-audio python -m rtclite.app.sip.caller --listen --register --user=bob --domain=localhost --port=5094 --to=sip:alice@localhost --send=hello --no-audio --- rtclite/app/sip/caller.py | 2 +- rtclite/multitask.py | 1 + rtclite/std/ietf/rfc2396.py | 17 ++++++++++++----- rtclite/std/ietf/rfc3261.py | 19 ++++++------------- 4 files changed, 20 insertions(+), 19 deletions(-) diff --git a/rtclite/app/sip/caller.py b/rtclite/app/sip/caller.py index d5ba899..79ab9c8 100644 --- a/rtclite/app/sip/caller.py +++ b/rtclite/app/sip/caller.py @@ -361,7 +361,7 @@ def send(self, data, addr, stack): if stack.sock: try: if self.options.use_lf: data = re.sub(r'\r\n', '\n', data) - if stack.transport.type == Stacks.UDP: stack.sock.sendto(data, addr) + if stack.transport.type == Stacks.UDP: stack.sock.sendto(data.encode('utf-8'), addr) elif addr in self._conn: self._conn[addr].sendall(data) elif self.allow_outbound: conn = self._conn[addr] = socket.socket(type=socket.SOCK_STREAM) diff --git a/rtclite/multitask.py b/rtclite/multitask.py index 90f17ce..68bae18 100755 --- a/rtclite/multitask.py +++ b/rtclite/multitask.py @@ -411,6 +411,7 @@ def __init__(self, fd, func, args=(), kwargs={}, read=False, write=False, self.func = func self.args = args self.kwargs = kwargs + self.args = [arg.encode('utf-8') if isinstance(arg, str) else arg for arg in self.args] def _eval(self): return self.func(*(self.args), **(self.kwargs)) diff --git a/rtclite/std/ietf/rfc2396.py b/rtclite/std/ietf/rfc2396.py index f5ab2ab..14211b2 100755 --- a/rtclite/std/ietf/rfc2396.py +++ b/rtclite/std/ietf/rfc2396.py @@ -5,6 +5,7 @@ ''' import re, socket, struct +from functools import total_ordering def isIPv4(data): '''Check if the data is a dotted decimal IPv4 address or not? @@ -54,7 +55,8 @@ def isPrivate(data): return a == 10 or a == 172 and 16 <= b < 32 or a == 192 and b == 168 except: return False - + +@total_ordering class URI(object): '''A URI object with dynamic properties. Attributes and items such as scheme, user, password, host, port, @@ -124,10 +126,15 @@ def dup(self): def __hash__(self): '''Hash is derived from lower-case string, hence causes case insensitive match''' return hash(str(self).lower()) - - def __cmp__(self, other): - '''Compare two URI objects by comparing their hash values''' - return cmp(str(self).lower(), str(other).lower()) + + def __eq__(self, other): + return str(self).lower() == str(other).lower() + + def __ne__(self, other): + return str(self).lower() != str(other).lower() + + def __lt__(self, other): + return str(self).lower() < str(other).lower() @property def hostPort(self): diff --git a/rtclite/std/ietf/rfc3261.py b/rtclite/std/ietf/rfc3261.py index 1a6cd70..c2e68ed 100755 --- a/rtclite/std/ietf/rfc3261.py +++ b/rtclite/std/ietf/rfc3261.py @@ -132,7 +132,7 @@ def parseParams(rest, delimiter=';'): yield (n, v) except: logger.exception('error parsing parameters') - raise StopIteration(None) + return def __str__(self): @@ -245,6 +245,7 @@ def _parse(self, value): # 8. Content-Length if present must match the length of body. # 9. mandatory headers are To, From, Call-ID and CSeq. # 10. syntax for top Via header and fields: ttl, maddr, received, branch. + value = value.decode() if not isinstance(value, str) else value indexCRLFCRLF, indexLFLF = value.find('\r\n\r\n'), value.find('\n\n') firstheaders = body = '' if indexCRLFCRLF >= 0 and indexLFLF >= 0: @@ -309,11 +310,7 @@ def __iter__(self): '''Return iterator to iterate over all Header objects.''' h = list() for n in [x for x in self.__dict__ if not x.startswith('_') and x not in Message._keywords]: - if isinstance(x, Header): - arr = [self[n]] - elif isinstance(self[n],list): - arr = self[n] - h += [x for x in arr] + h += list(filter(lambda x: isinstance(x, Header), self[n] if isinstance(self[n], list) else [self[n]])) return iter(h) def first(self, name): @@ -326,11 +323,7 @@ def all(self, *args): args = [x.lower() for x in args] h = list() for n in [x for x in self.__dict__ if x in args and not x.startswith('_') and x not in Message._keywords]: - if isinstance(x, Header): - arr = [self[n]] - elif isinstance(self[n],list): - arr = self[n] - h += [x for x in arr] + h += list(filter(lambda x: isinstance(x, Header), self[n] if isinstance(self[n], list) else [self[n]])) return h def insert(self, header, append=False): @@ -725,13 +718,13 @@ def createBranch(request, server): or using [To, From, Call-ID, CSeq-number(int)] and server (Boolean).''' To, From, CallId, CSeq = (request.To.value, request.From.value, request['Call-ID'].value, request.CSeq.number) if isinstance(request, Message) else (request[0], request[1], request[2], request[3]) data = str(To).lower() + '|' + str(From).lower() + '|' + str(CallId) + '|' + str(CSeq) + '|' + str(server) - return 'z9hG4bK' + str(urlsafe_b64encode(md5(data).digest())).replace('=','.') + return 'z9hG4bK' + str(urlsafe_b64encode(md5(data.encode('utf-8')).digest())).replace('=','.') @staticmethod def createProxyBranch(request, server): '''Create branch property from the request, which will get proxied in a new client branch.''' via = request.first('Via') - if via and 'branch' in via: return 'z9hG4bK'+ str(urlsafe_b64encode(md5(via.branch).digest())).replace('=','.') + if via and 'branch' in via: return 'z9hG4bK'+ str(urlsafe_b64encode(md5(via.branch.encode('utf-8')).digest())).replace('=','.') else: return Transaction.createBranch(request, server) @staticmethod