1
0

HostIP.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. # a very simple (and silly) mechanism for getting the host_ip
  2. import socket
  3. from BTL.platform import bttime
  4. from BTL.obsoletepythonsupport import set
  5. from BTL.reactor_magic import reactor
  6. from BTL import defer
  7. import BTL.stackthreading as threading
  8. from twisted.internet.protocol import ClientFactory, Protocol
  9. from twisted.protocols.policies import TimeoutMixin
  10. try:
  11. from BTL.iphelp import get_route_ip
  12. except:
  13. get_route_ip = None
  14. import thread
  15. _host_ip = 'unknown'
  16. _host_ip_callbacks = []
  17. _host_ip_cachetime = 0
  18. _host_ips = None
  19. _host_ips_cachetime = 0
  20. _thread_running = False
  21. CACHE_TIME = 3600 # hour
  22. wrap_task = reactor.callFromThread
  23. class RecorderProtocol(TimeoutMixin, Protocol):
  24. def makeConnection(self, transport):
  25. self.setTimeout(20)
  26. Protocol.makeConnection(self, transport)
  27. def connectionMade(self):
  28. _got_result(self.transport.getHost().host)
  29. self.transport.write("GET /myip HTTP/1.0\r\n\r\n")
  30. self.transport.loseConnection()
  31. def connectionLost(self, reason):
  32. _got_result(None)
  33. class RecorderFactory(ClientFactory):
  34. def clientConnectionFailed(self, connector, reason):
  35. _got_result(None)
  36. def _resolve():
  37. try:
  38. ip = socket.gethostbyname(socket.gethostname())
  39. except socket.error, e:
  40. ip = 'unknown'
  41. reactor.callFromThread(_got_result, ip)
  42. def _finish(ip):
  43. global _thread_running
  44. _thread_running = False
  45. _got_result(ip)
  46. def _got_result(ip):
  47. global _host_ip
  48. global _host_ip_callbacks
  49. global _host_ip_cachetime
  50. global _thread_running
  51. if hasattr(reactor, 'ident'):
  52. assert reactor.ident == thread.get_ident()
  53. if _thread_running:
  54. return
  55. if ip is None:
  56. t = threading.Thread(target=_resolve)
  57. t.setDaemon(True)
  58. _thread_running = True
  59. t.start()
  60. return
  61. if ip is not 'unknown':
  62. _host_ip = ip
  63. _host_ip_cachetime = bttime()
  64. l = _host_ip_callbacks
  65. _host_ip_callbacks = []
  66. for df in l:
  67. df.callback(_host_ip)
  68. def get_deferred_host_ip():
  69. global _host_ip
  70. global _host_ip_callbacks
  71. global _host_ip_cachetime
  72. if hasattr(reactor, 'ident'):
  73. assert reactor.ident == thread.get_ident()
  74. if _host_ip is not 'unknown' and _host_ip_cachetime + CACHE_TIME > bttime():
  75. return defer.succeed(_host_ip)
  76. if get_route_ip:
  77. ip = get_route_ip()
  78. if ip:
  79. _host_ip = ip
  80. _host_ip_cachetime = bttime()
  81. return defer.succeed(_host_ip)
  82. df = defer.Deferred()
  83. if not _host_ip_callbacks:
  84. def connect(ip):
  85. factory = RecorderFactory()
  86. factory.protocol = RecorderProtocol
  87. if hasattr(reactor, 'limiter'):
  88. reactor.connectTCP(ip, 80, factory, urgent=True)
  89. else:
  90. reactor.connectTCP(ip, 80, factory)
  91. rdf = reactor.resolve("ip.bittorrent.com")
  92. rdf.addCallback(connect)
  93. rdf.addErrback(lambda e : _got_result(None))
  94. _host_ip_callbacks.append(df)
  95. return df
  96. def get_host_ip():
  97. """ Blocking version, do not use from reactor thread! """
  98. global _host_ip
  99. global _host_ip_callbacks
  100. global _host_ip_cachetime
  101. if hasattr(reactor, 'ident'):
  102. assert reactor.ident != thread.get_ident()
  103. if _host_ip is not 'unknown' and _host_ip_cachetime + CACHE_TIME > bttime():
  104. return _host_ip
  105. if get_route_ip:
  106. ip = get_route_ip()
  107. if ip:
  108. _host_ip = ip
  109. _host_ip_cachetime = bttime()
  110. return _host_ip
  111. try:
  112. s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  113. s.settimeout(5)
  114. # what moron decided to make try/except/finally not work?
  115. # Guido van Rossum.
  116. try:
  117. s.connect(("ip.bittorrent.com", 80))
  118. endpoint = s.getsockname()
  119. _host_ip = endpoint[0]
  120. _host_ip_cachetime = bttime()
  121. s.send("GET /myip HTTP/1.0\r\n\r\n")
  122. except (socket.error, socket.timeout), e:
  123. try:
  124. _host_ip = socket.gethostbyname(socket.gethostname())
  125. except socket.error, e:
  126. pass
  127. try:
  128. s.close()
  129. except:
  130. pass
  131. except:
  132. pass
  133. return _host_ip
  134. def get_deferred_host_ips():
  135. global _host_ips
  136. global _host_ips_cachetime
  137. if hasattr(reactor, 'ident'):
  138. assert reactor.ident == thread.get_ident()
  139. if _host_ips is not None and _host_ips_cachetime + CACHE_TIME > bttime():
  140. return defer.succeed(_host_ips)
  141. df = get_deferred_host_ip()
  142. finaldf = defer.Deferred()
  143. df.addCallback(_get_deferred_host_ips2, finaldf)
  144. return finaldf
  145. def _get_deferred_host_ips2(host_ip, finaldf):
  146. if hasattr(reactor, 'ident'):
  147. assert reactor.ident == thread.get_ident()
  148. df = defer.ThreadedDeferred(wrap_task, _get_deferred_host_ips3,
  149. host_ip, daemon=True)
  150. df.chainDeferred(finaldf)
  151. def _get_deferred_host_ips3(host_ip):
  152. global _host_ips
  153. global _host_ips_cachetime
  154. if hasattr(reactor, 'ident'):
  155. assert reactor.ident != thread.get_ident()
  156. l = set()
  157. if host_ip is not 'unknown':
  158. l.add(host_ip)
  159. try:
  160. hostname = socket.gethostname()
  161. hostname, aliaslist, ipaddrlist = socket.gethostbyname_ex(hostname)
  162. l.update(ipaddrlist)
  163. except socket.error, e:
  164. print "ARG", e
  165. _host_ips = l
  166. _host_ips_cachetime = bttime()
  167. return _host_ips
  168. def get_host_ips():
  169. return _get_deferred_host_ips3(get_host_ip())