Skip to content

Commit 957908d

Browse files
Add error details for proto/auth errors.
1 parent 8ea30fa commit 957908d

File tree

5 files changed

+332
-16
lines changed

5 files changed

+332
-16
lines changed

src/native.ts

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,35 @@ interface ErrnoError extends Error {
145145
errno: number
146146
}
147147

148+
interface AuthError extends Error {
149+
status: 300 | 400 | 500
150+
}
151+
152+
interface ProtoError extends Error {
153+
code: (
154+
"ERR_ZMTP_UNSPECIFIED" |
155+
"ERR_ZMTP_UNEXPECTED_COMMAND" |
156+
"ERR_ZMTP_INVALID_SEQUENCE" |
157+
"ERR_ZMTP_KEY_EXCHANGE" |
158+
"ERR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED" |
159+
"ERR_ZMTP_MALFORMED_COMMAND_MESSAGE" |
160+
"ERR_ZMTP_MALFORMED_COMMAND_HELLO" |
161+
"ERR_ZMTP_MALFORMED_COMMAND_INITIATE" |
162+
"ERR_ZMTP_MALFORMED_COMMAND_ERROR" |
163+
"ERR_ZMTP_MALFORMED_COMMAND_READY" |
164+
"ERR_ZMTP_MALFORMED_COMMAND_WELCOME" |
165+
"ERR_ZMTP_INVALID_METADATA" |
166+
"ERR_ZMTP_CRYPTOGRAPHIC" |
167+
"ERR_ZMTP_MECHANISM_MISMATCH" |
168+
"ERR_ZAP_UNSPECIFIED" |
169+
"ERR_ZAP_MALFORMED_REPLY" |
170+
"ERR_ZAP_BAD_REQUEST_ID" |
171+
"ERR_ZAP_BAD_VERSION" |
172+
"ERR_ZAP_INVALID_STATUS_CODE" |
173+
"ERR_ZAP_INVALID_METADATA"
174+
)
175+
}
176+
148177
interface EventAddress {
149178
address: string
150179
}
@@ -153,8 +182,8 @@ interface EventInterval {
153182
interval: number
154183
}
155184

156-
interface EventError {
157-
error: ErrnoError
185+
interface EventError<E = ErrnoError> {
186+
error: E
158187
}
159188

160189
type EventFor<T extends string, D = {}> = Expand<{type: T} & D>
@@ -264,8 +293,8 @@ export type Event = (
264293
EventFor<"disconnect", EventAddress> |
265294
EventFor<"end"> |
266295
EventFor<"handshake", EventAddress> |
267-
EventFor<"handshake:error:protocol", EventAddress> | /* TODO add error data */
268-
EventFor<"handshake:error:auth", EventAddress> | /* TODO add error data */
296+
EventFor<"handshake:error:protocol", EventAddress & EventError<ProtoError>> |
297+
EventFor<"handshake:error:auth", EventAddress & EventError<AuthError>> |
269298
EventFor<"handshake:error:other", EventAddress & EventError> |
270299
EventFor<"unknown">
271300
)

src/observer.cc

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,50 @@ static inline const char* EventName(uint32_t val) {
7979
return events[ffs];
8080
}
8181

82+
static inline const char* AuthError(uint32_t val) {
83+
switch (val) {
84+
case 300:
85+
return "Temporary error";
86+
case 400:
87+
return "Authentication failure";
88+
case 500:
89+
return "Internal error";
90+
default:
91+
return "Unknown error";
92+
}
93+
}
94+
95+
static inline std::pair<const char*, const char*> ProtoError(uint32_t val) {
96+
#define PROTO_ERROR_CASE(_prefix, _err) \
97+
case ZMQ_PROTOCOL_ERROR_##_prefix##_##_err: \
98+
return std::make_pair(#_prefix " protocol error", "ERR_" #_prefix "_" #_err);
99+
100+
switch (val) {
101+
PROTO_ERROR_CASE(ZMTP, UNSPECIFIED);
102+
PROTO_ERROR_CASE(ZMTP, UNEXPECTED_COMMAND);
103+
PROTO_ERROR_CASE(ZMTP, INVALID_SEQUENCE);
104+
PROTO_ERROR_CASE(ZMTP, KEY_EXCHANGE);
105+
PROTO_ERROR_CASE(ZMTP, MALFORMED_COMMAND_UNSPECIFIED);
106+
PROTO_ERROR_CASE(ZMTP, MALFORMED_COMMAND_MESSAGE);
107+
PROTO_ERROR_CASE(ZMTP, MALFORMED_COMMAND_HELLO);
108+
PROTO_ERROR_CASE(ZMTP, MALFORMED_COMMAND_INITIATE);
109+
PROTO_ERROR_CASE(ZMTP, MALFORMED_COMMAND_ERROR);
110+
PROTO_ERROR_CASE(ZMTP, MALFORMED_COMMAND_READY);
111+
PROTO_ERROR_CASE(ZMTP, MALFORMED_COMMAND_WELCOME);
112+
PROTO_ERROR_CASE(ZMTP, INVALID_METADATA);
113+
PROTO_ERROR_CASE(ZMTP, CRYPTOGRAPHIC);
114+
PROTO_ERROR_CASE(ZMTP, MECHANISM_MISMATCH);
115+
PROTO_ERROR_CASE(ZAP, UNSPECIFIED);
116+
PROTO_ERROR_CASE(ZAP, MALFORMED_REPLY);
117+
PROTO_ERROR_CASE(ZAP, BAD_REQUEST_ID);
118+
PROTO_ERROR_CASE(ZAP, BAD_VERSION);
119+
PROTO_ERROR_CASE(ZAP, INVALID_STATUS_CODE);
120+
PROTO_ERROR_CASE(ZAP, INVALID_METADATA);
121+
default:
122+
return std::make_pair("Unknown error", "ERR_UNKNOWN");
123+
}
124+
}
125+
82126
Observer::Observer(const Napi::CallbackInfo& info)
83127
: Napi::ObjectWrap<Observer>(info), async_context(Env(), "Observer"), poller(*this),
84128
module(*reinterpret_cast<Module*>(info.Data())) {
@@ -198,7 +242,7 @@ void Observer::Receive(const Napi::Promise::Deferred& res) {
198242

199243
auto data1 = static_cast<uint8_t*>(zmq_msg_data(&msg1));
200244
auto event_id = *reinterpret_cast<uint16_t*>(data1);
201-
auto event_value = *reinterpret_cast<uint32_t*>(data1 + 2);
245+
auto value = *reinterpret_cast<uint32_t*>(data1 + 2);
202246
zmq_msg_close(&msg1);
203247

204248
zmq_msg_init(&msg2);
@@ -223,23 +267,41 @@ void Observer::Receive(const Napi::Promise::Deferred& res) {
223267
zmq_msg_close(&msg2);
224268

225269
switch (event_id) {
226-
case ZMQ_EVENT_CONNECT_RETRIED:
227-
event["interval"] = Napi::Number::New(Env(), event_value);
270+
case ZMQ_EVENT_CONNECT_RETRIED: {
271+
event["interval"] = Napi::Number::New(Env(), value);
228272
break;
273+
}
274+
229275
case ZMQ_EVENT_BIND_FAILED:
230276
case ZMQ_EVENT_ACCEPT_FAILED:
231277
case ZMQ_EVENT_CLOSE_FAILED:
232278
#ifdef ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL
233-
case ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL:
279+
case ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL: {
280+
event["error"] = ErrnoException(Env(), value).Value();
281+
break;
282+
}
234283
#endif
235-
event["error"] = ErrnoException(Env(), event_value).Value();
284+
285+
#ifdef ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL
286+
case ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL: {
287+
auto desc = ProtoError(value);
288+
event["error"] = CodedException(Env(), desc.first, desc.second).Value();
289+
break;
290+
}
291+
#endif
292+
293+
#ifdef ZMQ_EVENT_HANDSHAKE_FAILED_AUTH
294+
case ZMQ_EVENT_HANDSHAKE_FAILED_AUTH: {
295+
event["error"] = StatusException(Env(), AuthError(value), value).Value();
236296
break;
237-
case ZMQ_EVENT_MONITOR_STOPPED:
297+
}
298+
#endif
299+
300+
case ZMQ_EVENT_MONITOR_STOPPED: {
238301
/* Also close the monitoring socket. */
239302
Close();
240303
break;
241-
// case ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL:
242-
// case ZMQ_EVENT_HANDSHAKE_FAILED_AUTH:
304+
}
243305
}
244306

245307
res.Resolve(event);

src/util/error.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,22 @@ static inline void Warn(const Napi::Env& env, const std::string& msg) {
1515
fn.Call({Napi::String::New(env, msg)});
1616
}
1717

18+
static inline Napi::Error StatusException(
19+
const Napi::Env& env, const std::string& msg, uint32_t status) {
20+
Napi::HandleScope scope(env);
21+
auto exception = Napi::Error::New(env, msg);
22+
exception.Set("status", Napi::Number::New(env, status));
23+
return exception;
24+
}
25+
26+
static inline Napi::Error CodedException(
27+
const Napi::Env& env, const std::string& msg, const std::string& code) {
28+
Napi::HandleScope scope(env);
29+
auto exception = Napi::Error::New(env, msg);
30+
exception.Set("code", Napi::String::New(env, code));
31+
return exception;
32+
}
33+
1834
/* This mostly duplicates node::ErrnoException, but it is not public. */
1935
static inline Napi::Error ErrnoException(const Napi::Env& env, int32_t error) {
2036
Napi::HandleScope scope(env);

test/unit/socket-pair-test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import {testProtos, uniqAddress} from "./helpers"
55

66
for (const proto of testProtos("tcp", "ipc", "inproc")) {
77
describe(`socket with ${proto} pair/pair`, function() {
8-
let sockA: zmq.Dealer
9-
let sockB: zmq.Dealer
8+
let sockA: zmq.Pair
9+
let sockB: zmq.Pair
1010

1111
beforeEach(function() {
12-
sockA = new zmq.Dealer
13-
sockB = new zmq.Dealer
12+
sockA = new zmq.Pair
13+
sockB = new zmq.Pair
1414
})
1515

1616
afterEach(function() {

0 commit comments

Comments
 (0)