diff --git a/coapthon/client/coap.py b/coapthon/client/coap.py index 5cfa41c..919429c 100644 --- a/coapthon/client/coap.py +++ b/coapthon/client/coap.py @@ -75,7 +75,7 @@ class CoAP(object): event.set() if self._receiver_thread is not None: self._receiver_thread.join() - self._socket.close() + # self._socket.close() @property def current_mid(self): @@ -290,6 +290,7 @@ class CoAP(object): self._messageLayer.receive_empty(message) logger.debug("Exiting receiver Thread due to request") + self._socket.close() def _send_ack(self, transaction): """ diff --git a/coapthon/defines.py b/coapthon/defines.py index 9b081ea..094d001 100644 --- a/coapthon/defines.py +++ b/coapthon/defines.py @@ -124,6 +124,7 @@ class OptionRegistry(object): LOCATION_QUERY = OptionItem(20,"Location-Query",STRING, True, None) BLOCK2 = OptionItem(23, "Block2", INTEGER, False, None) BLOCK1 = OptionItem(27, "Block1", INTEGER, False, None) + SIZE2 = OptionItem(28, "Size2", INTEGER, False, None) PROXY_URI = OptionItem(35, "Proxy-Uri", STRING, False, None) PROXY_SCHEME = OptionItem(39, "Proxy-Schema", STRING, False, None) SIZE1 = OptionItem(60, "Size1", INTEGER, False, None) @@ -147,6 +148,7 @@ class OptionRegistry(object): 20: LOCATION_QUERY, 23: BLOCK2, 27: BLOCK1, + 28: SIZE2, 35: PROXY_URI, 39: PROXY_SCHEME, 60: SIZE1, diff --git a/coapthon/forward_proxy/coap.py b/coapthon/forward_proxy/coap.py index 654a165..922405f 100644 --- a/coapthon/forward_proxy/coap.py +++ b/coapthon/forward_proxy/coap.py @@ -88,19 +88,24 @@ class CoAP(object): # Allow multiple copies of this program on one machine # (not strictly needed) self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self._socket.bind((defines.ALL_COAP_NODES, self.server_address[1])) + self._socket.bind(('', self.server_address[1])) + mreq = struct.pack("4sl", socket.inet_aton(defines.ALL_COAP_NODES), socket.INADDR_ANY) self._socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) self._unicast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._unicast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._unicast_socket.bind(self.server_address) else: + # Bugfix for Python 3.6 for Windows ... missing IPPROTO_IPV6 constant + if not hasattr(socket, 'IPPROTO_IPV6'): + socket.IPPROTO_IPV6 = 41 + self._socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # Allow multiple copies of this program on one machine # (not strictly needed) self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self._socket.bind((defines.ALL_COAP_NODES_IPV6, self.server_address[1])) + self._socket.bind(('', self.server_address[1])) addrinfo_multicast = socket.getaddrinfo(defines.ALL_COAP_NODES_IPV6, 5683)[0] group_bin = socket.inet_pton(socket.AF_INET6, addrinfo_multicast[4][0]) @@ -159,7 +164,7 @@ class CoAP(object): self.stopped.set() for event in self.to_be_stopped: event.set() - self._socket.close() + # self._socket.close() def receive_datagram(self, args): """ diff --git a/coapthon/layers/blocklayer.py b/coapthon/layers/blocklayer.py index 8f698a3..afbed89 100644 --- a/coapthon/layers/blocklayer.py +++ b/coapthon/layers/blocklayer.py @@ -67,7 +67,11 @@ class BlockLayer(object): host, port = transaction.request.source key_token = hash(str(host) + str(port) + str(transaction.request.token)) num, m, size = transaction.request.block1 + if transaction.request.size1 is not None: + # What to do if the size1 is larger than the maximum resource size or the maxium server buffer + pass if key_token in self._block1_receive: + # n-th block content_type = transaction.request.content_type if num != self._block1_receive[key_token].num \ or content_type != self._block1_receive[key_token].content_type: @@ -145,6 +149,8 @@ class BlockLayer(object): else: item.m = 1 request.block1 = (item.num, item.m, item.size) + # The original request already has this option set + # request.size1 = len(item.payload) elif transaction.response.block2 is not None: num, m, size = transaction.response.block2 @@ -225,10 +231,13 @@ class BlockLayer(object): self._block2_receive[key_token] = BlockItem(byte, num, m, size) - if len(transaction.response.payload) > (byte + size): - m = 1 - else: - m = 0 + # correct m + m = 0 if ((num * size) + size) > len(transaction.response.payload) else 1 + # add size2 if requested or if payload is bigger than one datagram + del transaction.response.size2 + if (transaction.request.size2 is not None and transaction.request.size2 == 0) or \ + (transaction.response.payload is not None and len(transaction.response.payload) > defines.MAX_PAYLOAD): + transaction.response.size2 = len(transaction.response.payload) transaction.response.payload = transaction.response.payload[byte:byte + size] del transaction.response.block2 transaction.response.block2 = (num, m, size) @@ -258,7 +267,10 @@ class BlockLayer(object): num = 0 m = 1 size = defines.MAX_PAYLOAD - + # correct m + m = 0 if ((num * size) + size) > len(request.payload) else 1 + del request.size1 + request.size1 = len(request.payload) self._block1_sent[key_token] = BlockItem(size, num, m, size, request.payload, request.content_type) request.payload = request.payload[0:size] del request.block1 diff --git a/coapthon/messages/message.py b/coapthon/messages/message.py index c7aa32f..d678227 100644 --- a/coapthon/messages/message.py +++ b/coapthon/messages/message.py @@ -641,6 +641,44 @@ class Message(object): """ self.del_option_by_number(defines.OptionRegistry.BLOCK2.number) + @property + def size1(self): + value = None + for option in self.options: + if option.number == defines.OptionRegistry.SIZE1.number: + value = option.value if option.value is not None else 0 + return value + + @size1.setter + def size1(self, value): + option = Option() + option.number = defines.OptionRegistry.SIZE1.number + option.value = value + self.add_option(option) + + @size1.deleter + def size1(self): + self.del_option_by_number(defines.OptionRegistry.SIZE1.number) + + @property + def size2(self): + value = None + for option in self.options: + if option.number == defines.OptionRegistry.SIZE2.number: + value = option.value if option.value is not None else 0 + return value + + @size2.setter + def size2(self, value): + option = Option() + option.number = defines.OptionRegistry.SIZE2.number + option.value = value + self.add_option(option) + + @size2.deleter + def size2(self): + self.del_option_by_number(defines.OptionRegistry.SIZE2.number) + @property def line_print(self): """ diff --git a/coapthon/reverse_proxy/coap.py b/coapthon/reverse_proxy/coap.py index 32bbce5..0d7cd47 100644 --- a/coapthon/reverse_proxy/coap.py +++ b/coapthon/reverse_proxy/coap.py @@ -81,6 +81,8 @@ class CoAP(object): # Use given socket, could be a DTLS socket self._socket = sock + self.parse_config() + elif self.multicast: # pragma: no cover # Create a socket @@ -94,19 +96,24 @@ class CoAP(object): # Allow multiple copies of this program on one machine # (not strictly needed) self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self._socket.bind((defines.ALL_COAP_NODES, self.server_address[1])) + self._socket.bind(('', self.server_address[1])) + mreq = struct.pack("4sl", socket.inet_aton(defines.ALL_COAP_NODES), socket.INADDR_ANY) self._socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) self._unicast_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._unicast_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._unicast_socket.bind(self.server_address) else: + # Bugfix for Python 3.6 for Windows ... missing IPPROTO_IPV6 constant + if not hasattr(socket, 'IPPROTO_IPV6'): + socket.IPPROTO_IPV6 = 41 + self._socket = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM, socket.IPPROTO_UDP) # Allow multiple copies of this program on one machine # (not strictly needed) self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self._socket.bind((defines.ALL_COAP_NODES_IPV6, self.server_address[1])) + self._socket.bind(('', self.server_address[1])) addrinfo_multicast = socket.getaddrinfo(defines.ALL_COAP_NODES_IPV6, 5683)[0] group_bin = socket.inet_pton(socket.AF_INET6, addrinfo_multicast[4][0]) @@ -251,7 +258,7 @@ class CoAP(object): self.stopped.set() for event in self.to_be_stopped: event.set() - self._socket.close() + # self._socket.close() def receive_datagram(self, args): """ diff --git a/coverage_test.py b/coverage_test.py index 2546c8c..e61a2af 100644 --- a/coverage_test.py +++ b/coverage_test.py @@ -536,6 +536,27 @@ class Tests(unittest.TestCase): print("TEST_GET_BLOCK") path = "/big" + req = Request() + req.code = defines.Codes.GET.number + req.uri_path = path + req.type = defines.Types["CON"] + req._mid = self.current_mid + req.destination = self.server_address + req.payload = None + # req.block2 = (0, 0, 512) + + expected = Response() + expected.type = defines.Types["ACK"] + expected._mid = None + expected.code = defines.Codes.CONTENT.number + expected.token = None + expected.payload = None + expected.block2 = (0, 1, defines.MAX_PAYLOAD) + expected.size2 = 2041 + + exchange0 = (req, expected) + self.current_mid += 1 + req = Request() req.code = defines.Codes.GET.number req.uri_path = path @@ -552,6 +573,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (0, 1, 512) + expected.size2 = 2041 exchange1 = (req, expected) self.current_mid += 1 @@ -572,6 +594,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (1, 1, 256) + expected.size2 = 2041 exchange2 = (req, expected) self.current_mid += 1 @@ -592,6 +615,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (2, 1, 128) + expected.size2 = 2041 exchange3 = (req, expected) self.current_mid += 1 @@ -612,6 +636,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (3, 1, 64) + expected.size2 = 2041 exchange4 = (req, expected) self.current_mid += 1 @@ -632,6 +657,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (4, 1, 32) + expected.size2 = 2041 exchange5 = (req, expected) self.current_mid += 1 @@ -652,6 +678,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (5, 1, 16) + expected.size2 = 2041 exchange6 = (req, expected) self.current_mid += 1 @@ -671,7 +698,8 @@ class Tests(unittest.TestCase): expected.code = defines.Codes.CONTENT.number expected.token = None expected.payload = None - expected.block2 = (6, 1, 1024) + expected.block2 = (6, 0, 1024) + expected.size2 = 2041 exchange7 = (req, expected) self.current_mid += 1 @@ -692,11 +720,12 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (7, 0, 1024) + expected.size2 = 2041 exchange8 = (req, expected) self.current_mid += 1 - self._test_plugtest([exchange1, exchange2, exchange3, exchange4, exchange5, exchange6, exchange7, exchange8]) + self._test_plugtest([exchange0, exchange1, exchange2, exchange3, exchange4, exchange5, exchange6, exchange7, exchange8]) def test_post_block_big(self): print("TEST_POST_BLOCK_BIG") diff --git a/coverage_test_proxy.py b/coverage_test_proxy.py index 153a8ae..eb7c838 100644 --- a/coverage_test_proxy.py +++ b/coverage_test_proxy.py @@ -31,12 +31,12 @@ class Tests(unittest.TestCase): self.queue = Queue() def tearDown(self): - self.server.close() - self.server_thread.join(timeout=25) - self.server = None self.proxy.close() self.proxy_thread.join(timeout=25) self.proxy = None + self.server.close() + self.server_thread.join(timeout=25) + self.server = None def _test_with_client(self, message_list): # pragma: no cover client = HelperClient(self.server_address) @@ -509,6 +509,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (0, 1, 512) + expected.size2 = 2041 exchange1 = (req, expected) self.current_mid += 1 @@ -529,6 +530,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (1, 1, 256) + expected.size2 = 2041 exchange2 = (req, expected) self.current_mid += 1 @@ -549,6 +551,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (2, 1, 128) + expected.size2 = 2041 exchange3 = (req, expected) self.current_mid += 1 @@ -569,6 +572,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (3, 1, 64) + expected.size2 = 2041 exchange4 = (req, expected) self.current_mid += 1 @@ -589,6 +593,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (4, 1, 32) + expected.size2 = 2041 exchange5 = (req, expected) self.current_mid += 1 @@ -609,6 +614,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (5, 1, 16) + expected.size2 = 2041 exchange6 = (req, expected) self.current_mid += 1 @@ -628,7 +634,8 @@ class Tests(unittest.TestCase): expected.code = defines.Codes.CONTENT.number expected.token = None expected.payload = None - expected.block2 = (6, 1, 1024) + expected.block2 = (6, 0, 1024) + expected.size2 = 2041 exchange7 = (req, expected) self.current_mid += 1 @@ -649,14 +656,13 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (7, 0, 1024) + expected.size2 = 2041 exchange8 = (req, expected) self.current_mid += 1 self._test_plugtest([exchange1, exchange2, exchange3, exchange4, exchange5, exchange6, exchange7, exchange8]) - #self._test_plugtest([exchange1]) - def test_post_block_big(self): print("TEST_POST_BLOCK_BIG") req = Request() diff --git a/coverage_test_reverse_proxy.py b/coverage_test_reverse_proxy.py index beab967..293a212 100644 --- a/coverage_test_reverse_proxy.py +++ b/coverage_test_reverse_proxy.py @@ -33,12 +33,12 @@ class Tests(unittest.TestCase): self.queue = Queue() def tearDown(self): - self.server.close() - self.server_thread.join(timeout=25) - self.server = None self.proxy.close() self.proxy_thread.join(timeout=25) self.proxy = None + self.server.close() + self.server_thread.join(timeout=25) + self.server = None def _test_with_client(self, message_list): # pragma: no cover client = HelperClient(self.server_address) @@ -560,6 +560,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (0, 1, 512) + expected.size2 = 2041 exchange1 = (req, expected) self.current_mid += 1 @@ -580,6 +581,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (1, 1, 256) + expected.size2 = 2041 exchange2 = (req, expected) self.current_mid += 1 @@ -600,6 +602,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (2, 1, 128) + expected.size2 = 2041 exchange3 = (req, expected) self.current_mid += 1 @@ -620,6 +623,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (3, 1, 64) + expected.size2 = 2041 exchange4 = (req, expected) self.current_mid += 1 @@ -640,6 +644,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (4, 1, 32) + expected.size2 = 2041 exchange5 = (req, expected) self.current_mid += 1 @@ -660,6 +665,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (5, 1, 16) + expected.size2 = 2041 exchange6 = (req, expected) self.current_mid += 1 @@ -679,7 +685,8 @@ class Tests(unittest.TestCase): expected.code = defines.Codes.CONTENT.number expected.token = None expected.payload = None - expected.block2 = (6, 1, 1024) + expected.block2 = (6, 0, 1024) + expected.size2 = 2041 exchange7 = (req, expected) self.current_mid += 1 @@ -700,6 +707,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (7, 0, 1024) + expected.size2 = 2041 exchange8 = (req, expected) self.current_mid += 1 diff --git a/plugtest.py b/plugtest.py index eb764c5..b7146b0 100644 --- a/plugtest.py +++ b/plugtest.py @@ -566,6 +566,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (0, 1, 1024) + expected.size2 = 1990 exchange1 = (req, expected) self.current_mid += 1 @@ -586,6 +587,7 @@ class Tests(unittest.TestCase): expected.token = None expected.payload = None expected.block2 = (1, 0, 1024) + expected.size2 = 1990 exchange2 = (req, expected) self.current_mid += 1 @@ -632,6 +634,7 @@ I say, looked for all the world like a strip of that same patchwork quilt. Indee when I first awoke, I could hardly tell it from the quilt, they so blended their hues together; and it was only by the sense of weight and pressure that I could tell that Queequeg was hugging""" expected.block2 = (1, 0, 1024) + expected.size2 = 1990 exchange1 = (req, expected) self.current_mid += 1 @@ -677,6 +680,7 @@ I say, looked for all the world like a strip of that same patchwork quilt. Indee when I first awoke, I could hardly tell it from the quilt, they so blended their hues together; and it was only by the sense of weight and pressure that I could tell that Queequeg was hugging""" expected.block2 = (1, 0, 1024) + expected.size2 = 1990 exchange1 = (req, expected) self.current_mid += 1 @@ -702,6 +706,7 @@ I say, looked for all the world like a strip of that same patchwork quilt. Indee expected.token = None expected.payload = None expected.block2 = (0, 1, 1024) + expected.size2 = 1990 exchange1 = (req, expected) self.current_mid += 1 @@ -722,6 +727,7 @@ I say, looked for all the world like a strip of that same patchwork quilt. Indee expected.token = None expected.payload = None expected.block2 = (1, 0, 1024) + expected.size2 = 1990 exchange2 = (req, expected) self.current_mid += 1 diff --git a/setup.py b/setup.py index b2c96e8..884e0ed 100644 --- a/setup.py +++ b/setup.py @@ -3,14 +3,29 @@ from distutils.core import setup setup( name='CoAPthon3', version='1.0.1', - packages=['coapthon', 'coapthon.caching', 'coapthon.layers', 'coapthon.client', 'coapthon.server', 'coapthon.messages', - 'coapthon.forward_proxy', 'coapthon.resources', 'coapthon.reverse_proxy'], + packages=[ + 'coapthon', + 'coapthon.caching', + 'coapthon.client', + 'coapthon.forward_proxy', + 'coapthon.layers', + 'coapthon.messages', + 'coapthon.resources', + 'coapthon.reverse_proxy', + 'coapthon.server', + ], url='https://github.com/Tanganelli/CoAPthon3', license='MIT License', author='Giacomo Tanganelli', author_email='giacomo.tanganelli@for.unipi.it', download_url='https://github.com/Tanganelli/CoAPthon3/archive/1.0.1.tar.gz', description='CoAPthon is a python library to the CoAP protocol. ', - scripts=['coapserver.py', 'coapclient.py', 'exampleresources.py', 'coapforwardproxy.py', 'coapreverseproxy.py'], + scripts=[ + 'coapclient.py', + 'coapforwardproxy.py', + 'coapreverseproxy.py', + 'coapserver.py', + 'exampleresources.py', + ], requires=['sphinx', 'cachetools'] )