# -*- coding: latin-1 -*- # # Copyright (C) AB Strakt # Copyright (C) Jean-Paul Calderone # See LICENSE for details. """ Simple echo server, using nonblocking I/O """ from __future__ import print_function import os import select import socket import sys from OpenSSL import SSL, crypto def verify_cb(conn, cert, errnum, depth, ok): certsubject = crypto.X509Name(cert.get_subject()) commonname = certsubject.commonName print('Got certificate: ' + commonname) return ok if len(sys.argv) < 2: print('Usage: python server.py PORT') sys.exit(1) dir = os.path.dirname(sys.argv[0]) if dir == '': dir = os.curdir # Initialize context ctx = SSL.Context(SSL.SSLv23_METHOD) ctx.set_options(SSL.OP_NO_SSLv2) ctx.set_options(SSL.OP_NO_SSLv3) ctx.set_verify( SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb ) # Demand a certificate ctx.use_privatekey_file(os.path.join(dir, 'server.pkey')) ctx.use_certificate_file(os.path.join(dir, 'server.cert')) ctx.load_verify_locations(os.path.join(dir, 'CA.cert')) # Set up server server = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) server.bind(('', int(sys.argv[1]))) server.listen(3) server.setblocking(0) clients = {} writers = {} def dropClient(cli, errors=None): if errors: print('Client %s left unexpectedly:' % (clients[cli],)) print(' ', errors) else: print('Client %s left politely' % (clients[cli],)) del clients[cli] if cli in writers: del writers[cli] if not errors: cli.shutdown() cli.close() while 1: try: r, w, _ = select.select( [server] + list(clients.keys()), list(writers.keys()), [] ) except Exception: break for cli in r: if cli == server: cli, addr = server.accept() print('Connection from %s' % (addr,)) clients[cli] = addr else: try: ret = cli.recv(1024).decode('utf-8') except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError): pass except SSL.ZeroReturnError: dropClient(cli) except SSL.Error as errors: dropClient(cli, errors) else: if cli not in writers: writers[cli] = '' writers[cli] = writers[cli] + ret for cli in w: try: ret = cli.send(writers[cli]) except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError): pass except SSL.ZeroReturnError: dropClient(cli) except SSL.Error as errors: dropClient(cli, errors) else: writers[cli] = writers[cli][ret:] if writers[cli] == '': del writers[cli] for cli in clients.keys(): cli.close() server.close()