-
Notifications
You must be signed in to change notification settings - Fork 8
/
errors.go
195 lines (174 loc) · 6.53 KB
/
errors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// Copyright (c) SandboxAQ. All rights reserved.
// SPDX-License-Identifier: AGPL-3.0-only
// Error defines all errors that may happen when using the Sandwich Go library.
// It uses the error codes defined in the protobuf.
package errors
import (
"fmt"
pb "github.com/sandbox-quantum/sandwich/go/proto/sandwich"
)
// Error represents the interface for all Sandwich errors.
type Error interface {
// Error extends the builtin `error` interface.
error
// `Code` returns the error code, defined in the protobuf.
Code() int32
// `SetDetails` sets the encapsulated error.
setDetails(e Error)
// `Unwrap` unwraps the next error. It is meant to be used with the `errors`
// package.
Unwrap() error
}
// BaseError represents the base structure for all Sandwich errors.
type BaseError struct {
// details holds the encapsulated error.
details Error
// msg holds the error string.
msg string
// code holds the error code, which comes from the protobuf. It is compatible
// with the C++ library.
code int32
}
// Code implements the Error interface.
func (err *BaseError) Code() int32 {
return err.code
}
// SetDetails implements the Error interface.
func (err *BaseError) setDetails(e Error) {
err.details = e
}
// Unwrap implements the Error interface.
func (err *BaseError) Unwrap() error {
return err.details
}
// Error implements the error interface.
func (err *BaseError) Error() string {
return err.msg
}
// handshakeStateErrorMap is a map code -> string for errors regarding the handshake
// state. These errors are defined in `tunnel.proto` defined by `HandshakeState`.
var handshakeStateErrorMap = map[int32]string{
int32(pb.HandshakeState_HANDSHAKESTATE_IN_PROGRESS): "the operation is still in progress",
int32(pb.HandshakeState_HANDSHAKESTATE_WANT_READ): "the implementation wants to read from the wire, but the underlying I/O is non-blocking",
int32(pb.HandshakeState_HANDSHAKESTATE_WANT_WRITE): "the implementation wants to write to the wire, but the underlying I/O is non-blocking",
int32(pb.HandshakeState_HANDSHAKESTATE_ERROR): "a critical error occurred",
}
// HandshakeStateError defines errors that take place during the handshake stage.
// These states are defined by the enum `HandshakeState` in `tunnel.proto`.
// They are used by `Tunnel.Handshake`.
type HandshakeStateError struct {
BaseError
}
// NewHandshakeStateError creates an error from an error code.
// The error code is supposed to match a key in `handshakeStateErrorMap`, defined above.
func NewHandshakeStateError(code int32, msg string) *HandshakeStateError {
err_msg := ";"
if msg != "" {
err_msg = "; " + msg
}
if val, ok := handshakeStateErrorMap[code]; ok {
return &HandshakeStateError{
BaseError{
msg: val + err_msg,
code: code,
},
}
}
return &HandshakeStateError{
BaseError{
msg: fmt.Sprintf("unknown HandshakeStateError code %d;", code),
code: code,
},
}
}
// NewHandshakeErrorFromEnum creates an error from the enum pb.HandshakeState.
func NewHandshakeStateErrorFromEnum(err pb.HandshakeState) *HandshakeStateError {
return NewHandshakeStateError(int32(err), "")
}
// recordPlaneErrorMap is a map code -> string for errors regarding the record
// plane. These errors are defined in `tunnel.proto` defined by `RecordError`.
var recordPlaneErrorMap = map[int32]string{
int32(pb.RecordError_RECORDERROR_WANT_READ): "tunnel wants to read data, but the underlying I/O interface is non-blocking.",
int32(pb.RecordError_RECORDERROR_WANT_WRITE): "tunnel wants to write data, but the underlying I/O interface is non-blocking.",
int32(pb.RecordError_RECORDERROR_BEING_SHUTDOWN): "tunnel is being closed",
int32(pb.RecordError_RECORDERROR_CLOSED): "tunnel is closed",
int32(pb.RecordError_RECORDERROR_UNKNOWN): "an unknown error occurred",
}
// RecordPlaneError defines the error that can happens during the record plane.
// These errors are defined by the enum `RecordError` in `tunnel.proto`.
// They are used by `Tunnel.Write` and `Tunnel.Read`.
type RecordPlaneError struct {
BaseError
}
// NewRecordPlaneError creates an error from an error code.
// The error code is supposed to match a key in `recordPlaneErrorMap`, defined above.
func NewRecordPlaneError(code int32, msg string) *RecordPlaneError {
err_msg := ";"
if msg != "" {
err_msg = "; " + msg
}
if val, ok := recordPlaneErrorMap[code]; ok {
return &RecordPlaneError{
BaseError{
msg: val + err_msg,
code: code,
},
}
}
return &RecordPlaneError{
BaseError{
msg: fmt.Sprintf("unknown RecordPlaneError code %d;", code),
code: code,
},
}
}
// NewRecordPlaneErrorFromEnum creates an error from the enum pb.RecordError.
func NewRecordPlaneErrorFromEnum(err pb.RecordError) *RecordPlaneError {
return NewRecordPlaneError(int32(err), "")
}
// ioErrorMap is a map code -> string for errors regarding the I/O interface.
// These errors ared defined in `io.proto` defined by `IOError`.
var ioErrorMap = map[int32]string{
int32(pb.IOError_IOERROR_IN_PROGRESS): "the I/O interface is still connecting to the remote peer",
int32(pb.IOError_IOERROR_WOULD_BLOCK): "the I/O operation would block, but the I/O interface is non-blocking",
int32(pb.IOError_IOERROR_REFUSED): "the I/O interface has been refused connection",
int32(pb.IOError_IOERROR_CLOSED): "this I/O interface is closed",
int32(pb.IOError_IOERROR_INVALID): "this I/O interface isn't valid",
int32(pb.IOError_IOERROR_SYSTEM_ERROR): "there was a system error while trying to use this I/O",
int32(pb.IOError_IOERROR_ADDRESS_IN_USE): "address is already in use",
int32(pb.IOError_IOERROR_UNKNOWN): "this I/O interface raised an unknown error",
}
// IOError defines the error that can happens during the i/o operations done by
// an I/O interface.
// These errors are defined by the enum `IOError` in `io.proto`.
type IOError struct {
BaseError
}
// NewIOError creates an error from an error code.
// The error code is supposed to match a key in `ioErrorMap`, defined above.
// This function is publicly exposed, as it is meant to be used by the user
// to implement their own I/O interface.
func NewIOError(code int32, msg string) *IOError {
err_msg := ";"
if msg != "" {
err_msg = "; " + msg
}
if val, ok := ioErrorMap[code]; ok {
return &IOError{
BaseError{
msg: val + err_msg,
code: code,
},
}
}
return &IOError{
BaseError{
msg: fmt.Sprintf("unknown IOError code %d;", code),
code: code,
},
}
}
// NewIOErrorFromEnum creates an error from the enum pb.IOError.
func NewIOErrorFromEnum(err pb.IOError) *IOError {
return NewIOError(int32(err), "")
}