@@ -1590,6 +1590,143 @@ pub fn test_socket<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
15901590 Ok ( ( ) )
15911591}
15921592
1593+ pub fn test_socket_bind_listen < S : squeue:: EntryMarker , C : cqueue:: EntryMarker > (
1594+ ring : & mut IoUring < S , C > ,
1595+ test : & Test ,
1596+ ) -> anyhow:: Result < ( ) > {
1597+ use socket2:: { Domain , Protocol , Socket , Type } ;
1598+
1599+ require ! (
1600+ test;
1601+ test. probe. is_supported( opcode:: Socket :: CODE ) ;
1602+ test. probe. is_supported( opcode:: Bind :: CODE ) ;
1603+ test. probe. is_supported( opcode:: Listen :: CODE ) ;
1604+ ) ;
1605+
1606+ println ! ( "test socket_bind_listen" ) ;
1607+
1608+ // Open a TCP socket through old-style `socket(2)` syscall.
1609+ // This is used both as a kernel sanity check, and for comparing the returned io-uring FD.
1610+ let plain_socket = Socket :: new ( Domain :: IPV4 , Type :: STREAM , Some ( Protocol :: TCP ) ) . unwrap ( ) ;
1611+ let plain_fd = plain_socket. as_raw_fd ( ) ;
1612+
1613+ let socket_fd_op = opcode:: Socket :: new (
1614+ Domain :: IPV4 . into ( ) ,
1615+ Type :: STREAM . into ( ) ,
1616+ Protocol :: TCP . into ( ) ,
1617+ ) ;
1618+ unsafe {
1619+ ring. submission ( )
1620+ . push ( & socket_fd_op. build ( ) . user_data ( 42 ) . into ( ) )
1621+ . expect ( "queue is full" ) ;
1622+ }
1623+ ring. submit_and_wait ( 1 ) ?;
1624+
1625+ let cqes: Vec < cqueue:: Entry > = ring. completion ( ) . map ( Into :: into) . collect ( ) ;
1626+ assert_eq ! ( cqes. len( ) , 1 ) ;
1627+ assert_eq ! ( cqes[ 0 ] . user_data( ) , 42 ) ;
1628+ assert ! ( cqes[ 0 ] . result( ) >= 0 ) ;
1629+ let io_uring_socket = unsafe { Socket :: from_raw_fd ( cqes[ 0 ] . result ( ) ) } ;
1630+ assert ! ( io_uring_socket. as_raw_fd( ) != plain_fd) ;
1631+ assert_eq ! ( cqes[ 0 ] . flags( ) , 0 ) ;
1632+
1633+ // Try to bind.
1634+ {
1635+ let server_addr: std:: net:: SocketAddr = "127.0.0.1:0" . parse ( ) . unwrap ( ) ;
1636+ let server_addr: socket2:: SockAddr = server_addr. into ( ) ;
1637+ let op = io_uring:: opcode:: Bind :: new (
1638+ io_uring:: types:: Fd ( io_uring_socket. as_raw_fd ( ) ) ,
1639+ server_addr. as_ptr ( ) as * const _ ,
1640+ server_addr. len ( ) ,
1641+ )
1642+ . build ( )
1643+ . user_data ( 2345 ) ;
1644+ unsafe {
1645+ ring. submission ( ) . push ( & op. into ( ) ) . expect ( "queue is full" ) ;
1646+ }
1647+ ring. submit_and_wait ( 1 ) ?;
1648+ let cqes: Vec < cqueue:: Entry > = ring. completion ( ) . map ( Into :: into) . collect ( ) ;
1649+ assert_eq ! ( cqes. len( ) , 1 ) ;
1650+ assert_eq ! ( cqes[ 0 ] . user_data( ) , 2345 ) ;
1651+ assert_eq ! ( cqes[ 0 ] . result( ) , 0 ) ;
1652+ assert_eq ! ( cqes[ 0 ] . flags( ) , 0 ) ;
1653+
1654+ assert_eq ! (
1655+ io_uring_socket
1656+ . local_addr( )
1657+ . expect( "no local addr" )
1658+ . as_socket_ipv4( )
1659+ . expect( "no IPv4 address" )
1660+ . ip( ) ,
1661+ server_addr. as_socket_ipv4( ) . unwrap( ) . ip( )
1662+ ) ;
1663+ }
1664+
1665+ // Try to listen.
1666+ {
1667+ let op =
1668+ io_uring:: opcode:: Listen :: new ( io_uring:: types:: Fd ( io_uring_socket. as_raw_fd ( ) ) , 128 )
1669+ . build ( )
1670+ . user_data ( 3456 ) ;
1671+ unsafe {
1672+ ring. submission ( ) . push ( & op. into ( ) ) . expect ( "queue is full" ) ;
1673+ }
1674+ ring. submit_and_wait ( 1 ) ?;
1675+ let cqes: Vec < cqueue:: Entry > = ring. completion ( ) . map ( Into :: into) . collect ( ) ;
1676+ assert_eq ! ( cqes. len( ) , 1 ) ;
1677+ assert_eq ! ( cqes[ 0 ] . user_data( ) , 3456 ) ;
1678+ assert_eq ! ( cqes[ 0 ] . result( ) , 0 ) ;
1679+ assert_eq ! ( cqes[ 0 ] . flags( ) , 0 ) ;
1680+
1681+ // Ensure the socket is actually in the listening state.
1682+ _ = TcpStream :: connect (
1683+ io_uring_socket
1684+ . local_addr ( )
1685+ . unwrap ( )
1686+ . as_socket_ipv4 ( )
1687+ . unwrap ( ) ,
1688+ ) ?;
1689+ }
1690+
1691+ // Close both sockets, to avoid leaking FDs.
1692+ drop ( plain_socket) ;
1693+ drop ( io_uring_socket) ;
1694+
1695+ // Cleanup all fixed files (if any), then reserve slot 0.
1696+ let _ = ring. submitter ( ) . unregister_files ( ) ;
1697+ ring. submitter ( ) . register_files_sparse ( 1 ) . unwrap ( ) ;
1698+
1699+ let fixed_socket_op = opcode:: Socket :: new (
1700+ Domain :: IPV4 . into ( ) ,
1701+ Type :: DGRAM . into ( ) ,
1702+ Protocol :: UDP . into ( ) ,
1703+ ) ;
1704+ let dest_slot = types:: DestinationSlot :: try_from_slot_target ( 0 ) . unwrap ( ) ;
1705+ unsafe {
1706+ ring. submission ( )
1707+ . push (
1708+ & fixed_socket_op
1709+ . file_index ( Some ( dest_slot) )
1710+ . build ( )
1711+ . user_data ( 55 )
1712+ . into ( ) ,
1713+ )
1714+ . expect ( "queue is full" ) ;
1715+ }
1716+ ring. submit_and_wait ( 1 ) ?;
1717+
1718+ let cqes: Vec < cqueue:: Entry > = ring. completion ( ) . map ( Into :: into) . collect ( ) ;
1719+ assert_eq ! ( cqes. len( ) , 1 ) ;
1720+ assert_eq ! ( cqes[ 0 ] . user_data( ) , 55 ) ;
1721+ assert_eq ! ( cqes[ 0 ] . result( ) , 0 ) ;
1722+ assert_eq ! ( cqes[ 0 ] . flags( ) , 0 ) ;
1723+
1724+ // If the fixed-socket operation worked properly, this must not fail.
1725+ ring. submitter ( ) . unregister_files ( ) . unwrap ( ) ;
1726+
1727+ Ok ( ( ) )
1728+ }
1729+
15931730pub fn test_udp_recvmsg_multishot < S : squeue:: EntryMarker , C : cqueue:: EntryMarker > (
15941731 ring : & mut IoUring < S , C > ,
15951732 test : & Test ,
0 commit comments