@@ -108,6 +108,9 @@ const MAX_DISPATCH_PAYLOAD: usize = 64 * 1024 * 1024;
108108/// Cap for `__hl_sleep` duration to prevent unbounded host-thread blocking (60 s).
109109const MAX_SLEEP_NS : u64 = 60_000_000_000 ;
110110
111+ /// Default socket timeout for read/write/connect operations (30 s).
112+ const SOCKET_TIMEOUT : std:: time:: Duration = std:: time:: Duration :: from_secs ( 30 ) ;
113+
111114/// A preopened host directory exposed to the guest.
112115///
113116/// Semantics mirror Wasmtime's `preopened_dir`: `host_dir` is canonicalised
@@ -1211,6 +1214,8 @@ fn handle_net_socket(
12111214 Some ( Protocol :: from ( protocol) )
12121215 } ;
12131216 let sock = Socket :: new ( domain, stype, proto) ?;
1217+ sock. set_read_timeout ( Some ( SOCKET_TIMEOUT ) ) ?;
1218+ sock. set_write_timeout ( Some ( SOCKET_TIMEOUT ) ) ?;
12141219 let fd = table. lock ( ) . unwrap ( ) . insert ( HostSocket {
12151220 socket : sock,
12161221 sock_type,
@@ -1229,9 +1234,11 @@ fn handle_net_connect(
12291234 let addr = parse_sockaddr ( args) ?;
12301235 policy. check ( & addr) ?;
12311236 let sa: SockAddr = addr. into ( ) ;
1232- let tbl = table. lock ( ) . unwrap ( ) ;
1233- let sock = tbl. get_socket ( fd) ?;
1234- sock. connect ( & sa) ?;
1237+ let sock = {
1238+ let tbl = table. lock ( ) . unwrap ( ) ;
1239+ tbl. get_socket ( fd) ?. try_clone ( ) ?
1240+ } ;
1241+ sock. connect_timeout ( & sa, SOCKET_TIMEOUT ) ?;
12351242 Ok ( json ! ( { } ) )
12361243}
12371244
@@ -3435,4 +3442,27 @@ mod tests {
34353442 al. learn_ip ( IpAddr :: V4 ( Ipv4Addr :: new ( 10 , 1 , 0 , 1 ) ) ) ;
34363443 assert_eq ! ( al. learned_ips. lock( ) . unwrap( ) . len( ) , MAX_LEARNED_IPS ) ;
34373444 }
3445+
3446+ #[ test]
3447+ fn net_socket_has_default_timeout ( ) {
3448+ let mut tools = ToolRegistry :: new ( ) ;
3449+ let exit_code = Arc :: new ( AtomicI32 :: new ( 0 ) ) ;
3450+ let table =
3451+ register_internal_tools ( & mut tools, & exit_code, Some ( & NetworkPolicy :: AllowAll ) , None )
3452+ . expect ( "network tools should be registered" ) ;
3453+
3454+ let req = br#"{"name":"net_socket","args":{"family":2,"type":1}}"# ;
3455+ let resp = tools. dispatch ( req) ;
3456+ let s = std:: str:: from_utf8 ( & resp) . unwrap ( ) ;
3457+ assert ! ( !s. contains( "error" ) , "socket creation should succeed: {s}" ) ;
3458+
3459+ let v: serde_json:: Value = serde_json:: from_str ( s) . unwrap ( ) ;
3460+ let fd = v[ "result" ] [ "fd" ] . as_u64 ( ) . unwrap ( ) ;
3461+ assert ! ( fd > 0 ) ;
3462+
3463+ let tbl = table. lock ( ) . unwrap ( ) ;
3464+ let sock = tbl. get_socket ( fd) . unwrap ( ) ;
3465+ assert_eq ! ( sock. read_timeout( ) . unwrap( ) , Some ( SOCKET_TIMEOUT ) ) ;
3466+ assert_eq ! ( sock. write_timeout( ) . unwrap( ) , Some ( SOCKET_TIMEOUT ) ) ;
3467+ }
34383468}
0 commit comments