Professional Documents
Culture Documents
Server cst311
Server cst311
env python
# Import statements
from typing import *
import socket as s
import ssl
import threading as t
# Configure logging
import logging
logging.basicConfig()
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
# Constants
SERVER_NAME = "chatserver.pa4.cst311.test"
SERVER_PORT: int = 12000
NUM_CLIENTS: int = 2
CLIENT_NAMES: Tuple[str, str] = ("X", "Y")
BYE_COMMAND = "bye"
CERT_FILE = f"/etc/ssl/demoCA/newcerts/{SERVER_NAME}-cert.pem"
KEY_FILE = f"/etc/ssl/demoCA/private/{SERVER_NAME}-key.pem"
###########
# Classes #
###########
value = self.value
return value
# Frees the entry (unlinks it from the list) if all consumers have
processed it
def _check_free_entry(self, next_entry):
# Lock to prevent multiple threads from freeing the entry
queue = self.queue
free_lock = queue.free_lock
free_lock.acquire()
if self.num_consumed == queue.num_consumers:
# Set num_consumed to dummy value so subsequent consumers
don't free the entry
self.num_consumed = -1
free_lock.release()
# Waits for the next entry, and returns it along with its value
def wait_for_next(self):
queue = self.queue
next_entry: SendQueue.Entry
# Waits until next_entry is valid (not the tail)
# Lock to check "new entry" condition
with (cond := queue.new_entry_cond):
while (next_entry := self.next) is queue.tail:
cond.wait()
self._check_free_entry(next_entry)
return next_entry, next_entry._consume()
# Returns the queue's head, which acts as the start of the queue for
any consumers
def get_head(self):
return self.head
# Before the actual adding code so that size can never be observed
as < 0 ("new entry"
# condition fulfilled + all consumers consume entry before size
incremented)
with self.size_lock:
self.size += 1
with self.new_entry_cond:
self.new_entry_cond.notify_all()
# May return a number greater than the current size, in which case one
or more messages are about to be added
def get_size(self):
return self.size
# Globals
client_states: List[ClientState] = []
send_queue: SendQueue = SendQueue(NUM_CLIENTS)
server_print_lock: t.Lock = t.Lock()
running_lock: t.Lock = t.Lock()
running = True
# Prints synchronously
def print_lock(value):
with server_print_lock:
print(value)
global running
client_name = client_state.client_name
secure_socket = client_state.secure_socket
while running:
# Read data from the connection socket
# If no data has been sent this blocks until there is data
client_response = secure_socket.recv(1024).decode()
client_name = client_state.client_name
secure_socket = client_state.secure_socket
def main():
# Assign IP address and port number to socket, and bind to chosen port
server_socket.bind(("", SERVER_PORT))
finally:
# Close client sockets
for client_state in client_states:
client_state.secure_socket.close()
if __name__ == "__main__":
main()