Electroneum
Toggle main menu visibility
Loading...
Searching...
No Matches
zmq.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 "
net/zmq.h
"
30
31
#include <cassert>
32
#include <cerrno>
33
#include <limits>
34
#include <utility>
35
36
namespace
net
37
{
38
namespace
zmq
39
{
40
const
std::error_category&
error_category
() noexcept
41
{
42
struct
category final : std::error_category
43
{
44
virtual
const
char
* name()
const
noexcept
override
final
45
{
46
return
"error::error_category()"
;
47
}
48
49
virtual
std::string
message
(
int
value
)
const
override
final
50
{
51
char
const
*
const
msg = zmq_strerror(
value
);
52
if
(msg)
53
return
msg;
54
return
"zmq_strerror failure"
;
55
}
56
57
virtual
std::error_condition default_error_condition(
int
value
)
const
noexcept
override
final
58
{
59
// maps specific errors to generic `std::errc` cases.
60
switch
(
value
)
61
{
62
case
EFSM:
63
case
ETERM:
64
break
;
65
default
:
66
/* zmq is using cerrno errors. C++ spec indicates that
67
`std::errc` values must be identical to the cerrno value.
68
So just map every zmq specific error to the generic errc
69
equivalent. zmq extensions must be in the switch or they
70
map to a non-existent errc enum value. */
71
return
std::errc(
value
);
72
}
73
return
std::error_condition{
value
, *
this
};
74
}
75
76
};
77
static
const
category instance{};
78
return
instance;
79
}
80
81
void
terminate::call(
void
* ptr)
noexcept
82
{
83
assert(ptr !=
nullptr
);
// see header
84
while
(zmq_term(ptr))
85
{
86
if
(zmq_errno() != EINTR)
87
break
;
88
}
89
}
90
91
namespace
92
{
94
class
message
95
{
96
zmq_msg_t handle_;
97
98
public
:
99
message
() noexcept
100
: handle_()
101
{
102
zmq_msg_init(handle());
103
}
104
105
message
(
message
&& rhs) =
delete
;
106
message
(
const
message
& rhs) =
delete
;
107
message
&
operator=
(
message
&& rhs) =
delete
;
108
message
&
operator=
(
const
message
& rhs) =
delete
;
109
110
~message() noexcept
111
{
112
zmq_msg_close(handle());
113
}
114
115
zmq_msg_t* handle() noexcept
116
{
117
return
std::addressof(handle_);
118
}
119
120
const
char
* data() noexcept
121
{
122
return
static_cast<
const
char
*
>
(zmq_msg_data(handle()));
123
}
124
125
std::size_t size() noexcept
126
{
127
return
zmq_msg_size(handle());
128
}
129
};
130
131
struct
do_receive
132
{
133
/* ZMQ documentation states that message parts are atomic - either
134
all are received or none are. Looking through ZMQ code and
135
Github discussions indicates that after part 1 is returned,
136
`EAGAIN` cannot be returned to meet these guarantees. Unit tests
137
verify (for the `inproc://` case) that this is the behavior.
138
Therefore, read errors after the first part are treated as a
139
failure for the entire message (probably `ETERM`). */
140
int
operator()(std::string& payload,
void
*
const
socket
,
const
int
flags)
const
141
{
142
static
constexpr
const
int
max_out = std::numeric_limits<int>::max();
143
const
std::string::size_type initial = payload.size();
144
message
part{};
145
for
(;;)
146
{
147
int
last = 0;
148
if
((last = zmq_msg_recv(part.handle(),
socket
, flags)) < 0)
149
return
last;
150
151
payload.append(part.data(), part.size());
152
if
(!zmq_msg_more(part.handle()))
153
break
;
154
}
155
const
std::string::size_type added = payload.size() - initial;
156
return
unsigned(max_out) < added ? max_out : int(added);
157
}
158
};
159
160
template
<
typename
F
,
typename
...
T
>
161
expect<void> retry_op(
F
op,
T
&&... args)
noexcept
(
noexcept
(op(args...)))
162
{
163
for
(;;)
164
{
165
if
(0 <= op(args...))
166
return
success();
167
168
const
int
error
= zmq_errno();
169
if
(
error
!= EINTR)
170
return
make_error_code
(
error
);
171
}
172
}
173
}
// anonymous
174
175
expect<std::string>
receive
(
void
*
const
socket
,
const
int
flags)
176
{
177
std::string payload{};
178
ELECTRONEUM_CHECK
(retry_op(do_receive{}, payload,
socket
, flags));
179
return
{std::move(payload)};
180
}
181
182
expect<void>
send
(
const
epee::span<const std::uint8_t>
payload,
void
*
const
socket
,
const
int
flags)
noexcept
183
{
184
return
retry_op(zmq_send,
socket
, payload.data(), payload.size(), flags);
185
}
186
}
// zmq
187
}
// net
operator=
connection< TProtocol > & operator=(const connection< TProtocol > &obj)
Definition
abstract_tcp_server_cp.h:196
epee::span
Non-owning sequence of data. Does not deep copy.
Definition
span.h:57
expect
Definition
expect.h:133
F
#define F(s)
message
std::string message("Message requiring signing")
ELECTRONEUM_CHECK
#define ELECTRONEUM_CHECK(...)
Check expect<void> and return errors in current scope.
Definition
expect.h:47
net::zmq
Definition
zmq.cpp:39
net::zmq::error_category
const std::error_category & error_category() noexcept
Definition
zmq.cpp:40
net::zmq::send
expect< void > send(const epee::span< const std::uint8_t > payload, void *const socket, const int flags) noexcept
Definition
zmq.cpp:182
net::zmq::make_error_code
std::error_code make_error_code(int code) noexcept
Definition
zmq.h:64
net::zmq::receive
expect< std::string > receive(void *const socket, const int flags)
Definition
zmq.cpp:175
net::zmq::socket
std::unique_ptr< void, close > socket
Unique ZMQ socket handle, calls zmq_close on destruction.
Definition
zmq.h:101
net
Definition
net_utils_base.h:54
net::error
error
General net errors.
Definition
error.h:38
value
const GenericPointer< typename T::ValueType > T2 value
Definition
pointer.h:1225
T
#define T(x)
zmq.h
src
net
zmq.cpp
Generated on
for Electroneum by
1.17.0