You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294
  1. # -*- test-case-name: twisted.test.test_sip -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. Session Initialization Protocol.
  6. Documented in RFC 2543.
  7. [Superseded by 3261]
  8. """
  9. import socket
  10. import time
  11. import warnings
  12. from zope.interface import implementer, Interface
  13. from collections import OrderedDict
  14. from twisted import cred
  15. from twisted.internet import protocol, defer, reactor
  16. from twisted.protocols import basic
  17. from twisted.python import log
  18. from twisted.python.compat import _PY3, iteritems, unicode
  19. PORT = 5060
  20. # SIP headers have short forms
  21. shortHeaders = {"call-id": "i",
  22. "contact": "m",
  23. "content-encoding": "e",
  24. "content-length": "l",
  25. "content-type": "c",
  26. "from": "f",
  27. "subject": "s",
  28. "to": "t",
  29. "via": "v",
  30. }
  31. longHeaders = {}
  32. for k, v in shortHeaders.items():
  33. longHeaders[v] = k
  34. del k, v
  35. statusCodes = {
  36. 100: "Trying",
  37. 180: "Ringing",
  38. 181: "Call Is Being Forwarded",
  39. 182: "Queued",
  40. 183: "Session Progress",
  41. 200: "OK",
  42. 300: "Multiple Choices",
  43. 301: "Moved Permanently",
  44. 302: "Moved Temporarily",
  45. 303: "See Other",
  46. 305: "Use Proxy",
  47. 380: "Alternative Service",
  48. 400: "Bad Request",
  49. 401: "Unauthorized",
  50. 402: "Payment Required",
  51. 403: "Forbidden",
  52. 404: "Not Found",
  53. 405: "Method Not Allowed",
  54. 406: "Not Acceptable",
  55. 407: "Proxy Authentication Required",
  56. 408: "Request Timeout",
  57. 409: "Conflict", # Not in RFC3261
  58. 410: "Gone",
  59. 411: "Length Required", # Not in RFC3261
  60. 413: "Request Entity Too Large",
  61. 414: "Request-URI Too Large",
  62. 415: "Unsupported Media Type",
  63. 416: "Unsupported URI Scheme",
  64. 420: "Bad Extension",
  65. 421: "Extension Required",
  66. 423: "Interval Too Brief",
  67. 480: "Temporarily Unavailable",
  68. 481: "Call/Transaction Does Not Exist",
  69. 482: "Loop Detected",
  70. 483: "Too Many Hops",
  71. 484: "Address Incomplete",
  72. 485: "Ambiguous",
  73. 486: "Busy Here",
  74. 487: "Request Terminated",
  75. 488: "Not Acceptable Here",
  76. 491: "Request Pending",
  77. 493: "Undecipherable",
  78. 500: "Internal Server Error",
  79. 501: "Not Implemented",
  80. 502: "Bad Gateway", # No donut
  81. 503: "Service Unavailable",
  82. 504: "Server Time-out",
  83. 505: "SIP Version not supported",
  84. 513: "Message Too Large",
  85. 600: "Busy Everywhere",
  86. 603: "Decline",
  87. 604: "Does not exist anywhere",
  88. 606: "Not Acceptable",
  89. }
  90. specialCases = {
  91. 'cseq': 'CSeq',
  92. 'call-id': 'Call-ID',
  93. 'www-authenticate': 'WWW-Authenticate',
  94. }
  95. def dashCapitalize(s):
  96. """
  97. Capitalize a string, making sure to treat '-' as a word separator
  98. """
  99. return '-'.join([ x.capitalize() for x in s.split('-')])
  100. def unq(s):
  101. if s[0] == s[-1] == '"':
  102. return s[1:-1]
  103. return s
  104. _absent = object()
  105. class Via(object):
  106. """
  107. A L{Via} is a SIP Via header, representing a segment of the path taken by
  108. the request.
  109. See RFC 3261, sections 8.1.1.7, 18.2.2, and 20.42.
  110. @ivar transport: Network protocol used for this leg. (Probably either "TCP"
  111. or "UDP".)
  112. @type transport: C{str}
  113. @ivar branch: Unique identifier for this request.
  114. @type branch: C{str}
  115. @ivar host: Hostname or IP for this leg.
  116. @type host: C{str}
  117. @ivar port: Port used for this leg.
  118. @type port C{int}, or None.
  119. @ivar rportRequested: Whether to request RFC 3581 client processing or not.
  120. @type rportRequested: C{bool}
  121. @ivar rportValue: Servers wishing to honor requests for RFC 3581 processing
  122. should set this parameter to the source port the request was received
  123. from.
  124. @type rportValue: C{int}, or None.
  125. @ivar ttl: Time-to-live for requests on multicast paths.
  126. @type ttl: C{int}, or None.
  127. @ivar maddr: The destination multicast address, if any.
  128. @type maddr: C{str}, or None.
  129. @ivar hidden: Obsolete in SIP 2.0.
  130. @type hidden: C{bool}
  131. @ivar otherParams: Any other parameters in the header.
  132. @type otherParams: C{dict}
  133. """
  134. def __init__(self, host, port=PORT, transport="UDP", ttl=None,
  135. hidden=False, received=None, rport=_absent, branch=None,
  136. maddr=None, **kw):
  137. """
  138. Set parameters of this Via header. All arguments correspond to
  139. attributes of the same name.
  140. To maintain compatibility with old SIP
  141. code, the 'rport' argument is used to determine the values of
  142. C{rportRequested} and C{rportValue}. If None, C{rportRequested} is set
  143. to True. (The deprecated method for doing this is to pass True.) If an
  144. integer, C{rportValue} is set to the given value.
  145. Any arguments not explicitly named here are collected into the
  146. C{otherParams} dict.
  147. """
  148. self.transport = transport
  149. self.host = host
  150. self.port = port
  151. self.ttl = ttl
  152. self.hidden = hidden
  153. self.received = received
  154. if rport is True:
  155. warnings.warn(
  156. "rport=True is deprecated since Twisted 9.0.",
  157. DeprecationWarning,
  158. stacklevel=2)
  159. self.rportValue = None
  160. self.rportRequested = True
  161. elif rport is None:
  162. self.rportValue = None
  163. self.rportRequested = True
  164. elif rport is _absent:
  165. self.rportValue = None
  166. self.rportRequested = False
  167. else:
  168. self.rportValue = rport
  169. self.rportRequested = False
  170. self.branch = branch
  171. self.maddr = maddr
  172. self.otherParams = kw
  173. def _getrport(self):
  174. """
  175. Returns the rport value expected by the old SIP code.
  176. """
  177. if self.rportRequested == True:
  178. return True
  179. elif self.rportValue is not None:
  180. return self.rportValue
  181. else:
  182. return None
  183. def _setrport(self, newRPort):
  184. """
  185. L{Base._fixupNAT} sets C{rport} directly, so this method sets
  186. C{rportValue} based on that.
  187. @param newRPort: The new rport value.
  188. @type newRPort: C{int}
  189. """
  190. self.rportValue = newRPort
  191. self.rportRequested = False
  192. rport = property(_getrport, _setrport)
  193. def toString(self):
  194. """
  195. Serialize this header for use in a request or response.
  196. """
  197. s = "SIP/2.0/%s %s:%s" % (self.transport, self.host, self.port)
  198. if self.hidden:
  199. s += ";hidden"
  200. for n in "ttl", "branch", "maddr", "received":
  201. value = getattr(self, n)
  202. if value is not None:
  203. s += ";%s=%s" % (n, value)
  204. if self.rportRequested:
  205. s += ";rport"
  206. elif self.rportValue is not None:
  207. s += ";rport=%s" % (self.rport,)
  208. etc = sorted(self.otherParams.items())
  209. for k, v in etc:
  210. if v is None:
  211. s += ";" + k
  212. else:
  213. s += ";%s=%s" % (k, v)
  214. return s
  215. def parseViaHeader(value):
  216. """
  217. Parse a Via header.
  218. @return: The parsed version of this header.
  219. @rtype: L{Via}
  220. """
  221. parts = value.split(";")
  222. sent, params = parts[0], parts[1:]
  223. protocolinfo, by = sent.split(" ", 1)
  224. by = by.strip()
  225. result = {}
  226. pname, pversion, transport = protocolinfo.split("/")
  227. if pname != "SIP" or pversion != "2.0":
  228. raise ValueError("wrong protocol or version: %r" % (value,))
  229. result["transport"] = transport
  230. if ":" in by:
  231. host, port = by.split(":")
  232. result["port"] = int(port)
  233. result["host"] = host
  234. else:
  235. result["host"] = by
  236. for p in params:
  237. # It's the comment-striping dance!
  238. p = p.strip().split(" ", 1)
  239. if len(p) == 1:
  240. p, comment = p[0], ""
  241. else:
  242. p, comment = p
  243. if p == "hidden":
  244. result["hidden"] = True
  245. continue
  246. parts = p.split("=", 1)
  247. if len(parts) == 1:
  248. name, value = parts[0], None
  249. else:
  250. name, value = parts
  251. if name in ("rport", "ttl"):
  252. value = int(value)
  253. result[name] = value
  254. return Via(**result)
  255. class URL:
  256. """
  257. A SIP URL.
  258. """
  259. def __init__(self, host, username=None, password=None, port=None,
  260. transport=None, usertype=None, method=None,
  261. ttl=None, maddr=None, tag=None, other=None, headers=None):
  262. self.username = username
  263. self.host = host
  264. self.password = password
  265. self.port = port
  266. self.transport = transport
  267. self.usertype = usertype
  268. self.method = method
  269. self.tag = tag
  270. self.ttl = ttl
  271. self.maddr = maddr
  272. if other == None:
  273. self.other = []
  274. else:
  275. self.other = other
  276. if headers == None:
  277. self.headers = {}
  278. else:
  279. self.headers = headers
  280. def toString(self):
  281. l = []; w = l.append
  282. w("sip:")
  283. if self.username != None:
  284. w(self.username)
  285. if self.password != None:
  286. w(":%s" % self.password)
  287. w("@")
  288. w(self.host)
  289. if self.port != None:
  290. w(":%d" % self.port)
  291. if self.usertype != None:
  292. w(";user=%s" % self.usertype)
  293. for n in ("transport", "ttl", "maddr", "method", "tag"):
  294. v = getattr(self, n)
  295. if v != None:
  296. w(";%s=%s" % (n, v))
  297. for v in self.other:
  298. w(";%s" % v)
  299. if self.headers:
  300. w("?")
  301. w("&".join([("%s=%s" % (specialCases.get(h) or dashCapitalize(h), v)) for (h, v) in self.headers.items()]))
  302. return "".join(l)
  303. def __str__(self):
  304. return self.toString()
  305. def __repr__(self):
  306. return '<URL %s:%s@%s:%r/%s>' % (self.username, self.password, self.host, self.port, self.transport)
  307. def parseURL(url, host=None, port=None):
  308. """
  309. Return string into URL object.
  310. URIs are of form 'sip:user@example.com'.
  311. """
  312. d = {}
  313. if not url.startswith("sip:"):
  314. raise ValueError("unsupported scheme: " + url[:4])
  315. parts = url[4:].split(";")
  316. userdomain, params = parts[0], parts[1:]
  317. udparts = userdomain.split("@", 1)
  318. if len(udparts) == 2:
  319. userpass, hostport = udparts
  320. upparts = userpass.split(":", 1)
  321. if len(upparts) == 1:
  322. d["username"] = upparts[0]
  323. else:
  324. d["username"] = upparts[0]
  325. d["password"] = upparts[1]
  326. else:
  327. hostport = udparts[0]
  328. hpparts = hostport.split(":", 1)
  329. if len(hpparts) == 1:
  330. d["host"] = hpparts[0]
  331. else:
  332. d["host"] = hpparts[0]
  333. d["port"] = int(hpparts[1])
  334. if host != None:
  335. d["host"] = host
  336. if port != None:
  337. d["port"] = port
  338. for p in params:
  339. if p == params[-1] and "?" in p:
  340. d["headers"] = h = {}
  341. p, headers = p.split("?", 1)
  342. for header in headers.split("&"):
  343. k, v = header.split("=")
  344. h[k] = v
  345. nv = p.split("=", 1)
  346. if len(nv) == 1:
  347. d.setdefault("other", []).append(p)
  348. continue
  349. name, value = nv
  350. if name == "user":
  351. d["usertype"] = value
  352. elif name in ("transport", "ttl", "maddr", "method", "tag"):
  353. if name == "ttl":
  354. value = int(value)
  355. d[name] = value
  356. else:
  357. d.setdefault("other", []).append(p)
  358. return URL(**d)
  359. def cleanRequestURL(url):
  360. """
  361. Clean a URL from a Request line.
  362. """
  363. url.transport = None
  364. url.maddr = None
  365. url.ttl = None
  366. url.headers = {}
  367. def parseAddress(address, host=None, port=None, clean=0):
  368. """
  369. Return (name, uri, params) for From/To/Contact header.
  370. @param clean: remove unnecessary info, usually for From and To headers.
  371. """
  372. address = address.strip()
  373. # Simple 'sip:foo' case
  374. if address.startswith("sip:"):
  375. return "", parseURL(address, host=host, port=port), {}
  376. params = {}
  377. name, url = address.split("<", 1)
  378. name = name.strip()
  379. if name.startswith('"'):
  380. name = name[1:]
  381. if name.endswith('"'):
  382. name = name[:-1]
  383. url, paramstring = url.split(">", 1)
  384. url = parseURL(url, host=host, port=port)
  385. paramstring = paramstring.strip()
  386. if paramstring:
  387. for l in paramstring.split(";"):
  388. if not l:
  389. continue
  390. k, v = l.split("=")
  391. params[k] = v
  392. if clean:
  393. # RFC 2543 6.21
  394. url.ttl = None
  395. url.headers = {}
  396. url.transport = None
  397. url.maddr = None
  398. return name, url, params
  399. class SIPError(Exception):
  400. def __init__(self, code, phrase=None):
  401. if phrase is None:
  402. phrase = statusCodes[code]
  403. Exception.__init__(self, "SIP error (%d): %s" % (code, phrase))
  404. self.code = code
  405. self.phrase = phrase
  406. class RegistrationError(SIPError):
  407. """
  408. Registration was not possible.
  409. """
  410. class Message:
  411. """
  412. A SIP message.
  413. """
  414. length = None
  415. def __init__(self):
  416. self.headers = OrderedDict() # Map name to list of values
  417. self.body = ""
  418. self.finished = 0
  419. def addHeader(self, name, value):
  420. name = name.lower()
  421. name = longHeaders.get(name, name)
  422. if name == "content-length":
  423. self.length = int(value)
  424. self.headers.setdefault(name,[]).append(value)
  425. def bodyDataReceived(self, data):
  426. self.body += data
  427. def creationFinished(self):
  428. if (self.length != None) and (self.length != len(self.body)):
  429. raise ValueError("wrong body length")
  430. self.finished = 1
  431. def toString(self):
  432. s = "%s\r\n" % self._getHeaderLine()
  433. for n, vs in self.headers.items():
  434. for v in vs:
  435. s += "%s: %s\r\n" % (specialCases.get(n) or dashCapitalize(n), v)
  436. s += "\r\n"
  437. s += self.body
  438. return s
  439. def _getHeaderLine(self):
  440. raise NotImplementedError
  441. class Request(Message):
  442. """
  443. A Request for a URI
  444. """
  445. def __init__(self, method, uri, version="SIP/2.0"):
  446. Message.__init__(self)
  447. self.method = method
  448. if isinstance(uri, URL):
  449. self.uri = uri
  450. else:
  451. self.uri = parseURL(uri)
  452. cleanRequestURL(self.uri)
  453. def __repr__(self):
  454. return "<SIP Request %d:%s %s>" % (id(self), self.method, self.uri.toString())
  455. def _getHeaderLine(self):
  456. return "%s %s SIP/2.0" % (self.method, self.uri.toString())
  457. class Response(Message):
  458. """
  459. A Response to a URI Request
  460. """
  461. def __init__(self, code, phrase=None, version="SIP/2.0"):
  462. Message.__init__(self)
  463. self.code = code
  464. if phrase == None:
  465. phrase = statusCodes[code]
  466. self.phrase = phrase
  467. def __repr__(self):
  468. return "<SIP Response %d:%s>" % (id(self), self.code)
  469. def _getHeaderLine(self):
  470. return "SIP/2.0 %s %s" % (self.code, self.phrase)
  471. class MessagesParser(basic.LineReceiver):
  472. """
  473. A SIP messages parser.
  474. Expects dataReceived, dataDone repeatedly,
  475. in that order. Shouldn't be connected to actual transport.
  476. """
  477. version = "SIP/2.0"
  478. acceptResponses = 1
  479. acceptRequests = 1
  480. state = "firstline" # Or "headers", "body" or "invalid"
  481. debug = 0
  482. def __init__(self, messageReceivedCallback):
  483. self.messageReceived = messageReceivedCallback
  484. self.reset()
  485. def reset(self, remainingData=""):
  486. self.state = "firstline"
  487. self.length = None # Body length
  488. self.bodyReceived = 0 # How much of the body we received
  489. self.message = None
  490. self.header = None
  491. self.setLineMode(remainingData)
  492. def invalidMessage(self):
  493. self.state = "invalid"
  494. self.setRawMode()
  495. def dataDone(self):
  496. """
  497. Clear out any buffered data that may be hanging around.
  498. """
  499. self.clearLineBuffer()
  500. if self.state == "firstline":
  501. return
  502. if self.state != "body":
  503. self.reset()
  504. return
  505. if self.length == None:
  506. # No content-length header, so end of data signals message done
  507. self.messageDone()
  508. elif self.length < self.bodyReceived:
  509. # Aborted in the middle
  510. self.reset()
  511. else:
  512. # We have enough data and message wasn't finished? something is wrong
  513. raise RuntimeError("this should never happen")
  514. def dataReceived(self, data):
  515. try:
  516. if isinstance(data, unicode):
  517. data = data.encode("utf-8")
  518. basic.LineReceiver.dataReceived(self, data)
  519. except:
  520. log.err()
  521. self.invalidMessage()
  522. def handleFirstLine(self, line):
  523. """
  524. Expected to create self.message.
  525. """
  526. raise NotImplementedError
  527. def lineLengthExceeded(self, line):
  528. self.invalidMessage()
  529. def lineReceived(self, line):
  530. if _PY3 and isinstance(line, bytes):
  531. line = line.decode("utf-8")
  532. if self.state == "firstline":
  533. while line.startswith("\n") or line.startswith("\r"):
  534. line = line[1:]
  535. if not line:
  536. return
  537. try:
  538. a, b, c = line.split(" ", 2)
  539. except ValueError:
  540. self.invalidMessage()
  541. return
  542. if a == "SIP/2.0" and self.acceptResponses:
  543. # Response
  544. try:
  545. code = int(b)
  546. except ValueError:
  547. self.invalidMessage()
  548. return
  549. self.message = Response(code, c)
  550. elif c == "SIP/2.0" and self.acceptRequests:
  551. self.message = Request(a, b)
  552. else:
  553. self.invalidMessage()
  554. return
  555. self.state = "headers"
  556. return
  557. else:
  558. assert self.state == "headers"
  559. if line:
  560. # Multiline header
  561. if line.startswith(" ") or line.startswith("\t"):
  562. name, value = self.header
  563. self.header = name, (value + line.lstrip())
  564. else:
  565. # New header
  566. if self.header:
  567. self.message.addHeader(*self.header)
  568. self.header = None
  569. try:
  570. name, value = line.split(":", 1)
  571. except ValueError:
  572. self.invalidMessage()
  573. return
  574. self.header = name, value.lstrip()
  575. # XXX we assume content-length won't be multiline
  576. if name.lower() == "content-length":
  577. try:
  578. self.length = int(value.lstrip())
  579. except ValueError:
  580. self.invalidMessage()
  581. return
  582. else:
  583. # CRLF, we now have message body until self.length bytes,
  584. # or if no length was given, until there is no more data
  585. # from the connection sending us data.
  586. self.state = "body"
  587. if self.header:
  588. self.message.addHeader(*self.header)
  589. self.header = None
  590. if self.length == 0:
  591. self.messageDone()
  592. return
  593. self.setRawMode()
  594. def messageDone(self, remainingData=""):
  595. assert self.state == "body"
  596. self.message.creationFinished()
  597. self.messageReceived(self.message)
  598. self.reset(remainingData)
  599. def rawDataReceived(self, data):
  600. assert self.state in ("body", "invalid")
  601. if _PY3 and isinstance(data, bytes):
  602. data = data.decode("utf-8")
  603. if self.state == "invalid":
  604. return
  605. if self.length == None:
  606. self.message.bodyDataReceived(data)
  607. else:
  608. dataLen = len(data)
  609. expectedLen = self.length - self.bodyReceived
  610. if dataLen > expectedLen:
  611. self.message.bodyDataReceived(data[:expectedLen])
  612. self.messageDone(data[expectedLen:])
  613. return
  614. else:
  615. self.bodyReceived += dataLen
  616. self.message.bodyDataReceived(data)
  617. if self.bodyReceived == self.length:
  618. self.messageDone()
  619. class Base(protocol.DatagramProtocol):
  620. """
  621. Base class for SIP clients and servers.
  622. """
  623. PORT = PORT
  624. debug = False
  625. def __init__(self):
  626. self.messages = []
  627. self.parser = MessagesParser(self.addMessage)
  628. def addMessage(self, msg):
  629. self.messages.append(msg)
  630. def datagramReceived(self, data, addr):
  631. self.parser.dataReceived(data)
  632. self.parser.dataDone()
  633. for m in self.messages:
  634. self._fixupNAT(m, addr)
  635. if self.debug:
  636. log.msg("Received %r from %r" % (m.toString(), addr))
  637. if isinstance(m, Request):
  638. self.handle_request(m, addr)
  639. else:
  640. self.handle_response(m, addr)
  641. self.messages[:] = []
  642. def _fixupNAT(self, message, sourcePeer):
  643. # RFC 2543 6.40.2,
  644. (srcHost, srcPort) = sourcePeer
  645. senderVia = parseViaHeader(message.headers["via"][0])
  646. if senderVia.host != srcHost:
  647. senderVia.received = srcHost
  648. if senderVia.port != srcPort:
  649. senderVia.rport = srcPort
  650. message.headers["via"][0] = senderVia.toString()
  651. elif senderVia.rport == True:
  652. senderVia.received = srcHost
  653. senderVia.rport = srcPort
  654. message.headers["via"][0] = senderVia.toString()
  655. def deliverResponse(self, responseMessage):
  656. """
  657. Deliver response.
  658. Destination is based on topmost Via header.
  659. """
  660. destVia = parseViaHeader(responseMessage.headers["via"][0])
  661. # XXX we don't do multicast yet
  662. host = destVia.received or destVia.host
  663. port = destVia.rport or destVia.port or self.PORT
  664. destAddr = URL(host=host, port=port)
  665. self.sendMessage(destAddr, responseMessage)
  666. def responseFromRequest(self, code, request):
  667. """
  668. Create a response to a request message.
  669. """
  670. response = Response(code)
  671. for name in ("via", "to", "from", "call-id", "cseq"):
  672. response.headers[name] = request.headers.get(name, [])[:]
  673. return response
  674. def sendMessage(self, destURL, message):
  675. """
  676. Send a message.
  677. @param destURL: C{URL}. This should be a *physical* URL, not a logical one.
  678. @param message: The message to send.
  679. """
  680. if destURL.transport not in ("udp", None):
  681. raise RuntimeError("only UDP currently supported")
  682. if self.debug:
  683. log.msg("Sending %r to %r" % (message.toString(), destURL))
  684. data = message.toString()
  685. if isinstance(data, unicode):
  686. data = data.encode("utf-8")
  687. self.transport.write(data, (destURL.host, destURL.port or self.PORT))
  688. def handle_request(self, message, addr):
  689. """
  690. Override to define behavior for requests received
  691. @type message: C{Message}
  692. @type addr: C{tuple}
  693. """
  694. raise NotImplementedError
  695. def handle_response(self, message, addr):
  696. """
  697. Override to define behavior for responses received.
  698. @type message: C{Message}
  699. @type addr: C{tuple}
  700. """
  701. raise NotImplementedError
  702. class IContact(Interface):
  703. """
  704. A user of a registrar or proxy
  705. """
  706. class Registration:
  707. def __init__(self, secondsToExpiry, contactURL):
  708. self.secondsToExpiry = secondsToExpiry
  709. self.contactURL = contactURL
  710. class IRegistry(Interface):
  711. """
  712. Allows registration of logical->physical URL mapping.
  713. """
  714. def registerAddress(domainURL, logicalURL, physicalURL):
  715. """
  716. Register the physical address of a logical URL.
  717. @return: Deferred of C{Registration} or failure with RegistrationError.
  718. """
  719. def unregisterAddress(domainURL, logicalURL, physicalURL):
  720. """
  721. Unregister the physical address of a logical URL.
  722. @return: Deferred of C{Registration} or failure with RegistrationError.
  723. """
  724. def getRegistrationInfo(logicalURL):
  725. """
  726. Get registration info for logical URL.
  727. @return: Deferred of C{Registration} object or failure of LookupError.
  728. """
  729. class ILocator(Interface):
  730. """
  731. Allow looking up physical address for logical URL.
  732. """
  733. def getAddress(logicalURL):
  734. """
  735. Return physical URL of server for logical URL of user.
  736. @param logicalURL: a logical C{URL}.
  737. @return: Deferred which becomes URL or fails with LookupError.
  738. """
  739. class Proxy(Base):
  740. """
  741. SIP proxy.
  742. """
  743. PORT = PORT
  744. locator = None # Object implementing ILocator
  745. def __init__(self, host=None, port=PORT):
  746. """
  747. Create new instance.
  748. @param host: our hostname/IP as set in Via headers.
  749. @param port: our port as set in Via headers.
  750. """
  751. self.host = host or socket.getfqdn()
  752. self.port = port
  753. Base.__init__(self)
  754. def getVia(self):
  755. """
  756. Return value of Via header for this proxy.
  757. """
  758. return Via(host=self.host, port=self.port)
  759. def handle_request(self, message, addr):
  760. # Send immediate 100/trying message before processing
  761. #self.deliverResponse(self.responseFromRequest(100, message))
  762. f = getattr(self, "handle_%s_request" % message.method, None)
  763. if f is None:
  764. f = self.handle_request_default
  765. try:
  766. d = f(message, addr)
  767. except SIPError as e:
  768. self.deliverResponse(self.responseFromRequest(e.code, message))
  769. except:
  770. log.err()
  771. self.deliverResponse(self.responseFromRequest(500, message))
  772. else:
  773. if d is not None:
  774. d.addErrback(lambda e:
  775. self.deliverResponse(self.responseFromRequest(e.code, message))
  776. )
  777. def handle_request_default(self, message, sourcePeer):
  778. """
  779. Default request handler.
  780. Default behaviour for OPTIONS and unknown methods for proxies
  781. is to forward message on to the client.
  782. Since at the moment we are stateless proxy, that's basically
  783. everything.
  784. """
  785. (srcHost, srcPort) = sourcePeer
  786. def _mungContactHeader(uri, message):
  787. message.headers['contact'][0] = uri.toString()
  788. return self.sendMessage(uri, message)
  789. viaHeader = self.getVia()
  790. if viaHeader.toString() in message.headers["via"]:
  791. # Must be a loop, so drop message
  792. log.msg("Dropping looped message.")
  793. return
  794. message.headers["via"].insert(0, viaHeader.toString())
  795. name, uri, tags = parseAddress(message.headers["to"][0], clean=1)
  796. # This is broken and needs refactoring to use cred
  797. d = self.locator.getAddress(uri)
  798. d.addCallback(self.sendMessage, message)
  799. d.addErrback(self._cantForwardRequest, message)
  800. def _cantForwardRequest(self, error, message):
  801. error.trap(LookupError)
  802. del message.headers["via"][0] # This'll be us
  803. self.deliverResponse(self.responseFromRequest(404, message))
  804. def deliverResponse(self, responseMessage):
  805. """
  806. Deliver response.
  807. Destination is based on topmost Via header.
  808. """
  809. destVia = parseViaHeader(responseMessage.headers["via"][0])
  810. # XXX we don't do multicast yet
  811. host = destVia.received or destVia.host
  812. port = destVia.rport or destVia.port or self.PORT
  813. destAddr = URL(host=host, port=port)
  814. self.sendMessage(destAddr, responseMessage)
  815. def responseFromRequest(self, code, request):
  816. """
  817. Create a response to a request message.
  818. """
  819. response = Response(code)
  820. for name in ("via", "to", "from", "call-id", "cseq"):
  821. response.headers[name] = request.headers.get(name, [])[:]
  822. return response
  823. def handle_response(self, message, addr):
  824. """
  825. Default response handler.
  826. """
  827. v = parseViaHeader(message.headers["via"][0])
  828. if (v.host, v.port) != (self.host, self.port):
  829. # We got a message not intended for us?
  830. # XXX note this check breaks if we have multiple external IPs
  831. # yay for suck protocols
  832. log.msg("Dropping incorrectly addressed message")
  833. return
  834. del message.headers["via"][0]
  835. if not message.headers["via"]:
  836. # This message is addressed to us
  837. self.gotResponse(message, addr)
  838. return
  839. self.deliverResponse(message)
  840. def gotResponse(self, message, addr):
  841. """
  842. Called with responses that are addressed at this server.
  843. """
  844. pass
  845. class IAuthorizer(Interface):
  846. def getChallenge(peer):
  847. """
  848. Generate a challenge the client may respond to.
  849. @type peer: C{tuple}
  850. @param peer: The client's address
  851. @rtype: C{str}
  852. @return: The challenge string
  853. """
  854. def decode(response):
  855. """
  856. Create a credentials object from the given response.
  857. @type response: C{str}
  858. """
  859. class RegisterProxy(Proxy):
  860. """
  861. A proxy that allows registration for a specific domain.
  862. Unregistered users won't be handled.
  863. """
  864. portal = None
  865. registry = None # Should implement IRegistry
  866. authorizers = {}
  867. def __init__(self, *args, **kw):
  868. Proxy.__init__(self, *args, **kw)
  869. self.liveChallenges = {}
  870. def handle_ACK_request(self, message, host_port):
  871. # XXX
  872. # ACKs are a client's way of indicating they got the last message
  873. # Responding to them is not a good idea.
  874. # However, we should keep track of terminal messages and re-transmit
  875. # if no ACK is received.
  876. (host, port) = host_port
  877. pass
  878. def handle_REGISTER_request(self, message, host_port):
  879. """
  880. Handle a registration request.
  881. Currently registration is not proxied.
  882. """
  883. (host, port) = host_port
  884. if self.portal is None:
  885. # There is no portal. Let anyone in.
  886. self.register(message, host, port)
  887. else:
  888. # There is a portal. Check for credentials.
  889. if "authorization" not in message.headers:
  890. return self.unauthorized(message, host, port)
  891. else:
  892. return self.login(message, host, port)
  893. def unauthorized(self, message, host, port):
  894. m = self.responseFromRequest(401, message)
  895. for (scheme, auth) in iteritems(self.authorizers):
  896. chal = auth.getChallenge((host, port))
  897. if chal is None:
  898. value = '%s realm="%s"' % (scheme.title(), self.host)
  899. else:
  900. value = '%s %s,realm="%s"' % (scheme.title(), chal, self.host)
  901. m.headers.setdefault('www-authenticate', []).append(value)
  902. self.deliverResponse(m)
  903. def login(self, message, host, port):
  904. parts = message.headers['authorization'][0].split(None, 1)
  905. a = self.authorizers.get(parts[0].lower())
  906. if a:
  907. try:
  908. c = a.decode(parts[1])
  909. except SIPError:
  910. raise
  911. except:
  912. log.err()
  913. self.deliverResponse(self.responseFromRequest(500, message))
  914. else:
  915. c.username += '@' + self.host
  916. self.portal.login(c, None, IContact
  917. ).addCallback(self._cbLogin, message, host, port
  918. ).addErrback(self._ebLogin, message, host, port
  919. ).addErrback(log.err
  920. )
  921. else:
  922. self.deliverResponse(self.responseFromRequest(501, message))
  923. def _cbLogin(self, i_a_l, message, host, port):
  924. # It's stateless, matey. What a joke.
  925. (i, a, l) = i_a_l
  926. self.register(message, host, port)
  927. def _ebLogin(self, failure, message, host, port):
  928. failure.trap(cred.error.UnauthorizedLogin)
  929. self.unauthorized(message, host, port)
  930. def register(self, message, host, port):
  931. """
  932. Allow all users to register
  933. """
  934. name, toURL, params = parseAddress(message.headers["to"][0], clean=1)
  935. contact = None
  936. if "contact" in message.headers:
  937. contact = message.headers["contact"][0]
  938. if message.headers.get("expires", [None])[0] == "0":
  939. self.unregister(message, toURL, contact)
  940. else:
  941. # XXX Check expires on appropriate URL, and pass it to registry
  942. # instead of having registry hardcode it.
  943. if contact is not None:
  944. name, contactURL, params = parseAddress(contact, host=host, port=port)
  945. d = self.registry.registerAddress(message.uri, toURL, contactURL)
  946. else:
  947. d = self.registry.getRegistrationInfo(toURL)
  948. d.addCallbacks(self._cbRegister, self._ebRegister,
  949. callbackArgs=(message,),
  950. errbackArgs=(message,)
  951. )
  952. def _cbRegister(self, registration, message):
  953. response = self.responseFromRequest(200, message)
  954. if registration.contactURL != None:
  955. response.addHeader("contact", registration.contactURL.toString())
  956. response.addHeader("expires", "%d" % registration.secondsToExpiry)
  957. response.addHeader("content-length", "0")
  958. self.deliverResponse(response)
  959. def _ebRegister(self, error, message):
  960. error.trap(RegistrationError, LookupError)
  961. # XXX return error message, and alter tests to deal with
  962. # this, currently tests assume no message sent on failure
  963. def unregister(self, message, toURL, contact):
  964. try:
  965. expires = int(message.headers["expires"][0])
  966. except ValueError:
  967. self.deliverResponse(self.responseFromRequest(400, message))
  968. else:
  969. if expires == 0:
  970. if contact == "*":
  971. contactURL = "*"
  972. else:
  973. name, contactURL, params = parseAddress(contact)
  974. d = self.registry.unregisterAddress(message.uri, toURL, contactURL)
  975. d.addCallback(self._cbUnregister, message
  976. ).addErrback(self._ebUnregister, message
  977. )
  978. def _cbUnregister(self, registration, message):
  979. msg = self.responseFromRequest(200, message)
  980. msg.headers.setdefault('contact', []).append(registration.contactURL.toString())
  981. msg.addHeader("expires", "0")
  982. self.deliverResponse(msg)
  983. def _ebUnregister(self, registration, message):
  984. pass
  985. @implementer(IRegistry, ILocator)
  986. class InMemoryRegistry:
  987. """
  988. A simplistic registry for a specific domain.
  989. """
  990. def __init__(self, domain):
  991. self.domain = domain # The domain we handle registration for
  992. self.users = {} # Map username to (IDelayedCall for expiry, address URI)
  993. def getAddress(self, userURI):
  994. if userURI.host != self.domain:
  995. return defer.fail(LookupError("unknown domain"))
  996. if userURI.username in self.users:
  997. dc, url = self.users[userURI.username]
  998. return defer.succeed(url)
  999. else:
  1000. return defer.fail(LookupError("no such user"))
  1001. def getRegistrationInfo(self, userURI):
  1002. if userURI.host != self.domain:
  1003. return defer.fail(LookupError("unknown domain"))
  1004. if userURI.username in self.users:
  1005. dc, url = self.users[userURI.username]
  1006. return defer.succeed(Registration(int(dc.getTime() - time.time()), url))
  1007. else:
  1008. return defer.fail(LookupError("no such user"))
  1009. def _expireRegistration(self, username):
  1010. try:
  1011. dc, url = self.users[username]
  1012. except KeyError:
  1013. return defer.fail(LookupError("no such user"))
  1014. else:
  1015. dc.cancel()
  1016. del self.users[username]
  1017. return defer.succeed(Registration(0, url))
  1018. def registerAddress(self, domainURL, logicalURL, physicalURL):
  1019. if domainURL.host != self.domain:
  1020. log.msg("Registration for domain we don't handle.")
  1021. return defer.fail(RegistrationError(404))
  1022. if logicalURL.host != self.domain:
  1023. log.msg("Registration for domain we don't handle.")
  1024. return defer.fail(RegistrationError(404))
  1025. if logicalURL.username in self.users:
  1026. dc, old = self.users[logicalURL.username]
  1027. dc.reset(3600)
  1028. else:
  1029. dc = reactor.callLater(3600, self._expireRegistration, logicalURL.username)
  1030. log.msg("Registered %s at %s" % (logicalURL.toString(), physicalURL.toString()))
  1031. self.users[logicalURL.username] = (dc, physicalURL)
  1032. return defer.succeed(Registration(int(dc.getTime() - time.time()), physicalURL))
  1033. def unregisterAddress(self, domainURL, logicalURL, physicalURL):
  1034. return self._expireRegistration(logicalURL.username)