summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCamil Staps2016-05-30 17:43:40 +0200
committerCamil Staps2016-05-30 17:43:40 +0200
commitbbd1357b8d3cfde6dd129397fbe1df5e674b0447 (patch)
treec92bcfedbaf74b7f2a81e6b9b406c2c951a7740d
parentTest cases for the server; fix infinite loop in resolver (diff)
Last fixes; concurrency test for the server
-rw-r--r--project2/proj2_s4498062/dns/cache.py3
-rw-r--r--project2/proj2_s4498062/dns/server.py10
-rwxr-xr-xproject2/proj2_s4498062/dns_tests.py48
3 files changed, 55 insertions, 6 deletions
diff --git a/project2/proj2_s4498062/dns/cache.py b/project2/proj2_s4498062/dns/cache.py
index a8b62be..9e3a508 100644
--- a/project2/proj2_s4498062/dns/cache.py
+++ b/project2/proj2_s4498062/dns/cache.py
@@ -20,7 +20,7 @@ class ResourceEncoder(json.JSONEncoder):
Usage:
string = json.dumps(records, cls=ResourceEncoder, indent=4)
"""
- def default(self, obj):
+ def default(self, obj): # pylint: disable=method-hidden
if isinstance(obj, ResourceRecord):
return {
"name": obj.name,
@@ -90,6 +90,7 @@ class RecordCache(object):
if r.match(name=dname, type_=type_, class_=class_)]
def add_records_from(self, msg):
+ """Apply add_record to answers, authorities and additionals of msg"""
for record in msg.answers + msg.authorities + msg.additionals:
if record.type_ in [Type.A, Type.AAAA, Type.CNAME, Type.NS] and \
record.class_ == Class.IN:
diff --git a/project2/proj2_s4498062/dns/server.py b/project2/proj2_s4498062/dns/server.py
index 10cad8b..f1d33c1 100644
--- a/project2/proj2_s4498062/dns/server.py
+++ b/project2/proj2_s4498062/dns/server.py
@@ -19,7 +19,7 @@ from dns.resource import \
class RequestHandler(Thread):
""" A handler for requests to the DNS server """
- def __init__(self, skt, ttl, data, addr, zone):
+ def __init__(self, skt, ttl, data, addr, zone, resolv):
# pylint: disable=too-many-arguments
""" Initialize the handler thread """
super(RequestHandler, self).__init__()
@@ -29,11 +29,10 @@ class RequestHandler(Thread):
self.data = data
self.addr = addr
self.zone = zone
+ self.resolv = resolv
def run(self):
""" Run the handler thread """
- resolver = Resolver(True, self.ttl)
-
request = Message.from_bytes(self.data)
answs, adds, auths = [], [], []
@@ -44,7 +43,7 @@ class RequestHandler(Thread):
if rrs != []:
auths += rrs
elif req.qtype in [Type.A, Type.CNAME] and req.qclass == Class.IN:
- name, cnames, addrs = resolver.gethostbyname(req.qname)
+ name, cnames, addrs = self.resolv.gethostbyname(req.qname)
if name != req.qname:
answs.append(ResourceRecord(
str(req.qname), Type.CNAME, Class.IN, self.ttl,
@@ -86,6 +85,7 @@ class Server(object):
self.port = port
self.done = False
self.zone = []
+ self.resolv = Resolver(True, self.ttl)
self.skt = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
@@ -95,7 +95,7 @@ class Server(object):
while not self.done:
data, addr = self.skt.recvfrom(512)
reqh = RequestHandler(
- self.skt, self.ttl, data, addr, zone=self.zone)
+ self.skt, self.ttl, data, addr, self.zone, self.resolv)
reqh.start()
def shutdown(self):
diff --git a/project2/proj2_s4498062/dns_tests.py b/project2/proj2_s4498062/dns_tests.py
index 6a5a16e..fe4ffc2 100755
--- a/project2/proj2_s4498062/dns_tests.py
+++ b/project2/proj2_s4498062/dns_tests.py
@@ -3,6 +3,7 @@
# pylint: disable=too-many-public-methods, invalid-name
+import copy
from random import randint
import socket
import sys
@@ -143,6 +144,53 @@ class TestServer(unittest.TestCase):
elif record.type_ == Type.CNAME:
self.assertIn(record.rdata.data, aliases)
+ def test_concurrency(self):
+ """Test the server's concurrent abilities
+
+ Note: we can never be sure that the server handles these requests in
+ parallel. What we do is (1) sending a request for a domain outside the
+ zone, and (2) sending a request for inside the zone. We would expect
+ the latter to be quicker.
+ """
+ sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ sock.settimeout(self.TIMEOUT)
+
+ header = Header(0, 0, 1, 0, 0, 0)
+ header.qr = 0
+ header.opcode = 0
+ header.rd = 1
+
+ header.ident = 1
+ req1 = Message(header, [Question('camilstaps.nl', Type.A, Class.IN)])
+
+ header = copy.copy(header)
+ header.ident = 2
+ req2 = Message(header, [Question('cloogle.org', Type.A, Class.IN)])
+
+ sock.sendto(req1.to_bytes(), ('127.0.0.1', portnr))
+ sock.sendto(req2.to_bytes(), ('127.0.0.1', portnr))
+
+ try:
+ # The second request
+ data = sock.recv(512)
+ resp = Message.from_bytes(data)
+ self.assertEqual(resp.header.ident, 2)
+ self.assert_match(
+ resp.authorities[0],
+ 'cloogle.org', Type.A, Class.IN, '84.22.111.158')
+ self.assertEqual(resp.answers + resp.additionals, [])
+
+ # The first request
+ data = sock.recv(512)
+ resp = Message.from_bytes(data)
+ self.assertEqual(resp.header.ident, 1)
+ self.assert_match(
+ resp.answers[0],
+ 'camilstaps.nl', Type.A, Class.IN, '84.22.111.158')
+ self.assertEqual(resp.authorities + resp.additionals, [])
+ except socket.timeout:
+ self.fail('timeout')
+
if __name__ == "__main__":
# Parse command line arguments
import argparse