/
nv-lang
/
nova-tls
Обзор
Документация
Войти
/
nv-lang
/
nova-tls
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
src/server.nv
83 строки
4 KB
Evgeniy Golovin
wip(187): checkpoint — TLS resource-death diag + partial fix (scratch reuse, right-sized flush_out, TLS_CHUNK 16K->4K)
17 июл 2026, 22:09
17 июл 2026, 22:09
1fd7800
Код
Авторство
О чём код?
// SPDX-License-Identifier: MIT OR Apache-2.0 // nova-tls: server.nv — server handshake на принятом соединении. Extracted // from monorepo std/tls (Plan 193 Ф.1). // // Симметрично client.nv: эфемерный shim-билдер потребляется tls_server_new; // TcpStream закрывается на всех error-путях. mTLS-режимы (ClientCertMode) — // данные уже проходят границу. module tls import std.net.{Net, TcpStream} // Собрать эфемерный shim-конфиг из ServerConfig. На ошибке билдер освобождён. fn build_server_cfg(config ServerConfig) -> Result[CTlsCfgHandle, TlsError] { if config.cert_pem.len() == 0 || config.key_pem.len() == 0 { return Err(TlsError.InvalidPem("server config requires cert and key PEM")) } ro c = tls_server_cfg_new() if (c as int) == 0 { return Err(TlsError.Internal("tls shim not built for this host")) } ro crc = unsafe { tls_cfg_cert_key_pem(c, config.cert_pem.ptr(), config.cert_pem.len(), config.key_pem.ptr(), config.key_pem.len()) } if crc != 0 { tls_cfg_free(c) return Err(TlsError.from_shim(crc, "server cert/key")) } ro mrc = match config.client_cert { NoClientAuth => 0 Optional(roots) => unsafe { tls_cfg_client_auth_pem(c, roots.ptr(), roots.len(), false) } Required(roots) => unsafe { tls_cfg_client_auth_pem(c, roots.ptr(), roots.len(), true) } } if mrc != 0 { tls_cfg_free(c) return Err(TlsError.from_shim(mrc, "client auth config")) } for i in 0..config.alpn_protocols.len() { ro pb = config.alpn_protocols[i].bytes() ro arc = unsafe { tls_cfg_alpn_add(c, pb.ptr(), pb.len()) } if arc != 0 { tls_cfg_free(c) return Err(TlsError.from_shim(arc, "alpn config")) } } Ok(c) } /// Server handshake на принятом `TcpStream` (владение забирается; на любой /// ошибке сокет закрывается внутри). #stable(since = "0.1") export fn TlsStream.accept(consume stream TcpStream, config ServerConfig) Net -> Result[TlsStream, TlsError] { // Канон Plan 201 (D188-амендмент v3) — см. client.nv: блок владеет // stream, `return Err(...)` закрывает сокет cleanup'ом exactly-once; // успешный handshake выносит stream ПРЯМО в // `return Ok(TlsStream.new(stream, session))` — ровно одно вхождение // `stream`, аргументом consume-параметра `wrap`, дизарм в момент // передачи владения. `mut session_out`/`ro s`/wrap-снаружи (v2-канон) // больше не нужен. consume stream { ro c = match build_server_cfg(config) { Err(e) => { return Err(e) } // cleanup закрывает stream Ok(cc) => cc } mut err int = 0 ro session = unsafe { tls_server_new(c, &err) } if (session as int) == 0 { return Err(TlsError.from_shim(err, "server session")) } // Переиспользуемый ciphertext-скретч — см. client.nv/stream.nv banner // ([M-187-sustained-live-tls-resource-death] фикс). mut scratch []u8 = []u8.new() // См. client.nv: pump по view-borrow; wrap — прямо в return. match pump_handshake(stream, session, scratch) { Ok(_) => { return Ok(TlsStream.new(stream, session, scratch)) } // дизарм: stream → new Err(e) => { tls_free(session) return Err(e) // cleanup закрывает stream } } } }