-
Notifications
You must be signed in to change notification settings - Fork 9
/
socket.go
570 lines (470 loc) · 12.3 KB
/
socket.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
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
package wasi
import (
"context"
"encoding/json"
"fmt"
"net"
"strconv"
"time"
)
// RIFlags are flags provided to SockRecv.
type RIFlags uint16
const (
// RecvPeek indicates that SockRecv should return the message without
// removing it from the socket's receive queue.
RecvPeek RIFlags = 1 << iota
// RecvWaitAll indicates that on byte-stream sockets, SockRecv should block
// until the full amount of data can be returned.
RecvWaitAll
)
// Has is true if the flag is set.
func (flags RIFlags) Has(f RIFlags) bool {
return (flags & f) == f
}
var riflagsStrings = [...]string{
"RecvPeek",
"RecvWaitAll",
}
func (flags RIFlags) String() (s string) {
if flags == 0 {
return "RIFlags(0)"
}
for i, name := range riflagsStrings {
if !flags.Has(1 << i) {
continue
}
if len(s) > 0 {
s += "|"
}
s += name
}
if len(s) == 0 {
return fmt.Sprintf("RIFlags(%d)", flags)
}
return
}
// ROFlags are flags returned by SockRecv.
type ROFlags uint16
const (
// RecvDataTruncated indicates that message data has been truncated.
RecvDataTruncated ROFlags = 1 << iota
)
// Has is true if the flag is set.
func (flags ROFlags) Has(f ROFlags) bool {
return (flags & f) == f
}
func (flags ROFlags) String() string {
switch flags {
case RecvDataTruncated:
return "RecvDataTruncated"
default:
return fmt.Sprintf("ROFlags(%d)", flags)
}
}
// SIFlags are flags provided to SockSend.
//
// As there are currently no flags defined, it must be set to zero.
type SIFlags uint16
// Has is true if the flag is set.
func (flags SIFlags) Has(f SIFlags) bool {
return (flags & f) == f
}
func (flags SIFlags) String() string {
return fmt.Sprintf("SIFlags(%d)", flags)
}
// SDFlags are flags provided to SockShutdown which indicate which channels
// on a socket to shut down.
type SDFlags uint16
const (
// ShutdownRD disables further receive operations.
ShutdownRD SDFlags = 1 << iota
// ShutdownWR disables further send operations.
ShutdownWR
)
// Has is true if the flag is set.
func (flags SDFlags) Has(f SDFlags) bool {
return (flags & f) == f
}
var sdflagsStrings = [...]string{
"ShutdownRD",
"ShutdownWR",
}
func (flags SDFlags) String() (s string) {
if flags == 0 {
return "SDFlags(0)"
}
for i, name := range sdflagsStrings {
if !flags.Has(1 << i) {
continue
}
if len(s) > 0 {
s += "|"
}
s += name
}
if len(s) == 0 {
return fmt.Sprintf("SDFlags(%d)", flags)
}
return
}
// =============================================================================
// The types and functions below are used in socket extensions to the initial
// WASI preview 1 specification.
// =============================================================================
// Port is a port.
type Port uint32
// SocketAddress is a socket address.
type SocketAddress interface {
Network() string
String() string
Family() ProtocolFamily
sockaddr()
}
// These interfaces are declared in encoding/json and gopkg.in/yaml.v3,
// but we redeclare them here to avoid taking a dependency on those packages.
type jsonMarshaler interface{ MarshalJSON() ([]byte, error) }
type yamlMarshaler interface{ MarshalYAML() (any, error) }
type Inet4Address struct {
Port int
Addr [4]byte
}
func (a *Inet4Address) sockaddr() {}
func (a *Inet4Address) Family() ProtocolFamily {
return InetFamily
}
func (a *Inet4Address) Network() string {
return "ip4"
}
func (a *Inet4Address) String() string {
return fmt.Sprintf(`%d.%d.%d.%d:%d`, a.Addr[0], a.Addr[1], a.Addr[2], a.Addr[3], a.Port)
}
func (a *Inet4Address) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf(`"%d.%d.%d.%d:%d"`, a.Addr[0], a.Addr[1], a.Addr[2], a.Addr[3], a.Port)), nil
}
func (a *Inet4Address) MarshalYAML() (any, error) {
return a.String(), nil
}
var (
_ jsonMarshaler = (*Inet4Address)(nil)
_ yamlMarshaler = (*Inet4Address)(nil)
)
type Inet6Address struct {
Port int
Addr [16]byte
}
func (a *Inet6Address) sockaddr() {}
func (a *Inet6Address) Family() ProtocolFamily {
return Inet6Family
}
func (a *Inet6Address) Network() string {
return "ip6"
}
func (a *Inet6Address) String() string {
return net.JoinHostPort(net.IP(a.Addr[:]).String(), strconv.Itoa(a.Port))
}
func (a *Inet6Address) MarshalJSON() ([]byte, error) {
return []byte(`"` + a.String() + `"`), nil
}
func (a *Inet6Address) MarshalYAML() (any, error) {
return a.String(), nil
}
var (
_ jsonMarshaler = (*Inet6Address)(nil)
_ yamlMarshaler = (*Inet6Address)(nil)
)
type UnixAddress struct {
Name string
}
func (a *UnixAddress) sockaddr() {}
func (a *UnixAddress) Family() ProtocolFamily {
return UnixFamily
}
func (a *UnixAddress) Network() string {
return "unix"
}
func (a *UnixAddress) String() string {
return a.Name
}
func (a *UnixAddress) MarshalJSON() ([]byte, error) {
return json.Marshal(a.Name)
}
func (a *UnixAddress) MarshalYAML() (any, error) {
return a.Name, nil
}
var (
_ jsonMarshaler = (*UnixAddress)(nil)
_ yamlMarshaler = (*UnixAddress)(nil)
)
// ProtocolFamily is a socket protocol family.
type ProtocolFamily int32
const (
UnspecifiedFamily ProtocolFamily = iota
InetFamily
Inet6Family
UnixFamily
)
func (pf ProtocolFamily) String() string {
switch pf {
case UnspecifiedFamily:
return "UnspecifiedFamily"
case InetFamily:
return "InetFamily"
case Inet6Family:
return "Inet6Family"
case UnixFamily:
return "UnixFamily"
default:
return fmt.Sprintf("ProtocolFamily(%d)", pf)
}
}
// Protocol is a socket protocol.
type Protocol int32
const (
IPProtocol Protocol = iota
TCPProtocol
UDPProtocol
)
func (p Protocol) String() string {
switch p {
case IPProtocol:
return "IPProtocol"
case TCPProtocol:
return "TCPProtocol"
case UDPProtocol:
return "UDPProtocol"
default:
return fmt.Sprintf("Protocol(%d)", p)
}
}
// SocketType is a type of socket.
type SocketType int32
const (
AnySocket SocketType = iota
DatagramSocket
StreamSocket
)
func (st SocketType) String() string {
switch st {
case AnySocket:
return "AnySocket"
case DatagramSocket:
return "DatagramSocket"
case StreamSocket:
return "StreamSocket"
default:
return fmt.Sprintf("SocketType(%d)", st)
}
}
// SocketOptionLevel controls the level that a socket option is applied
// at or queried from.
type SocketOptionLevel int32
const (
SocketLevel SocketOptionLevel = 0 // SOL_SOCKET
TcpLevel SocketOptionLevel = 6 // IPPROTO_TCP
)
func (sl SocketOptionLevel) String() string {
switch sl {
case SocketLevel:
return "SocketLevel"
case TcpLevel:
return "TcpLevel"
default:
return fmt.Sprintf("SocketOptionLevel(%d)", sl)
}
}
// SocketOption is a socket option that can be queried or set.
type SocketOption int64
func (s SocketOption) Level() SocketOptionLevel {
return SocketOptionLevel(s >> 32)
}
func MakeSocketOption(level SocketOptionLevel, option int32) SocketOption {
return (SocketOption(level) << 32) | SocketOption(option)
}
// SOL_SOCKET level options.
const (
ReuseAddress SocketOption = (SocketOption(SocketLevel) << 32) | iota
QuerySocketType
QuerySocketError
DontRoute
Broadcast
SendBufferSize
RecvBufferSize
KeepAlive
OOBInline
Linger
RecvLowWatermark
RecvTimeout
SendTimeout
QueryAcceptConnections
BindToDevice
)
// IPPROTO_TCP level options
const (
TcpNoDelay SocketOption = (SocketOption(TcpLevel) << 32) | (15)
)
func (so SocketOption) String() string {
switch so {
case ReuseAddress:
return "ReuseAddress"
case QuerySocketType:
return "QuerySocketType"
case QuerySocketError:
return "QuerySocketError"
case DontRoute:
return "DontRoute"
case Broadcast:
return "Broadcast"
case SendBufferSize:
return "SendBufferSize"
case RecvBufferSize:
return "RecvBufferSize"
case KeepAlive:
return "KeepAlive"
case OOBInline:
return "OOBInline"
case Linger:
return "Linger"
case RecvLowWatermark:
return "RecvLowWatermark"
case RecvTimeout:
return "RecvTimeout"
case SendTimeout:
return "SendTimeout"
case QueryAcceptConnections:
return "QueryAcceptConnections"
case BindToDevice:
return "BindToDevice"
case TcpNoDelay:
return "TcpNoDelay"
default:
return fmt.Sprintf("SocketOption(%d|%d)", so.Level(), int32(so))
}
}
// AddressInfo is information about an address.
type AddressInfo struct {
Flags AddressInfoFlags
Family ProtocolFamily
SocketType SocketType
Protocol Protocol
Address SocketAddress
CanonicalName string
}
// AddressInfoFlags are AddressInfo flags.
type AddressInfoFlags uint16
const (
Passive AddressInfoFlags = 1 << iota
CanonicalName
NumericHost
NumericService
V4Mapped
QueryAll
AddressConfigured
)
// Has is true if the flag is set. If multiple flags are specified, Has returns
// true if all flags are set.
func (flags AddressInfoFlags) Has(f AddressInfoFlags) bool {
return (flags & f) == f
}
// HasAny is true if any of the specified flags are set.
func (flags AddressInfoFlags) HasAny(f AddressInfoFlags) bool {
return (flags & f) != 0
}
var addressInfoFlagsStrings = [...]string{
"Passive",
"CanonicalName",
"NumericHost",
"NumericService",
"V4Mapped",
"QueryAll",
"AddressConfigured",
}
func (flags AddressInfoFlags) String() (s string) {
for i, name := range addressInfoFlagsStrings {
if !flags.Has(1 << i) {
continue
}
if len(s) > 0 {
s += "|"
}
s += name
}
if len(s) == 0 {
return fmt.Sprintf("AddressInfoFlags(%d)", flags)
}
return
}
// SocketOptionValue is a socket option value.
type SocketOptionValue interface {
String() string
sockopt()
}
// IntValue is an integer value.
type IntValue int
func (IntValue) sockopt() {}
func (i IntValue) String() string {
return strconv.Itoa(int(i))
}
// TimeValue is used to represent socket options with a duration value.
type TimeValue Timestamp
func (TimeValue) sockopt() {}
func (tv TimeValue) String() string {
return time.Duration(tv).String()
}
// BytesValue is used to represent an arbitrary socket option value.
type BytesValue []byte
func (BytesValue) sockopt() {}
func (s BytesValue) String() string {
return string(s)
}
// SocketsNotSupported is a helper type intended to be embeded in
// implementations of the Sytem interface that do not support sockets.
//
// The type defines all socket-related methods to return ENOSYS, allowing
// the type to implement the interface but indicating to callers that the
// functionality is not supported.
type SocketsNotSupported struct{}
func (SocketsNotSupported) SockOpen(ctx context.Context, family ProtocolFamily, socketType SocketType, protocol Protocol, rightsBase, rightsInheriting Rights) (FD, Errno) {
return -1, ENOSYS
}
func (SocketsNotSupported) SockBind(ctx context.Context, fd FD, addr SocketAddress) (SocketAddress, Errno) {
return nil, ENOSYS
}
func (SocketsNotSupported) SockConnect(ctx context.Context, fd FD, addr SocketAddress) (SocketAddress, Errno) {
return nil, ENOSYS
}
func (SocketsNotSupported) SockListen(ctx context.Context, fd FD, backlog int) Errno {
return ENOSYS
}
func (SocketsNotSupported) SockAccept(ctx context.Context, fd FD, flags FDFlags) (FD, SocketAddress, SocketAddress, Errno) {
return -1, nil, nil, ENOSYS
}
func (SocketsNotSupported) SockRecv(ctx context.Context, fd FD, iovecs []IOVec, flags RIFlags) (Size, ROFlags, Errno) {
return 0, 0, ENOSYS
}
func (SocketsNotSupported) SockSend(ctx context.Context, fd FD, iovecs []IOVec, flags SIFlags) (Size, Errno) {
return 0, ENOSYS
}
func (SocketsNotSupported) SockSendTo(ctx context.Context, fd FD, iovecs []IOVec, flags SIFlags, addr SocketAddress) (Size, Errno) {
return 0, ENOSYS
}
func (SocketsNotSupported) SockRecvFrom(ctx context.Context, fd FD, iovecs []IOVec, flags RIFlags) (Size, ROFlags, SocketAddress, Errno) {
return 0, 0, nil, ENOSYS
}
func (SocketsNotSupported) SockGetOpt(ctx context.Context, fd FD, level SocketOptionLevel, option SocketOption) (SocketOptionValue, Errno) {
return nil, ENOSYS
}
func (SocketsNotSupported) SockSetOpt(ctx context.Context, fd FD, level SocketOptionLevel, option SocketOption, value SocketOptionValue) Errno {
return ENOSYS
}
func (SocketsNotSupported) SockLocalAddress(ctx context.Context, fd FD) (SocketAddress, Errno) {
return nil, ENOSYS
}
func (SocketsNotSupported) SockRemoteAddress(ctx context.Context, fd FD) (SocketAddress, Errno) {
return nil, ENOSYS
}
func (SocketsNotSupported) SockAddressInfo(ctx context.Context, name, service string, hints AddressInfo, results []AddressInfo) (int, Errno) {
return 0, ENOSYS
}
func (SocketsNotSupported) SockShutdown(ctx context.Context, fd FD, flags SDFlags) Errno {
return ENOSYS
}