feat: support SCTP & UDP as endpoint type (#352)
* feat: support SCTP & UDP as endpoint type * update README * modify endpoint type test for sctp & udp
This commit is contained in:
		
							
								
								
									
										35
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								README.md
									
									
									
									
									
								
							| @ -74,6 +74,8 @@ Like this project? Please consider [sponsoring me](https://github.com/sponsors/T | ||||
|   - [Recommended interval](#recommended-interval) | ||||
|   - [Default timeouts](#default-timeouts) | ||||
|   - [Monitoring a TCP endpoint](#monitoring-a-tcp-endpoint) | ||||
|   - [Monitoring a UDP endpoint](#monitoring-a-udp-endpoint) | ||||
|   - [Monitoring a SCTP endpoint](#monitoring-a-sctp-endpoint) | ||||
|   - [Monitoring an endpoint using ICMP](#monitoring-an-endpoint-using-icmp) | ||||
|   - [Monitoring an endpoint using DNS queries](#monitoring-an-endpoint-using-dns-queries) | ||||
|   - [Monitoring an endpoint using STARTTLS](#monitoring-an-endpoint-using-starttls) | ||||
| @ -1328,6 +1330,39 @@ This works for applications such as databases (Postgres, MySQL, etc.) and caches | ||||
| something at the given address listening to the given port, and that a connection to that address was successfully | ||||
| established. | ||||
|  | ||||
| ### Monitoring a UDP endpoint | ||||
| By prefixing `endpoints[].url` with `udp:\\`, you can monitor UDP endpoints at a very basic level: | ||||
|  | ||||
| ```yaml | ||||
| endpoints: | ||||
|   - name: iper server | ||||
|     url: "udp://127.0.0.1:12345" | ||||
|     interval: 30s | ||||
|     conditions: | ||||
|       - "[CONNECTED] == true" | ||||
| ``` | ||||
|  | ||||
| Placeholders `[STATUS]` and `[BODY]` as well as the fields `endpoints[].body`, `endpoints[].headers`, | ||||
| `endpoints[].method` and `endpoints[].graphql` are not supported for UDP endpoints. | ||||
|  | ||||
| This works for UDP based application. | ||||
|  | ||||
| ### Monitoring a SCTP endpoint | ||||
| By prefixing `endpoints[].url` with `sctp:\\`, you can monitor TCP endpoints at a very basic level: | ||||
|  | ||||
| ```yaml | ||||
| endpoints: | ||||
|   - name: amf | ||||
|     url: "sctp://127.0.0.1:38412" | ||||
|     interval: 30s | ||||
|     conditions: | ||||
|       - "[CONNECTED] == true" | ||||
| ``` | ||||
|  | ||||
| Placeholders `[STATUS]` and `[BODY]` as well as the fields `endpoints[].body`, `endpoints[].headers`, | ||||
| `endpoints[].method` and `endpoints[].graphql` are not supported for SCTP endpoints. | ||||
|  | ||||
| This works for SCTP based application. | ||||
|  | ||||
| ### Monitoring an endpoint using ICMP | ||||
| By prefixing `endpoints[].url` with `icmp:\\`, you can monitor endpoints at a very basic level using ICMP, or more | ||||
|  | ||||
| @ -12,6 +12,7 @@ import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/go-ping/ping" | ||||
| 	"github.com/ishidawataru/sctp" | ||||
| ) | ||||
|  | ||||
| // injectedHTTPClient is used for testing purposes | ||||
| @ -38,6 +39,41 @@ func CanCreateTCPConnection(address string, config *Config) bool { | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // CanCreateUDPConnection checks whether a connection can be established with a UDP endpoint | ||||
| func CanCreateUDPConnection(address string, config *Config) bool { | ||||
| 	conn, err := net.DialTimeout("udp", address, config.Timeout) | ||||
| 	if err != nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	_ = conn.Close() | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| // CanCreateSCTPConnection checks whether a connection can be established with a SCTP endpoint | ||||
| func CanCreateSCTPConnection(address string, config *Config) bool { | ||||
| 	ch := make(chan bool) | ||||
| 	go (func(res chan bool) { | ||||
| 		addr, err := sctp.ResolveSCTPAddr("sctp", address) | ||||
| 		if err != nil { | ||||
| 			res <- false | ||||
| 		} | ||||
|  | ||||
| 		conn, err := sctp.DialSCTP("sctp", nil, addr) | ||||
| 		if err != nil { | ||||
| 			res <- false | ||||
| 		} | ||||
| 		_ = conn.Close() | ||||
| 		res <- true | ||||
| 	})(ch) | ||||
|  | ||||
| 	select { | ||||
| 	case result := <-ch: | ||||
| 		return result | ||||
| 	case <-time.After(config.Timeout): | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // CanPerformStartTLS checks whether a connection can be established to an address using the STARTTLS protocol | ||||
| func CanPerformStartTLS(address string, config *Config) (connected bool, certificate *x509.Certificate, err error) { | ||||
| 	hostAndPort := strings.Split(address, ":") | ||||
|  | ||||
| @ -36,6 +36,8 @@ const ( | ||||
|  | ||||
| 	EndpointTypeDNS      EndpointType = "DNS" | ||||
| 	EndpointTypeTCP      EndpointType = "TCP" | ||||
| 	EndpointTypeSCTP     EndpointType = "SCTP" | ||||
| 	EndpointTypeUDP      EndpointType = "UDP" | ||||
| 	EndpointTypeICMP     EndpointType = "ICMP" | ||||
| 	EndpointTypeSTARTTLS EndpointType = "STARTTLS" | ||||
| 	EndpointTypeTLS      EndpointType = "TLS" | ||||
| @ -132,6 +134,10 @@ func (endpoint Endpoint) Type() EndpointType { | ||||
| 		return EndpointTypeDNS | ||||
| 	case strings.HasPrefix(endpoint.URL, "tcp://"): | ||||
| 		return EndpointTypeTCP | ||||
| 	case strings.HasPrefix(endpoint.URL, "sctp://"): | ||||
| 		return EndpointTypeSCTP | ||||
| 	case strings.HasPrefix(endpoint.URL, "udp://"): | ||||
| 		return EndpointTypeUDP | ||||
| 	case strings.HasPrefix(endpoint.URL, "icmp://"): | ||||
| 		return EndpointTypeICMP | ||||
| 	case strings.HasPrefix(endpoint.URL, "starttls://"): | ||||
| @ -329,6 +335,12 @@ func (endpoint *Endpoint) call(result *Result) { | ||||
| 	} else if endpointType == EndpointTypeTCP { | ||||
| 		result.Connected = client.CanCreateTCPConnection(strings.TrimPrefix(endpoint.URL, "tcp://"), endpoint.ClientConfig) | ||||
| 		result.Duration = time.Since(startTime) | ||||
| 	} else if endpointType == EndpointTypeUDP { | ||||
| 		result.Connected = client.CanCreateUDPConnection(strings.TrimPrefix(endpoint.URL, "udp://"), endpoint.ClientConfig) | ||||
| 		result.Duration = time.Since(startTime) | ||||
| 	} else if endpointType == EndpointTypeSCTP { | ||||
| 		result.Connected = client.CanCreateSCTPConnection(strings.TrimPrefix(endpoint.URL, "sctp://"), endpoint.ClientConfig) | ||||
| 		result.Duration = time.Since(startTime) | ||||
| 	} else if endpointType == EndpointTypeICMP { | ||||
| 		result.Connected, result.Duration = client.Ping(strings.TrimPrefix(endpoint.URL, "icmp://"), endpoint.ClientConfig) | ||||
| 	} else { | ||||
|  | ||||
| @ -283,6 +283,18 @@ func TestEndpoint_Type(t *testing.T) { | ||||
| 			}, | ||||
| 			want: EndpointTypeICMP, | ||||
| 		}, | ||||
| 		{ | ||||
| 			args: args{ | ||||
| 				URL: "sctp://example.com", | ||||
| 			}, | ||||
| 			want: EndpointTypeSCTP, | ||||
| 		}, | ||||
| 		{ | ||||
| 			args: args{ | ||||
| 				URL: "udp://example.com", | ||||
| 			}, | ||||
| 			want: EndpointTypeUDP, | ||||
| 		}, | ||||
| 		{ | ||||
| 			args: args{ | ||||
| 				URL: "starttls://smtp.gmail.com:587", | ||||
|  | ||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @ -28,6 +28,7 @@ require ( | ||||
| 	github.com/davecgh/go-spew v1.1.1 // indirect | ||||
| 	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect | ||||
| 	github.com/golang/protobuf v1.5.2 // indirect | ||||
| 	github.com/ishidawataru/sctp v0.0.0-20210707070123-9a39160e9062 | ||||
| 	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect | ||||
| 	github.com/mattn/go-isatty v0.0.14 // indirect | ||||
| 	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect | ||||
|  | ||||
							
								
								
									
										5
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										5
									
								
								go.sum
									
									
									
									
									
								
							| @ -149,6 +149,8 @@ github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB7 | ||||
| github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | ||||
| github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= | ||||
| github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= | ||||
| github.com/ishidawataru/sctp v0.0.0-20210707070123-9a39160e9062 h1:G1+wBT0dwjIrBdLy0MIG0i+E4CQxEnedHXdauJEIH6g= | ||||
| github.com/ishidawataru/sctp v0.0.0-20210707070123-9a39160e9062/go.mod h1:co9pwDoBCm1kGxawmb4sPq0cSIOOWNPT4KnHotMP1Zg= | ||||
| github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= | ||||
| github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= | ||||
| github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= | ||||
| @ -236,6 +238,7 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de | ||||
| github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= | ||||
| go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= | ||||
| go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= | ||||
| go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= | ||||
| @ -281,6 +284,7 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB | ||||
| golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= | ||||
| golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||||
| golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||||
| golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||||
| golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= | ||||
| golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= | ||||
| golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||||
| @ -382,6 +386,7 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w | ||||
| golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
|  | ||||
							
								
								
									
										16
									
								
								vendor/github.com/ishidawataru/sctp/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/ishidawataru/sctp/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| # Binaries for programs and plugins | ||||
| *.exe | ||||
| *.dll | ||||
| *.so | ||||
| *.dylib | ||||
|  | ||||
| # Test binary, build with `go test -c` | ||||
| *.test | ||||
|  | ||||
| # Output of the go coverage tool, specifically when used with LiteIDE | ||||
| *.out | ||||
|  | ||||
| # Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 | ||||
| .glide/ | ||||
|  | ||||
| example/example | ||||
							
								
								
									
										29
									
								
								vendor/github.com/ishidawataru/sctp/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								vendor/github.com/ishidawataru/sctp/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | ||||
| language: go | ||||
| arch: | ||||
|     - amd64 | ||||
|     - ppc64le | ||||
| go: | ||||
|  - 1.9.x | ||||
|  - 1.10.x | ||||
|  - 1.11.x | ||||
|  - 1.12.x | ||||
|  - 1.13.x | ||||
| # allowing test cases to fail  for the versions were not suppotred by ppc64le  | ||||
| matrix: | ||||
|   allow_failures: | ||||
|                 - go: 1.9.x | ||||
|                 - go: 1.10.x | ||||
|                 - go: 1.13.x | ||||
|  | ||||
|  | ||||
| script: | ||||
|  - go test -v -race ./... | ||||
|  - GOOS=linux   GOARCH=amd64   go build . | ||||
|  - GOOS=linux   GOARCH=arm     go build . | ||||
|  - GOOS=linux   GOARCH=arm64   go build . | ||||
|  - GOOS=linux   GOARCH=ppc64le go build . | ||||
|  - GOOS=linux   GOARCH=mips64le go build . | ||||
|  - (go version | grep go1.6 > /dev/null) || GOOS=linux   GOARCH=s390x   go build . | ||||
| # can be compiled but not functional: | ||||
|  - GOOS=linux   GOARCH=386     go build . | ||||
|  - GOOS=windows GOARCH=amd64   go build . | ||||
							
								
								
									
										27
									
								
								vendor/github.com/ishidawataru/sctp/GO_LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/github.com/ishidawataru/sctp/GO_LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | ||||
| Copyright (c) 2009 The Go Authors. All rights reserved. | ||||
|  | ||||
| Redistribution and use in source and binary forms, with or without | ||||
| modification, are permitted provided that the following conditions are | ||||
| met: | ||||
|  | ||||
|    * Redistributions of source code must retain the above copyright | ||||
| notice, this list of conditions and the following disclaimer. | ||||
|    * Redistributions in binary form must reproduce the above | ||||
| copyright notice, this list of conditions and the following disclaimer | ||||
| in the documentation and/or other materials provided with the | ||||
| distribution. | ||||
|    * Neither the name of Google Inc. nor the names of its | ||||
| contributors may be used to endorse or promote products derived from | ||||
| this software without specific prior written permission. | ||||
|  | ||||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||
							
								
								
									
										201
									
								
								vendor/github.com/ishidawataru/sctp/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										201
									
								
								vendor/github.com/ishidawataru/sctp/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,201 @@ | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
|  | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
|  | ||||
|    1. Definitions. | ||||
|  | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
|  | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
|  | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
|  | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
|  | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
|  | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
|  | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
|  | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
|  | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
|  | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
|  | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
|  | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
|  | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
|  | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
|  | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
|  | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
|  | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
|  | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
|  | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
|  | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
|  | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
|  | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
|  | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
|  | ||||
|    END OF TERMS AND CONDITIONS | ||||
|  | ||||
|    APPENDIX: How to apply the Apache License to your work. | ||||
|  | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "{}" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
|  | ||||
|    Copyright {yyyy} {name of copyright owner} | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
							
								
								
									
										3
									
								
								vendor/github.com/ishidawataru/sctp/NOTICE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/ishidawataru/sctp/NOTICE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| This source code includes following third party code | ||||
|  | ||||
| - ipsock_linux.go : licensed by the Go authors, see GO_LICENSE file for the license which applies to the code | ||||
							
								
								
									
										18
									
								
								vendor/github.com/ishidawataru/sctp/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								vendor/github.com/ishidawataru/sctp/README.md
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| Stream Control Transmission Protocol (SCTP) | ||||
| ---- | ||||
|  | ||||
| [](https://travis-ci.org/ishidawataru/sctp/builds) | ||||
|  | ||||
| Examples | ||||
| ---- | ||||
|  | ||||
| See `example/sctp.go` | ||||
|  | ||||
| ```go | ||||
| $ cd example | ||||
| $ go build | ||||
| $ # run example SCTP server | ||||
| $ ./example -server -port 1000 -ip 10.10.0.1,10.20.0.1 | ||||
| $ # run example SCTP client | ||||
| $ ./example -port 1000 -ip 10.10.0.1,10.20.0.1 | ||||
| ``` | ||||
							
								
								
									
										222
									
								
								vendor/github.com/ishidawataru/sctp/ipsock_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								vendor/github.com/ishidawataru/sctp/ipsock_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,222 @@ | ||||
| // Copyright 2009 The Go Authors. All rights reserved. | ||||
| // Use of this source code is governed by a BSD-style | ||||
| // license that can be found in the GO_LICENSE file. | ||||
|  | ||||
| package sctp | ||||
|  | ||||
| import ( | ||||
| 	"net" | ||||
| 	"os" | ||||
| 	"sync" | ||||
| 	"syscall" | ||||
| ) | ||||
|  | ||||
| //from https://github.com/golang/go | ||||
| // Boolean to int. | ||||
| func boolint(b bool) int { | ||||
| 	if b { | ||||
| 		return 1 | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
|  | ||||
| //from https://github.com/golang/go | ||||
| func ipToSockaddr(family int, ip net.IP, port int, zone string) (syscall.Sockaddr, error) { | ||||
| 	switch family { | ||||
| 	case syscall.AF_INET: | ||||
| 		if len(ip) == 0 { | ||||
| 			ip = net.IPv4zero | ||||
| 		} | ||||
| 		ip4 := ip.To4() | ||||
| 		if ip4 == nil { | ||||
| 			return nil, &net.AddrError{Err: "non-IPv4 address", Addr: ip.String()} | ||||
| 		} | ||||
| 		sa := &syscall.SockaddrInet4{Port: port} | ||||
| 		copy(sa.Addr[:], ip4) | ||||
| 		return sa, nil | ||||
| 	case syscall.AF_INET6: | ||||
| 		// In general, an IP wildcard address, which is either | ||||
| 		// "0.0.0.0" or "::", means the entire IP addressing | ||||
| 		// space. For some historical reason, it is used to | ||||
| 		// specify "any available address" on some operations | ||||
| 		// of IP node. | ||||
| 		// | ||||
| 		// When the IP node supports IPv4-mapped IPv6 address, | ||||
| 		// we allow an listener to listen to the wildcard | ||||
| 		// address of both IP addressing spaces by specifying | ||||
| 		// IPv6 wildcard address. | ||||
| 		if len(ip) == 0 || ip.Equal(net.IPv4zero) { | ||||
| 			ip = net.IPv6zero | ||||
| 		} | ||||
| 		// We accept any IPv6 address including IPv4-mapped | ||||
| 		// IPv6 address. | ||||
| 		ip6 := ip.To16() | ||||
| 		if ip6 == nil { | ||||
| 			return nil, &net.AddrError{Err: "non-IPv6 address", Addr: ip.String()} | ||||
| 		} | ||||
| 		//we set ZoneId to 0, as currently we use this functon only to probe the IP capabilities of the host | ||||
| 		//if real Zone handling is required, the zone cache implementation in golang/net should be pulled here | ||||
| 		sa := &syscall.SockaddrInet6{Port: port, ZoneId: 0} | ||||
| 		copy(sa.Addr[:], ip6) | ||||
| 		return sa, nil | ||||
| 	} | ||||
| 	return nil, &net.AddrError{Err: "invalid address family", Addr: ip.String()} | ||||
| } | ||||
|  | ||||
| //from https://github.com/golang/go | ||||
| func sockaddr(a *net.TCPAddr, family int) (syscall.Sockaddr, error) { | ||||
| 	if a == nil { | ||||
| 		return nil, nil | ||||
| 	} | ||||
| 	return ipToSockaddr(family, a.IP, a.Port, a.Zone) | ||||
| } | ||||
|  | ||||
| //from https://github.com/golang/go | ||||
| type ipStackCapabilities struct { | ||||
| 	sync.Once             // guards following | ||||
| 	ipv4Enabled           bool | ||||
| 	ipv6Enabled           bool | ||||
| 	ipv4MappedIPv6Enabled bool | ||||
| } | ||||
|  | ||||
| //from https://github.com/golang/go | ||||
| var ipStackCaps ipStackCapabilities | ||||
|  | ||||
| //from https://github.com/golang/go | ||||
| // supportsIPv4 reports whether the platform supports IPv4 networking | ||||
| // functionality. | ||||
| func supportsIPv4() bool { | ||||
| 	ipStackCaps.Once.Do(ipStackCaps.probe) | ||||
| 	return ipStackCaps.ipv4Enabled | ||||
| } | ||||
|  | ||||
| //from https://github.com/golang/go | ||||
| // supportsIPv6 reports whether the platform supports IPv6 networking | ||||
| // functionality. | ||||
| func supportsIPv6() bool { | ||||
| 	ipStackCaps.Once.Do(ipStackCaps.probe) | ||||
| 	return ipStackCaps.ipv6Enabled | ||||
| } | ||||
|  | ||||
| //from https://github.com/golang/go | ||||
| // supportsIPv4map reports whether the platform supports mapping an | ||||
| // IPv4 address inside an IPv6 address at transport layer | ||||
| // protocols. See RFC 4291, RFC 4038 and RFC 3493. | ||||
| func supportsIPv4map() bool { | ||||
| 	ipStackCaps.Once.Do(ipStackCaps.probe) | ||||
| 	return ipStackCaps.ipv4MappedIPv6Enabled | ||||
| } | ||||
|  | ||||
| //from https://github.com/golang/go | ||||
| // Probe probes IPv4, IPv6 and IPv4-mapped IPv6 communication | ||||
| // capabilities which are controlled by the IPV6_V6ONLY socket option | ||||
| // and kernel configuration. | ||||
| // | ||||
| // Should we try to use the IPv4 socket interface if we're only | ||||
| // dealing with IPv4 sockets? As long as the host system understands | ||||
| // IPv4-mapped IPv6, it's okay to pass IPv4-mapeed IPv6 addresses to | ||||
| // the IPv6 interface. That simplifies our code and is most | ||||
| // general. Unfortunately, we need to run on kernels built without | ||||
| // IPv6 support too. So probe the kernel to figure it out. | ||||
| func (p *ipStackCapabilities) probe() { | ||||
| 	s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) | ||||
| 	switch err { | ||||
| 	case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT: | ||||
| 	case nil: | ||||
| 		syscall.Close(s) | ||||
| 		p.ipv4Enabled = true | ||||
| 	} | ||||
| 	var probes = []struct { | ||||
| 		laddr net.TCPAddr | ||||
| 		value int | ||||
| 	}{ | ||||
| 		// IPv6 communication capability | ||||
| 		{laddr: net.TCPAddr{IP: net.IPv6loopback}, value: 1}, | ||||
| 		// IPv4-mapped IPv6 address communication capability | ||||
| 		{laddr: net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)}, value: 0}, | ||||
| 	} | ||||
|  | ||||
| 	for i := range probes { | ||||
| 		s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		defer syscall.Close(s) | ||||
| 		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value) | ||||
| 		sa, err := sockaddr(&(probes[i].laddr), syscall.AF_INET6) | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		if err := syscall.Bind(s, sa); err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		if i == 0 { | ||||
| 			p.ipv6Enabled = true | ||||
| 		} else { | ||||
| 			p.ipv4MappedIPv6Enabled = true | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| //from https://github.com/golang/go | ||||
| //Change: we check the first IP address in the list of candidate SCTP IP addresses | ||||
| func (a *SCTPAddr) isWildcard() bool { | ||||
| 	if a == nil { | ||||
| 		return true | ||||
| 	} | ||||
| 	if 0 == len(a.IPAddrs) { | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| 	return a.IPAddrs[0].IP.IsUnspecified() | ||||
| } | ||||
|  | ||||
| func (a *SCTPAddr) family() int { | ||||
| 	if a != nil { | ||||
| 		for _, ip := range a.IPAddrs { | ||||
| 			if ip.IP.To4() == nil { | ||||
| 				return syscall.AF_INET6 | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return syscall.AF_INET | ||||
| } | ||||
|  | ||||
| //from https://github.com/golang/go | ||||
| func favoriteAddrFamily(network string, laddr *SCTPAddr, raddr *SCTPAddr, mode string) (family int, ipv6only bool) { | ||||
| 	switch network[len(network)-1] { | ||||
| 	case '4': | ||||
| 		return syscall.AF_INET, false | ||||
| 	case '6': | ||||
| 		return syscall.AF_INET6, true | ||||
| 	} | ||||
|  | ||||
| 	if mode == "listen" && (laddr == nil || laddr.isWildcard()) { | ||||
| 		if supportsIPv4map() || !supportsIPv4() { | ||||
| 			return syscall.AF_INET6, false | ||||
| 		} | ||||
| 		if laddr == nil { | ||||
| 			return syscall.AF_INET, false | ||||
| 		} | ||||
| 		return laddr.family(), false | ||||
| 	} | ||||
|  | ||||
| 	if (laddr == nil || laddr.family() == syscall.AF_INET) && | ||||
| 		(raddr == nil || raddr.family() == syscall.AF_INET) { | ||||
| 		return syscall.AF_INET, false | ||||
| 	} | ||||
| 	return syscall.AF_INET6, false | ||||
| } | ||||
|  | ||||
| //from https://github.com/golang/go | ||||
| //Changes: it is for SCTP only | ||||
| func setDefaultSockopts(s int, family int, ipv6only bool) error { | ||||
| 	if family == syscall.AF_INET6 { | ||||
| 		// Allow both IP versions even if the OS default | ||||
| 		// is otherwise. Note that some operating systems | ||||
| 		// never admit this option. | ||||
| 		syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only)) | ||||
| 	} | ||||
| 	// Allow broadcast. | ||||
| 	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)) | ||||
| } | ||||
							
								
								
									
										737
									
								
								vendor/github.com/ishidawataru/sctp/sctp.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										737
									
								
								vendor/github.com/ishidawataru/sctp/sctp.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,737 @@ | ||||
| // Copyright 2019 Wataru Ishida. All rights reserved. | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //    http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
| // implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package sctp | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/binary" | ||||
| 	"fmt" | ||||
| 	"net" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"sync/atomic" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	SOL_SCTP = 132 | ||||
|  | ||||
| 	SCTP_BINDX_ADD_ADDR = 0x01 | ||||
| 	SCTP_BINDX_REM_ADDR = 0x02 | ||||
|  | ||||
| 	MSG_NOTIFICATION = 0x8000 | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	SCTP_RTOINFO = iota | ||||
| 	SCTP_ASSOCINFO | ||||
| 	SCTP_INITMSG | ||||
| 	SCTP_NODELAY | ||||
| 	SCTP_AUTOCLOSE | ||||
| 	SCTP_SET_PEER_PRIMARY_ADDR | ||||
| 	SCTP_PRIMARY_ADDR | ||||
| 	SCTP_ADAPTATION_LAYER | ||||
| 	SCTP_DISABLE_FRAGMENTS | ||||
| 	SCTP_PEER_ADDR_PARAMS | ||||
| 	SCTP_DEFAULT_SENT_PARAM | ||||
| 	SCTP_EVENTS | ||||
| 	SCTP_I_WANT_MAPPED_V4_ADDR | ||||
| 	SCTP_MAXSEG | ||||
| 	SCTP_STATUS | ||||
| 	SCTP_GET_PEER_ADDR_INFO | ||||
| 	SCTP_DELAYED_ACK_TIME | ||||
| 	SCTP_DELAYED_ACK  = SCTP_DELAYED_ACK_TIME | ||||
| 	SCTP_DELAYED_SACK = SCTP_DELAYED_ACK_TIME | ||||
|  | ||||
| 	SCTP_SOCKOPT_BINDX_ADD = 100 | ||||
| 	SCTP_SOCKOPT_BINDX_REM = 101 | ||||
| 	SCTP_SOCKOPT_PEELOFF   = 102 | ||||
| 	SCTP_GET_PEER_ADDRS    = 108 | ||||
| 	SCTP_GET_LOCAL_ADDRS   = 109 | ||||
| 	SCTP_SOCKOPT_CONNECTX  = 110 | ||||
| 	SCTP_SOCKOPT_CONNECTX3 = 111 | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	SCTP_EVENT_DATA_IO = 1 << iota | ||||
| 	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 | ||||
|  | ||||
| 	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 | ||||
| ) | ||||
|  | ||||
| type SCTPNotificationType int | ||||
|  | ||||
| const ( | ||||
| 	SCTP_SN_TYPE_BASE = SCTPNotificationType(iota + (1 << 15)) | ||||
| 	SCTP_ASSOC_CHANGE | ||||
| 	SCTP_PEER_ADDR_CHANGE | ||||
| 	SCTP_SEND_FAILED | ||||
| 	SCTP_REMOTE_ERROR | ||||
| 	SCTP_SHUTDOWN_EVENT | ||||
| 	SCTP_PARTIAL_DELIVERY_EVENT | ||||
| 	SCTP_ADAPTATION_INDICATION | ||||
| 	SCTP_AUTHENTICATION_INDICATION | ||||
| 	SCTP_SENDER_DRY_EVENT | ||||
| ) | ||||
|  | ||||
| type NotificationHandler func([]byte) error | ||||
|  | ||||
| type EventSubscribe struct { | ||||
| 	DataIO          uint8 | ||||
| 	Association     uint8 | ||||
| 	Address         uint8 | ||||
| 	SendFailure     uint8 | ||||
| 	PeerError       uint8 | ||||
| 	Shutdown        uint8 | ||||
| 	PartialDelivery uint8 | ||||
| 	AdaptationLayer uint8 | ||||
| 	Authentication  uint8 | ||||
| 	SenderDry       uint8 | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	SCTP_CMSG_INIT = iota | ||||
| 	SCTP_CMSG_SNDRCV | ||||
| 	SCTP_CMSG_SNDINFO | ||||
| 	SCTP_CMSG_RCVINFO | ||||
| 	SCTP_CMSG_NXTINFO | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	SCTP_UNORDERED = 1 << iota | ||||
| 	SCTP_ADDR_OVER | ||||
| 	SCTP_ABORT | ||||
| 	SCTP_SACK_IMMEDIATELY | ||||
| 	SCTP_EOF | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	SCTP_MAX_STREAM = 0xffff | ||||
| ) | ||||
|  | ||||
| type InitMsg struct { | ||||
| 	NumOstreams    uint16 | ||||
| 	MaxInstreams   uint16 | ||||
| 	MaxAttempts    uint16 | ||||
| 	MaxInitTimeout uint16 | ||||
| } | ||||
|  | ||||
| type SndRcvInfo struct { | ||||
| 	Stream  uint16 | ||||
| 	SSN     uint16 | ||||
| 	Flags   uint16 | ||||
| 	_       uint16 | ||||
| 	PPID    uint32 | ||||
| 	Context uint32 | ||||
| 	TTL     uint32 | ||||
| 	TSN     uint32 | ||||
| 	CumTSN  uint32 | ||||
| 	AssocID int32 | ||||
| } | ||||
|  | ||||
| type SndInfo struct { | ||||
| 	SID     uint16 | ||||
| 	Flags   uint16 | ||||
| 	PPID    uint32 | ||||
| 	Context uint32 | ||||
| 	AssocID int32 | ||||
| } | ||||
|  | ||||
| type GetAddrsOld struct { | ||||
| 	AssocID int32 | ||||
| 	AddrNum int32 | ||||
| 	Addrs   uintptr | ||||
| } | ||||
|  | ||||
| type NotificationHeader struct { | ||||
| 	Type   uint16 | ||||
| 	Flags  uint16 | ||||
| 	Length uint32 | ||||
| } | ||||
|  | ||||
| type SCTPState uint16 | ||||
|  | ||||
| const ( | ||||
| 	SCTP_COMM_UP = SCTPState(iota) | ||||
| 	SCTP_COMM_LOST | ||||
| 	SCTP_RESTART | ||||
| 	SCTP_SHUTDOWN_COMP | ||||
| 	SCTP_CANT_STR_ASSOC | ||||
| ) | ||||
|  | ||||
| var nativeEndian binary.ByteOrder | ||||
| var sndRcvInfoSize uintptr | ||||
|  | ||||
| func init() { | ||||
| 	i := uint16(1) | ||||
| 	if *(*byte)(unsafe.Pointer(&i)) == 0 { | ||||
| 		nativeEndian = binary.BigEndian | ||||
| 	} else { | ||||
| 		nativeEndian = binary.LittleEndian | ||||
| 	} | ||||
| 	info := SndRcvInfo{} | ||||
| 	sndRcvInfoSize = unsafe.Sizeof(info) | ||||
| } | ||||
|  | ||||
| func toBuf(v interface{}) []byte { | ||||
| 	var buf bytes.Buffer | ||||
| 	binary.Write(&buf, nativeEndian, v) | ||||
| 	return buf.Bytes() | ||||
| } | ||||
|  | ||||
| func htons(h uint16) uint16 { | ||||
| 	if nativeEndian == binary.LittleEndian { | ||||
| 		return (h << 8 & 0xff00) | (h >> 8 & 0xff) | ||||
| 	} | ||||
| 	return h | ||||
| } | ||||
|  | ||||
| var ntohs = htons | ||||
|  | ||||
| // setInitOpts sets options for an SCTP association initialization | ||||
| // see https://tools.ietf.org/html/rfc4960#page-25 | ||||
| func setInitOpts(fd int, options InitMsg) error { | ||||
| 	optlen := unsafe.Sizeof(options) | ||||
| 	_, _, err := setsockopt(fd, SCTP_INITMSG, uintptr(unsafe.Pointer(&options)), uintptr(optlen)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func setNumOstreams(fd, num int) error { | ||||
| 	return setInitOpts(fd, InitMsg{NumOstreams: uint16(num)}) | ||||
| } | ||||
|  | ||||
| type SCTPAddr struct { | ||||
| 	IPAddrs []net.IPAddr | ||||
| 	Port    int | ||||
| } | ||||
|  | ||||
| func (a *SCTPAddr) ToRawSockAddrBuf() []byte { | ||||
| 	p := htons(uint16(a.Port)) | ||||
| 	if len(a.IPAddrs) == 0 { // if a.IPAddrs list is empty - fall back to IPv4 zero addr | ||||
| 		s := syscall.RawSockaddrInet4{ | ||||
| 			Family: syscall.AF_INET, | ||||
| 			Port:   p, | ||||
| 		} | ||||
| 		copy(s.Addr[:], net.IPv4zero) | ||||
| 		return toBuf(s) | ||||
| 	} | ||||
| 	buf := []byte{} | ||||
| 	for _, ip := range a.IPAddrs { | ||||
| 		ipBytes := ip.IP | ||||
| 		if len(ipBytes) == 0 { | ||||
| 			ipBytes = net.IPv4zero | ||||
| 		} | ||||
| 		if ip4 := ipBytes.To4(); ip4 != nil { | ||||
| 			s := syscall.RawSockaddrInet4{ | ||||
| 				Family: syscall.AF_INET, | ||||
| 				Port:   p, | ||||
| 			} | ||||
| 			copy(s.Addr[:], ip4) | ||||
| 			buf = append(buf, toBuf(s)...) | ||||
| 		} else { | ||||
| 			var scopeid uint32 | ||||
| 			ifi, err := net.InterfaceByName(ip.Zone) | ||||
| 			if err == nil { | ||||
| 				scopeid = uint32(ifi.Index) | ||||
| 			} | ||||
| 			s := syscall.RawSockaddrInet6{ | ||||
| 				Family:   syscall.AF_INET6, | ||||
| 				Port:     p, | ||||
| 				Scope_id: scopeid, | ||||
| 			} | ||||
| 			copy(s.Addr[:], ipBytes) | ||||
| 			buf = append(buf, toBuf(s)...) | ||||
| 		} | ||||
| 	} | ||||
| 	return buf | ||||
| } | ||||
|  | ||||
| func (a *SCTPAddr) String() string { | ||||
| 	var b bytes.Buffer | ||||
|  | ||||
| 	for n, i := range a.IPAddrs { | ||||
| 		if i.IP.To4() != nil { | ||||
| 			b.WriteString(i.String()) | ||||
| 		} else if i.IP.To16() != nil { | ||||
| 			b.WriteRune('[') | ||||
| 			b.WriteString(i.String()) | ||||
| 			b.WriteRune(']') | ||||
| 		} | ||||
| 		if n < len(a.IPAddrs)-1 { | ||||
| 			b.WriteRune('/') | ||||
| 		} | ||||
| 	} | ||||
| 	b.WriteRune(':') | ||||
| 	b.WriteString(strconv.Itoa(a.Port)) | ||||
| 	return b.String() | ||||
| } | ||||
|  | ||||
| func (a *SCTPAddr) Network() string { return "sctp" } | ||||
|  | ||||
| func ResolveSCTPAddr(network, addrs string) (*SCTPAddr, error) { | ||||
| 	tcpnet := "" | ||||
| 	switch network { | ||||
| 	case "", "sctp": | ||||
| 		tcpnet = "tcp" | ||||
| 	case "sctp4": | ||||
| 		tcpnet = "tcp4" | ||||
| 	case "sctp6": | ||||
| 		tcpnet = "tcp6" | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("invalid net: %s", network) | ||||
| 	} | ||||
| 	elems := strings.Split(addrs, "/") | ||||
| 	if len(elems) == 0 { | ||||
| 		return nil, fmt.Errorf("invalid input: %s", addrs) | ||||
| 	} | ||||
| 	ipaddrs := make([]net.IPAddr, 0, len(elems)) | ||||
| 	for _, e := range elems[:len(elems)-1] { | ||||
| 		tcpa, err := net.ResolveTCPAddr(tcpnet, e+":") | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		ipaddrs = append(ipaddrs, net.IPAddr{IP: tcpa.IP, Zone: tcpa.Zone}) | ||||
| 	} | ||||
| 	tcpa, err := net.ResolveTCPAddr(tcpnet, elems[len(elems)-1]) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if tcpa.IP != nil { | ||||
| 		ipaddrs = append(ipaddrs, net.IPAddr{IP: tcpa.IP, Zone: tcpa.Zone}) | ||||
| 	} else { | ||||
| 		ipaddrs = nil | ||||
| 	} | ||||
| 	return &SCTPAddr{ | ||||
| 		IPAddrs: ipaddrs, | ||||
| 		Port:    tcpa.Port, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func SCTPConnect(fd int, addr *SCTPAddr) (int, error) { | ||||
| 	buf := addr.ToRawSockAddrBuf() | ||||
| 	param := GetAddrsOld{ | ||||
| 		AddrNum: int32(len(buf)), | ||||
| 		Addrs:   uintptr(uintptr(unsafe.Pointer(&buf[0]))), | ||||
| 	} | ||||
| 	optlen := unsafe.Sizeof(param) | ||||
| 	_, _, err := getsockopt(fd, SCTP_SOCKOPT_CONNECTX3, uintptr(unsafe.Pointer(¶m)), uintptr(unsafe.Pointer(&optlen))) | ||||
| 	if err == nil { | ||||
| 		return int(param.AssocID), nil | ||||
| 	} else if err != syscall.ENOPROTOOPT { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	r0, _, err := setsockopt(fd, SCTP_SOCKOPT_CONNECTX, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf))) | ||||
| 	return int(r0), err | ||||
| } | ||||
|  | ||||
| func SCTPBind(fd int, addr *SCTPAddr, flags int) error { | ||||
| 	var option uintptr | ||||
| 	switch flags { | ||||
| 	case SCTP_BINDX_ADD_ADDR: | ||||
| 		option = SCTP_SOCKOPT_BINDX_ADD | ||||
| 	case SCTP_BINDX_REM_ADDR: | ||||
| 		option = SCTP_SOCKOPT_BINDX_REM | ||||
| 	default: | ||||
| 		return syscall.EINVAL | ||||
| 	} | ||||
|  | ||||
| 	buf := addr.ToRawSockAddrBuf() | ||||
| 	_, _, err := setsockopt(fd, option, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf))) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| type SCTPConn struct { | ||||
| 	_fd                 int32 | ||||
| 	notificationHandler NotificationHandler | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) fd() int { | ||||
| 	return int(atomic.LoadInt32(&c._fd)) | ||||
| } | ||||
|  | ||||
| func NewSCTPConn(fd int, handler NotificationHandler) *SCTPConn { | ||||
| 	conn := &SCTPConn{ | ||||
| 		_fd:                 int32(fd), | ||||
| 		notificationHandler: handler, | ||||
| 	} | ||||
| 	return conn | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) Write(b []byte) (int, error) { | ||||
| 	return c.SCTPWrite(b, nil) | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) Read(b []byte) (int, error) { | ||||
| 	n, _, err := c.SCTPRead(b) | ||||
| 	if n < 0 { | ||||
| 		n = 0 | ||||
| 	} | ||||
| 	return n, err | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SetInitMsg(numOstreams, maxInstreams, maxAttempts, maxInitTimeout int) error { | ||||
| 	return setInitOpts(c.fd(), InitMsg{ | ||||
| 		NumOstreams:    uint16(numOstreams), | ||||
| 		MaxInstreams:   uint16(maxInstreams), | ||||
| 		MaxAttempts:    uint16(maxAttempts), | ||||
| 		MaxInitTimeout: uint16(maxInitTimeout), | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SubscribeEvents(flags int) error { | ||||
| 	var d, a, ad, sf, p, sh, pa, ada, au, se uint8 | ||||
| 	if flags&SCTP_EVENT_DATA_IO > 0 { | ||||
| 		d = 1 | ||||
| 	} | ||||
| 	if flags&SCTP_EVENT_ASSOCIATION > 0 { | ||||
| 		a = 1 | ||||
| 	} | ||||
| 	if flags&SCTP_EVENT_ADDRESS > 0 { | ||||
| 		ad = 1 | ||||
| 	} | ||||
| 	if flags&SCTP_EVENT_SEND_FAILURE > 0 { | ||||
| 		sf = 1 | ||||
| 	} | ||||
| 	if flags&SCTP_EVENT_PEER_ERROR > 0 { | ||||
| 		p = 1 | ||||
| 	} | ||||
| 	if flags&SCTP_EVENT_SHUTDOWN > 0 { | ||||
| 		sh = 1 | ||||
| 	} | ||||
| 	if flags&SCTP_EVENT_PARTIAL_DELIVERY > 0 { | ||||
| 		pa = 1 | ||||
| 	} | ||||
| 	if flags&SCTP_EVENT_ADAPTATION_LAYER > 0 { | ||||
| 		ada = 1 | ||||
| 	} | ||||
| 	if flags&SCTP_EVENT_AUTHENTICATION > 0 { | ||||
| 		au = 1 | ||||
| 	} | ||||
| 	if flags&SCTP_EVENT_SENDER_DRY > 0 { | ||||
| 		se = 1 | ||||
| 	} | ||||
| 	param := EventSubscribe{ | ||||
| 		DataIO:          d, | ||||
| 		Association:     a, | ||||
| 		Address:         ad, | ||||
| 		SendFailure:     sf, | ||||
| 		PeerError:       p, | ||||
| 		Shutdown:        sh, | ||||
| 		PartialDelivery: pa, | ||||
| 		AdaptationLayer: ada, | ||||
| 		Authentication:  au, | ||||
| 		SenderDry:       se, | ||||
| 	} | ||||
| 	optlen := unsafe.Sizeof(param) | ||||
| 	_, _, err := setsockopt(c.fd(), SCTP_EVENTS, uintptr(unsafe.Pointer(¶m)), uintptr(optlen)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SubscribedEvents() (int, error) { | ||||
| 	param := EventSubscribe{} | ||||
| 	optlen := unsafe.Sizeof(param) | ||||
| 	_, _, err := getsockopt(c.fd(), SCTP_EVENTS, uintptr(unsafe.Pointer(¶m)), uintptr(unsafe.Pointer(&optlen))) | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
| 	var flags int | ||||
| 	if param.DataIO > 0 { | ||||
| 		flags |= SCTP_EVENT_DATA_IO | ||||
| 	} | ||||
| 	if param.Association > 0 { | ||||
| 		flags |= SCTP_EVENT_ASSOCIATION | ||||
| 	} | ||||
| 	if param.Address > 0 { | ||||
| 		flags |= SCTP_EVENT_ADDRESS | ||||
| 	} | ||||
| 	if param.SendFailure > 0 { | ||||
| 		flags |= SCTP_EVENT_SEND_FAILURE | ||||
| 	} | ||||
| 	if param.PeerError > 0 { | ||||
| 		flags |= SCTP_EVENT_PEER_ERROR | ||||
| 	} | ||||
| 	if param.Shutdown > 0 { | ||||
| 		flags |= SCTP_EVENT_SHUTDOWN | ||||
| 	} | ||||
| 	if param.PartialDelivery > 0 { | ||||
| 		flags |= SCTP_EVENT_PARTIAL_DELIVERY | ||||
| 	} | ||||
| 	if param.AdaptationLayer > 0 { | ||||
| 		flags |= SCTP_EVENT_ADAPTATION_LAYER | ||||
| 	} | ||||
| 	if param.Authentication > 0 { | ||||
| 		flags |= SCTP_EVENT_AUTHENTICATION | ||||
| 	} | ||||
| 	if param.SenderDry > 0 { | ||||
| 		flags |= SCTP_EVENT_SENDER_DRY | ||||
| 	} | ||||
| 	return flags, nil | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SetDefaultSentParam(info *SndRcvInfo) error { | ||||
| 	optlen := unsafe.Sizeof(*info) | ||||
| 	_, _, err := setsockopt(c.fd(), SCTP_DEFAULT_SENT_PARAM, uintptr(unsafe.Pointer(info)), uintptr(optlen)) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) GetDefaultSentParam() (*SndRcvInfo, error) { | ||||
| 	info := &SndRcvInfo{} | ||||
| 	optlen := unsafe.Sizeof(*info) | ||||
| 	_, _, err := getsockopt(c.fd(), SCTP_DEFAULT_SENT_PARAM, uintptr(unsafe.Pointer(info)), uintptr(unsafe.Pointer(&optlen))) | ||||
| 	return info, err | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) Getsockopt(optname, optval, optlen uintptr) (uintptr, uintptr, error) { | ||||
| 	return getsockopt(c.fd(), optname, optval, optlen) | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) Setsockopt(optname, optval, optlen uintptr) (uintptr, uintptr, error) { | ||||
| 	return setsockopt(c.fd(), optname, optval, optlen) | ||||
| } | ||||
|  | ||||
| func resolveFromRawAddr(ptr unsafe.Pointer, n int) (*SCTPAddr, error) { | ||||
| 	addr := &SCTPAddr{ | ||||
| 		IPAddrs: make([]net.IPAddr, n), | ||||
| 	} | ||||
|  | ||||
| 	switch family := (*(*syscall.RawSockaddrAny)(ptr)).Addr.Family; family { | ||||
| 	case syscall.AF_INET: | ||||
| 		addr.Port = int(ntohs(uint16((*(*syscall.RawSockaddrInet4)(ptr)).Port))) | ||||
| 		tmp := syscall.RawSockaddrInet4{} | ||||
| 		size := unsafe.Sizeof(tmp) | ||||
| 		for i := 0; i < n; i++ { | ||||
| 			a := *(*syscall.RawSockaddrInet4)(unsafe.Pointer( | ||||
| 				uintptr(ptr) + size*uintptr(i))) | ||||
| 			addr.IPAddrs[i] = net.IPAddr{IP: a.Addr[:]} | ||||
| 		} | ||||
| 	case syscall.AF_INET6: | ||||
| 		addr.Port = int(ntohs(uint16((*(*syscall.RawSockaddrInet4)(ptr)).Port))) | ||||
| 		tmp := syscall.RawSockaddrInet6{} | ||||
| 		size := unsafe.Sizeof(tmp) | ||||
| 		for i := 0; i < n; i++ { | ||||
| 			a := *(*syscall.RawSockaddrInet6)(unsafe.Pointer( | ||||
| 				uintptr(ptr) + size*uintptr(i))) | ||||
| 			var zone string | ||||
| 			ifi, err := net.InterfaceByIndex(int(a.Scope_id)) | ||||
| 			if err == nil { | ||||
| 				zone = ifi.Name | ||||
| 			} | ||||
| 			addr.IPAddrs[i] = net.IPAddr{IP: a.Addr[:], Zone: zone} | ||||
| 		} | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("unknown address family: %d", family) | ||||
| 	} | ||||
| 	return addr, nil | ||||
| } | ||||
|  | ||||
| func sctpGetAddrs(fd, id, optname int) (*SCTPAddr, error) { | ||||
|  | ||||
| 	type getaddrs struct { | ||||
| 		assocId int32 | ||||
| 		addrNum uint32 | ||||
| 		addrs   [4096]byte | ||||
| 	} | ||||
| 	param := getaddrs{ | ||||
| 		assocId: int32(id), | ||||
| 	} | ||||
| 	optlen := unsafe.Sizeof(param) | ||||
| 	_, _, err := getsockopt(fd, uintptr(optname), uintptr(unsafe.Pointer(¶m)), uintptr(unsafe.Pointer(&optlen))) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return resolveFromRawAddr(unsafe.Pointer(¶m.addrs), int(param.addrNum)) | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SCTPGetPrimaryPeerAddr() (*SCTPAddr, error) { | ||||
|  | ||||
| 	type sctpGetSetPrim struct { | ||||
| 		assocId int32 | ||||
| 		addrs   [128]byte | ||||
| 	} | ||||
| 	param := sctpGetSetPrim{ | ||||
| 		assocId: int32(0), | ||||
| 	} | ||||
| 	optlen := unsafe.Sizeof(param) | ||||
| 	_, _, err := getsockopt(c.fd(), SCTP_PRIMARY_ADDR, uintptr(unsafe.Pointer(¶m)), uintptr(unsafe.Pointer(&optlen))) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return resolveFromRawAddr(unsafe.Pointer(¶m.addrs), 1) | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SCTPLocalAddr(id int) (*SCTPAddr, error) { | ||||
| 	return sctpGetAddrs(c.fd(), id, SCTP_GET_LOCAL_ADDRS) | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SCTPRemoteAddr(id int) (*SCTPAddr, error) { | ||||
| 	return sctpGetAddrs(c.fd(), id, SCTP_GET_PEER_ADDRS) | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) LocalAddr() net.Addr { | ||||
| 	addr, err := sctpGetAddrs(c.fd(), 0, SCTP_GET_LOCAL_ADDRS) | ||||
| 	if err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return addr | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) RemoteAddr() net.Addr { | ||||
| 	addr, err := sctpGetAddrs(c.fd(), 0, SCTP_GET_PEER_ADDRS) | ||||
| 	if err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return addr | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) PeelOff(id int) (*SCTPConn, error) { | ||||
| 	type peeloffArg struct { | ||||
| 		assocId int32 | ||||
| 		sd      int | ||||
| 	} | ||||
| 	param := peeloffArg{ | ||||
| 		assocId: int32(id), | ||||
| 	} | ||||
| 	optlen := unsafe.Sizeof(param) | ||||
| 	_, _, err := getsockopt(c.fd(), SCTP_SOCKOPT_PEELOFF, uintptr(unsafe.Pointer(¶m)), uintptr(unsafe.Pointer(&optlen))) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &SCTPConn{_fd: int32(param.sd)}, nil | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SetDeadline(t time.Time) error { | ||||
| 	return syscall.EOPNOTSUPP | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SetReadDeadline(t time.Time) error { | ||||
| 	return syscall.EOPNOTSUPP | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SetWriteDeadline(t time.Time) error { | ||||
| 	return syscall.EOPNOTSUPP | ||||
| } | ||||
|  | ||||
| type SCTPListener struct { | ||||
| 	fd int | ||||
| 	m  sync.Mutex | ||||
| } | ||||
|  | ||||
| func (ln *SCTPListener) Addr() net.Addr { | ||||
| 	laddr, err := sctpGetAddrs(ln.fd, 0, SCTP_GET_LOCAL_ADDRS) | ||||
| 	if err != nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return laddr | ||||
| } | ||||
|  | ||||
| type SCTPSndRcvInfoWrappedConn struct { | ||||
| 	conn *SCTPConn | ||||
| } | ||||
|  | ||||
| func NewSCTPSndRcvInfoWrappedConn(conn *SCTPConn) *SCTPSndRcvInfoWrappedConn { | ||||
| 	conn.SubscribeEvents(SCTP_EVENT_DATA_IO) | ||||
| 	return &SCTPSndRcvInfoWrappedConn{conn} | ||||
| } | ||||
|  | ||||
| func (c *SCTPSndRcvInfoWrappedConn) Write(b []byte) (int, error) { | ||||
| 	if len(b) < int(sndRcvInfoSize) { | ||||
| 		return 0, syscall.EINVAL | ||||
| 	} | ||||
| 	info := (*SndRcvInfo)(unsafe.Pointer(&b[0])) | ||||
| 	n, err := c.conn.SCTPWrite(b[sndRcvInfoSize:], info) | ||||
| 	return n + int(sndRcvInfoSize), err | ||||
| } | ||||
|  | ||||
| func (c *SCTPSndRcvInfoWrappedConn) Read(b []byte) (int, error) { | ||||
| 	if len(b) < int(sndRcvInfoSize) { | ||||
| 		return 0, syscall.EINVAL | ||||
| 	} | ||||
| 	n, info, err := c.conn.SCTPRead(b[sndRcvInfoSize:]) | ||||
| 	if err != nil { | ||||
| 		return n, err | ||||
| 	} | ||||
| 	copy(b, toBuf(info)) | ||||
| 	return n + int(sndRcvInfoSize), err | ||||
| } | ||||
|  | ||||
| func (c *SCTPSndRcvInfoWrappedConn) Close() error { | ||||
| 	return c.conn.Close() | ||||
| } | ||||
|  | ||||
| func (c *SCTPSndRcvInfoWrappedConn) LocalAddr() net.Addr { | ||||
| 	return c.conn.LocalAddr() | ||||
| } | ||||
|  | ||||
| func (c *SCTPSndRcvInfoWrappedConn) RemoteAddr() net.Addr { | ||||
| 	return c.conn.RemoteAddr() | ||||
| } | ||||
|  | ||||
| func (c *SCTPSndRcvInfoWrappedConn) SetDeadline(t time.Time) error { | ||||
| 	return c.conn.SetDeadline(t) | ||||
| } | ||||
|  | ||||
| func (c *SCTPSndRcvInfoWrappedConn) SetReadDeadline(t time.Time) error { | ||||
| 	return c.conn.SetReadDeadline(t) | ||||
| } | ||||
|  | ||||
| func (c *SCTPSndRcvInfoWrappedConn) SetWriteDeadline(t time.Time) error { | ||||
| 	return c.conn.SetWriteDeadline(t) | ||||
| } | ||||
|  | ||||
| func (c *SCTPSndRcvInfoWrappedConn) SetWriteBuffer(bytes int) error { | ||||
| 	return c.conn.SetWriteBuffer(bytes) | ||||
| } | ||||
|  | ||||
| func (c *SCTPSndRcvInfoWrappedConn) GetWriteBuffer() (int, error) { | ||||
| 	return c.conn.GetWriteBuffer() | ||||
| } | ||||
|  | ||||
| func (c *SCTPSndRcvInfoWrappedConn) SetReadBuffer(bytes int) error { | ||||
| 	return c.conn.SetReadBuffer(bytes) | ||||
| } | ||||
|  | ||||
| func (c *SCTPSndRcvInfoWrappedConn) GetReadBuffer() (int, error) { | ||||
| 	return c.conn.GetReadBuffer() | ||||
| } | ||||
|  | ||||
| // SocketConfig contains options for the SCTP socket. | ||||
| type SocketConfig struct { | ||||
| 	// If Control is not nil it is called after the socket is created but before | ||||
| 	// it is bound or connected. | ||||
| 	Control func(network, address string, c syscall.RawConn) error | ||||
|  | ||||
| 	// InitMsg is the options to send in the initial SCTP message | ||||
| 	InitMsg InitMsg | ||||
| } | ||||
|  | ||||
| func (cfg *SocketConfig) Listen(net string, laddr *SCTPAddr) (*SCTPListener, error) { | ||||
| 	return listenSCTPExtConfig(net, laddr, cfg.InitMsg, cfg.Control) | ||||
| } | ||||
|  | ||||
| func (cfg *SocketConfig) Dial(net string, laddr, raddr *SCTPAddr) (*SCTPConn, error) { | ||||
| 	return dialSCTPExtConfig(net, laddr, raddr, cfg.InitMsg, cfg.Control) | ||||
| } | ||||
							
								
								
									
										305
									
								
								vendor/github.com/ishidawataru/sctp/sctp_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										305
									
								
								vendor/github.com/ishidawataru/sctp/sctp_linux.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,305 @@ | ||||
| // +build linux,!386 | ||||
| // Copyright 2019 Wataru Ishida. All rights reserved. | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //    http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
| // implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package sctp | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"sync/atomic" | ||||
| 	"syscall" | ||||
| 	"unsafe" | ||||
| ) | ||||
|  | ||||
| func setsockopt(fd int, optname, optval, optlen uintptr) (uintptr, uintptr, error) { | ||||
| 	// FIXME: syscall.SYS_SETSOCKOPT is undefined on 386 | ||||
| 	r0, r1, errno := syscall.Syscall6(syscall.SYS_SETSOCKOPT, | ||||
| 		uintptr(fd), | ||||
| 		SOL_SCTP, | ||||
| 		optname, | ||||
| 		optval, | ||||
| 		optlen, | ||||
| 		0) | ||||
| 	if errno != 0 { | ||||
| 		return r0, r1, errno | ||||
| 	} | ||||
| 	return r0, r1, nil | ||||
| } | ||||
|  | ||||
| func getsockopt(fd int, optname, optval, optlen uintptr) (uintptr, uintptr, error) { | ||||
| 	// FIXME: syscall.SYS_GETSOCKOPT is undefined on 386 | ||||
| 	r0, r1, errno := syscall.Syscall6(syscall.SYS_GETSOCKOPT, | ||||
| 		uintptr(fd), | ||||
| 		SOL_SCTP, | ||||
| 		optname, | ||||
| 		optval, | ||||
| 		optlen, | ||||
| 		0) | ||||
| 	if errno != 0 { | ||||
| 		return r0, r1, errno | ||||
| 	} | ||||
| 	return r0, r1, nil | ||||
| } | ||||
|  | ||||
| type rawConn struct { | ||||
| 	sockfd int | ||||
| } | ||||
|  | ||||
| func (r rawConn) Control(f func(fd uintptr)) error { | ||||
| 	f(uintptr(r.sockfd)) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (r rawConn) Read(f func(fd uintptr) (done bool)) error { | ||||
| 	panic("not implemented") | ||||
| } | ||||
|  | ||||
| func (r rawConn) Write(f func(fd uintptr) (done bool)) error { | ||||
| 	panic("not implemented") | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SCTPWrite(b []byte, info *SndRcvInfo) (int, error) { | ||||
| 	var cbuf []byte | ||||
| 	if info != nil { | ||||
| 		cmsgBuf := toBuf(info) | ||||
| 		hdr := &syscall.Cmsghdr{ | ||||
| 			Level: syscall.IPPROTO_SCTP, | ||||
| 			Type:  SCTP_CMSG_SNDRCV, | ||||
| 		} | ||||
|  | ||||
| 		// bitwidth of hdr.Len is platform-specific, | ||||
| 		// so we use hdr.SetLen() rather than directly setting hdr.Len | ||||
| 		hdr.SetLen(syscall.CmsgSpace(len(cmsgBuf))) | ||||
| 		cbuf = append(toBuf(hdr), cmsgBuf...) | ||||
| 	} | ||||
| 	return syscall.SendmsgN(c.fd(), b, cbuf, nil, 0) | ||||
| } | ||||
|  | ||||
| func parseSndRcvInfo(b []byte) (*SndRcvInfo, error) { | ||||
| 	msgs, err := syscall.ParseSocketControlMessage(b) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, m := range msgs { | ||||
| 		if m.Header.Level == syscall.IPPROTO_SCTP { | ||||
| 			switch m.Header.Type { | ||||
| 			case SCTP_CMSG_SNDRCV: | ||||
| 				return (*SndRcvInfo)(unsafe.Pointer(&m.Data[0])), nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, nil | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SCTPRead(b []byte) (int, *SndRcvInfo, error) { | ||||
| 	oob := make([]byte, 254) | ||||
| 	for { | ||||
| 		n, oobn, recvflags, _, err := syscall.Recvmsg(c.fd(), b, oob, 0) | ||||
| 		if err != nil { | ||||
| 			return n, nil, err | ||||
| 		} | ||||
|  | ||||
| 		if n == 0 && oobn == 0 { | ||||
| 			return 0, nil, io.EOF | ||||
| 		} | ||||
|  | ||||
| 		if recvflags&MSG_NOTIFICATION > 0 && c.notificationHandler != nil { | ||||
| 			if err := c.notificationHandler(b[:n]); err != nil { | ||||
| 				return 0, nil, err | ||||
| 			} | ||||
| 		} else { | ||||
| 			var info *SndRcvInfo | ||||
| 			if oobn > 0 { | ||||
| 				info, err = parseSndRcvInfo(oob[:oobn]) | ||||
| 			} | ||||
| 			return n, info, err | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) Close() error { | ||||
| 	if c != nil { | ||||
| 		fd := atomic.SwapInt32(&c._fd, -1) | ||||
| 		if fd > 0 { | ||||
| 			info := &SndRcvInfo{ | ||||
| 				Flags: SCTP_EOF, | ||||
| 			} | ||||
| 			c.SCTPWrite(nil, info) | ||||
| 			syscall.Shutdown(int(fd), syscall.SHUT_RDWR) | ||||
| 			return syscall.Close(int(fd)) | ||||
| 		} | ||||
| 	} | ||||
| 	return syscall.EBADF | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SetWriteBuffer(bytes int) error { | ||||
| 	return syscall.SetsockoptInt(c.fd(), syscall.SOL_SOCKET, syscall.SO_SNDBUF, bytes) | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) GetWriteBuffer() (int, error) { | ||||
| 	return syscall.GetsockoptInt(c.fd(), syscall.SOL_SOCKET, syscall.SO_SNDBUF) | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SetReadBuffer(bytes int) error { | ||||
| 	return syscall.SetsockoptInt(c.fd(), syscall.SOL_SOCKET, syscall.SO_RCVBUF, bytes) | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) GetReadBuffer() (int, error) { | ||||
| 	return syscall.GetsockoptInt(c.fd(), syscall.SOL_SOCKET, syscall.SO_RCVBUF) | ||||
| } | ||||
|  | ||||
| // ListenSCTP - start listener on specified address/port | ||||
| func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) { | ||||
| 	return ListenSCTPExt(net, laddr, InitMsg{NumOstreams: SCTP_MAX_STREAM}) | ||||
| } | ||||
|  | ||||
| // ListenSCTPExt - start listener on specified address/port with given SCTP options | ||||
| func ListenSCTPExt(network string, laddr *SCTPAddr, options InitMsg) (*SCTPListener, error) { | ||||
| 	return listenSCTPExtConfig(network, laddr, options, nil) | ||||
| } | ||||
|  | ||||
| // listenSCTPExtConfig - start listener on specified address/port with given SCTP options and socket configuration | ||||
| func listenSCTPExtConfig(network string, laddr *SCTPAddr, options InitMsg, control func(network, address string, c syscall.RawConn) error) (*SCTPListener, error) { | ||||
| 	af, ipv6only := favoriteAddrFamily(network, laddr, nil, "listen") | ||||
| 	sock, err := syscall.Socket( | ||||
| 		af, | ||||
| 		syscall.SOCK_STREAM, | ||||
| 		syscall.IPPROTO_SCTP, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// close socket on error | ||||
| 	defer func() { | ||||
| 		if err != nil { | ||||
| 			syscall.Close(sock) | ||||
| 		} | ||||
| 	}() | ||||
| 	if err = setDefaultSockopts(sock, af, ipv6only); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if control != nil { | ||||
| 		rc := rawConn{sockfd: sock} | ||||
| 		if err = control(network, laddr.String(), rc); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	err = setInitOpts(sock, options) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if laddr != nil { | ||||
| 		// If IP address and/or port was not provided so far, let's use the unspecified IPv4 or IPv6 address | ||||
| 		if len(laddr.IPAddrs) == 0 { | ||||
| 			if af == syscall.AF_INET { | ||||
| 				laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv4zero}) | ||||
| 			} else if af == syscall.AF_INET6 { | ||||
| 				laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv6zero}) | ||||
| 			} | ||||
| 		} | ||||
| 		err = SCTPBind(sock, laddr, SCTP_BINDX_ADD_ADDR) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	err = syscall.Listen(sock, syscall.SOMAXCONN) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &SCTPListener{ | ||||
| 		fd: sock, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| // AcceptSCTP waits for and returns the next SCTP connection to the listener. | ||||
| func (ln *SCTPListener) AcceptSCTP() (*SCTPConn, error) { | ||||
| 	fd, _, err := syscall.Accept4(ln.fd, 0) | ||||
| 	return NewSCTPConn(fd, nil), err | ||||
| } | ||||
|  | ||||
| // Accept waits for and returns the next connection connection to the listener. | ||||
| func (ln *SCTPListener) Accept() (net.Conn, error) { | ||||
| 	return ln.AcceptSCTP() | ||||
| } | ||||
|  | ||||
| func (ln *SCTPListener) Close() error { | ||||
| 	syscall.Shutdown(ln.fd, syscall.SHUT_RDWR) | ||||
| 	return syscall.Close(ln.fd) | ||||
| } | ||||
|  | ||||
| // DialSCTP - bind socket to laddr (if given) and connect to raddr | ||||
| func DialSCTP(net string, laddr, raddr *SCTPAddr) (*SCTPConn, error) { | ||||
| 	return DialSCTPExt(net, laddr, raddr, InitMsg{NumOstreams: SCTP_MAX_STREAM}) | ||||
| } | ||||
|  | ||||
| // DialSCTPExt - same as DialSCTP but with given SCTP options | ||||
| func DialSCTPExt(network string, laddr, raddr *SCTPAddr, options InitMsg) (*SCTPConn, error) { | ||||
| 	return dialSCTPExtConfig(network, laddr, raddr, options, nil) | ||||
| } | ||||
|  | ||||
| // dialSCTPExtConfig - same as DialSCTP but with given SCTP options and socket configuration | ||||
| func dialSCTPExtConfig(network string, laddr, raddr *SCTPAddr, options InitMsg, control func(network, address string, c syscall.RawConn) error) (*SCTPConn, error) { | ||||
| 	af, ipv6only := favoriteAddrFamily(network, laddr, raddr, "dial") | ||||
| 	sock, err := syscall.Socket( | ||||
| 		af, | ||||
| 		syscall.SOCK_STREAM, | ||||
| 		syscall.IPPROTO_SCTP, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// close socket on error | ||||
| 	defer func() { | ||||
| 		if err != nil { | ||||
| 			syscall.Close(sock) | ||||
| 		} | ||||
| 	}() | ||||
| 	if err = setDefaultSockopts(sock, af, ipv6only); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if control != nil { | ||||
| 		rc := rawConn{sockfd: sock} | ||||
| 		if err = control(network, laddr.String(), rc); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	err = setInitOpts(sock, options) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	if laddr != nil { | ||||
| 		// If IP address and/or port was not provided so far, let's use the unspecified IPv4 or IPv6 address | ||||
| 		if len(laddr.IPAddrs) == 0 { | ||||
| 			if af == syscall.AF_INET { | ||||
| 				laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv4zero}) | ||||
| 			} else if af == syscall.AF_INET6 { | ||||
| 				laddr.IPAddrs = append(laddr.IPAddrs, net.IPAddr{IP: net.IPv6zero}) | ||||
| 			} | ||||
| 		} | ||||
| 		err := SCTPBind(sock, laddr, SCTP_BINDX_ADD_ADDR) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
| 	_, err = SCTPConnect(sock, raddr) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return NewSCTPConn(sock, nil), nil | ||||
| } | ||||
							
								
								
									
										98
									
								
								vendor/github.com/ishidawataru/sctp/sctp_unsupported.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								vendor/github.com/ishidawataru/sctp/sctp_unsupported.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,98 @@ | ||||
| // +build !linux linux,386 | ||||
| // Copyright 2019 Wataru Ishida. All rights reserved. | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| // you may not use this file except in compliance with the License. | ||||
| // You may obtain a copy of the License at | ||||
| // | ||||
| //    http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
| // implied. | ||||
| // See the License for the specific language governing permissions and | ||||
| // limitations under the License. | ||||
|  | ||||
| package sctp | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"net" | ||||
| 	"runtime" | ||||
| 	"syscall" | ||||
| ) | ||||
|  | ||||
| var ErrUnsupported = errors.New("SCTP is unsupported on " + runtime.GOOS + "/" + runtime.GOARCH) | ||||
|  | ||||
| func setsockopt(fd int, optname, optval, optlen uintptr) (uintptr, uintptr, error) { | ||||
| 	return 0, 0, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func getsockopt(fd int, optname, optval, optlen uintptr) (uintptr, uintptr, error) { | ||||
| 	return 0, 0, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SCTPWrite(b []byte, info *SndRcvInfo) (int, error) { | ||||
| 	return 0, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SCTPRead(b []byte) (int, *SndRcvInfo, error) { | ||||
| 	return 0, nil, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) Close() error { | ||||
| 	return ErrUnsupported | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SetWriteBuffer(bytes int) error { | ||||
| 	return ErrUnsupported | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) GetWriteBuffer() (int, error) { | ||||
| 	return 0, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) SetReadBuffer(bytes int) error { | ||||
| 	return ErrUnsupported | ||||
| } | ||||
|  | ||||
| func (c *SCTPConn) GetReadBuffer() (int, error) { | ||||
| 	return 0, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func ListenSCTP(net string, laddr *SCTPAddr) (*SCTPListener, error) { | ||||
| 	return nil, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func ListenSCTPExt(net string, laddr *SCTPAddr, options InitMsg) (*SCTPListener, error) { | ||||
| 	return nil, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func listenSCTPExtConfig(network string, laddr *SCTPAddr, options InitMsg, control func(network, address string, c syscall.RawConn) error) (*SCTPListener, error) { | ||||
| 	return nil, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func (ln *SCTPListener) Accept() (net.Conn, error) { | ||||
| 	return nil, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func (ln *SCTPListener) AcceptSCTP() (*SCTPConn, error) { | ||||
| 	return nil, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func (ln *SCTPListener) Close() error { | ||||
| 	return ErrUnsupported | ||||
| } | ||||
|  | ||||
| func DialSCTP(net string, laddr, raddr *SCTPAddr) (*SCTPConn, error) { | ||||
| 	return nil, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func DialSCTPExt(network string, laddr, raddr *SCTPAddr, options InitMsg) (*SCTPConn, error) { | ||||
| 	return nil, ErrUnsupported | ||||
| } | ||||
|  | ||||
| func dialSCTPExtConfig(network string, laddr, raddr *SCTPAddr, options InitMsg, control func(network, address string, c syscall.RawConn) error) (*SCTPConn, error) { | ||||
| 	return nil, ErrUnsupported | ||||
| } | ||||
							
								
								
									
										3
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							| @ -39,6 +39,9 @@ github.com/google/uuid | ||||
| # github.com/gorilla/mux v1.8.0 | ||||
| ## explicit; go 1.12 | ||||
| github.com/gorilla/mux | ||||
| # github.com/ishidawataru/sctp v0.0.0-20210707070123-9a39160e9062 | ||||
| ## explicit; go 1.12 | ||||
| github.com/ishidawataru/sctp | ||||
| # github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 | ||||
| ## explicit | ||||
| github.com/kballard/go-shellquote | ||||
|  | ||||
		Reference in New Issue
	
	Block a user