|
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,22 @@ 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 |
| 134 | + # nest eventloops. |
| 135 | + with concurrent.futures.ThreadPoolExecutor() as executor: |
| 136 | + future = executor.submit(run_async_in_thread, async_getaddrinfo(*args)) |
| 137 | + return future.result() |
136 | 138 |
|
137 | 139 | with self.waitfor('Opening connection to %s on port %s' % (self.rhost, self.rport)) as h: |
138 | 140 | hostnames = sync_getaddrinfo(self.rhost, self.rport, fam, typ, 0, socket.AI_PASSIVE) |
|
0 commit comments