8000 extmod/asyncio: Add ssl support with SSLContext. · micropython/micropython@2175158 · GitHub
[go: up one dir, main page]

Skip to content

Commit 2175158

Browse files
committed
extmod/asyncio: Add ssl support with SSLContext.
This adds asyncio ssl support and fix async stream read methods in unix port. The reason is stream ssl sockets seem to behave different from plain stream sockets. The main difference is doing partial reads on ssl sockets will clear any write/read/close "event" flag even if there is still pending data to be read. So registering the ssl socket again in the poller will wait there until a new event or timeout. The fix is check first if the ssl socket has pending data and read/return it instead of registering in the poller to wait for an event. Signed-off-by: Carlos Gil <carlosgilglez@gmail.com>
1 parent ec9b94a commit 2175158

7 files changed

+581
-8
lines changed

extmod/asyncio/stream.py

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22
# MIT license; Copyright (c) 2019-2020 Damien P. George
33

44
from . import core
5+
import sys
6+
7+
try:
8+
import ssl as _ssl
9+
except:
10+
_ssl = False
511

612

713
class Stream:
@@ -30,6 +36,15 @@ async def wait_closed(self):
3036
def read(self, n=-1):
3137
r = b""
3238
while True:
39+
if hasattr(self.s, "ssl_pending"):
40+
if self.s.ssl_pending():
41+
r2 = self.s.read(n)
42+
if r2 is not None:
43+
if n >= 0:
44+
return r2
45+
if not len(r2):
46+
return r
47+
r += r2
3348< 10000 /td>
yield core._io_queue.queue_read(self.s)
3449
r2 = self.s.read(n)
3550
if r2 is not None:
@@ -41,13 +56,25 @@ def read(self, n=-1):
4156

4257
# async
4358
def readinto(self, buf):
59+
if hasattr(self.s, "ssl_pending"):
60+
if self.s.ssl_pending():
61+
return self.s.readinto(buf)
4462
yield core._io_queue.queue_read(self.s)
4563
return self.s.readinto(buf)
4664

4765
# async
4866
def readexactly(self, n):
4967
r = b""
5068
while n:
69+
# prevent queueing if pending read in a ssl socket
70+
if hasattr(self.s, "ssl_pending"):
71+
if self.s.ssl_pending():
72+
r2 = self.s.read(n)
73+
if r2 is not None:
74+
if not len(r2):
75+
raise EOFError
76+
r += r2
77+
n -= len(r2)
5178
yield core._io_queue.queue_read(self.s)
5279
r2 = self.s.read(n)
5380
if r2 is not None:
@@ -61,9 +88,22 @@ def readexactly(self, n):
6188
def readline(self):
6289
l = b""
6390
while True:
91+
# prevent queueing if pending read in a ssl socket
92+
if hasattr(self.s, "ssl_pending"):
93+
if self.s.ssl_pending():
94+
l2 = self.s.readline()
95+
if l2:
96+
l += l2
97+
if l2 is None:
98+
continue
99+
if not l2 or l[-1] == 10:
100+
return l
64101
yield core._io_queue.queue_read(self.s)
65102
l2 = self.s.readline() # may do multiple reads but won't block
66-
l += l2
103+
if l2:
104+
l += l2
105+
if l2 is None:
106+
continue
67107
if not l2 or l[-1] == 10: # \n (check l in case l2 is str)
68108
return l
69109

@@ -100,20 +140,40 @@ def drain(self):
100140
# Create a TCP stream connection to a remote host
101141
#
102142
# async
103-
def open_connection(host, port):
143+
async def open_connection(host, port, ssl=None, server_hostname=None):
104144
from errno import EINPROGRESS
105145
import socket
106146

107147
ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)[0] # TODO this is blocking!
108148
s = socket.socket(ai[0], ai[1], ai[2])
109-
s.setblocking(False)
110-
ss = Stream(s)
149+
if not ssl:
150+
s.setblocking(False)
151+
ss = Stream(s)
111152
try:
112153
s.connect(ai[-1])
113154
except OSError as er:
114155
if er.errno != EINPROGRESS:
115156
raise er
116-
yield core._io_queue.queue_write(s)
157+
if not ssl:
158+
yield core._io_queue.queue_write(s)
159+
# wrap with SSL, if requested
160+
if ssl:
161+
if not _ssl:
162+
raise ValueError("SSL not supported")
163+
if ssl is True:
164+
ssl = _ssl.SSLContext(_ssl.PROTOCOL_TLS_CLIENT)
165+
# spec says to use ssl.create_default_context()
166+
else:
167+
try:
168+
assert isinstance(ssl, _ssl.SSLContext)
169+
except:
170+
raise ValueError("Invalid ssl param")
171+
if not server_hostname:
172+
server_hostname = host
173+
s = ssl.wrap_socket(s, server_hostname=server_hostname)
174+
s.setblocking(False)
175+
yield core._io_queue.queue_write(s)
176+
ss = Stream(s)
117177
return ss, ss
118178

119179

@@ -132,7 +192,7 @@ def close(self):
132192
async def wait_closed(self):
133193
await self.task
134194

135-
async def _serve(self, s, cb):
195+
async def _serve(self, s, cb, ssl):
136196
# Accept incoming connections
137197
while True:
138198
try:
@@ -146,14 +206,24 @@ async def _serve(self, s, cb):
146206
except:
147207
# Ignore a failed accept
148208
continue
209+
if s2:
210+
if ssl and _ssl:
211+
if isinstance(ssl, _ssl.SSLContext):
212+
s2.setblocking(True)
213+
try:
214+
s2 = ssl.wrap_socket(s2, server_side=True)
215+
except OSError as e:
216+
sys.print_exception(e)
217+
s2.close()
218+
continue
149219
s2.setblocking(False)
150220
s2s = Stream(s2, {"peername": addr})
151221
core.create_task(cb(s2s, s2s))
152222

153223

154224
# Helper function to start a TCP stream server, running as a new task
155225
# TODO could use an accept-callback on socket read activity instead of creating a task
156-
async def start_server(cb, host, port, backlog=5):
226+
async def start_server(cb, host, port, backlog=5, ssl=None):
157227
import socket
158228

159229
# Create and bind server socket.
@@ -166,7 +236,7 @@ async def start_server(cb, host, port, backlog=5):
166236

167237
# Create and return server object and task.
168238
srv = Server()
169-
srv.task = core.< F438 span class="pl-c1">create_task(srv._serve(s, cb))
239+
srv.task = core.create_task(srv._serve(s, cb, ssl))
170240
return srv
171241

172242

extmod/modssl_mbedtls.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,14 @@ STATIC mp_obj_t mod_ssl_cipher(mp_obj_t o_in) {
590590
return mp_obj_new_tuple(2, tuple);
591591
}
592592
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mod_ssl_cipher_obj, mod_ssl_cipher);
593+
594+
STATIC mp_obj_t socket_ssl_pending(mp_obj_t self_in) {
595+
mp_obj_ssl_socket_t *o = MP_OBJ_TO_PTR(self_in);
596+
int check_pending = 0;
597+
check_pending = mbedtls_ssl_check_pending(&o->ssl);
598+
return mp_obj_new_int(check_pending);
599+
}
600+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_ssl_pending_obj, socket_ssl_pending);
593601
#endif
594602

595603
STATIC mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
@@ -662,6 +670,7 @@ STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
662670
}
663671
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
664672

673+
665674
STATIC mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
666675
mp_obj_ssl_socket_t *self = MP_OBJ_TO_PTR(o_in);
667676
mp_uint_t ret = 0;
@@ -726,6 +735,7 @@ STATIC const mp_rom_map_elem_t ssl_socket_locals_dict_table[] = {
726735
{ MP_ROM_QSTR(MP_QSTR_getpeercert), MP_ROM_PTR(&mod_ssl_getpeercert_obj) },
727736
#ifdef MICROPY_SSL_MBEDTLS_EXTRAS
728737
{ MP_ROM_QSTR(MP_QSTR_cipher), MP_ROM_PTR(&mod_ssl_cipher_obj) },
738+
{ MP_ROM_QSTR(MP_QSTR_ssl_pending), MP_ROM_PTR(&socket_ssl_pending_obj) },
729739
#endif
730740
};
731741
STATIC MP_DEFINE_CONST_DICT(ssl_socket_locals_dict, ssl_socket_locals_dict_table);
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
# Test uasyncio TCP server and client using start_server() and open_connection()
2+
3+
try:
4+
import binascii
5+
import asyncio
6+
import ssl
7+
import sys
8+
except ImportError:
9+
print("SKIP")
10+
raise SystemExit
11+
12+
# Asyncio + TLS in 32-bit systems fails.
13+
# Reason: UNKNOWN
14+
# Possible cause:
15+
# Incompatible ciphersuites + streams.
16+
# i.e. error OSError: (-29568, 'MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN')
17+
# Action: SKIP for now.
18+
if sys.maxsize == 2147483647:
19+
print("SKIP")
20+
raise SystemExit
21+
22+
23+
PORT = 8000
24+
25+
# testing/demonstration only. You should always generate your own key/cert.
26+
27+
# To generate a new self-signed key/cert pair with openssl do:
28+
# $ openssl req -x509 -newkey rsa:4096 -keyout rsa_key.pem -out rsa_cert.pem
29+
# -days 365 -nodes
30+
# In this case CN is: esphome.local
31+
#
32+
# Convert them to DER format:
33+
# $ openssl rsa -in rsa_key.pem -out rsa_key.der -outform DER
34+
# $ openssl x509 -in rsa_cert.pem -out rsa_cert.der -outform DER
35+
#
36+
# Then convert to hex format, eg using binascii.hexlify(data).
37+
38+
cert = binascii.unhexlify(
39+
b"308205d7308203bfa003020102020900bc63b48a700c3d49300d06092a864886f70d01010b050030"
40+
b"8181310b3009060355040613024155310c300a06035504080c03466f6f310c300a06035504070c03"
41+
b"42617231143012060355040a0c0b4d6963726f507974686f6e310c300a060355040b0c03666f6f31"
42+
b"16301406035504030c0d657370686f6d652e6c6f63616c311a301806092a864886f70d010901160b"
43+
b"666f6f406261722e636f6d301e170d3232303731323138303031335a170d32333037313231383030"
44+
b"31335a308181310b3009060355040613024155310c300a06035504080c03466f6f310c300a060355"
45+
b"04070c0342617231143012060355040a0c0b4d6963726f507974686f6e310c300a060355040b0c03"
46+
b"666f6f3116301406035504030c0d657370686f6d652e6c6f63616c311a301806092a864886f70d01"
47+
b"0901160b666f6f406261722e636f6d30820222300d06092a864886f70d01010105000382020f0030"
48+
b"82020a0282020100ce3c0f730ab34432ce605ab44d4ac0aafd8a6243133eab0dcc9d444ab7d9ff66"
49+
b"a6815a101d2d3cbd72140afc34f8c3caedce16e9528350f3e0e56343f248507d82e41b51abb515cb"
50+
b"f60e5a619f2dbca8684d174c3b0951e2c7ba576c7fb06453a3597755810a6a4c45eb0925c855ab53"
51+
b"7785df46bf29145871330ff0641a101a24f0830c20bae865ba8bb32606caac4555812acf19f59553"
52+
b"349ce70fb7ff63512f0444f8f41b973183eabf9679903087c6cd69dc3adcbe754dd0207ea57c50e9"
53+
b"2d800bce6258d1618bb749d3fc01239b6d1af6d3f9cada3acbb312a1d85a59cfabd28b2e572c56a4"
54+
b"818ce170ca2b781a04749c6239206c64ad9e057484143a4c52bdef6189c46405c1a9642489cb640a"
55+
b"937adfc2687578dfa2b40ebafa05213642a1ccbc265557cd40de53324cff1bfba6f5c215f657b8f9"
56+
b"f2260ab6293625d0e203bba975bc7ac6dff3e604c9b0d2a2a4ba5941c0dc8d2e0e9439c56447b404"
57+
b"8c0e6cfb03517742ff6f7c2140a05954aa1e29247d1ae8bfd7db0db8dd45d095710fb78284ede285"
58+
b"0fc0c21235406af83e6044addf9385316403e2a25442b9ffbfc7b01c6c9292e5a3531e6a48496c01"
59+
b"6de1373334a52f01b7c6a0ece1261936788d2161c53a8985a0946d6d319225b230d96d055ea4692f"
60+
b"eb71fdaf4b775ac9fbc38e1b943e6617cf61d33e930ab288a3ea4730b4f2784a8018e0dfc8a11e73"
61+
b"0203010001a350304e301d0603551d0e04160414bc6048fe3cd278257e8b7c90dedbbce8369b20b8"
62+
b"301f0603551d23041830168014bc6048fe3cd278257e8b7c90dedbbce8369b20b8300c0603551d13"
63+
b"040530030101ff300d06092a864886f70d01010b0500038202010009238354b43379a3d2b56e928c"
64+
b"ac8ea28e2c01cf8148e54c0bbd4055e2e57d578697d1e2c392f1fe3bc9211d4f27ed1be631e7547a"
65+
b"6390d7f121a9e20a195fdda73f755188b16cf39714924a9686dd7cc749421335038c0640c2c6b15d"
66+
b"f44d74d94a97285ee2a7b075ccc9d9d632e2a5906030cf59bde14ab10660b7cf47ec9d7ae2f35963"
67+
b"454f76735a3dac12a4a4c907183e9ccf3e07d59484c182e67edc7c35ce15c7e1072fae8c9965a126"
68+
b"1a1f31147d4af8d1ebf8ee7c142badfe67e31fb324a79a29bc94e89370b70d8cf7cd2b2aa427a49f"
69+
b"77849891e7c4d5911f6fda52733a3c169b0188c2d9918f296dd8e234f8962f0db5e47c6159448045"
70+
b"4e2d9a5850d4c696a0fb3b66534a4591c49dda8cc6f1b0008c625aa5e0091ecfbd51d9715c60b85e"
71+
b"4e89d4a6cfabb2acdf81518eb61403b8f8767c5c00216f730e08f22959dff695a081cc726c4ab35a"
72+
b"e3f6538a231f831a6e91206f3b691a94bdf95343ec02ef7aac42da2a70846cd5f13dd2955a5f1737"
73+
b"a4c3c6c03b041d334c1dadd1e305f07c83b4b4e0509ec1d23e95f820290942eaaf8bea304cd5a505"
74+
b"8fc0d4624ff1ffe1348e7bc54c756a12acb258eb5e7426fb062a82b88ec274c9c13b3eff8b010947"
75+
b"62e166f490cd25b14e762db708785859a337d8fd0008fe602a90e2933cded3359e98ce3fbc041208"
76+
b"66bd4d96d6b6f7f53def854d40021196b7a06b"
77+
)
78+
79+
key = binascii.unhexlify(
80+
b"308209290201000282020100ce3c0f730ab34432ce605ab44d4ac0aafd8a6243133eab0dcc9d444a"
81+
b"b7d9ff66a6815a101d2d3cbd72140afc34f8c3caedce16e9528350f3e0e56343f248507d82e41b51"
82+
b"abb515cbf60e5a619f2dbca8684d174c3b0951e2c7ba576c7fb06453a3597755810a6a4c45eb0925"
83+
b"c855ab537785df46bf29145871330ff0641a101a24f0830c20bae865ba8bb32606caac4555812acf"
84+
b"19f59553349ce70fb7ff63512f0444f8f41b973183eabf9679903087c6cd69dc3adcbe754dd0207e"
85+
b"a57c50e92d800bce6258d1618bb749d3fc01239b6d1af6d3f9cada3acbb312a1d85a59cfabd28b2e"
86+
b"572c56a4818ce170ca2b781a04749c6239206c64ad9e057484143a4c52bdef6189c46405c1a96424"
87+
b"89cb640a937adfc2687578dfa2b40ebafa05213642a1ccbc265557cd40de53324cff1bfba6f5c215"
88+
b"f657b8f9f2260ab6293625d0e203bba975bc7ac6dff3e604c9b0d2a2a4ba5941c0dc8d2e0e9439c5"
89+
b"6447b4048c0e6cfb03517742ff6f7c2140a05954aa1e29247d1ae8bfd7db0db8dd45d095710fb782"
90+
b"84ede2850fc0c21235406af83e6044addf9385316403e2a25442b9ffbfc7b01c6c9292e5a3531e6a"
91+
b"48496c016de1373334a52f01b7c6a0ece1261936788d2161c53a8985a0946d6d319225b230d96d05"
92+
b"5ea4692feb71fdaf4b775ac9fbc38e1b943e6617cf61d33e930ab288a3ea4730b4f2784a8018e0df"
93+
b"c8a11e73020301000102820201008efa0e8fe81c2e2cb6ed10152dfca4242750581d3e6b54f56524"
94+
b"a6a2d2613cf2727efcec6cfddebd4c285f1148bc2a2936c28919cb0da502dea8c92fe2f9856bee61"
95+
b"ac1aebdac838b5e66f7c7c799df07716f30ef362dbb5485884a180c8ce5539cb1db35699dce5f217"
96+
b"27295d811f1ce7a115111c1823b5c90ce880f5352872a7a76282f6f1fd8a015136ab274c3d30783d"
97+
b"eb6ad7096e33d826eafdf7c70398d5eab4d28f91cd3913c69c7a7ade9ef692b9f8292959be64dec4"
98+
b"6ab2c291b41a6464004b5ddd4b93bfe41b37eedeef4ba2d16dcbb9c28b96f57fb96c20ed4a9471ff"
99+
b"ae643b254f100f8c9702b5f67af6369e8d887f285e5d520c5aa5d3a79e5de96432e6d2e3dea68e58"
100+
b"208c075fb119c6d3d4149b7e1247208d6b337c70272befc41d57f278618f1a82de337173346dc135"
101+
b"4d80a7c9075af99dbb2a14733c06b71600c6677a6bb28c0e4fc63db622228047a2cb7474dc8141c3"
102+
b"5f3a597c3e2bca9911d28eb9fd1a0c915e9f9c1cfd643d4fd8cac867f215380168ec37b8cfa28564"
103+
b"e6288ab04a7d67ca44b4c8375214a7ffaa1e6be92c4b138fcfd6beaba251b31a50a6e2ef241c9554"
104+
b"a1dc710b4acb63e749f5849e53d3f4915c6eb2a9a009bab04e932841ab34ae29eb000a08777d6399"
105+
b"169c2dc3d7952df5bc2d06e90a32139c6a2793d3817e4feadac2ccac554d383a8d41569140c29168"
106+
b"89220d3a5e410282010100fd603d18feef7aac61bda3b674a57ab38748bcde5c3efdba2279638f8e"
107+
b"a413cc26b9dda0375c116a8798a295b2c283aaaad7cca0dbd9bb3322a9a815f6d0aa5fc4f9aff8fb"
108+
b"da8ff914091ede7aefdb07a119c9b2e2b2bda776ac497060b8e88a82eb20c62f26f343566697726e"
109+
b"71aa46fd4efad6f42fc8a478856324d72cbf5eb3918317162d6fc2cfd775969a2077759fa2c8220d"
110+
b"acdc2ebb03ec39feed3f2b415449cbf40a7126bcf01d1068e3a45ec01181f2c68d7e05b4720bfe4a"
111+
b"308e1648123c91214a5f8dfce58727c4cd9396a8b403b733a717449b2f1970db97a3b8467271ffa6"
112+
b"e8c7cc9e2e1c0f789284ae9efe77eaac01131463c9c1329a1ba3530282010100d05ed6ab9b9fbdf7"
113+
b"a0f5f91f68dc3bac5789332d6ece46103fb1ef109fc972fdc99edf3107a23d66d1cdfe6bdddfd1bb"
114+
b"3952ccd10b5c20ad1b3e0aa6a51271ecf3a7ef2a65e029f5d77f238d1235b52a9dca3451c165d70a"
115+
b"99cbaea5c610e5455979696db769191e7cf2db21f641959e4ba1c5c0aae260c724962b6ac2621d92"
116+
b"e9df7adeb82b522d37b42cb454003bbe60d9915bf7737aeccf88c7ed1263a22f431a734e61fe7173"
117+
b"a937ddf76ad2a79994c05238defc15f6846858e9edf27ae2a567c7c5c735ea5d2fbef65a2195bc05"
118+
b"d82cbf06a477b29c84c92e8054c2bb25d8c6f19d43ef5fd1fce13c2cdbc361c39baec37b399200b3"
119+
b"2d4a6798ba0b546102820101008e41492c4e7daff7368d1d6c64034067a94dca5461a0301e201add"
120+
b"2e0d5ccb8cb435685bfa98e362572cf8236a10d191b187a568aee688b6c60050d1bc181d7fd57c86"
121+
b"33195bf5b7576b637c6fb358dae8b52ccc15815affb99e334137dcb91a833475db2f4004164b5d20"
122+
b"2c6c1bbf094a50dc7e70ec9f0ed067bb6944b1e7e3c897aaecfc53984add1c4ff5b525034cf3ca95"
123+
b"e8a09aeba804f1c7e02be391b2bc641166c3e654eef5e72dba37d98f406f3fa520e41f2ea10f5574"
124+
b"ac5984f75145378fefbfac1d07fff3f234fec698d55e746b1da18f6f7de24ec84ed7cb446d428820"
125+
b"bef33c00693e6a0ef114b5d66e9fefa8ee059238df1ac37c87e7841ae7028201000721a7d139c34e"
126+
b"da21cd295894db2cc3aa3f4cdc1a35bf1a2143f2bdabea56202f7d5b802f15b36a4875f76633b2cc"
127+
b"57cf0f71691a2d6e04deb0d1e68031d06a5eb079b406c6944910b60e3e6ec81dca369a4c0e1c4363"
128+
b"07bed9c4c171b4f453da4b187ba3d25a04bc1c07b9f2d6adcb3c256e4238d7049eec36a387c4dd5c"
129+
b"cbc16b5fa62dc175cf8c5f83442cb7d153a3b6ee8daa3b6e929a4bc123f1042df1d6271a992d2b6b"
130+
b"309d33074ac7822c304a72069e61ab590915e10862013dd24cdd825ec8fb17724cfc2c59fc1db825"
131+
b F438 "3641fece0ee9241b9dd5c198f0d575d0b7ebe26b3489b5b09edc3bcd366fd3110e83ce886c383d31"
132+
b"feefe6e302cc2345210282010008f77a33d0081e9be3c1b1ac8b8e0eebb72df2eb69b95d2ed74935"
133+
b"b9dab8e17023cc38465354023c5183b51a6a20288fbb2181172be1c2fdb8b444419454e5b37f7f3b"
134+
b"df11e28cf4746b25534eb62f7e87bbbf28eda37024368b3897fbc661b40a93e04a183db9219c04a8"
135+
b"7643edf5d8b5dbfe3d424e91d558d5e3e2fa02ce1984ee69fb8518470eee2e7db0e1df5ac4571f78"
136+
b"a7a2529bc1fef5e32d46994869a8d8cc47869e174d84e7976be8ebb88f2ccb71a603a8bdb06af3eb"
137+
b"2ddbd62082f40d7987e47f2e321eb5eb2a28fefab263409f89dc97ebc723a1b751418cdd3ea684ba"
138+
b"8b17a330a306a6fbcf51ba83563aed85a4f886fff1a22423748d83798c"
139+
)
140+
141+
142+
async def handle_connection(reader, writer):
143+
# Test that peername exists (but don't check its value, it changes)
144+
writer.get_extra_info("peername")
145+
146+
data = await reader.read(100)
147+
print("echo:", data)
148+
writer.write(data)
149+
await writer.drain()
150+
151+
print("close")
152+
writer.close()
153+
await writer.wait_closed()
154+
155+
print("done")
156+
ev.set()
157+
158+
159+
async def tcp_server():
160+
global ev
161+
162+
server_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
163+
server_ctx.load_cert_chain(cert, keyfile=key)
164+
ev = asyncio.Event()
165+
server = await asyncio.start_server(handle_connection, "0.0.0.0", PORT, ssl=server_ctx)
166+
print("server running")
167+
multitest.next()
168+
async with server:
169+
await asyncio.wait_for(ev.wait(), 10)
170+
171+
172+
async def tcp_client(message):
173+
client_ctx = ssl. A706 SSLContext(ssl.PROTOCOL_TLS_CLIENT)
174+
client_ctx.verify_mode = ssl.CERT_REQUIRED
175+
client_ctx.load_verify_locations(cadata=cert)
176+
reader, writer = await asyncio.open_connection(
177+
IP, PORT, ssl=client_ctx, server_hostname="esphome.local"
178+
)
179+
print("write:", message)
180+
writer.write(message)
181+
await writer.drain()
182+
data = await reader.read(100)
183+
print("read:", data)
184+
185+
186+
def instance0():
187+
multitest.globals(IP=multitest.get_network_ip())
188+
asyncio.run(tcp_server())
189+
190+
191+
def instance1():
192+
multitest.next()
193+
asyncio.run(tcp_client(b"client data"))

0 commit comments

Comments
 (0)
0