Browse code

Support SCTP port mapping (bump up API to v1.37)

Signed-off-by: Wataru Ishida <ishida.wataru@lab.ntt.co.jp>
Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>

Akihiro Suda authored on 2018/02/02 18:29:55
Showing 25 changed files
... ...
@@ -19,10 +19,10 @@ produces:
19 19
 consumes:
20 20
   - "application/json"
21 21
   - "text/plain"
22
-basePath: "/v1.36"
22
+basePath: "/v1.37"
23 23
 info:
24 24
   title: "Docker Engine API"
25
-  version: "1.36"
25
+  version: "1.37"
26 26
   x-logo:
27 27
     url: "https://docs.docker.com/images/logo-docker-main.png"
28 28
   description: |
... ...
@@ -49,7 +49,7 @@ info:
49 49
     the URL is not supported by the daemon, a HTTP `400 Bad Request` error message
50 50
     is returned.
51 51
 
52
-    If you omit the version-prefix, the current version of the API (v1.36) is used.
52
+    If you omit the version-prefix, the current version of the API (v1.37) is used.
53 53
     For example, calling `/info` is the same as calling `/v1.36/info`. Using the
54 54
     API without a version-prefix is deprecated and will be removed in a future release.
55 55
 
... ...
@@ -167,7 +167,7 @@ definitions:
167 167
       Type:
168 168
         type: "string"
169 169
         x-nullable: false
170
-        enum: ["tcp", "udp"]
170
+        enum: ["tcp", "udp", "sctp"]
171 171
     example:
172 172
       PrivatePort: 8080
173 173
       PublicPort: 80
... ...
@@ -801,7 +801,7 @@ definitions:
801 801
         description: |
802 802
           An object mapping ports to an empty object in the form:
803 803
 
804
-          `{"<port>/<tcp|udp>": {}}`
804
+          `{"<port>/<tcp|udp|sctp>": {}}`
805 805
         type: "object"
806 806
         additionalProperties:
807 807
           type: "object"
... ...
@@ -1066,8 +1066,8 @@ definitions:
1066 1066
       container's port-number and protocol as key in the format `<port>/<protocol>`,
1067 1067
       for example, `80/udp`.
1068 1068
 
1069
-      If a container's port is mapped for both `tcp` and `udp`, two separate
1070
-      entries are added to the mapping table.
1069
+      If a container's port is mapped for multiple protocols, separate entries
1070
+      are added to the mapping table.
1071 1071
     type: "object"
1072 1072
     additionalProperties:
1073 1073
       type: "array"
... ...
@@ -3046,6 +3046,7 @@ definitions:
3046 3046
         enum:
3047 3047
           - "tcp"
3048 3048
           - "udp"
3049
+          - "sctp"
3049 3050
       TargetPort:
3050 3051
         description: "The port inside the container."
3051 3052
         type: "integer"
... ...
@@ -62,6 +62,8 @@ const (
62 62
 	PortConfigProtocolTCP PortConfigProtocol = "tcp"
63 63
 	// PortConfigProtocolUDP UDP
64 64
 	PortConfigProtocolUDP PortConfigProtocol = "udp"
65
+	// PortConfigProtocolSCTP SCTP
66
+	PortConfigProtocolSCTP PortConfigProtocol = "sctp"
65 67
 )
66 68
 
67 69
 // EndpointVirtualIP represents the virtual ip of a port.
... ...
@@ -621,6 +621,8 @@ func parsePortMap(portMap nat.PortMap) ([]*api.PortConfig, error) {
621 621
 			protocol = api.ProtocolTCP
622 622
 		case "udp":
623 623
 			protocol = api.ProtocolUDP
624
+		case "sctp":
625
+			protocol = api.ProtocolSCTP
624 626
 		default:
625 627
 			return nil, fmt.Errorf("invalid protocol: %s", parts[1])
626 628
 		}
... ...
@@ -13,6 +13,12 @@ keywords: "API, Docker, rcli, REST, documentation"
13 13
      will be rejected.
14 14
 -->
15 15
 
16
+## v1.37 API changes
17
+
18
+[Docker Engine API v1.37](https://docs.docker.com/engine/api/v1.36/) documentation
19
+
20
+* `POST /containers/create` and `POST /services/create` now supports exposing SCTP ports.
21
+
16 22
 ## v1.36 API changes
17 23
 
18 24
 [Docker Engine API v1.36](https://docs.docker.com/engine/api/v1.36/) documentation
... ...
@@ -16,7 +16,7 @@ TINI_COMMIT=949e6facb77383876aeff8a6944dde66b3089574
16 16
 # LIBNETWORK_COMMIT is used to build the docker-userland-proxy binary. When
17 17
 # updating the binary version, consider updating github.com/docker/libnetwork
18 18
 # in vendor.conf accordingly
19
-LIBNETWORK_COMMIT=20dd462e0a0e883437a274bd61df4bc4de980830
19
+LIBNETWORK_COMMIT=ed2130d117c11c542327b4d5216a5db36770bc65
20 20
 VNDR_COMMIT=a6e196d8b4b0cbbdc29aebdb20c59ac6926bb384
21 21
 
22 22
 # Linting
... ...
@@ -16,7 +16,7 @@ github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
16 16
 golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
17 17
 golang.org/x/sys 37707fdb30a5b38865cfb95e5aab41707daec7fd
18 18
 github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
19
-github.com/docker/go-connections 98e7d807e5d804e4e42a98d74d1dd695321224ef
19
+github.com/docker/go-connections 7beb39f0b969b075d1325fecb092faf27fd357b6
20 20
 golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
21 21
 github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987
22 22
 github.com/pmezard/go-difflib v1.0.0
... ...
@@ -33,7 +33,7 @@ github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
33 33
 #get libnetwork packages
34 34
 
35 35
 # When updating, also update LIBNETWORK_COMMIT in hack/dockerfile/binaries-commits accordingly
36
-github.com/docker/libnetwork 20dd462e0a0e883437a274bd61df4bc4de980830
36
+github.com/docker/libnetwork ed2130d117c11c542327b4d5216a5db36770bc65
37 37
 github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
38 38
 github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
39 39
 github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
... ...
@@ -57,6 +57,7 @@ github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
57 57
 github.com/hashicorp/consul v0.5.2
58 58
 github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
59 59
 github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
60
+github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
60 61
 
61 62
 # get graph and distribution packages
62 63
 github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c
... ...
@@ -113,7 +113,7 @@ func SplitProtoPort(rawPort string) (string, string) {
113 113
 }
114 114
 
115 115
 func validateProto(proto string) bool {
116
-	for _, availableProto := range []string{"tcp", "udp"} {
116
+	for _, availableProto := range []string{"tcp", "udp", "sctp"} {
117 117
 		if availableProto == proto {
118 118
 			return true
119 119
 		}
... ...
@@ -4,7 +4,6 @@ package tlsconfig
4 4
 
5 5
 import (
6 6
 	"crypto/x509"
7
-
8 7
 )
9 8
 
10 9
 // SystemCertPool returns an new empty cert pool,
... ...
@@ -1,6 +1,5 @@
1
-// Code generated by protoc-gen-gogo.
1
+// Code generated by protoc-gen-gogo. DO NOT EDIT.
2 2
 // source: agent.proto
3
-// DO NOT EDIT!
4 3
 
5 4
 /*
6 5
 	Package libnetwork is a generated protocol buffer package.
... ...
@@ -20,9 +19,6 @@ import math "math"
20 20
 import _ "github.com/gogo/protobuf/gogoproto"
21 21
 
22 22
 import strings "strings"
23
-import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto"
24
-import sort "sort"
25
-import strconv "strconv"
26 23
 import reflect "reflect"
27 24
 
28 25
 import io "io"
... ...
@@ -34,22 +30,27 @@ var _ = math.Inf
34 34
 
35 35
 // This is a compile-time assertion to ensure that this generated file
36 36
 // is compatible with the proto package it is being compiled against.
37
-const _ = proto.GoGoProtoPackageIsVersion1
37
+// A compilation error at this line likely means your copy of the
38
+// proto package needs to be updated.
39
+const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package
38 40
 
39 41
 type PortConfig_Protocol int32
40 42
 
41 43
 const (
42
-	ProtocolTCP PortConfig_Protocol = 0
43
-	ProtocolUDP PortConfig_Protocol = 1
44
+	ProtocolTCP  PortConfig_Protocol = 0
45
+	ProtocolUDP  PortConfig_Protocol = 1
46
+	ProtocolSCTP PortConfig_Protocol = 2
44 47
 )
45 48
 
46 49
 var PortConfig_Protocol_name = map[int32]string{
47 50
 	0: "TCP",
48 51
 	1: "UDP",
52
+	2: "SCTP",
49 53
 }
50 54
 var PortConfig_Protocol_value = map[string]int32{
51
-	"TCP": 0,
52
-	"UDP": 1,
55
+	"TCP":  0,
56
+	"UDP":  1,
57
+	"SCTP": 2,
53 58
 }
54 59
 
55 60
 func (x PortConfig_Protocol) String() string {
... ...
@@ -60,7 +61,7 @@ func (PortConfig_Protocol) EnumDescriptor() ([]byte, []int) { return fileDescrip
60 60
 // EndpointRecord specifies all the endpoint specific information that
61 61
 // needs to gossiped to nodes participating in the network.
62 62
 type EndpointRecord struct {
63
-	// Name of the endpoint
63
+	// Name of the container
64 64
 	Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
65 65
 	// Service name of the service to which this endpoint belongs.
66 66
 	ServiceName string `protobuf:"bytes,2,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"`
... ...
@@ -82,6 +83,41 @@ func (m *EndpointRecord) Reset()                    { *m = EndpointRecord{} }
82 82
 func (*EndpointRecord) ProtoMessage()               {}
83 83
 func (*EndpointRecord) Descriptor() ([]byte, []int) { return fileDescriptorAgent, []int{0} }
84 84
 
85
+func (m *EndpointRecord) GetName() string {
86
+	if m != nil {
87
+		return m.Name
88
+	}
89
+	return ""
90
+}
91
+
92
+func (m *EndpointRecord) GetServiceName() string {
93
+	if m != nil {
94
+		return m.ServiceName
95
+	}
96
+	return ""
97
+}
98
+
99
+func (m *EndpointRecord) GetServiceID() string {
100
+	if m != nil {
101
+		return m.ServiceID
102
+	}
103
+	return ""
104
+}
105
+
106
+func (m *EndpointRecord) GetVirtualIP() string {
107
+	if m != nil {
108
+		return m.VirtualIP
109
+	}
110
+	return ""
111
+}
112
+
113
+func (m *EndpointRecord) GetEndpointIP() string {
114
+	if m != nil {
115
+		return m.EndpointIP
116
+	}
117
+	return ""
118
+}
119
+
85 120
 func (m *EndpointRecord) GetIngressPorts() []*PortConfig {
86 121
 	if m != nil {
87 122
 		return m.IngressPorts
... ...
@@ -89,6 +125,20 @@ func (m *EndpointRecord) GetIngressPorts() []*PortConfig {
89 89
 	return nil
90 90
 }
91 91
 
92
+func (m *EndpointRecord) GetAliases() []string {
93
+	if m != nil {
94
+		return m.Aliases
95
+	}
96
+	return nil
97
+}
98
+
99
+func (m *EndpointRecord) GetTaskAliases() []string {
100
+	if m != nil {
101
+		return m.TaskAliases
102
+	}
103
+	return nil
104
+}
105
+
92 106
 // PortConfig specifies an exposed port which can be
93 107
 // addressed using the given name. This can be later queried
94 108
 // using a service discovery api or a DNS SRV query. The node
... ...
@@ -115,6 +165,34 @@ func (m *PortConfig) Reset()                    { *m = PortConfig{} }
115 115
 func (*PortConfig) ProtoMessage()               {}
116 116
 func (*PortConfig) Descriptor() ([]byte, []int) { return fileDescriptorAgent, []int{1} }
117 117
 
118
+func (m *PortConfig) GetName() string {
119
+	if m != nil {
120
+		return m.Name
121
+	}
122
+	return ""
123
+}
124
+
125
+func (m *PortConfig) GetProtocol() PortConfig_Protocol {
126
+	if m != nil {
127
+		return m.Protocol
128
+	}
129
+	return ProtocolTCP
130
+}
131
+
132
+func (m *PortConfig) GetTargetPort() uint32 {
133
+	if m != nil {
134
+		return m.TargetPort
135
+	}
136
+	return 0
137
+}
138
+
139
+func (m *PortConfig) GetPublishedPort() uint32 {
140
+	if m != nil {
141
+		return m.PublishedPort
142
+	}
143
+	return 0
144
+}
145
+
118 146
 func init() {
119 147
 	proto.RegisterType((*EndpointRecord)(nil), "libnetwork.EndpointRecord")
120 148
 	proto.RegisterType((*PortConfig)(nil), "libnetwork.PortConfig")
... ...
@@ -160,74 +238,57 @@ func valueToGoStringAgent(v interface{}, typ string) string {
160 160
 	pv := reflect.Indirect(rv).Interface()
161 161
 	return fmt.Sprintf("func(v %v) *%v { return &v } ( %#v )", typ, typ, pv)
162 162
 }
163
-func extensionToGoStringAgent(e map[int32]github_com_gogo_protobuf_proto.Extension) string {
164
-	if e == nil {
165
-		return "nil"
166
-	}
167
-	s := "map[int32]proto.Extension{"
168
-	keys := make([]int, 0, len(e))
169
-	for k := range e {
170
-		keys = append(keys, int(k))
171
-	}
172
-	sort.Ints(keys)
173
-	ss := []string{}
174
-	for _, k := range keys {
175
-		ss = append(ss, strconv.Itoa(k)+": "+e[int32(k)].GoString())
176
-	}
177
-	s += strings.Join(ss, ",") + "}"
178
-	return s
179
-}
180
-func (m *EndpointRecord) Marshal() (data []byte, err error) {
163
+func (m *EndpointRecord) Marshal() (dAtA []byte, err error) {
181 164
 	size := m.Size()
182
-	data = make([]byte, size)
183
-	n, err := m.MarshalTo(data)
165
+	dAtA = make([]byte, size)
166
+	n, err := m.MarshalTo(dAtA)
184 167
 	if err != nil {
185 168
 		return nil, err
186 169
 	}
187
-	return data[:n], nil
170
+	return dAtA[:n], nil
188 171
 }
189 172
 
190
-func (m *EndpointRecord) MarshalTo(data []byte) (int, error) {
173
+func (m *EndpointRecord) MarshalTo(dAtA []byte) (int, error) {
191 174
 	var i int
192 175
 	_ = i
193 176
 	var l int
194 177
 	_ = l
195 178
 	if len(m.Name) > 0 {
196
-		data[i] = 0xa
179
+		dAtA[i] = 0xa
197 180
 		i++
198
-		i = encodeVarintAgent(data, i, uint64(len(m.Name)))
199
-		i += copy(data[i:], m.Name)
181
+		i = encodeVarintAgent(dAtA, i, uint64(len(m.Name)))
182
+		i += copy(dAtA[i:], m.Name)
200 183
 	}
201 184
 	if len(m.ServiceName) > 0 {
202
-		data[i] = 0x12
185
+		dAtA[i] = 0x12
203 186
 		i++
204
-		i = encodeVarintAgent(data, i, uint64(len(m.ServiceName)))
205
-		i += copy(data[i:], m.ServiceName)
187
+		i = encodeVarintAgent(dAtA, i, uint64(len(m.ServiceName)))
188
+		i += copy(dAtA[i:], m.ServiceName)
206 189
 	}
207 190
 	if len(m.ServiceID) > 0 {
208
-		data[i] = 0x1a
191
+		dAtA[i] = 0x1a
209 192
 		i++
210
-		i = encodeVarintAgent(data, i, uint64(len(m.ServiceID)))
211
-		i += copy(data[i:], m.ServiceID)
193
+		i = encodeVarintAgent(dAtA, i, uint64(len(m.ServiceID)))
194
+		i += copy(dAtA[i:], m.ServiceID)
212 195
 	}
213 196
 	if len(m.VirtualIP) > 0 {
214
-		data[i] = 0x22
197
+		dAtA[i] = 0x22
215 198
 		i++
216
-		i = encodeVarintAgent(data, i, uint64(len(m.VirtualIP)))
217
-		i += copy(data[i:], m.VirtualIP)
199
+		i = encodeVarintAgent(dAtA, i, uint64(len(m.VirtualIP)))
200
+		i += copy(dAtA[i:], m.VirtualIP)
218 201
 	}
219 202
 	if len(m.EndpointIP) > 0 {
220
-		data[i] = 0x2a
203
+		dAtA[i] = 0x2a
221 204
 		i++
222
-		i = encodeVarintAgent(data, i, uint64(len(m.EndpointIP)))
223
-		i += copy(data[i:], m.EndpointIP)
205
+		i = encodeVarintAgent(dAtA, i, uint64(len(m.EndpointIP)))
206
+		i += copy(dAtA[i:], m.EndpointIP)
224 207
 	}
225 208
 	if len(m.IngressPorts) > 0 {
226 209
 		for _, msg := range m.IngressPorts {
227
-			data[i] = 0x32
210
+			dAtA[i] = 0x32
228 211
 			i++
229
-			i = encodeVarintAgent(data, i, uint64(msg.Size()))
230
-			n, err := msg.MarshalTo(data[i:])
212
+			i = encodeVarintAgent(dAtA, i, uint64(msg.Size()))
213
+			n, err := msg.MarshalTo(dAtA[i:])
231 214
 			if err != nil {
232 215
 				return 0, err
233 216
 			}
... ...
@@ -236,101 +297,101 @@ func (m *EndpointRecord) MarshalTo(data []byte) (int, error) {
236 236
 	}
237 237
 	if len(m.Aliases) > 0 {
238 238
 		for _, s := range m.Aliases {
239
-			data[i] = 0x3a
239
+			dAtA[i] = 0x3a
240 240
 			i++
241 241
 			l = len(s)
242 242
 			for l >= 1<<7 {
243
-				data[i] = uint8(uint64(l)&0x7f | 0x80)
243
+				dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
244 244
 				l >>= 7
245 245
 				i++
246 246
 			}
247
-			data[i] = uint8(l)
247
+			dAtA[i] = uint8(l)
248 248
 			i++
249
-			i += copy(data[i:], s)
249
+			i += copy(dAtA[i:], s)
250 250
 		}
251 251
 	}
252 252
 	if len(m.TaskAliases) > 0 {
253 253
 		for _, s := range m.TaskAliases {
254
-			data[i] = 0x42
254
+			dAtA[i] = 0x42
255 255
 			i++
256 256
 			l = len(s)
257 257
 			for l >= 1<<7 {
258
-				data[i] = uint8(uint64(l)&0x7f | 0x80)
258
+				dAtA[i] = uint8(uint64(l)&0x7f | 0x80)
259 259
 				l >>= 7
260 260
 				i++
261 261
 			}
262
-			data[i] = uint8(l)
262
+			dAtA[i] = uint8(l)
263 263
 			i++
264
-			i += copy(data[i:], s)
264
+			i += copy(dAtA[i:], s)
265 265
 		}
266 266
 	}
267 267
 	return i, nil
268 268
 }
269 269
 
270
-func (m *PortConfig) Marshal() (data []byte, err error) {
270
+func (m *PortConfig) Marshal() (dAtA []byte, err error) {
271 271
 	size := m.Size()
272
-	data = make([]byte, size)
273
-	n, err := m.MarshalTo(data)
272
+	dAtA = make([]byte, size)
273
+	n, err := m.MarshalTo(dAtA)
274 274
 	if err != nil {
275 275
 		return nil, err
276 276
 	}
277
-	return data[:n], nil
277
+	return dAtA[:n], nil
278 278
 }
279 279
 
280
-func (m *PortConfig) MarshalTo(data []byte) (int, error) {
280
+func (m *PortConfig) MarshalTo(dAtA []byte) (int, error) {
281 281
 	var i int
282 282
 	_ = i
283 283
 	var l int
284 284
 	_ = l
285 285
 	if len(m.Name) > 0 {
286
-		data[i] = 0xa
286
+		dAtA[i] = 0xa
287 287
 		i++
288
-		i = encodeVarintAgent(data, i, uint64(len(m.Name)))
289
-		i += copy(data[i:], m.Name)
288
+		i = encodeVarintAgent(dAtA, i, uint64(len(m.Name)))
289
+		i += copy(dAtA[i:], m.Name)
290 290
 	}
291 291
 	if m.Protocol != 0 {
292
-		data[i] = 0x10
292
+		dAtA[i] = 0x10
293 293
 		i++
294
-		i = encodeVarintAgent(data, i, uint64(m.Protocol))
294
+		i = encodeVarintAgent(dAtA, i, uint64(m.Protocol))
295 295
 	}
296 296
 	if m.TargetPort != 0 {
297
-		data[i] = 0x18
297
+		dAtA[i] = 0x18
298 298
 		i++
299
-		i = encodeVarintAgent(data, i, uint64(m.TargetPort))
299
+		i = encodeVarintAgent(dAtA, i, uint64(m.TargetPort))
300 300
 	}
301 301
 	if m.PublishedPort != 0 {
302
-		data[i] = 0x20
302
+		dAtA[i] = 0x20
303 303
 		i++
304
-		i = encodeVarintAgent(data, i, uint64(m.PublishedPort))
304
+		i = encodeVarintAgent(dAtA, i, uint64(m.PublishedPort))
305 305
 	}
306 306
 	return i, nil
307 307
 }
308 308
 
309
-func encodeFixed64Agent(data []byte, offset int, v uint64) int {
310
-	data[offset] = uint8(v)
311
-	data[offset+1] = uint8(v >> 8)
312
-	data[offset+2] = uint8(v >> 16)
313
-	data[offset+3] = uint8(v >> 24)
314
-	data[offset+4] = uint8(v >> 32)
315
-	data[offset+5] = uint8(v >> 40)
316
-	data[offset+6] = uint8(v >> 48)
317
-	data[offset+7] = uint8(v >> 56)
309
+func encodeFixed64Agent(dAtA []byte, offset int, v uint64) int {
310
+	dAtA[offset] = uint8(v)
311
+	dAtA[offset+1] = uint8(v >> 8)
312
+	dAtA[offset+2] = uint8(v >> 16)
313
+	dAtA[offset+3] = uint8(v >> 24)
314
+	dAtA[offset+4] = uint8(v >> 32)
315
+	dAtA[offset+5] = uint8(v >> 40)
316
+	dAtA[offset+6] = uint8(v >> 48)
317
+	dAtA[offset+7] = uint8(v >> 56)
318 318
 	return offset + 8
319 319
 }
320
-func encodeFixed32Agent(data []byte, offset int, v uint32) int {
321
-	data[offset] = uint8(v)
322
-	data[offset+1] = uint8(v >> 8)
323
-	data[offset+2] = uint8(v >> 16)
324
-	data[offset+3] = uint8(v >> 24)
320
+func encodeFixed32Agent(dAtA []byte, offset int, v uint32) int {
321
+	dAtA[offset] = uint8(v)
322
+	dAtA[offset+1] = uint8(v >> 8)
323
+	dAtA[offset+2] = uint8(v >> 16)
324
+	dAtA[offset+3] = uint8(v >> 24)
325 325
 	return offset + 4
326 326
 }
327
-func encodeVarintAgent(data []byte, offset int, v uint64) int {
327
+func encodeVarintAgent(dAtA []byte, offset int, v uint64) int {
328 328
 	for v >= 1<<7 {
329
-		data[offset] = uint8(v&0x7f | 0x80)
329
+		dAtA[offset] = uint8(v&0x7f | 0x80)
330 330
 		v >>= 7
331 331
 		offset++
332 332
 	}
333
-	data[offset] = uint8(v)
333
+	dAtA[offset] = uint8(v)
334 334
 	return offset + 1
335 335
 }
336 336
 func (m *EndpointRecord) Size() (n int) {
... ...
@@ -447,8 +508,8 @@ func valueToStringAgent(v interface{}) string {
447 447
 	pv := reflect.Indirect(rv).Interface()
448 448
 	return fmt.Sprintf("*%v", pv)
449 449
 }
450
-func (m *EndpointRecord) Unmarshal(data []byte) error {
451
-	l := len(data)
450
+func (m *EndpointRecord) Unmarshal(dAtA []byte) error {
451
+	l := len(dAtA)
452 452
 	iNdEx := 0
453 453
 	for iNdEx < l {
454 454
 		preIndex := iNdEx
... ...
@@ -460,7 +521,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
460 460
 			if iNdEx >= l {
461 461
 				return io.ErrUnexpectedEOF
462 462
 			}
463
-			b := data[iNdEx]
463
+			b := dAtA[iNdEx]
464 464
 			iNdEx++
465 465
 			wire |= (uint64(b) & 0x7F) << shift
466 466
 			if b < 0x80 {
... ...
@@ -488,7 +549,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
488 488
 				if iNdEx >= l {
489 489
 					return io.ErrUnexpectedEOF
490 490
 				}
491
-				b := data[iNdEx]
491
+				b := dAtA[iNdEx]
492 492
 				iNdEx++
493 493
 				stringLen |= (uint64(b) & 0x7F) << shift
494 494
 				if b < 0x80 {
... ...
@@ -503,7 +564,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
503 503
 			if postIndex > l {
504 504
 				return io.ErrUnexpectedEOF
505 505
 			}
506
-			m.Name = string(data[iNdEx:postIndex])
506
+			m.Name = string(dAtA[iNdEx:postIndex])
507 507
 			iNdEx = postIndex
508 508
 		case 2:
509 509
 			if wireType != 2 {
... ...
@@ -517,7 +578,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
517 517
 				if iNdEx >= l {
518 518
 					return io.ErrUnexpectedEOF
519 519
 				}
520
-				b := data[iNdEx]
520
+				b := dAtA[iNdEx]
521 521
 				iNdEx++
522 522
 				stringLen |= (uint64(b) & 0x7F) << shift
523 523
 				if b < 0x80 {
... ...
@@ -532,7 +593,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
532 532
 			if postIndex > l {
533 533
 				return io.ErrUnexpectedEOF
534 534
 			}
535
-			m.ServiceName = string(data[iNdEx:postIndex])
535
+			m.ServiceName = string(dAtA[iNdEx:postIndex])
536 536
 			iNdEx = postIndex
537 537
 		case 3:
538 538
 			if wireType != 2 {
... ...
@@ -546,7 +607,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
546 546
 				if iNdEx >= l {
547 547
 					return io.ErrUnexpectedEOF
548 548
 				}
549
-				b := data[iNdEx]
549
+				b := dAtA[iNdEx]
550 550
 				iNdEx++
551 551
 				stringLen |= (uint64(b) & 0x7F) << shift
552 552
 				if b < 0x80 {
... ...
@@ -561,7 +622,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
561 561
 			if postIndex > l {
562 562
 				return io.ErrUnexpectedEOF
563 563
 			}
564
-			m.ServiceID = string(data[iNdEx:postIndex])
564
+			m.ServiceID = string(dAtA[iNdEx:postIndex])
565 565
 			iNdEx = postIndex
566 566
 		case 4:
567 567
 			if wireType != 2 {
... ...
@@ -575,7 +636,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
575 575
 				if iNdEx >= l {
576 576
 					return io.ErrUnexpectedEOF
577 577
 				}
578
-				b := data[iNdEx]
578
+				b := dAtA[iNdEx]
579 579
 				iNdEx++
580 580
 				stringLen |= (uint64(b) & 0x7F) << shift
581 581
 				if b < 0x80 {
... ...
@@ -590,7 +651,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
590 590
 			if postIndex > l {
591 591
 				return io.ErrUnexpectedEOF
592 592
 			}
593
-			m.VirtualIP = string(data[iNdEx:postIndex])
593
+			m.VirtualIP = string(dAtA[iNdEx:postIndex])
594 594
 			iNdEx = postIndex
595 595
 		case 5:
596 596
 			if wireType != 2 {
... ...
@@ -604,7 +665,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
604 604
 				if iNdEx >= l {
605 605
 					return io.ErrUnexpectedEOF
606 606
 				}
607
-				b := data[iNdEx]
607
+				b := dAtA[iNdEx]
608 608
 				iNdEx++
609 609
 				stringLen |= (uint64(b) & 0x7F) << shift
610 610
 				if b < 0x80 {
... ...
@@ -619,7 +680,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
619 619
 			if postIndex > l {
620 620
 				return io.ErrUnexpectedEOF
621 621
 			}
622
-			m.EndpointIP = string(data[iNdEx:postIndex])
622
+			m.EndpointIP = string(dAtA[iNdEx:postIndex])
623 623
 			iNdEx = postIndex
624 624
 		case 6:
625 625
 			if wireType != 2 {
... ...
@@ -633,7 +694,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
633 633
 				if iNdEx >= l {
634 634
 					return io.ErrUnexpectedEOF
635 635
 				}
636
-				b := data[iNdEx]
636
+				b := dAtA[iNdEx]
637 637
 				iNdEx++
638 638
 				msglen |= (int(b) & 0x7F) << shift
639 639
 				if b < 0x80 {
... ...
@@ -648,7 +709,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
648 648
 				return io.ErrUnexpectedEOF
649 649
 			}
650 650
 			m.IngressPorts = append(m.IngressPorts, &PortConfig{})
651
-			if err := m.IngressPorts[len(m.IngressPorts)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
651
+			if err := m.IngressPorts[len(m.IngressPorts)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
652 652
 				return err
653 653
 			}
654 654
 			iNdEx = postIndex
... ...
@@ -664,7 +725,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
664 664
 				if iNdEx >= l {
665 665
 					return io.ErrUnexpectedEOF
666 666
 				}
667
-				b := data[iNdEx]
667
+				b := dAtA[iNdEx]
668 668
 				iNdEx++
669 669
 				stringLen |= (uint64(b) & 0x7F) << shift
670 670
 				if b < 0x80 {
... ...
@@ -679,7 +740,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
679 679
 			if postIndex > l {
680 680
 				return io.ErrUnexpectedEOF
681 681
 			}
682
-			m.Aliases = append(m.Aliases, string(data[iNdEx:postIndex]))
682
+			m.Aliases = append(m.Aliases, string(dAtA[iNdEx:postIndex]))
683 683
 			iNdEx = postIndex
684 684
 		case 8:
685 685
 			if wireType != 2 {
... ...
@@ -693,7 +754,7 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
693 693
 				if iNdEx >= l {
694 694
 					return io.ErrUnexpectedEOF
695 695
 				}
696
-				b := data[iNdEx]
696
+				b := dAtA[iNdEx]
697 697
 				iNdEx++
698 698
 				stringLen |= (uint64(b) & 0x7F) << shift
699 699
 				if b < 0x80 {
... ...
@@ -708,11 +769,11 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
708 708
 			if postIndex > l {
709 709
 				return io.ErrUnexpectedEOF
710 710
 			}
711
-			m.TaskAliases = append(m.TaskAliases, string(data[iNdEx:postIndex]))
711
+			m.TaskAliases = append(m.TaskAliases, string(dAtA[iNdEx:postIndex]))
712 712
 			iNdEx = postIndex
713 713
 		default:
714 714
 			iNdEx = preIndex
715
-			skippy, err := skipAgent(data[iNdEx:])
715
+			skippy, err := skipAgent(dAtA[iNdEx:])
716 716
 			if err != nil {
717 717
 				return err
718 718
 			}
... ...
@@ -731,8 +792,8 @@ func (m *EndpointRecord) Unmarshal(data []byte) error {
731 731
 	}
732 732
 	return nil
733 733
 }
734
-func (m *PortConfig) Unmarshal(data []byte) error {
735
-	l := len(data)
734
+func (m *PortConfig) Unmarshal(dAtA []byte) error {
735
+	l := len(dAtA)
736 736
 	iNdEx := 0
737 737
 	for iNdEx < l {
738 738
 		preIndex := iNdEx
... ...
@@ -744,7 +805,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
744 744
 			if iNdEx >= l {
745 745
 				return io.ErrUnexpectedEOF
746 746
 			}
747
-			b := data[iNdEx]
747
+			b := dAtA[iNdEx]
748 748
 			iNdEx++
749 749
 			wire |= (uint64(b) & 0x7F) << shift
750 750
 			if b < 0x80 {
... ...
@@ -772,7 +833,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
772 772
 				if iNdEx >= l {
773 773
 					return io.ErrUnexpectedEOF
774 774
 				}
775
-				b := data[iNdEx]
775
+				b := dAtA[iNdEx]
776 776
 				iNdEx++
777 777
 				stringLen |= (uint64(b) & 0x7F) << shift
778 778
 				if b < 0x80 {
... ...
@@ -787,7 +848,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
787 787
 			if postIndex > l {
788 788
 				return io.ErrUnexpectedEOF
789 789
 			}
790
-			m.Name = string(data[iNdEx:postIndex])
790
+			m.Name = string(dAtA[iNdEx:postIndex])
791 791
 			iNdEx = postIndex
792 792
 		case 2:
793 793
 			if wireType != 0 {
... ...
@@ -801,7 +862,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
801 801
 				if iNdEx >= l {
802 802
 					return io.ErrUnexpectedEOF
803 803
 				}
804
-				b := data[iNdEx]
804
+				b := dAtA[iNdEx]
805 805
 				iNdEx++
806 806
 				m.Protocol |= (PortConfig_Protocol(b) & 0x7F) << shift
807 807
 				if b < 0x80 {
... ...
@@ -820,7 +881,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
820 820
 				if iNdEx >= l {
821 821
 					return io.ErrUnexpectedEOF
822 822
 				}
823
-				b := data[iNdEx]
823
+				b := dAtA[iNdEx]
824 824
 				iNdEx++
825 825
 				m.TargetPort |= (uint32(b) & 0x7F) << shift
826 826
 				if b < 0x80 {
... ...
@@ -839,7 +900,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
839 839
 				if iNdEx >= l {
840 840
 					return io.ErrUnexpectedEOF
841 841
 				}
842
-				b := data[iNdEx]
842
+				b := dAtA[iNdEx]
843 843
 				iNdEx++
844 844
 				m.PublishedPort |= (uint32(b) & 0x7F) << shift
845 845
 				if b < 0x80 {
... ...
@@ -848,7 +909,7 @@ func (m *PortConfig) Unmarshal(data []byte) error {
848 848
 			}
849 849
 		default:
850 850
 			iNdEx = preIndex
851
-			skippy, err := skipAgent(data[iNdEx:])
851
+			skippy, err := skipAgent(dAtA[iNdEx:])
852 852
 			if err != nil {
853 853
 				return err
854 854
 			}
... ...
@@ -867,8 +928,8 @@ func (m *PortConfig) Unmarshal(data []byte) error {
867 867
 	}
868 868
 	return nil
869 869
 }
870
-func skipAgent(data []byte) (n int, err error) {
871
-	l := len(data)
870
+func skipAgent(dAtA []byte) (n int, err error) {
871
+	l := len(dAtA)
872 872
 	iNdEx := 0
873 873
 	for iNdEx < l {
874 874
 		var wire uint64
... ...
@@ -879,7 +940,7 @@ func skipAgent(data []byte) (n int, err error) {
879 879
 			if iNdEx >= l {
880 880
 				return 0, io.ErrUnexpectedEOF
881 881
 			}
882
-			b := data[iNdEx]
882
+			b := dAtA[iNdEx]
883 883
 			iNdEx++
884 884
 			wire |= (uint64(b) & 0x7F) << shift
885 885
 			if b < 0x80 {
... ...
@@ -897,7 +958,7 @@ func skipAgent(data []byte) (n int, err error) {
897 897
 					return 0, io.ErrUnexpectedEOF
898 898
 				}
899 899
 				iNdEx++
900
-				if data[iNdEx-1] < 0x80 {
900
+				if dAtA[iNdEx-1] < 0x80 {
901 901
 					break
902 902
 				}
903 903
 			}
... ...
@@ -914,7 +975,7 @@ func skipAgent(data []byte) (n int, err error) {
914 914
 				if iNdEx >= l {
915 915
 					return 0, io.ErrUnexpectedEOF
916 916
 				}
917
-				b := data[iNdEx]
917
+				b := dAtA[iNdEx]
918 918
 				iNdEx++
919 919
 				length |= (int(b) & 0x7F) << shift
920 920
 				if b < 0x80 {
... ...
@@ -937,7 +998,7 @@ func skipAgent(data []byte) (n int, err error) {
937 937
 					if iNdEx >= l {
938 938
 						return 0, io.ErrUnexpectedEOF
939 939
 					}
940
-					b := data[iNdEx]
940
+					b := dAtA[iNdEx]
941 941
 					iNdEx++
942 942
 					innerWire |= (uint64(b) & 0x7F) << shift
943 943
 					if b < 0x80 {
... ...
@@ -948,7 +1009,7 @@ func skipAgent(data []byte) (n int, err error) {
948 948
 				if innerWireType == 4 {
949 949
 					break
950 950
 				}
951
-				next, err := skipAgent(data[start:])
951
+				next, err := skipAgent(dAtA[start:])
952 952
 				if err != nil {
953 953
 					return 0, err
954 954
 				}
... ...
@@ -972,32 +1033,36 @@ var (
972 972
 	ErrIntOverflowAgent   = fmt.Errorf("proto: integer overflow")
973 973
 )
974 974
 
975
+func init() { proto.RegisterFile("agent.proto", fileDescriptorAgent) }
976
+
975 977
 var fileDescriptorAgent = []byte{
976
-	// 413 bytes of a gzipped FileDescriptorProto
977
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x90, 0xbf, 0xae, 0xd3, 0x30,
978
-	0x14, 0x87, 0x9b, 0xdb, 0x70, 0x6f, 0x73, 0x72, 0x13, 0xae, 0x2c, 0x84, 0xa2, 0x0e, 0x69, 0xa9,
979
-	0x84, 0x74, 0x07, 0x94, 0x2b, 0x95, 0xb1, 0x13, 0x6d, 0x19, 0xb2, 0xa0, 0xc8, 0xfc, 0x59, 0xa3,
980
-	0xb4, 0x31, 0xc1, 0x6a, 0x88, 0x23, 0xdb, 0x2d, 0x2b, 0x23, 0xe2, 0x1d, 0x98, 0x78, 0x19, 0x26,
981
-	0xc4, 0xc8, 0x84, 0x68, 0x57, 0x16, 0x1e, 0x01, 0xdb, 0x49, 0x5a, 0x21, 0x75, 0x38, 0x92, 0xf3,
982
-	0xfd, 0xbe, 0xe3, 0x1c, 0x1f, 0x70, 0xb3, 0x82, 0x54, 0x32, 0xaa, 0x39, 0x93, 0x0c, 0x41, 0x49,
983
-	0x57, 0x15, 0x91, 0x1f, 0x18, 0xdf, 0x0c, 0x1f, 0x14, 0xac, 0x60, 0x06, 0xdf, 0xe9, 0x53, 0x63,
984
-	0x4c, 0xbe, 0x5f, 0x80, 0xff, 0xbc, 0xca, 0x6b, 0x46, 0x2b, 0x89, 0xc9, 0x9a, 0xf1, 0x1c, 0x21,
985
-	0xb0, 0xab, 0xec, 0x3d, 0x09, 0xac, 0xb1, 0x75, 0xeb, 0x60, 0x73, 0x46, 0x8f, 0xe0, 0x5a, 0x10,
986
-	0xbe, 0xa3, 0x6b, 0x92, 0x9a, 0xec, 0xc2, 0x64, 0x6e, 0xcb, 0x5e, 0x68, 0xe5, 0x09, 0x40, 0xa7,
987
-	0xd0, 0x3c, 0xe8, 0x6b, 0x61, 0xee, 0x1d, 0x7e, 0x8d, 0x9c, 0x97, 0x0d, 0x8d, 0x97, 0xd8, 0x69,
988
-	0x85, 0x38, 0xd7, 0xf6, 0x8e, 0x72, 0xb9, 0xcd, 0xca, 0x94, 0xd6, 0x81, 0x7d, 0xb2, 0xdf, 0x34,
989
-	0x34, 0x4e, 0xb0, 0xd3, 0x0a, 0x71, 0x8d, 0xee, 0xc0, 0x25, 0xed, 0x90, 0x5a, 0xbf, 0x67, 0x74,
990
-	0x5f, 0xe9, 0xd0, 0xcd, 0xae, 0x7c, 0xe8, 0x14, 0xd5, 0x30, 0x03, 0x8f, 0x56, 0x05, 0x27, 0x42,
991
-	0xa4, 0x35, 0xe3, 0x52, 0x04, 0x97, 0xe3, 0xfe, 0xad, 0x3b, 0x7d, 0x18, 0x9d, 0x16, 0x12, 0x25,
992
-	0x2a, 0x58, 0xb0, 0xea, 0x2d, 0x2d, 0xf0, 0x75, 0x2b, 0x6b, 0x24, 0x50, 0x00, 0x57, 0x59, 0x49,
993
-	0x33, 0x41, 0x44, 0x70, 0xa5, 0xda, 0x1c, 0xdc, 0x7d, 0xea, 0x35, 0xc8, 0x4c, 0x6c, 0xd2, 0x2e,
994
-	0x1e, 0x98, 0xd8, 0xd5, 0xec, 0x59, 0x83, 0x26, 0x7f, 0x2c, 0x80, 0xd3, 0xcd, 0x67, 0x97, 0x39,
995
-	0x83, 0x81, 0x59, 0xfe, 0x9a, 0x95, 0x66, 0x91, 0xfe, 0x74, 0x74, 0x7e, 0xae, 0x28, 0x69, 0x35,
996
-	0x7c, 0x6c, 0x40, 0x23, 0x50, 0xbf, 0xe3, 0x05, 0x91, 0xe6, 0x61, 0x66, 0xcf, 0x1e, 0x86, 0x06,
997
-	0xe9, 0x4e, 0xf4, 0x18, 0xfc, 0x7a, 0xbb, 0x2a, 0xa9, 0x78, 0x47, 0xf2, 0xc6, 0xb1, 0x8d, 0xe3,
998
-	0x1d, 0xa9, 0xd6, 0x26, 0x4b, 0x18, 0x74, 0xb7, 0xab, 0x07, 0xf7, 0x5f, 0x2d, 0x92, 0x9b, 0xde,
999
-	0xf0, 0xfe, 0xe7, 0x2f, 0x63, 0xb7, 0xc3, 0x0a, 0xe9, 0xe4, 0xf5, 0x32, 0xb9, 0xb1, 0xfe, 0x4f,
1000
-	0x14, 0x1a, 0xda, 0x9f, 0xbe, 0x86, 0xbd, 0x79, 0xf0, 0x73, 0x1f, 0xf6, 0xfe, 0xee, 0x43, 0xeb,
1001
-	0xe3, 0x21, 0xb4, 0xbe, 0xa9, 0xfa, 0xa1, 0xea, 0xb7, 0xaa, 0xd5, 0xa5, 0x99, 0xf8, 0xe9, 0xbf,
1002
-	0x00, 0x00, 0x00, 0xff, 0xff, 0xc9, 0x63, 0x1a, 0x0f, 0x90, 0x02, 0x00, 0x00,
978
+	// 437 bytes of a gzipped FileDescriptorProto
979
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xc1, 0x6e, 0xd3, 0x30,
980
+	0x18, 0xc7, 0x9b, 0x36, 0x6c, 0xcd, 0x97, 0xb6, 0x54, 0x16, 0x42, 0x51, 0x0e, 0x69, 0xa8, 0x84,
981
+	0xd4, 0x03, 0xea, 0xa4, 0x71, 0xdc, 0x89, 0xb5, 0x1c, 0x72, 0x41, 0x96, 0xd7, 0x71, 0x0d, 0x69,
982
+	0x63, 0x82, 0xb5, 0x10, 0x47, 0xb6, 0x37, 0xae, 0xdc, 0x40, 0x7b, 0x87, 0x9d, 0x78, 0x19, 0x4e,
983
+	0x88, 0x23, 0xa7, 0x89, 0xe5, 0x09, 0x78, 0x04, 0x64, 0x27, 0x5e, 0x35, 0x69, 0x37, 0xfb, 0xf7,
984
+	0xff, 0xd9, 0xfa, 0xbe, 0x3f, 0xf8, 0x59, 0x41, 0x2b, 0xb5, 0xac, 0x05, 0x57, 0x1c, 0x41, 0xc9,
985
+	0xb6, 0x15, 0x55, 0x5f, 0xb8, 0xb8, 0x08, 0x9f, 0x15, 0xbc, 0xe0, 0x06, 0x1f, 0xe9, 0x53, 0x6b,
986
+	0xcc, 0x7f, 0xf5, 0x61, 0xf2, 0xb6, 0xca, 0x6b, 0xce, 0x2a, 0x45, 0xe8, 0x8e, 0x8b, 0x1c, 0x21,
987
+	0x70, 0xab, 0xec, 0x33, 0x0d, 0x9c, 0xd8, 0x59, 0x78, 0xc4, 0x9c, 0xd1, 0x0b, 0x18, 0x49, 0x2a,
988
+	0xae, 0xd8, 0x8e, 0xa6, 0x26, 0xeb, 0x9b, 0xcc, 0xef, 0xd8, 0x3b, 0xad, 0xbc, 0x02, 0xb0, 0x0a,
989
+	0xcb, 0x83, 0x81, 0x16, 0x4e, 0xc7, 0xcd, 0xed, 0xcc, 0x3b, 0x6b, 0x69, 0xb2, 0x26, 0x5e, 0x27,
990
+	0x24, 0xb9, 0xb6, 0xaf, 0x98, 0x50, 0x97, 0x59, 0x99, 0xb2, 0x3a, 0x70, 0xf7, 0xf6, 0xfb, 0x96,
991
+	0x26, 0x98, 0x78, 0x9d, 0x90, 0xd4, 0xe8, 0x08, 0x7c, 0xda, 0x0d, 0xa9, 0xf5, 0x27, 0x46, 0x9f,
992
+	0x34, 0xb7, 0x33, 0xb0, 0xb3, 0x27, 0x98, 0x80, 0x55, 0x92, 0x1a, 0x9d, 0xc0, 0x98, 0x55, 0x85,
993
+	0xa0, 0x52, 0xa6, 0x35, 0x17, 0x4a, 0x06, 0x07, 0xf1, 0x60, 0xe1, 0x1f, 0x3f, 0x5f, 0xee, 0x0b,
994
+	0x59, 0x62, 0x2e, 0xd4, 0x8a, 0x57, 0x1f, 0x59, 0x41, 0x46, 0x9d, 0xac, 0x91, 0x44, 0x01, 0x1c,
995
+	0x66, 0x25, 0xcb, 0x24, 0x95, 0xc1, 0x61, 0x3c, 0x58, 0x78, 0xc4, 0x5e, 0x75, 0x0d, 0x2a, 0x93,
996
+	0x17, 0xa9, 0x8d, 0x87, 0x26, 0xf6, 0x35, 0x7b, 0xd3, 0xa2, 0xf9, 0xb7, 0x3e, 0xc0, 0xfe, 0xe7,
997
+	0x47, 0xcb, 0x3c, 0x81, 0xa1, 0x29, 0x7f, 0xc7, 0x4b, 0x53, 0xe4, 0xe4, 0x78, 0xf6, 0xf8, 0x5c,
998
+	0x4b, 0xdc, 0x69, 0xe4, 0xfe, 0x01, 0x9a, 0x81, 0xaf, 0x32, 0x51, 0x50, 0x65, 0x16, 0x33, 0x3d,
999
+	0x8f, 0x09, 0xb4, 0x48, 0xbf, 0x44, 0x2f, 0x61, 0x52, 0x5f, 0x6e, 0x4b, 0x26, 0x3f, 0xd1, 0xbc,
1000
+	0x75, 0x5c, 0xe3, 0x8c, 0xef, 0xa9, 0xd6, 0xe6, 0x1f, 0x60, 0x68, 0x7f, 0x47, 0x01, 0x0c, 0x36,
1001
+	0x2b, 0x3c, 0xed, 0x85, 0x4f, 0xaf, 0x6f, 0x62, 0xdf, 0xe2, 0xcd, 0x0a, 0xeb, 0xe4, 0x7c, 0x8d,
1002
+	0xa7, 0xce, 0xc3, 0xe4, 0x7c, 0x8d, 0x51, 0x08, 0xee, 0xd9, 0x6a, 0x83, 0xa7, 0xfd, 0x70, 0x7a,
1003
+	0x7d, 0x13, 0x8f, 0x6c, 0xa4, 0x59, 0xe8, 0x7e, 0xff, 0x11, 0xf5, 0x4e, 0x83, 0x3f, 0x77, 0x51,
1004
+	0xef, 0xdf, 0x5d, 0xe4, 0x7c, 0x6d, 0x22, 0xe7, 0x67, 0x13, 0x39, 0xbf, 0x9b, 0xc8, 0xf9, 0xdb,
1005
+	0x44, 0xce, 0xf6, 0xc0, 0x6c, 0xf3, 0xfa, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xce, 0x12, 0x15,
1006
+	0x67, 0xac, 0x02, 0x00, 0x00,
1003 1007
 }
... ...
@@ -51,6 +51,7 @@ message PortConfig {
51 51
 
52 52
 		TCP = 0 [(gogoproto.enumvalue_customname) = "ProtocolTCP"];
53 53
 		UDP = 1 [(gogoproto.enumvalue_customname) = "ProtocolUDP"];
54
+		SCTP = 2 [(gogoproto.enumvalue_customname) = "ProtocolSCTP"];
54 55
 	}
55 56
 
56 57
 	// Name for the port. If provided the port information can
... ...
@@ -7,6 +7,7 @@ import (
7 7
 	"net"
8 8
 
9 9
 	"github.com/docker/libnetwork/types"
10
+	"github.com/ishidawataru/sctp"
10 11
 	"github.com/sirupsen/logrus"
11 12
 )
12 13
 
... ...
@@ -92,6 +93,9 @@ func (n *bridgeNetwork) allocatePort(bnd *types.PortBinding, containerIP, defHos
92 92
 	case *net.UDPAddr:
93 93
 		bnd.HostPort = uint16(host.(*net.UDPAddr).Port)
94 94
 		return nil
95
+	case *sctp.SCTPAddr:
96
+		bnd.HostPort = uint16(host.(*sctp.SCTPAddr).Port)
97
+		return nil
95 98
 	default:
96 99
 		// For completeness
97 100
 		return ErrUnsupportedAddressType(fmt.Sprintf("%T", netAddr))
... ...
@@ -42,4 +42,10 @@ const (
42 42
 
43 43
 	// DisableGatewayDNS label
44 44
 	DisableGatewayDNS = "com.docker.network.windowsshim.disable_gatewaydns"
45
+
46
+	// EnableOutboundNat label
47
+	EnableOutboundNat = "com.docker.network.windowsshim.enable_outboundnat"
48
+
49
+	// OutboundNatExceptions label
50
+	OutboundNatExceptions = "com.docker.network.windowsshim.outboundnat_exceptions"
45 51
 )
... ...
@@ -20,6 +20,7 @@ import (
20 20
 	"sync"
21 21
 
22 22
 	"github.com/Microsoft/hcsshim"
23
+	"github.com/docker/docker/pkg/system"
23 24
 	"github.com/docker/libnetwork/datastore"
24 25
 	"github.com/docker/libnetwork/discoverapi"
25 26
 	"github.com/docker/libnetwork/driverapi"
... ...
@@ -30,21 +31,23 @@ import (
30 30
 
31 31
 // networkConfiguration for network specific configuration
32 32
 type networkConfiguration struct {
33
-	ID                 string
34
-	Type               string
35
-	Name               string
36
-	HnsID              string
37
-	RDID               string
38
-	VLAN               uint
39
-	VSID               uint
40
-	DNSServers         string
41
-	MacPools           []hcsshim.MacPool
42
-	DNSSuffix          string
43
-	SourceMac          string
44
-	NetworkAdapterName string
45
-	dbIndex            uint64
46
-	dbExists           bool
47
-	DisableGatewayDNS  bool
33
+	ID                    string
34
+	Type                  string
35
+	Name                  string
36
+	HnsID                 string
37
+	RDID                  string
38
+	VLAN                  uint
39
+	VSID                  uint
40
+	DNSServers            string
41
+	MacPools              []hcsshim.MacPool
42
+	DNSSuffix             string
43
+	SourceMac             string
44
+	NetworkAdapterName    string
45
+	dbIndex               uint64
46
+	dbExists              bool
47
+	DisableGatewayDNS     bool
48
+	EnableOutboundNat     bool
49
+	OutboundNatExceptions []string
48 50
 }
49 51
 
50 52
 // endpointConfiguration represents the user specified configuration for the sandbox endpoint
... ...
@@ -208,6 +211,18 @@ func (d *driver) parseNetworkOptions(id string, genericOptions map[string]string
208 208
 				return nil, err
209 209
 			}
210 210
 			config.VSID = uint(vsid)
211
+		case EnableOutboundNat:
212
+			if system.GetOSVersion().Build <= 16236 {
213
+				return nil, fmt.Errorf("Invalid network option. OutboundNat is not supported on this OS version")
214
+			}
215
+			b, err := strconv.ParseBool(value)
216
+			if err != nil {
217
+				return nil, err
218
+			}
219
+			config.EnableOutboundNat = b
220
+		case OutboundNatExceptions:
221
+			s := strings.Split(value, ",")
222
+			config.OutboundNatExceptions = s
211 223
 		}
212 224
 	}
213 225
 
... ...
@@ -609,6 +624,19 @@ func (d *driver) CreateEndpoint(nid, eid string, ifInfo driverapi.InterfaceInfo,
609 609
 
610 610
 	endpointStruct.DisableICC = epOption.DisableICC
611 611
 
612
+	// Inherit OutboundNat policy from the network
613
+	if n.config.EnableOutboundNat {
614
+		outboundNatPolicy, err := json.Marshal(hcsshim.OutboundNatPolicy{
615
+			Policy:     hcsshim.Policy{Type: hcsshim.OutboundNat},
616
+			Exceptions: n.config.OutboundNatExceptions,
617
+		})
618
+
619
+		if err != nil {
620
+			return err
621
+		}
622
+		endpointStruct.Policies = append(endpointStruct.Policies, outboundNatPolicy)
623
+	}
624
+
612 625
 	configurationb, err := json.Marshal(endpointStruct)
613 626
 	if err != nil {
614 627
 		return err
... ...
@@ -276,7 +276,31 @@ func (c *ChainInfo) Forward(action Action, ip net.IP, port int, proto, destAddr
276 276
 		"--dport", strconv.Itoa(destPort),
277 277
 		"-j", "MASQUERADE",
278 278
 	}
279
-	return ProgramRule(Nat, "POSTROUTING", action, args)
279
+
280
+	if err := ProgramRule(Nat, "POSTROUTING", action, args); err != nil {
281
+		return err
282
+	}
283
+
284
+	if proto == "sctp" {
285
+		// Linux kernel v4.9 and below enables NETIF_F_SCTP_CRC for veth by
286
+		// the following commit.
287
+		// This introduces a problem when conbined with a physical NIC without
288
+		// NETIF_F_SCTP_CRC. As for a workaround, here we add an iptables entry
289
+		// to fill the checksum.
290
+		//
291
+		// https://github.com/torvalds/linux/commit/c80fafbbb59ef9924962f83aac85531039395b18
292
+		args = []string{
293
+			"-p", proto,
294
+			"--sport", strconv.Itoa(destPort),
295
+			"-j", "CHECKSUM",
296
+			"--checksum-fill",
297
+		}
298
+		if err := ProgramRule(Mangle, "POSTROUTING", action, args); err != nil {
299
+			return err
300
+		}
301
+	}
302
+
303
+	return nil
280 304
 }
281 305
 
282 306
 // Link adds reciprocal ACCEPT rule for two supplied IP addresses.
... ...
@@ -120,7 +120,7 @@ func (p *PortAllocator) RequestPortInRange(ip net.IP, proto string, portStart, p
120 120
 	p.mutex.Lock()
121 121
 	defer p.mutex.Unlock()
122 122
 
123
-	if proto != "tcp" && proto != "udp" {
123
+	if proto != "tcp" && proto != "udp" && proto != "sctp" {
124 124
 		return 0, ErrUnknownProtocol
125 125
 	}
126 126
 
... ...
@@ -131,8 +131,9 @@ func (p *PortAllocator) RequestPortInRange(ip net.IP, proto string, portStart, p
131 131
 	protomap, ok := p.ipMap[ipstr]
132 132
 	if !ok {
133 133
 		protomap = protoMap{
134
-			"tcp": p.newPortMap(),
135
-			"udp": p.newPortMap(),
134
+			"tcp":  p.newPortMap(),
135
+			"udp":  p.newPortMap(),
136
+			"sctp": p.newPortMap(),
136 137
 		}
137 138
 
138 139
 		p.ipMap[ipstr] = protomap
... ...
@@ -8,6 +8,7 @@ import (
8 8
 
9 9
 	"github.com/docker/libnetwork/iptables"
10 10
 	"github.com/docker/libnetwork/portallocator"
11
+	"github.com/ishidawataru/sctp"
11 12
 	"github.com/sirupsen/logrus"
12 13
 )
13 14
 
... ...
@@ -27,6 +28,8 @@ var (
27 27
 	ErrPortMappedForIP = errors.New("port is already mapped to ip")
28 28
 	// ErrPortNotMapped refers to an unmapped port
29 29
 	ErrPortNotMapped = errors.New("port is not mapped")
30
+	// ErrSCTPAddrNoIP refers to a SCTP address without IP address.
31
+	ErrSCTPAddrNoIP = errors.New("sctp address does not contain any IP address")
30 32
 )
31 33
 
32 34
 // PortMapper manages the network address translation
... ...
@@ -98,7 +101,10 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
98 98
 				return nil, err
99 99
 			}
100 100
 		} else {
101
-			m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort)
101
+			m.userlandProxy, err = newDummyProxy(proto, hostIP, allocatedHostPort)
102
+			if err != nil {
103
+				return nil, err
104
+			}
102 105
 		}
103 106
 	case *net.UDPAddr:
104 107
 		proto = "udp"
... ...
@@ -118,7 +124,37 @@ func (pm *PortMapper) MapRange(container net.Addr, hostIP net.IP, hostPortStart,
118 118
 				return nil, err
119 119
 			}
120 120
 		} else {
121
-			m.userlandProxy = newDummyProxy(proto, hostIP, allocatedHostPort)
121
+			m.userlandProxy, err = newDummyProxy(proto, hostIP, allocatedHostPort)
122
+			if err != nil {
123
+				return nil, err
124
+			}
125
+		}
126
+	case *sctp.SCTPAddr:
127
+		proto = "sctp"
128
+		if allocatedHostPort, err = pm.Allocator.RequestPortInRange(hostIP, proto, hostPortStart, hostPortEnd); err != nil {
129
+			return nil, err
130
+		}
131
+
132
+		m = &mapping{
133
+			proto:     proto,
134
+			host:      &sctp.SCTPAddr{IP: []net.IP{hostIP}, Port: allocatedHostPort},
135
+			container: container,
136
+		}
137
+
138
+		if useProxy {
139
+			sctpAddr := container.(*sctp.SCTPAddr)
140
+			if len(sctpAddr.IP) == 0 {
141
+				return nil, ErrSCTPAddrNoIP
142
+			}
143
+			m.userlandProxy, err = newProxy(proto, hostIP, allocatedHostPort, sctpAddr.IP[0], sctpAddr.Port, pm.proxyPath)
144
+			if err != nil {
145
+				return nil, err
146
+			}
147
+		} else {
148
+			m.userlandProxy, err = newDummyProxy(proto, hostIP, allocatedHostPort)
149
+			if err != nil {
150
+				return nil, err
151
+			}
122 152
 		}
123 153
 	default:
124 154
 		return nil, ErrUnknownBackendAddressType
... ...
@@ -195,8 +231,13 @@ func (pm *PortMapper) Unmap(host net.Addr) error {
195 195
 		return pm.Allocator.ReleasePort(a.IP, "tcp", a.Port)
196 196
 	case *net.UDPAddr:
197 197
 		return pm.Allocator.ReleasePort(a.IP, "udp", a.Port)
198
+	case *sctp.SCTPAddr:
199
+		if len(a.IP) == 0 {
200
+			return ErrSCTPAddrNoIP
201
+		}
202
+		return pm.Allocator.ReleasePort(a.IP[0], "sctp", a.Port)
198 203
 	}
199
-	return nil
204
+	return ErrUnknownBackendAddressType
200 205
 }
201 206
 
202 207
 //ReMapAll will re-apply all port mappings
... ...
@@ -219,6 +260,12 @@ func getKey(a net.Addr) string {
219 219
 		return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "tcp")
220 220
 	case *net.UDPAddr:
221 221
 		return fmt.Sprintf("%s:%d/%s", t.IP.String(), t.Port, "udp")
222
+	case *sctp.SCTPAddr:
223
+		if len(t.IP) == 0 {
224
+			logrus.Error(ErrSCTPAddrNoIP)
225
+			return ""
226
+		}
227
+		return fmt.Sprintf("%s:%d/%s", t.IP[0].String(), t.Port, "sctp")
222 228
 	}
223 229
 	return ""
224 230
 }
... ...
@@ -229,6 +276,12 @@ func getIPAndPort(a net.Addr) (net.IP, int) {
229 229
 		return t.IP, t.Port
230 230
 	case *net.UDPAddr:
231 231
 		return t.IP, t.Port
232
+	case *sctp.SCTPAddr:
233
+		if len(t.IP) == 0 {
234
+			logrus.Error(ErrSCTPAddrNoIP)
235
+			return nil, 0
236
+		}
237
+		return t.IP[0], t.Port
232 238
 	}
233 239
 	return nil, 0
234 240
 }
... ...
@@ -8,6 +8,8 @@ import (
8 8
 	"os"
9 9
 	"os/exec"
10 10
 	"time"
11
+
12
+	"github.com/ishidawataru/sctp"
11 13
 )
12 14
 
13 15
 var userlandProxyCommandName = "docker-proxy"
... ...
@@ -79,16 +81,20 @@ type dummyProxy struct {
79 79
 	addr     net.Addr
80 80
 }
81 81
 
82
-func newDummyProxy(proto string, hostIP net.IP, hostPort int) userlandProxy {
82
+func newDummyProxy(proto string, hostIP net.IP, hostPort int) (userlandProxy, error) {
83 83
 	switch proto {
84 84
 	case "tcp":
85 85
 		addr := &net.TCPAddr{IP: hostIP, Port: hostPort}
86
-		return &dummyProxy{addr: addr}
86
+		return &dummyProxy{addr: addr}, nil
87 87
 	case "udp":
88 88
 		addr := &net.UDPAddr{IP: hostIP, Port: hostPort}
89
-		return &dummyProxy{addr: addr}
89
+		return &dummyProxy{addr: addr}, nil
90
+	case "sctp":
91
+		addr := &sctp.SCTPAddr{IP: []net.IP{hostIP}, Port: hostPort}
92
+		return &dummyProxy{addr: addr}, nil
93
+	default:
94
+		return nil, fmt.Errorf("Unknown addr type: %s", proto)
90 95
 	}
91
-	return nil
92 96
 }
93 97
 
94 98
 func (p *dummyProxy) Start() error {
... ...
@@ -105,6 +111,12 @@ func (p *dummyProxy) Start() error {
105 105
 			return err
106 106
 		}
107 107
 		p.listener = l
108
+	case *sctp.SCTPAddr:
109
+		l, err := sctp.ListenSCTP("sctp", addr)
110
+		if err != nil {
111
+			return err
112
+		}
113
+		p.listener = l
108 114
 	default:
109 115
 		return fmt.Errorf("Unknown addr type: %T", p.addr)
110 116
 	}
... ...
@@ -19,6 +19,7 @@ import (
19 19
 	"github.com/docker/libnetwork/ipvs"
20 20
 	"github.com/docker/libnetwork/ns"
21 21
 	"github.com/gogo/protobuf/proto"
22
+	"github.com/ishidawataru/sctp"
22 23
 	"github.com/sirupsen/logrus"
23 24
 	"github.com/vishvananda/netlink/nl"
24 25
 	"github.com/vishvananda/netns"
... ...
@@ -503,6 +504,10 @@ func plumbProxy(iPort *PortConfig, isDelete bool) error {
503 503
 		l, err = net.ListenTCP("tcp", &net.TCPAddr{Port: int(iPort.PublishedPort)})
504 504
 	case ProtocolUDP:
505 505
 		l, err = net.ListenUDP("udp", &net.UDPAddr{Port: int(iPort.PublishedPort)})
506
+	case ProtocolSCTP:
507
+		l, err = sctp.ListenSCTP("sctp", &sctp.SCTPAddr{Port: int(iPort.PublishedPort)})
508
+	default:
509
+		err = fmt.Errorf("unknown protocol %v", iPort.Protocol)
506 510
 	}
507 511
 
508 512
 	if err != nil {
... ...
@@ -761,6 +766,7 @@ func redirecter() {
761 761
 
762 762
 	// Ensure blocking rules for anything else in/to ingress network
763 763
 	for _, rule := range [][]string{
764
+		{"-d", eIP.String(), "-p", "sctp", "-j", "DROP"},
764 765
 		{"-d", eIP.String(), "-p", "udp", "-j", "DROP"},
765 766
 		{"-d", eIP.String(), "-p", "tcp", "-j", "DROP"},
766 767
 	} {
... ...
@@ -7,6 +7,8 @@ import (
7 7
 	"net"
8 8
 	"strconv"
9 9
 	"strings"
10
+
11
+	"github.com/ishidawataru/sctp"
10 12
 )
11 13
 
12 14
 // constants for the IP address type
... ...
@@ -96,6 +98,8 @@ func (p PortBinding) HostAddr() (net.Addr, error) {
96 96
 		return &net.UDPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
97 97
 	case TCP:
98 98
 		return &net.TCPAddr{IP: p.HostIP, Port: int(p.HostPort)}, nil
99
+	case SCTP:
100
+		return &sctp.SCTPAddr{IP: []net.IP{p.HostIP}, Port: int(p.HostPort)}, nil
99 101
 	default:
100 102
 		return nil, ErrInvalidProtocolBinding(p.Proto.String())
101 103
 	}
... ...
@@ -108,6 +112,8 @@ func (p PortBinding) ContainerAddr() (net.Addr, error) {
108 108
 		return &net.UDPAddr{IP: p.IP, Port: int(p.Port)}, nil
109 109
 	case TCP:
110 110
 		return &net.TCPAddr{IP: p.IP, Port: int(p.Port)}, nil
111
+	case SCTP:
112
+		return &sctp.SCTPAddr{IP: []net.IP{p.IP}, Port: int(p.Port)}, nil
111 113
 	default:
112 114
 		return nil, ErrInvalidProtocolBinding(p.Proto.String())
113 115
 	}
... ...
@@ -233,6 +239,8 @@ const (
233 233
 	TCP = 6
234 234
 	// UDP is for the UDP ip protocol
235 235
 	UDP = 17
236
+	// SCTP is for the SCTP ip protocol
237
+	SCTP = 132
236 238
 )
237 239
 
238 240
 // Protocol represents an IP protocol number
... ...
@@ -246,6 +254,8 @@ func (p Protocol) String() string {
246 246
 		return "tcp"
247 247
 	case UDP:
248 248
 		return "udp"
249
+	case SCTP:
250
+		return "sctp"
249 251
 	default:
250 252
 		return fmt.Sprintf("%d", p)
251 253
 	}
... ...
@@ -260,6 +270,8 @@ func ParseProtocol(s string) Protocol {
260 260
 		return UDP
261 261
 	case "tcp":
262 262
 		return TCP
263
+	case "sctp":
264
+		return SCTP
263 265
 	default:
264 266
 		return 0
265 267
 	}
... ...
@@ -51,3 +51,4 @@ golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
51 51
 golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
52 52
 golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5
53 53
 github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
54
+github.com/ishidawataru/sctp 07191f837fedd2f13d1ec7b5f885f0f3ec54b1cb
54 55
new file mode 100644
... ...
@@ -0,0 +1,201 @@
0
+                                 Apache License
1
+                           Version 2.0, January 2004
2
+                        http://www.apache.org/licenses/
3
+
4
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
5
+
6
+   1. Definitions.
7
+
8
+      "License" shall mean the terms and conditions for use, reproduction,
9
+      and distribution as defined by Sections 1 through 9 of this document.
10
+
11
+      "Licensor" shall mean the copyright owner or entity authorized by
12
+      the copyright owner that is granting the License.
13
+
14
+      "Legal Entity" shall mean the union of the acting entity and all
15
+      other entities that control, are controlled by, or are under common
16
+      control with that entity. For the purposes of this definition,
17
+      "control" means (i) the power, direct or indirect, to cause the
18
+      direction or management of such entity, whether by contract or
19
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
20
+      outstanding shares, or (iii) beneficial ownership of such entity.
21
+
22
+      "You" (or "Your") shall mean an individual or Legal Entity
23
+      exercising permissions granted by this License.
24
+
25
+      "Source" form shall mean the preferred form for making modifications,
26
+      including but not limited to software source code, documentation
27
+      source, and configuration files.
28
+
29
+      "Object" form shall mean any form resulting from mechanical
30
+      transformation or translation of a Source form, including but
31
+      not limited to compiled object code, generated documentation,
32
+      and conversions to other media types.
33
+
34
+      "Work" shall mean the work of authorship, whether in Source or
35
+      Object form, made available under the License, as indicated by a
36
+      copyright notice that is included in or attached to the work
37
+      (an example is provided in the Appendix below).
38
+
39
+      "Derivative Works" shall mean any work, whether in Source or Object
40
+      form, that is based on (or derived from) the Work and for which the
41
+      editorial revisions, annotations, elaborations, or other modifications
42
+      represent, as a whole, an original work of authorship. For the purposes
43
+      of this License, Derivative Works shall not include works that remain
44
+      separable from, or merely link (or bind by name) to the interfaces of,
45
+      the Work and Derivative Works thereof.
46
+
47
+      "Contribution" shall mean any work of authorship, including
48
+      the original version of the Work and any modifications or additions
49
+      to that Work or Derivative Works thereof, that is intentionally
50
+      submitted to Licensor for inclusion in the Work by the copyright owner
51
+      or by an individual or Legal Entity authorized to submit on behalf of
52
+      the copyright owner. For the purposes of this definition, "submitted"
53
+      means any form of electronic, verbal, or written communication sent
54
+      to the Licensor or its representatives, including but not limited to
55
+      communication on electronic mailing lists, source code control systems,
56
+      and issue tracking systems that are managed by, or on behalf of, the
57
+      Licensor for the purpose of discussing and improving the Work, but
58
+      excluding communication that is conspicuously marked or otherwise
59
+      designated in writing by the copyright owner as "Not a Contribution."
60
+
61
+      "Contributor" shall mean Licensor and any individual or Legal Entity
62
+      on behalf of whom a Contribution has been received by Licensor and
63
+      subsequently incorporated within the Work.
64
+
65
+   2. Grant of Copyright License. Subject to the terms and conditions of
66
+      this License, each Contributor hereby grants to You a perpetual,
67
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
68
+      copyright license to reproduce, prepare Derivative Works of,
69
+      publicly display, publicly perform, sublicense, and distribute the
70
+      Work and such Derivative Works in Source or Object form.
71
+
72
+   3. Grant of Patent License. Subject to the terms and conditions of
73
+      this License, each Contributor hereby grants to You a perpetual,
74
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
75
+      (except as stated in this section) patent license to make, have made,
76
+      use, offer to sell, sell, import, and otherwise transfer the Work,
77
+      where such license applies only to those patent claims licensable
78
+      by such Contributor that are necessarily infringed by their
79
+      Contribution(s) alone or by combination of their Contribution(s)
80
+      with the Work to which such Contribution(s) was submitted. If You
81
+      institute patent litigation against any entity (including a
82
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
83
+      or a Contribution incorporated within the Work constitutes direct
84
+      or contributory patent infringement, then any patent licenses
85
+      granted to You under this License for that Work shall terminate
86
+      as of the date such litigation is filed.
87
+
88
+   4. Redistribution. You may reproduce and distribute copies of the
89
+      Work or Derivative Works thereof in any medium, with or without
90
+      modifications, and in Source or Object form, provided that You
91
+      meet the following conditions:
92
+
93
+      (a) You must give any other recipients of the Work or
94
+          Derivative Works a copy of this License; and
95
+
96
+      (b) You must cause any modified files to carry prominent notices
97
+          stating that You changed the files; and
98
+
99
+      (c) You must retain, in the Source form of any Derivative Works
100
+          that You distribute, all copyright, patent, trademark, and
101
+          attribution notices from the Source form of the Work,
102
+          excluding those notices that do not pertain to any part of
103
+          the Derivative Works; and
104
+
105
+      (d) If the Work includes a "NOTICE" text file as part of its
106
+          distribution, then any Derivative Works that You distribute must
107
+          include a readable copy of the attribution notices contained
108
+          within such NOTICE file, excluding those notices that do not
109
+          pertain to any part of the Derivative Works, in at least one
110
+          of the following places: within a NOTICE text file distributed
111
+          as part of the Derivative Works; within the Source form or
112
+          documentation, if provided along with the Derivative Works; or,
113
+          within a display generated by the Derivative Works, if and
114
+          wherever such third-party notices normally appear. The contents
115
+          of the NOTICE file are for informational purposes only and
116
+          do not modify the License. You may add Your own attribution
117
+          notices within Derivative Works that You distribute, alongside
118
+          or as an addendum to the NOTICE text from the Work, provided
119
+          that such additional attribution notices cannot be construed
120
+          as modifying the License.
121
+
122
+      You may add Your own copyright statement to Your modifications and
123
+      may provide additional or different license terms and conditions
124
+      for use, reproduction, or distribution of Your modifications, or
125
+      for any such Derivative Works as a whole, provided Your use,
126
+      reproduction, and distribution of the Work otherwise complies with
127
+      the conditions stated in this License.
128
+
129
+   5. Submission of Contributions. Unless You explicitly state otherwise,
130
+      any Contribution intentionally submitted for inclusion in the Work
131
+      by You to the Licensor shall be under the terms and conditions of
132
+      this License, without any additional terms or conditions.
133
+      Notwithstanding the above, nothing herein shall supersede or modify
134
+      the terms of any separate license agreement you may have executed
135
+      with Licensor regarding such Contributions.
136
+
137
+   6. Trademarks. This License does not grant permission to use the trade
138
+      names, trademarks, service marks, or product names of the Licensor,
139
+      except as required for reasonable and customary use in describing the
140
+      origin of the Work and reproducing the content of the NOTICE file.
141
+
142
+   7. Disclaimer of Warranty. Unless required by applicable law or
143
+      agreed to in writing, Licensor provides the Work (and each
144
+      Contributor provides its Contributions) on an "AS IS" BASIS,
145
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
146
+      implied, including, without limitation, any warranties or conditions
147
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
148
+      PARTICULAR PURPOSE. You are solely responsible for determining the
149
+      appropriateness of using or redistributing the Work and assume any
150
+      risks associated with Your exercise of permissions under this License.
151
+
152
+   8. Limitation of Liability. In no event and under no legal theory,
153
+      whether in tort (including negligence), contract, or otherwise,
154
+      unless required by applicable law (such as deliberate and grossly
155
+      negligent acts) or agreed to in writing, shall any Contributor be
156
+      liable to You for damages, including any direct, indirect, special,
157
+      incidental, or consequential damages of any character arising as a
158
+      result of this License or out of the use or inability to use the
159
+      Work (including but not limited to damages for loss of goodwill,
160
+      work stoppage, computer failure or malfunction, or any and all
161
+      other commercial damages or losses), even if such Contributor
162
+      has been advised of the possibility of such damages.
163
+
164
+   9. Accepting Warranty or Additional Liability. While redistributing
165
+      the Work or Derivative Works thereof, You may choose to offer,
166
+      and charge a fee for, acceptance of support, warranty, indemnity,
167
+      or other liability obligations and/or rights consistent with this
168
+      License. However, in accepting such obligations, You may act only
169
+      on Your own behalf and on Your sole responsibility, not on behalf
170
+      of any other Contributor, and only if You agree to indemnify,
171
+      defend, and hold each Contributor harmless for any liability
172
+      incurred by, or claims asserted against, such Contributor by reason
173
+      of your accepting any such warranty or additional liability.
174
+
175
+   END OF TERMS AND CONDITIONS
176
+
177
+   APPENDIX: How to apply the Apache License to your work.
178
+
179
+      To apply the Apache License to your work, attach the following
180
+      boilerplate notice, with the fields enclosed by brackets "{}"
181
+      replaced with your own identifying information. (Don't include
182
+      the brackets!)  The text should be enclosed in the appropriate
183
+      comment syntax for the file format. We also recommend that a
184
+      file or class name and description of purpose be included on the
185
+      same "printed page" as the copyright notice for easier
186
+      identification within third-party archives.
187
+
188
+   Copyright {yyyy} {name of copyright owner}
189
+
190
+   Licensed under the Apache License, Version 2.0 (the "License");
191
+   you may not use this file except in compliance with the License.
192
+   You may obtain a copy of the License at
193
+
194
+       http://www.apache.org/licenses/LICENSE-2.0
195
+
196
+   Unless required by applicable law or agreed to in writing, software
197
+   distributed under the License is distributed on an "AS IS" BASIS,
198
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
199
+   See the License for the specific language governing permissions and
200
+   limitations under the License.
0 201
new file mode 100644
... ...
@@ -0,0 +1,18 @@
0
+Stream Control Transmission Protocol (SCTP)
1
+----
2
+
3
+[![Build Status](https://travis-ci.org/ishidawataru/sctp.svg?branch=master)](https://travis-ci.org/ishidawataru/sctp/builds)
4
+
5
+Examples
6
+----
7
+
8
+See `example/sctp.go`
9
+
10
+```go
11
+$ cd example
12
+$ go build
13
+$ # run example SCTP server
14
+$ ./example -server -port 1000 -ip 10.10.0.1,10.20.0.1
15
+$ # run example SCTP client
16
+$ ./example -port 1000 -ip 10.10.0.1,10.20.0.1
17
+```
0 18
new file mode 100644
... ...
@@ -0,0 +1,656 @@
0
+package sctp
1
+
2
+import (
3
+	"bytes"
4
+	"encoding/binary"
5
+	"fmt"
6
+	"net"
7
+	"strconv"
8
+	"strings"
9
+	"sync"
10
+	"sync/atomic"
11
+	"syscall"
12
+	"time"
13
+	"unsafe"
14
+)
15
+
16
+const (
17
+	SOL_SCTP = 132
18
+
19
+	SCTP_BINDX_ADD_ADDR = 0x01
20
+	SCTP_BINDX_REM_ADDR = 0x02
21
+
22
+	MSG_NOTIFICATION = 0x8000
23
+)
24
+
25
+const (
26
+	SCTP_RTOINFO = iota
27
+	SCTP_ASSOCINFO
28
+	SCTP_INITMSG
29
+	SCTP_NODELAY
30
+	SCTP_AUTOCLOSE
31
+	SCTP_SET_PEER_PRIMARY_ADDR
32
+	SCTP_PRIMARY_ADDR
33
+	SCTP_ADAPTATION_LAYER
34
+	SCTP_DISABLE_FRAGMENTS
35
+	SCTP_PEER_ADDR_PARAMS
36
+	SCTP_DEFAULT_SENT_PARAM
37
+	SCTP_EVENTS
38
+	SCTP_I_WANT_MAPPED_V4_ADDR
39
+	SCTP_MAXSEG
40
+	SCTP_STATUS
41
+	SCTP_GET_PEER_ADDR_INFO
42
+	SCTP_DELAYED_ACK_TIME
43
+	SCTP_DELAYED_ACK  = SCTP_DELAYED_ACK_TIME
44
+	SCTP_DELAYED_SACK = SCTP_DELAYED_ACK_TIME
45
+
46
+	SCTP_SOCKOPT_BINDX_ADD = 100
47
+	SCTP_SOCKOPT_BINDX_REM = 101
48
+	SCTP_SOCKOPT_PEELOFF   = 102
49
+	SCTP_GET_PEER_ADDRS    = 108
50
+	SCTP_GET_LOCAL_ADDRS   = 109
51
+	SCTP_SOCKOPT_CONNECTX  = 110
52
+	SCTP_SOCKOPT_CONNECTX3 = 111
53
+)
54
+
55
+const (
56
+	SCTP_EVENT_DATA_IO = 1 << iota
57
+	SCTP_EVENT_ASSOCIATION
58
+	SCTP_EVENT_ADDRESS
59
+	SCTP_EVENT_SEND_FAILURE
60
+	SCTP_EVENT_PEER_ERROR
61
+	SCTP_EVENT_SHUTDOWN
62
+	SCTP_EVENT_PARTIAL_DELIVERY
63
+	SCTP_EVENT_ADAPTATION_LAYER
64
+	SCTP_EVENT_AUTHENTICATION
65
+	SCTP_EVENT_SENDER_DRY
66
+
67
+	SCTP_EVENT_ALL = SCTP_EVENT_DATA_IO | SCTP_EVENT_ASSOCIATION | SCTP_EVENT_ADDRESS | SCTP_EVENT_SEND_FAILURE | SCTP_EVENT_PEER_ERROR | SCTP_EVENT_SHUTDOWN | SCTP_EVENT_PARTIAL_DELIVERY | SCTP_EVENT_ADAPTATION_LAYER | SCTP_EVENT_AUTHENTICATION | SCTP_EVENT_SENDER_DRY
68
+)
69
+
70
+type SCTPNotificationType int
71
+
72
+const (
73
+	SCTP_SN_TYPE_BASE = SCTPNotificationType(iota + (1 << 15))
74
+	SCTP_ASSOC_CHANGE
75
+	SCTP_PEER_ADDR_CHANGE
76
+	SCTP_SEND_FAILED
77
+	SCTP_REMOTE_ERROR
78
+	SCTP_SHUTDOWN_EVENT
79
+	SCTP_PARTIAL_DELIVERY_EVENT
80
+	SCTP_ADAPTATION_INDICATION
81
+	SCTP_AUTHENTICATION_INDICATION
82
+	SCTP_SENDER_DRY_EVENT
83
+)
84
+
85
+type NotificationHandler func([]byte) error
86
+
87
+type EventSubscribe struct {
88
+	DataIO          uint8
89
+	Association     uint8
90
+	Address         uint8
91
+	SendFailure     uint8
92
+	PeerError       uint8
93
+	Shutdown        uint8
94
+	PartialDelivery uint8
95
+	AdaptationLayer uint8
96
+	Authentication  uint8
97
+	SenderDry       uint8
98
+}
99
+
100
+const (
101
+	SCTP_CMSG_INIT = iota
102
+	SCTP_CMSG_SNDRCV
103
+	SCTP_CMSG_SNDINFO
104
+	SCTP_CMSG_RCVINFO
105
+	SCTP_CMSG_NXTINFO
106
+)
107
+
108
+const (
109
+	SCTP_UNORDERED = 1 << iota
110
+	SCTP_ADDR_OVER
111
+	SCTP_ABORT
112
+	SCTP_SACK_IMMEDIATELY
113
+	SCTP_EOF
114
+)
115
+
116
+const (
117
+	SCTP_MAX_STREAM = 0xffff
118
+)
119
+
120
+type InitMsg struct {
121
+	NumOstreams    uint16
122
+	MaxInstreams   uint16
123
+	MaxAttempts    uint16
124
+	MaxInitTimeout uint16
125
+}
126
+
127
+type SndRcvInfo struct {
128
+	Stream  uint16
129
+	SSN     uint16
130
+	Flags   uint16
131
+	_       uint16
132
+	PPID    uint32
133
+	Context uint32
134
+	TTL     uint32
135
+	TSN     uint32
136
+	CumTSN  uint32
137
+	AssocID int32
138
+}
139
+
140
+type SndInfo struct {
141
+	SID     uint16
142
+	Flags   uint16
143
+	PPID    uint32
144
+	Context uint32
145
+	AssocID int32
146
+}
147
+
148
+type GetAddrsOld struct {
149
+	AssocID int32
150
+	AddrNum int32
151
+	Addrs   uintptr
152
+}
153
+
154
+type NotificationHeader struct {
155
+	Type   uint16
156
+	Flags  uint16
157
+	Length uint32
158
+}
159
+
160
+type SCTPState uint16
161
+
162
+const (
163
+	SCTP_COMM_UP = SCTPState(iota)
164
+	SCTP_COMM_LOST
165
+	SCTP_RESTART
166
+	SCTP_SHUTDOWN_COMP
167
+	SCTP_CANT_STR_ASSOC
168
+)
169
+
170
+var nativeEndian binary.ByteOrder
171
+var sndRcvInfoSize uintptr
172
+
173
+func init() {
174
+	i := uint16(1)
175
+	if *(*byte)(unsafe.Pointer(&i)) == 0 {
176
+		nativeEndian = binary.BigEndian
177
+	} else {
178
+		nativeEndian = binary.LittleEndian
179
+	}
180
+	info := SndRcvInfo{}
181
+	sndRcvInfoSize = unsafe.Sizeof(info)
182
+}
183
+
184
+func toBuf(v interface{}) []byte {
185
+	var buf bytes.Buffer
186
+	binary.Write(&buf, nativeEndian, v)
187
+	return buf.Bytes()
188
+}
189
+
190
+func htons(h uint16) uint16 {
191
+	if nativeEndian == binary.LittleEndian {
192
+		return (h << 8 & 0xff00) | (h >> 8 & 0xff)
193
+	}
194
+	return h
195
+}
196
+
197
+var ntohs = htons
198
+
199
+func setNumOstreams(fd, num int) error {
200
+	param := InitMsg{
201
+		NumOstreams: uint16(num),
202
+	}
203
+	optlen := unsafe.Sizeof(param)
204
+	_, _, err := setsockopt(fd, SCTP_INITMSG, uintptr(unsafe.Pointer(&param)), uintptr(optlen))
205
+	return err
206
+}
207
+
208
+type SCTPAddr struct {
209
+	IP   []net.IP
210
+	Port int
211
+}
212
+
213
+func (a *SCTPAddr) ToRawSockAddrBuf() []byte {
214
+	buf := []byte{}
215
+	p := htons(uint16(a.Port))
216
+	for _, ip := range a.IP {
217
+		if ip.To4() != nil {
218
+			s := syscall.RawSockaddrInet4{
219
+				Family: syscall.AF_INET,
220
+				Port:   p,
221
+			}
222
+			copy(s.Addr[:], ip.To4())
223
+			buf = append(buf, toBuf(s)...)
224
+		} else {
225
+			s := syscall.RawSockaddrInet6{
226
+				Family: syscall.AF_INET6,
227
+				Port:   p,
228
+			}
229
+			copy(s.Addr[:], ip)
230
+			buf = append(buf, toBuf(s)...)
231
+		}
232
+	}
233
+	return buf
234
+}
235
+
236
+func (a *SCTPAddr) String() string {
237
+	var b bytes.Buffer
238
+
239
+	for n, i := range a.IP {
240
+		if a.IP[n].To4() != nil {
241
+			b.WriteString(i.String())
242
+		} else if a.IP[n].To16() != nil {
243
+			b.WriteRune('[')
244
+			b.WriteString(i.String())
245
+			b.WriteRune(']')
246
+		}
247
+		if n < len(a.IP)-1 {
248
+			b.WriteRune('/')
249
+		}
250
+	}
251
+	b.WriteRune(':')
252
+	b.WriteString(strconv.Itoa(a.Port))
253
+	return b.String()
254
+}
255
+
256
+func (a *SCTPAddr) Network() string { return "sctp" }
257
+
258
+func ResolveSCTPAddr(network, addrs string) (*SCTPAddr, error) {
259
+	tcpnet := ""
260
+	switch network {
261
+	case "", "sctp":
262
+	case "sctp4":
263
+		tcpnet = "tcp4"
264
+	case "sctp6":
265
+		tcpnet = "tcp6"
266
+	default:
267
+		return nil, fmt.Errorf("invalid net: %s", network)
268
+	}
269
+	elems := strings.Split(addrs, "/")
270
+	if len(elems) == 0 {
271
+		return nil, fmt.Errorf("invalid input: %s", addrs)
272
+	}
273
+	ipaddrs := make([]net.IP, 0, len(elems))
274
+	for _, e := range elems[:len(elems)-1] {
275
+		tcpa, err := net.ResolveTCPAddr(tcpnet, e+":")
276
+		if err != nil {
277
+			return nil, err
278
+		}
279
+		ipaddrs = append(ipaddrs, tcpa.IP)
280
+	}
281
+	tcpa, err := net.ResolveTCPAddr(tcpnet, elems[len(elems)-1])
282
+	if err != nil {
283
+		return nil, err
284
+	}
285
+	if tcpa.IP != nil {
286
+		ipaddrs = append(ipaddrs, tcpa.IP)
287
+	} else {
288
+		ipaddrs = nil
289
+	}
290
+	return &SCTPAddr{
291
+		IP:   ipaddrs,
292
+		Port: tcpa.Port,
293
+	}, nil
294
+}
295
+
296
+func SCTPConnect(fd int, addr *SCTPAddr) (int, error) {
297
+	buf := addr.ToRawSockAddrBuf()
298
+	param := GetAddrsOld{
299
+		AddrNum: int32(len(buf)),
300
+		Addrs:   uintptr(uintptr(unsafe.Pointer(&buf[0]))),
301
+	}
302
+	optlen := unsafe.Sizeof(param)
303
+	_, _, err := getsockopt(fd, SCTP_SOCKOPT_CONNECTX3, uintptr(unsafe.Pointer(&param)), uintptr(unsafe.Pointer(&optlen)))
304
+	if err == nil {
305
+		return int(param.AssocID), nil
306
+	} else if err != syscall.ENOPROTOOPT {
307
+		return 0, err
308
+	}
309
+	r0, _, err := setsockopt(fd, SCTP_SOCKOPT_CONNECTX, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
310
+	return int(r0), err
311
+}
312
+
313
+func SCTPBind(fd int, addr *SCTPAddr, flags int) error {
314
+	var option uintptr
315
+	switch flags {
316
+	case SCTP_BINDX_ADD_ADDR:
317
+		option = SCTP_SOCKOPT_BINDX_ADD
318
+	case SCTP_BINDX_REM_ADDR:
319
+		option = SCTP_SOCKOPT_BINDX_REM
320
+	default:
321
+		return syscall.EINVAL
322
+	}
323
+
324
+	buf := addr.ToRawSockAddrBuf()
325
+	_, _, err := setsockopt(fd, option, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
326
+	return err
327
+}
328
+
329
+type SCTPConn struct {
330
+	_fd                 int32
331
+	notificationHandler NotificationHandler
332
+}
333
+
334
+func (c *SCTPConn) fd() int {
335
+	return int(atomic.LoadInt32(&c._fd))
336
+}
337
+
338
+func NewSCTPConn(fd int, handler NotificationHandler) *SCTPConn {
339
+	conn := &SCTPConn{
340
+		_fd:                 int32(fd),
341
+		notificationHandler: handler,
342
+	}
343
+	return conn
344
+}
345
+
346
+func (c *SCTPConn) Write(b []byte) (int, error) {
347
+	return c.SCTPWrite(b, nil)
348
+}
349
+
350
+func (c *SCTPConn) Read(b []byte) (int, error) {
351
+	n, _, err := c.SCTPRead(b)
352
+	if n < 0 {
353
+		n = 0
354
+	}
355
+	return n, err
356
+}
357
+
358
+func (c *SCTPConn) SetInitMsg(numOstreams, maxInstreams, maxAttempts, maxInitTimeout int) error {
359
+	param := InitMsg{
360
+		NumOstreams:    uint16(numOstreams),
361
+		MaxInstreams:   uint16(maxInstreams),
362
+		MaxAttempts:    uint16(maxAttempts),
363
+		MaxInitTimeout: uint16(maxInitTimeout),
364
+	}
365
+	optlen := unsafe.Sizeof(param)
366
+	_, _, err := setsockopt(c.fd(), SCTP_INITMSG, uintptr(unsafe.Pointer(&param)), uintptr(optlen))
367
+	return err
368
+}
369
+
370
+func (c *SCTPConn) SubscribeEvents(flags int) error {
371
+	var d, a, ad, sf, p, sh, pa, ada, au, se uint8
372
+	if flags&SCTP_EVENT_DATA_IO > 0 {
373
+		d = 1
374
+	}
375
+	if flags&SCTP_EVENT_ASSOCIATION > 0 {
376
+		a = 1
377
+	}
378
+	if flags&SCTP_EVENT_ADDRESS > 0 {
379
+		ad = 1
380
+	}
381
+	if flags&SCTP_EVENT_SEND_FAILURE > 0 {
382
+		sf = 1
383
+	}
384
+	if flags&SCTP_EVENT_PEER_ERROR > 0 {
385
+		p = 1
386
+	}
387
+	if flags&SCTP_EVENT_SHUTDOWN > 0 {
388
+		sh = 1
389
+	}
390
+	if flags&SCTP_EVENT_PARTIAL_DELIVERY > 0 {
391
+		pa = 1
392
+	}
393
+	if flags&SCTP_EVENT_ADAPTATION_LAYER > 0 {
394
+		ada = 1
395
+	}
396
+	if flags&SCTP_EVENT_AUTHENTICATION > 0 {
397
+		au = 1
398
+	}
399
+	if flags&SCTP_EVENT_SENDER_DRY > 0 {
400
+		se = 1
401
+	}
402
+	param := EventSubscribe{
403
+		DataIO:          d,
404
+		Association:     a,
405
+		Address:         ad,
406
+		SendFailure:     sf,
407
+		PeerError:       p,
408
+		Shutdown:        sh,
409
+		PartialDelivery: pa,
410
+		AdaptationLayer: ada,
411
+		Authentication:  au,
412
+		SenderDry:       se,
413
+	}
414
+	optlen := unsafe.Sizeof(param)
415
+	_, _, err := setsockopt(c.fd(), SCTP_EVENTS, uintptr(unsafe.Pointer(&param)), uintptr(optlen))
416
+	return err
417
+}
418
+
419
+func (c *SCTPConn) SubscribedEvents() (int, error) {
420
+	param := EventSubscribe{}
421
+	optlen := unsafe.Sizeof(param)
422
+	_, _, err := getsockopt(c.fd(), SCTP_EVENTS, uintptr(unsafe.Pointer(&param)), uintptr(unsafe.Pointer(&optlen)))
423
+	if err != nil {
424
+		return 0, err
425
+	}
426
+	var flags int
427
+	if param.DataIO > 0 {
428
+		flags |= SCTP_EVENT_DATA_IO
429
+	}
430
+	if param.Association > 0 {
431
+		flags |= SCTP_EVENT_ASSOCIATION
432
+	}
433
+	if param.Address > 0 {
434
+		flags |= SCTP_EVENT_ADDRESS
435
+	}
436
+	if param.SendFailure > 0 {
437
+		flags |= SCTP_EVENT_SEND_FAILURE
438
+	}
439
+	if param.PeerError > 0 {
440
+		flags |= SCTP_EVENT_PEER_ERROR
441
+	}
442
+	if param.Shutdown > 0 {
443
+		flags |= SCTP_EVENT_SHUTDOWN
444
+	}
445
+	if param.PartialDelivery > 0 {
446
+		flags |= SCTP_EVENT_PARTIAL_DELIVERY
447
+	}
448
+	if param.AdaptationLayer > 0 {
449
+		flags |= SCTP_EVENT_ADAPTATION_LAYER
450
+	}
451
+	if param.Authentication > 0 {
452
+		flags |= SCTP_EVENT_AUTHENTICATION
453
+	}
454
+	if param.SenderDry > 0 {
455
+		flags |= SCTP_EVENT_SENDER_DRY
456
+	}
457
+	return flags, nil
458
+}
459
+
460
+func (c *SCTPConn) SetDefaultSentParam(info *SndRcvInfo) error {
461
+	optlen := unsafe.Sizeof(*info)
462
+	_, _, err := setsockopt(c.fd(), SCTP_DEFAULT_SENT_PARAM, uintptr(unsafe.Pointer(info)), uintptr(optlen))
463
+	return err
464
+}
465
+
466
+func (c *SCTPConn) GetDefaultSentParam() (*SndRcvInfo, error) {
467
+	info := &SndRcvInfo{}
468
+	optlen := unsafe.Sizeof(*info)
469
+	_, _, err := getsockopt(c.fd(), SCTP_DEFAULT_SENT_PARAM, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(&optlen)))
470
+	return info, err
471
+}
472
+
473
+func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) {
474
+	addr := &SCTPAddr{
475
+		IP: make([]net.IP, n),
476
+	}
477
+
478
+	switch family := (*(*syscall.RawSockaddrAny)(ptr)).Addr.Family; family {
479
+	case syscall.AF_INET:
480
+		addr.Port = int(ntohs(uint16((*(*syscall.RawSockaddrInet4)(ptr)).Port)))
481
+		tmp := syscall.RawSockaddrInet4{}
482
+		size := unsafe.Sizeof(tmp)
483
+		for i := 0; i < n; i++ {
484
+			a := *(*syscall.RawSockaddrInet4)(unsafe.Pointer(
485
+				uintptr(ptr) + size*uintptr(i)))
486
+			addr.IP[i] = a.Addr[:]
487
+		}
488
+	case syscall.AF_INET6:
489
+		addr.Port = int(ntohs(uint16((*(*syscall.RawSockaddrInet4)(ptr)).Port)))
490
+		tmp := syscall.RawSockaddrInet6{}
491
+		size := unsafe.Sizeof(tmp)
492
+		for i := 0; i < n; i++ {
493
+			a := *(*syscall.RawSockaddrInet6)(unsafe.Pointer(
494
+				uintptr(ptr) + size*uintptr(i)))
495
+			addr.IP[i] = a.Addr[:]
496
+		}
497
+	default:
498
+		return nil, fmt.Errorf("unknown address family: %d", family)
499
+	}
500
+	return addr, nil
501
+}
502
+
503
+func sctpGetAddrs(fd, id, optname int) (*SCTPAddr, error) {
504
+
505
+	type getaddrs struct {
506
+		assocId int32
507
+		addrNum uint32
508
+		addrs   [4096]byte
509
+	}
510
+	param := getaddrs{
511
+		assocId: int32(id),
512
+	}
513
+	optlen := unsafe.Sizeof(param)
514
+	_, _, err := getsockopt(fd, uintptr(optname), uintptr(unsafe.Pointer(&param)), uintptr(unsafe.Pointer(&optlen)))
515
+	if err != nil {
516
+		return nil, err
517
+	}
518
+	return resolveFromRawAddr(unsafe.Pointer(&param.addrs), int(param.addrNum))
519
+}
520
+
521
+func (c *SCTPConn) SCTPGetPrimaryPeerAddr() (*SCTPAddr, error) {
522
+
523
+	type sctpGetSetPrim struct {
524
+		assocId int32
525
+		addrs   [128]byte
526
+	}
527
+	param := sctpGetSetPrim{
528
+		assocId: int32(0),
529
+	}
530
+	optlen := unsafe.Sizeof(param)
531
+	_, _, err := getsockopt(c.fd(), SCTP_PRIMARY_ADDR, uintptr(unsafe.Pointer(&param)), uintptr(unsafe.Pointer(&optlen)))
532
+	if err != nil {
533
+		return nil, err
534
+	}
535
+	return resolveFromRawAddr(unsafe.Pointer(&param.addrs), 1)
536
+}
537
+
538
+func (c *SCTPConn) SCTPLocalAddr(id int) (*SCTPAddr, error) {
539
+	return sctpGetAddrs(c.fd(), id, SCTP_GET_LOCAL_ADDRS)
540
+}
541
+
542
+func (c *SCTPConn) SCTPRemoteAddr(id int) (*SCTPAddr, error) {
543
+	return sctpGetAddrs(c.fd(), id, SCTP_GET_PEER_ADDRS)
544
+}
545
+
546
+func (c *SCTPConn) LocalAddr() net.Addr {
547
+	addr, err := sctpGetAddrs(c.fd(), 0, SCTP_GET_LOCAL_ADDRS)
548
+	if err != nil {
549
+		return nil
550
+	}
551
+	return addr
552
+}
553
+
554
+func (c *SCTPConn) RemoteAddr() net.Addr {
555
+	addr, err := sctpGetAddrs(c.fd(), 0, SCTP_GET_PEER_ADDRS)
556
+	if err != nil {
557
+		return nil
558
+	}
559
+	return addr
560
+}
561
+
562
+func (c *SCTPConn) PeelOff(id int) (*SCTPConn, error) {
563
+	type peeloffArg struct {
564
+		assocId int32
565
+		sd      int
566
+	}
567
+	param := peeloffArg{
568
+		assocId: int32(id),
569
+	}
570
+	optlen := unsafe.Sizeof(param)
571
+	_, _, err := getsockopt(c.fd(), SCTP_SOCKOPT_PEELOFF, uintptr(unsafe.Pointer(&param)), uintptr(unsafe.Pointer(&optlen)))
572
+	if err != nil {
573
+		return nil, err
574
+	}
575
+	return &SCTPConn{_fd: int32(param.sd)}, nil
576
+}
577
+
578
+func (c *SCTPConn) SetDeadline(t time.Time) error {
579
+	return syscall.EOPNOTSUPP
580
+}
581
+
582
+func (c *SCTPConn) SetReadDeadline(t time.Time) error {
583
+	return syscall.EOPNOTSUPP
584
+}
585
+
586
+func (c *SCTPConn) SetWriteDeadline(t time.Time) error {
587
+	return syscall.EOPNOTSUPP
588
+}
589
+
590
+type SCTPListener struct {
591
+	fd int
592
+	m  sync.Mutex
593
+}
594
+
595
+func (ln *SCTPListener) Addr() net.Addr {
596
+	laddr, err := sctpGetAddrs(ln.fd, 0, SCTP_GET_LOCAL_ADDRS)
597
+	if err != nil {
598
+		return nil
599
+	}
600
+	return laddr
601
+}
602
+
603
+type SCTPSndRcvInfoWrappedConn struct {
604
+	conn *SCTPConn
605
+}
606
+
607
+func NewSCTPSndRcvInfoWrappedConn(conn *SCTPConn) *SCTPSndRcvInfoWrappedConn {
608
+	conn.SubscribeEvents(SCTP_EVENT_DATA_IO)
609
+	return &SCTPSndRcvInfoWrappedConn{conn}
610
+}
611
+
612
+func (c *SCTPSndRcvInfoWrappedConn) Write(b []byte) (int, error) {
613
+	if len(b) < int(sndRcvInfoSize) {
614
+		return 0, syscall.EINVAL
615
+	}
616
+	info := (*SndRcvInfo)(unsafe.Pointer(&b[0]))
617
+	n, err := c.conn.SCTPWrite(b[sndRcvInfoSize:], info)
618
+	return n + int(sndRcvInfoSize), err
619
+}
620
+
621
+func (c *SCTPSndRcvInfoWrappedConn) Read(b []byte) (int, error) {
622
+	if len(b) < int(sndRcvInfoSize) {
623
+		return 0, syscall.EINVAL
624
+	}
625
+	n, info, err := c.conn.SCTPRead(b[sndRcvInfoSize:])
626
+	if err != nil {
627
+		return n, err
628
+	}
629
+	copy(b, toBuf(info))
630
+	return n + int(sndRcvInfoSize), err
631
+}
632
+
633
+func (c *SCTPSndRcvInfoWrappedConn) Close() error {
634
+	return c.conn.Close()
635
+}
636
+
637
+func (c *SCTPSndRcvInfoWrappedConn) LocalAddr() net.Addr {
638
+	return c.conn.LocalAddr()
639
+}
640
+
641
+func (c *SCTPSndRcvInfoWrappedConn) RemoteAddr() net.Addr {
642
+	return c.conn.RemoteAddr()
643
+}
644
+
645
+func (c *SCTPSndRcvInfoWrappedConn) SetDeadline(t time.Time) error {
646
+	return c.conn.SetDeadline(t)
647
+}
648
+
649
+func (c *SCTPSndRcvInfoWrappedConn) SetReadDeadline(t time.Time) error {
650
+	return c.conn.SetReadDeadline(t)
651
+}
652
+
653
+func (c *SCTPSndRcvInfoWrappedConn) SetWriteDeadline(t time.Time) error {
654
+	return c.conn.SetWriteDeadline(t)
655
+}
0 656
new file mode 100644
... ...
@@ -0,0 +1,227 @@
0
+// +build linux,!386
1
+
2
+package sctp
3
+
4
+import (
5
+	"fmt"
6
+	"io"
7
+	"net"
8
+	"sync/atomic"
9
+	"syscall"
10
+	"unsafe"
11
+)
12
+
13
+func setsockopt(fd int, optname, optval, optlen uintptr) (uintptr, uintptr, error) {
14
+	// FIXME: syscall.SYS_SETSOCKOPT is undefined on 386
15
+	r0, r1, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT,
16
+		uintptr(fd),
17
+		SOL_SCTP,
18
+		optname,
19
+		optval,
20
+		optlen,
21
+		0)
22
+	if errno != 0 {
23
+		return r0, r1, errno
24
+	}
25
+	return r0, r1, nil
26
+}
27
+
28
+func getsockopt(fd int, optname, optval, optlen uintptr) (uintptr, uintptr, error) {
29
+	// FIXME: syscall.SYS_GETSOCKOPT is undefined on 386
30
+	r0, r1, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT,
31
+		uintptr(fd),
32
+		SOL_SCTP,
33
+		optname,
34
+		optval,
35
+		optlen,
36
+		0)
37
+	if errno != 0 {
38
+		return r0, r1, errno
39
+	}
40
+	return r0, r1, nil
41
+}
42
+
43
+func (c *SCTPConn) SCTPWrite(b []byte, info *SndRcvInfo) (int, error) {
44
+	var cbuf []byte
45
+	if info != nil {
46
+		cmsgBuf := toBuf(info)
47
+		hdr := &syscall.Cmsghdr{
48
+			Level: syscall.IPPROTO_SCTP,
49
+			Type:  SCTP_CMSG_SNDRCV,
50
+		}
51
+
52
+		// bitwidth of hdr.Len is platform-specific,
53
+		// so we use hdr.SetLen() rather than directly setting hdr.Len
54
+		hdr.SetLen(syscall.CmsgSpace(len(cmsgBuf)))
55
+		cbuf = append(toBuf(hdr), cmsgBuf...)
56
+	}
57
+	return syscall.SendmsgN(c.fd(), b, cbuf, nil, 0)
58
+}
59
+
60
+func parseSndRcvInfo(b []byte) (*SndRcvInfo, error) {
61
+	msgs, err := syscall.ParseSocketControlMessage(b)
62
+	if err != nil {
63
+		return nil, err
64
+	}
65
+	for _, m := range msgs {
66
+		if m.Header.Level == syscall.IPPROTO_SCTP {
67
+			switch m.Header.Type {
68
+			case SCTP_CMSG_SNDRCV:
69
+				return (*SndRcvInfo)(unsafe.Pointer(&m.Data[0])), nil
70
+			}
71
+		}
72
+	}
73
+	return nil, nil
74
+}
75
+
76
+func (c *SCTPConn) SCTPRead(b []byte) (int, *SndRcvInfo, error) {
77
+	oob := make([]byte, 254)
78
+	for {
79
+		n, oobn, recvflags, _, err := syscall.Recvmsg(c.fd(), b, oob, 0)
80
+		if err != nil {
81
+			return n, nil, err
82
+		}
83
+
84
+		if n == 0 && oobn == 0 {
85
+			return 0, nil, io.EOF
86
+		}
87
+
88
+		if recvflags&MSG_NOTIFICATION > 0 && c.notificationHandler != nil {
89
+			if err := c.notificationHandler(b[:n]); err != nil {
90
+				return 0, nil, err
91
+			}
92
+		} else {
93
+			var info *SndRcvInfo
94
+			if oobn > 0 {
95
+				info, err = parseSndRcvInfo(oob[:oobn])
96
+			}
97
+			return n, info, err
98
+		}
99
+	}
100
+}
101
+
102
+func (c *SCTPConn) Close() error {
103
+	if c != nil {
104
+		fd := atomic.SwapInt32(&c._fd, -1)
105
+		if fd > 0 {
106
+			info := &SndRcvInfo{
107
+				Flags: SCTP_EOF,
108
+			}
109
+			c.SCTPWrite(nil, info)
110
+			syscall.Shutdown(int(fd), syscall.SHUT_RDWR)
111
+			return syscall.Close(int(fd))
112
+		}
113
+	}
114
+	return syscall.EBADF
115
+}
116
+
117
+func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) {
118
+	af := syscall.AF_INET
119
+	switch net {
120
+	case "sctp":
121
+		hasv6 := func(addr *SCTPAddr) bool {
122
+			if addr == nil {
123
+				return false
124
+			}
125
+			for _, ip := range addr.IP {
126
+				if ip.To4() == nil {
127
+					return true
128
+				}
129
+			}
130
+			return false
131
+		}
132
+		if hasv6(laddr) {
133
+			af = syscall.AF_INET6
134
+		}
135
+	case "sctp4":
136
+	case "sctp6":
137
+		af = syscall.AF_INET6
138
+	default:
139
+		return nil, fmt.Errorf("invalid net: %s", net)
140
+	}
141
+
142
+	sock, err := syscall.Socket(
143
+		af,
144
+		syscall.SOCK_STREAM,
145
+		syscall.IPPROTO_SCTP,
146
+	)
147
+	if err != nil {
148
+		return nil, err
149
+	}
150
+	err = setNumOstreams(sock, SCTP_MAX_STREAM)
151
+	if err != nil {
152
+		return nil, err
153
+	}
154
+	if laddr != nil && len(laddr.IP) != 0 {
155
+		err := SCTPBind(sock, laddr, SCTP_BINDX_ADD_ADDR)
156
+		if err != nil {
157
+			return nil, err
158
+		}
159
+	}
160
+	err = syscall.Listen(sock, syscall.SOMAXCONN)
161
+	if err != nil {
162
+		return nil, err
163
+	}
164
+	return &SCTPListener{
165
+		fd: sock,
166
+	}, nil
167
+}
168
+
169
+func (ln *SCTPListener) Accept() (net.Conn, error) {
170
+	fd, _, err := syscall.Accept4(ln.fd, 0)
171
+	return NewSCTPConn(fd, nil), err
172
+}
173
+
174
+func (ln *SCTPListener) Close() error {
175
+	syscall.Shutdown(ln.fd, syscall.SHUT_RDWR)
176
+	return syscall.Close(ln.fd)
177
+}
178
+
179
+func DialSCTP(net string, laddr, raddr *SCTPAddr) (*SCTPConn, error) {
180
+	af := syscall.AF_INET
181
+	switch net {
182
+	case "sctp":
183
+		hasv6 := func(addr *SCTPAddr) bool {
184
+			if addr == nil {
185
+				return false
186
+			}
187
+			for _, ip := range addr.IP {
188
+				if ip.To4() == nil {
189
+					return true
190
+				}
191
+			}
192
+			return false
193
+		}
194
+		if hasv6(laddr) || hasv6(raddr) {
195
+			af = syscall.AF_INET6
196
+		}
197
+	case "sctp4":
198
+	case "sctp6":
199
+		af = syscall.AF_INET6
200
+	default:
201
+		return nil, fmt.Errorf("invalid net: %s", net)
202
+	}
203
+	sock, err := syscall.Socket(
204
+		af,
205
+		syscall.SOCK_STREAM,
206
+		syscall.IPPROTO_SCTP,
207
+	)
208
+	if err != nil {
209
+		return nil, err
210
+	}
211
+	err = setNumOstreams(sock, SCTP_MAX_STREAM)
212
+	if err != nil {
213
+		return nil, err
214
+	}
215
+	if laddr != nil {
216
+		err := SCTPBind(sock, laddr, SCTP_BINDX_ADD_ADDR)
217
+		if err != nil {
218
+			return nil, err
219
+		}
220
+	}
221
+	_, err = SCTPConnect(sock, raddr)
222
+	if err != nil {
223
+		return nil, err
224
+	}
225
+	return NewSCTPConn(sock, nil), nil
226
+}
0 227
new file mode 100644
... ...
@@ -0,0 +1,47 @@
0
+// +build !linux linux,386
1
+
2
+package sctp
3
+
4
+import (
5
+	"errors"
6
+	"net"
7
+	"runtime"
8
+)
9
+
10
+var ErrUnsupported = errors.New("SCTP is unsupported on " + runtime.GOOS + "/" + runtime.GOARCH)
11
+
12
+func setsockopt(fd int, optname, optval, optlen uintptr) (uintptr, uintptr, error) {
13
+	return 0, 0, ErrUnsupported
14
+}
15
+
16
+func getsockopt(fd int, optname, optval, optlen uintptr) (uintptr, uintptr, error) {
17
+	return 0, 0, ErrUnsupported
18
+}
19
+
20
+func (c *SCTPConn) SCTPWrite(b []byte, info *SndRcvInfo) (int, error) {
21
+	return 0, ErrUnsupported
22
+}
23
+
24
+func (c *SCTPConn) SCTPRead(b []byte) (int, *SndRcvInfo, error) {
25
+	return 0, nil, ErrUnsupported
26
+}
27
+
28
+func (c *SCTPConn) Close() error {
29
+	return ErrUnsupported
30
+}
31
+
32
+func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) {
33
+	return nil, ErrUnsupported
34
+}
35
+
36
+func (ln *SCTPListener) Accept() (net.Conn, error) {
37
+	return nil, ErrUnsupported
38
+}
39
+
40
+func (ln *SCTPListener) Close() error {
41
+	return ErrUnsupported
42
+}
43
+
44
+func DialSCTP(net string, laddr, raddr *SCTPAddr) (*SCTPConn, error) {
45
+	return nil, ErrUnsupported
46
+}