Ticket #2197: sip_2197.diff
| File sip_2197.diff, 19.8 KB (added by therve, 7 years ago) |
|---|
-
twisted/protocols/sip.py
94 94 488: "Not Acceptable Here", 95 95 491: "Request Pending", 96 96 493: "Undecipherable", 97 97 98 98 500: "Internal Server Error", 99 99 501: "Not Implemented", 100 100 502: "Bad Gateway", # no donut … … 102 102 504: "Server Time-out", 103 103 505: "SIP Version not supported", 104 104 513: "Message Too Large", 105 105 106 106 600: "Busy Everywhere", 107 107 603: "Decline", 108 108 604: "Does not exist anywhere", … … 167 167 m.update(":") 168 168 m.update(pszHEntity) 169 169 HA2 = m.digest().encode('hex') 170 170 171 171 m = md5.md5() 172 172 m.update(HA1) 173 173 m.update(":") … … 266 266 self.tag = tag 267 267 self.ttl = ttl 268 268 self.maddr = maddr 269 if other ==None:269 if other is None: 270 270 self.other = [] 271 271 else: 272 272 self.other = other 273 if headers ==None:273 if headers is None: 274 274 self.headers = {} 275 275 else: 276 276 self.headers = headers … … 301 301 302 302 def __str__(self): 303 303 return self.toString() 304 304 305 305 def __repr__(self): 306 306 return '<URL %s:%s@%s:%r/%s>' % (self.username, self.password, self.host, self.port, self.transport) 307 307 … … 419 419 """A SIP message.""" 420 420 421 421 length = None 422 422 423 423 def __init__(self): 424 424 self.headers = util.OrderedDict() # map name to list of values 425 425 self.body = "" 426 426 self.finished = 0 427 427 428 428 def addHeader(self, name, value): 429 429 name = name.lower() 430 430 name = longHeaders.get(name, name) … … 434 434 435 435 def bodyDataReceived(self, data): 436 436 self.body += data 437 437 438 438 def creationFinished(self): 439 439 if (self.length != None) and (self.length != len(self.body)): 440 440 raise ValueError, "wrong body length" … … 465 465 else: 466 466 self.uri = parseURL(uri) 467 467 cleanRequestURL(self.uri) 468 468 469 469 def __repr__(self): 470 470 return "<SIP Request %d:%s %s>" % (id(self), self.method, self.uri.toString()) 471 471 … … 479 479 def __init__(self, code, phrase=None, version="SIP/2.0"): 480 480 Message.__init__(self) 481 481 self.code = code 482 if phrase ==None:482 if phrase is None: 483 483 phrase = statusCodes[code] 484 484 self.phrase = phrase 485 485 … … 501 501 acceptResponses = 1 502 502 acceptRequests = 1 503 503 state = "firstline" # or "headers", "body" or "invalid" 504 504 505 505 debug = 0 506 506 507 507 def __init__(self, messageReceivedCallback): 508 508 self.messageReceived = messageReceivedCallback 509 509 self.reset() … … 514 514 self.bodyReceived = 0 # how much of the body we received 515 515 self.message = None 516 516 self.setLineMode(remainingData) 517 517 518 518 def invalidMessage(self): 519 519 self.state = "invalid" 520 520 self.setRawMode() 521 521 522 522 def dataDone(self): 523 523 # clear out any buffered data that may be hanging around 524 524 self.clearLineBuffer() … … 527 527 if self.state != "body": 528 528 self.reset() 529 529 return 530 if self.length ==None:530 if self.length is None: 531 531 # no content-length header, so end of data signals message done 532 532 self.messageDone() 533 elif self.length <self.bodyReceived:533 elif self.length > self.bodyReceived: 534 534 # aborted in the middle 535 535 self.reset() 536 536 else: 537 537 # we have enough data and message wasn't finished? something is wrong 538 538 raise RuntimeError, "this should never happen" 539 539 540 540 def dataReceived(self, data): 541 541 try: 542 542 basic.LineReceiver.dataReceived(self, data) 543 543 except: 544 544 log.err() 545 545 self.invalidMessage() 546 546 547 547 def handleFirstLine(self, line): 548 548 """Expected to create self.message.""" 549 549 raise NotImplementedError 550 550 551 551 def lineLengthExceeded(self, line): 552 552 self.invalidMessage() 553 553 554 554 def lineReceived(self, line): 555 555 if self.state == "firstline": 556 556 while line.startswith("\n") or line.startswith("\r"): … … 608 608 self.message.creationFinished() 609 609 self.messageReceived(self.message) 610 610 self.reset(remainingData) 611 611 612 612 def rawDataReceived(self, data): 613 613 assert self.state in ("body", "invalid") 614 614 if self.state == "invalid": 615 615 return 616 if self.length ==None:616 if self.length is None: 617 617 self.message.bodyDataReceived(data) 618 618 else: 619 619 dataLen = len(data) … … 631 631 632 632 class Base(protocol.DatagramProtocol): 633 633 """Base class for SIP clients and servers.""" 634 634 635 635 PORT = PORT 636 636 debug = False 637 637 638 638 def __init__(self): 639 639 self.messages = [] 640 640 self.parser = MessagesParser(self.addMessage) … … 658 658 def _fixupNAT(self, message, (srcHost, srcPort)): 659 659 # RFC 2543 6.40.2, 660 660 senderVia = parseViaHeader(message.headers["via"][0]) 661 if senderVia.host != srcHost: 661 if senderVia.host != srcHost: 662 662 senderVia.received = srcHost 663 663 if senderVia.port != srcPort: 664 664 senderVia.rport = srcPort … … 709 709 710 710 def handle_response(self, message, addr): 711 711 """Override to define behavior for responses received. 712 712 713 713 @type message: C{Message} 714 714 @type addr: C{tuple} 715 715 """ … … 760 760 761 761 class Proxy(Base): 762 762 """SIP proxy.""" 763 763 764 764 PORT = PORT 765 765 766 766 locator = None # object implementing ILocator 767 767 768 768 def __init__(self, host=None, port=PORT): 769 769 """Create new instance. 770 770 … … 774 774 self.host = host or socket.getfqdn() 775 775 self.port = port 776 776 Base.__init__(self) 777 777 778 778 def getVia(self): 779 779 """Return value of Via header for this proxy.""" 780 780 return Via(host=self.host, port=self.port) … … 797 797 d.addErrback(lambda e: 798 798 self.deliverResponse(self.responseFromRequest(e.code, message)) 799 799 ) 800 800 801 801 def handle_request_default(self, message, (srcHost, srcPort)): 802 802 """Default request handler. 803 803 804 804 Default behaviour for OPTIONS and unknown methods for proxies 805 805 is to forward message on to the client. 806 806 … … 808 808 everything. 809 809 """ 810 810 def _mungContactHeader(uri, message): 811 message.headers['contact'][0] = uri.toString() 811 message.headers['contact'][0] = uri.toString() 812 812 return self.sendMessage(uri, message) 813 813 814 814 viaHeader = self.getVia() 815 815 if viaHeader.toString() in message.headers["via"]: 816 816 # must be a loop, so drop message … … 824 824 d = self.locator.getAddress(uri) 825 825 d.addCallback(self.sendMessage, message) 826 826 d.addErrback(self._cantForwardRequest, message) 827 827 828 828 def _cantForwardRequest(self, error, message): 829 829 error.trap(LookupError) 830 830 del message.headers["via"][0] # this'll be us 831 831 self.deliverResponse(self.responseFromRequest(404, message)) 832 832 833 833 def deliverResponse(self, responseMessage): 834 834 """Deliver response. 835 835 … … 838 838 # XXX we don't do multicast yet 839 839 host = destVia.received or destVia.host 840 840 port = destVia.rport or destVia.port or self.PORT 841 841 842 842 destAddr = URL(host=host, port=port) 843 843 self.sendMessage(destAddr, responseMessage) 844 844 … … 848 848 for name in ("via", "to", "from", "call-id", "cseq"): 849 849 response.headers[name] = request.headers.get(name, [])[:] 850 850 return response 851 851 852 852 def handle_response(self, message, addr): 853 853 """Default response handler.""" 854 854 v = parseViaHeader(message.headers["via"][0]) … … 864 864 self.gotResponse(message, addr) 865 865 return 866 866 self.deliverResponse(message) 867 867 868 868 def gotResponse(self, message, addr): 869 869 """Called with responses that are addressed at this server.""" 870 870 pass … … 872 872 class IAuthorizer(Interface): 873 873 def getChallenge(peer): 874 874 """Generate a challenge the client may respond to. 875 875 876 876 @type peer: C{tuple} 877 877 @param peer: The client's address 878 878 879 879 @rtype: C{str} 880 880 @return: The challenge string 881 881 """ 882 882 883 883 def decode(response): 884 884 """Create a credentials object from the given response. 885 885 886 886 @type response: C{str} 887 887 """ 888 888 889 889 class BasicAuthorizer: 890 890 """Authorizer for insecure Basic (base64-encoded plaintext) authentication. 891 891 892 892 This form of authentication is broken and insecure. Do not use it. 893 893 """ 894 894 895 895 implements(IAuthorizer) 896 896 897 897 def getChallenge(self, peer): 898 898 return None 899 899 900 900 def decode(self, response): 901 901 # At least one SIP client improperly pads its Base64 encoded messages 902 902 for i in range(3): … … 917 917 918 918 class DigestedCredentials(cred.credentials.UsernameHashedPassword): 919 919 """Yet Another Simple Digest-MD5 authentication scheme""" 920 920 921 921 def __init__(self, username, fields, challenges): 922 922 self.username = username 923 923 self.fields = fields 924 924 self.challenges = challenges 925 925 926 926 def checkPassword(self, password): 927 927 method = 'REGISTER' 928 928 response = self.fields.get('response') … … 937 937 if opaque not in self.challenges: 938 938 return False 939 939 del self.challenges[opaque] 940 940 941 941 user, domain = self.username.split('@', 1) 942 942 if uri is None: 943 943 uri = 'sip:' + domain … … 946 946 DigestCalcHA1(algo, user, domain, password, nonce, cnonce), 947 947 nonce, nc, cnonce, qop, method, uri, None, 948 948 ) 949 949 950 950 return expected == response 951 951 952 952 class DigestAuthorizer: 953 953 CHALLENGE_LIFETIME = 15 954 954 955 955 implements(IAuthorizer) 956 956 957 957 def __init__(self): 958 958 self.outstanding = {} 959 959 960 960 def generateNonce(self): 961 961 c = tuple([random.randrange(sys.maxint) for _ in range(3)]) 962 962 c = '%d%d%d' % c … … 975 975 'qop-options="auth"', 976 976 'algorithm="MD5"', 977 977 )) 978 978 979 979 def decode(self, response): 980 980 response = ' '.join(response.splitlines()) 981 981 parts = response.split(',') … … 1003 1003 authorizers = { 1004 1004 'digest': DigestAuthorizer(), 1005 1005 } 1006 1006 1007 1007 def __init__(self, *args, **kw): 1008 1008 Proxy.__init__(self, *args, **kw) 1009 1009 self.liveChallenges = {} 1010 1010 1011 1011 def handle_ACK_request(self, message, (host, port)): 1012 1012 # XXX 1013 1013 # ACKs are a client's way of indicating they got the last message … … 1042 1042 m.headers.setdefault('www-authenticate', []).append(value) 1043 1043 self.deliverResponse(m) 1044 1044 1045 1045 1046 1046 def login(self, message, host, port): 1047 1047 parts = message.headers['authorization'][0].split(None, 1) 1048 1048 a = self.authorizers.get(parts[0].lower()) … … 1067 1067 def _cbLogin(self, (i, a, l), message, host, port): 1068 1068 # It's stateless, matey. What a joke. 1069 1069 self.register(message, host, port) 1070 1070 1071 1071 def _ebLogin(self, failure, message, host, port): 1072 1072 failure.trap(cred.error.UnauthorizedLogin) 1073 1073 self.unauthorized(message, host, port) … … 1137 1137 """A simplistic registry for a specific domain.""" 1138 1138 1139 1139 implements(IRegistry, ILocator) 1140 1140 1141 1141 def __init__(self, domain): 1142 1142 self.domain = domain # the domain we handle registration for 1143 1143 self.users = {} # map username to (IDelayedCall for expiry, address URI) … … 1150 1150 return defer.succeed(url) 1151 1151 else: 1152 1152 return defer.fail(LookupError("no such user")) 1153 1153 1154 1154 def getRegistrationInfo(self, userURI): 1155 1155 if userURI.host != self.domain: 1156 1156 return defer.fail(LookupError("unknown domain")) … … 1159 1159 return defer.succeed(Registration(int(dc.getTime() - time.time()), url)) 1160 1160 else: 1161 1161 return defer.fail(LookupError("no such user")) 1162 1162 1163 1163 def _expireRegistration(self, username): 1164 1164 try: 1165 1165 dc, url = self.users[username] … … 1169 1169 dc.cancel() 1170 1170 del self.users[username] 1171 1171 return defer.succeed(Registration(0, url)) 1172 1172 1173 1173 def registerAddress(self, domainURL, logicalURL, physicalURL): 1174 1174 if domainURL.host != self.domain: 1175 1175 log.msg("Registration for domain we don't handle.") -
twisted/test/test_sip.py
155 155 self.validateMessage(l[0], "INVITE", "sip:foo", 156 156 {"from": ["mo"], "to": ["joe"], "content-length": ["4"]}, 157 157 "abcd") 158 158 159 159 def testSimpleResponse(self): 160 160 l = self.l 161 161 self.feedMessage(response1) … … 167 167 self.assertEquals(m.body, "") 168 168 self.assertEquals(m.finished, 1) 169 169 170 def testIncomplete(self): 171 # test for "aborted" request (body shorter than content-length) 172 l = self.l 173 self.feedMessage(request4[:-1]) 174 self.assertEquals(len(l), 2) 170 175 176 171 177 class MessageParsingTestCase2(MessageParsingTestCase): 172 178 """Same as base class, but feed data char by char.""" 173 179 … … 208 214 self.assertEquals(v1.transport, v2.transport) 209 215 self.assertEquals(v1.host, v2.host) 210 216 self.assertEquals(v1.port, v2.port) 211 217 212 218 def testComplex(self): 213 219 s = "SIP/2.0/UDP first.example.com:4000;ttl=16;maddr=224.2.0.1 ;branch=a7c6a8dlze (Example)" 214 220 v = sip.parseViaHeader(s) … … 222 228 self.assertEquals(v.toString(), 223 229 "SIP/2.0/UDP first.example.com:4000;ttl=16;branch=a7c6a8dlze;maddr=224.2.0.1") 224 230 self.checkRoundtrip(v) 225 231 226 232 def testSimple(self): 227 233 s = "SIP/2.0/UDP example.com;hidden" 228 234 v = sip.parseViaHeader(s) … … 236 242 self.assertEquals(v.toString(), 237 243 "SIP/2.0/UDP example.com:5060;hidden") 238 244 self.checkRoundtrip(v) 239 245 240 246 def testSimpler(self): 241 247 v = sip.Via("example.com") 242 248 self.checkRoundtrip(v) … … 253 259 self.assertEquals(v.port, 5060) 254 260 self.assertEquals(v.received, "22.13.1.5") 255 261 self.assertEquals(v.rport, 12345) 256 262 257 263 self.assertNotEquals(v.toString().find("rport=12345"), -1) 258 264 259 265 class URLTestCase(unittest.TestCase): … … 305 311 implements(sip.ILocator) 306 312 def getAddress(self, logicalURL): 307 313 return defer.fail(LookupError()) 308 309 314 315 310 316 class ProxyTestCase(unittest.TestCase): 311 317 312 318 def setUp(self): … … 314 320 self.proxy.locator = DummyLocator() 315 321 self.sent = [] 316 322 self.proxy.sendMessage = lambda dest, msg: self.sent.append((dest, msg)) 317 323 318 324 def testRequestForward(self): 319 325 r = sip.Request("INVITE", "sip:foo") 320 326 r.addHeader("via", sip.Via("1.2.3.4").toString()) … … 334 340 "SIP/2.0/UDP 1.2.3.4:5060", 335 341 "SIP/2.0/UDP 1.2.3.5:5060"]) 336 342 337 343 338 344 def testReceivedRequestForward(self): 339 345 r = sip.Request("INVITE", "sip:foo") 340 346 r.addHeader("via", sip.Via("1.2.3.4").toString()) … … 346 352 self.assertEquals(m.headers["via"], 347 353 ["SIP/2.0/UDP 127.0.0.1:5060", 348 354 "SIP/2.0/UDP 1.2.3.4:5060;received=1.1.1.1"]) 349 350 355 356 351 357 def testResponseWrongVia(self): 352 358 # first via must match proxy's address 353 359 r = sip.Response(200) 354 360 r.addHeader("via", sip.Via("foo.com").toString()) 355 361 self.proxy.datagramReceived(r.toString(), ("1.1.1.1", 5060)) 356 362 self.assertEquals(len(self.sent), 0) 357 363 358 364 def testResponseForward(self): 359 365 r = sip.Response(200) 360 366 r.addHeader("via", sip.Via("127.0.0.1").toString()) … … 365 371 self.assertEquals((dest.host, dest.port), ("client.com", 1234)) 366 372 self.assertEquals(m.code, 200) 367 373 self.assertEquals(m.headers["via"], ["SIP/2.0/UDP client.com:1234"]) 368 374 369 375 def testReceivedResponseForward(self): 370 376 r = sip.Response(200) 371 377 r.addHeader("via", sip.Via("127.0.0.1").toString()) … … 374 380 self.assertEquals(len(self.sent), 1) 375 381 dest, m = self.sent[0] 376 382 self.assertEquals((dest.host, dest.port), ("client.com", 5060)) 377 383 378 384 def testResponseToUs(self): 379 385 r = sip.Response(200) 380 386 r.addHeader("via", sip.Via("127.0.0.1").toString()) … … 385 391 m, addr = l[0] 386 392 self.assertEquals(len(m.headers.get("via", [])), 0) 387 393 self.assertEquals(m.code, 200) 388 394 389 395 def testLoop(self): 390 396 r = sip.Request("INVITE", "sip:foo") 391 r.addHeader("via", sip.Via("1.2.3.4").toString()) 397 r.addHeader("via", sip.Via("1.2.3.4").toString()) 392 398 r.addHeader("via", sip.Via("127.0.0.1").toString()) 393 399 self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) 394 400 self.assertEquals(self.sent, []) … … 431 437 r.addHeader("contact", "sip:joe@client.com:1234") 432 438 r.addHeader("via", sip.Via("client.com").toString()) 433 439 self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) 434 440 435 441 def unregister(self): 436 442 r = sip.Request("REGISTER", "sip:bell.example.com") 437 443 r.addHeader("to", "sip:joe@bell.example.com") … … 439 445 r.addHeader("via", sip.Via("client.com").toString()) 440 446 r.addHeader("expires", "0") 441 447 self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) 442 448 443 449 def testRegister(self): 444 450 self.register() 445 451 dest, m = self.sent[0] … … 482 488 def testFailedAuthentication(self): 483 489 self.addPortal() 484 490 self.register() 485 491 486 492 self.assertEquals(len(self.registry.users), 0) 487 493 self.assertEquals(len(self.sent), 1) 488 494 dest, m = self.sent[0] … … 500 506 r.addHeader("via", sip.Via("client.com").toString()) 501 507 r.addHeader("authorization", "Basic " + "userXname:passXword".encode('base64')) 502 508 self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) 503 509 504 510 self.assertEquals(len(self.registry.users), 1) 505 511 self.assertEquals(len(self.sent), 1) 506 512 dest, m = self.sent[0] 507 513 self.assertEquals(m.code, 200) 508 514 509 515 510 516 def testFailedBasicAuthentication(self): 511 517 self.addPortal() 512 518 self.proxy.authorizers = self.proxy.authorizers.copy() … … 518 524 r.addHeader("via", sip.Via("client.com").toString()) 519 525 r.addHeader("authorization", "Basic " + "userXname:password".encode('base64')) 520 526 self.proxy.datagramReceived(r.toString(), ("client.com", 5060)) 521 527 522 528 self.assertEquals(len(self.registry.users), 0) 523 529 self.assertEquals(len(self.sent), 1) 524 530 dest, m = self.sent[0] … … 546 552 d = self.proxy.locator.getAddress(url) 547 553 self.assertFailure(d, LookupError) 548 554 return d 549 555 550 556 def testNoContactLookup(self): 551 557 self.register() 552 558 url = sip.URL(username="jane", host="bell.example.com") … … 623 629 self.assertEquals(r.code, 200) 624 630 d.addCallback(check) 625 631 return d 626 627 632 633 628 634 registerRequest = """ 629 635 REGISTER sip:intarweb.us SIP/2.0\r 630 636 Via: SIP/2.0/UDP 192.168.1.100:50609\r … … 724 730 for d, uri in self.registry.users.values(): 725 731 d.cancel() 726 732 del self.proxy 727 733 728 734 def testChallenge(self): 729 735 self.proxy.datagramReceived(registerRequest, ("127.0.0.1", 5632)) 730 736 self.assertEquals(
