From 44b1293fa6d6c9fb55aba846b2439f72f0c4ebea Mon Sep 17 00:00:00 2001 From: Retep Relleum Date: Sat, 20 Jun 2020 12:39:19 +0200 Subject: [PATCH 1/5] Create LICENSE --- LICENSE | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From ed86963fe5a98a7700a889fedde9d63663fbb4c4 Mon Sep 17 00:00:00 2001 From: RetepRelleum Date: Sat, 20 Jun 2020 12:44:00 +0200 Subject: [PATCH 2/5] k --- uPySip/sipMachine.py | 3 +-- uSipB2Bua.py | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/uPySip/sipMachine.py b/uPySip/sipMachine.py index 239f00d..81d7978 100644 --- a/uPySip/sipMachine.py +++ b/uPySip/sipMachine.py @@ -1,4 +1,3 @@ -import _thread import uPySip.md5 import utime import socket @@ -8,7 +7,7 @@ import sys import os -debug=True +debug=False def _randomChr(size): ret = "" diff --git a/uSipB2Bua.py b/uSipB2Bua.py index bf92386..e13b6f6 100644 --- a/uSipB2Bua.py +++ b/uSipB2Bua.py @@ -26,6 +26,7 @@ if loop==sipMachine.RINGING: if int(sipMachine.getTelNrB())<300: sipMachine.acceptCall() + warte=False if sipMachine.IDLE!=loop: pass #print(loop) @@ -47,5 +48,3 @@ if keyPressed=='3': sipMachine.play('/sd/warte.aLaw') warte=True - else: - warte=False \ No newline at end of file From 1b7c98396743e0456254588c274d138687fdffef Mon Sep 17 00:00:00 2001 From: RetepRelleum Date: Sun, 21 Jun 2020 07:42:53 +0200 Subject: [PATCH 3/5] li --- LICENSE | 201 -------------------------------------------------------- 1 file changed, 201 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9..0000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. From ea7d77933784b615efbc4c507ed7e76a4823f632 Mon Sep 17 00:00:00 2001 From: RetepRelleum Date: Sun, 21 Jun 2020 11:12:34 +0200 Subject: [PATCH 4/5] Linter --- uPySip/DTMF.py | 3 +- uPySip/sipMachine.py | 264 ++++++++++++++++++++++++------------------- uSipB2Bua.py | 75 ++++++------ 3 files changed, 188 insertions(+), 154 deletions(-) diff --git a/uPySip/DTMF.py b/uPySip/DTMF.py index e6e4380..2a99ef5 100644 --- a/uPySip/DTMF.py +++ b/uPySip/DTMF.py @@ -1,4 +1,5 @@ -import cmath,math +import cmath +import math import time import uPySip.aLaw diff --git a/uPySip/sipMachine.py b/uPySip/sipMachine.py index 81d7978..20be4de 100644 --- a/uPySip/sipMachine.py +++ b/uPySip/sipMachine.py @@ -1,3 +1,9 @@ +"""Module sip Machine. + +This module is a sip implementation in python + +""" + import uPySip.md5 import utime import socket @@ -7,22 +13,24 @@ import sys import os -debug=False +debug = True + def _randomChr(size): ret = "" a = 0 while a < size: - try: - b = os.urandom(10)[5] - if (b >= 48 and b < 58) or (b > 64 and b < 91) or (b > 97 and b < 123): - ret = '{}{}'.format(ret, chr(b)) - a = a+1 - except: - pass + b = os.urandom(10)[5] + + if (bytes([b]).isalpha()): + ret = '{}{}'.format(ret, chr(b)) + a = a+1 return ret + class User: + """Base User Class.""" + telNr = None agent = None cSeq = 0 @@ -32,16 +40,23 @@ class User: class UserA(User): + """User A.""" + userClient = None + def __init__(self): + """Init the Class.""" + self.branch = 'z9hG4bK-{}'.format(_randomChr(30)) + class UserB(User): toB = None viaB = None fromB = None sdp_o = None + class Auth: __RN = '\r\n' user = None @@ -52,10 +67,9 @@ class Auth: qop = None def __getUri(self, userB: UserB): - if userB.telNr == None: + if userB.telNr is None: return userB.agent - else: - return '{}@{}'.format(userB.telNr, userB.agent) + return '{}@{}'.format(userB.telNr, userB.agent) def __getAuth(self, userB: UserB): a1 = '{}:{}:{}'.format(self.user, self.realm, self.pwd) @@ -67,35 +81,44 @@ def __getAuth(self, userB: UserB): return uPySip.md5.md5(a3.encode()).hexdigest() def getAuthorization(self, userB: UserB) -> str: - """function getAuthorization + """function getAuthorization Args: userB (UserB): UserB with telNr and agent Returns: - str: Sip Line for Authorization + str: Sip Line for Authorization """ self.nonceCount = 1 self.cnonce = uPySip.md5.md5('das ist ein Chaos'.encode()).hexdigest() response = self.__getAuth(userB) - return 'Authorization: Digest username="{}",realm="{}",nonce="{}",opaque="",uri="sip:{}",cnonce="{}",nc={:0>8},algorithm=MD5,qop="auth",response="{}"{}'.format( - self.user, self.realm, self.nonce, self.__getUri(userB), self.cnonce, self.nonceCount, response, self.__RN) + ret = 'Authorization: Digest username="{}"'.format(self.user) + ret = '{},realm="{}"'.format(ret, self.realm) + ret = '{},nonce="{}"'.format(ret, self.nonce) + ret = '{},opaque="",uri="sip:{}"'.format(ret, self.__getUri(userB)) + ret = '{},cnonce="{}"'.format(ret, self.cnonce) + ret = '{},nc={:0>8}'.format(ret, self.nonceCount) + ret = '{},nc={:0>8}'.format(ret, self.nonceCount) + ret = '{},algorithm=MD5,qop="auth",response="{}"{}'.format( + ret, response, self.__RN) + return ret + class SipMachine: - REGISTER = 0x00 - IDLE = 0x01 - RINGING = 0x02 - CALLING = 0x03 - TRYING = 0x0 - CALL_ACCEPT = 0x05 - ON_CALL = 0x06 - BYE=0x07 + REGISTER = b'x00' + IDLE = b'x01' + RINGING = b'x02' + CALLING = b'x03' + TRYING = b'x04' + CALL_ACCEPT = b'x05' + ON_CALL = b'x06' + BYE = b'x07' __userB = UserB() __userA = UserA() __auth = Auth() __RN = '\r\n' __INVITE = 'INVITE' __REGISTER = 'REGISTER' - __BYE='BYE' + __BYE = 'BYE' __status = REGISTER __key = '' __record = False @@ -111,19 +134,19 @@ class SipMachine: __proxyServer = None __proxyRegistrar = None __port = 5060 - __keyTimestamp=0 + __keyTimestamp = 0 - def __init__(self:str, user:str, pwd:str, telNr:str, userAgent:str, userClient:str, proxyServer:str, proxyRegistrar:str='192.168.1.1', port:str=5060): + def __init__(self: str, user: str, pwd: str, telNr: str, userAgent: str, userClient: str, proxyServer: str, proxyRegistrar: str = '192.168.1.1', port: str = 5060): """Init sipMachine Args: - user (str): sip User configure in proxyRegistrar - pwd (str): password configured in proxyRegistrar + user (str): sip User configure in proxyRegistrar + pwd (str): password configured in proxyRegistrar telNr (str): telephon number configured in proxyRegistrar userAgent (str): b2b user Agent name . userClient (str): ip Adress Client. proxyServer (str): ip Adress proxiServer. - proxyRegistrar (str, ): ip Adress proxyRegistrar most proxiServer . + proxyRegistrar (str, ): ip Adress proxyRegistrar most proxiServer. port (str, optional): [description]. Defaults to 5060. """ self.__auth.user = user @@ -136,11 +159,13 @@ def __init__(self:str, user:str, pwd:str, telNr:str, userAgent:str, userClient:s self.__userA.userClient = userClient self.__sock_sip_r = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.__sock_sip_r.bind(socket.getaddrinfo(self.__userA.userClient, port)[0][-1]) + self.__sock_sip_r.bind(socket.getaddrinfo( + self.__userA.userClient, port)[0][-1]) self.__sock_sip_r.listen(0) self.__sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) - self.__sock.bind(socket.getaddrinfo(self.__userA.userClient, 17000)[0][-1]) + self.__sock.bind(socket.getaddrinfo( + self.__userA.userClient, 17000)[0][-1]) self.__polling_object = select.poll() @@ -149,7 +174,7 @@ def __init__(self:str, user:str, pwd:str, telNr:str, userAgent:str, userClient:s self.__sipRegister(self.__userA, self.__auth) self.__call = False - self.__path='/sd/wilk.aLaw' + self.__path = '/sd/wilk.aLaw' # path=__file__.replace('sipMachine.py','data.pcmA') # f=open(path,'wb') @@ -159,7 +184,7 @@ def __init__(self:str, user:str, pwd:str, telNr:str, userAgent:str, userClient:s # f.write(k) # f.close() - def loop(self)->bytes: + def loop(self) -> bytes: """ loop in main Returns: @@ -174,62 +199,66 @@ def loop(self)->bytes: ready_list = self.__polling_object.poll() for fd in ready_list: if fd[1] & select.POLLIN: - if self.__f_sip != None: + if self.__f_sip is not None: if fd[0] == self.__f_sip.fileno() or fd[0] == self.__f_sip: self.__readSIPdata() if fd[0] == self.__sock.fileno() or fd[0] == self.__sock: self.__recive() if fd[0] == self.__sock_sip_r.fileno() or fd[0] == self.__sock_sip_r: - if self.__f_sip != None: + if self.__f_sip is not None: self.__closeConnection() - (a, b) = self.__sock_sip_r.accept() - self.__setConnection(a) + a = self.__sock_sip_r.accept() + self.__setConnection(a[0]) gc.collect() if self.__call: - if debug: print('start') + if debug: + print('start') f = open(self.__path, 'rb') v = memoryview(self.__buffer) - l = f.readinto(v[12:]) + li = f.readinto(v[12:]) t = utime.ticks_ms() - i=0 - while l == 160: + i = 0 + while li == 160: if utime.ticks_ms()-t >= 20: - i+=1 + i += 1 t = utime.ticks_ms() self.__send(self.server_addressS) - l = f.readinto(v[12:]) - if i%20==0: #Bad solution + li = f.readinto(v[12:]) + if i % 20 == 0: # Bad solution gc.collect() f.close() self.__call = False - if debug:print('end') - if sys.platform!='linux': - if debug:print(gc.mem_free()) + if debug: + print('end') + if sys.platform != 'linux': + if debug: + print(gc.mem_free()) return self.__status - def bye(self,auth=None): + def bye(self, auth=None): """ terminate the call Args: auth ([type], optional): [description]. Defaults to None. """ - self.__userA.cSeq+=1 + self.__userA.cSeq += 1 self.__setConnection() - self.__writeSIPdata('BYE sip:{}@{} SIP/2.0{}'.format(self.__userA.telNr,self.__userA.userClient, self.__RN)) + self.__writeSIPdata( + 'BYE sip:{}@{} SIP/2.0{}'.format(self.__userA.telNr, self.__userA.userClient, self.__RN)) self.__getVia(self.__userA) self.__getMaxForwards() self.__getFrom(self.__userA) self.__getTo(self.__userB) self.__getCallID(self.__userA) - self.__getCSeq(self.__userA.cSeq, self.__BYE) - if auth != None: - self.__auth.types=self.__BYE + self.__getCSeq(self.__userA.cSeq, self.__BYE) + if auth is not None: + self.__auth.types = self.__BYE self.__writeSIPdata(self.__auth.getAuthorization(self.__userB)) self.__getContentLength() - self.__writeSIPdata(self.__RN) - self.__status = self.BYE + self.__writeSIPdata(self.__RN) + self.__status = self.BYE - def invite(self, telNr:str, userAgent=None): + def invite(self, telNr: str, userAgent=None): """make a call Args: @@ -239,12 +268,12 @@ def invite(self, telNr:str, userAgent=None): self.__setConnection() self.__userB.sdp_o = 25 self.__userB.telNr = telNr - if userAgent == None: + if userAgent is None: self.__userB.agent = self.__userA.agent else: self.__userB.agent = userAgent self.__userA.callId = _randomChr(7) - self.__userA.tagFrom =_randomChr(30) + self.__userA.tagFrom = _randomChr(30) self.__userA.cSeq += 1 self.__auth.nonce = None self.__sipInvite(self.__userB, self.__userA, self.__auth) @@ -256,7 +285,7 @@ def acceptCall(self): self.__sipOK(self.__userB, self.__userA) self.__status = self.CALL_ACCEPT - def getTelNrB(self)->str: + def getTelNrB(self) -> str: """ get the tel nr of the ringing call Returns: @@ -264,7 +293,7 @@ def getTelNrB(self)->str: """ return self.__userB.fromB.split('sip:')[1].split('@')[0] - def getKeyPressed(self)->str: + def getKeyPressed(self) -> str: """ get the pressed key on the phone b Returns: @@ -273,27 +302,28 @@ def getKeyPressed(self)->str: key = self.__key self.__key = '' return key - - def play(self,path): - """Ply the pcmAlaw file + + def play(self, path): + """Ply the pcmAlaw file Args: - path (str): path to the pcmAlaw file + path (str): path to the pcmAlaw file """ - self.__path=path - self.__call=True + self.__path = path + self.__call = True - def __sipRegister(self, userA: UserA, auth: Auth = None): + def __sipRegister(self, userA: UserA, auth: Auth): self.__setConnection() userB = UserB() userB.telNr = None userB.agent = self.__proxyRegistrar - if auth.nonce != None: + if auth.nonce is not None: userA.cSeq += 1 auth.types = self.__REGISTER else: - userA.callId =_randomChr(7) - self.__writeSIPdata('REGISTER sip:{} SIP/2.0{}'.format(self.__proxyRegistrar, self.__RN)) + userA.callId = _randomChr(7) + self.__writeSIPdata( + 'REGISTER sip:{} SIP/2.0{}'.format(self.__proxyRegistrar, self.__RN)) self.__getVia(userA) self.__getMaxForwards() self.__getTo(userA) @@ -302,7 +332,7 @@ def __sipRegister(self, userA: UserA, auth: Auth = None): self.__getCSeq(userA.cSeq, self.__REGISTER) self.__getContact(userA) self.__getAllow() - if auth.nonce != None: + if auth.nonce is not None: self.__writeSIPdata(self.__auth.getAuthorization(userB)) self.__getContentLength() self.__writeSIPdata(self.__RN) @@ -315,21 +345,20 @@ def __sipOK(self, userB: UserB, userA: UserA = None): self.__writeSIPdata(userB.toB) self.__writeSIPdata(userB.callId) self.__writeSIPdata(userB.cSeq) - if userA != None: + if userA is not None: conten = self.__getConten(userB, userA.userClient) contentLength = len(conten) self.__getContact(userA) self.__getContentType() self.__getContentLength(contentLength) self.__writeSIPdata(self.__RN) - if userA != None: + if userA is not None: self.__writeSIPdata(conten) def __getConten(self, userB: UserB, userClient): conten = '' conten = '{}{}{}'.format(conten, 'v=0', self.__RN) - conten = '{}{} {} {} {} {}{}'.format( - conten, 'o=-', int(userB.sdp_o)+1, int(userB.sdp_o)+1, 'IN IP4', userClient, self.__RN) + conten = '{}{} {} {} {} {}{}'.format(conten, 'o=-', int(userB.sdp_o)+1, int(userB.sdp_o)+1, 'IN IP4', userClient, self.__RN) conten = '{}{}{}'.format(conten, 's=-', self.__RN) conten = '{}{} {}{}'.format(conten, 'c=IN IP4', userClient, self.__RN) conten = '{}{}{}'.format(conten, 't=0 0', self.__RN) @@ -353,11 +382,11 @@ def __sipRinging(self, userB: UserB, userA: UserA): self.__getContentLength() self.__writeSIPdata(self.__RN) - def __sipInvite(self, userB: UserB, userA: UserA, auth: Auth = None): + def __sipInvite(self, userB: UserB, userA: UserA, auth: Auth): self.__userB.tagTo = '' conten = self.__getConten(userB, userA.userClient) contentLength = len(conten) - if auth.nonce != None: + if auth.nonce is not None: userA.cSeq += 1 auth.types = self.__INVITE self.__getInvite(userB) @@ -367,7 +396,7 @@ def __sipInvite(self, userB: UserB, userA: UserA, auth: Auth = None): self.__getTo(userB) self.__getCallID(userA) self.__getCSeq(userA.cSeq, self.__INVITE) - if auth.nonce != None: + if auth.nonce is not None: self.__writeSIPdata(self.__auth.getAuthorization(userB)) self.__getContact(userA) self.__getContentType() @@ -375,7 +404,7 @@ def __sipInvite(self, userB: UserB, userA: UserA, auth: Auth = None): self.__writeSIPdata(self.__RN) self.__writeSIPdata(conten) - def __sipACK(self, userB: UserB, userA: UserA, auth: Auth): + def __sipACK(self, userB: UserB, userA: UserA): self.__getACK(userB.telNr, userB.agent, self.__port) self.__getVia(userA) self.__getMaxForwards() @@ -386,14 +415,14 @@ def __sipACK(self, userB: UserB, userA: UserA, auth: Auth): self.__getContentLength() self.__writeSIPdata(self.__RN) - def __getVia(self, user) -> str: + def __getVia(self, user): self.__writeSIPdata('Via: SIP/2.0/TCP {}:{};branch={}{}'.format( user.userClient, self.__port, user.branch, self.__RN)) - def __getMaxForwards(self) -> str: + def __getMaxForwards(self): self.__writeSIPdata('Max-Forwards: 70{}'.format(self.__RN)) - def __getTo(self, user: User) -> str: + def __getTo(self, user: User): if len(user.tagTo) > 0: self.__writeSIPdata('To: ;tag={}{}'.format( user.telNr, user.agent, user.tagTo, self.__RN)) @@ -401,40 +430,41 @@ def __getTo(self, user: User) -> str: self.__writeSIPdata('To: {}'.format( user.telNr, user.agent, self.__RN)) - def __getFrom(self, userA: UserA) -> str: - self.__writeSIPdata('From: ;tag={}{}'.format(userA.telNr, userA.agent, userA.tagFrom, self.__RN)) + def __getFrom(self, userA: UserA): + self.__writeSIPdata( + 'From: ;tag={}{}'.format(userA.telNr, userA.agent, userA.tagFrom, self.__RN)) - def __getCallID(self, userA: UserA) -> str: + def __getCallID(self, userA: UserA): self.__writeSIPdata( 'Call-ID: {}@{}{}'.format(userA.callId, userA.agent, self.__RN)) - def __getCSeq(self, cSeq, typ) -> str: + def __getCSeq(self, cSeq, typ): self.__writeSIPdata('CSeq: {} {}{}'.format(cSeq, typ, self.__RN)) - def __getContact(self, user: User) -> str: + def __getContact(self, user: User): self.__writeSIPdata('Contact: {}'.format( user.telNr, user.userClient, self.__RN)) - def __getExpires(self, expires) -> str: + def __getExpires(self, expires): return 'Expires: {}{}'.format(expires, self.__RN) - def __getContentLength(self, contentLength=0) -> str: + def __getContentLength(self, contentLength=0): self.__writeSIPdata( 'Content-Length: {}{}'.format(contentLength, self.__RN)) - def __getACK(self, telNr, agent, port) -> str: + def __getACK(self, telNr, agent, port): self.__writeSIPdata( 'ACK sip:{}@{}:{} SIP/2.0{}'.format(telNr, agent, port, self.__RN)) - def __getAllow(self) -> str: + def __getAllow(self): self.__writeSIPdata( 'Allow: INVITE,ACK,OPTIONS,BYE,CANCEL,SUBSCRIBE,NOTIFY,REFER,MESSAGE,INFO,PING{}'.format(self.__RN)) - def __getInvite(self, user: User) -> str: + def __getInvite(self, user: User): self.__writeSIPdata( 'INVITE sip:{}@{} SIP/2.0{}'.format(user.telNr, user.agent, self.__RN)) - def __getContentType(self) -> str: + def __getContentType(self): self.__writeSIPdata( 'Content-Type: application/sdp{}'.format(self.__RN)) @@ -513,7 +543,8 @@ def __exec(self): pass elif self.CSeqTyp == self.__INVITE and self.responseCodes == '200': self.__call = True - self.server_addressS = socket.getaddrinfo(self.__proxyServer, self.pcmuPort)[0][-1] + self.server_addressS = socket.getaddrinfo( + self.__proxyServer, self.pcmuPort)[0][-1] self.__sipACK(self.__userB, self.__userA, self.__auth) self.__status = self.ON_CALL self.__closeConnection() @@ -522,10 +553,11 @@ def __exec(self): self.__sipRinging(self.__userB, self.__userA) self.__status = self.RINGING elif self.CSeqTyp == 'ACK' and self.responseCodes == 'ACK sip:': - self.server_addressS = socket.getaddrinfo(self.__proxyServer, self.pcmuPort)[0][-1] + self.server_addressS = socket.getaddrinfo( + self.__proxyServer, self.pcmuPort)[0][-1] self.__call = True self.__closeConnection() - self.__status = self.ON_CALL + self.__status = self.ON_CALL elif self.CSeqTyp == 'BYE' and self.responseCodes == 'BYE sip:': self.__sipOK(self.__userB) self.__call = False @@ -543,12 +575,14 @@ def __exec(self): def __readSIPdata(self): try: data = self.__f_sip.readline() - if debug:print('-', data.decode(), end='') + if debug: + print('-', data.decode(), end='') if (data == b'\r\n'): if (self.___contentLenght > 0): data = self.__f_sip.read(self.___contentLenght).decode() for k in data.split('\r\n'): - if debug:print('*', k) + if debug: + print('*', k) self.__parser(k.encode()) self.__exec() elif len(data) > 0: @@ -557,7 +591,8 @@ def __readSIPdata(self): self.logger.error("exception from sock_read.recvfrom {}".format(e)) def __writeSIPdata(self, message): - if debug:print(message, end='') + if debug: + print(message, end='') self.__f_sip.write(message.encode()) def __send(self, server_addressS): @@ -576,38 +611,37 @@ def __send(self, server_addressS): def __recive(self): try: - (data, proxyServer) = self.__sock.recvfrom(180) - a = uPySip.DTMF.DTMF().getKey(data) - if a[1] > 500000 : - if int.from_bytes(data[4:8],'big')-self.__keyTimestamp>3000: + data = self.__sock.recvfrom(180) + a = uPySip.DTMF.DTMF().getKey(data[0]) + if a[1] > 500000: + if int.from_bytes(data[4:8], 'big')-self.__keyTimestamp > 3000: self.__key = a[0] - self.__keyTimestamp=int.from_bytes(data[4:8],'big') - + self.__keyTimestamp = int.from_bytes(data[4:8], 'big') except OSError as msg: print("Socket Error: {}".format(msg)) def __setConnection(self, __sock_SIP=None): gc.collect() - if self.__sock_SIP == None: + if self.__sock_SIP is None: self.__sock_SIP = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.__sock_SIP.connect(socket.getaddrinfo(self.__proxyServer, self.__port)[0][-1]) - if __sock_SIP != None: + self.__sock_SIP.connect(socket.getaddrinfo( + self.__proxyServer, self.__port)[0][-1]) + if __sock_SIP is not None: self.__sock_SIP = __sock_SIP - if self.__f_sip == None: - if debug:print('** on') - self.__f_sip = self.__sock_SIP.makefile('rwb',0) + if self.__f_sip is None: + if debug: + print('** on') + self.__f_sip = self.__sock_SIP.makefile('rwb', 0) self.__polling_object.register(self.__f_sip) self.__userB.viaB = '' def __closeConnection(self): - if debug:print('** off') + if debug: + print('** off') self.__polling_object.unregister(self.__f_sip) self.__f_sip.close() self.__sock_SIP.close() self.__f_sip = None self.__sock_SIP = None gc.collect() - - - diff --git a/uSipB2Bua.py b/uSipB2Bua.py index e13b6f6..f7d6699 100644 --- a/uSipB2Bua.py +++ b/uSipB2Bua.py @@ -1,50 +1,49 @@ import uPySip.sipMachine import sys import utime -import gc -port=5060 -server='192.168.1.1' -client1='192.168.1.113' -client2='192.168.1.119' -telId1=225 -telid2=226 -if sys.platform=='linux': - client=client1 - telId=telId1 + +port = 5060 +server = '192.168.1.1' +client1 = '192.168.1.113' +client2 = '192.168.1.119' +telId1 = '225' +telid2 = '226' +if sys.platform == 'linux': + client = client1 + telId = telId1 else: - client=client2 - telId=telid2 + client = client2 + telId = telid2 -sipMachine=uPySip.sipMachine.SipMachine(user='relleum', pwd='jutkk7x1',telNr=telId,userAgent="b2b.domain",userClient=client,proxyServer=server,proxyRegistrar=server) -loop=True -first =False -warte=False +sipMachine = uPySip.sipMachine.SipMachine(user='relleum', pwd='jutkk7x1', telNr=telId, + userAgent="b2b.domain", userClient=client, proxyServer=server, proxyRegistrar=server) +loop = b'x00' +first = False +warte = False -while loop>=0: - loop=sipMachine.loop() - if loop==sipMachine.RINGING: - if int(sipMachine.getTelNrB())<300: +while loop >= b'x00': + loop = sipMachine.loop() + if loop == sipMachine.RINGING: + if int(sipMachine.getTelNrB()) < 300: sipMachine.acceptCall() - warte=False - if sipMachine.IDLE!=loop: - pass - #print(loop) - if sipMachine.IDLE==loop: + warte = False + + elif sipMachine.IDLE == loop: if first: sipMachine.invite('222') - first=False - if sipMachine.ON_CALL==loop: - if warte and utime.ticks_ms()%5000==0: + first = False + elif sipMachine.ON_CALL == loop: + if warte and utime.ticks_ms() % 5000 == 0: sipMachine.play('/sd/warte.aLaw') - keyPressed=sipMachine.getKeyPressed() - if keyPressed!='': - if keyPressed=='0': - sipMachine.play('/sd/wilk.aLaw') - if keyPressed=='1': - sipMachine.play('/sd/info.aLaw') - if keyPressed=='2': - sipMachine.play('/sd/info.aLaw') - if keyPressed=='3': + keyPressed = sipMachine.getKeyPressed() + if keyPressed != '': + if keyPressed == '0': + sipMachine.play('/sd/wilk.aLaw') + if keyPressed == '1': + sipMachine.play('/sd/info.aLaw') + if keyPressed == '2': + sipMachine.play('/sd/info.aLaw') + if keyPressed == '3': sipMachine.play('/sd/warte.aLaw') - warte=True + warte = True From 7ba83d7382778945d66e4a8d85f8695540c1c1a3 Mon Sep 17 00:00:00 2001 From: RetepRelleum Date: Sun, 6 Dec 2020 07:47:30 +0100 Subject: [PATCH 5/5] Test --- uPySip/sipMachine.py | 8 +++-- uPySip/test.py | 80 ++++++++++++++++++++++++++++++++++++++++++++ uSipB2Bua.py | 6 ++-- 3 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 uPySip/test.py diff --git a/uPySip/sipMachine.py b/uPySip/sipMachine.py index 20be4de..75adeb3 100644 --- a/uPySip/sipMachine.py +++ b/uPySip/sipMachine.py @@ -73,11 +73,16 @@ def __getUri(self, userB: UserB): def __getAuth(self, userB: UserB): a1 = '{}:{}:{}'.format(self.user, self.realm, self.pwd) + print("- "+a1) ha1 = uPySip.md5.md5(a1.encode()).hexdigest() + print("- "+ha1) a2 = '{}:sip:{}'.format(self.types, self.__getUri(userB)) + print("- "+a2) ha2 = uPySip.md5.md5(a2.encode()).hexdigest() + print("- "+ha2) a3 = '{}:{}:{:0>8}:{}:{}:{}'.format( ha1, self.nonce, self.nonceCount, self.cnonce, self.qop, ha2) + print("- "+a3) return uPySip.md5.md5(a3.encode()).hexdigest() def getAuthorization(self, userB: UserB) -> str: @@ -97,7 +102,6 @@ def getAuthorization(self, userB: UserB) -> str: ret = '{},opaque="",uri="sip:{}"'.format(ret, self.__getUri(userB)) ret = '{},cnonce="{}"'.format(ret, self.cnonce) ret = '{},nc={:0>8}'.format(ret, self.nonceCount) - ret = '{},nc={:0>8}'.format(ret, self.nonceCount) ret = '{},algorithm=MD5,qop="auth",response="{}"{}'.format( ret, response, self.__RN) return ret @@ -404,7 +408,7 @@ def __sipInvite(self, userB: UserB, userA: UserA, auth: Auth): self.__writeSIPdata(self.__RN) self.__writeSIPdata(conten) - def __sipACK(self, userB: UserB, userA: UserA): + def __sipACK(self, userB: UserB, userA: UserA,d): self.__getACK(userB.telNr, userB.agent, self.__port) self.__getVia(userA) self.__getMaxForwards() diff --git a/uPySip/test.py b/uPySip/test.py new file mode 100644 index 0000000..a27e6c7 --- /dev/null +++ b/uPySip/test.py @@ -0,0 +1,80 @@ +import os +import md5 + +def _randomChr(size): + ret = "" + a = 0 + while a < size: + b = os.urandom(10)[5] + + if (bytes([b]).isalpha()): + ret = '{}{}'.format(ret, chr(b)) + a = a+1 + return ret + +class User: + """Base User Class.""" + + telNr = None + agent = None + cSeq = 0 + callId = None + tagTo = "" + tagFrom = _randomChr(30) + +class UserB(User): + toB = None + viaB = None + fromB = None + sdp_o = None + +class Auth: + __RN = '\r\n' + user = "relleum" + pwd = "jutkk7x1" + realm = "Home" + types = "REGISTER" + nonce = "535a8a2bb603502035ed0cbb" + qop = "auth" + + def __getUri(self, userB: UserB): + if userB.telNr is None: + return userB.agent + return '{}@{}'.format(userB.telNr, userB.agent) + + def __getAuth(self, userB: UserB): + a1 = '{}:{}:{}'.format(self.user, self.realm, self.pwd) + ha1 = md5.md5(a1.encode()).hexdigest() + a2 = '{}:sip:{}'.format(self.types, self.__getUri(userB)) + ha2 = md5.md5(a2.encode()).hexdigest() + a3 = '{}:{}:{:0>8}:{}:{}:{}'.format( + ha1, self.nonce, self.nonceCount, self.cnonce, self.qop, ha2) + return md5.md5(a3.encode()).hexdigest() + + def getAuthorization(self, userB: UserB) -> str: + """function getAuthorization + Args: + userB (UserB): UserB with telNr and agent + + Returns: + str: Sip Line for Authorization + """ + self.nonceCount = 1 + self.cnonce = md5.md5('das ist ein Chaos'.encode()).hexdigest() + response = self.__getAuth(userB) + ret = 'Authorization: Digest username="{}"'.format(self.user) + ret = '{},realm="{}"'.format(ret, self.realm) + ret = '{},nonce="{}"'.format(ret, self.nonce) + ret = '{},opaque="",uri="sip:{}"'.format(ret, self.__getUri(userB)) + ret = '{},cnonce="{}"'.format(ret, self.cnonce) + ret = '{},nc={:0>8}'.format(ret, self.nonceCount) + ret = '{},algorithm=MD5,qop="auth",response="{}"{}'.format( + ret, response, self.__RN) + return ret + +user =UserB() +user.agent='192.168.1.1' +aut=Auth() +k=aut.getAuthorization(user) +print(k) + diff --git a/uSipB2Bua.py b/uSipB2Bua.py index f7d6699..37314d5 100644 --- a/uSipB2Bua.py +++ b/uSipB2Bua.py @@ -7,8 +7,8 @@ server = '192.168.1.1' client1 = '192.168.1.113' client2 = '192.168.1.119' -telId1 = '225' -telid2 = '226' +telId1 = '220' +telid2 = '225' if sys.platform == 'linux': client = client1 telId = telId1 @@ -19,7 +19,7 @@ sipMachine = uPySip.sipMachine.SipMachine(user='relleum', pwd='jutkk7x1', telNr=telId, userAgent="b2b.domain", userClient=client, proxyServer=server, proxyRegistrar=server) loop = b'x00' -first = False +first = True warte = False while loop >= b'x00':