|
2 | 2 | from __future__ import division
|
3 | 3 |
|
4 | 4 | import asyncio
|
| 5 | +import concurrent |
5 | 6 | import socket
|
6 | 7 | import socks
|
7 | 8 |
|
@@ -118,21 +119,21 @@ async def async_getaddrinfo(host, port, fam=0, typ=0, proto=0, flags=0):
|
118 | 119 | result = []
|
119 | 120 | return result
|
120 | 121 |
|
| 122 | + def run_async_in_thread(coro): |
| 123 | + loop = asyncio.new_event_loop() |
| 124 | + asyncio.set_event_loop(loop) |
| 125 | + future = loop.run_until_complete(coro) |
| 126 | + loop.close() |
| 127 | + return future |
| 128 | + |
121 | 129 | # Using asyncio to avoid blocking when DNS resolution fail. It's probably better
|
122 | 130 | # to use async all the ways to `sock.connect`. However, let's keep the changes
|
123 | 131 | # small until we have the needs.
|
124 | 132 | def sync_getaddrinfo(*args):
|
125 |
| - coro = async_getaddrinfo(*args) |
126 |
| - try: |
127 |
| - loop = asyncio.get_event_loop() |
128 |
| - if loop.is_running(): |
129 |
| - # If an event loop is already running, use it to run the async function |
130 |
| - future = asyncio.run_coroutine_threadsafe(coro, loop) |
131 |
| - return future.result() |
132 |
| - except RuntimeError: |
133 |
| - pass |
134 |
| - # If no event loop is running, create a new one |
135 |
| - return asyncio.run(coro) |
| 133 | + # Run in a a seperate thread to avoid deadlocks when users nest eventloops. |
| 134 | + with concurrent.futures.ThreadPoolExecutor() as executor: |
| 135 | + future = executor.submit(run_async_in_thread, async_getaddrinfo(*args)) |
| 136 | + return future.result() |
136 | 137 |
|
137 | 138 | with self.waitfor('Opening connection to %s on port %s' % (self.rhost, self.rport)) as h:
|
138 | 139 | hostnames = sync_getaddrinfo(self.rhost, self.rport, fam, typ, 0, socket.AI_PASSIVE)
|
|
0 commit comments