• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# -*- coding: latin-1 -*-
2#
3# Copyright (C) AB Strakt
4# Copyright (C) Jean-Paul Calderone
5# See LICENSE for details.
6
7"""
8Simple echo server, using nonblocking I/O
9"""
10
11from __future__ import print_function
12
13import os
14import select
15import socket
16import sys
17
18from OpenSSL import SSL, crypto
19
20
21def verify_cb(conn, cert, errnum, depth, ok):
22    certsubject = crypto.X509Name(cert.get_subject())
23    commonname = certsubject.commonName
24    print('Got certificate: ' + commonname)
25    return ok
26
27
28if len(sys.argv) < 2:
29    print('Usage: python server.py PORT')
30    sys.exit(1)
31
32dir = os.path.dirname(sys.argv[0])
33if dir == '':
34    dir = os.curdir
35
36# Initialize context
37ctx = SSL.Context(SSL.SSLv23_METHOD)
38ctx.set_options(SSL.OP_NO_SSLv2)
39ctx.set_options(SSL.OP_NO_SSLv3)
40ctx.set_verify(
41    SSL.VERIFY_PEER | SSL.VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb
42)  # Demand a certificate
43ctx.use_privatekey_file(os.path.join(dir, 'server.pkey'))
44ctx.use_certificate_file(os.path.join(dir, 'server.cert'))
45ctx.load_verify_locations(os.path.join(dir, 'CA.cert'))
46
47# Set up server
48server = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM))
49server.bind(('', int(sys.argv[1])))
50server.listen(3)
51server.setblocking(0)
52
53clients = {}
54writers = {}
55
56
57def dropClient(cli, errors=None):
58    if errors:
59        print('Client %s left unexpectedly:' % (clients[cli],))
60        print('  ', errors)
61    else:
62        print('Client %s left politely' % (clients[cli],))
63    del clients[cli]
64    if cli in writers:
65        del writers[cli]
66    if not errors:
67        cli.shutdown()
68    cli.close()
69
70
71while 1:
72    try:
73        r, w, _ = select.select(
74            [server] + list(clients.keys()), list(writers.keys()), []
75        )
76    except Exception:
77        break
78
79    for cli in r:
80        if cli == server:
81            cli, addr = server.accept()
82            print('Connection from %s' % (addr,))
83            clients[cli] = addr
84
85        else:
86            try:
87                ret = cli.recv(1024).decode('utf-8')
88            except (SSL.WantReadError,
89                    SSL.WantWriteError,
90                    SSL.WantX509LookupError):
91                pass
92            except SSL.ZeroReturnError:
93                dropClient(cli)
94            except SSL.Error as errors:
95                dropClient(cli, errors)
96            else:
97                if cli not in writers:
98                    writers[cli] = ''
99                writers[cli] = writers[cli] + ret
100
101    for cli in w:
102        try:
103            ret = cli.send(writers[cli])
104        except (SSL.WantReadError,
105                SSL.WantWriteError,
106                SSL.WantX509LookupError):
107            pass
108        except SSL.ZeroReturnError:
109            dropClient(cli)
110        except SSL.Error as errors:
111            dropClient(cli, errors)
112        else:
113            writers[cli] = writers[cli][ret:]
114            if writers[cli] == '':
115                del writers[cli]
116
117for cli in clients.keys():
118    cli.close()
119server.close()
120