Listen for incoming connections, and spawn a handler for each using an internal nursery. Similar to `~trio.serve_tcp`, this function never returns until cancelled, or the `DTLSEndpoint` is closed and all handlers have exited. Usage commonly looks like::
(
self,
ssl_context: SSL.Context,
async_fn: Callable[[DTLSChannel, Unpack[PosArgsT]], Awaitable[object]],
*args: Unpack[PosArgsT],
task_status: trio.TaskStatus[None] = trio.TASK_STATUS_IGNORED,
)
| 1270 | raise trio.ClosedResourceError |
| 1271 | |
| 1272 | async def serve( |
| 1273 | self, |
| 1274 | ssl_context: SSL.Context, |
| 1275 | async_fn: Callable[[DTLSChannel, Unpack[PosArgsT]], Awaitable[object]], |
| 1276 | *args: Unpack[PosArgsT], |
| 1277 | task_status: trio.TaskStatus[None] = trio.TASK_STATUS_IGNORED, |
| 1278 | ) -> None: |
| 1279 | """Listen for incoming connections, and spawn a handler for each using an |
| 1280 | internal nursery. |
| 1281 | |
| 1282 | Similar to `~trio.serve_tcp`, this function never returns until cancelled, or |
| 1283 | the `DTLSEndpoint` is closed and all handlers have exited. |
| 1284 | |
| 1285 | Usage commonly looks like:: |
| 1286 | |
| 1287 | async def handler(dtls_channel): |
| 1288 | ... |
| 1289 | |
| 1290 | async with trio.open_nursery() as nursery: |
| 1291 | await nursery.start(dtls_endpoint.serve, ssl_context, handler) |
| 1292 | # ... do other things here ... |
| 1293 | |
| 1294 | The ``dtls_channel`` passed into the handler function has already performed the |
| 1295 | "cookie exchange" part of the DTLS handshake, so the peer address is |
| 1296 | trustworthy. But the actual cryptographic handshake doesn't happen until you |
| 1297 | start using it, giving you a chance for any last minute configuration, and the |
| 1298 | option to catch and handle handshake errors. |
| 1299 | |
| 1300 | Args: |
| 1301 | ssl_context (OpenSSL.SSL.Context): The PyOpenSSL context object to use for |
| 1302 | incoming connections. |
| 1303 | async_fn: The handler function that will be invoked for each incoming |
| 1304 | connection. |
| 1305 | *args: Additional arguments to pass to the handler function. |
| 1306 | |
| 1307 | """ |
| 1308 | self._check_closed() |
| 1309 | if self._listening_context is not None: |
| 1310 | raise trio.BusyResourceError("another task is already listening") |
| 1311 | try: |
| 1312 | self.socket.getsockname() |
| 1313 | except OSError: # TODO: test this line |
| 1314 | raise RuntimeError( |
| 1315 | "DTLS socket must be bound before it can serve", |
| 1316 | ) from None |
| 1317 | self._ensure_receive_loop() |
| 1318 | # We do cookie verification ourselves, so tell OpenSSL not to worry about it. |
| 1319 | # (See also _inject_client_hello_untrusted.) |
| 1320 | ssl_context.set_cookie_verify_callback(lambda *_: True) |
| 1321 | set_ssl_context_options(ssl_context) |
| 1322 | try: |
| 1323 | self._listening_context = ssl_context |
| 1324 | task_status.started() |
| 1325 | |
| 1326 | async def handler_wrapper(stream: DTLSChannel) -> None: |
| 1327 | with stream: |
| 1328 | await async_fn(stream, *args) |
| 1329 |
nothing calls this directly
no test coverage detected