Program Listing for File PacketUtils.h

Return to documentation for file (/home/docs/checkouts/readthedocs.org/user_builds/ska-telescope-ska-pst-recv/checkouts/latest/src/ska/pst/recv/network/PacketUtils.h)

/*
 * Copyright 2022 Square Kilometre Array Observatory
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <memory>
#include <vector>
#include <cstdint>

#include "ska/pst/recv/network/Endian.h"

#ifndef SKA_PST_RECV_NETWORK_PacketUtils_h
#define SKA_PST_RECV_NETWORK_PacketUtils_h

namespace ska::pst::recv {

  typedef std::array<uint8_t, 6> mac_address;

  typedef std::array<uint8_t, 4> ip_addr_v4;

  class PacketBuffer
  {
    public:
      PacketBuffer();

      PacketBuffer(char *ptr, size_t length);

      char * data() const;

      size_t size() const;

    protected:

      template<typename T>
      T get(size_t offset) const
      {
        T out;
        std::memcpy(&out, ptr + offset, sizeof(out));
        return out;
      }

      template<typename T>
      T get_be(size_t offset) const
      {
        return betoh(get<T>(offset));
      }

    private:
      char * ptr;
      size_t length;
  };

  class UDPPacket : public PacketBuffer
  {
    public:
      static constexpr size_t min_size = 8;

      static constexpr uint8_t protocol = 0x11;

      UDPPacket() = default;

      UDPPacket(char *ptr, size_t size);

      uint16_t source_port() const { return get_be<uint16_t>(0); };

      uint16_t destination_port() const { return get_be<uint16_t>(2); };

      uint16_t length() const { return get_be<uint16_t>(4); };

      uint16_t checksum() const { return get_be<uint16_t>(6); };

      PacketBuffer payload() const;
  };

  class IPv4Packet : public PacketBuffer
  {
    public:
      static constexpr size_t min_size = 20;
      static constexpr uint16_t ethertype = 0x0800;
      static constexpr uint16_t flag_do_not_fragment = 0x4000;
      static constexpr uint16_t flag_more_fragments = 0x2000;
      static constexpr uint16_t flag_more_fragments_bitmask = 0x1fff;
      static constexpr uint8_t header_length_bitmask = 0xf;

      IPv4Packet() = default;

      IPv4Packet(char *ptr, size_t size);

      uint8_t version_ihl() const { return get<uint8_t>(0); };
      uint8_t dscp_ecn() const { return get<uint8_t>(1); };
      uint16_t total_length() const{ return get_be<uint16_t>(2); };
      uint16_t identification() const { return get_be<uint16_t>(4); };
      uint16_t flags_frag_off() const { return get_be<uint16_t>(6); };
      uint8_t ttl() const { return get<uint8_t>(8); };
      uint8_t protocol() const { return get<uint8_t>(9); };
      uint16_t checksum() const { return get<uint16_t>(10); };
      ip_addr_v4 source_address() const { return get<ip_addr_v4>(12); };
      ip_addr_v4 destination_address() const { return get<ip_addr_v4>(16); };

      bool is_fragment() const;
      size_t header_length() const;
      int version() const;
      UDPPacket payload_udp() const;
  };

  class EthernetFrame : public PacketBuffer
  {
    public:
      static constexpr size_t min_size = 14;

      EthernetFrame() = default;

      EthernetFrame(char * ptr, size_t size);

      mac_address destination_mac() const { return get<mac_address>(0); };

      mac_address source_mac() const { return get<mac_address>(6); };

      uint16_t ethertype() const { return get_be<uint16_t>(12); };

      IPv4Packet payload_ipv4() const;
  };

  PacketBuffer udp_from_ethernet(char *ptr, size_t size);

  mac_address interface_mac(const std::string &ip_address);

} // namespace ska::pst::recv
#endif // SKA_PST_RECV_NETWORK_PacketUtils_h