From 5531da077fd697ea29f90dd5680220c90855c46e Mon Sep 17 00:00:00 2001 From: Tom Wang Date: Sat, 28 Mar 2020 19:28:29 -0700 Subject: [PATCH] Update Flowchart.vsd app_client_blocking.py - shortening main and other DRY fixes app_server.py - adding lsock close to cleanup base line secure socket framework --- Flowchart.vsd | Bin 0 -> 52224 bytes app_client_blocking.py | 92 ++++++++--------- app_secure_client.py | 151 ++++++++++++++++++++++++++++ app_secure_server.py | 60 +++++++++++ app_server.py | 5 +- lib_secure_server.py | 223 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 481 insertions(+), 50 deletions(-) create mode 100644 Flowchart.vsd create mode 100644 app_secure_client.py create mode 100644 app_secure_server.py create mode 100644 lib_secure_server.py diff --git a/Flowchart.vsd b/Flowchart.vsd new file mode 100644 index 0000000000000000000000000000000000000000..8100d8edbe70e074518aa9803ed8d354a7165f5b GIT binary patch literal 52224 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"LijFO{C=@; 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 b=CKG3_82g(ULb_$9u_yzP3iLQKkWYiq02JD literal 0 HcmV?d00001 diff --git a/app_client_blocking.py b/app_client_blocking.py index 32f774d..b7f5e1c 100644 --- a/app_client_blocking.py +++ b/app_client_blocking.py @@ -76,58 +76,15 @@ def create_message(request): return message -def main(): - if len(sys.argv) != 5: - print("usage:", sys.argv[0], " ") - sys.exit(1) +def read_to_buffer(sock, length, buf : bytearray): + while len(buf) < length: + data = sock.recv(4096) + buf += data - host, port = sys.argv[1], int(sys.argv[2]) - action, value = sys.argv[3], sys.argv[4] - request = create_request(action, value) - message = create_message(request) - addr = (host, port) - print("starting connection to", addr) - sock = socket.create_connection(addr) - sock.settimeout(5) - - print(f"sending request {repr(message)} to {addr}") - sock.sendall(message) - - _recv_buffer = bytearray(b"") - def read_to_buffer(sock, length, buf : bytearray): - while len(buf) < length: - data = sock.recv(4096) - buf += data - - # read and process protoheader (fixed length of 2 byte in network order) - hdrlen = 2 - read_to_buffer(sock, hdrlen, _recv_buffer) - - # process_protoheader() - _jsonheader_len = struct.unpack(">H", _recv_buffer[:hdrlen])[0] - _recv_buffer = _recv_buffer[hdrlen:] - - # read and process jsonheader - read_to_buffer(sock, _jsonheader_len, _recv_buffer) - - # process_jsonheader() - jsonheader = _json_decode(_recv_buffer[:_jsonheader_len], "utf-8") - _recv_buffer = _recv_buffer[_jsonheader_len:] - for reqhdr in ( - "byteorder", - "content-length", - "content-type", - "content-encoding", - ): - if reqhdr not in jsonheader: - raise ValueError(f'Missing required header "{reqhdr}".') - - # read and process response +def process_response(sock, addr, jsonheader, _recv_buffer): content_len = jsonheader["content-length"] read_to_buffer(sock, content_len, _recv_buffer) - - # process_response(): data = _recv_buffer[:content_len] _recv_buffer = _recv_buffer[content_len:] if jsonheader["content-type"] == "text/json": @@ -147,6 +104,45 @@ def main(): content = response print(f"got response: {repr(content)}") + +def main(): + HDRLEN = 2 + _recv_buffer = bytearray(b"") + + if len(sys.argv) != 5: + print("usage:", sys.argv[0], " ") + sys.exit(1) + + host, port = sys.argv[1], int(sys.argv[2]) + action, value = sys.argv[3], sys.argv[4] + request = create_request(action, value) + message = create_message(request) + + addr = (host, port) + print("starting connection to", addr) + sock = socket.create_connection(addr) + sock.settimeout(5) + + print(f"sending request {repr(message)} to {addr}") + sock.sendall(message) + + # read and process protoheader (fixed length of 2 byte in network order) + read_to_buffer(sock, HDRLEN, _recv_buffer) + _jsonheader_len = struct.unpack(">H", _recv_buffer[:HDRLEN])[0] + _recv_buffer = _recv_buffer[HDRLEN:] + + # read and process jsonheader + read_to_buffer(sock, _jsonheader_len, _recv_buffer) + jsonheader = _json_decode(_recv_buffer[:_jsonheader_len], "utf-8") + _recv_buffer = _recv_buffer[_jsonheader_len:] + for reqhdr in ("byteorder", "content-length", "content-type", + "content-encoding",): + if reqhdr not in jsonheader: + raise ValueError(f'Missing required header "{reqhdr}".') + + # read and process response + process_response(sock, addr, jsonheader, _recv_buffer) + sock.shutdown(socket.SHUT_RDWR) sock.close() diff --git a/app_secure_client.py b/app_secure_client.py new file mode 100644 index 0000000..b7f5e1c --- /dev/null +++ b/app_secure_client.py @@ -0,0 +1,151 @@ +# -*- coding: utf-8 -*- +""" +Created on Sun Mar 22 10:46:20 2020 + +@author: cpan + +Simple client implementation with timeout feature to prevent hanging + +""" + +import sys +import socket +import json +import io +import struct + + +def create_request(action, value): + if action == "search": + return dict( + type="text/json", + encoding="utf-8", + content=dict(action=action, value=value), + ) + else: + return dict( + type="binary/custom-client-binary-type", + encoding="binary", + content=bytes(action + value, encoding="utf-8"), + ) + + +def _json_encode(obj, encoding): + return json.dumps(obj, ensure_ascii=False).encode(encoding) + + +def _json_decode(json_bytes, encoding): + tiow = io.TextIOWrapper( + io.BytesIO(json_bytes), encoding=encoding, newline="" + ) + obj = json.load(tiow) + tiow.close() + return obj + + +def _create_message(*, content_bytes, content_type, content_encoding): + jsonheader = { + "byteorder": sys.byteorder, + "content-type": content_type, + "content-encoding": content_encoding, + "content-length": len(content_bytes), + } + jsonheader_bytes = _json_encode(jsonheader, "utf-8") + message_hdr = struct.pack(">H", len(jsonheader_bytes)) + message = message_hdr + jsonheader_bytes + content_bytes + return message + + +def create_message(request): + content = request["content"] + content_type = request["type"] + content_encoding = request["encoding"] + if content_type == "text/json": + req = { + "content_bytes": _json_encode(content, content_encoding), + "content_type": content_type, + "content_encoding": content_encoding, + } + else: + req = { + "content_bytes": content, + "content_type": content_type, + "content_encoding": content_encoding, + } + message = _create_message(**req) + return message + + +def read_to_buffer(sock, length, buf : bytearray): + while len(buf) < length: + data = sock.recv(4096) + buf += data + + +def process_response(sock, addr, jsonheader, _recv_buffer): + content_len = jsonheader["content-length"] + read_to_buffer(sock, content_len, _recv_buffer) + data = _recv_buffer[:content_len] + _recv_buffer = _recv_buffer[content_len:] + if jsonheader["content-type"] == "text/json": + encoding = jsonheader["content-encoding"] + response = _json_decode(data, encoding) + print("received response", repr(response), "from", addr) + content = response + result = content.get("result") + print(f"got result: {result}") + else: + # Binary or unknown content-type + response = data + print( + f'received {jsonheader["content-type"]} response from', + addr, + ) + content = response + print(f"got response: {repr(content)}") + + +def main(): + HDRLEN = 2 + _recv_buffer = bytearray(b"") + + if len(sys.argv) != 5: + print("usage:", sys.argv[0], " ") + sys.exit(1) + + host, port = sys.argv[1], int(sys.argv[2]) + action, value = sys.argv[3], sys.argv[4] + request = create_request(action, value) + message = create_message(request) + + addr = (host, port) + print("starting connection to", addr) + sock = socket.create_connection(addr) + sock.settimeout(5) + + print(f"sending request {repr(message)} to {addr}") + sock.sendall(message) + + # read and process protoheader (fixed length of 2 byte in network order) + read_to_buffer(sock, HDRLEN, _recv_buffer) + _jsonheader_len = struct.unpack(">H", _recv_buffer[:HDRLEN])[0] + _recv_buffer = _recv_buffer[HDRLEN:] + + # read and process jsonheader + read_to_buffer(sock, _jsonheader_len, _recv_buffer) + jsonheader = _json_decode(_recv_buffer[:_jsonheader_len], "utf-8") + _recv_buffer = _recv_buffer[_jsonheader_len:] + for reqhdr in ("byteorder", "content-length", "content-type", + "content-encoding",): + if reqhdr not in jsonheader: + raise ValueError(f'Missing required header "{reqhdr}".') + + # read and process response + process_response(sock, addr, jsonheader, _recv_buffer) + + sock.shutdown(socket.SHUT_RDWR) + sock.close() + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/app_secure_server.py b/app_secure_server.py new file mode 100644 index 0000000..c59f268 --- /dev/null +++ b/app_secure_server.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +""" +Created on Sun Mar 22 10:43:35 2020 + +@author: cpan +""" + +import sys +import socket +import selectors +import traceback +import lib_secure_server as libserver + + +sel = selectors.DefaultSelector() + + +def accept_wrapper(sock): + conn, addr = sock.accept() # Should be ready to read + print("accepted connection from", addr) + conn.setblocking(False) + message = libserver.Message(sel, conn, addr) + sel.register(conn, selectors.EVENT_READ, data=message) + + +if len(sys.argv) != 3: + print("usage:", sys.argv[0], " ") + sys.exit(1) + +host, port = sys.argv[1], int(sys.argv[2]) +lsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# Avoid bind() exception: OSError: [Errno 48] Address already in use +lsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) +lsock.bind((host, port)) +lsock.listen() +print("listening on", (host, port)) +lsock.setblocking(False) +sel.register(lsock, selectors.EVENT_READ, data=None) + +try: + while True: + events = sel.select(timeout=None) + for key, mask in events: + if key.data is None: + accept_wrapper(key.fileobj) + else: + message = key.data + try: + message.process_events(mask) + except Exception: + print( + "main: error: exception for", + f"{message.addr}:\n{traceback.format_exc()}", + ) + message.close() +except KeyboardInterrupt: + print("caught keyboard interrupt, exiting") +finally: + sel.close() + lsock.close() \ No newline at end of file diff --git a/app_server.py b/app_server.py index 721d21a..d8c0fe1 100644 --- a/app_server.py +++ b/app_server.py @@ -9,9 +9,9 @@ import sys import socket import selectors import traceback - import libserver + sel = selectors.DefaultSelector() @@ -56,4 +56,5 @@ try: except KeyboardInterrupt: print("caught keyboard interrupt, exiting") finally: - sel.close() \ No newline at end of file + sel.close() + lsock.close() \ No newline at end of file diff --git a/lib_secure_server.py b/lib_secure_server.py new file mode 100644 index 0000000..b85391a --- /dev/null +++ b/lib_secure_server.py @@ -0,0 +1,223 @@ +# -*- coding: utf-8 -*- +""" +Created on Sun Mar 22 10:44:50 2020 + +@author: cpan +""" + +import sys +import selectors +import json +import io +import struct + +request_search = { + "morpheus": "Follow the white rabbit. \U0001f430", + "ring": "In the caves beneath the Misty Mountains. \U0001f48d", + "\U0001f436": "\U0001f43e Playing ball! \U0001f3d0", +} + + +class Message: + def __init__(self, selector, sock, addr): + self.selector = selector + self.sock = sock + self.addr = addr + self._recv_buffer = b"" + self._send_buffer = b"" + self._jsonheader_len = None + self.jsonheader = None + self.request = None + self.response_created = False + + def _set_selector_events_mask(self, mode): + """Set selector to listen for events: mode is 'r', 'w', or 'rw'.""" + if mode == "r": + events = selectors.EVENT_READ + elif mode == "w": + events = selectors.EVENT_WRITE + elif mode == "rw": + events = selectors.EVENT_READ | selectors.EVENT_WRITE + else: + raise ValueError(f"Invalid events mask mode {repr(mode)}.") + self.selector.modify(self.sock, events, data=self) + + def _read(self): + try: + # Should be ready to read + data = self.sock.recv(4096) + except BlockingIOError: + # Resource temporarily unavailable (errno EWOULDBLOCK) + pass + else: + if data: + self._recv_buffer += data + else: + raise RuntimeError("Peer closed.") + + def _write(self): + if self._send_buffer: + print("sending", repr(self._send_buffer), "to", self.addr) + try: + # Should be ready to write + sent = self.sock.send(self._send_buffer) + except BlockingIOError: + # Resource temporarily unavailable (errno EWOULDBLOCK) + pass + else: + self._send_buffer = self._send_buffer[sent:] + # Close when the buffer is drained. The response has been sent. + if sent and not self._send_buffer: + self.close() + + def _json_encode(self, obj, encoding): + return json.dumps(obj, ensure_ascii=False).encode(encoding) + + def _json_decode(self, json_bytes, encoding): + tiow = io.TextIOWrapper( + io.BytesIO(json_bytes), encoding=encoding, newline="" + ) + obj = json.load(tiow) + tiow.close() + return obj + + def _create_message( + self, *, content_bytes, content_type, content_encoding + ): + jsonheader = { + "byteorder": sys.byteorder, + "content-type": content_type, + "content-encoding": content_encoding, + "content-length": len(content_bytes), + } + jsonheader_bytes = self._json_encode(jsonheader, "utf-8") + message_hdr = struct.pack(">H", len(jsonheader_bytes)) + message = message_hdr + jsonheader_bytes + content_bytes + return message + + def _create_response_json_content(self): + action = self.request.get("action") + if action == "search": + query = self.request.get("value") + answer = request_search.get(query) or f'No match for "{query}".' + content = {"result": answer} + else: + content = {"result": f'Error: invalid action "{action}".'} + content_encoding = "utf-8" + response = { + "content_bytes": self._json_encode(content, content_encoding), + "content_type": "text/json", + "content_encoding": content_encoding, + } + return response + + def _create_response_binary_content(self): + response = { + "content_bytes": b"First 10 bytes of request: " + + self.request[:10], + "content_type": "binary/custom-server-binary-type", + "content_encoding": "binary", + } + return response + + def process_events(self, mask): + if mask & selectors.EVENT_READ: + self.read() + if mask & selectors.EVENT_WRITE: + self.write() + + def read(self): + self._read() + + if self._jsonheader_len is None: + self.process_protoheader() + + if self._jsonheader_len is not None: + if self.jsonheader is None: + self.process_jsonheader() + + if self.jsonheader: + if self.request is None: + self.process_request() + + def write(self): + if self.request: + if not self.response_created: + self.create_response() + + self._write() + + def close(self): + print("closing connection to", self.addr) + try: + self.selector.unregister(self.sock) + except Exception as e: + print( + f"error: selector.unregister() exception for", + f"{self.addr}: {repr(e)}", + ) + + try: + self.sock.close() + except OSError as e: + print( + f"error: socket.close() exception for", + f"{self.addr}: {repr(e)}", + ) + finally: + # Delete reference to socket object for garbage collection + self.sock = None + + def process_protoheader(self): + hdrlen = 2 + if len(self._recv_buffer) >= hdrlen: + self._jsonheader_len = struct.unpack( + ">H", self._recv_buffer[:hdrlen] + )[0] + self._recv_buffer = self._recv_buffer[hdrlen:] + + def process_jsonheader(self): + hdrlen = self._jsonheader_len + if len(self._recv_buffer) >= hdrlen: + self.jsonheader = self._json_decode( + self._recv_buffer[:hdrlen], "utf-8" + ) + self._recv_buffer = self._recv_buffer[hdrlen:] + for reqhdr in ( + "byteorder", + "content-length", + "content-type", + "content-encoding", + ): + if reqhdr not in self.jsonheader: + raise ValueError(f'Missing required header "{reqhdr}".') + + def process_request(self): + content_len = self.jsonheader["content-length"] + if not len(self._recv_buffer) >= content_len: + return + data = self._recv_buffer[:content_len] + self._recv_buffer = self._recv_buffer[content_len:] + if self.jsonheader["content-type"] == "text/json": + encoding = self.jsonheader["content-encoding"] + self.request = self._json_decode(data, encoding) + print("received request", repr(self.request), "from", self.addr) + else: + # Binary or unknown content-type + self.request = data + print( + f'received {self.jsonheader["content-type"]} request from', + self.addr, + ) + # Set selector to listen for write events, we're done reading. + self._set_selector_events_mask("w") + + def create_response(self): + if self.jsonheader["content-type"] == "text/json": + response = self._create_response_json_content() + else: + # Binary or unknown content-type + response = self._create_response_binary_content() + message = self._create_message(**response) + self.response_created = True + self._send_buffer += message \ No newline at end of file