aboutsummaryrefslogtreecommitdiff
path: root/rfc4251.H
diff options
context:
space:
mode:
Diffstat (limited to 'rfc4251.H')
-rw-r--r--rfc4251.H160
1 files changed, 48 insertions, 112 deletions
diff --git a/rfc4251.H b/rfc4251.H
index 7d4c0d3..fe8ccd4 100644
--- a/rfc4251.H
+++ b/rfc4251.H
@@ -10,7 +10,7 @@
* those structs contain the objects in their RFC 4251 representation,
* conversions are provided via constructors and cast operators
*
- * Copyright (C) 2013-2015 Timo Weingärtner <timo@tiwe.de>
+ * Copyright (C) 2013-2015,2021 Timo Weingärtner <timo@tiwe.de>
*
* This file is part of ssh-agent-filter.
*
@@ -28,132 +28,69 @@
* along with ssh-agent-filter. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <type_traits>
+#include <cstdint>
+#include <array>
#include <vector>
#include <string>
#include <iostream>
#include <limits>
#include <stdexcept>
-#include <arpa/inet.h> // ntohl() / htonl()
#include <gmpxx.h>
#include <boost/operators.hpp>
namespace rfc4251 {
-struct byte {
- union {
- uint8_t value;
- char buf[1];
- };
-
- byte () = default;
- explicit byte (uint8_t v) : value(v) {}
- inline explicit byte (std::istream &);
-
- operator uint8_t () const { return value; }
-};
-
-inline std::istream & operator>> (std::istream & is, byte & x) {
- return is.read(x.buf, sizeof(x.buf));
-}
-
-inline std::ostream & operator<< (std::ostream & os, byte const & x) {
- return os.write(x.buf, sizeof(x.buf));
-}
-
-inline byte::byte (std::istream & is) {
- is >> *this;
-}
-
-struct boolean {
- union {
- bool value;
- char buf[1];
- };
-
- boolean () = default;
- explicit boolean (uint8_t v) : value(v) {}
- inline explicit boolean (std::istream &);
-
- operator uint8_t () const { return value; }
-};
-
-inline std::istream & operator>> (std::istream & is, boolean & x) {
- return is.read(x.buf, sizeof(x.buf));
-}
-
-inline std::ostream & operator<< (std::ostream & os, boolean const & x) {
- return os.write(x.buf, sizeof(x.buf));
-}
-
-inline boolean::boolean (std::istream & is) {
- is >> *this;
-}
+namespace internal {
+ template<typename T>
+ constexpr inline auto host_to_network (T value) noexcept {
+ static_assert(std::is_unsigned_v<T>, "shift is only supported on unsigned");
+
+ std::array<char, sizeof(T)> ret;
+ for (auto it{rbegin(ret)}; it != rend(ret); ++it) {
+ *it = value & 0xff;
+ if constexpr (sizeof(T) > 1) value >>= 8;
+ }
+ return ret;
+ }
-struct uint32 {
- union {
- uint32_t value;
- char buf[4];
- };
+ template<typename T>
+ constexpr inline auto network_to_host (std::array<char, sizeof(T)> const buf) noexcept {
+ static_assert(std::is_unsigned_v<T>, "shift is only supported on unsigned");
- uint32 () = default;
- explicit uint32 (uint32_t v) { value = htonl(v); }
- inline explicit uint32 (std::istream &);
+ T ret{0};
+ for (auto it{cbegin(buf)}; it != cend(buf); ++it) {
+ if constexpr (sizeof(T) > 1) ret <<= 8;
+ ret |= static_cast<uint8_t>(*it);
+ }
+ return ret;
+ }
- operator uint32_t () const { return ntohl(value); }
-};
+ template<typename T>
+ struct fixed_length {
+ static_assert(std::is_unsigned_v<T>, "support for signed types might need more work");
-inline std::istream & operator>> (std::istream & is, uint32 & x) {
- return is.read(x.buf, sizeof(x.buf));
-}
+ std::array<char, sizeof(T)> buf{};
-inline std::ostream & operator<< (std::ostream & os, uint32 const & x) {
- return os.write(x.buf, sizeof(x.buf));
-}
+ constexpr fixed_length () noexcept = default;
+ constexpr explicit fixed_length (T const v) noexcept : buf{host_to_network(v)} {}
+ explicit fixed_length (std::istream & is) { is >> *this; }
-inline uint32::uint32 (std::istream & is) {
- is >> *this;
-}
+ constexpr operator T () const noexcept { return network_to_host<T>(buf); }
-struct uint64 {
- union {
- uint64_t value;
- char buf[8];
+ friend std::istream & operator>> (std::istream & is, fixed_length & x) {
+ return is.read(x.buf.data(), x.buf.size());
+ }
+ friend std::ostream & operator<< (std::ostream & os, fixed_length const & x) {
+ return os.write(x.buf.data(), x.buf.size());
+ }
};
-
- uint64 () = default;
- inline explicit uint64 (uint64_t v);
- inline explicit uint64 (std::istream &);
-
- inline explicit operator uint64_t () const;
-};
-
-inline uint64::uint64 (uint64_t v) {
- for (int_fast8_t i{7}; i >= 0; --i) {
- buf[i] = v & 0xff;
- v >>= 8;
- }
-}
-
-inline uint64::operator uint64_t () const {
- uint64_t ret{0};
- for (uint_fast8_t i{0}; i < 8; ++i) {
- ret <<= 8;
- ret |= static_cast<uint8_t>(buf[i]);
- }
- return ret;
}
-inline std::istream & operator>> (std::istream & is, uint64 & x) {
- return is.read(x.buf, sizeof(x.buf));
-}
-
-inline std::ostream & operator<< (std::ostream & os, uint64 const & x) {
- return os.write(x.buf, sizeof(x.buf));
-}
-
-inline uint64::uint64 (std::istream & is) {
- is >> *this;
-}
+using byte = internal::fixed_length<uint8_t>;
+using boolean = internal::fixed_length<bool>;
+using uint32 = internal::fixed_length<uint32_t>;
+using uint64 = internal::fixed_length<uint64_t>;
struct string : boost::totally_ordered<string> {
std::vector<char> value;
@@ -166,9 +103,9 @@ struct string : boost::totally_ordered<string> {
explicit string (mpz_class const & x) : string{x.get_mpz_t()} {}
inline explicit string (std::istream &);
- size_t size () const { return value.size(); }
- char const * data () const { return value.data(); }
- char * data () { return value.data(); }
+ size_t size () const noexcept { return value.size(); }
+ char const * data () const noexcept { return value.data(); }
+ char * data () noexcept { return value.data(); }
operator std::string () const { return {value.begin(), value.end()}; }
operator std::vector<std::string> () const;
@@ -183,8 +120,7 @@ inline string::string (char const * s, size_t l) {
inline std::istream & operator>> (std::istream & is, string & s) {
s.value.clear();
- uint32 len;
- if (is >> len) {
+ if (uint32_t const len{uint32{is}}; is) {
s.value.resize(len);
is.read(s.value.data(), len);
}