mirror of
https://github.com/TwiN/gatus.git
synced 2024-12-14 11:58:04 +00:00
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:
parent
1f84f2afa0
commit
fa47a199e5
17 changed files with 1760 additions and 0 deletions
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)
|
||||
----
|
||||
|
||||
[![Build Status](https://travis-ci.org/ishidawataru/sctp.svg?branch=master)](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
|
||||
|
|
Loading…
Reference in a new issue