From 7b59f5276334574ba4f606b3d4486917fa993fed Mon Sep 17 00:00:00 2001 From: Matt Millett Date: Sat, 17 Aug 2024 13:08:17 -0400 Subject: [PATCH] Describe Ethernet addresses, protocols, and its header --- groups/nts/ntsa/ntsa_ethernetaddress.cpp | 186 +++++++++++ groups/nts/ntsa/ntsa_ethernetaddress.h | 350 ++++++++++++++++++++ groups/nts/ntsa/ntsa_ethernetaddress.t.cpp | 71 ++++ groups/nts/ntsa/ntsa_ethernetheader.cpp | 72 ++++ groups/nts/ntsa/ntsa_ethernetheader.h | 311 +++++++++++++++++ groups/nts/ntsa/ntsa_ethernetheader.t.cpp | 76 +++++ groups/nts/ntsa/ntsa_ethernetprotocol.cpp | 104 ++++++ groups/nts/ntsa/ntsa_ethernetprotocol.h | 88 +++++ groups/nts/ntsa/ntsa_ethernetprotocol.t.cpp | 55 +++ groups/nts/ntsa/package/ntsa.mem | 3 + targets.cmake | 3 + 11 files changed, 1319 insertions(+) create mode 100644 groups/nts/ntsa/ntsa_ethernetaddress.cpp create mode 100644 groups/nts/ntsa/ntsa_ethernetaddress.h create mode 100644 groups/nts/ntsa/ntsa_ethernetaddress.t.cpp create mode 100644 groups/nts/ntsa/ntsa_ethernetheader.cpp create mode 100644 groups/nts/ntsa/ntsa_ethernetheader.h create mode 100644 groups/nts/ntsa/ntsa_ethernetheader.t.cpp create mode 100644 groups/nts/ntsa/ntsa_ethernetprotocol.cpp create mode 100644 groups/nts/ntsa/ntsa_ethernetprotocol.h create mode 100644 groups/nts/ntsa/ntsa_ethernetprotocol.t.cpp diff --git a/groups/nts/ntsa/ntsa_ethernetaddress.cpp b/groups/nts/ntsa/ntsa_ethernetaddress.cpp new file mode 100644 index 000000000..b289d016c --- /dev/null +++ b/groups/nts/ntsa/ntsa_ethernetaddress.cpp @@ -0,0 +1,186 @@ +// Copyright 2020-2023 Bloomberg Finance L.P. +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +BSLS_IDENT_RCSID(ntsa_ethernetaddress_cpp, "$Id$ $CSID$") + +#include +#include +#include +#include +#include +#include + +namespace BloombergLP { +namespace ntsa { + +namespace { + +void throwEthernetInvalidFormat(const bslstl::StringRef& text) +{ + bsl::stringstream ss; + ss << "Failed to parse Ethernet address: the text '" + << text + << "' is invalid"; + + NTSCFG_THROW(ss.str()); +} + +bool checkEthernetBufferUnderflow(bsl::size_t size) +{ + if (size < 6) { + return false; + } + + return true; +} + +bool checkEthernetBufferOverflow(bsl::size_t size) +{ + if (size < 6) { + return false; + } + + return true; +} + +} // close unnamed namespace + +EthernetAddress::EthernetAddress(const bslstl::StringRef& text) +{ + bsl::memset(d_value, 0, sizeof d_value); + + if (!this->parse(text)) { + throwEthernetInvalidFormat(text); + } +} + +bsl::size_t EthernetAddress::copyFrom(const void* source, bsl::size_t size) +{ + if (!checkEthernetBufferUnderflow(size)) { + return 0; + } + + bsl::memcpy(&d_value, source, sizeof d_value); + return sizeof d_value; +} + +bsl::size_t EthernetAddress::copyTo(void* destination, + bsl::size_t capacity) const +{ + if (!checkEthernetBufferOverflow(capacity)) { + return 0; + } + + bsl::memcpy(destination, &d_value, sizeof d_value); + return sizeof d_value; +} + +bool EthernetAddress::parse(const bslstl::StringRef& text) +{ + if (text.size() != MAX_TEXT_LENGTH) { + return false; + } + + const char* current = text.begin(); + + for (bsl::size_t i = 0; i < 6; ++i) { + if (i != 0) { + char separator = *current++; + if (separator != ':') { + return false; + } + } + + const char ch1 = *current++; + const char ch2 = *current++; + + const bsl::uint8_t hi = static_cast(bsl::isdigit(ch1) + ? ch1 - '0' + : bsl::tolower(ch1) - 'a' + 10); + + const bsl::uint8_t lo = static_cast(bsl::isdigit(ch2) + ? ch2 - '0' + : bsl::tolower(ch2) - 'a' + 10); + + + d_value[i] = hi << 4 | lo; + } + + return true; +} + +bsl::size_t EthernetAddress::format(char* buffer, + bsl::size_t capacity) const +{ + if (capacity < ntsa::EthernetAddress::MAX_TEXT_LENGTH + 1) { + if (capacity > 0) { + buffer[0] = 0; + } + + return 0; + } + + char* bufferTarget = buffer; + + for (bsl::size_t i = 0; i < 6; ++i) { + const bsl::uint8_t value = d_value[i]; + + const bsl::uint8_t a = value >> 4; + const bsl::uint8_t b = value & 0x0F; + + if (a < 10) { + *bufferTarget++ = static_cast('0' + a); + } + else { + *bufferTarget++ = static_cast('a' + (a - 10)); + } + + if (b < 10) { + *bufferTarget++ = static_cast('0' + b); + } + else { + *bufferTarget++ = static_cast('a' + (b - 10)); + } + + if (i != 5) { + *bufferTarget++ = ':'; + } + } + + *bufferTarget++ = 0; + + return (bufferTarget - buffer) - 1; +} + +bsl::ostream& EthernetAddress::print(bsl::ostream& stream, + int level, + int spacesPerLevel) const +{ + char buffer[ntsa::EthernetAddress::MAX_TEXT_LENGTH + 1]; + const bsl::size_t size = EthernetAddress::format(buffer, sizeof buffer); + + bslim::Printer printer(&stream, level, spacesPerLevel); + printer.start(true); + stream.write(buffer, size); + printer.end(true); + + return stream; +} + +} // close package namespace +} // close enterprise namespace diff --git a/groups/nts/ntsa/ntsa_ethernetaddress.h b/groups/nts/ntsa/ntsa_ethernetaddress.h new file mode 100644 index 000000000..51d4ff9ed --- /dev/null +++ b/groups/nts/ntsa/ntsa_ethernetaddress.h @@ -0,0 +1,350 @@ +// Copyright 2020-2023 Bloomberg Finance L.P. +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef INCLUDED_NTSA_ETHERNETADDRESS +#define INCLUDED_NTSA_ETHERNETADDRESS + +#include +BSLS_IDENT("$Id: $") + +#include +#include +#include +#include +#include +#include + +namespace BloombergLP { +namespace ntsa { + +/// Provide an Ethernet address. +/// +/// @par Thread Safety +/// This class is not thread safe. +/// +/// @ingroup module_ntsa_identity +class EthernetAddress +{ + bsl::uint8_t d_value[6]; + +public: + /// Declare constants used by this implementation. + enum Constant { + /// The maximum required capacity of a buffer to store the longest + /// textual representation of an Ethernet addresses, not including the + /// null terminator. + MAX_TEXT_LENGTH = 17 + }; + + /// Create a new Ethernet address with a default value. + EthernetAddress(); + + /// Create a new IPv4 address parsed from the specified 'text' + /// representation. + explicit EthernetAddress(const bslstl::StringRef& text); + + /// Create a new Ethernet address with the specified 'byte0', 'byte1', + /// 'byte2', 'byte3', 'byte4', and 'byte5' value. + EthernetAddress(bsl::uint8_t byte0, + bsl::uint8_t byte1, + bsl::uint8_t byte2, + bsl::uint8_t byte3, + bsl::uint8_t byte4, + bsl::uint8_t byte5); + + /// Create a new Ethernet address having the same value as the specified + /// 'original' object. Assign an unspecified but valid value to the + /// 'original' original. + EthernetAddress( + bslmf::MovableRef original) NTSCFG_NOEXCEPT; + + /// Create a new Ethernet address with the same value as the specified + /// 'original' object. + EthernetAddress(const EthernetAddress& original); + + /// Destroy this object. + ~EthernetAddress(); + + /// Assign the value of the specified 'other' object to this object. Assign + /// an unspecified but valid value to the 'original' original. Return a + /// reference to this modifiable object. + EthernetAddress& operator=(bslmf::MovableRef other) + NTSCFG_NOEXCEPT; + + /// Assign the value of the specified 'other' object to this object. Return + /// a reference to this modifiable object. + EthernetAddress& operator=(const EthernetAddress& other); + + /// Reset the value of this object to its value upon default construction. + void reset(); + + // Set the value of this object from the value parsed from any of its + /// textual representations. Return true if the 'text' is in a valid + /// format and was parsed successfully, otherwise return false. If false + /// is returned then the value of this object was set to its value upon + /// default construction. + bool parse(const bslstl::StringRef& text); + + /// Copy the representation of the Ethernet address from the specified + /// 'source' having the specified 'size' to this object. Return the + /// number of bytes read. + bsl::size_t copyFrom(const void* source, bsl::size_t size); + + /// Return a reference to the modifiable byte at the specified 'index'. + /// The behavior is undefined unless 'index < 6'. + bsl::uint8_t& operator[](bsl::size_t index); + + /// Copy the value of this object to the representation in the specified + /// 'destination' having the specified 'capacity'. Return the number of + /// bytes written. + bsl::size_t copyTo(void* destination, + bsl::size_t capacity) const; + + /// Format the IPv4 address into the specified 'buffer' having the + /// specified 'capacity'. Return the number of bytes written. + bsl::size_t format(char* buffer, + bsl::size_t capacity) const; + + /// Return the string representation of this object. + bsl::string text() const; + + /// Return true if this object has the same value as the specified + /// 'other' object, otherwise return false. + bool equals(const EthernetAddress& other) const; + + /// Return true if the value of this object is less than the value of + /// the specified 'other' object, otherwise return false. + bool less(const EthernetAddress& other) const; + + /// Contribute the values of the salient attributes of this object to the + /// specified hash 'algorithm'. + template + void hash(HASH_ALGORITHM& algorithm) const; + + /// Format this object to the specified output 'stream' at the + /// optionally specified indentation 'level' and return a reference to + /// the modifiable 'stream'. If 'level' is specified, optionally + /// specify 'spacesPerLevel', the number of spaces per indentation level + /// for this and all of its nested objects. Each line is indented by + /// the absolute value of 'level * spacesPerLevel'. If 'level' is + /// negative, suppress indentation of the first line. If + /// 'spacesPerLevel' is negative, suppress line breaks and format the + /// entire output on one line. If 'stream' is initially invalid, this + /// operation has no effect. Note that a trailing newline is provided + /// in multiline mode only. + bsl::ostream& print(bsl::ostream& stream, + int level = 0, + int spacesPerLevel = 4) const; + + /// Return the value of the byte at the specified 'index'. The behavior + /// is undefined unless 'index < 4'. + bsl::uint8_t operator[](bsl::size_t index) const; + + /// This type's default constructor is equivalent to setting each byte of + /// the object's footprint to zero. + NTSCFG_TYPE_TRAIT_BITWISE_INITIALIZABLE(EthernetAddress); + + /// This type's copy-constructor and copy-assignment operator is equivalent + /// to copying each byte of the source object's footprint to each + /// corresponding byte of the destination object's footprint. + NTSCFG_TYPE_TRAIT_BITWISE_COPYABLE(EthernetAddress); + + /// This type's move-constructor and move-assignment operator is equivalent + /// to copying each byte of the source object's footprint to each + /// corresponding byte of the destination object's footprint. + NTSCFG_TYPE_TRAIT_BITWISE_MOVABLE(EthernetAddress); + + /// This type's equality-comparison operator is equivalent to comparing + /// each byte of one comparand's footprint to each corresponding byte of + /// the other comparand's footprint. Note that this trait implies that an + /// object of this type has no padding bytes between data members. + NTSCFG_TYPE_TRAIT_BITWISE_COMPARABLE(EthernetAddress); +}; + +/// Write a formatted, human-readable description of the specified 'object' +/// into the specified 'stream'. Return a reference to the modifiable +/// 'stream'. +/// +/// @related ntsa::EthernetAddress +bsl::ostream& operator<<(bsl::ostream& stream, const EthernetAddress& object); + +/// Return true if the specified 'lhs' has the same value as the specified +/// 'rhs', otherwise return false. +/// +/// @related ntsa::EthernetAddress +bool operator==(const EthernetAddress& lhs, const EthernetAddress& rhs); + +/// Return true if the specified 'lhs' does not have the same value as the +/// specified 'rhs', otherwise return false. +/// +/// @related ntsa::EthernetAddress +bool operator!=(const EthernetAddress& lhs, const EthernetAddress& rhs); + +/// Return true if the specified 'lhs' is "less than" the specified 'rhs', +/// otherwise return false. +/// +/// @related ntsa::EthernetAddress +bool operator<(const EthernetAddress& lhs, const EthernetAddress& rhs); + +/// Contribute the values of the salient attributes of the specified 'value' +/// to the specified hash 'algorithm'. +/// +/// @related ntsa::EthernetAddress +template +void hashAppend(HASH_ALGORITHM& algorithm, const EthernetAddress& value); + +NTSCFG_INLINE +EthernetAddress::EthernetAddress() +{ + bsl::memset(d_value, 0, sizeof d_value); +} + +NTSCFG_INLINE +EthernetAddress::EthernetAddress(bsl::uint8_t byte0, + bsl::uint8_t byte1, + bsl::uint8_t byte2, + bsl::uint8_t byte3, + bsl::uint8_t byte4, + bsl::uint8_t byte5) +{ + d_value[0] = byte0; + d_value[1] = byte1; + d_value[2] = byte2; + d_value[3] = byte3; + d_value[4] = byte4; + d_value[5] = byte5; +} + +NTSCFG_INLINE +EthernetAddress::EthernetAddress( + bslmf::MovableRef original) NTSCFG_NOEXCEPT +{ + bsl::memcpy(d_value, NTSCFG_MOVE_FROM(original, d_value), sizeof d_value); + NTSCFG_MOVE_RESET(original); +} + +NTSCFG_INLINE +EthernetAddress::EthernetAddress(const EthernetAddress& original) +{ + bsl::memcpy(d_value, original.d_value, sizeof d_value); +} + +NTSCFG_INLINE +EthernetAddress::~EthernetAddress() +{ +} + +NTSCFG_INLINE +EthernetAddress& EthernetAddress::operator=(bslmf::MovableRef other) + NTSCFG_NOEXCEPT +{ + bsl::memcpy(d_value, NTSCFG_MOVE_FROM(other, d_value), sizeof d_value); + NTSCFG_MOVE_RESET(other); + + return *this; +} + +NTSCFG_INLINE +EthernetAddress& EthernetAddress::operator=(const EthernetAddress& other) +{ + if (this != &other) { + bsl::memcpy(d_value, other.d_value, sizeof d_value); + } + + return *this; +} + +NTSCFG_INLINE +void EthernetAddress::reset() +{ + bsl::memset(d_value, 0, sizeof d_value); +} + +NTSCFG_INLINE +bsl::uint8_t& EthernetAddress::operator[](bsl::size_t index) +{ + BSLS_ASSERT(index < sizeof d_value); + return d_value[index]; +} + +NTSCFG_INLINE +bsl::string EthernetAddress::text() const +{ + char buffer[ntsa::EthernetAddress::MAX_TEXT_LENGTH + 1]; + const bsl::size_t size = EthernetAddress::format(buffer, sizeof buffer); + + return bsl::string(buffer, buffer + size); +} + +NTSCFG_INLINE +bool EthernetAddress::equals(const EthernetAddress& other) const +{ + return bsl::memcmp(d_value, other.d_value, sizeof d_value) == 0; +} + +NTSCFG_INLINE +bool EthernetAddress::less(const EthernetAddress& other) const +{ + return bsl::memcmp(d_value, other.d_value, sizeof d_value) < 0; +} + +template +NTSCFG_INLINE +void EthernetAddress::hash(HASH_ALGORITHM& algorithm) const +{ + algorithm(reinterpret_cast(d_value), sizeof d_value); +} + +NTSCFG_INLINE +bsl::uint8_t EthernetAddress::operator[](bsl::size_t index) const +{ + BSLS_ASSERT(index < sizeof d_value); + return d_value[index]; +} + +NTSCFG_INLINE +bsl::ostream& operator<<(bsl::ostream& stream, const EthernetAddress& object) +{ + return object.print(stream, 0, -1); +} + +NTSCFG_INLINE +bool operator==(const EthernetAddress& lhs, const EthernetAddress& rhs) +{ + return lhs.equals(rhs); +} + +NTSCFG_INLINE +bool operator!=(const EthernetAddress& lhs, const EthernetAddress& rhs) +{ + return !operator==(lhs, rhs); +} + +NTSCFG_INLINE +bool operator<(const EthernetAddress& lhs, const EthernetAddress& rhs) +{ + return lhs.less(rhs); +} + +template +NTSCFG_INLINE +void hashAppend(HASH_ALGORITHM& algorithm, const EthernetAddress& value) +{ + value.hash(algorithm); +} + +} // close package namespace +} // close enterprise namespace +#endif diff --git a/groups/nts/ntsa/ntsa_ethernetaddress.t.cpp b/groups/nts/ntsa/ntsa_ethernetaddress.t.cpp new file mode 100644 index 000000000..71c27483d --- /dev/null +++ b/groups/nts/ntsa/ntsa_ethernetaddress.t.cpp @@ -0,0 +1,71 @@ +// Copyright 2020-2023 Bloomberg Finance L.P. +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include + +#include +#include +#include + +using namespace BloombergLP; +using namespace ntsa; + +NTSCFG_TEST_CASE(1) +{ + // Concern: + // Plan: + + ntscfg::TestAllocator ta; + { + ntsa::EthernetAddress address1; + + address1[0] = 0xb8; + address1[1] = 0xe6; + address1[2] = 0x0c; + address1[3] = 0x06; + address1[4] = 0x3c; + address1[5] = 0x7b; + + NTSCFG_TEST_LOG_DEBUG << "Address1 = " << address1 + << NTSCFG_TEST_LOG_END; + + char buffer[ntsa::EthernetAddress::MAX_TEXT_LENGTH + 1]; + bsl::memset(buffer, 0, sizeof buffer); + + bsl::size_t n = address1.format(buffer, sizeof buffer); + NTSCFG_TEST_EQ(n, ntsa::EthernetAddress::MAX_TEXT_LENGTH); + + ntsa::EthernetAddress address2; + + bool result = address2.parse( + bslstl::StringRef(buffer, ntsa::EthernetAddress::MAX_TEXT_LENGTH)); + NTSCFG_TEST_TRUE(result); + + NTSCFG_TEST_LOG_DEBUG << "Address2 = " << address2 + << NTSCFG_TEST_LOG_END; + + NTSCFG_TEST_EQ(address1, address2); + + } + NTSCFG_TEST_ASSERT(ta.numBlocksInUse() == 0); +} + +NTSCFG_TEST_DRIVER +{ + NTSCFG_TEST_REGISTER(1); +} +NTSCFG_TEST_DRIVER_END; diff --git a/groups/nts/ntsa/ntsa_ethernetheader.cpp b/groups/nts/ntsa/ntsa_ethernetheader.cpp new file mode 100644 index 000000000..d7d3ea934 --- /dev/null +++ b/groups/nts/ntsa/ntsa_ethernetheader.cpp @@ -0,0 +1,72 @@ +// Copyright 2020-2023 Bloomberg Finance L.P. +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +BSLS_IDENT_RCSID(ntsa_ethernetheader_cpp, "$Id$ $CSID$") + +#include +#include +#include +#include + +namespace BloombergLP { +namespace ntsa { + +bool EthernetHeader::equals(const EthernetHeader& other) const +{ + return d_source == other.d_source && + d_destination == other.d_destination && + d_protocol == other.d_protocol; +} + +bool EthernetHeader::less(const EthernetHeader& other) const +{ + if (d_source < other.d_source) { + return true; + } + + if (other.d_source < d_source) { + return false; + } + + if (d_destination < other.d_destination) { + return true; + } + + if (other.d_destination < d_destination) { + return false; + } + + return d_protocol < other.d_protocol; +} + +bsl::ostream& EthernetHeader::print(bsl::ostream& stream, + int level, + int spacesPerLevel) const +{ + bslim::Printer printer(&stream, level, spacesPerLevel); + printer.start(); + printer.printAttribute("source", d_source); + printer.printAttribute("destination", d_destination); + printer.printAttribute("protocol", d_protocol); + printer.end(); + + return stream; +} + +} // close package namespace +} // close enterprise namespace diff --git a/groups/nts/ntsa/ntsa_ethernetheader.h b/groups/nts/ntsa/ntsa_ethernetheader.h new file mode 100644 index 000000000..1017200b3 --- /dev/null +++ b/groups/nts/ntsa/ntsa_ethernetheader.h @@ -0,0 +1,311 @@ +// Copyright 2020-2023 Bloomberg Finance L.P. +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef INCLUDED_NTSA_ETHERNETHEADER +#define INCLUDED_NTSA_ETHERNETHEADER + +#include +BSLS_IDENT("$Id: $") + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace BloombergLP { +namespace ntsa { + +/// Provide an Ethernet header. +/// +/// @details +/// This class is value-semantic type that represents an Ethernet header. +/// +/// @par Thread Safety +/// This class is not thread safe. +/// +/// @ingroup module_ntsa_identity +class EthernetHeader +{ + ntsa::EthernetAddress d_source; + ntsa::EthernetAddress d_destination; + ntsa::EthernetProtocol::Value d_protocol; + + public: + /// Create a new IPv4 address having a default value. + EthernetHeader(); + + /// Create a new IPv4 address having the same value as the specified + /// 'original' object. Assign an unspecified but valid value to the + /// 'original' original. + EthernetHeader(bslmf::MovableRef original) NTSCFG_NOEXCEPT; + + /// Create a new IPv4 address having the same value as the specified + /// 'original' object. + EthernetHeader(const EthernetHeader& original); + + /// Destroy this object. + ~EthernetHeader(); + + /// Assign the value of the specified 'other' object to this object. Assign + /// an unspecified but valid value to the 'original' original. Return a + /// reference to this modifiable object. + EthernetHeader& operator=(bslmf::MovableRef other) + NTSCFG_NOEXCEPT; + + /// Assign the value of the specified 'other' object to this object. + /// Return a reference to this modifiable object. + EthernetHeader& operator=(const EthernetHeader& other); + + /// Reset the value of this object to its value upon default + /// construction. + void reset(); + + /// Set the source address to the specified 'value'. + void setSource(const ntsa::EthernetAddress& value); + + /// Set the destination address to the specified 'value'. + void setDestination(const ntsa::EthernetAddress& value); + + /// Set the protocol to the specified 'value'. + void setProtocol(ntsa::EthernetProtocol::Value value); + + /// Return the source address. + const ntsa::EthernetAddress& source() const; + + /// Return the destination address. + const ntsa::EthernetAddress& destination() const; + + /// Return the protocol. + ntsa::EthernetProtocol::Value protocol() const; + + /// Return true if this object has the same value as the specified + /// 'other' object, otherwise return false. + bool equals(const EthernetHeader& other) const; + + /// Return true if the value of this object is less than the value of + /// the specified 'other' object, otherwise return false. + bool less(const EthernetHeader& other) const; + + /// Contribute the values of the salient attributes of this object to the + /// specified hash 'algorithm'. + template + void hash(HASH_ALGORITHM& algorithm) const; + + /// Format this object to the specified output 'stream' at the + /// optionally specified indentation 'level' and return a reference to + /// the modifiable 'stream'. If 'level' is specified, optionally + /// specify 'spacesPerLevel', the number of spaces per indentation level + /// for this and all of its nested objects. Each line is indented by + /// the absolute value of 'level * spacesPerLevel'. If 'level' is + /// negative, suppress indentation of the first line. If + /// 'spacesPerLevel' is negative, suppress line breaks and format the + /// entire output on one line. If 'stream' is initially invalid, this + /// operation has no effect. Note that a trailing newline is provided + /// in multiline mode only. + bsl::ostream& print(bsl::ostream& stream, + int level = 0, + int spacesPerLevel = 4) const; + + /// This type's default constructor is equivalent to setting each byte of + /// the object's footprint to zero. + NTSCFG_TYPE_TRAIT_BITWISE_INITIALIZABLE(EthernetHeader); + + /// This type's copy-constructor and copy-assignment operator is equivalent + /// to copying each byte of the source object's footprint to each + /// corresponding byte of the destination object's footprint. + NTSCFG_TYPE_TRAIT_BITWISE_COPYABLE(EthernetHeader); + + /// This type's move-constructor and move-assignment operator is equivalent + /// to copying each byte of the source object's footprint to each + /// corresponding byte of the destination object's footprint. + NTSCFG_TYPE_TRAIT_BITWISE_MOVABLE(EthernetHeader); +}; + +/// Write a formatted, human-readable description of the specified 'object' +/// into the specified 'stream'. Return a reference to the modifiable +/// 'stream'. +/// +/// @related ntsa::EthernetHeader +bsl::ostream& operator<<(bsl::ostream& stream, const EthernetHeader& object); + +/// Return true if the specified 'lhs' has the same value as the specified +/// 'rhs', otherwise return false. +/// +/// @related ntsa::EthernetHeader +bool operator==(const EthernetHeader& lhs, const EthernetHeader& rhs); + +/// Return true if the specified 'lhs' does not have the same value as the +/// specified 'rhs', otherwise return false. +/// +/// @related ntsa::EthernetHeader +bool operator!=(const EthernetHeader& lhs, const EthernetHeader& rhs); + +/// Return true if the specified 'lhs' is "less than" the specified 'rhs', +/// otherwise return false. +/// +/// @related ntsa::EthernetHeader +bool operator<(const EthernetHeader& lhs, const EthernetHeader& rhs); + +/// Contribute the values of the salient attributes of the specified 'value' +/// to the specified hash 'algorithm'. +/// +/// @related ntsa::EthernetHeader +template +void hashAppend(HASH_ALGORITHM& algorithm, const EthernetHeader& value); + +NTSCFG_INLINE +EthernetHeader::EthernetHeader() +: d_source() +, d_destination() +, d_protocol(ntsa::EthernetProtocol::e_UNDEFINED) +{ +} + +NTSCFG_INLINE +EthernetHeader::EthernetHeader( + bslmf::MovableRef original) NTSCFG_NOEXCEPT +: d_source(NTSCFG_MOVE_FROM(original, d_source)) +, d_destination(NTSCFG_MOVE_FROM(original, d_destination)) +, d_protocol(NTSCFG_MOVE_FROM(original, d_protocol)) +{ + NTSCFG_MOVE_RESET(original); +} + +NTSCFG_INLINE +EthernetHeader::EthernetHeader(const EthernetHeader& original) +: d_source(original.d_source) +, d_destination(original.d_destination) +, d_protocol(original.d_protocol) +{ +} + +NTSCFG_INLINE +EthernetHeader::~EthernetHeader() +{ +} + +NTSCFG_INLINE +EthernetHeader& EthernetHeader::operator=( + bslmf::MovableRef other) NTSCFG_NOEXCEPT +{ + d_source = NTSCFG_MOVE_FROM(other, d_source); + d_destination = NTSCFG_MOVE_FROM(other, d_destination); + d_protocol = NTSCFG_MOVE_FROM(other, d_protocol); + + NTSCFG_MOVE_RESET(other); + + return *this; +} + +NTSCFG_INLINE +EthernetHeader& EthernetHeader::operator=(const EthernetHeader& other) +{ + d_source = other.d_source; + d_destination = other.d_destination; + d_protocol = other.d_protocol; + return *this; +} + +NTSCFG_INLINE +void EthernetHeader::reset() +{ + d_source.reset(); + d_destination.reset(); + d_protocol = ntsa::EthernetProtocol::e_UNDEFINED; +} + +NTSCFG_INLINE +void EthernetHeader::setSource(const ntsa::EthernetAddress& value) +{ + d_source = value; +} + +NTSCFG_INLINE +void EthernetHeader::setDestination(const ntsa::EthernetAddress& value) +{ + d_destination = value; +} + +NTSCFG_INLINE +void EthernetHeader::setProtocol(ntsa::EthernetProtocol::Value value) +{ + d_protocol = value; +} + +NTSCFG_INLINE +const ntsa::EthernetAddress& EthernetHeader::source() const +{ + return d_source; +} + +NTSCFG_INLINE +const ntsa::EthernetAddress& EthernetHeader::destination() const +{ + return d_destination; +} + +NTSCFG_INLINE +ntsa::EthernetProtocol::Value EthernetHeader::protocol() const +{ + return d_protocol; +} + +template +NTSCFG_INLINE void EthernetHeader::hash(HASH_ALGORITHM& algorithm) const +{ + using bslh::hashAppend; + hashAppend(algorithm, d_source); + hashAppend(algorithm, d_destination); + hashAppend(algorithm, d_protocol); +} + +NTSCFG_INLINE +bsl::ostream& operator<<(bsl::ostream& stream, const EthernetHeader& object) +{ + return object.print(stream, 0, -1); +} + +NTSCFG_INLINE +bool operator==(const EthernetHeader& lhs, const EthernetHeader& rhs) +{ + return lhs.equals(rhs); +} + +NTSCFG_INLINE +bool operator!=(const EthernetHeader& lhs, const EthernetHeader& rhs) +{ + return !operator==(lhs, rhs); +} + +NTSCFG_INLINE +bool operator<(const EthernetHeader& lhs, const EthernetHeader& rhs) +{ + return lhs.less(rhs); +} + +template +NTSCFG_INLINE void hashAppend(HASH_ALGORITHM& algorithm, + const EthernetHeader& value) +{ + value.hash(algorithm); +} + +} // close package namespace +} // close enterprise namespace +#endif diff --git a/groups/nts/ntsa/ntsa_ethernetheader.t.cpp b/groups/nts/ntsa/ntsa_ethernetheader.t.cpp new file mode 100644 index 000000000..e2c3f3a69 --- /dev/null +++ b/groups/nts/ntsa/ntsa_ethernetheader.t.cpp @@ -0,0 +1,76 @@ +// Copyright 2020-2023 Bloomberg Finance L.P. +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +BSLS_IDENT_RCSID(ntsa_ethernetheader_t_cpp, "$Id$ $CSID$") + +#include + +using namespace BloombergLP; + +namespace BloombergLP { +namespace ntsa { + +// Provide tests for 'ntsa::EthernetHeader'. +class EthernetHeaderTest +{ + public: + // Test value semantics: type traits. + static void verifyTypeTraits(); + + // Test usage example. + static void verifyUsage(); +}; + +void EthernetHeaderTest::verifyTypeTraits() +{ + const bool isBitwiseInitializable = + NTSCFG_TYPE_CHECK_BITWISE_INITIALIZABLE(ntsa::EthernetHeader); + + NTSCFG_TEST_TRUE(isBitwiseInitializable); + + const bool isBitwiseMovable = + NTSCFG_TYPE_CHECK_BITWISE_MOVABLE(ntsa::EthernetHeader); + + NTSCFG_TEST_TRUE(isBitwiseMovable); + + const bool isBitwiseCopyable = + NTSCFG_TYPE_CHECK_BITWISE_COPYABLE(ntsa::EthernetHeader); + + NTSCFG_TEST_TRUE(isBitwiseCopyable); +} + +void EthernetHeaderTest::verifyUsage() +{ + ntsa::EthernetHeader header; + + header.setSource(ntsa::EthernetAddress("36:2c:a1:55:0c:c0")); + header.setDestination(ntsa::EthernetAddress("3e:07:f4:b5:bf:48")); + header.setProtocol(ntsa::EthernetProtocol::e_IPV4); + + NTSCFG_TEST_LOG_DEBUG << "Ethernet = " << header << NTSCFG_TEST_LOG_END; +} + +} // close namespace ntsa +} // close namespace BloombergLP + +NTSCFG_TEST_SUITE +{ + NTSCFG_TEST_FUNCTION(&ntsa::EthernetHeaderTest::verifyTypeTraits); + NTSCFG_TEST_FUNCTION(&ntsa::EthernetHeaderTest::verifyUsage); +} +NTSCFG_TEST_SUITE_END; diff --git a/groups/nts/ntsa/ntsa_ethernetprotocol.cpp b/groups/nts/ntsa/ntsa_ethernetprotocol.cpp new file mode 100644 index 000000000..d9726d591 --- /dev/null +++ b/groups/nts/ntsa/ntsa_ethernetprotocol.cpp @@ -0,0 +1,104 @@ +// Copyright 2020-2023 Bloomberg Finance L.P. +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include +BSLS_IDENT_RCSID(ntsa_ethernetprotocol_cpp, "$Id$ $CSID$") + +#include + +namespace BloombergLP { +namespace ntsa { + +int EthernetProtocol::fromInt(EthernetProtocol::Value* result, int number) +{ + switch (number) { + case EthernetProtocol::e_UNDEFINED: + case EthernetProtocol::e_IPV4: + case EthernetProtocol::e_ARP: + case EthernetProtocol::e_RARP: + case EthernetProtocol::e_IPV6: + *result = static_cast(number); + return 0; + default: + return -1; + } +} + +int EthernetProtocol::fromString(EthernetProtocol::Value* result, + const bslstl::StringRef& string) +{ + if (bdlb::String::areEqualCaseless(string, "UNDEFINED")) { + *result = e_UNDEFINED; + return 0; + } + if (bdlb::String::areEqualCaseless(string, "IPV4")) { + *result = e_IPV4; + return 0; + } + if (bdlb::String::areEqualCaseless(string, "ARP")) { + *result = e_ARP; + return 0; + } + if (bdlb::String::areEqualCaseless(string, "RARP")) { + *result = e_RARP; + return 0; + } + if (bdlb::String::areEqualCaseless(string, "IPV6")) { + *result = e_IPV6; + return 0; + } + + return -1; +} + +const char* EthernetProtocol::toString(EthernetProtocol::Value value) +{ + switch (value) { + case e_UNDEFINED: { + return "UNDEFINED"; + } break; + case e_IPV4: { + return "IPV4"; + } break; + case e_ARP: { + return "ARP"; + } break; + case e_RARP: { + return "RARP"; + } break; + case e_IPV6: { + return "IPV6"; + } break; + } + + BSLS_ASSERT(!"invalid enumerator"); + return 0; +} + +bsl::ostream& EthernetProtocol::print(bsl::ostream& stream, + EthernetProtocol::Value value) +{ + return stream << toString(value); +} + +bsl::ostream& operator<<(bsl::ostream& stream, EthernetProtocol::Value rhs) +{ + return EthernetProtocol::print(stream, rhs); +} + +} // close package namespace +} // close enterprise namespace diff --git a/groups/nts/ntsa/ntsa_ethernetprotocol.h b/groups/nts/ntsa/ntsa_ethernetprotocol.h new file mode 100644 index 000000000..37e89af84 --- /dev/null +++ b/groups/nts/ntsa/ntsa_ethernetprotocol.h @@ -0,0 +1,88 @@ +// Copyright 2020-2023 Bloomberg Finance L.P. +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef INCLUDED_NTSA_ETHERNETPROTOCOL +#define INCLUDED_NTSA_ETHERNETPROTOCOL + +#include +BSLS_IDENT("$Id: $") + +#include +#include + +namespace BloombergLP { +namespace ntsa { + +/// Provide an enumeration of the protocols carried by an ethernet frame. +/// +/// @par Thread Safety +/// This struct is thread safe. +/// +/// @ingroup module_ntsa_identity +struct EthernetProtocol { + public: + /// Provide an enumeration of the protocols carried by an ethernet frame. + enum Value { + /// The protocol carried by the ethernet frame is undefined. + e_UNDEFINED = 0, + + /// The protocol carried by the ethernet frame is the Internet + /// Protocol, version 4 (IPv4). + e_IPV4 = 0x0800, + + /// The protocol carried by the ethernet frame is the Address + /// Resolution Protocol (ARP). + e_ARP = 0x0806, + + /// The protocol carried by the ethernet frame is the Reverse Address + /// Resolution Protocol (RARP). + e_RARP = 0x8035, + + /// The protocol carried by the ethernet frame is the Internet + /// Protocol, version 6 (IPv6). + e_IPV6 = 0x86DD + }; + + /// Return the string representation exactly matching the enumerator + /// name corresponding to the specified enumeration 'value'. + static const char* toString(Value value); + + /// Load into the specified 'result' the enumerator matching the + /// specified 'string'. Return 0 on success, and a non-zero value with + /// no effect on 'result' otherwise (i.e., 'string' does not match any + /// enumerator). + static int fromString(Value* result, const bslstl::StringRef& string); + + /// Load into the specified 'result' the enumerator matching the + /// specified 'number'. Return 0 on success, and a non-zero value with + /// no effect on 'result' otherwise (i.e., 'number' does not match any + /// enumerator). + static int fromInt(Value* result, int number); + + /// Write to the specified 'stream' the string representation of the + /// specified enumeration 'value'. Return a reference to the modifiable + /// 'stream'. + static bsl::ostream& print(bsl::ostream& stream, Value value); +}; + +/// Format the specified 'rhs' to the specified output 'stream' and return a +/// reference to the modifiable 'stream'. +/// +/// @related ntsa::EthernetProtocol +bsl::ostream& operator<<(bsl::ostream& stream, EthernetProtocol::Value rhs); + +} // close package namespace +} // close enterprise namespace +#endif diff --git a/groups/nts/ntsa/ntsa_ethernetprotocol.t.cpp b/groups/nts/ntsa/ntsa_ethernetprotocol.t.cpp new file mode 100644 index 000000000..05d03e2a7 --- /dev/null +++ b/groups/nts/ntsa/ntsa_ethernetprotocol.t.cpp @@ -0,0 +1,55 @@ +// Copyright 2020-2023 Bloomberg Finance L.P. +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include + +#include +#include +#include + +using namespace BloombergLP; +using namespace ntsa; + +//============================================================================= +// TEST PLAN +//----------------------------------------------------------------------------- +// Overview +// -------- +// +//----------------------------------------------------------------------------- + +// [ 1] +//----------------------------------------------------------------------------- +// [ 1] +//----------------------------------------------------------------------------- + +NTSCFG_TEST_CASE(1) +{ + // Concern: + // Plan: + + ntscfg::TestAllocator ta; + { + } + NTSCFG_TEST_ASSERT(ta.numBlocksInUse() == 0); +} + +NTSCFG_TEST_DRIVER +{ + NTSCFG_TEST_REGISTER(1); +} +NTSCFG_TEST_DRIVER_END; diff --git a/groups/nts/ntsa/package/ntsa.mem b/groups/nts/ntsa/package/ntsa.mem index 3c2835ee8..7dbe4b7b7 100644 --- a/groups/nts/ntsa/package/ntsa.mem +++ b/groups/nts/ntsa/package/ntsa.mem @@ -9,6 +9,9 @@ ntsa_endpoint ntsa_endpointoptions ntsa_endpointtype ntsa_error +ntsa_ethernetaddress +ntsa_ethernetheader +ntsa_ethernetprotocol ntsa_event ntsa_file ntsa_guid diff --git a/targets.cmake b/targets.cmake index 3c410634e..e5a7a9a6a 100644 --- a/targets.cmake +++ b/targets.cmake @@ -114,6 +114,9 @@ if (${NTF_BUILD_WITH_NTS}) ntf_component(NAME ntsa_endpointoptions) ntf_component(NAME ntsa_endpointtype) ntf_component(NAME ntsa_error) + ntf_component(NAME ntsa_ethernetaddress) + ntf_component(NAME ntsa_ethernetheader) + ntf_component(NAME ntsa_ethernetprotocol) ntf_component(NAME ntsa_event) ntf_component(NAME ntsa_file) ntf_component(NAME ntsa_guid)