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.

_resolver.py 8.3KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. # -*- test-case-name: twisted.internet.test.test_resolver -*-
  2. # Copyright (c) Twisted Matrix Laboratories.
  3. # See LICENSE for details.
  4. """
  5. IPv6-aware hostname resolution.
  6. @see: L{IHostnameResolver}
  7. """
  8. from socket import (
  9. AF_INET,
  10. AF_INET6,
  11. AF_UNSPEC,
  12. SOCK_DGRAM,
  13. SOCK_STREAM,
  14. gaierror,
  15. getaddrinfo,
  16. )
  17. from zope.interface import implementer
  18. from twisted.internet._idna import _idnaBytes
  19. from twisted.internet.address import IPv4Address, IPv6Address
  20. from twisted.internet.defer import Deferred
  21. from twisted.internet.error import DNSLookupError
  22. from twisted.internet.interfaces import (
  23. IHostnameResolver,
  24. IHostResolution,
  25. IResolutionReceiver,
  26. IResolverSimple,
  27. )
  28. from twisted.internet.threads import deferToThreadPool
  29. from twisted.logger import Logger
  30. from twisted.python.compat import nativeString
  31. @implementer(IHostResolution)
  32. class HostResolution:
  33. """
  34. The in-progress resolution of a given hostname.
  35. """
  36. def __init__(self, name):
  37. """
  38. Create a L{HostResolution} with the given name.
  39. """
  40. self.name = name
  41. def cancel(self):
  42. # IHostResolution.cancel
  43. raise NotImplementedError()
  44. _any = frozenset([IPv4Address, IPv6Address])
  45. _typesToAF = {
  46. frozenset([IPv4Address]): AF_INET,
  47. frozenset([IPv6Address]): AF_INET6,
  48. _any: AF_UNSPEC,
  49. }
  50. _afToType = {
  51. AF_INET: IPv4Address,
  52. AF_INET6: IPv6Address,
  53. }
  54. _transportToSocket = {
  55. "TCP": SOCK_STREAM,
  56. "UDP": SOCK_DGRAM,
  57. }
  58. _socktypeToType = {
  59. SOCK_STREAM: "TCP",
  60. SOCK_DGRAM: "UDP",
  61. }
  62. @implementer(IHostnameResolver)
  63. class GAIResolver:
  64. """
  65. L{IHostnameResolver} implementation that resolves hostnames by calling
  66. L{getaddrinfo} in a thread.
  67. """
  68. def __init__(self, reactor, getThreadPool=None, getaddrinfo=getaddrinfo):
  69. """
  70. Create a L{GAIResolver}.
  71. @param reactor: the reactor to schedule result-delivery on
  72. @type reactor: L{IReactorThreads}
  73. @param getThreadPool: a function to retrieve the thread pool to use for
  74. scheduling name resolutions. If not supplied, the use the given
  75. C{reactor}'s thread pool.
  76. @type getThreadPool: 0-argument callable returning a
  77. L{twisted.python.threadpool.ThreadPool}
  78. @param getaddrinfo: a reference to the L{getaddrinfo} to use - mainly
  79. parameterized for testing.
  80. @type getaddrinfo: callable with the same signature as L{getaddrinfo}
  81. """
  82. self._reactor = reactor
  83. self._getThreadPool = (
  84. reactor.getThreadPool if getThreadPool is None else getThreadPool
  85. )
  86. self._getaddrinfo = getaddrinfo
  87. def resolveHostName(
  88. self,
  89. resolutionReceiver,
  90. hostName,
  91. portNumber=0,
  92. addressTypes=None,
  93. transportSemantics="TCP",
  94. ):
  95. """
  96. See L{IHostnameResolver.resolveHostName}
  97. @param resolutionReceiver: see interface
  98. @param hostName: see interface
  99. @param portNumber: see interface
  100. @param addressTypes: see interface
  101. @param transportSemantics: see interface
  102. @return: see interface
  103. """
  104. pool = self._getThreadPool()
  105. addressFamily = _typesToAF[
  106. _any if addressTypes is None else frozenset(addressTypes)
  107. ]
  108. socketType = _transportToSocket[transportSemantics]
  109. def get():
  110. try:
  111. return self._getaddrinfo(
  112. hostName, portNumber, addressFamily, socketType
  113. )
  114. except gaierror:
  115. return []
  116. d = deferToThreadPool(self._reactor, pool, get)
  117. resolution = HostResolution(hostName)
  118. resolutionReceiver.resolutionBegan(resolution)
  119. @d.addCallback
  120. def deliverResults(result):
  121. for family, socktype, proto, cannoname, sockaddr in result:
  122. addrType = _afToType[family]
  123. resolutionReceiver.addressResolved(
  124. addrType(_socktypeToType.get(socktype, "TCP"), *sockaddr)
  125. )
  126. resolutionReceiver.resolutionComplete()
  127. return resolution
  128. @implementer(IHostnameResolver)
  129. class SimpleResolverComplexifier:
  130. """
  131. A converter from L{IResolverSimple} to L{IHostnameResolver}.
  132. """
  133. _log = Logger()
  134. def __init__(self, simpleResolver):
  135. """
  136. Construct a L{SimpleResolverComplexifier} with an L{IResolverSimple}.
  137. """
  138. self._simpleResolver = simpleResolver
  139. def resolveHostName(
  140. self,
  141. resolutionReceiver,
  142. hostName,
  143. portNumber=0,
  144. addressTypes=None,
  145. transportSemantics="TCP",
  146. ):
  147. """
  148. See L{IHostnameResolver.resolveHostName}
  149. @param resolutionReceiver: see interface
  150. @param hostName: see interface
  151. @param portNumber: see interface
  152. @param addressTypes: see interface
  153. @param transportSemantics: see interface
  154. @return: see interface
  155. """
  156. # If it's str, we need to make sure that it's just ASCII.
  157. try:
  158. hostName = hostName.encode("ascii")
  159. except UnicodeEncodeError:
  160. # If it's not just ASCII, IDNA it. We don't want to give a Unicode
  161. # string with non-ASCII in it to Python 3, as if anyone passes that
  162. # to a Python 3 stdlib function, it will probably use the wrong
  163. # IDNA version and break absolutely everything
  164. hostName = _idnaBytes(hostName)
  165. # Make sure it's passed down as a native str, to maintain the interface
  166. hostName = nativeString(hostName)
  167. resolution = HostResolution(hostName)
  168. resolutionReceiver.resolutionBegan(resolution)
  169. onAddress = self._simpleResolver.getHostByName(hostName)
  170. def addressReceived(address):
  171. resolutionReceiver.addressResolved(IPv4Address("TCP", address, portNumber))
  172. def errorReceived(error):
  173. if not error.check(DNSLookupError):
  174. self._log.failure(
  175. "while looking up {name} with {resolver}",
  176. error,
  177. name=hostName,
  178. resolver=self._simpleResolver,
  179. )
  180. onAddress.addCallbacks(addressReceived, errorReceived)
  181. def finish(result):
  182. resolutionReceiver.resolutionComplete()
  183. onAddress.addCallback(finish)
  184. return resolution
  185. @implementer(IResolutionReceiver)
  186. class FirstOneWins:
  187. """
  188. An L{IResolutionReceiver} which fires a L{Deferred} with its first result.
  189. """
  190. def __init__(self, deferred):
  191. """
  192. @param deferred: The L{Deferred} to fire when the first resolution
  193. result arrives.
  194. """
  195. self._deferred = deferred
  196. self._resolved = False
  197. def resolutionBegan(self, resolution):
  198. """
  199. See L{IResolutionReceiver.resolutionBegan}
  200. @param resolution: See L{IResolutionReceiver.resolutionBegan}
  201. """
  202. self._resolution = resolution
  203. def addressResolved(self, address):
  204. """
  205. See L{IResolutionReceiver.addressResolved}
  206. @param address: See L{IResolutionReceiver.addressResolved}
  207. """
  208. if self._resolved:
  209. return
  210. self._resolved = True
  211. self._deferred.callback(address.host)
  212. def resolutionComplete(self):
  213. """
  214. See L{IResolutionReceiver.resolutionComplete}
  215. """
  216. if self._resolved:
  217. return
  218. self._deferred.errback(DNSLookupError(self._resolution.name))
  219. @implementer(IResolverSimple)
  220. class ComplexResolverSimplifier:
  221. """
  222. A converter from L{IHostnameResolver} to L{IResolverSimple}
  223. """
  224. def __init__(self, nameResolver):
  225. """
  226. Create a L{ComplexResolverSimplifier} with an L{IHostnameResolver}.
  227. @param nameResolver: The L{IHostnameResolver} to use.
  228. """
  229. self._nameResolver = nameResolver
  230. def getHostByName(self, name, timeouts=()):
  231. """
  232. See L{IResolverSimple.getHostByName}
  233. @param name: see L{IResolverSimple.getHostByName}
  234. @param timeouts: see L{IResolverSimple.getHostByName}
  235. @return: see L{IResolverSimple.getHostByName}
  236. """
  237. result = Deferred()
  238. self._nameResolver.resolveHostName(FirstOneWins(result), name, 0, [IPv4Address])
  239. return result