Electroneum
Loading...
Searching...
No Matches
i2p_address.cpp
Go to the documentation of this file.
1// Copyright (c) 2019, The Monero Project
2//
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without modification, are
6// permitted provided that the following conditions are met:
7//
8// 1. Redistributions of source code must retain the above copyright notice, this list of
9// conditions and the following disclaimer.
10//
11// 2. Redistributions in binary form must reproduce the above copyright notice, this list
12// of conditions and the following disclaimer in the documentation and/or other
13// materials provided with the distribution.
14//
15// 3. Neither the name of the copyright holder nor the names of its contributors may be
16// used to endorse or promote products derived from this software without specific
17// prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29#include "i2p_address.h"
30
31#include <algorithm>
32#include <boost/spirit/include/karma_generate.hpp>
33#include <boost/spirit/include/karma_uint.hpp>
34#include <cassert>
35#include <cstring>
36#include <limits>
37
38#include "net/error.h"
41#include "string_tools.h"
42
43namespace net
44{
45 namespace
46 {
47 // !TODO only b32 addresses right now
48 constexpr const char tld[] = u8".b32.i2p";
49 constexpr const char unknown_host[] = "<unknown i2p host>";
50
51 constexpr const unsigned b32_length = 52;
52
53 constexpr const char base32_alphabet[] =
54 u8"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz234567";
55
56 expect<void> host_check(boost::string_ref host) noexcept
57 {
58 if (!host.ends_with(tld))
60
61 host.remove_suffix(sizeof(tld) - 1);
62
63 if (host.size() != b32_length)
65 if (host.find_first_not_of(base32_alphabet) != boost::string_ref::npos)
67
68 return success();
69 }
70
71 struct i2p_serialized
72 {
73 std::string host;
74 std::uint16_t port;
75
77 KV_SERIALIZE(host)
78 KV_SERIALIZE(port)
80 };
81 }
82
83 i2p_address::i2p_address(const boost::string_ref host, const std::uint16_t port) noexcept
84 : port_(port)
85 {
86 // this is a private constructor, throw if moved to public
87 assert(host.size() < sizeof(host_));
88
89 const std::size_t length = std::min(sizeof(host_) - 1, host.size());
90 std::memcpy(host_, host.data(), length);
91 std::memset(host_ + length, 0, sizeof(host_) - length);
92 }
93
94 const char* i2p_address::unknown_str() noexcept
95 {
96 return unknown_host;
97 }
98
100 : port_(0)
101 {
102 static_assert(sizeof(unknown_host) <= sizeof(host_), "bad buffer size");
103 std::memcpy(host_, unknown_host, sizeof(unknown_host));
104 std::memset(host_ + sizeof(unknown_host), 0, sizeof(host_) - sizeof(unknown_host));
105 }
106
107 expect<i2p_address> i2p_address::make(const boost::string_ref address, const std::uint16_t default_port)
108 {
109 boost::string_ref host = address.substr(0, address.rfind(':'));
110 const boost::string_ref port =
111 address.substr(host.size() + (host.size() == address.size() ? 0 : 1));
112
113 ELECTRONEUM_CHECK(host_check(host));
114
115 std::uint16_t porti = default_port;
116 if (!port.empty() && !epee::string_tools::get_xtype_from_string(porti, std::string{port}))
118
119 static_assert(b32_length + sizeof(tld) == sizeof(i2p_address::host_), "bad internal host size");
120 return i2p_address{host, porti};
121 }
122
124 {
125 i2p_serialized in{};
126 if (in._load(src, hparent) && in.host.size() < sizeof(host_) && (in.host == unknown_host || !host_check(in.host).has_error()))
127 {
128 std::memcpy(host_, in.host.data(), in.host.size());
129 std::memset(host_ + in.host.size(), 0, sizeof(host_) - in.host.size());
130 port_ = in.port;
131 return true;
132 }
133 static_assert(sizeof(unknown_host) <= sizeof(host_), "bad buffer size");
134 std::memcpy(host_, unknown_host, sizeof(unknown_host)); // include null terminator
135 port_ = 0;
136 return false;
137 }
138
140 {
141 const i2p_serialized out{std::string{host_}, port_};
142 return out.store(dest, hparent);
143 }
144
145 i2p_address::i2p_address(const i2p_address& rhs) noexcept
146 : port_(rhs.port_)
147 {
148 std::memcpy(host_, rhs.host_, sizeof(host_));
149 }
150
151 i2p_address& i2p_address::operator=(const i2p_address& rhs) noexcept
152 {
153 if (this != std::addressof(rhs))
154 {
155 port_ = rhs.port_;
156 std::memcpy(host_, rhs.host_, sizeof(host_));
157 }
158 return *this;
159 }
160
161 bool i2p_address::is_unknown() const noexcept
162 {
163 static_assert(1 <= sizeof(host_), "host size too small");
164 return host_[0] == '<'; // character is not allowed otherwise
165 }
166
167 bool i2p_address::equal(const i2p_address& rhs) const noexcept
168 {
169 return port_ == rhs.port_ && is_same_host(rhs);
170 }
171
172 bool i2p_address::less(const i2p_address& rhs) const noexcept
173 {
174 return std::strcmp(host_str(), rhs.host_str()) < 0 || port() < rhs.port();
175 }
176
177 bool i2p_address::is_same_host(const i2p_address& rhs) const noexcept
178 {
179 return std::strcmp(host_str(), rhs.host_str()) == 0;
180 }
181
182 std::string i2p_address::str() const
183 {
184 const std::size_t host_length = std::strlen(host_str());
185 const std::size_t port_length =
186 port_ == 0 ? 0 : std::numeric_limits<std::uint16_t>::digits10 + 2;
187
188 std::string out{};
189 out.reserve(host_length + port_length);
190 out.assign(host_str(), host_length);
191
192 if (port_ != 0)
193 {
194 out.push_back(':');
195 namespace karma = boost::spirit::karma;
196 karma::generate(std::back_inserter(out), karma::ushort_, port());
197 }
198 return out;
199 }
200}
unsigned char u8
std::uint16_t port() const noexcept
i2p_address & operator=(const i2p_address &rhs) noexcept
bool store(epee::serialization::portable_storage &dest, epee::serialization::section *hparent) const
Store in epee p2p format.
bool equal(const i2p_address &rhs) const noexcept
bool is_same_host(const i2p_address &rhs) const noexcept
bool is_unknown() const noexcept
bool less(const i2p_address &rhs) const noexcept
static expect< i2p_address > make(boost::string_ref address, std::uint16_t default_port=0)
const char * host_str() const noexcept
std::string str() const
bool _load(epee::serialization::portable_storage &src, epee::serialization::section *hparent)
Load from epee p2p format, and.
i2p_address() noexcept
An object with port() == 0 and host_str() == unknown_str().
static const char * unknown_str() noexcept
#define ELECTRONEUM_CHECK(...)
Check expect<void> and return errors in current scope.
Definition expect.h:47
#define KV_SERIALIZE(varialble)
#define END_KV_SERIALIZE_MAP()
#define BEGIN_KV_SERIALIZE_MAP()
PUSH_WARNINGS bool get_xtype_from_string(OUT XType &val, const std::string &str_id)
@ invalid_port
Outside of 0-65535 range.
Definition error.h:43
@ expected_tld
Expected a tld.
Definition error.h:40
@ invalid_i2p_address
Definition error.h:42
CXA_THROW_INFO_T void(* dest)(void *))
unsigned short uint16_t
Definition stdint.h:125
const char * address
Definition multisig.cpp:37