LCOV - code coverage report
Current view: top level - disco/net - fd_net_sock.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 48 0.0 %
Date: 2026-11-11 12:40:43 Functions: 0 21 0.0 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_disco_net_fd_net_sock_h
       2             : #define HEADER_fd_src_disco_net_fd_net_sock_h
       3             : 
       4             : #include "../fd_disco_base.h"
       5             : #include "../../util/net/fd_ip4.h"
       6             : 
       7             : #include <errno.h>
       8             : #include <sys/socket.h>
       9             : #include <netinet/in.h>
      10             : 
      11             : /* fd_net_sock_ops_t is the syscall interface used by fd_net_sock.
      12             :    Signatures and semantics match libc.  Tests substitute mocks. */
      13             : struct fd_net_sock_ops {
      14             :   int  (*socket)( int domain, int type, int protocol );
      15             :   long (*sendto)( int sock, void const * buf, ulong len, int flags, struct sockaddr const * addr, socklen_t addr_len );
      16             : };
      17             : typedef struct fd_net_sock_ops fd_net_sock_ops_t;
      18             : 
      19             : struct fd_net_sock {
      20             :   fd_net_sock_ops_t const * ops;
      21             :   int                       sock;
      22             : };
      23             : typedef struct fd_net_sock fd_net_sock_t;
      24             : 
      25             : FD_PROTOTYPES_BEGIN
      26             : 
      27             : /* fd_net_sock_init_ops is the same as fd_net_sock_init but uses the
      28             :    given ops instead of libc.  ops and each of its members must be
      29             :    non-NULL. */
      30             : static fd_net_sock_t *
      31             : fd_net_sock_init_ops( fd_net_sock_t *           net_sock,
      32           0 :                       fd_net_sock_ops_t const * ops ) {
      33           0 :   if( FD_UNLIKELY( !net_sock ) ) {
      34           0 :     FD_LOG_WARNING(( "NULL net_sock" ));
      35           0 :     errno = EINVAL;
      36           0 :     return NULL;
      37           0 :   }
      38           0 :   if( FD_UNLIKELY( !ops ) ) {
      39           0 :     FD_LOG_WARNING(( "NULL ops" ));
      40           0 :     errno = EINVAL;
      41           0 :     return NULL;
      42           0 :   }
      43           0 :   if( FD_UNLIKELY( !ops->socket ) ) {
      44           0 :     FD_LOG_WARNING(( "NULL ops->socket" ));
      45           0 :     errno = EINVAL;
      46           0 :     return NULL;
      47           0 :   }
      48           0 :   if( FD_UNLIKELY( !ops->sendto ) ) {
      49           0 :     FD_LOG_WARNING(( "NULL ops->sendto" ));
      50           0 :     errno = EINVAL;
      51           0 :     return NULL;
      52           0 :   }
      53           0 :   int const sock = ops->socket( AF_INET, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, IPPROTO_RAW );
      54           0 :   if( FD_UNLIKELY( sock<0 ) ) {
      55           0 :     int const err = errno;
      56           0 :     FD_LOG_WARNING(( "socket(AF_INET,SOCK_RAW|SOCK_NONBLOCK,IPPROTO_RAW) failed (%i-%s)", err, fd_io_strerror( err ) ));
      57           0 :     errno = err;
      58           0 :     return NULL;
      59           0 :   }
      60           0 :   net_sock->ops  = ops;
      61           0 :   net_sock->sock = sock;
      62           0 :   return net_sock;
      63           0 : }
      64             : 
      65             : /* fd_net_sock_init initializes net_sock and opens a non-blocking
      66             :    send-only IPPROTO_RAW socket.  It is not bound to an interface and
      67             :    relies on the kernel to route packets.  Returns net_sock on success
      68             :    and NULL on error with errno set. */
      69             : static fd_net_sock_t *
      70           0 : fd_net_sock_init( fd_net_sock_t * net_sock ) {
      71           0 :   static fd_net_sock_ops_t const ops = {
      72           0 :     .socket = socket,
      73           0 :     .sendto = sendto
      74           0 :   };
      75           0 :   return fd_net_sock_init_ops( net_sock, &ops );
      76           0 : }
      77             : 
      78             : /* fd_net_sock_send sends one packet on net_sock with a single
      79             :    non-blocking sendto.  ip4 points to the beginning of an IPv4 header.
      80             :    ip4_sz is the size of the IP header and payload.  The L2 header will
      81             :    be constructed by the kernel.  The destination is ip4->daddr.
      82             :    Returns 1 if the whole packet was sent and 0 if the packet was
      83             :    not (the send would block, failed, or was short).  Failed packets
      84             :    are not retried. */
      85             : FD_FN_UNUSED static int
      86             : fd_net_sock_send( fd_net_sock_t *      net_sock,
      87             :                   fd_ip4_hdr_t const * ip4,
      88           0 :                   ulong                ip4_sz ) {
      89           0 :   struct sockaddr_in sa = {
      90           0 :     .sin_family      = AF_INET,
      91           0 :     .sin_addr.s_addr = ip4->daddr,
      92           0 :     .sin_port        = 0 /* ignored */
      93           0 :   };
      94             :   /* Single non-blocking attempt.  If the send would block, fails, or
      95             :      is short, the packet is dropped. */
      96           0 :   long const sent_sz = net_sock->ops->sendto( net_sock->sock, ip4, ip4_sz, MSG_DONTWAIT, fd_type_pun_const( &sa ), sizeof(struct sockaddr_in) );
      97           0 :   return sent_sz==(long)ip4_sz;
      98           0 : }
      99             : 
     100             : FD_PROTOTYPES_END
     101             : 
     102             : #endif /* HEADER_fd_src_disco_net_fd_net_sock_h */

Generated by: LCOV version 1.14