address.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. """
  4. Address objects for network connections.
  5. """
  6. from __future__ import division, absolute_import
  7. import attr
  8. import warnings, os
  9. from zope.interface import implementer
  10. from twisted.internet.interfaces import IAddress
  11. from twisted.python.filepath import _asFilesystemBytes
  12. from twisted.python.filepath import _coerceToFilesystemEncoding
  13. from twisted.python.runtime import platform
  14. from twisted.python.compat import _PY3
  15. @implementer(IAddress)
  16. @attr.s(hash=True)
  17. class IPv4Address(object):
  18. """
  19. An L{IPv4Address} represents the address of an IPv4 socket endpoint.
  20. @ivar type: A string describing the type of transport, either 'TCP' or
  21. 'UDP'.
  22. @ivar host: A string containing a dotted-quad IPv4 address; for example,
  23. "127.0.0.1".
  24. @type host: C{str}
  25. @ivar port: An integer representing the port number.
  26. @type port: C{int}
  27. """
  28. type = attr.ib(validator=attr.validators.in_(["TCP", "UDP"]))
  29. host = attr.ib()
  30. port = attr.ib()
  31. @implementer(IAddress)
  32. @attr.s(hash=True)
  33. class IPv6Address(object):
  34. """
  35. An L{IPv6Address} represents the address of an IPv6 socket endpoint.
  36. @ivar type: A string describing the type of transport, either 'TCP' or
  37. 'UDP'.
  38. @ivar host: A string containing a colon-separated, hexadecimal formatted
  39. IPv6 address; for example, "::1".
  40. @type host: C{str}
  41. @ivar port: An integer representing the port number.
  42. @type port: C{int}
  43. @ivar flowInfo: the IPv6 flow label. This can be used by QoS routers to
  44. identify flows of traffic; you may generally safely ignore it.
  45. @type flowInfo: L{int}
  46. @ivar scopeID: the IPv6 scope identifier - roughly analagous to what
  47. interface traffic destined for this address must be transmitted over.
  48. @type scopeID: L{int} or L{str}
  49. """
  50. type = attr.ib(validator=attr.validators.in_(["TCP", "UDP"]))
  51. host = attr.ib()
  52. port = attr.ib()
  53. flowInfo = attr.ib(default=0)
  54. scopeID = attr.ib(default=0)
  55. @implementer(IAddress)
  56. class _ProcessAddress(object):
  57. """
  58. An L{interfaces.IAddress} provider for process transports.
  59. """
  60. @attr.s(hash=True)
  61. @implementer(IAddress)
  62. class HostnameAddress(object):
  63. """
  64. A L{HostnameAddress} represents the address of a L{HostnameEndpoint}.
  65. @ivar hostname: A hostname byte string; for example, b"example.com".
  66. @type hostname: L{bytes}
  67. @ivar port: An integer representing the port number.
  68. @type port: L{int}
  69. """
  70. hostname = attr.ib()
  71. port = attr.ib()
  72. @attr.s(hash=False, repr=False, eq=False)
  73. @implementer(IAddress)
  74. class UNIXAddress(object):
  75. """
  76. Object representing a UNIX socket endpoint.
  77. @ivar name: The filename associated with this socket.
  78. @type name: C{bytes}
  79. """
  80. name = attr.ib(converter=attr.converters.optional(_asFilesystemBytes))
  81. if getattr(os.path, 'samefile', None) is not None:
  82. def __eq__(self, other):
  83. """
  84. Overriding C{attrs} to ensure the os level samefile
  85. check is done if the name attributes do not match.
  86. """
  87. if isinstance(other, self.__class__):
  88. res = self.name == other.name
  89. else:
  90. return False
  91. if not res and self.name and other.name:
  92. try:
  93. return os.path.samefile(self.name, other.name)
  94. except OSError:
  95. pass
  96. except (TypeError, ValueError) as e:
  97. # On Linux, abstract namespace UNIX sockets start with a
  98. # \0, which os.path doesn't like.
  99. if not _PY3 and not platform.isLinux():
  100. raise e
  101. return res
  102. else:
  103. def __eq__(self, other):
  104. if isinstance(other, self.__class__):
  105. return self.name == other.name
  106. return False
  107. def __ne__(self, other):
  108. if isinstance(other, self.__class__):
  109. return not self.__eq__(other)
  110. return True
  111. def __repr__(self):
  112. name = self.name
  113. if name:
  114. name = _coerceToFilesystemEncoding('', self.name)
  115. return 'UNIXAddress(%r)' % (name,)
  116. def __hash__(self):
  117. if self.name is None:
  118. return hash((self.__class__, None))
  119. try:
  120. s1 = os.stat(self.name)
  121. return hash((s1.st_ino, s1.st_dev))
  122. except OSError:
  123. return hash(self.name)
  124. # These are for buildFactory backwards compatibility due to
  125. # stupidity-induced inconsistency.
  126. class _ServerFactoryIPv4Address(IPv4Address):
  127. """Backwards compatibility hack. Just like IPv4Address in practice."""
  128. def __eq__(self, other):
  129. if isinstance(other, tuple):
  130. warnings.warn("IPv4Address.__getitem__ is deprecated. Use attributes instead.",
  131. category=DeprecationWarning, stacklevel=2)
  132. return (self.host, self.port) == other
  133. elif isinstance(other, IPv4Address):
  134. a = (self.type, self.host, self.port)
  135. b = (other.type, other.host, other.port)
  136. return a == b
  137. return False