1use crate::host::{invoke, with_host, IoTask, JsObj};
21use fusevm::Value;
22use indexmap::IndexMap;
23use once_cell::sync::OnceCell;
24use rustls::pki_types::{CertificateDer, PrivateKeyDer, ServerName, UnixTime};
25use rustls::{
26 ClientConfig, ClientConnection, ConnectionCommon, DigitallySignedStruct, RootCertStore,
27 ServerConfig, ServerConnection, SideData, SignatureScheme, StreamOwned,
28};
29use std::collections::HashMap;
30use std::io::{Read, Write};
31use std::net::TcpStream;
32use std::ops::{Deref, DerefMut};
33use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
34use std::sync::mpsc::{Receiver, Sender};
35use std::sync::Arc;
36
37pub const MODULE_METHODS: &[&str] = &[
39 "connect",
40 "createServer",
41 "createSecureContext",
42 "checkServerIdentity",
43 "convertALPNProtocols",
44 "getCiphers",
45 "getCACertificates",
46 "setDefaultCACertificates",
47 "getCertificateCompressionAlgorithms",
48];
49
50const CIPHERS: &[&str] = &[
54 "aes128-gcm-sha256",
55 "aes128-sha",
56 "aes128-sha256",
57 "aes256-gcm-sha384",
58 "aes256-sha",
59 "aes256-sha256",
60 "dhe-psk-aes128-cbc-sha",
61 "dhe-psk-aes128-cbc-sha256",
62 "dhe-psk-aes128-gcm-sha256",
63 "dhe-psk-aes256-cbc-sha",
64 "dhe-psk-aes256-cbc-sha384",
65 "dhe-psk-aes256-gcm-sha384",
66 "dhe-psk-chacha20-poly1305",
67 "dhe-rsa-aes128-gcm-sha256",
68 "dhe-rsa-aes128-sha",
69 "dhe-rsa-aes128-sha256",
70 "dhe-rsa-aes256-gcm-sha384",
71 "dhe-rsa-aes256-sha",
72 "dhe-rsa-aes256-sha256",
73 "dhe-rsa-chacha20-poly1305",
74 "ecdhe-ecdsa-aes128-gcm-sha256",
75 "ecdhe-ecdsa-aes128-sha",
76 "ecdhe-ecdsa-aes128-sha256",
77 "ecdhe-ecdsa-aes256-gcm-sha384",
78 "ecdhe-ecdsa-aes256-sha",
79 "ecdhe-ecdsa-aes256-sha384",
80 "ecdhe-ecdsa-chacha20-poly1305",
81 "ecdhe-psk-aes128-cbc-sha",
82 "ecdhe-psk-aes128-cbc-sha256",
83 "ecdhe-psk-aes256-cbc-sha",
84 "ecdhe-psk-aes256-cbc-sha384",
85 "ecdhe-psk-chacha20-poly1305",
86 "ecdhe-rsa-aes128-gcm-sha256",
87 "ecdhe-rsa-aes128-sha",
88 "ecdhe-rsa-aes128-sha256",
89 "ecdhe-rsa-aes256-gcm-sha384",
90 "ecdhe-rsa-aes256-sha",
91 "ecdhe-rsa-aes256-sha384",
92 "ecdhe-rsa-chacha20-poly1305",
93 "psk-aes128-cbc-sha",
94 "psk-aes128-cbc-sha256",
95 "psk-aes128-gcm-sha256",
96 "psk-aes256-cbc-sha",
97 "psk-aes256-cbc-sha384",
98 "psk-aes256-gcm-sha384",
99 "psk-chacha20-poly1305",
100 "rsa-psk-aes128-cbc-sha",
101 "rsa-psk-aes128-cbc-sha256",
102 "rsa-psk-aes128-gcm-sha256",
103 "rsa-psk-aes256-cbc-sha",
104 "rsa-psk-aes256-cbc-sha384",
105 "rsa-psk-aes256-gcm-sha384",
106 "rsa-psk-chacha20-poly1305",
107 "srp-aes-128-cbc-sha",
108 "srp-aes-256-cbc-sha",
109 "srp-rsa-aes-128-cbc-sha",
110 "srp-rsa-aes-256-cbc-sha",
111 "tls_aes_128_ccm_8_sha256",
112 "tls_aes_128_ccm_sha256",
113 "tls_aes_128_gcm_sha256",
114 "tls_aes_256_gcm_sha384",
115 "tls_chacha20_poly1305_sha256",
116];
117
118pub const SERVER_METHODS: &[&str] = &["listen", "close", "address"];
121pub const SOCKET_METHODS: &[&str] = &[
122 "write",
123 "end",
124 "destroy",
125 "setEncoding",
126 "setKeepAlive",
127 "setNoDelay",
128 "setTimeout",
129 "ref",
130 "unref",
131 "pause",
132 "resume",
133];
134
135pub type ConnHook = std::rc::Rc<dyn Fn(&Value, &Value, u64) -> Result<(), String>>;
139
140enum WriteCmd {
142 Data(Vec<u8>),
143 Shutdown,
144}
145
146static NEXT_TLS_ID: AtomicU64 = AtomicU64::new(1);
150static NEXT_SERVER_ID: AtomicU64 = AtomicU64::new(1);
151
152fn next_tls_id() -> u64 {
153 NEXT_TLS_ID.fetch_add(1, Ordering::Relaxed)
154}
155fn next_server_id() -> u64 {
156 NEXT_SERVER_ID.fetch_add(1, Ordering::Relaxed)
157}
158
159struct TlsServerRec {
161 emitter: Value,
162 stop: Arc<AtomicBool>,
163 conn_hook: Option<ConnHook>,
164 listener: Option<Value>,
166}
167
168struct TlsSocketRec {
170 emitter: Value,
171 tx: Sender<WriteCmd>,
173}
174
175#[derive(Default)]
176struct TlsState {
177 servers: HashMap<u64, TlsServerRec>,
178 sockets: HashMap<u64, TlsSocketRec>,
179}
180
181thread_local! {
182 static TLS: std::cell::RefCell<TlsState> = std::cell::RefCell::new(TlsState::default());
183 static PENDING_CONFIGS: std::cell::RefCell<Vec<(Value, Arc<ServerConfig>)>> =
186 const { std::cell::RefCell::new(Vec::new()) };
187 static PENDING_HOOKS: std::cell::RefCell<Vec<(Value, ConnHook)>> =
188 const { std::cell::RefCell::new(Vec::new()) };
189 static DEFAULT_CA_CERTS: std::cell::RefCell<Vec<String>> =
192 const { std::cell::RefCell::new(Vec::new()) };
193}
194
195fn get_prop(recv: &Value, key: &str) -> Option<Value> {
198 with_host(|h| match h.get(recv) {
199 Some(JsObj::Object(p)) => p.get(key).cloned(),
200 _ => None,
201 })
202}
203
204fn set_prop(recv: &Value, key: &str, val: Value) {
205 with_host(|h| {
206 if let Some(JsObj::Object(p)) = h.get_mut(recv) {
207 p.insert(key.to_string(), val);
208 }
209 });
210}
211
212fn u64_prop(recv: &Value, key: &str) -> Option<u64> {
213 get_prop(recv, key).map(|v| with_host(|h| h.to_number(&v)) as u64)
214}
215
216fn emitter_dispatch(recv: &Value, method: &str, args: &[Value]) -> Option<Result<Value, String>> {
218 match method {
219 "on"
220 | "addListener"
221 | "prependListener"
222 | "once"
223 | "prependOnceListener"
224 | "emit"
225 | "removeListener"
226 | "off"
227 | "removeAllListeners"
228 | "listenerCount"
229 | "eventNames"
230 | "setMaxListeners"
231 | "getMaxListeners"
232 | "listeners" => Some(super::events::instance_call(recv, method, args.to_vec())),
233 _ => None,
234 }
235}
236
237fn value_bytes(v: Option<&Value>) -> Vec<u8> {
240 let Some(v) = v else { return Vec::new() };
241 let is_buffer =
242 with_host(|h| matches!(h.get(v), Some(JsObj::Object(p)) if p.contains_key("@@bytes")));
243 if is_buffer {
244 return with_host(|h| match h.get(v) {
245 Some(JsObj::Object(p)) => match p.get("@@bytes").and_then(|b| h.get(b)) {
246 Some(JsObj::Array(items)) => items.iter().map(|x| h.to_number(x) as u8).collect(),
247 _ => Vec::new(),
248 },
249 _ => Vec::new(),
250 });
251 }
252 with_host(|h| h.str_of(v)).into_bytes()
253}
254
255pub fn call(method: &str, args: &[Value]) -> Option<Result<Value, String>> {
259 match method {
260 "connect" => Some(connect(args)),
261 "createServer" => Some(create_server(args)),
262 "createSecureContext" => Some(Ok(with_host(|h| {
265 let mut m = IndexMap::new();
266 m.insert("@@native".into(), h.new_str("SecureContext"));
267 if let Some(o) = args.first() {
268 m.insert("@@options".into(), o.clone());
269 }
270 h.new_object(m)
271 }))),
272 "checkServerIdentity" => Some(check_server_identity(args)),
273 "convertALPNProtocols" => Some(convert_alpn_protocols(args)),
274 "getCiphers" => Some(Ok(with_host(|h| {
275 let items = CIPHERS.iter().map(|c| h.new_str(*c)).collect();
276 h.new_array(items)
277 }))),
278 "getCACertificates" => Some(get_ca_certificates(args)),
279 "setDefaultCACertificates" => Some(set_default_ca_certificates(args)),
280 "getCertificateCompressionAlgorithms" => Some(Ok(with_host(|h| h.new_array(Vec::new())))),
284 _ => None,
285 }
286}
287
288fn read_string_array(v: Option<&Value>) -> Vec<String> {
293 let Some(v) = v else { return Vec::new() };
294 with_host(|h| match h.get(v) {
295 Some(JsObj::Array(items)) => items.iter().map(|x| h.str_of(x)).collect(),
296 _ if h.as_str(v).is_some() => vec![h.str_of(v)],
297 _ => Vec::new(),
298 })
299}
300
301fn host_matches(host: &str, pattern: &str) -> bool {
305 let host = host.trim().to_ascii_lowercase();
306 let pattern = pattern.trim().to_ascii_lowercase();
307 if let Some(suffix) = pattern.strip_prefix("*.") {
308 match host.split_once('.') {
310 Some((_, rest)) => rest == suffix,
311 None => false,
312 }
313 } else {
314 host == pattern
315 }
316}
317
318fn check_server_identity(args: &[Value]) -> Result<Value, String> {
323 let host = super::arg_str(args, 0);
324 let cert = args.get(1).cloned().unwrap_or(Value::Undef);
325
326 let altname_str = get_prop(&cert, "subjectaltname")
328 .filter(|v| with_host(|h| h.as_str(v)).is_some())
329 .map(|v| with_host(|h| h.str_of(&v)))
330 .unwrap_or_default();
331 let dns_names: Vec<String> = altname_str
332 .split(',')
333 .filter_map(|e| e.trim().strip_prefix("DNS:").map(|s| s.trim().to_string()))
334 .filter(|s| !s.is_empty())
335 .collect();
336
337 let matched = if !dns_names.is_empty() {
338 dns_names.iter().any(|p| host_matches(&host, p))
339 } else {
340 let cn = get_prop(&cert, "subject")
342 .and_then(|s| get_prop(&s, "CN"))
343 .filter(|v| with_host(|h| h.as_str(v)).is_some())
344 .map(|v| with_host(|h| h.str_of(&v)))
345 .unwrap_or_default();
346 !cn.is_empty() && host_matches(&host, &cn)
347 };
348
349 if matched {
350 return Ok(Value::Undef);
351 }
352 let reason = if !altname_str.is_empty() {
353 format!("Host: {host}. is not in the cert's altnames: {altname_str}")
354 } else {
355 format!("Host: {host}. is not cert's CN")
356 };
357 let message = format!("Hostname/IP does not match certificate's altnames: {reason}");
358 Ok(with_host(|h| {
359 let mut m = IndexMap::new();
360 m.insert("message".into(), h.new_str(message));
361 m.insert("reason".into(), h.new_str(reason));
362 m.insert("host".into(), h.new_str(host));
363 m.insert("code".into(), h.new_str("ERR_TLS_CERT_ALTNAME_INVALID"));
364 m.insert("cert".into(), cert);
365 h.new_object(m)
366 }))
367}
368
369fn convert_alpn_protocols(args: &[Value]) -> Result<Value, String> {
373 let protocols = read_string_array(args.first());
374 let mut wire = Vec::new();
375 for p in &protocols {
376 let bytes = p.as_bytes();
377 wire.push(bytes.len().min(255) as u8);
380 wire.extend_from_slice(&bytes[..bytes.len().min(255)]);
381 }
382 let buf = super::buffer::from_bytes(&wire);
383 if let Some(out) = args.get(1).filter(|v| matches!(v, Value::Obj(_))) {
384 set_prop(out, "ALPNProtocols", buf.clone());
385 }
386 Ok(buf)
387}
388
389fn get_ca_certificates(args: &[Value]) -> Result<Value, String> {
398 let kind = if args.is_empty() {
399 "default".to_string()
400 } else {
401 super::arg_str(args, 0)
402 };
403 let certs: Vec<String> = match kind.as_str() {
404 "default" => DEFAULT_CA_CERTS.with(|c| c.borrow().clone()),
405 _ => Vec::new(),
406 };
407 Ok(with_host(|h| {
408 let items = certs.into_iter().map(|c| h.new_str(c)).collect();
409 h.new_array(items)
410 }))
411}
412
413fn set_default_ca_certificates(args: &[Value]) -> Result<Value, String> {
416 let certs = read_string_array(args.first());
417 DEFAULT_CA_CERTS.with(|c| *c.borrow_mut() = certs);
418 Ok(Value::Undef)
419}
420
421fn verifying_client_config() -> Arc<ClientConfig> {
428 static CFG: OnceCell<Arc<ClientConfig>> = OnceCell::new();
429 CFG.get_or_init(|| {
430 let root_store = RootCertStore {
431 roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
432 };
433 let provider = Arc::new(rustls::crypto::aws_lc_rs::default_provider());
434 let cfg = ClientConfig::builder_with_provider(provider)
435 .with_safe_default_protocol_versions()
436 .expect("aws-lc-rs provider supports the default protocol versions")
437 .with_root_certificates(root_store)
438 .with_no_client_auth();
439 Arc::new(cfg)
440 })
441 .clone()
442}
443
444fn insecure_client_config() -> Arc<ClientConfig> {
448 static CFG: OnceCell<Arc<ClientConfig>> = OnceCell::new();
449 CFG.get_or_init(|| {
450 let provider = Arc::new(rustls::crypto::aws_lc_rs::default_provider());
451 let cfg = ClientConfig::builder_with_provider(provider.clone())
452 .with_safe_default_protocol_versions()
453 .expect("aws-lc-rs provider supports the default protocol versions")
454 .dangerous()
455 .with_custom_certificate_verifier(Arc::new(NoVerify(provider)))
456 .with_no_client_auth();
457 Arc::new(cfg)
458 })
459 .clone()
460}
461
462#[derive(Debug)]
465struct NoVerify(Arc<rustls::crypto::CryptoProvider>);
466
467impl rustls::client::danger::ServerCertVerifier for NoVerify {
468 fn verify_server_cert(
469 &self,
470 _end_entity: &CertificateDer<'_>,
471 _intermediates: &[CertificateDer<'_>],
472 _server_name: &ServerName<'_>,
473 _ocsp: &[u8],
474 _now: UnixTime,
475 ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
476 Ok(rustls::client::danger::ServerCertVerified::assertion())
477 }
478 fn verify_tls12_signature(
479 &self,
480 message: &[u8],
481 cert: &CertificateDer<'_>,
482 dss: &DigitallySignedStruct,
483 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
484 rustls::crypto::verify_tls12_signature(
485 message,
486 cert,
487 dss,
488 &self.0.signature_verification_algorithms,
489 )
490 }
491 fn verify_tls13_signature(
492 &self,
493 message: &[u8],
494 cert: &CertificateDer<'_>,
495 dss: &DigitallySignedStruct,
496 ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
497 rustls::crypto::verify_tls13_signature(
498 message,
499 cert,
500 dss,
501 &self.0.signature_verification_algorithms,
502 )
503 }
504 fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
505 self.0.signature_verification_algorithms.supported_schemes()
506 }
507}
508
509pub fn client_config(reject_unauthorized: bool) -> Arc<ClientConfig> {
513 if reject_unauthorized {
514 verifying_client_config()
515 } else {
516 insecure_client_config()
517 }
518}
519
520pub fn build_server_config(cert_pem: &[u8], key_pem: &[u8]) -> Result<Arc<ServerConfig>, String> {
522 let certs: Vec<CertificateDer<'static>> = rustls_pemfile::certs(&mut &cert_pem[..])
523 .collect::<Result<_, _>>()
524 .map_err(|e| format!("Error: tls: bad certificate PEM: {e}"))?;
525 if certs.is_empty() {
526 return Err("Error: tls: no certificates found in `cert`".to_string());
527 }
528 let key: PrivateKeyDer<'static> = rustls_pemfile::private_key(&mut &key_pem[..])
529 .map_err(|e| format!("Error: tls: bad private key PEM: {e}"))?
530 .ok_or_else(|| "Error: tls: no private key found in `key`".to_string())?;
531 let cfg = ServerConfig::builder()
532 .with_no_client_auth()
533 .with_single_cert(certs, key)
534 .map_err(|e| format!("Error: tls: invalid key/cert: {e}"))?;
535 Ok(Arc::new(cfg))
536}
537
538pub fn connect(args: &[Value]) -> Result<Value, String> {
544 let mut port: u16 = 0;
545 let mut host = "localhost".to_string();
546 let mut servername: Option<String> = None;
547 let mut reject_unauthorized = true;
548 let mut cb: Option<Value> = None;
549
550 for a in args {
551 let n = with_host(|h| h.to_number(a));
552 if with_host(|h| crate::host::is_callable(h, a)) {
553 cb = Some(a.clone());
554 } else if !n.is_nan() && matches!(a, Value::Float(_) | Value::Int(_)) {
555 port = n as u16;
556 } else if with_host(|h| h.as_str(a)).is_some() {
557 host = with_host(|h| h.str_of(a));
558 } else if matches!(a, Value::Obj(_)) {
559 if let Some(p) = get_prop(a, "port") {
561 port = with_host(|h| h.to_number(&p)) as u16;
562 }
563 for key in ["host", "hostname"] {
564 if let Some(hv) = get_prop(a, key).filter(|v| with_host(|h| h.as_str(v)).is_some())
565 {
566 host = with_host(|h| h.str_of(&hv));
567 }
568 }
569 if let Some(sv) =
570 get_prop(a, "servername").filter(|v| with_host(|h| h.as_str(v)).is_some())
571 {
572 servername = Some(with_host(|h| h.str_of(&sv)));
573 }
574 if let Some(rv) = get_prop(a, "rejectUnauthorized") {
575 reject_unauthorized = with_host(|h| h.truthy(&rv));
576 }
577 }
578 }
579 let servername = servername.unwrap_or_else(|| host.clone());
580
581 let sock_id = next_tls_id();
583 let (tx, rx) = std::sync::mpsc::channel::<WriteCmd>();
584 let mut extra = IndexMap::new();
585 extra.insert("@@tlsid".into(), Value::Float(sock_id as f64));
586 extra.insert("authorized".into(), Value::Bool(reject_unauthorized));
587 extra.insert("encrypted".into(), Value::Bool(true));
588 let socket = new_emitter_object("TLSSocket", extra);
589 TLS.with(|s| {
590 s.borrow_mut().sockets.insert(
591 sock_id,
592 TlsSocketRec {
593 emitter: socket.clone(),
594 tx,
595 },
596 );
597 });
598 with_host(|h| h.incr_handle());
599 if let Some(cb) = cb {
601 super::events::instance_call(
602 &socket,
603 "once",
604 vec![with_host(|h| h.new_str("secureConnect")), cb],
605 )?;
606 }
607
608 let io_tx = with_host(|h| h.io_sender());
609 let config = if reject_unauthorized {
610 verifying_client_config()
611 } else {
612 insecure_client_config()
613 };
614
615 std::thread::spawn(move || {
616 let server_name = match ServerName::try_from(servername.clone()) {
617 Ok(n) => n,
618 Err(_) => {
619 post_socket_error(
620 &io_tx,
621 sock_id,
622 format!("Error: tls: invalid servername '{servername}'"),
623 );
624 return;
625 }
626 };
627 let mut sock = match TcpStream::connect((host.as_str(), port)) {
628 Ok(s) => s,
629 Err(e) => {
630 post_socket_error(
631 &io_tx,
632 sock_id,
633 format!("Error: connect ECONNREFUSED {host}:{port}: {e}"),
634 );
635 return;
636 }
637 };
638 let mut conn = match ClientConnection::new(config, server_name) {
639 Ok(c) => c,
640 Err(e) => {
641 post_socket_error(&io_tx, sock_id, format!("Error: tls: {e}"));
642 return;
643 }
644 };
645 if let Err(e) = conn.complete_io(&mut sock) {
647 post_socket_error(&io_tx, sock_id, format!("Error: tls handshake failed: {e}"));
648 return;
649 }
650 let _ = io_tx.send(Box::new(move || on_secure_connect(sock_id)));
651 let stream = StreamOwned::new(conn, sock);
652 owner_loop(stream, sock_id, rx, io_tx);
653 });
654
655 Ok(socket)
656}
657
658fn on_secure_connect(sock_id: u64) -> Result<(), String> {
660 let socket = TLS.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.emitter.clone()));
661 if let Some(socket) = socket {
662 super::events::instance_call(
663 &socket,
664 "emit",
665 vec![with_host(|h| h.new_str("secureConnect"))],
666 )?;
667 }
668 Ok(())
669}
670
671fn post_socket_error(io_tx: &Sender<IoTask>, sock_id: u64, msg: String) {
673 let _ = io_tx.send(Box::new(move || {
674 let socket = TLS.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.emitter.clone()));
675 if let Some(socket) = socket {
676 let err = with_host(|h| {
677 let mut m = IndexMap::new();
678 m.insert("message".into(), h.new_str(msg.clone()));
679 h.new_object(m)
680 });
681 super::events::instance_call(
682 &socket,
683 "emit",
684 vec![with_host(|h| h.new_str("error")), err],
685 )?;
686 }
687 on_socket_close(sock_id)
688 }));
689}
690
691pub fn create_server(args: &[Value]) -> Result<Value, String> {
697 let mut options: Option<Value> = None;
698 let mut listener: Option<Value> = None;
699 for a in args {
700 if with_host(|h| crate::host::is_callable(h, a)) {
701 listener = Some(a.clone());
702 } else if matches!(a, Value::Obj(_)) {
703 options = Some(a.clone());
704 }
705 }
706 let opts = options.ok_or_else(|| {
707 crate::host::type_error("tls.createServer requires an options object with `key` and `cert`")
708 })?;
709 let cert = value_bytes(get_prop(&opts, "cert").as_ref());
710 let key = value_bytes(get_prop(&opts, "key").as_ref());
711 if cert.is_empty() || key.is_empty() {
712 return Err(crate::host::type_error(
713 "tls.createServer requires `key` and `cert`",
714 ));
715 }
716 let config = build_server_config(&cert, &key)?;
717
718 let mut extra = IndexMap::new();
719 if let Some(cb) = listener {
720 extra.insert("@@connListener".into(), cb);
721 }
722 let server = new_emitter_object("TLSServer", extra);
723 PENDING_CONFIGS.with(|p| p.borrow_mut().push((server.clone(), config)));
724 Ok(server)
725}
726
727pub fn create_server_with_config(
731 config: Arc<ServerConfig>,
732 hook: ConnHook,
733 request_listener: Value,
734) -> Value {
735 let mut extra = IndexMap::new();
736 extra.insert("@@requestListener".into(), request_listener);
737 let server = new_emitter_object("TLSServer", extra);
738 PENDING_CONFIGS.with(|p| p.borrow_mut().push((server.clone(), config)));
739 PENDING_HOOKS.with(|p| p.borrow_mut().push((server.clone(), hook)));
740 server
741}
742
743fn take_pending_config(server: &Value) -> Option<Arc<ServerConfig>> {
744 PENDING_CONFIGS.with(|p| {
745 let mut p = p.borrow_mut();
746 p.iter()
747 .position(|(s, _)| s == server)
748 .map(|pos| p.remove(pos).1)
749 })
750}
751fn take_pending_hook(server: &Value) -> Option<ConnHook> {
752 PENDING_HOOKS.with(|p| {
753 let mut p = p.borrow_mut();
754 p.iter()
755 .position(|(s, _)| s == server)
756 .map(|pos| p.remove(pos).1)
757 })
758}
759
760pub fn instance_call(
763 tag: &str,
764 recv: &Value,
765 method: &str,
766 args: Vec<Value>,
767) -> Result<Value, String> {
768 match tag {
769 "TLSServer" => server_call(recv, method, args),
770 "TLSSocket" => socket_call(recv, method, args),
771 _ => Err(crate::host::type_error(&format!(
772 "{method} is not a function"
773 ))),
774 }
775}
776
777fn server_call(recv: &Value, method: &str, args: Vec<Value>) -> Result<Value, String> {
778 if let Some(r) = emitter_dispatch(recv, method, &args) {
779 return r;
780 }
781 match method {
782 "listen" => server_listen(recv, &args),
783 "close" => server_close(recv, &args),
784 "address" => Ok(get_prop(recv, "@@address").unwrap_or(Value::Undef)),
785 _ => Err(crate::host::type_error(&format!(
786 "server.{method} is not a function"
787 ))),
788 }
789}
790
791fn server_listen(recv: &Value, args: &[Value]) -> Result<Value, String> {
794 let port = with_host(|h| args.first().map(|v| h.to_number(v)).unwrap_or(0.0)) as u16;
795 let mut host = "0.0.0.0".to_string();
796 let mut cb: Option<Value> = None;
797 for a in &args[1.min(args.len())..] {
798 if with_host(|h| h.as_str(a)).is_some() {
799 host = with_host(|h| h.str_of(a));
800 } else if with_host(|h| crate::host::is_callable(h, a)) {
801 cb = Some(a.clone());
802 }
803 }
804
805 let config = take_pending_config(recv)
806 .ok_or_else(|| crate::host::type_error("tls server has no secure context"))?;
807 let listener = std::net::TcpListener::bind((host.as_str(), port))
808 .map_err(|e| format!("Error: listen EADDRINUSE: {e}"))?;
809 let local = listener.local_addr().ok();
810
811 let id = next_server_id();
812 set_prop(recv, "@@serverid", Value::Float(id as f64));
813 if let Some(addr) = local {
814 let mut a = IndexMap::new();
815 a.insert("port".into(), Value::Float(addr.port() as f64));
816 a.insert(
817 "address".into(),
818 with_host(|h| h.new_str(addr.ip().to_string())),
819 );
820 a.insert(
821 "family".into(),
822 with_host(|h| h.new_str(if addr.is_ipv6() { "IPv6" } else { "IPv4" })),
823 );
824 let addr_obj = with_host(|h| h.new_object(a));
825 set_prop(recv, "@@address", addr_obj);
826 }
827 let conn_hook = take_pending_hook(recv);
828 let request_listener = get_prop(recv, "@@requestListener");
829 let plain_listener = get_prop(recv, "@@connListener");
830 let stop = Arc::new(AtomicBool::new(false));
831 TLS.with(|s| {
832 s.borrow_mut().servers.insert(
833 id,
834 TlsServerRec {
835 emitter: recv.clone(),
836 stop: stop.clone(),
837 conn_hook,
838 listener: plain_listener,
839 },
840 );
841 });
842 let _ = request_listener;
845 with_host(|h| h.incr_handle());
846
847 let io_tx = with_host(|h| h.io_sender());
848 listener.set_nonblocking(true).ok();
849 std::thread::spawn(move || {
850 loop {
851 if stop.load(Ordering::Acquire) {
852 break;
853 }
854 match listener.accept() {
855 Ok((stream, _addr)) => {
856 let cfg = config.clone();
857 let tx = io_tx.clone();
858 std::thread::spawn(move || accept_connection(id, stream, cfg, tx));
860 }
861 Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => {
862 std::thread::sleep(std::time::Duration::from_millis(5));
863 }
864 Err(_) => break,
865 }
866 }
867 });
868
869 let server = recv.clone();
870 let _ = with_host(|h| h.io_sender()).send(Box::new(move || {
871 super::events::instance_call(&server, "emit", vec![with_host(|h| h.new_str("listening"))])?;
872 if let Some(cb) = cb {
873 invoke(&cb, Vec::new(), None)?;
874 }
875 Ok(())
876 }));
877 Ok(recv.clone())
878}
879
880fn accept_connection(
883 server_id: u64,
884 mut sock: TcpStream,
885 config: Arc<ServerConfig>,
886 io_tx: Sender<IoTask>,
887) {
888 let mut conn = match ServerConnection::new(config) {
889 Ok(c) => c,
890 Err(_) => return,
891 };
892 if conn.complete_io(&mut sock).is_err() {
893 return;
894 }
895 let sock_id = next_tls_id();
896 let (tx, rx) = std::sync::mpsc::channel::<WriteCmd>();
897 let tx_for_main = tx;
898 let _ = io_tx.send(Box::new(move || {
899 on_server_connection(server_id, sock_id, tx_for_main)
900 }));
901 let stream = StreamOwned::new(conn, sock);
902 owner_loop(stream, sock_id, rx, io_tx);
903}
904
905fn on_server_connection(server_id: u64, sock_id: u64, tx: Sender<WriteCmd>) -> Result<(), String> {
908 let server = TLS.with(|s| {
909 s.borrow()
910 .servers
911 .get(&server_id)
912 .map(|r| r.emitter.clone())
913 });
914 let Some(server) = server else { return Ok(()) };
915
916 let mut extra = IndexMap::new();
917 extra.insert("@@tlsid".into(), Value::Float(sock_id as f64));
918 extra.insert("encrypted".into(), Value::Bool(true));
919 let socket = new_emitter_object("TLSSocket", extra);
920 TLS.with(|s| {
921 s.borrow_mut().sockets.insert(
922 sock_id,
923 TlsSocketRec {
924 emitter: socket.clone(),
925 tx,
926 },
927 );
928 });
929 with_host(|h| h.incr_handle());
930
931 super::events::instance_call(
933 &server,
934 "emit",
935 vec![with_host(|h| h.new_str("secureConnection")), socket.clone()],
936 )?;
937 super::events::instance_call(
938 &server,
939 "emit",
940 vec![with_host(|h| h.new_str("connection")), socket.clone()],
941 )?;
942
943 let hook = TLS.with(|s| {
945 s.borrow()
946 .servers
947 .get(&server_id)
948 .and_then(|r| r.conn_hook.clone())
949 });
950 if let Some(hook) = hook {
951 hook(&server, &socket, sock_id)?;
952 } else {
953 let listener = TLS.with(|s| {
954 s.borrow()
955 .servers
956 .get(&server_id)
957 .and_then(|r| r.listener.clone())
958 });
959 if let Some(cb) = listener {
960 invoke(&cb, vec![socket.clone()], None)?;
961 }
962 }
963 Ok(())
964}
965
966fn server_close(recv: &Value, args: &[Value]) -> Result<Value, String> {
967 if let Some(id) = u64_prop(recv, "@@serverid") {
968 let rec = TLS.with(|s| s.borrow_mut().servers.remove(&id));
969 if let Some(rec) = rec {
970 rec.stop.store(true, Ordering::Release);
971 with_host(|h| h.decr_handle());
972 let _ = with_host(|h| h.io_sender()).send(Box::new(|| Ok(())));
973 }
974 }
975 if let Some(cb) = args
976 .first()
977 .filter(|v| with_host(|h| crate::host::is_callable(h, v)))
978 {
979 invoke(cb, Vec::new(), None)?;
980 }
981 super::events::instance_call(recv, "emit", vec![with_host(|h| h.new_str("close"))])?;
982 Ok(recv.clone())
983}
984
985fn socket_call(recv: &Value, method: &str, args: Vec<Value>) -> Result<Value, String> {
988 if let Some(r) = emitter_dispatch(recv, method, &args) {
989 return r;
990 }
991 match method {
992 "write" => {
993 if let Some(id) = u64_prop(recv, "@@tlsid") {
994 socket_write(id, &value_bytes(args.first()));
995 }
996 Ok(Value::Bool(true))
997 }
998 "end" => {
999 if let Some(id) = u64_prop(recv, "@@tlsid") {
1000 if let Some(chunk) = args.first().filter(|v| !matches!(v, Value::Undef)) {
1001 socket_write(id, &value_bytes(Some(chunk)));
1002 }
1003 socket_end(id);
1004 }
1005 Ok(recv.clone())
1006 }
1007 "destroy" => {
1008 if let Some(id) = u64_prop(recv, "@@tlsid") {
1009 socket_end(id);
1010 }
1011 Ok(recv.clone())
1012 }
1013 "setEncoding" | "setTimeout" | "setNoDelay" | "setKeepAlive" | "ref" | "unref"
1014 | "pause" | "resume" => Ok(recv.clone()),
1015 _ => Err(crate::host::type_error(&format!(
1016 "socket.{method} is not a function"
1017 ))),
1018 }
1019}
1020
1021pub fn socket_write(sock_id: u64, data: &[u8]) {
1024 let tx = TLS.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.tx.clone()));
1025 if let Some(tx) = tx {
1026 let _ = tx.send(WriteCmd::Data(data.to_vec()));
1027 }
1028}
1029
1030pub fn socket_end(sock_id: u64) {
1032 let tx = TLS.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.tx.clone()));
1033 if let Some(tx) = tx {
1034 let _ = tx.send(WriteCmd::Shutdown);
1035 }
1036}
1037
1038fn owner_loop<C, S>(
1046 mut stream: StreamOwned<C, TcpStream>,
1047 sock_id: u64,
1048 rx: Receiver<WriteCmd>,
1049 io_tx: Sender<IoTask>,
1050) where
1051 C: DerefMut + Deref<Target = ConnectionCommon<S>>,
1052 S: SideData,
1053{
1054 stream
1055 .sock
1056 .set_read_timeout(Some(std::time::Duration::from_millis(20)))
1057 .ok();
1058 let mut buf = [0u8; 16384];
1059 loop {
1060 let mut shutdown = false;
1062 loop {
1063 match rx.try_recv() {
1064 Ok(WriteCmd::Data(bytes)) => {
1065 if stream
1066 .write_all(&bytes)
1067 .and_then(|_| stream.flush())
1068 .is_err()
1069 {
1070 let _ = io_tx.send(Box::new(move || on_socket_close(sock_id)));
1071 return;
1072 }
1073 }
1074 Ok(WriteCmd::Shutdown) => shutdown = true,
1075 Err(std::sync::mpsc::TryRecvError::Empty) => break,
1076 Err(std::sync::mpsc::TryRecvError::Disconnected) => break,
1077 }
1078 }
1079 if shutdown {
1080 stream.conn.send_close_notify();
1081 let _ = stream.flush();
1082 let _ = stream.sock.shutdown(std::net::Shutdown::Write);
1083 }
1084
1085 match stream.read(&mut buf) {
1087 Ok(0) => {
1088 let _ = io_tx.send(Box::new(move || on_socket_end(sock_id)));
1089 return;
1090 }
1091 Ok(n) => {
1092 let bytes = buf[..n].to_vec();
1093 let _ = io_tx.send(Box::new(move || on_socket_data(sock_id, bytes)));
1094 }
1095 Err(ref e)
1096 if matches!(
1097 e.kind(),
1098 std::io::ErrorKind::WouldBlock | std::io::ErrorKind::TimedOut
1099 ) =>
1100 {
1101 continue;
1103 }
1104 Err(_) => {
1105 let _ = io_tx.send(Box::new(move || on_socket_close(sock_id)));
1106 return;
1107 }
1108 }
1109 }
1110}
1111
1112fn on_socket_data(sock_id: u64, bytes: Vec<u8>) -> Result<(), String> {
1115 let socket = TLS.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.emitter.clone()));
1116 let Some(socket) = socket else { return Ok(()) };
1117 super::https::feed(sock_id, &socket, &bytes)?;
1119 let chunk = super::buffer::from_bytes(&bytes);
1120 super::events::instance_call(
1121 &socket,
1122 "emit",
1123 vec![with_host(|h| h.new_str("data")), chunk],
1124 )?;
1125 Ok(())
1126}
1127
1128fn on_socket_end(sock_id: u64) -> Result<(), String> {
1129 let socket = TLS.with(|s| s.borrow().sockets.get(&sock_id).map(|r| r.emitter.clone()));
1130 if let Some(socket) = socket {
1131 super::events::instance_call(&socket, "emit", vec![with_host(|h| h.new_str("end"))])?;
1132 }
1133 on_socket_close(sock_id)
1134}
1135
1136fn on_socket_close(sock_id: u64) -> Result<(), String> {
1137 let rec = TLS.with(|s| s.borrow_mut().sockets.remove(&sock_id));
1138 super::https::drop_conn(sock_id);
1139 if let Some(rec) = rec {
1140 super::events::instance_call(
1141 &rec.emitter,
1142 "emit",
1143 vec![with_host(|h| h.new_str("close"))],
1144 )?;
1145 with_host(|h| h.decr_handle());
1146 let _ = with_host(|h| h.io_sender()).send(Box::new(|| Ok(())));
1147 }
1148 Ok(())
1149}
1150
1151pub fn new_emitter_object(tag: &str, mut extra: IndexMap<String, Value>) -> Value {
1156 with_host(|h| {
1157 let on = h.new_object(IndexMap::new());
1158 let once = h.new_object(IndexMap::new());
1159 let mut m = IndexMap::new();
1160 m.insert("@@native".into(), h.new_str(tag));
1161 m.insert("@@on".into(), on);
1162 m.insert("@@once".into(), once);
1163 for (k, v) in extra.drain(..) {
1164 m.insert(k, v);
1165 }
1166 h.new_object(m)
1167 })
1168}