Browse Source

(refactor) No need for separate task to respond to requests

main
Michal Charemza 5 years ago
parent
commit
9cdfe8679f
No known key found for this signature in database GPG Key ID: 4BBAF0F6B73C4363
1 changed files with 8 additions and 49 deletions
  1. +8
    -49
      dnsrewriteproxy.py

+ 8
- 49
dnsrewriteproxy.py View File

@@ -43,7 +43,7 @@ def get_logger_default():
def DnsProxy(
get_resolver=get_resolver_default, get_logger=get_logger_default,
get_socket=get_socket_default,
num_workers=1000, downstream_queue_maxsize=10000, upstream_queue_maxsize=10000,
num_workers=1000, upstream_queue_maxsize=10000,
rules=(),
):

@@ -61,20 +61,12 @@ def DnsProxy(
# workers

async def server_worker(sock, resolve):
downstream_queue = Queue(maxsize=downstream_queue_maxsize)
upstream_queue = Queue(maxsize=upstream_queue_maxsize)

# It would "usually" be ok to send downstream from multiple tasks, but
# if the socket has a full buffer, it would raise a BlockingIOError,
# and we will need to attach a reader. We can only attach one reader
# per underlying file, and since we have a single socket, we have a
# single file. So we send downstream from a single task
downstream_worker_task = create_task(downstream_worker(sock, downstream_queue))

# We have multiple upstream workers to be able to send multiple
# requests upstream concurrently, and add responses to downstream_queue
upstream_worker_tasks = [
create_task(upstream_worker(resolve, upstream_queue, downstream_queue))
create_task(upstream_worker(sock, resolve, upstream_queue))
for _ in range(0, num_workers)]

try:
@@ -82,50 +74,31 @@ def DnsProxy(
request_data, addr = await recvfrom(loop, [sock], 512)
await upstream_queue.put((request_data, addr))
finally:
# Finish upstream requests, which can add to to the downstream
# queue
# Finish upstream requests
await upstream_queue.join()
for upstream_task in upstream_worker_tasks:
upstream_task.cancel()

# Ensure we have sent the responses downstream
await downstream_queue.join()
downstream_worker_task.cancel()

# Wait for the tasks to really be finished
for upstream_task in upstream_worker_tasks:
try:
await upstream_task
except Exception:
pass
try:
await downstream_worker_task
except Exception:
pass

async def upstream_worker(resolve, upstream_queue, downstream_queue):
async def upstream_worker(sock, resolve, upstream_queue):
while True:
request_data, addr = await upstream_queue.get()

try:
response_data = await get_response_data(resolve, request_data)
# Sendto for non-blocking UDP sockets cannot raise a BlockingIOError
# https://stackoverflow.com/a/59794872/1319998
sock.sendto(response_data, addr)
except Exception:
logger.exception('Exception from handler_request_data %s', addr)
continue
else:
await downstream_queue.put((response_data, addr))
logger.exception('Processing request from %s', addr)
finally:
upstream_queue.task_done()

async def downstream_worker(sock, downstream_queue):
while True:
response_data, addr = await downstream_queue.get()
try:
await sendto(sock, response_data, addr)
except Exception:
logger.exception('Unable to send response to %s', addr)
downstream_queue.task_done()

async def get_response_data(resolve, request_data):
# This may raise an exception, which is handled at a higher level.
# We can't [and I suspect shouldn't try to] return an error to the
@@ -206,17 +179,3 @@ def error(query, rcode):
qid=query.qid, qr=RESPONSE, opcode=0, aa=0, tc=0, rd=0, ra=1, z=0, rcode=rcode,
qd=query.qd, an=(), ns=(), ar=(),
)


async def sendto(sock, data, addr):
# In our cases, the UDP responses will always be 512 bytes or less.
# Even if sendto sent some of the data, there is no way for the other
# end to reconstruct their order, so we don't include any logic to send
# the rest of the data. Since it's UDP, the client already has to have
# retry logic.
#
# Potentially also, this can raise a BlockingIOError, but even trying
# to force high numbers of messages with a small socket buffer, this has
# never been observed. As above, the client must have retry logic, so we
# leave it to the client to deal with this.
return sock.sendto(data, addr)

Loading…
Cancel
Save