char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
1f64888
main
1use std:: collections:: HashMap ; 2use std:: convert:: Infallible ; 3use std:: io; 4use std:: sync:: atomic::{ AtomicBool , AtomicU64 , Ordering }; 5use std:: sync::{ Arc , Mutex }; 6 7use avril_caps::{ Capabilities , PathTarget }; 8use avril_core:: serde_v8::{ JsBuffer , ToJsBuffer }; 9use avril_core::{ Extension , Op }; 10use avril_net::{ Address , Endpoint , Socket }; 11use serde:: Serialize ; 12use tokio:: io::{ AsyncReadExt , AsyncWriteExt , ReadHalf , WriteHalf }; 13use tokio:: sync::{ Mutex as AsyncMutex , oneshot}; 14use tokio_util:: sync:: CancellationToken ; 15 16use avril_host:: io:: response; 17 18mod udp; 19 20const CHUNK : usize =64 * 1024 ; 21const MAX_ID : u64 =9_007_199_254_740_991 ; 22type ConnectionInfo =( u64 , Endpoint , Endpoint ); 23type ListenerInfo =( u64 , Endpoint ); 24 25fn closed () -> io:: Error { 26 io:: Error :: new ( io:: ErrorKind :: NotConnected , "Socket is closed" ) 27} 28 29# [ derive ( Clone )] 30enum Authority { 31Net { 32caps : Arc < Capabilities >, 33hostname : String , 34port : u16 , 35}, 36Unix { 37caps : Arc < Capabilities >, 38target : PathTarget , 39}, 40} 41impl Authority { 42fn check ( & self ) -> io:: Result <()> { 43let result =match self { 44Self :: Net { caps, hostname, port} => caps. check_net ( hostname, * port), 45Self :: Unix { caps, target} => caps. check_write ( target), 46}; 47 result. map_err ( |error| io:: Error :: new ( io:: ErrorKind :: PermissionDenied , error)) 48} 49} 50fn authority ( 51mut address : Address , 52caps : & Arc < Capabilities >, 53connecting : bool , 54) -> io:: Result <( Address , Authority )> { 55let authority =match & mut address{ 56Address :: Tcp { hostname, port} =>Authority :: Net { 57caps : caps. clone (), 58hostname : hostname. clone (), 59port : * port, 60}, 61Address :: Unix { path} =>{ 62if !cfg! ( unix) { 63return Err ( io:: Error :: new ( 64 io:: ErrorKind :: Unsupported , 65"Unix sockets are not supported on this platform" , 66)); 67} 68let label = path 69. as_ref () 70. filter ( |path| !path. is_empty ()) 71. ok_or_else ( ||{ 72 io:: Error :: new ( io:: ErrorKind :: InvalidInput , "Missing Unix socket path" ) 73}) ?; 74let target =if connecting{ 75PathTarget :: resolve ( caps. cwd (). join ( label)) ? 76} else { 77PathTarget :: for_entry ( caps. cwd (). join ( label)) ? 78}; 79* path =Some ( 80 target 81. as_path () 82. to_str () 83. ok_or_else ( ||{ 84 io:: Error :: new ( 85 io:: ErrorKind :: InvalidInput , 86"Unix socket paths must be UTF-8" , 87) 88}) ? 89. to_owned (), 90); 91Authority :: Unix { caps : caps. clone (), target} 92} 93}; 94 authority. check () ?; 95Ok (( address, authority)) 96} 97fn hostname ( value : & str ) ->& str { 98 value 99. strip_prefix ( '[' ) 100. and_then ( |value| value. strip_suffix ( ']' )) 101. unwrap_or ( value) 102} 103 104struct Connection { 105reader : AsyncMutex < ReadHalf < Socket >>, 106writer : AsyncMutex < WriteHalf < Socket >>, 107write_closed : AtomicBool , 108canceled : CancellationToken , 109authority : Authority , 110local : Endpoint , 111remote : Endpoint , 112} 113impl Connection { 114fn new ( 115socket : Socket , 116local : Endpoint , 117remote : Endpoint , 118authority : Authority , 119canceled : CancellationToken , 120) ->Self { 121let ( reader, writer) = tokio:: io:: split ( socket); 122Self { 123reader : AsyncMutex :: new ( reader), 124writer : AsyncMutex :: new ( writer), 125write_closed : AtomicBool :: new ( false ), 126 canceled, 127 authority, 128 local, 129 remote, 130} 131} 132} 133struct Listener { 134socket : avril_net:: Listener , 135authority : Authority , 136canceled : CancellationToken , 137} 138struct Pending { 139receiver : AsyncMutex < Option < oneshot:: Receiver < io:: Result < Connection >>>>, 140canceled : CancellationToken , 141} 142enum Resource { 143Connection ( Arc < Connection >), 144Listener ( Arc < Listener >), 145Pending ( Arc < Pending >), 146Datagram ( Arc < udp:: Datagram >), 147} 148impl Resource { 149fn cancel ( & self ) { 150match self { 151Self :: Connection ( value) => value. canceled . cancel (), 152Self :: Listener ( value) => value. canceled . cancel (), 153Self :: Pending ( value) => value. canceled . cancel (), 154Self :: Datagram ( value) => value. canceled . cancel (), 155} 156} 157} 158// Spawned I/O must not keep the registry alive: its drop cancels worker resources. 159struct Sockets { 160runtime : tokio:: runtime:: Handle , 161caps : Arc < Capabilities >, 162resources : Mutex < HashMap < u64 , Resource >>, 163next : AtomicU64 , 164canceled : CancellationToken , 165} 166impl Drop for Sockets { 167fn drop ( & mut self ) { 168self . canceled . cancel (); 169} 170} 171impl Sockets { 172fn id ( & self ) -> io:: Result < u64 > { 173self . next 174. fetch_update ( Ordering :: Relaxed , Ordering :: Relaxed , |id|{ 175( id <=MAX_ID ). then_some ( id +1 ) 176}) 177. map_err ( |_| io:: Error :: other ( "Socket IDs exhausted" )) 178} 179fn connection ( & self , id : u64 ) -> io:: Result < Arc < Connection >> { 180match self . resources . lock (). unwrap (). get ( & id) { 181Some ( Resource :: Connection ( value)) =>Ok ( value. clone ()), 182 _ =>Err ( closed ()), 183} 184} 185fn insert ( & self , connection : Connection ) -> io:: Result < ConnectionInfo > { 186let id =self . id () ?; 187let row =( id, connection. local . clone (), connection. remote . clone ()); 188self . resources 189. lock () 190. unwrap () 191. insert ( id, Resource :: Connection ( Arc :: new ( connection))); 192Ok ( row) 193} 194fn listen ( & self , target : Address ) -> io:: Result < ListenerInfo > { 195let ( target, mut authority) =authority ( target, & self . caps , false ) ?; 196let ( socket, local) = 197 avril_net:: Listener :: bind ( & self . runtime , & target). map_err ( io:: Error :: other) ?; 198if let ( Authority :: Net { port, ..}, Endpoint :: Tcp ( selected)) =( & mut authority, & local) { 199* port = selected. port (); 200} 201 authority. check () ?; 202let id =self . id () ?; 203self . resources . lock (). unwrap (). insert ( 204 id, 205Resource :: Listener ( Arc :: new ( Listener { 206 socket, 207 authority, 208canceled : self . canceled . child_token (), 209})), 210); 211Ok (( id, local)) 212} 213fn start ( & self , target : Address ) -> io:: Result < u64 > { 214let ( target, authority) =authority ( target, & self . caps , true ) ?; 215let id =self . id () ?; 216let canceled =self . canceled . child_token (); 217let ( sender, receiver) = oneshot:: channel (); 218self . resources . lock (). unwrap (). insert ( 219 id, 220Resource :: Pending ( Arc :: new ( Pending { 221receiver : AsyncMutex :: new ( Some ( receiver)), 222canceled : canceled. clone (), 223})), 224); 225self . runtime . spawn ( async move { 226let result =async { 227let ( socket, local, remote): ( Socket , Endpoint , Endpoint ) =match & target{ 228Address :: Tcp { hostname : host, port} =>{ 229let socket=tokio:: net:: TcpStream :: connect (( hostname ( host), * port)). await ?; 230let local=Endpoint :: Tcp ( socket. local_addr () ?); 231let remote=Endpoint :: Tcp ( socket. peer_addr () ?); 232( socket. into (), local, remote) 233} 234# [ cfg ( unix )] 235Address :: Unix { path : Some ( path) } =>{ 236let socket=tokio:: net:: UnixStream :: connect ( path). await ?; 237let local=Endpoint :: Unix { path : socket. local_addr () ?. as_pathname (). map ( |path|path. to_string_lossy (). into_owned ())}; 238( socket. into (), local, Endpoint :: Unix { path : Some ( path. clone ())}) 239} 240 _ =>return Err ( io:: Error :: new ( io:: ErrorKind :: Unsupported , "Unsupported socket transport" )), 241}; 242 authority. check () ?; 243Ok ( Connection :: new ( socket, local, remote, authority, canceled. clone ())) 244}; 245let value = tokio:: select!{ biased; _=canceled. cancelled () =>Err ( closed ()), value=result=>value}; 246let _ = sender. send ( value); 247}); 248Ok ( id) 249} 250fn close ( & self , id : u64 ) -> io:: Result <()> { 251let value =self 252. resources 253. lock () 254. unwrap () 255. remove ( & id) 256. ok_or_else ( closed) ?; 257 value. cancel (); 258Ok (()) 259} 260} 261 262async fn reply < T : Serialize >( 263task : tokio:: task:: JoinHandle < io:: Result < T >>, 264) ->Result < impl Serialize , Infallible > { 265Ok ( response ( task. await . unwrap_or_else ( |error|{ 266Err ( io:: Error :: other ( error. to_string ())) 267}))) 268} 269 270pub fn init ( runtime : tokio:: runtime:: Handle , caps : Arc < Capabilities >) ->Extension { 271let sockets =Arc :: new ( Sockets { 272runtime : runtime. clone (), 273 caps, 274resources : Mutex :: new ( HashMap :: new ()), 275next : AtomicU64 :: new ( 0 ), 276canceled : CancellationToken :: new (), 277}); 278let mut ops =vec! [ 279Op :: new ( "op_net_listen" , { 280let sockets = sockets. clone (); 281move |target : Address |Ok ::< _ , Infallible >( response ( sockets. listen ( target))) 282}), 283Op :: new ( "op_net_connect_start" , { 284let sockets = sockets. clone (); 285move |target : Address |Ok ::< _ , Infallible >( response ( sockets. start ( target))) 286}), 287Op :: asynchronous ( "op_net_connected" , { 288let sockets = sockets. clone (); 289move |id : u64 |{ 290let pending =match sockets. resources . lock (). unwrap (). get ( & id) { 291Some ( Resource :: Pending ( value)) =>Some ( value. clone ()), 292 _ =>None , 293}; 294let weak =Arc :: downgrade ( & sockets); 295reply ( runtime. spawn ( async move { 296let pending = pending. ok_or_else ( closed) ?; 297let receiver = pending. receiver . lock (). await . take (). ok_or_else ( closed) ?; 298let connection = tokio:: select!{ 299 biased; 300 _ = pending. canceled . cancelled () =>return Err ( closed ()), 301 value = receiver => value. map_err ( |_|closed ()) ??, 302}; 303 connection. authority . check () ?; 304let sockets = weak. upgrade (). ok_or_else ( closed) ?; 305let row =( id, connection. local . clone (), connection. remote . clone ()); 306let mut resources = sockets. resources . lock (). unwrap (); 307if pending. canceled . is_cancelled () || !resources. contains_key ( & id) { 308return Err ( closed ()); 309} 310 resources. insert ( id, Resource :: Connection ( Arc :: new ( connection))); 311Ok ( row) 312})) 313} 314}), 315Op :: asynchronous ( "op_net_accept" , { 316let sockets = sockets. clone (); 317let runtime = sockets. runtime . clone (); 318move |id : u64 |{ 319let listener =match sockets. resources . lock (). unwrap (). get ( & id) { 320Some ( Resource :: Listener ( value)) =>Some ( value. clone ()), 321 _ =>None , 322}; 323let weak =Arc :: downgrade ( & sockets); 324let canceled = sockets. canceled . child_token (); 325reply ( runtime. spawn ( async move { 326let listener = listener. ok_or_else ( closed) ?; 327 listener. authority . check () ?; 328let accepted = tokio:: select!{ 329 biased; 330 _ = listener. canceled . cancelled () =>return Err ( closed ()), 331 value = listener. socket . accept () => value?, 332}; 333 listener. authority . check () ?; 334if listener. canceled . is_cancelled () { 335return Err ( closed ()); 336} 337let connection =Connection :: new ( 338 accepted. socket , 339 accepted. local , 340 accepted. remote , 341 listener. authority . clone (), 342 canceled, 343); 344 weak. upgrade (). ok_or_else ( closed) ?. insert ( connection) 345})) 346} 347}), 348Op :: asynchronous ( "op_net_read" , { 349let sockets = sockets. clone (); 350let runtime = sockets. runtime . clone (); 351move |( id, count): ( u64 , usize ) |{ 352let connection = sockets. connection ( id); 353reply ( runtime. spawn ( async move { 354let connection = connection?; 355 connection. authority . check () ?; 356let work =async { 357let mut reader = connection. reader . lock (). await ; 358 connection. authority . check () ?; 359let mut bytes =vec! [ 0 ; count. min ( CHUNK )]; 360if bytes. is_empty () { 361return Ok ( Some ( ToJsBuffer :: from ( bytes))); 362} 363let count = reader. read ( & mut bytes). await ?; 364 connection. authority . check () ?; 365if count ==0 { 366return Ok ( None ); 367} 368 bytes. truncate ( count); 369Ok ( Some ( ToJsBuffer :: from ( bytes))) 370}; 371 tokio:: select!{ 372 biased; 373 _ = connection. canceled . cancelled () =>Err ( closed ()), 374 value = work => value, 375} 376})) 377} 378}), 379Op :: asynchronous ( "op_net_write" , { 380let sockets = sockets. clone (); 381let runtime = sockets. runtime . clone (); 382move |( id, bytes): ( u64 , JsBuffer ) |{ 383let connection = sockets. connection ( id); 384let bytes = bytes[ ..bytes. len (). min ( CHUNK )]. to_vec (); 385reply ( runtime. spawn ( async move { 386let connection = connection?; 387let work =async { 388let mut writer = connection. writer . lock (). await ; 389 connection. authority . check () ?; 390if connection. write_closed . load ( Ordering :: Acquire ) { 391return Err ( closed ()); 392} 393 writer. write ( & bytes). await 394}; 395 tokio:: select!{ 396 biased; 397 _ = connection. canceled . cancelled () =>Err ( closed ()), 398 value = work => value, 399} 400})) 401} 402}), 403Op :: asynchronous ( "op_net_writev" , { 404let sockets = sockets. clone (); 405let runtime = sockets. runtime . clone (); 406move |( id, buffers): ( u64 , Vec < JsBuffer >) |{ 407let connection = sockets. connection ( id); 408let segments = avril_host:: io:: bound_vectored ( buffers); 409reply ( runtime. spawn ( async move { 410let connection = connection?; 411let work =async { 412let mut writer = connection. writer . lock (). await ; 413 connection. authority . check () ?; 414if connection. write_closed . load ( Ordering :: Acquire ) { 415return Err ( closed ()); 416} 417if segments. is_empty () { 418return Ok ( 0 ); 419} 420let slices = segments 421. iter () 422. map ( |segment| io:: IoSlice :: new ( segment)) 423. collect ::< Vec < _ >>(); 424 writer. write_vectored ( & slices). await 425}; 426 tokio:: select!{ 427 biased; 428 _ = connection. canceled . cancelled () =>Err ( closed ()), 429 value = work => value, 430} 431})) 432} 433}), 434Op :: asynchronous ( "op_net_shutdown" , { 435let sockets = sockets. clone (); 436let runtime = sockets. runtime . clone (); 437move |id : u64 |{ 438let connection = sockets. connection ( id); 439reply ( runtime. spawn ( async move { 440let connection = connection?; 441let work =async { 442let mut writer = connection. writer . lock (). await ; 443 connection. authority . check () ?; 444if !connection. write_closed . swap ( true , Ordering :: AcqRel ) { 445 writer. shutdown (). await ?; 446} 447Ok (()) 448}; 449 tokio:: select!{ 450 biased; 451 _ = connection. canceled . cancelled () =>Err ( closed ()), 452 value = work => value, 453} 454})) 455} 456}), 457Op :: new ( "op_net_close" , { 458let sockets = sockets. clone (); 459move |id : u64 |Ok ::< _ , Infallible >( response ( sockets. close ( id))) 460}), 461]; 462 ops. extend ( udp:: ops ( sockets)); 463Extension { 464name : "ext:net" , 465dependencies : & [ "ext:file" , "ext:web" , "ext:webstreams" ], 466 ops, 467modules : & [( 468"ext:net/main.js" , 469include_str! ( concat! ( env! ( "OUT_DIR" ), "/main.js" )), 470)], 471entry_point : None , 472} 473}