Back to index

python3.2  3.2.2
Public Member Functions
test.test_ssl.ThreadedTests Class Reference

List of all members.

Public Member Functions

def test_echo
def test_getpeercert
def test_empty_cert
def test_malformed_cert
def test_nonexisting_cert
def test_malformed_key
def test_rude_shutdown
def test_protocol_sslv2
def test_protocol_sslv23
def test_protocol_sslv3
def test_protocol_tlsv1
def test_starttls
def test_socketserver
def test_asyncore_server
def test_recv_send
def test_handshake_timeout

Detailed Description

Definition at line 1113 of file test_ssl.py.


Member Function Documentation

Check the example asyncore integration.

Definition at line 1403 of file test_ssl.py.

01403 
01404         def test_asyncore_server(self):
01405             """Check the example asyncore integration."""
01406             indata = "TEST MESSAGE of mixed case\n"
01407 
01408             if support.verbose:
01409                 sys.stdout.write("\n")
01410 
01411             indata = b"FOO\n"
01412             server = AsyncoreEchoServer(CERTFILE)
01413             flag = threading.Event()
01414             server.start(flag)
01415             # wait for it to start
01416             flag.wait()
01417             # try to connect
01418             try:
01419                 s = ssl.wrap_socket(socket.socket())
01420                 s.connect(('127.0.0.1', server.port))
01421                 if support.verbose:
01422                     sys.stdout.write(
01423                         " client:  sending %r...\n" % indata)
01424                 s.write(indata)
01425                 outdata = s.read()
01426                 if support.verbose:
01427                     sys.stdout.write(" client:  read %r\n" % outdata)
01428                 if outdata != indata.lower():
01429                     self.fail(
01430                         "bad data <<%r>> (%d) received; expected <<%r>> (%d)\n"
01431                         % (outdata[:20], len(outdata),
01432                            indata[:20].lower(), len(indata)))
01433                 s.write(b"over\n")
01434                 if support.verbose:
01435                     sys.stdout.write(" client:  closing connection.\n")
01436                 s.close()
01437                 if support.verbose:
01438                     sys.stdout.write(" client:  connection closed.\n")
01439             finally:
01440                 if support.verbose:
01441                     sys.stdout.write(" cleanup: stopping server.\n")
01442                 server.stop()
01443                 if support.verbose:
01444                     sys.stdout.write(" cleanup: joining server thread.\n")
01445                 server.join()
01446                 if support.verbose:
01447                     sys.stdout.write(" cleanup: successfully joined.\n")

Here is the call graph for this function:

Basic test of an SSL client connecting to a server

Definition at line 1116 of file test_ssl.py.

01116 
01117         def test_echo(self):
01118             """Basic test of an SSL client connecting to a server"""
01119             if support.verbose:
01120                 sys.stdout.write("\n")
01121             for protocol in PROTOCOLS:
01122                 context = ssl.SSLContext(protocol)
01123                 context.load_cert_chain(CERTFILE)
01124                 server_params_test(context, context,
01125                                    chatty=True, connectionchatty=True)

Here is the call graph for this function:

Connecting with an empty cert file

Definition at line 1166 of file test_ssl.py.

01166 
01167         def test_empty_cert(self):
01168             """Connecting with an empty cert file"""
01169             bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
                                      "nullcert.pem"))

Here is the call graph for this function:

Definition at line 1126 of file test_ssl.py.

01126 
01127         def test_getpeercert(self):
01128             if support.verbose:
01129                 sys.stdout.write("\n")
01130             context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
01131             context.verify_mode = ssl.CERT_REQUIRED
01132             context.load_verify_locations(CERTFILE)
01133             context.load_cert_chain(CERTFILE)
01134             server = ThreadedEchoServer(context=context, chatty=False)
01135             flag = threading.Event()
01136             server.start(flag)
01137             # wait for it to start
01138             flag.wait()
01139             # try to connect
01140             try:
01141                 s = context.wrap_socket(socket.socket())
01142                 s.connect((HOST, server.port))
01143                 cert = s.getpeercert()
01144                 self.assertTrue(cert, "Can't get peer certificate.")
01145                 cipher = s.cipher()
01146                 if support.verbose:
01147                     sys.stdout.write(pprint.pformat(cert) + '\n')
01148                     sys.stdout.write("Connection cipher is " + str(cipher) + '.\n')
01149                 if 'subject' not in cert:
01150                     self.fail("No subject field in certificate: %s." %
01151                               pprint.pformat(cert))
01152                 if ((('organizationName', 'Python Software Foundation'),)
01153                     not in cert['subject']):
01154                     self.fail(
01155                         "Missing or invalid 'organizationName' field in certificate subject; "
01156                         "should be 'Python Software Foundation'.")
01157                 self.assertIn('notBefore', cert)
01158                 self.assertIn('notAfter', cert)
01159                 before = ssl.cert_time_to_seconds(cert['notBefore'])
01160                 after = ssl.cert_time_to_seconds(cert['notAfter'])
01161                 self.assertLess(before, after)
01162                 s.close()
01163             finally:
01164                 server.stop()
01165                 server.join()

Here is the call graph for this function:

Definition at line 1563 of file test_ssl.py.

01563 
01564         def test_handshake_timeout(self):
01565             # Issue #5103: SSL handshake must respect the socket timeout
01566             server = socket.socket(socket.AF_INET)
01567             host = "127.0.0.1"
01568             port = support.bind_port(server)
01569             started = threading.Event()
01570             finish = False
01571 
01572             def serve():
01573                 server.listen(5)
01574                 started.set()
01575                 conns = []
01576                 while not finish:
01577                     r, w, e = select.select([server], [], [], 0.1)
01578                     if server in r:
01579                         # Let the socket hang around rather than having
01580                         # it closed by garbage collection.
01581                         conns.append(server.accept()[0])
01582                 for sock in conns:
01583                     sock.close()
01584 
01585             t = threading.Thread(target=serve)
01586             t.start()
01587             started.wait()
01588 
01589             try:
01590                 try:
01591                     c = socket.socket(socket.AF_INET)
01592                     c.settimeout(0.2)
01593                     c.connect((host, port))
01594                     # Will attempt handshake and time out
01595                     self.assertRaisesRegex(socket.timeout, "timed out",
01596                                            ssl.wrap_socket, c)
01597                 finally:
01598                     c.close()
01599                 try:
01600                     c = socket.socket(socket.AF_INET)
01601                     c = ssl.wrap_socket(c)
01602                     c.settimeout(0.2)
01603                     # Will attempt handshake and time out
01604                     self.assertRaisesRegex(socket.timeout, "timed out",
01605                                            c.connect, (host, port))
01606                 finally:
01607                     c.close()
01608             finally:
01609                 finish = True
01610                 t.join()
01611                 server.close()
01612 

Here is the call graph for this function:

Connecting with a badly formatted certificate (syntax error)

Definition at line 1170 of file test_ssl.py.

01170 
01171         def test_malformed_cert(self):
01172             """Connecting with a badly formatted certificate (syntax error)"""
01173             bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
                                       "badcert.pem"))

Here is the call graph for this function:

Connecting with a badly formatted key (syntax error)

Definition at line 1178 of file test_ssl.py.

01178 
01179         def test_malformed_key(self):
01180             """Connecting with a badly formatted key (syntax error)"""
01181             bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
01182                                        "badkey.pem"))

Here is the call graph for this function:

Connecting with a non-existing cert file

Definition at line 1174 of file test_ssl.py.

01174 
01175         def test_nonexisting_cert(self):
01176             """Connecting with a non-existing cert file"""
01177             bad_cert_test(os.path.join(os.path.dirname(__file__) or os.curdir,
                                       "wrongcert.pem"))

Here is the call graph for this function:

Connecting to an SSLv2 server with various client options

Definition at line 1226 of file test_ssl.py.

01226 
01227         def test_protocol_sslv2(self):
01228             """Connecting to an SSLv2 server with various client options"""
01229             if support.verbose:
01230                 sys.stdout.write("\n")
01231             try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True)
01232             try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_OPTIONAL)
01233             try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv2, True, ssl.CERT_REQUIRED)
01234             try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True)
01235             try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv3, False)
01236             try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_TLSv1, False)
01237             # SSLv23 client with specific SSL options
01238             if no_sslv2_implies_sslv3_hello():
01239                 # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs
01240                 try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, False,
01241                                    client_options=ssl.OP_NO_SSLv2)
01242             try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True,
01243                                client_options=ssl.OP_NO_SSLv3)
01244             try_protocol_combo(ssl.PROTOCOL_SSLv2, ssl.PROTOCOL_SSLv23, True,
01245                                client_options=ssl.OP_NO_TLSv1)

Here is the call graph for this function:

Connecting to an SSLv23 server with various client options

Definition at line 1247 of file test_ssl.py.

01247 
01248         def test_protocol_sslv23(self):
01249             """Connecting to an SSLv23 server with various client options"""
01250             if support.verbose:
01251                 sys.stdout.write("\n")
01252             if hasattr(ssl, 'PROTOCOL_SSLv2'):
01253                 try:
01254                     try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv2, True)
01255                 except (ssl.SSLError, socket.error) as x:
01256                     # this fails on some older versions of OpenSSL (0.9.7l, for instance)
01257                     if support.verbose:
01258                         sys.stdout.write(
01259                             " SSL2 client to SSL23 server test unexpectedly failed:\n %s\n"
01260                             % str(x))
01261             try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True)
01262             try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True)
01263             try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True)
01264 
01265             try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
01266             try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL)
01267             try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
01268 
01269             try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
01270             try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED)
01271             try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
01272 
01273             # Server with specific SSL options
01274             try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, False,
01275                                server_options=ssl.OP_NO_SSLv3)
01276             # Will choose TLSv1
01277             try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True,
01278                                server_options=ssl.OP_NO_SSLv2 | ssl.OP_NO_SSLv3)
01279             try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, False,
01280                                server_options=ssl.OP_NO_TLSv1)
01281 

Here is the call graph for this function:

Connecting to an SSLv3 server with various client options

Definition at line 1283 of file test_ssl.py.

01283 
01284         def test_protocol_sslv3(self):
01285             """Connecting to an SSLv3 server with various client options"""
01286             if support.verbose:
01287                 sys.stdout.write("\n")
01288             try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True)
01289             try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_OPTIONAL)
01290             try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv3, True, ssl.CERT_REQUIRED)
01291             if hasattr(ssl, 'PROTOCOL_SSLv2'):
01292                 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv2, False)
01293             try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, False)
01294             try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_TLSv1, False)
01295             if no_sslv2_implies_sslv3_hello():
01296                 # No SSLv2 => client will use an SSLv3 hello on recent OpenSSLs
01297                 try_protocol_combo(ssl.PROTOCOL_SSLv3, ssl.PROTOCOL_SSLv23, True,
01298                                    client_options=ssl.OP_NO_SSLv2)

Here is the call graph for this function:

Connecting to a TLSv1 server with various client options

Definition at line 1300 of file test_ssl.py.

01300 
01301         def test_protocol_tlsv1(self):
01302             """Connecting to a TLSv1 server with various client options"""
01303             if support.verbose:
01304                 sys.stdout.write("\n")
01305             try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True)
01306             try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_OPTIONAL)
01307             try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, True, ssl.CERT_REQUIRED)
01308             if hasattr(ssl, 'PROTOCOL_SSLv2'):
01309                 try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False)
01310             try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv3, False)
01311             try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv23, False)

Here is the call graph for this function:

Test recv(), send() and friends.

Definition at line 1448 of file test_ssl.py.

01448 
01449         def test_recv_send(self):
01450             """Test recv(), send() and friends."""
01451             if support.verbose:
01452                 sys.stdout.write("\n")
01453 
01454             server = ThreadedEchoServer(CERTFILE,
01455                                         certreqs=ssl.CERT_NONE,
01456                                         ssl_version=ssl.PROTOCOL_TLSv1,
01457                                         cacerts=CERTFILE,
01458                                         chatty=True,
01459                                         connectionchatty=False)
01460             flag = threading.Event()
01461             server.start(flag)
01462             # wait for it to start
01463             flag.wait()
01464             # try to connect
01465             s = ssl.wrap_socket(socket.socket(),
01466                                 server_side=False,
01467                                 certfile=CERTFILE,
01468                                 ca_certs=CERTFILE,
01469                                 cert_reqs=ssl.CERT_NONE,
01470                                 ssl_version=ssl.PROTOCOL_TLSv1)
01471             s.connect((HOST, server.port))
01472             try:
01473                 # helper methods for standardising recv* method signatures
01474                 def _recv_into():
01475                     b = bytearray(b"\0"*100)
01476                     count = s.recv_into(b)
01477                     return b[:count]
01478 
01479                 def _recvfrom_into():
01480                     b = bytearray(b"\0"*100)
01481                     count, addr = s.recvfrom_into(b)
01482                     return b[:count]
01483 
01484                 # (name, method, whether to expect success, *args)
01485                 send_methods = [
01486                     ('send', s.send, True, []),
01487                     ('sendto', s.sendto, False, ["some.address"]),
01488                     ('sendall', s.sendall, True, []),
01489                 ]
01490                 recv_methods = [
01491                     ('recv', s.recv, True, []),
01492                     ('recvfrom', s.recvfrom, False, ["some.address"]),
01493                     ('recv_into', _recv_into, True, []),
01494                     ('recvfrom_into', _recvfrom_into, False, []),
01495                 ]
01496                 data_prefix = "PREFIX_"
01497 
01498                 for meth_name, send_meth, expect_success, args in send_methods:
01499                     indata = (data_prefix + meth_name).encode('ascii')
01500                     try:
01501                         send_meth(indata, *args)
01502                         outdata = s.read()
01503                         if outdata != indata.lower():
01504                             self.fail(
01505                                 "While sending with <<{name:s}>> bad data "
01506                                 "<<{outdata:r}>> ({nout:d}) received; "
01507                                 "expected <<{indata:r}>> ({nin:d})\n".format(
01508                                     name=meth_name, outdata=outdata[:20],
01509                                     nout=len(outdata),
01510                                     indata=indata[:20], nin=len(indata)
01511                                 )
01512                             )
01513                     except ValueError as e:
01514                         if expect_success:
01515                             self.fail(
01516                                 "Failed to send with method <<{name:s}>>; "
01517                                 "expected to succeed.\n".format(name=meth_name)
01518                             )
01519                         if not str(e).startswith(meth_name):
01520                             self.fail(
01521                                 "Method <<{name:s}>> failed with unexpected "
01522                                 "exception message: {exp:s}\n".format(
01523                                     name=meth_name, exp=e
01524                                 )
01525                             )
01526 
01527                 for meth_name, recv_meth, expect_success, args in recv_methods:
01528                     indata = (data_prefix + meth_name).encode('ascii')
01529                     try:
01530                         s.send(indata)
01531                         outdata = recv_meth(*args)
01532                         if outdata != indata.lower():
01533                             self.fail(
01534                                 "While receiving with <<{name:s}>> bad data "
01535                                 "<<{outdata:r}>> ({nout:d}) received; "
01536                                 "expected <<{indata:r}>> ({nin:d})\n".format(
01537                                     name=meth_name, outdata=outdata[:20],
01538                                     nout=len(outdata),
01539                                     indata=indata[:20], nin=len(indata)
01540                                 )
01541                             )
01542                     except ValueError as e:
01543                         if expect_success:
01544                             self.fail(
01545                                 "Failed to receive with method <<{name:s}>>; "
01546                                 "expected to succeed.\n".format(name=meth_name)
01547                             )
01548                         if not str(e).startswith(meth_name):
01549                             self.fail(
01550                                 "Method <<{name:s}>> failed with unexpected "
01551                                 "exception message: {exp:s}\n".format(
01552                                     name=meth_name, exp=e
01553                                 )
01554                             )
01555                         # consume data
01556                         s.read()
01557 
01558                 s.write(b"over\n")
01559                 s.close()
01560             finally:
01561                 server.stop()
01562                 server.join()

Here is the call graph for this function:

A brutal shutdown of an SSL server should raise an IOError
in the client when attempting handshake.

Definition at line 1183 of file test_ssl.py.

01183 
01184         def test_rude_shutdown(self):
01185             """A brutal shutdown of an SSL server should raise an IOError
01186             in the client when attempting handshake.
01187             """
01188             listener_ready = threading.Event()
01189             listener_gone = threading.Event()
01190 
01191             s = socket.socket()
01192             port = support.bind_port(s, HOST)
01193 
01194             # `listener` runs in a thread.  It sits in an accept() until
01195             # the main thread connects.  Then it rudely closes the socket,
01196             # and sets Event `listener_gone` to let the main thread know
01197             # the socket is gone.
01198             def listener():
01199                 s.listen(5)
01200                 listener_ready.set()
01201                 newsock, addr = s.accept()
01202                 newsock.close()
01203                 s.close()
01204                 listener_gone.set()
01205 
01206             def connector():
01207                 listener_ready.wait()
01208                 with socket.socket() as c:
01209                     c.connect((HOST, port))
01210                     listener_gone.wait()
01211                     try:
01212                         ssl_sock = ssl.wrap_socket(c)
01213                     except IOError:
01214                         pass
01215                     else:
01216                         self.fail('connecting to closed SSL socket should have failed')
01217 
01218             t = threading.Thread(target=listener)
01219             t.start()
01220             try:
01221                 connector()
01222             finally:
01223                 t.join()

Here is the call graph for this function:

Using a SocketServer to create and manage SSL connections.

Definition at line 1378 of file test_ssl.py.

01378 
01379         def test_socketserver(self):
01380             """Using a SocketServer to create and manage SSL connections."""
01381             server = make_https_server(self, CERTFILE)
01382             # try to connect
01383             if support.verbose:
01384                 sys.stdout.write('\n')
01385             with open(CERTFILE, 'rb') as f:
01386                 d1 = f.read()
01387             d2 = ''
01388             # now fetch the same data from the HTTPS server
01389             url = 'https://%s:%d/%s' % (
01390                 HOST, server.port, os.path.split(CERTFILE)[1])
01391             f = urllib.request.urlopen(url)
01392             try:
01393                 dlen = f.info().get("content-length")
01394                 if dlen and (int(dlen) > 0):
01395                     d2 = f.read(int(dlen))
01396                     if support.verbose:
01397                         sys.stdout.write(
01398                             " client: read %d bytes from remote server '%s'\n"
01399                             % (len(d2), server))
01400             finally:
01401                 f.close()
01402             self.assertEqual(d1, d2)

Here is the call graph for this function:

Switching from clear text to encrypted and back again.

Definition at line 1312 of file test_ssl.py.

01312 
01313         def test_starttls(self):
01314             """Switching from clear text to encrypted and back again."""
01315             msgs = (b"msg 1", b"MSG 2", b"STARTTLS", b"MSG 3", b"msg 4", b"ENDTLS", b"msg 5", b"msg 6")
01316 
01317             server = ThreadedEchoServer(CERTFILE,
01318                                         ssl_version=ssl.PROTOCOL_TLSv1,
01319                                         starttls_server=True,
01320                                         chatty=True,
01321                                         connectionchatty=True)
01322             flag = threading.Event()
01323             server.start(flag)
01324             # wait for it to start
01325             flag.wait()
01326             # try to connect
01327             wrapped = False
01328             try:
01329                 s = socket.socket()
01330                 s.setblocking(1)
01331                 s.connect((HOST, server.port))
01332                 if support.verbose:
01333                     sys.stdout.write("\n")
01334                 for indata in msgs:
01335                     if support.verbose:
01336                         sys.stdout.write(
01337                             " client:  sending %r...\n" % indata)
01338                     if wrapped:
01339                         conn.write(indata)
01340                         outdata = conn.read()
01341                     else:
01342                         s.send(indata)
01343                         outdata = s.recv(1024)
01344                     msg = outdata.strip().lower()
01345                     if indata == b"STARTTLS" and msg.startswith(b"ok"):
01346                         # STARTTLS ok, switch to secure mode
01347                         if support.verbose:
01348                             sys.stdout.write(
01349                                 " client:  read %r from server, starting TLS...\n"
01350                                 % msg)
01351                         conn = ssl.wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1)
01352                         wrapped = True
01353                     elif indata == b"ENDTLS" and msg.startswith(b"ok"):
01354                         # ENDTLS ok, switch back to clear text
01355                         if support.verbose:
01356                             sys.stdout.write(
01357                                 " client:  read %r from server, ending TLS...\n"
01358                                 % msg)
01359                         s = conn.unwrap()
01360                         wrapped = False
01361                     else:
01362                         if support.verbose:
01363                             sys.stdout.write(
01364                                 " client:  read %r from server\n" % msg)
01365                 if support.verbose:
01366                     sys.stdout.write(" client:  closing connection.\n")
01367                 if wrapped:
01368                     conn.write(b"over\n")
01369                 else:
01370                     s.send(b"over\n")
01371                 if wrapped:
01372                     conn.close()
01373                 else:
01374                     s.close()
01375             finally:
01376                 server.stop()
01377                 server.join()

Here is the call graph for this function:


The documentation for this class was generated from the following file: