-
Notifications
You must be signed in to change notification settings - Fork 41
/
canopus.go
429 lines (367 loc) · 12 KB
/
canopus.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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
package canopus
import (
"errors"
"math/rand"
"net"
"sync"
"time"
)
// CurrentMessageID stores the current message id used/generated for messages
var CurrentMessageID = 0
var MESSAGEID_MUTEX *sync.Mutex
func init() {
rand.Seed(time.Now().UTC().UnixNano())
CurrentMessageID = rand.Intn(65535)
MESSAGEID_MUTEX = &sync.Mutex{}
}
var GENERATE_ID uint16 = 0
const UDP = "udp"
// Types of Messages
const (
MessageConfirmable = 0
MessageNonConfirmable = 1
MessageAcknowledgment = 2
MessageReset = 3
)
// Fragments/parts of a CoAP Message packet
const (
DataHeader = 0
DataCode = 1
DataMsgIDStart = 2
DataMsgIDEnd = 4
DataTokenStart = 4
)
// OptionCode type represents a valid CoAP Option Code
type OptionCode int
const (
// OptionIfMatch request-header field is used with a method to make it conditional.
// A client that has one or more entities previously obtained from the resource can verify
// that one of those entities is current by including a list of their associated entity tags
// in the If-Match header field.
OptionIfMatch OptionCode = 1
OptionURIHost OptionCode = 3
OptionEtag OptionCode = 4
OptionIfNoneMatch OptionCode = 5
OptionObserve OptionCode = 6
OptionURIPort OptionCode = 7
OptionLocationPath OptionCode = 8
OptionURIPath OptionCode = 11
OptionContentFormat OptionCode = 12
OptionMaxAge OptionCode = 14
OptionURIQuery OptionCode = 15
OptionAccept OptionCode = 17
OptionLocationQuery OptionCode = 20
OptionBlock2 OptionCode = 23
OptionBlock1 OptionCode = 27
OptionSize2 OptionCode = 28
OptionProxyURI OptionCode = 35
OptionProxyScheme OptionCode = 39
OptionSize1 OptionCode = 60
)
// CoapCode defines a valid CoAP Code Type
type CoapCode uint8
const (
Get CoapCode = 1
Post CoapCode = 2
Put CoapCode = 3
Delete CoapCode = 4
// 2.x
CoapCodeEmpty CoapCode = 0
CoapCodeCreated CoapCode = 65 // 2.01
CoapCodeDeleted CoapCode = 66 // 2.02
CoapCodeValid CoapCode = 67 // 2.03
CoapCodeChanged CoapCode = 68 // 2.04
CoapCodeContent CoapCode = 69 // 2.05
CoapCodeContinue CoapCode = 95 // 2.31
// 4.x
CoapCodeBadRequest CoapCode = 128 // 4.00
CoapCodeUnauthorized CoapCode = 129 // 4.01
CoapCodeBadOption CoapCode = 130 // 4.02
CoapCodeForbidden CoapCode = 131 // 4.03
CoapCodeNotFound CoapCode = 132 // 4.04
CoapCodeMethodNotAllowed CoapCode = 133 // 4.05
CoapCodeNotAcceptable CoapCode = 134 // 4.06
CoapCodeRequestEntityIncomplete CoapCode = 136 // 4.08
CoapCodeConflict CoapCode = 137 // 4.09
CoapCodePreconditionFailed CoapCode = 140 // 4.12
CoapCodeRequestEntityTooLarge CoapCode = 141 // 4.13
CoapCodeUnsupportedContentFormat CoapCode = 143 // 4.15
// 5.x
CoapCodeInternalServerError CoapCode = 160 // 5.00
CoapCodeNotImplemented CoapCode = 161 // 5.01
CoapCodeBadGateway CoapCode = 162 // 5.02
CoapCodeServiceUnavailable CoapCode = 163 // 5.03
CoapCodeGatewayTimeout CoapCode = 164 // 5.04
CoapCodeProxyingNotSupported CoapCode = 165 // 5.05
)
const DefaultAckTimeout = 2
const DefaultAckRandomFactor = 1.5
const DefaultMaxRetransmit = 4
const DefaultNStart = 1
const DefaultLeisure = 5
const DefaultProbingRate = 1
const CoapDefaultHost = ""
const CoapDefaultPort = 5683
const CoapsDefaultPort = 5684
const PayloadMarker = 0xff
const MaxPacketSize = 1500
// MessageIDPurgeDuration defines the number of seconds before a MessageID Purge is initiated
const MessageIDPurgeDuration = 60
type RouteHandler func(Request) Response
// Proxy Filter
type ProxyFilter func(Message, net.Addr) bool
type ProxyHandler func(c CoapServer, msg Message, session Session)
type MediaType int
const (
MediaTypeTextPlain MediaType = 0
MediaTypeTextXML MediaType = 1
MediaTypeTextCsv MediaType = 2
MediaTypeTextHTML MediaType = 3
MediaTypeImageGif MediaType = 21
MediaTypeImageJpeg MediaType = 22
MediaTypeImagePng MediaType = 23
MediaTypeImageTiff MediaType = 24
MediaTypeAudioRaw MediaType = 25
MediaTypeVideoRaw MediaType = 26
MediaTypeApplicationLinkFormat MediaType = 40
MediaTypeApplicationXML MediaType = 41
MediaTypeApplicationOctetStream MediaType = 42
MediaTypeApplicationRdfXML MediaType = 43
MediaTypeApplicationSoapXML MediaType = 44
MediaTypeApplicationAtomXML MediaType = 45
MediaTypeApplicationXmppXML MediaType = 46
MediaTypeApplicationExi MediaType = 47
MediaTypeApplicationFastInfoSet MediaType = 48
MediaTypeApplicationSoapFastInfoSet MediaType = 49
MediaTypeApplicationJSON MediaType = 50
MediaTypeApplicationXObitBinary MediaType = 51
MediaTypeTextPlainVndOmaLwm2m MediaType = 1541
MediaTypeTlvVndOmaLwm2m MediaType = 1542
MediaTypeJSONVndOmaLwm2m MediaType = 1543
MediaTypeOpaqueVndOmaLwm2m MediaType = 1544
)
const (
MethodGet = "GET"
MethodPut = "PUT"
MethodPost = "POST"
MethodDelete = "DELETE"
MethodOptions = "OPTIONS"
MethodPatch = "PATCH"
)
type BlockSizeType byte
const (
BlockSize16 BlockSizeType = 0
BlockSize32 BlockSizeType = 1
BlockSize64 BlockSizeType = 2
BlockSize128 BlockSizeType = 3
BlockSize256 BlockSizeType = 4
BlockSize512 BlockSizeType = 5
BlockSize1024 BlockSizeType = 6
)
// Errors
var ErrPacketLengthLessThan4 = errors.New("Packet length less than 4 bytes")
var ErrInvalidCoapVersion = errors.New("Invalid CoAP version. Should be 1.")
var ErrOptionLengthUsesValue15 = errors.New(("Message format error. Option length has reserved value of 15"))
var ErrOptionDeltaUsesValue15 = errors.New(("Message format error. Option delta has reserved value of 15"))
var ErrUnknownMessageType = errors.New("Unknown message type")
var ErrInvalidTokenLength = errors.New("Invalid Token Length ( > 8)")
var ErrUnknownCriticalOption = errors.New("Unknown critical option encountered")
var ErrUnsupportedMethod = errors.New("Unsupported Method")
var ErrNoMatchingRoute = errors.New("No matching route found")
var ErrUnsupportedContentFormat = errors.New("Unsupported Content-Format")
var ErrNoMatchingMethod = errors.New("No matching method")
var ErrNilMessage = errors.New("Message is nil")
var ErrNilConn = errors.New("Connection object is nil")
var ErrNilAddr = errors.New("Address cannot be nil")
var ErrMessageSizeTooLongBlockOptionValNotSet = errors.New("Message is too long, block option or value not set")
// Security Options
const (
SecNoSec = "NoSec"
SecPreSharedKey = "PreSharedKey"
SecRawPublicKey = "RawPublicKey"
SecCertificate = "Certificate"
)
// Interfaces
type CoapServer interface {
ListenAndServe(addr string)
ListenAndServeDTLS(addr string)
Stop()
Get(path string, fn RouteHandler) Route
Delete(path string, fn RouteHandler) Route
Put(path string, fn RouteHandler) Route
Post(path string, fn RouteHandler) Route
Options(path string, fn RouteHandler) Route
Patch(path string, fn RouteHandler) Route
NewRoute(path string, method CoapCode, fn RouteHandler) Route
NotifyChange(resource, value string, confirm bool)
OnNotify(fn FnEventNotify)
OnStart(fn FnEventStart)
OnClose(fn FnEventClose)
OnDiscover(fn FnEventDiscover)
OnError(fn FnEventError)
OnObserve(fn FnEventObserve)
OnObserveCancel(fn FnEventObserveCancel)
OnMessage(fn FnEventMessage)
OnBlockMessage(fn FnEventBlockMessage)
ProxyOverHttp(enabled bool)
ProxyOverCoap(enabled bool)
GetEvents() Events
AllowProxyForwarding(Message, net.Addr) bool
GetRoutes() []Route
ForwardCoap(msg Message, session Session)
ForwardHTTP(msg Message, session Session)
AddObservation(resource, token string, session Session)
HasObservation(resource string, addr net.Addr) bool
RemoveObservation(resource string, addr net.Addr)
HandlePSK(func(id string) []byte)
GetSession(addr string) Session
DeleteSession(ssn Session)
GetCookieSecret() []byte
}
type ServerConnection interface {
ReadFrom(b []byte) (n int, addr net.Addr, err error)
WriteTo(b []byte, addr net.Addr) (n int, err error)
Close() error
LocalAddr() net.Addr
SetDeadline(t time.Time) error
SetReadDeadline(t time.Time) error
SetWriteDeadline(t time.Time) error
}
type Option interface {
Name() string
IsElective() bool
IsCritical() bool
StringValue() string
IntValue() int
GetCode() OptionCode
GetValue() interface{}
}
type Session interface {
GetConnection() ServerConnection
GetAddress() net.Addr
Write([]byte) (int, error)
Read([]byte) (n int, err error)
GetServer() CoapServer
WriteBuffer([]byte) int
}
type Request interface {
GetAttributes() map[string]string
GetAttribute(o string) string
GetAttributeAsInt(o string) int
GetMessage() Message
GetURIQuery(q string) string
SetProxyURI(uri string)
SetMediaType(mt MediaType)
SetPayload([]byte)
SetStringPayload(s string)
SetRequestURI(uri string)
SetConfirmable(con bool)
SetToken(t string)
SetURIQuery(k string, v string)
}
type Response interface {
GetMessage() Message
GetError() error
GetPayload() []byte
GetURIQuery(q string) string
}
type Connection interface {
ObserveResource(resource string) (tok string, err error)
CancelObserveResource(resource string, token string) (err error)
StopObserve(ch chan ObserveMessage)
Observe(ch chan ObserveMessage)
Send(req Request) (resp Response, err error)
Write(b []byte) (n int, err error)
Read(b []byte) (n int, err error)
Close() error
}
// Represents the payload/content of a CoAP Message
type MessagePayload interface {
GetBytes() []byte
Length() int
String() string
}
type Message interface {
GetToken() []byte
GetMessageId() uint16
GetMessageType() uint8
GetAcceptedContent() MediaType
GetCodeString() string
GetCode() CoapCode
GetMethod() uint8
GetTokenLength() uint8
GetTokenString() string
GetOptions(id OptionCode) []Option
GetOption(id OptionCode) Option
GetAllOptions() []Option
GetOptionsAsString(id OptionCode) []string
GetLocationPath() string
GetURIPath() string
GetPayload() MessagePayload
SetToken([]byte)
SetMessageId(uint16)
SetMessageType(uint8)
SetBlock1Option(opt Option)
SetStringPayload(s string)
SetPayload(MessagePayload)
AddOption(code OptionCode, value interface{})
AddOptions(opts []Option)
CloneOptions(cm Message, opts ...OptionCode)
ReplaceOptions(code OptionCode, opts []Option)
RemoveOptions(id OptionCode)
}
type Route interface {
GetMethod() string
GetMediaTypes() []MediaType
GetConfiguredPath() string
Matches(path string) (bool, map[string]string)
AutoAcknowledge() bool
Handle(req Request) Response
}
type FnEventNotify func(string, interface{}, Message)
type FnEventStart func(CoapServer)
type FnEventClose func(CoapServer)
type FnEventDiscover func()
type FnEventError func(error)
type FnEventObserve func(string, Message)
type FnEventObserveCancel func(string, Message)
type FnEventMessage func(Message, bool)
type FnEventBlockMessage func(Message, bool)
type EventCode int
const (
EventStart EventCode = 0
EventClose EventCode = 1
EventDiscover EventCode = 2
EventMessage EventCode = 3
EventError EventCode = 4
EventObserve EventCode = 5
EventObserveCancel EventCode = 6
EventNotify EventCode = 7
)
type ObserveMessage interface {
GetResource() string
GetValue() interface{}
GetMessage() Message
}
type Events interface {
OnNotify(fn FnEventNotify)
OnStart(fn FnEventStart)
OnClose(fn FnEventClose)
OnDiscover(fn FnEventDiscover)
OnError(fn FnEventError)
OnObserve(fn FnEventObserve)
OnObserveCancel(fn FnEventObserveCancel)
OnMessage(fn FnEventMessage)
OnBlockMessage(fn FnEventBlockMessage)
Notify(resource string, value interface{}, msg Message)
Started(server CoapServer)
Closed(server CoapServer)
Discover()
Error(err error)
Observe(resource string, msg Message)
ObserveCancelled(resource string, msg Message)
Message(msg Message, inbound bool)
BlockMessage(msg Message, inbound bool)
}
type BlockMessage interface {
}