0

This question is the follow up from a previous question I asked. I have incorporated the code that resolves that issue. My program uses threading and SSL. I am still unsure if this is relevant, so I decided to post a complete working sample of both the server and client, in the hope that someone may be able to assist in working out why I cannot send large files.

When I uncomment line 9 in client.py (FILENAME = '2KB.zip'; this is actually a 1.5KB zip file), everything works as expected. The md5sum of the file on the server side matches the one on the client side.

However, when I run the code as is, attempting to send the '44MB.zip' file (which is indeed a 44MB zip file), there is always a (different) remaining amount of bytes and it ends with a ConnectionResetError: [Errno 104] Connection reset by peer. Any insights into why this happens and what I can do to resolve the issue are greatly appreciated.

Here is what the output looks like when sending 44MB.zip:

...
Remaining: 505927
Remaining: 495687
Remaining: 485447
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/usr/lib/python3.8/threading.py", line 932, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.8/threading.py", line 870, in run
    self._target(*self._args, **self._kwargs)
  File "gen3-server.py", line 25, in handle_client
    count = f.write(r.read(min(10240, remaining)))
  File "/usr/lib/python3.8/socket.py", line 669, in readinto
    return self._sock.recv_into(b)
  File "/usr/lib/python3.8/ssl.py", line 1241, in recv_into
    return self.read(nbytes, buffer)
  File "/usr/lib/python3.8/ssl.py", line 1099, in read
    return self._sslobj.read(len, buffer)
ConnectionResetError: [Errno 104] Connection reset by peer
# server.py
import socket
import ssl
import threading
import os
import json

server_ip = "192.168.12.110"
server_port = 443
server_address = (server_ip, server_port)

def handle_client(conn, addr):
    r = conn.makefile('rb')
    with conn, r:
        while True:
            header_line = r.readline()
            if not header_line: break
            header = json.loads(header_line)
            print('Header received from client: ' + str(header))
            remaining = header['length']

            with open(header['filename'], 'wb') as f:
                while remaining:
                    count = f.write(r.read(min(10240, remaining)))
                    print('Remaining: ' + str(remaining))
                    if not count:
                        if remaining:
                        break
                    remaining -= count
                else:
                    return
    return

def main():
    context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
    context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
    context.load_cert_chain('/etc/ssl/certs/server-certificate.pem', keyfile='/etc/ssl/private/server-private-key.pem', password='password')

    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(server_address)
    server.listen()
    server = context.wrap_socket(server, server_side=True)
    
    while True:
        conn, addr = server.accept()
        thread = threading.Thread(target=handle_client, args=(conn, addr))
        thread.start()
            
if __name__ == "__main__":
    main()
# client.py
import socket
import ssl
import json

server_ip = "192.168.12.110"
server_port = 443
server_address = (server_ip, server_port)
FILENAME = '44MB.zip'
#FILENAME = '2KB.zip'

    
def transmit(sock, filename, author, content):
    msg = {'filename': filename, 'author': author, 'length': len(content)}
    data = json.dumps(msg, ensure_ascii=False).encode() + b'\r\n' + content
    sock.sendall(data)

def main():
    context = ssl.SSLContext()
    context.verify_mode = ssl.CERT_REQUIRED
    context.check_hostname = True
    context.load_verify_locations(cafile='ca-certificate.pem')

    client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    client = context.wrap_socket(client, server_hostname="ag-docose1")
    client.connect(server_address)
    
    with client:
        with open(FILENAME, 'rb') as f:
            content = f.read()
        transmit(client, FILENAME, 'Marc', content)

if __name__ == "__main__":
    main()
Marc
  • 17
  • 7
  • After a lot of trial and error, I found that the code works fine when I do not wrap the socket in the SSL context. This leads me to believe there is something wrong with the way I am implementing SSL/TLS. – Marc May 06 '22 at 13:36
  • I am getting a step closer. Using the answer from [this example](https://stackoverflow.com/questions/55839932/sending-encrypted-data-through-socket-and-decrypting-doesnt-work) ensures that I can send large files. I tested it on a 2.5GB file and the md5sums match. The trick is to read the source file in chunks. – Marc May 10 '22 at 13:00

0 Answers0