LCOV - code coverage report
Current view: top level - util/net - fd_udp.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 6 34 17.6 %
Date: 2024-11-13 11:58:15 Functions: 3 48 6.2 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_util_net_fd_udp_h
       2             : #define HEADER_fd_src_util_net_fd_udp_h
       3             : 
       4             : #include "fd_ip4.h" /* UDP is tightly tied to IP regardless of standard intent due to pseudo header layer violating BS */
       5             : 
       6             : /* FIXME: UDP CRASH COURSE HERE */
       7             : 
       8             : union fd_udp_hdr {
       9             :   struct {
      10             :     ushort net_sport; /* src port, net order */
      11             :     ushort net_dport; /* dst port, net order */
      12             :     ushort net_len;   /* datagram length, from first byte of this header to last byte of the udp payload */
      13             :     ushort check;     /* UDP checksum ("invariant" order), from first byte of pseudo header prepended before this header to last
      14             :                          byte of udp payload with zero padding to even length inclusive.  In IP4, 0 indicates no checksum. */
      15             :   };
      16             :   uint u[2];
      17             : };
      18             : 
      19             : typedef union fd_udp_hdr fd_udp_hdr_t;
      20             : 
      21             : /* FIXME: CONSIDER A PRETTY PRINTER FOR A FD_UDP_HDR? */
      22             : 
      23             : FD_PROTOTYPES_BEGIN
      24             : 
      25             : /* fd_ip4_udp_check is used for udp check field computation and
      26             :    validation.  If the dgram has no checksum (check==0), this returns
      27             :    the value to use for check.  If the dgram has a checksum (check!=0),
      28             :    this returns 0 if the message has a valid checksum or non-zero if
      29             :    not.  ip4_saddr and ip4_daddr are the ip4 source and destination
      30             :    addresses to use for the udp pseudo header.  udp is a non-NULL
      31             :    pointer to the first byte of a memory region containing the udp
      32             :    header and dgram is a non-NULL pointer to the first byte of a memory
      33             :    region containing a datagram of size:
      34             : 
      35             :      dgram_sz = fd_ushort_bswap(udp->net_len) - sizeof(fd_udp_hdr_t)
      36             : 
      37             :    bytes.  This assumes it is safe to read up to 3 bytes past the end of
      38             :    dgram (technically it will read the fd_align_up(dgram_sz,4UL) bytes
      39             :    dgram).  The contents of the tail read region are irrelevant.
      40             : 
      41             :    This is neither a particularly fast calculation (reasonably fast
      42             :    O(dgram_sz)) nor a particularly robust and it can inhibit cut-through
      43             :    usage.  So in general it is best to avoid UDP checksums, usually by
      44             :    exploiting their optionality in IP4 (note that the Ethernet CRC is
      45             :    reasonably strong and still provides protection).
      46             : 
      47             :    As such, this is mostly here for the rare application that needs to
      48             :    manually compute / validate UDP checksums (e.g. overhead doesn't
      49             :    matter or when the hardware sending/receiving the packet doesn't do
      50             :    various checksum offload computations and UDP checksums are
      51             :    required).
      52             : 
      53             :    WARNING!  With strict aliasing optimizations enabled and having this
      54             :    inline, the caller might need to type pun the dgram value passed to
      55             :    this (e.g. fd_type_pun_const(my_dgram)), wrap their dgram structure
      56             :    in a union like seen above for the udp_hdr_t or play various games
      57             :    with the may_alias attribute.  fd_type_pun_const is the quickest way
      58             :    to handle this but can inhibit various optimizations.  Wrapping in a
      59             :    union type is the fastest and most conformant way to handle this.
      60             :    The compiler is pretty good at catching when this is necessary and
      61             :    warning about it but be careful here.  FIXME: CONSIDER NOT INLINING
      62             :    THIS? */
      63             : 
      64             : FD_FN_PURE static inline ushort
      65             : fd_ip4_udp_check( uint                 ip4_saddr,
      66             :                   uint                 ip4_daddr,
      67             :                   fd_udp_hdr_t const * udp,
      68           0 :                   void const *         dgram ) { /* Assumed safe to tail read up to 3 bytes past end of msg */
      69           0 :   ushort net_len = udp->net_len; /* In net order */
      70           0 :   uint   rem     = (uint)fd_ushort_bswap( net_len ) - (uint)sizeof(fd_udp_hdr_t);
      71           0 : 
      72           0 :   /* Sum the pseudo header and UDP header words */
      73           0 :   uint const * u = udp->u;
      74           0 :   ulong ul = ((((ulong)FD_IP4_HDR_PROTOCOL_UDP)<<8) | (((ulong)net_len)<<16))
      75           0 :            + ((ulong)ip4_saddr)
      76           0 :            + ((ulong)ip4_daddr)
      77           0 :            + ((ulong)u[0])
      78           0 :            + ((ulong)u[1]);
      79           0 : 
      80           0 :   /* Sum the dgram words (reads up to 4 past end of msg) */
      81           0 :   u = (uint const *)dgram; /* See warning above */
      82           0 :   for( ; rem>3U; rem-=4U, u++ ) ul += (ulong)u[0];
      83           0 :   ul += (ulong)( u[0] & ((1U<<(8U*rem))-1U) );
      84           0 : 
      85           0 :   /* Reduce the sum to a 16-bit one's complement sum */
      86           0 :   ul  = ( ul>>32            ) +
      87           0 :         ((ul>>16) & 0xffffUL) +
      88           0 :         ( ul      & 0xffffUL);
      89           0 :   ul  = ( ul>>16            ) +
      90           0 :         ( ul      & 0xffffUL);
      91           0 :   ul += ( ul>>16            );
      92           0 : 
      93           0 :   /* And complement it */
      94           0 :   return (ushort)~ul;
      95           0 : }
      96             : 
      97             : /* fd_udp_hdr_bswap reverses the endianness of all fields in the UDP
      98             :    header. */
      99             : 
     100             : static inline void
     101    37643694 : fd_udp_hdr_bswap( fd_udp_hdr_t * hdr ) {
     102    37643694 :   hdr->net_sport = (ushort)fd_ushort_bswap( hdr->net_sport    );
     103    37643694 :   hdr->net_dport = (ushort)fd_ushort_bswap( hdr->net_dport    );
     104    37643694 :   hdr->net_len   = (ushort)fd_ushort_bswap( hdr->net_len      );
     105    37643694 :   hdr->check     = (ushort)fd_ushort_bswap( hdr->check        );
     106    37643694 : }
     107             : 
     108             : FD_PROTOTYPES_END
     109             : 
     110             : #endif /* HEADER_fd_src_util_net_fd_udp_h */

Generated by: LCOV version 1.14