Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
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.

sip.py 37KB

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