@@ -19,13 +19,15 @@ use crate::{
1919 server:: Server ,
2020 tcp:: { TCPReadHandle , TCPServer , TCPServerRef , TCPTransport , TCPWriteHandle } ,
2121 time:: Timer ,
22+ udp:: { UDPReadHandle , UDPTransport , UDPWriteHandle } ,
2223} ;
2324
2425enum IOHandle {
2526 Py ( PyHandleData ) ,
2627 Signals ,
2728 TCPListener ( TCPListenerHandleData ) ,
2829 TCPStream ( Interest ) ,
30+ UDPSocket ( Interest ) ,
2931}
3032
3133struct PyHandleData {
@@ -73,6 +75,7 @@ pub struct EventLoop {
7375 task_factory : RwLock < PyObject > ,
7476 tcp_lstreams : papaya:: HashMap < usize , papaya:: HashSet < usize > > ,
7577 tcp_transports : papaya:: HashMap < usize , Py < TCPTransport > > ,
78+ udp_transports : papaya:: HashMap < usize , Py < UDPTransport > > ,
7679 thread_id : atomic:: AtomicI64 ,
7780 watcher_child : RwLock < PyObject > ,
7881 #[ pyo3( get) ]
@@ -149,6 +152,7 @@ impl EventLoop {
149152 IOHandle :: Py ( handle) => self . handle_io_py ( py, event, handle, & mut cb_handles) ,
150153 IOHandle :: TCPListener ( handle) => self . handle_io_tcpl ( py, handle, & io_handles, & mut cb_handles) ,
151154 IOHandle :: TCPStream ( _) => self . handle_io_tcps ( event, & mut cb_handles) ,
155+ IOHandle :: UDPSocket ( _) => self . handle_io_udp ( event, & mut cb_handles) ,
152156 IOHandle :: Signals => self . handle_io_signals ( py, & mut state. buf , & mut cb_handles) ,
153157 }
154158 }
@@ -231,7 +235,7 @@ impl EventLoop {
231235 let fd = stream. as_raw_fd ( ) as usize ;
232236 let token = Token ( fd) ;
233237 #[ allow( clippy:: cast_possible_wrap) ]
234- let mut source = Source :: TCPStream ( fd as i32 ) ;
238+ let mut source = Source :: FD ( fd as i32 ) ;
235239 let ( pytransport, stream_handle) = handle. server . new_stream ( py, stream) ;
236240 transports. insert ( fd, pytransport) ;
237241 lstreams. insert ( fd) ;
@@ -254,6 +258,16 @@ impl EventLoop {
254258 }
255259 }
256260
261+ #[ inline]
262+ fn handle_io_udp ( & self , event : & event:: Event , handles_ready : & mut VecDeque < BoxedHandle > ) {
263+ let fd = event. token ( ) . 0 ;
264+ if event. is_readable ( ) {
265+ handles_ready. push_back ( Box :: new ( UDPReadHandle { fd } ) ) ;
266+ } else if event. is_writable ( ) {
267+ handles_ready. push_back ( Box :: new ( UDPWriteHandle { fd } ) ) ;
268+ }
269+ }
270+
257271 #[ inline]
258272 fn handle_io_signals ( & self , py : Python , buf : & mut [ u8 ] , handles_ready : & mut VecDeque < BoxedHandle > ) {
259273 let mut sock_guard = self . ssock . write ( ) . unwrap ( ) ;
@@ -338,7 +352,7 @@ impl EventLoop {
338352 } ,
339353 || {
340354 #[ allow( clippy:: cast_possible_wrap) ]
341- let mut source = Source :: TCPStream ( fd as i32 ) ;
355+ let mut source = Source :: FD ( fd as i32 ) ;
342356 {
343357 let guard_poll = self . io . lock ( ) . unwrap ( ) ;
344358 _ = guard_poll. registry ( ) . register ( & mut source, token, interest) ;
@@ -403,6 +417,83 @@ impl EventLoop {
403417 }
404418 }
405419
420+ #[ inline]
421+ pub ( crate ) fn udp_socket_add ( & self , fd : usize , interest : Interest ) {
422+ let token = Token ( fd) ;
423+ self . handles_io . pin ( ) . update_or_insert_with (
424+ token,
425+ |io_handle| {
426+ if let IOHandle :: UDPSocket ( interest_prev) = io_handle {
427+ if * interest_prev == interest {
428+ return IOHandle :: UDPSocket ( interest) ;
429+ }
430+
431+ let interests = * interest_prev | interest;
432+ {
433+ #[ allow( clippy:: cast_possible_wrap) ]
434+ let mut source = Source :: FD ( fd as i32 ) ;
435+ let guard_poll = self . io . lock ( ) . unwrap ( ) ;
436+ _ = guard_poll. registry ( ) . reregister ( & mut source, token, interests) ;
437+ }
438+ return IOHandle :: UDPSocket ( interests) ;
439+ }
440+ unreachable ! ( )
441+ } ,
442+ || {
443+ #[ allow( clippy:: cast_possible_wrap) ]
444+ let mut source = Source :: FD ( fd as i32 ) ;
445+ {
446+ let guard_poll = self . io . lock ( ) . unwrap ( ) ;
447+ _ = guard_poll. registry ( ) . register ( & mut source, token, interest) ;
448+ }
449+ IOHandle :: UDPSocket ( interest)
450+ } ,
451+ ) ;
452+ }
453+
454+ #[ inline]
455+ pub ( crate ) fn udp_socket_rem ( & self , fd : usize , interest : Interest ) {
456+ let token = Token ( fd) ;
457+
458+ match self . handles_io . pin ( ) . remove_if ( & token, |_, io_handle| {
459+ if let IOHandle :: UDPSocket ( interest_ex) = io_handle {
460+ return * interest_ex == interest;
461+ }
462+ false
463+ } ) {
464+ Ok ( None ) => { }
465+ Ok ( _) => {
466+ #[ allow( clippy:: cast_possible_wrap) ]
467+ let mut source = Source :: FD ( fd as i32 ) ;
468+ let guard_poll = self . io . lock ( ) . unwrap ( ) ;
469+ _ = guard_poll. registry ( ) . deregister ( & mut source) ;
470+ }
471+ _ => {
472+ self . handles_io . pin ( ) . update ( token, |io_handle| {
473+ if let IOHandle :: UDPSocket ( interest_ex) = io_handle {
474+ let interest_new = interest_ex. remove ( interest) . unwrap ( ) ;
475+ #[ allow( clippy:: cast_possible_wrap) ]
476+ let mut source = Source :: FD ( fd as i32 ) ;
477+ let guard_poll = self . io . lock ( ) . unwrap ( ) ;
478+ _ = guard_poll. registry ( ) . reregister ( & mut source, token, interest_new) ;
479+ return IOHandle :: UDPSocket ( interest_new) ;
480+ }
481+ unreachable ! ( )
482+ } ) ;
483+ }
484+ }
485+ }
486+
487+ #[ inline]
488+ pub ( crate ) fn udp_socket_close ( & self , fd : usize ) {
489+ self . udp_transports . pin ( ) . remove ( & fd) ;
490+ }
491+
492+ #[ inline( always) ]
493+ pub ( crate ) fn get_udp_transport ( & self , fd : usize , py : Python ) -> Py < UDPTransport > {
494+ self . udp_transports . pin ( ) . get ( & fd) . unwrap ( ) . clone_ref ( py)
495+ }
496+
406497 pub ( crate ) fn log_exception ( & self , py : Python , ctx : LogExc ) -> PyResult < PyObject > {
407498 let handler = self . exc_handler . read ( ) . unwrap ( ) ;
408499 handler. call1 (
@@ -631,6 +722,7 @@ impl EventLoop {
631722 task_factory : RwLock :: new ( py. None ( ) ) ,
632723 tcp_lstreams : papaya:: HashMap :: with_capacity ( 32 ) ,
633724 tcp_transports : papaya:: HashMap :: with_capacity ( 1024 ) ,
725+ udp_transports : papaya:: HashMap :: with_capacity ( 1024 ) ,
634726 thread_id : atomic:: AtomicI64 :: new ( 0 ) ,
635727 watcher_child : RwLock :: new ( py. None ( ) ) ,
636728 _asyncgens : weakset ( py) ?. unbind ( ) ,
@@ -1110,6 +1202,23 @@ impl EventLoop {
11101202 self . tcp_transports . pin ( ) . contains_key ( & fd)
11111203 }
11121204
1205+ fn _udp_conn (
1206+ pyself : Py < Self > ,
1207+ py : Python ,
1208+ sock : ( i32 , i32 ) ,
1209+ protocol_factory : PyObject ,
1210+ remote_addr : Option < ( String , u16 ) > ,
1211+ ) -> PyResult < ( Py < UDPTransport > , PyObject ) > {
1212+ let rself = pyself. get ( ) ;
1213+ let transport = UDPTransport :: from_py ( py, & pyself, sock, protocol_factory, remote_addr) ;
1214+ let fd = transport. fd ;
1215+ let pytransport = Py :: new ( py, transport) ?;
1216+ let proto = UDPTransport :: attach ( & pytransport, py) ?;
1217+ rself. udp_transports . pin ( ) . insert ( fd, pytransport. clone_ref ( py) ) ;
1218+ rself. udp_socket_add ( fd, Interest :: READABLE ) ;
1219+ Ok ( ( pytransport, proto) )
1220+ }
1221+
11131222 fn _sig_add ( & self , py : Python , sig : u8 , callback : PyObject , args : PyObject , context : PyObject ) {
11141223 let handle = Py :: new ( py, CBHandle :: new ( callback, args, context) ) . unwrap ( ) ;
11151224 self . sig_handlers . pin ( ) . insert ( sig, handle) ;
0 commit comments