├── .dockerignore ├── vendor ├── github.com │ ├── pkg │ │ └── profile │ │ │ ├── AUTHORS │ │ │ ├── .travis.yml │ │ │ ├── LICENSE │ │ │ └── README.md │ ├── benburkert │ │ └── openpgp │ │ │ └── aes │ │ │ └── keywrap │ │ │ ├── doc.go │ │ │ └── keywrap.go │ ├── stretchr │ │ └── testify │ │ │ ├── require │ │ │ ├── require_forward.go.tmpl │ │ │ ├── require.go.tmpl │ │ │ ├── forward_requirements.go │ │ │ ├── doc.go │ │ │ └── requirements.go │ │ │ ├── assert │ │ │ ├── assertion_format.go.tmpl │ │ │ ├── assertion_forward.go.tmpl │ │ │ ├── errors.go │ │ │ ├── forward_assertions.go │ │ │ ├── yaml │ │ │ │ ├── yaml_fail.go │ │ │ │ ├── yaml_custom.go │ │ │ │ └── yaml_default.go │ │ │ ├── doc.go │ │ │ ├── assertion_order.go │ │ │ └── http_assertions.go │ │ │ └── LICENSE │ ├── google │ │ └── pprof │ │ │ ├── AUTHORS │ │ │ ├── CONTRIBUTORS │ │ │ └── profile │ │ │ ├── index.go │ │ │ ├── prune.go │ │ │ └── filter.go │ ├── davecgh │ │ └── go-spew │ │ │ ├── LICENSE │ │ │ └── spew │ │ │ ├── bypasssafe.go │ │ │ ├── bypass.go │ │ │ └── spew.go │ ├── felixge │ │ └── fgprof │ │ │ ├── handler.go │ │ │ ├── LICENSE.txt │ │ │ └── BenchmarkProfilerGoroutines.txt │ └── pmezard │ │ └── go-difflib │ │ └── LICENSE ├── golang.org │ └── x │ │ └── sys │ │ ├── windows │ │ ├── aliases.go │ │ ├── mksyscall.go │ │ ├── race0.go │ │ ├── str.go │ │ ├── race.go │ │ ├── eventlog.go │ │ ├── types_windows_amd64.go │ │ ├── types_windows_arm64.go │ │ ├── types_windows_386.go │ │ ├── types_windows_arm.go │ │ ├── mkknownfolderids.bash │ │ ├── memory_windows.go │ │ ├── env_windows.go │ │ ├── mkerrors.bash │ │ ├── syscall.go │ │ └── exec_windows.go │ │ ├── PATENTS │ │ └── LICENSE ├── gopkg.in │ └── yaml.v3 │ │ ├── NOTICE │ │ ├── writerc.go │ │ ├── LICENSE │ │ ├── sorter.go │ │ ├── README.md │ │ └── yamlprivateh.go └── modules.txt ├── .gitignore ├── congestion ├── live │ ├── doc.go │ ├── send_test.go │ └── fake.go └── congestion.go ├── .github ├── dependabot.yml └── workflows │ ├── go-tests.yml │ └── codeql-analysis.yml ├── .editorconfig ├── Dockerfile ├── SECURITY.md ├── go.mod ├── net ├── syncookie_test.go ├── syncookie.go ├── ip_test.go └── ip.go ├── LICENSE ├── rand ├── rand_test.go └── rand.go ├── server_test.go ├── log_test.go ├── doc.go ├── CODE_OF_CONDUCT.md ├── contrib ├── client │ ├── reader.go │ ├── writer.go │ └── main.go └── server │ └── main.go ├── net.go ├── net_windows.go ├── config_test.go ├── Makefile ├── log.go ├── go.sum ├── circular ├── circular_test.go └── circular.go ├── server.go ├── pubsub_test.go ├── pubsub.go └── crypto └── crypto.go /.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | /.git 3 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/profile/AUTHORS: -------------------------------------------------------------------------------- 1 | Dave Cheney 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /contrib/server/server* 2 | /contrib/client/client* 3 | *.prof 4 | *.out 5 | *.html 6 | *.ts 7 | *.mp4 8 | -------------------------------------------------------------------------------- /congestion/live/doc.go: -------------------------------------------------------------------------------- 1 | // Package live provides implementations of the Sender and Receiver interfaces for live congestion control 2 | package live 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "gomod" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /vendor/github.com/benburkert/openpgp/aes/keywrap/doc.go: -------------------------------------------------------------------------------- 1 | // Package keywrap is an implementation of the RFC 3394 AES key wrapping 2 | // algorithm. This is used in OpenPGP with elliptic curve keys. 3 | package keywrap 4 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/profile/.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go_import_path: github.com/pkg/profile 3 | go: 4 | - 1.13.x 5 | - 1.14.x 6 | - tip 7 | 8 | script: 9 | - go test -race github.com/pkg/profile 10 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) { 3 | if h, ok := a.t.(tHelper); ok { h.Helper() } 4 | {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentFormat}} 2 | func {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool { 3 | if h, ok := t.(tHelper); ok { h.Helper() } 4 | return {{.DocInfo.Name}}(t, {{.ForwardedParamsFormat}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_forward.go.tmpl: -------------------------------------------------------------------------------- 1 | {{.CommentWithoutT "a"}} 2 | func (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool { 3 | if h, ok := a.t.(tHelper); ok { h.Helper() } 4 | return {{.DocInfo.Name}}(a.t, {{.ForwardedParams}}) 5 | } 6 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/require.go.tmpl: -------------------------------------------------------------------------------- 1 | {{ replace .Comment "assert." "require."}} 2 | func {{.DocInfo.Name}}(t TestingT, {{.Params}}) { 3 | if h, ok := t.(tHelper); ok { h.Helper() } 4 | if assert.{{.DocInfo.Name}}(t, {{.ForwardedParams}}) { return } 5 | t.FailNow() 6 | } 7 | -------------------------------------------------------------------------------- /vendor/github.com/google/pprof/AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the official list of pprof authors for copyright purposes. 2 | # This file is distinct from the CONTRIBUTORS files. 3 | # See the latter for an explanation. 4 | # Names should be added to this file as: 5 | # Name or Organization 6 | # The email address is not required for organizations. 7 | Google Inc. -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/aliases.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build windows 6 | 7 | package windows 8 | 9 | import "syscall" 10 | 11 | type Errno = syscall.Errno 12 | type SysProcAttr = syscall.SysProcAttr 13 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/errors.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // AnError is an error instance useful for testing. If the code does not care 8 | // about error specifics, and only needs to return the error for example, this 9 | // error should be used to make the test code more readable. 10 | var AnError = errors.New("assert.AnError general error for testing") 11 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/mksyscall.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build generate 6 | 7 | package windows 8 | 9 | //go:generate go run golang.org/x/sys/windows/mkwinsyscall -output zsyscall_windows.go eventlog.go service.go syscall_windows.go security_windows.go setupapi_windows.go 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # For more information about the properties used in 2 | # this file, please see the EditorConfig documentation: 3 | # http://editorconfig.org/ 4 | root = true 5 | 6 | [*] 7 | charset = utf-8 8 | end_of_line = lf 9 | indent_size = 4 10 | indent_style = tab 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | spaces_around_brackets = outside 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | indent_style = space 18 | 19 | [*.patch] 20 | indent_style = space 21 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BUILD_IMAGE=golang:1.23-alpine 2 | 3 | FROM $BUILD_IMAGE as builder 4 | 5 | COPY . /build 6 | 7 | RUN cd /build/contrib/client && CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -a -o client . 8 | RUN cd /build/contrib/server && CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -a -o server . 9 | 10 | FROM scratch 11 | 12 | COPY --from=builder /build/contrib/client/client /bin/srt-client 13 | COPY --from=builder /build/contrib/server/server /bin/srt-server 14 | 15 | WORKDIR /srt 16 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | All versions in the list receive security updates. 6 | 7 | | Version | Supported | 8 | | ------- | ------------------ | 9 | | 0.1.1 | :white_check_mark: | 10 | | - | :x: | 11 | 12 | ## Reporting a Vulnerability 13 | 14 | If you have found or just suspect a security problem somewhere in Restreamer or Core, report it on support@datarhei.com. 15 | 16 | We treat security issues with confidentiality until controlled and disclosed responsibly. 17 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/forward_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=assert -template=assertion_forward.go.tmpl -include-format-funcs" 17 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/forward_requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // Assertions provides assertion methods around the 4 | // TestingT interface. 5 | type Assertions struct { 6 | t TestingT 7 | } 8 | 9 | // New makes a new Assertions object for the specified TestingT. 10 | func New(t TestingT) *Assertions { 11 | return &Assertions{ 12 | t: t, 13 | } 14 | } 15 | 16 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require_forward.go.tmpl -include-format-funcs" 17 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/datarhei/gosrt 2 | 3 | go 1.24.0 4 | 5 | require ( 6 | github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c 7 | github.com/pkg/profile v1.7.0 8 | github.com/stretchr/testify v1.11.1 9 | golang.org/x/sys v0.38.0 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/felixge/fgprof v0.9.3 // indirect 15 | github.com/google/pprof v0.0.0-20211214055906-6f57359322fd // indirect 16 | github.com/pmezard/go-difflib v1.0.0 // indirect 17 | gopkg.in/yaml.v3 v3.0.1 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/race0.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build windows && !race 6 | 7 | package windows 8 | 9 | import ( 10 | "unsafe" 11 | ) 12 | 13 | const raceenabled = false 14 | 15 | func raceAcquire(addr unsafe.Pointer) { 16 | } 17 | 18 | func raceReleaseMerge(addr unsafe.Pointer) { 19 | } 20 | 21 | func raceReadRange(addr unsafe.Pointer, len int) { 22 | } 23 | 24 | func raceWriteRange(addr unsafe.Pointer, len int) { 25 | } 26 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/str.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build windows 6 | 7 | package windows 8 | 9 | func itoa(val int) string { // do it here rather than with fmt to avoid dependency 10 | if val < 0 { 11 | return "-" + itoa(-val) 12 | } 13 | var buf [32]byte // big enough for int64 14 | i := len(buf) - 1 15 | for val >= 10 { 16 | buf[i] = byte(val%10 + '0') 17 | i-- 18 | val /= 10 19 | } 20 | buf[i] = byte(val + '0') 21 | return string(buf[i:]) 22 | } 23 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2011-2016 Canonical Ltd. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/yaml/yaml_fail.go: -------------------------------------------------------------------------------- 1 | //go:build testify_yaml_fail && !testify_yaml_custom && !testify_yaml_default 2 | 3 | // Package yaml is an implementation of YAML functions that always fail. 4 | // 5 | // This implementation can be used at build time to replace the default implementation 6 | // to avoid linking with [gopkg.in/yaml.v3]: 7 | // 8 | // go test -tags testify_yaml_fail 9 | package yaml 10 | 11 | import "errors" 12 | 13 | var errNotImplemented = errors.New("YAML functions are not available (see https://pkg.go.dev/github.com/stretchr/testify/assert/yaml)") 14 | 15 | func Unmarshal([]byte, interface{}) error { 16 | return errNotImplemented 17 | } 18 | -------------------------------------------------------------------------------- /vendor/github.com/google/pprof/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # People who have agreed to one of the CLAs and can contribute patches. 2 | # The AUTHORS file lists the copyright holders; this file 3 | # lists people. For example, Google employees are listed here 4 | # but not in AUTHORS, because Google holds the copyright. 5 | # 6 | # https://developers.google.com/open-source/cla/individual 7 | # https://developers.google.com/open-source/cla/corporate 8 | # 9 | # Names should be added to this file as: 10 | # Name 11 | Raul Silvera 12 | Tipp Moseley 13 | Hyoun Kyu Cho 14 | Martin Spier 15 | Taco de Wolff 16 | Andrew Hunter 17 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/race.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build windows && race 6 | 7 | package windows 8 | 9 | import ( 10 | "runtime" 11 | "unsafe" 12 | ) 13 | 14 | const raceenabled = true 15 | 16 | func raceAcquire(addr unsafe.Pointer) { 17 | runtime.RaceAcquire(addr) 18 | } 19 | 20 | func raceReleaseMerge(addr unsafe.Pointer) { 21 | runtime.RaceReleaseMerge(addr) 22 | } 23 | 24 | func raceReadRange(addr unsafe.Pointer, len int) { 25 | runtime.RaceReadRange(addr, len) 26 | } 27 | 28 | func raceWriteRange(addr unsafe.Pointer, len int) { 29 | runtime.RaceWriteRange(addr, len) 30 | } 31 | -------------------------------------------------------------------------------- /.github/workflows/go-tests.yml: -------------------------------------------------------------------------------- 1 | name: tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v4 10 | with: 11 | fetch-depth: 2 12 | - uses: actions/setup-go@v5 13 | with: 14 | go-version: "1.24" 15 | - name: Run coverage 16 | run: go test -coverprofile=coverage.out -covermode=atomic -race -v ./... 17 | - name: Upload coverage to Codecov 18 | uses: codecov/codecov-action@v5 19 | with: 20 | token: ${{ secrets.CODECOV_TOKEN }} 21 | files: coverage.out 22 | flags: unit-linux 23 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2012-2016 Dave Collins 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /net/syncookie_test.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestSYNCookie(t *testing.T) { 10 | counter := int64(0) 11 | 12 | s, err := NewSYNCookie("192.168.0.1", func() int64 { 13 | return counter 14 | }) 15 | require.NoError(t, err) 16 | 17 | s.secret1 = "dl2INvNSQTZ5zQu9MxNmGyAVmNkB33io" 18 | s.secret2 = "nwj2qrsh3xyC8OmCp1gObD0iOtQNQsLi" 19 | 20 | cookie := s.Get("192.168.0.2") 21 | 22 | require.Equal(t, uint32(0xe6303651), cookie) 23 | 24 | require.True(t, s.Verify(cookie, "192.168.0.2")) 25 | 26 | require.False(t, s.Verify(cookie, "192.168.0.3")) 27 | require.False(t, s.Verify(cookie-95854, "192.168.0.2")) 28 | 29 | counter = 1 30 | 31 | require.True(t, s.Verify(cookie, "192.168.0.2")) 32 | 33 | counter = 2 34 | 35 | require.False(t, s.Verify(cookie, "192.168.0.2")) 36 | } 37 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/yaml/yaml_custom.go: -------------------------------------------------------------------------------- 1 | //go:build testify_yaml_custom && !testify_yaml_fail && !testify_yaml_default 2 | 3 | // Package yaml is an implementation of YAML functions that calls a pluggable implementation. 4 | // 5 | // This implementation is selected with the testify_yaml_custom build tag. 6 | // 7 | // go test -tags testify_yaml_custom 8 | // 9 | // This implementation can be used at build time to replace the default implementation 10 | // to avoid linking with [gopkg.in/yaml.v3]. 11 | // 12 | // In your test package: 13 | // 14 | // import assertYaml "github.com/stretchr/testify/assert/yaml" 15 | // 16 | // func init() { 17 | // assertYaml.Unmarshal = func (in []byte, out interface{}) error { 18 | // // ... 19 | // return nil 20 | // } 21 | // } 22 | package yaml 23 | 24 | var Unmarshal func(in []byte, out interface{}) error 25 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/eventlog.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build windows 6 | 7 | package windows 8 | 9 | const ( 10 | EVENTLOG_SUCCESS = 0 11 | EVENTLOG_ERROR_TYPE = 1 12 | EVENTLOG_WARNING_TYPE = 2 13 | EVENTLOG_INFORMATION_TYPE = 4 14 | EVENTLOG_AUDIT_SUCCESS = 8 15 | EVENTLOG_AUDIT_FAILURE = 16 16 | ) 17 | 18 | //sys RegisterEventSource(uncServerName *uint16, sourceName *uint16) (handle Handle, err error) [failretval==0] = advapi32.RegisterEventSourceW 19 | //sys DeregisterEventSource(handle Handle) (err error) = advapi32.DeregisterEventSource 20 | //sys ReportEvent(log Handle, etype uint16, category uint16, eventId uint32, usrSId uintptr, numStrings uint16, dataSize uint32, strings **uint16, rawData *byte) (err error) = advapi32.ReportEventW 21 | -------------------------------------------------------------------------------- /vendor/modules.txt: -------------------------------------------------------------------------------- 1 | # github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c 2 | ## explicit 3 | github.com/benburkert/openpgp/aes/keywrap 4 | # github.com/davecgh/go-spew v1.1.1 5 | ## explicit 6 | github.com/davecgh/go-spew/spew 7 | # github.com/felixge/fgprof v0.9.3 8 | ## explicit; go 1.14 9 | github.com/felixge/fgprof 10 | # github.com/google/pprof v0.0.0-20211214055906-6f57359322fd 11 | ## explicit; go 1.14 12 | github.com/google/pprof/profile 13 | # github.com/pkg/profile v1.7.0 14 | ## explicit; go 1.13 15 | github.com/pkg/profile 16 | # github.com/pmezard/go-difflib v1.0.0 17 | ## explicit 18 | github.com/pmezard/go-difflib/difflib 19 | # github.com/stretchr/testify v1.11.1 20 | ## explicit; go 1.17 21 | github.com/stretchr/testify/assert 22 | github.com/stretchr/testify/assert/yaml 23 | github.com/stretchr/testify/require 24 | # golang.org/x/sys v0.38.0 25 | ## explicit; go 1.24.0 26 | golang.org/x/sys/windows 27 | # gopkg.in/yaml.v3 v3.0.1 28 | ## explicit 29 | gopkg.in/yaml.v3 30 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/types_windows_amd64.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package windows 6 | 7 | type WSAData struct { 8 | Version uint16 9 | HighVersion uint16 10 | MaxSockets uint16 11 | MaxUdpDg uint16 12 | VendorInfo *byte 13 | Description [WSADESCRIPTION_LEN + 1]byte 14 | SystemStatus [WSASYS_STATUS_LEN + 1]byte 15 | } 16 | 17 | type Servent struct { 18 | Name *byte 19 | Aliases **byte 20 | Proto *byte 21 | Port uint16 22 | } 23 | 24 | type JOBOBJECT_BASIC_LIMIT_INFORMATION struct { 25 | PerProcessUserTimeLimit int64 26 | PerJobUserTimeLimit int64 27 | LimitFlags uint32 28 | MinimumWorkingSetSize uintptr 29 | MaximumWorkingSetSize uintptr 30 | ActiveProcessLimit uint32 31 | Affinity uintptr 32 | PriorityClass uint32 33 | SchedulingClass uint32 34 | } 35 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/types_windows_arm64.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package windows 6 | 7 | type WSAData struct { 8 | Version uint16 9 | HighVersion uint16 10 | MaxSockets uint16 11 | MaxUdpDg uint16 12 | VendorInfo *byte 13 | Description [WSADESCRIPTION_LEN + 1]byte 14 | SystemStatus [WSASYS_STATUS_LEN + 1]byte 15 | } 16 | 17 | type Servent struct { 18 | Name *byte 19 | Aliases **byte 20 | Proto *byte 21 | Port uint16 22 | } 23 | 24 | type JOBOBJECT_BASIC_LIMIT_INFORMATION struct { 25 | PerProcessUserTimeLimit int64 26 | PerJobUserTimeLimit int64 27 | LimitFlags uint32 28 | MinimumWorkingSetSize uintptr 29 | MaximumWorkingSetSize uintptr 30 | ActiveProcessLimit uint32 31 | Affinity uintptr 32 | PriorityClass uint32 33 | SchedulingClass uint32 34 | } 35 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/types_windows_386.go: -------------------------------------------------------------------------------- 1 | // Copyright 2011 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package windows 6 | 7 | type WSAData struct { 8 | Version uint16 9 | HighVersion uint16 10 | Description [WSADESCRIPTION_LEN + 1]byte 11 | SystemStatus [WSASYS_STATUS_LEN + 1]byte 12 | MaxSockets uint16 13 | MaxUdpDg uint16 14 | VendorInfo *byte 15 | } 16 | 17 | type Servent struct { 18 | Name *byte 19 | Aliases **byte 20 | Port uint16 21 | Proto *byte 22 | } 23 | 24 | type JOBOBJECT_BASIC_LIMIT_INFORMATION struct { 25 | PerProcessUserTimeLimit int64 26 | PerJobUserTimeLimit int64 27 | LimitFlags uint32 28 | MinimumWorkingSetSize uintptr 29 | MaximumWorkingSetSize uintptr 30 | ActiveProcessLimit uint32 31 | Affinity uintptr 32 | PriorityClass uint32 33 | SchedulingClass uint32 34 | _ uint32 // pad to 8 byte boundary 35 | } 36 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/types_windows_arm.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package windows 6 | 7 | type WSAData struct { 8 | Version uint16 9 | HighVersion uint16 10 | Description [WSADESCRIPTION_LEN + 1]byte 11 | SystemStatus [WSASYS_STATUS_LEN + 1]byte 12 | MaxSockets uint16 13 | MaxUdpDg uint16 14 | VendorInfo *byte 15 | } 16 | 17 | type Servent struct { 18 | Name *byte 19 | Aliases **byte 20 | Port uint16 21 | Proto *byte 22 | } 23 | 24 | type JOBOBJECT_BASIC_LIMIT_INFORMATION struct { 25 | PerProcessUserTimeLimit int64 26 | PerJobUserTimeLimit int64 27 | LimitFlags uint32 28 | MinimumWorkingSetSize uintptr 29 | MaximumWorkingSetSize uintptr 30 | ActiveProcessLimit uint32 31 | Affinity uintptr 32 | PriorityClass uint32 33 | SchedulingClass uint32 34 | _ uint32 // pad to 8 byte boundary 35 | } 36 | -------------------------------------------------------------------------------- /vendor/github.com/felixge/fgprof/handler.go: -------------------------------------------------------------------------------- 1 | package fgprof 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "strconv" 7 | "time" 8 | ) 9 | 10 | // Handler returns an http handler that takes an optional "seconds" query 11 | // argument that defaults to "30" and produces a profile over this duration. 12 | // The optional "format" parameter controls if the output is written in 13 | // Google's "pprof" format (default) or Brendan Gregg's "folded" stack format. 14 | func Handler() http.Handler { 15 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 16 | var seconds int 17 | var err error 18 | if s := r.URL.Query().Get("seconds"); s == "" { 19 | seconds = 30 20 | } else if seconds, err = strconv.Atoi(s); err != nil || seconds <= 0 { 21 | w.WriteHeader(http.StatusBadRequest) 22 | fmt.Fprintf(w, "bad seconds: %d: %s\n", seconds, err) 23 | return 24 | } 25 | 26 | format := Format(r.URL.Query().Get("format")) 27 | if format == "" { 28 | format = FormatPprof 29 | } 30 | 31 | stop := Start(w, format) 32 | defer stop() 33 | time.Sleep(time.Duration(seconds) * time.Second) 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /vendor/github.com/felixge/fgprof/LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright © 2020 Felix Geisendörfer 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2022 FOSS GmbH 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /rand/rand_test.go: -------------------------------------------------------------------------------- 1 | package rand 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestRandomString(t *testing.T) { 10 | s1, err := RandomString(42, AlphaNumericCharset) 11 | require.NoError(t, err) 12 | 13 | s2, err := RandomString(42, AlphaNumericCharset) 14 | require.NoError(t, err) 15 | 16 | require.NotEqual(t, s1, s2) 17 | } 18 | 19 | func TestUint32(t *testing.T) { 20 | u1, err := Uint32() 21 | require.NoError(t, err) 22 | 23 | u2, err := Uint32() 24 | require.NoError(t, err) 25 | 26 | require.NotEqual(t, u1, u2) 27 | } 28 | 29 | func TestInt63(t *testing.T) { 30 | u1, err := Int63() 31 | require.NoError(t, err) 32 | 33 | u2, err := Int63() 34 | require.NoError(t, err) 35 | 36 | require.NotEqual(t, u1, u2) 37 | } 38 | 39 | func TestInt63n(t *testing.T) { 40 | u1, err := Int63n(42) 41 | require.NoError(t, err) 42 | 43 | u2, err := Int63n(42) 44 | require.NoError(t, err) 45 | 46 | require.NotEqual(t, u1, u2) 47 | 48 | u3, err := Int63n(64) 49 | require.NoError(t, err) 50 | 51 | u4, err := Int63n(64) 52 | require.NoError(t, err) 53 | 54 | require.NotEqual(t, u3, u4) 55 | } 56 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/doc.go: -------------------------------------------------------------------------------- 1 | // Package require implements the same assertions as the `assert` package but 2 | // stops test execution when a test fails. 3 | // 4 | // # Example Usage 5 | // 6 | // The following is a complete example using require in a standard test function: 7 | // 8 | // import ( 9 | // "testing" 10 | // "github.com/stretchr/testify/require" 11 | // ) 12 | // 13 | // func TestSomething(t *testing.T) { 14 | // 15 | // var a string = "Hello" 16 | // var b string = "Hello" 17 | // 18 | // require.Equal(t, a, b, "The two words should be the same.") 19 | // 20 | // } 21 | // 22 | // # Assertions 23 | // 24 | // The `require` package have same global functions as in the `assert` package, 25 | // but instead of returning a boolean result they call `t.FailNow()`. 26 | // A consequence of this is that it must be called from the goroutine running 27 | // the test function, not from other goroutines created during the test. 28 | // 29 | // Every assertion function also takes an optional string message as the final argument, 30 | // allowing custom error messages to be appended to the message the assertion method outputs. 31 | package require 32 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012-2020 Mat Ryer, Tyler Bunnell and contributors. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/require/requirements.go: -------------------------------------------------------------------------------- 1 | package require 2 | 3 | // TestingT is an interface wrapper around *testing.T 4 | type TestingT interface { 5 | Errorf(format string, args ...interface{}) 6 | FailNow() 7 | } 8 | 9 | type tHelper = interface { 10 | Helper() 11 | } 12 | 13 | // ComparisonAssertionFunc is a common function prototype when comparing two values. Can be useful 14 | // for table driven tests. 15 | type ComparisonAssertionFunc func(TestingT, interface{}, interface{}, ...interface{}) 16 | 17 | // ValueAssertionFunc is a common function prototype when validating a single value. Can be useful 18 | // for table driven tests. 19 | type ValueAssertionFunc func(TestingT, interface{}, ...interface{}) 20 | 21 | // BoolAssertionFunc is a common function prototype when validating a bool value. Can be useful 22 | // for table driven tests. 23 | type BoolAssertionFunc func(TestingT, bool, ...interface{}) 24 | 25 | // ErrorAssertionFunc is a common function prototype when validating an error value. Can be useful 26 | // for table driven tests. 27 | type ErrorAssertionFunc func(TestingT, error, ...interface{}) 28 | 29 | //go:generate sh -c "cd ../_codegen && go build && cd - && ../_codegen/_codegen -output-package=require -template=require.go.tmpl -include-format-funcs" 30 | -------------------------------------------------------------------------------- /server_test.go: -------------------------------------------------------------------------------- 1 | package srt 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestServer(t *testing.T) { 10 | server := Server{ 11 | Addr: "127.0.0.1:6003", 12 | HandleConnect: func(req ConnRequest) ConnType { 13 | streamid := req.StreamId() 14 | 15 | if streamid == "publish" { 16 | return PUBLISH 17 | } else if streamid == "subscribe" { 18 | return SUBSCRIBE 19 | } 20 | 21 | return REJECT 22 | }, 23 | } 24 | 25 | err := server.Listen() 26 | require.NoError(t, err) 27 | 28 | defer server.Shutdown() 29 | 30 | go func() { 31 | err := server.Serve() 32 | if err == ErrServerClosed { 33 | return 34 | } 35 | require.NoError(t, err) 36 | }() 37 | 38 | config := DefaultConfig() 39 | config.StreamId = "publish" 40 | 41 | conn, err := Dial("srt", "127.0.0.1:6003", config) 42 | require.NoError(t, err) 43 | 44 | err = conn.Close() 45 | require.NoError(t, err) 46 | 47 | config = DefaultConfig() 48 | config.StreamId = "subscribe" 49 | 50 | conn, err = Dial("srt", "127.0.0.1:6003", config) 51 | require.NoError(t, err) 52 | 53 | err = conn.Close() 54 | require.NoError(t, err) 55 | 56 | config = DefaultConfig() 57 | config.StreamId = "nothing" 58 | 59 | _, err = Dial("srt", "127.0.0.1:6003", config) 60 | require.Error(t, err) 61 | } 62 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Go project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Go, where such license applies only to those patent 11 | claims, both currently owned or controlled by Google and acquired in 12 | the future, licensable by Google that are necessarily infringed by this 13 | implementation of Go. This grant does not include claims that would be 14 | infringed only as a consequence of further modification of this 15 | implementation. If you or your agent or exclusive licensee institute or 16 | order or agree to the institution of patent litigation against any 17 | entity (including a cross-claim or counterclaim in a lawsuit) alleging 18 | that this implementation of Go or any code incorporated within this 19 | implementation of Go constitutes direct or contributory patent 20 | infringement, or inducement of patent infringement, then any patent 21 | rights granted to you under this License for this implementation of Go 22 | shall terminate as of the date such litigation is filed. 23 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/profile/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Dave Cheney. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 15 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 16 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 17 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 18 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 20 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /log_test.go: -------------------------------------------------------------------------------- 1 | package srt 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/require" 7 | ) 8 | 9 | func TestHasTopic(t *testing.T) { 10 | l := NewLogger([]string{ 11 | "packet:recv:dump", 12 | }) 13 | 14 | ok := l.HasTopic("foobar") 15 | require.False(t, ok) 16 | 17 | ok = l.HasTopic("packet:recv:dump") 18 | require.True(t, ok) 19 | 20 | ok = l.HasTopic("packet:recv") 21 | require.False(t, ok) 22 | 23 | ok = l.HasTopic("packet") 24 | require.False(t, ok) 25 | } 26 | 27 | var result bool 28 | 29 | func BenchmarkHasTopicNil(b *testing.B) { 30 | l := NewLogger(nil) 31 | 32 | var r bool 33 | for n := 0; n < b.N; n++ { 34 | r = l.HasTopic("foobar") 35 | } 36 | 37 | result = r 38 | } 39 | 40 | func BenchmarkHasTopicD1(b *testing.B) { 41 | l := NewLogger([]string{ 42 | "packet:recv:dump", 43 | }) 44 | 45 | var r bool 46 | for n := 0; n < b.N; n++ { 47 | r = l.HasTopic("packet") 48 | } 49 | 50 | result = r 51 | } 52 | 53 | func BenchmarkHasTopicD2(b *testing.B) { 54 | l := NewLogger([]string{ 55 | "packet:recv:dump", 56 | }) 57 | 58 | var r bool 59 | for n := 0; n < b.N; n++ { 60 | r = l.HasTopic("packet:recv") 61 | } 62 | 63 | result = r 64 | } 65 | 66 | func BenchmarkHasTopicD3(b *testing.B) { 67 | l := NewLogger([]string{ 68 | "packet:recv:dump", 69 | }) 70 | 71 | var r bool 72 | for n := 0; n < b.N; n++ { 73 | r = l.HasTopic("packet:recv:dump") 74 | } 75 | 76 | result = r 77 | } 78 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/mkknownfolderids.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2019 The Go Authors. All rights reserved. 4 | # Use of this source code is governed by a BSD-style 5 | # license that can be found in the LICENSE file. 6 | 7 | set -e 8 | shopt -s nullglob 9 | 10 | knownfolders="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/um/KnownFolders.h | sort -Vr | head -n 1)" 11 | [[ -n $knownfolders ]] || { echo "Unable to find KnownFolders.h" >&2; exit 1; } 12 | 13 | { 14 | echo "// Code generated by 'mkknownfolderids.bash'; DO NOT EDIT." 15 | echo 16 | echo "package windows" 17 | echo "type KNOWNFOLDERID GUID" 18 | echo "var (" 19 | while read -r line; do 20 | [[ $line =~ DEFINE_KNOWN_FOLDER\((FOLDERID_[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+),[\t\ ]*(0x[^,]+)\) ]] || continue 21 | printf "%s = &KNOWNFOLDERID{0x%08x, 0x%04x, 0x%04x, [8]byte{0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x}}\n" \ 22 | "${BASH_REMATCH[1]}" $(( "${BASH_REMATCH[2]}" )) $(( "${BASH_REMATCH[3]}" )) $(( "${BASH_REMATCH[4]}" )) \ 23 | $(( "${BASH_REMATCH[5]}" )) $(( "${BASH_REMATCH[6]}" )) $(( "${BASH_REMATCH[7]}" )) $(( "${BASH_REMATCH[8]}" )) \ 24 | $(( "${BASH_REMATCH[9]}" )) $(( "${BASH_REMATCH[10]}" )) $(( "${BASH_REMATCH[11]}" )) $(( "${BASH_REMATCH[12]}" )) 25 | done < "$knownfolders" 26 | echo ")" 27 | } | gofmt > "zknownfolderids_windows.go" 28 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2009 The Go Authors. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of Google LLC nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /vendor/github.com/pmezard/go-difflib/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Patrick Mezard 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | The names of its contributors may not be used to endorse or promote 14 | products derived from this software without specific prior written 15 | permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 18 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 20 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 23 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 24 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 25 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 26 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package srt provides an interface for network I/O using the SRT protocol (https://github.com/Haivision/srt). 3 | 4 | The package gives access to the basic interface provided by the Dial, Listen, and Accept functions and the associated 5 | Conn and Listener interfaces. 6 | 7 | The Dial function connects to a server: 8 | 9 | conn, err := srt.Dial("srt", "golang.org:6000", srt.Config{ 10 | StreamId: "...", 11 | }) 12 | if err != nil { 13 | // handle error 14 | } 15 | 16 | buffer := make([]byte, 2048) 17 | 18 | for { 19 | n, err := conn.Read(buffer) 20 | if err != nil { 21 | // handle error 22 | } 23 | 24 | // handle received data 25 | } 26 | 27 | conn.Close() 28 | 29 | The Listen function creates servers: 30 | 31 | ln, err := srt.Listen("srt", ":6000", srt.Config{...}) 32 | if err != nil { 33 | // handle error 34 | } 35 | 36 | for { 37 | conn, mode, err := ln.Accept(handleConnect) 38 | if err != nil { 39 | // handle error 40 | } 41 | 42 | if mode == srt.REJECT { 43 | // rejected connection, ignore 44 | continue 45 | } 46 | 47 | if mode == srt.PUBLISH { 48 | go handlePublish(conn) 49 | } else { 50 | go handleSubscribe(conn) 51 | } 52 | } 53 | 54 | The ln.Accept function expects a function that takes a srt.ConnRequest 55 | and returns a srt.ConnType. The srt.ConnRequest lets you retrieve the 56 | streamid with on which you can decide what mode (srt.ConnType) to return. 57 | 58 | Check out the Server type that wraps the Listen and Accept into a 59 | convenient framework for your own SRT server. 60 | */ 61 | package srt 62 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/memory_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2017 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package windows 6 | 7 | const ( 8 | MEM_COMMIT = 0x00001000 9 | MEM_RESERVE = 0x00002000 10 | MEM_DECOMMIT = 0x00004000 11 | MEM_RELEASE = 0x00008000 12 | MEM_RESET = 0x00080000 13 | MEM_TOP_DOWN = 0x00100000 14 | MEM_WRITE_WATCH = 0x00200000 15 | MEM_PHYSICAL = 0x00400000 16 | MEM_RESET_UNDO = 0x01000000 17 | MEM_LARGE_PAGES = 0x20000000 18 | 19 | PAGE_NOACCESS = 0x00000001 20 | PAGE_READONLY = 0x00000002 21 | PAGE_READWRITE = 0x00000004 22 | PAGE_WRITECOPY = 0x00000008 23 | PAGE_EXECUTE = 0x00000010 24 | PAGE_EXECUTE_READ = 0x00000020 25 | PAGE_EXECUTE_READWRITE = 0x00000040 26 | PAGE_EXECUTE_WRITECOPY = 0x00000080 27 | PAGE_GUARD = 0x00000100 28 | PAGE_NOCACHE = 0x00000200 29 | PAGE_WRITECOMBINE = 0x00000400 30 | PAGE_TARGETS_INVALID = 0x40000000 31 | PAGE_TARGETS_NO_UPDATE = 0x40000000 32 | 33 | QUOTA_LIMITS_HARDWS_MIN_DISABLE = 0x00000002 34 | QUOTA_LIMITS_HARDWS_MIN_ENABLE = 0x00000001 35 | QUOTA_LIMITS_HARDWS_MAX_DISABLE = 0x00000008 36 | QUOTA_LIMITS_HARDWS_MAX_ENABLE = 0x00000004 37 | ) 38 | 39 | type MemoryBasicInformation struct { 40 | BaseAddress uintptr 41 | AllocationBase uintptr 42 | AllocationProtect uint32 43 | PartitionId uint16 44 | RegionSize uintptr 45 | State uint32 46 | Protect uint32 47 | Type uint32 48 | } 49 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/env_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2010 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Windows environment variables. 6 | 7 | package windows 8 | 9 | import ( 10 | "syscall" 11 | "unsafe" 12 | ) 13 | 14 | func Getenv(key string) (value string, found bool) { 15 | return syscall.Getenv(key) 16 | } 17 | 18 | func Setenv(key, value string) error { 19 | return syscall.Setenv(key, value) 20 | } 21 | 22 | func Clearenv() { 23 | syscall.Clearenv() 24 | } 25 | 26 | func Environ() []string { 27 | return syscall.Environ() 28 | } 29 | 30 | // Returns a default environment associated with the token, rather than the current 31 | // process. If inheritExisting is true, then this environment also inherits the 32 | // environment of the current process. 33 | func (token Token) Environ(inheritExisting bool) (env []string, err error) { 34 | var block *uint16 35 | err = CreateEnvironmentBlock(&block, token, inheritExisting) 36 | if err != nil { 37 | return nil, err 38 | } 39 | defer DestroyEnvironmentBlock(block) 40 | size := unsafe.Sizeof(*block) 41 | for *block != 0 { 42 | // find NUL terminator 43 | end := unsafe.Pointer(block) 44 | for *(*uint16)(end) != 0 { 45 | end = unsafe.Add(end, size) 46 | } 47 | 48 | entry := unsafe.Slice(block, (uintptr(end)-uintptr(unsafe.Pointer(block)))/size) 49 | env = append(env, UTF16ToString(entry)) 50 | block = (*uint16)(unsafe.Add(end, size)) 51 | } 52 | return env, nil 53 | } 54 | 55 | func Unsetenv(key string) error { 56 | return syscall.Unsetenv(key) 57 | } 58 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | Contributor Code of Conduct 2 | =========================== 3 | 4 | As contributors and maintainers of this project, we pledge to respect all 5 | people who contribute through reporting issues, posting feature requests, 6 | updating documentation, submitting pull requests or patches, and other 7 | activities. 8 | 9 | Examples of unacceptable behavior by participants include: 10 | - Sexual language or imagery. 11 | - Derogatory comments or personal attacks. 12 | - Trolling, public or private harassment. 13 | - Insults. 14 | - Other unprofessional conduct. 15 | 16 | Examples of unacceptable behavior by participants include sexual 17 | language or imagery, derogatory comments or personal attacks, trolling, public 18 | or private harassment, insults, or other unprofessional conduct. 19 | 20 | Project maintainers have the right and responsibility to remove, edit, or reject 21 | comments, commits, code, wiki edits, issues, and other contributions that are not 22 | aligned with this Code of Conduct. In addition, project maintainers who do not 23 | follow the Code of Conduct may be removed from the project team. 24 | 25 | This code of conduct applies both within a project and in public spaces when an 26 | individual represents the project or its community. 27 | 28 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 29 | reported by opening an issue or contacting one or more of the project maintainers. 30 | 31 | This Code of Conduct is adapted from the [Contributor 32 | Covenant](https://contributor-covenant.org/), version 1.1.0, available at 33 | [https://contributor-covenant.org/version/1/1/0/](https://contributor-covenant.org/version/1/1/0/) 34 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/doc.go: -------------------------------------------------------------------------------- 1 | // Package assert provides a set of comprehensive testing tools for use with the normal Go testing system. 2 | // 3 | // # Note 4 | // 5 | // All functions in this package return a bool value indicating whether the assertion has passed. 6 | // 7 | // # Example Usage 8 | // 9 | // The following is a complete example using assert in a standard test function: 10 | // 11 | // import ( 12 | // "testing" 13 | // "github.com/stretchr/testify/assert" 14 | // ) 15 | // 16 | // func TestSomething(t *testing.T) { 17 | // 18 | // var a string = "Hello" 19 | // var b string = "Hello" 20 | // 21 | // assert.Equal(t, a, b, "The two words should be the same.") 22 | // 23 | // } 24 | // 25 | // if you assert many times, use the format below: 26 | // 27 | // import ( 28 | // "testing" 29 | // "github.com/stretchr/testify/assert" 30 | // ) 31 | // 32 | // func TestSomething(t *testing.T) { 33 | // assert := assert.New(t) 34 | // 35 | // var a string = "Hello" 36 | // var b string = "Hello" 37 | // 38 | // assert.Equal(a, b, "The two words should be the same.") 39 | // } 40 | // 41 | // # Assertions 42 | // 43 | // Assertions allow you to easily write test code, and are global funcs in the `assert` package. 44 | // All assertion functions take, as the first argument, the `*testing.T` object provided by the 45 | // testing framework. This allows the assertion funcs to write the failings and other details to 46 | // the correct place. 47 | // 48 | // Every assertion function also takes an optional string message as the final argument, 49 | // allowing custom error messages to be appended to the message the assertion method outputs. 50 | package assert 51 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/yaml/yaml_default.go: -------------------------------------------------------------------------------- 1 | //go:build !testify_yaml_fail && !testify_yaml_custom 2 | 3 | // Package yaml is just an indirection to handle YAML deserialization. 4 | // 5 | // This package is just an indirection that allows the builder to override the 6 | // indirection with an alternative implementation of this package that uses 7 | // another implementation of YAML deserialization. This allows to not either not 8 | // use YAML deserialization at all, or to use another implementation than 9 | // [gopkg.in/yaml.v3] (for example for license compatibility reasons, see [PR #1120]). 10 | // 11 | // Alternative implementations are selected using build tags: 12 | // 13 | // - testify_yaml_fail: [Unmarshal] always fails with an error 14 | // - testify_yaml_custom: [Unmarshal] is a variable. Caller must initialize it 15 | // before calling any of [github.com/stretchr/testify/assert.YAMLEq] or 16 | // [github.com/stretchr/testify/assert.YAMLEqf]. 17 | // 18 | // Usage: 19 | // 20 | // go test -tags testify_yaml_fail 21 | // 22 | // You can check with "go list" which implementation is linked: 23 | // 24 | // go list -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml 25 | // go list -tags testify_yaml_fail -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml 26 | // go list -tags testify_yaml_custom -f '{{.Imports}}' github.com/stretchr/testify/assert/yaml 27 | // 28 | // [PR #1120]: https://github.com/stretchr/testify/pull/1120 29 | package yaml 30 | 31 | import goyaml "gopkg.in/yaml.v3" 32 | 33 | // Unmarshal is just a wrapper of [gopkg.in/yaml.v3.Unmarshal]. 34 | func Unmarshal(in []byte, out interface{}) error { 35 | return goyaml.Unmarshal(in, out) 36 | } 37 | -------------------------------------------------------------------------------- /contrib/client/reader.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "io" 6 | "time" 7 | ) 8 | 9 | type Reader interface { 10 | io.ReadCloser 11 | } 12 | 13 | type debugReader struct { 14 | bytesPerSec uint64 15 | cancel context.CancelFunc 16 | data chan byte 17 | } 18 | 19 | type DebugReaderOptions struct { 20 | Bitrate uint64 21 | } 22 | 23 | func NewDebugReader(options DebugReaderOptions) (Reader, error) { 24 | r := &debugReader{ 25 | bytesPerSec: options.Bitrate / 8, 26 | } 27 | 28 | if r.bytesPerSec == 0 { 29 | r.bytesPerSec = 262_144 // 2Mbit/s 30 | } 31 | 32 | r.data = make(chan byte, r.bytesPerSec) 33 | 34 | ctx, cancel := context.WithCancel(context.Background()) 35 | r.cancel = cancel 36 | 37 | go r.generator(ctx) 38 | 39 | return r, nil 40 | } 41 | 42 | func (r *debugReader) Read(p []byte) (int, error) { 43 | len := len(p) 44 | 45 | if len == 0 { 46 | return 0, nil 47 | } 48 | 49 | var i int = 0 50 | 51 | for b := range r.data { 52 | p[i] = b 53 | 54 | i += 1 55 | if i == len { 56 | break 57 | } 58 | } 59 | 60 | return i, nil 61 | } 62 | 63 | func (r *debugReader) Close() error { 64 | r.cancel() 65 | 66 | return nil 67 | } 68 | 69 | func (r *debugReader) generator(ctx context.Context) { 70 | t := time.NewTicker(100 * time.Millisecond) 71 | defer t.Stop() 72 | 73 | s := "abcdefghijklmnopqrstuvwxyz*" 74 | pivot := 0 75 | 76 | defer func() { close(r.data) }() 77 | 78 | for { 79 | select { 80 | case <-ctx.Done(): 81 | return 82 | case <-t.C: 83 | for i := uint64(0); i < r.bytesPerSec/10; i += 1 { 84 | r.data <- s[pivot] 85 | pivot += 1 86 | if pivot >= len(s) { 87 | pivot = 0 88 | } 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /net.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | 3 | package srt 4 | 5 | import "syscall" 6 | 7 | func ListenControl(config Config) func(network, address string, c syscall.RawConn) error { 8 | return func(network, address string, c syscall.RawConn) error { 9 | var opErr error 10 | err := c.Control(func(fd uintptr) { 11 | // Set REUSEADDR 12 | opErr = syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1) 13 | if opErr != nil { 14 | return 15 | } 16 | 17 | // Set TOS 18 | if config.IPTOS > 0 { 19 | opErr = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TOS, config.IPTOS) 20 | if opErr != nil { 21 | return 22 | } 23 | } 24 | 25 | // Set TTL 26 | if config.IPTTL > 0 { 27 | opErr = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TTL, config.IPTTL) 28 | if opErr != nil { 29 | return 30 | } 31 | } 32 | }) 33 | if err != nil { 34 | return err 35 | } 36 | return opErr 37 | } 38 | } 39 | 40 | func DialControl(config Config) func(network string, address string, c syscall.RawConn) error { 41 | return func(network, address string, c syscall.RawConn) error { 42 | var opErr error 43 | err := c.Control(func(fd uintptr) { 44 | // Set TOS 45 | if config.IPTOS > 0 { 46 | opErr = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TOS, config.IPTOS) 47 | if opErr != nil { 48 | return 49 | } 50 | } 51 | 52 | // Set TTL 53 | if config.IPTTL > 0 { 54 | opErr = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_IP, syscall.IP_TTL, config.IPTTL) 55 | if opErr != nil { 56 | return 57 | } 58 | } 59 | }) 60 | if err != nil { 61 | return err 62 | } 63 | return opErr 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /rand/rand.go: -------------------------------------------------------------------------------- 1 | package rand 2 | 3 | import "crypto/rand" 4 | 5 | var AlphaNumericCharset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 6 | 7 | // https://www.calhoun.io/creating-random-strings-in-go/ 8 | func RandomString(length int, charset string) (string, error) { 9 | b := make([]byte, length) 10 | for i := range b { 11 | j, err := Int63n(int64(len(charset))) 12 | if err != nil { 13 | return "", err 14 | } 15 | b[i] = charset[j] 16 | } 17 | 18 | return string(b), nil 19 | } 20 | 21 | func Read(b []byte) (int, error) { 22 | return rand.Read(b) 23 | } 24 | 25 | func Uint32() (uint32, error) { 26 | var b [4]byte 27 | _, err := rand.Read(b[:]) 28 | if err != nil { 29 | return 0, err 30 | } 31 | 32 | return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3]), nil 33 | } 34 | 35 | func Int63() (int64, error) { 36 | var b [8]byte 37 | _, err := rand.Read(b[:]) 38 | if err != nil { 39 | return 0, err 40 | } 41 | 42 | return int64(uint64(b[0]&0b01111111)<<56 | uint64(b[1])<<48 | uint64(b[2])<<40 | uint64(b[3])<<32 | 43 | uint64(b[4])<<24 | uint64(b[5])<<16 | uint64(b[6])<<8 | uint64(b[7])), nil 44 | } 45 | 46 | // https://cs.opensource.google/go/go/+/refs/tags/go1.20.4:src/math/rand/rand.go;l=119 47 | func Int63n(n int64) (int64, error) { 48 | if n&(n-1) == 0 { // n is power of two, can mask 49 | r, err := Int63() 50 | if err != nil { 51 | return 0, err 52 | } 53 | return r & (n - 1), nil 54 | } 55 | 56 | max := int64((1 << 63) - 1 - (1<<63)%uint64(n)) 57 | 58 | v, err := Int63() 59 | if err != nil { 60 | return 0, err 61 | } 62 | 63 | for v > max { 64 | v, err = Int63() 65 | if err != nil { 66 | return 0, err 67 | } 68 | } 69 | 70 | return v % n, nil 71 | } 72 | -------------------------------------------------------------------------------- /vendor/github.com/pkg/profile/README.md: -------------------------------------------------------------------------------- 1 | profile 2 | ======= 3 | 4 | Simple profiling support package for Go 5 | 6 | [![Build Status](https://travis-ci.org/pkg/profile.svg?branch=master)](https://travis-ci.org/pkg/profile) [![GoDoc](http://godoc.org/github.com/pkg/profile?status.svg)](http://godoc.org/github.com/pkg/profile) 7 | 8 | 9 | installation 10 | ------------ 11 | 12 | go get github.com/pkg/profile 13 | 14 | usage 15 | ----- 16 | 17 | Enabling profiling in your application is as simple as one line at the top of your main function 18 | 19 | ```go 20 | import "github.com/pkg/profile" 21 | 22 | func main() { 23 | defer profile.Start().Stop() 24 | ... 25 | } 26 | ``` 27 | 28 | options 29 | ------- 30 | 31 | What to profile is controlled by config value passed to profile.Start. 32 | By default CPU profiling is enabled. 33 | 34 | ```go 35 | import "github.com/pkg/profile" 36 | 37 | func main() { 38 | // p.Stop() must be called before the program exits to 39 | // ensure profiling information is written to disk. 40 | p := profile.Start(profile.MemProfile, profile.ProfilePath("."), profile.NoShutdownHook) 41 | ... 42 | // You can enable different kinds of memory profiling, either Heap or Allocs where Heap 43 | // profiling is the default with profile.MemProfile. 44 | p := profile.Start(profile.MemProfileAllocs, profile.ProfilePath("."), profile.NoShutdownHook) 45 | } 46 | ``` 47 | 48 | Several convenience package level values are provided for cpu, memory, and block (contention) profiling. 49 | 50 | For more complex options, consult the [documentation](http://godoc.org/github.com/pkg/profile). 51 | 52 | contributing 53 | ------------ 54 | 55 | We welcome pull requests, bug fixes and issue reports. 56 | 57 | Before proposing a change, please discuss it first by raising an issue. 58 | -------------------------------------------------------------------------------- /net/syncookie.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | import ( 4 | "crypto/md5" 5 | "encoding/binary" 6 | "strconv" 7 | "time" 8 | 9 | "github.com/datarhei/gosrt/rand" 10 | ) 11 | 12 | // SYNCookie implements a syn cookie for the SRT handshake. 13 | type SYNCookie struct { 14 | secret1 string 15 | secret2 string 16 | daddr string 17 | counter func() int64 18 | } 19 | 20 | func defaultCounter() int64 { 21 | return time.Now().Unix() >> 6 22 | } 23 | 24 | // NewSYNCookie returns a SYNCookie for a destination address. 25 | func NewSYNCookie(daddr string, counter func() int64) (*SYNCookie, error) { 26 | s := &SYNCookie{ 27 | daddr: daddr, 28 | counter: counter, 29 | } 30 | 31 | if s.counter == nil { 32 | s.counter = defaultCounter 33 | } 34 | 35 | var err error 36 | s.secret1, err = rand.RandomString(32, rand.AlphaNumericCharset) 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | s.secret2, err = rand.RandomString(32, rand.AlphaNumericCharset) 42 | if err != nil { 43 | return nil, err 44 | } 45 | 46 | return s, nil 47 | } 48 | 49 | // Get returns the current syn cookie with a sender address. 50 | func (s *SYNCookie) Get(saddr string) uint32 { 51 | return s.calculate(s.counter(), saddr) 52 | } 53 | 54 | // Verify verfies that two syn cookies relate. 55 | func (s *SYNCookie) Verify(cookie uint32, saddr string) bool { 56 | counter := s.counter() 57 | 58 | if s.calculate(counter, saddr) == cookie { 59 | return true 60 | } 61 | 62 | if s.calculate(counter-1, saddr) == cookie { 63 | return true 64 | } 65 | 66 | return false 67 | } 68 | 69 | func (s *SYNCookie) calculate(counter int64, saddr string) uint32 { 70 | data := s.secret1 + s.daddr + saddr + s.secret2 + strconv.FormatInt(counter, 10) 71 | 72 | md5sum := md5.Sum([]byte(data)) 73 | 74 | return binary.BigEndian.Uint32(md5sum[0:]) 75 | } 76 | -------------------------------------------------------------------------------- /vendor/github.com/felixge/fgprof/BenchmarkProfilerGoroutines.txt: -------------------------------------------------------------------------------- 1 | $ go test -bench=BenchmarkProfilerGoroutines 2 | goos: darwin 3 | goarch: amd64 4 | pkg: github.com/felixge/fgprof 5 | BenchmarkProfilerGoroutines/1_goroutines-8 43431 26860 ns/op 6 | BenchmarkProfilerGoroutines/2_goroutines-8 42590 27648 ns/op 7 | BenchmarkProfilerGoroutines/4_goroutines-8 40725 28694 ns/op 8 | BenchmarkProfilerGoroutines/8_goroutines-8 37874 31067 ns/op 9 | BenchmarkProfilerGoroutines/16_goroutines-8 32778 37302 ns/op 10 | BenchmarkProfilerGoroutines/32_goroutines-8 25447 47171 ns/op 11 | BenchmarkProfilerGoroutines/64_goroutines-8 17937 66803 ns/op 12 | BenchmarkProfilerGoroutines/128_goroutines-8 11138 108283 ns/op 13 | BenchmarkProfilerGoroutines/256_goroutines-8 5232 191830 ns/op 14 | BenchmarkProfilerGoroutines/512_goroutines-8 2848 351686 ns/op 15 | BenchmarkProfilerGoroutines/1024_goroutines-8 1611 681412 ns/op 16 | BenchmarkProfilerGoroutines/2048_goroutines-8 846 1396125 ns/op 17 | BenchmarkProfilerGoroutines/4096_goroutines-8 358 3286943 ns/op 18 | BenchmarkProfilerGoroutines/8192_goroutines-8 153 7813804 ns/op 19 | BenchmarkProfilerGoroutines/16384_goroutines-8 70 16440643 ns/op 20 | BenchmarkProfilerGoroutines/32768_goroutines-8 33 34101649 ns/op 21 | BenchmarkProfilerGoroutines/65536_goroutines-8 16 68460458 ns/op 22 | BenchmarkProfilerGoroutines/131072_goroutines-8 8 134481118 ns/op 23 | BenchmarkProfilerGoroutines/262144_goroutines-8 4 270522885 ns/op 24 | BenchmarkProfilerGoroutines/524288_goroutines-8 2 567821104 ns/op 25 | BenchmarkProfilerGoroutines/1048576_goroutines-8 1 1202184643 ns/op 26 | -------------------------------------------------------------------------------- /net_windows.go: -------------------------------------------------------------------------------- 1 | //go:build windows 2 | 3 | package srt 4 | 5 | import ( 6 | "syscall" 7 | 8 | "golang.org/x/sys/windows" 9 | ) 10 | 11 | func ListenControl(config Config) func(network, address string, c syscall.RawConn) error { 12 | return func(network, address string, c syscall.RawConn) error { 13 | var opErr error 14 | err := c.Control(func(fd uintptr) { 15 | // Set REUSEADDR 16 | opErr = windows.SetsockoptInt(windows.Handle(fd), windows.SOL_SOCKET, windows.SO_REUSEADDR, 1) 17 | if opErr != nil { 18 | return 19 | } 20 | 21 | // Set TOS 22 | if config.IPTOS > 0 { 23 | opErr = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, windows.IP_TOS, config.IPTOS) 24 | if opErr != nil { 25 | return 26 | } 27 | } 28 | 29 | // Set TTL 30 | if config.IPTTL > 0 { 31 | opErr = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, windows.IP_TTL, config.IPTTL) 32 | if opErr != nil { 33 | return 34 | } 35 | } 36 | }) 37 | if err != nil { 38 | return err 39 | } 40 | return opErr 41 | } 42 | } 43 | 44 | func DialControl(config Config) func(network string, address string, c syscall.RawConn) error { 45 | return func(network, address string, c syscall.RawConn) error { 46 | var opErr error 47 | err := c.Control(func(fd uintptr) { 48 | // Set TOS 49 | if config.IPTOS > 0 { 50 | opErr = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, windows.IP_TOS, config.IPTOS) 51 | if opErr != nil { 52 | return 53 | } 54 | } 55 | 56 | // Set TTL 57 | if config.IPTTL > 0 { 58 | opErr = windows.SetsockoptInt(windows.Handle(fd), windows.IPPROTO_IP, windows.IP_TTL, config.IPTTL) 59 | if opErr != nil { 60 | return 61 | } 62 | } 63 | }) 64 | if err != nil { 65 | return err 66 | } 67 | return opErr 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypasssafe.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is running on Google App Engine, compiled by GopherJS, or 17 | // "-tags safe" is added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // +build js appengine safe disableunsafe !go1.4 20 | 21 | package spew 22 | 23 | import "reflect" 24 | 25 | const ( 26 | // UnsafeDisabled is a build-time constant which specifies whether or 27 | // not access to the unsafe package is available. 28 | UnsafeDisabled = true 29 | ) 30 | 31 | // unsafeReflectValue typically converts the passed reflect.Value into a one 32 | // that bypasses the typical safety restrictions preventing access to 33 | // unaddressable and unexported data. However, doing this relies on access to 34 | // the unsafe package. This is a stub version which simply returns the passed 35 | // reflect.Value when the unsafe package is not available. 36 | func unsafeReflectValue(v reflect.Value) reflect.Value { 37 | return v 38 | } 39 | -------------------------------------------------------------------------------- /config_test.go: -------------------------------------------------------------------------------- 1 | package srt 2 | 3 | import ( 4 | "testing" 5 | "time" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestDefaultConfig(t *testing.T) { 11 | config := DefaultConfig() 12 | err := config.Validate() 13 | 14 | if err != nil { 15 | require.NoError(t, err, "Failed to verify the default configuration: %s", err) 16 | } 17 | } 18 | 19 | func TestMarshalUnmarshal(t *testing.T) { 20 | wantConfig := Config{ 21 | Congestion: "xxx", 22 | ConnectionTimeout: 42 * time.Second, 23 | DriftTracer: false, 24 | EnforcedEncryption: false, 25 | FC: 42, 26 | GroupConnect: true, 27 | GroupStabilityTimeout: 42 * time.Second, 28 | InputBW: 42, 29 | IPTOS: 42, 30 | IPTTL: 42, 31 | IPv6Only: 42, 32 | KMPreAnnounce: 42, 33 | KMRefreshRate: 42, 34 | Latency: 42 * time.Second, 35 | LossMaxTTL: 42, 36 | MaxBW: 42, 37 | MessageAPI: true, 38 | MinInputBW: 42, 39 | MSS: 42, 40 | NAKReport: false, 41 | OverheadBW: 42, 42 | PacketFilter: "FEC", 43 | Passphrase: "foobar", 44 | PayloadSize: 42, 45 | PBKeylen: 42, 46 | PeerIdleTimeout: 42 * time.Second, 47 | PeerLatency: 42 * time.Second, 48 | ReceiverBufferSize: 42, 49 | ReceiverLatency: 42 * time.Second, 50 | SendBufferSize: 42, 51 | SendDropDelay: 42 * time.Second, 52 | StreamId: "foobaz", 53 | TooLatePacketDrop: false, 54 | TransmissionType: "yyy", 55 | TSBPDMode: false, 56 | Logger: nil, 57 | } 58 | 59 | url := wantConfig.MarshalURL("localhost:6000") 60 | 61 | config := Config{} 62 | config.UnmarshalURL(url) 63 | 64 | require.Equal(t, wantConfig, config) 65 | } 66 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | COMMIT := $(shell if [ -d .git ]; then git rev-parse HEAD; else echo "unknown"; fi) 2 | SHORTCOMMIT := $(shell echo $(COMMIT) | head -c 7) 3 | 4 | all: build 5 | 6 | ## test: Run all tests 7 | test: 8 | go test -race -coverprofile=/dev/null -covermode=atomic -v ./... 9 | 10 | ## fuzz: Run fuzz tests 11 | fuzz: 12 | go test -fuzz=Fuzz -run=^Fuzz ./packet -fuzztime 30s 13 | 14 | ## vet: Analyze code for potential errors 15 | vet: 16 | go vet ./... 17 | 18 | ## fmt: Format code 19 | fmt: 20 | go fmt ./... 21 | 22 | ## update: Update dependencies 23 | update: 24 | go get -u -t 25 | @-$(MAKE) tidy 26 | @-$(MAKE) vendor 27 | 28 | ## tidy: Tidy up go.mod 29 | tidy: 30 | go mod tidy 31 | 32 | ## vendor: Update vendored packages 33 | vendor: 34 | go mod vendor 35 | 36 | ## lint: Static analysis with staticcheck 37 | lint: 38 | staticcheck ./... 39 | 40 | ## client: Build import binary 41 | client: 42 | cd contrib/client && CGO_ENABLED=0 go build -o client -ldflags="-s -w" -a 43 | 44 | ## server: Build import binary 45 | server: 46 | cd contrib/server && CGO_ENABLED=0 go build -o server -ldflags="-s -w" -a 47 | 48 | ## coverage: Generate code coverage analysis 49 | coverage: 50 | go test -race -coverprofile=cover.out -timeout 60s -v ./... 51 | go tool cover -html=cover.out -o cover.html 52 | 53 | ## commit: Prepare code for commit (vet, fmt, test) 54 | commit: vet fmt lint test 55 | @echo "No errors found. Ready for a commit." 56 | 57 | ## docker: Build standard Docker image 58 | docker: 59 | docker build -t gosrt:$(SHORTCOMMIT) . 60 | 61 | ## logtopics: Extract all logging topics 62 | logtopics: 63 | grep -ERho 'log\("([^"]+)' *.go | sed -E -e 's/log\("//' | sort -u 64 | 65 | .PHONY: help test fuzz vet fmt vendor commit coverage lint client server update logtopics 66 | 67 | ## help: Show all commands 68 | help: Makefile 69 | @echo 70 | @echo " Choose a command:" 71 | @echo 72 | @sed -n 's/^##//p' $< | column -t -s ':' | sed -e 's/^/ /' 73 | @echo 74 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/writerc.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2011-2019 Canonical Ltd 3 | // Copyright (c) 2006-2010 Kirill Simonov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | // this software and associated documentation files (the "Software"), to deal in 7 | // the Software without restriction, including without limitation the rights to 8 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | // of the Software, and to permit persons to whom the Software is furnished to do 10 | // so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package yaml 24 | 25 | // Set the writer error and return false. 26 | func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { 27 | emitter.error = yaml_WRITER_ERROR 28 | emitter.problem = problem 29 | return false 30 | } 31 | 32 | // Flush the output buffer. 33 | func yaml_emitter_flush(emitter *yaml_emitter_t) bool { 34 | if emitter.write_handler == nil { 35 | panic("write handler not set") 36 | } 37 | 38 | // Check if the buffer is empty. 39 | if emitter.buffer_pos == 0 { 40 | return true 41 | } 42 | 43 | if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { 44 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 45 | } 46 | emitter.buffer_pos = 0 47 | return true 48 | } 49 | -------------------------------------------------------------------------------- /vendor/github.com/google/pprof/profile/index.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package profile 16 | 17 | import ( 18 | "fmt" 19 | "strconv" 20 | "strings" 21 | ) 22 | 23 | // SampleIndexByName returns the appropriate index for a value of sample index. 24 | // If numeric, it returns the number, otherwise it looks up the text in the 25 | // profile sample types. 26 | func (p *Profile) SampleIndexByName(sampleIndex string) (int, error) { 27 | if sampleIndex == "" { 28 | if dst := p.DefaultSampleType; dst != "" { 29 | for i, t := range sampleTypes(p) { 30 | if t == dst { 31 | return i, nil 32 | } 33 | } 34 | } 35 | // By default select the last sample value 36 | return len(p.SampleType) - 1, nil 37 | } 38 | if i, err := strconv.Atoi(sampleIndex); err == nil { 39 | if i < 0 || i >= len(p.SampleType) { 40 | return 0, fmt.Errorf("sample_index %s is outside the range [0..%d]", sampleIndex, len(p.SampleType)-1) 41 | } 42 | return i, nil 43 | } 44 | 45 | // Remove the inuse_ prefix to support legacy pprof options 46 | // "inuse_space" and "inuse_objects" for profiles containing types 47 | // "space" and "objects". 48 | noInuse := strings.TrimPrefix(sampleIndex, "inuse_") 49 | for i, t := range p.SampleType { 50 | if t.Type == sampleIndex || t.Type == noInuse { 51 | return i, nil 52 | } 53 | } 54 | 55 | return 0, fmt.Errorf("sample_index %q must be one of: %v", sampleIndex, sampleTypes(p)) 56 | } 57 | 58 | func sampleTypes(p *Profile) []string { 59 | types := make([]string, len(p.SampleType)) 60 | for i, t := range p.SampleType { 61 | types[i] = t.Type 62 | } 63 | return types 64 | } 65 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | This project is covered by two different licenses: MIT and Apache. 3 | 4 | #### MIT License #### 5 | 6 | The following files were ported to Go from C files of libyaml, and thus 7 | are still covered by their original MIT license, with the additional 8 | copyright staring in 2011 when the project was ported over: 9 | 10 | apic.go emitterc.go parserc.go readerc.go scannerc.go 11 | writerc.go yamlh.go yamlprivateh.go 12 | 13 | Copyright (c) 2006-2010 Kirill Simonov 14 | Copyright (c) 2006-2011 Kirill Simonov 15 | 16 | Permission is hereby granted, free of charge, to any person obtaining a copy of 17 | this software and associated documentation files (the "Software"), to deal in 18 | the Software without restriction, including without limitation the rights to 19 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 20 | of the Software, and to permit persons to whom the Software is furnished to do 21 | so, subject to the following conditions: 22 | 23 | The above copyright notice and this permission notice shall be included in all 24 | copies or substantial portions of the Software. 25 | 26 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32 | SOFTWARE. 33 | 34 | ### Apache License ### 35 | 36 | All the remaining project files are covered by the Apache license: 37 | 38 | Copyright (c) 2011-2019 Canonical Ltd 39 | 40 | Licensed under the Apache License, Version 2.0 (the "License"); 41 | you may not use this file except in compliance with the License. 42 | You may obtain a copy of the License at 43 | 44 | http://www.apache.org/licenses/LICENSE-2.0 45 | 46 | Unless required by applicable law or agreed to in writing, software 47 | distributed under the License is distributed on an "AS IS" BASIS, 48 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 49 | See the License for the specific language governing permissions and 50 | limitations under the License. 51 | -------------------------------------------------------------------------------- /contrib/client/writer.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "io" 6 | "sync" 7 | "time" 8 | ) 9 | 10 | // NonblockingWriter is a io.Writer and io.Closer that won't block 11 | // any writes. If the underlying writer is blocking the data will be 12 | // buffered until it's available again. 13 | type Writer interface { 14 | io.WriteCloser 15 | } 16 | 17 | // nonblockingWriter implements the NonblockingWriter interface 18 | type nonblockingWriter struct { 19 | dst io.WriteCloser 20 | buf *bytes.Buffer 21 | lock sync.RWMutex 22 | size int 23 | done bool 24 | } 25 | 26 | // NewNonblockingWriter return a new NonBlockingWriter with writer as the 27 | // underlying writer. The size is the number of bytes to write to the 28 | // underlying writer in one iteration. It written as fast as possible to 29 | // the underlying writer. If there's no more data available to write 30 | // a pause of 10 milliseconds will be done. There's currently no limit 31 | // for the amount of data to be buffered. A call of the Close function 32 | // will close this writer. The underlying writer will not be closed. In 33 | // case there's an error while writing to the underlying writer, this 34 | // will close itself. 35 | func NewNonblockingWriter(writer io.WriteCloser, size int) Writer { 36 | u := &nonblockingWriter{ 37 | dst: writer, 38 | buf: new(bytes.Buffer), 39 | size: size, 40 | done: false, 41 | } 42 | 43 | if u.size <= 0 { 44 | u.size = 2048 45 | } 46 | 47 | go u.writer() 48 | 49 | return u 50 | } 51 | 52 | func (u *nonblockingWriter) Write(p []byte) (int, error) { 53 | if u.done { 54 | return 0, io.EOF 55 | } 56 | 57 | u.lock.Lock() 58 | defer u.lock.Unlock() 59 | 60 | return u.buf.Write(p) 61 | } 62 | 63 | func (u *nonblockingWriter) Close() error { 64 | u.done = true 65 | 66 | u.dst.Close() 67 | 68 | return nil 69 | } 70 | 71 | // writer writes to the underlying writer in chunks read from 72 | // the buffer. If the buffer is empty, a short pause will be made. 73 | func (u *nonblockingWriter) writer() { 74 | p := make([]byte, u.size) 75 | 76 | for { 77 | u.lock.RLock() 78 | n, err := u.buf.Read(p) 79 | u.lock.RUnlock() 80 | 81 | if n == 0 || err == io.EOF { 82 | if u.done { 83 | break 84 | } 85 | 86 | time.Sleep(10 * time.Millisecond) 87 | continue 88 | } 89 | 90 | if _, err := u.dst.Write(p[:n]); err != nil { 91 | break 92 | } 93 | } 94 | 95 | u.done = true 96 | } 97 | -------------------------------------------------------------------------------- /net/ip_test.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | import ( 4 | "net" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | func TestIPDefault(t *testing.T) { 11 | ip := IP{} 12 | 13 | ip.setDefault() 14 | 15 | require.Equal(t, "127.0.0.1", ip.String()) 16 | } 17 | 18 | func TestIPParse(t *testing.T) { 19 | ip := IP{} 20 | 21 | ip.Parse("192.168.1.3") 22 | 23 | require.Equal(t, "192.168.1.3", ip.String()) 24 | 25 | ip.Parse("fhdhdf") 26 | 27 | require.Equal(t, "127.0.0.1", ip.String()) 28 | } 29 | 30 | func TestIPFrom(t *testing.T) { 31 | ip := IP{} 32 | 33 | ip.FromNetIP(net.ParseIP("192.168.2.56")) 34 | 35 | require.Equal(t, "192.168.2.56", ip.String()) 36 | 37 | ip.FromNetIP(net.ParseIP("127.0.0.1")) 38 | 39 | require.Equal(t, "127.0.0.1", ip.String()) 40 | 41 | udpaddr, err := net.ResolveUDPAddr("udp", "localhost:12345") 42 | 43 | require.NoError(t, err) 44 | ip.FromNetAddr(udpaddr) 45 | 46 | require.Equal(t, "127.0.0.1", ip.String()) 47 | 48 | ipaddr, err := net.ResolveIPAddr("ip", "localhost") 49 | 50 | require.NoError(t, err) 51 | ip.FromNetAddr(ipaddr) 52 | 53 | require.Equal(t, "127.0.0.1", ip.String()) 54 | } 55 | 56 | func TestIPUnmarshal(t *testing.T) { 57 | ip := IP{} 58 | 59 | b0 := [5]byte{} 60 | 61 | err := ip.Unmarshal(b0[:]) 62 | 63 | require.Error(t, err) 64 | 65 | b1 := [...]byte{1, 0, 168, 192} 66 | 67 | err = ip.Unmarshal(b1[:]) 68 | 69 | require.NoError(t, err) 70 | require.Equal(t, "192.168.0.1", ip.String()) 71 | 72 | b2 := [...]byte{1, 0, 168, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 73 | 74 | err = ip.Unmarshal(b2[:]) 75 | 76 | require.NoError(t, err) 77 | require.Equal(t, "192.168.0.1", ip.String()) 78 | 79 | b3 := [...]byte{1, 0, 0, 0, 0, 0, 0, 0, 0xc5, 0x71, 0x26, 0xdb, 0x94, 0x8c, 0x30, 0xfd} 80 | 81 | err = ip.Unmarshal(b3[:]) 82 | 83 | require.NoError(t, err) 84 | require.Equal(t, "fd30:8c94:db26:71c5::1", ip.String()) 85 | } 86 | 87 | func TestIPMarshal(t *testing.T) { 88 | ip := IP{} 89 | 90 | ip.Parse("192.168.0.1") 91 | 92 | b := [16]byte{} 93 | 94 | ip.Marshal(b[:]) 95 | 96 | require.Equal(t, [...]byte{1, 0, 168, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, b) 97 | 98 | ip.Parse("fd30:8c94:db26:71c5::1") 99 | 100 | ip.Marshal(b[:]) 101 | 102 | require.Equal(t, [...]byte{1, 0, 0, 0, 0, 0, 0, 0, 0xc5, 0x71, 0x26, 0xdb, 0x94, 0x8c, 0x30, 0xfd}, b) 103 | } 104 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/mkerrors.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2019 The Go Authors. All rights reserved. 4 | # Use of this source code is governed by a BSD-style 5 | # license that can be found in the LICENSE file. 6 | 7 | set -e 8 | shopt -s nullglob 9 | 10 | winerror="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/shared/winerror.h | sort -Vr | head -n 1)" 11 | [[ -n $winerror ]] || { echo "Unable to find winerror.h" >&2; exit 1; } 12 | ntstatus="$(printf '%s\n' "/mnt/c/Program Files (x86)/Windows Kits/"/*/Include/*/shared/ntstatus.h | sort -Vr | head -n 1)" 13 | [[ -n $ntstatus ]] || { echo "Unable to find ntstatus.h" >&2; exit 1; } 14 | 15 | declare -A errors 16 | 17 | { 18 | echo "// Code generated by 'mkerrors.bash'; DO NOT EDIT." 19 | echo 20 | echo "package windows" 21 | echo "import \"syscall\"" 22 | echo "const (" 23 | 24 | while read -r line; do 25 | unset vtype 26 | if [[ $line =~ ^#define\ +([A-Z0-9_]+k?)\ +([A-Z0-9_]+\()?([A-Z][A-Z0-9_]+k?)\)? ]]; then 27 | key="${BASH_REMATCH[1]}" 28 | value="${BASH_REMATCH[3]}" 29 | elif [[ $line =~ ^#define\ +([A-Z0-9_]+k?)\ +([A-Z0-9_]+\()?((0x)?[0-9A-Fa-f]+)L?\)? ]]; then 30 | key="${BASH_REMATCH[1]}" 31 | value="${BASH_REMATCH[3]}" 32 | vtype="${BASH_REMATCH[2]}" 33 | elif [[ $line =~ ^#define\ +([A-Z0-9_]+k?)\ +\(\(([A-Z]+)\)((0x)?[0-9A-Fa-f]+)L?\) ]]; then 34 | key="${BASH_REMATCH[1]}" 35 | value="${BASH_REMATCH[3]}" 36 | vtype="${BASH_REMATCH[2]}" 37 | else 38 | continue 39 | fi 40 | [[ -n $key && -n $value ]] || continue 41 | [[ -z ${errors["$key"]} ]] || continue 42 | errors["$key"]="$value" 43 | if [[ -v vtype ]]; then 44 | if [[ $key == FACILITY_* || $key == NO_ERROR ]]; then 45 | vtype="" 46 | elif [[ $vtype == *HANDLE* || $vtype == *HRESULT* ]]; then 47 | vtype="Handle" 48 | else 49 | vtype="syscall.Errno" 50 | fi 51 | last_vtype="$vtype" 52 | else 53 | vtype="" 54 | if [[ $last_vtype == Handle && $value == NO_ERROR ]]; then 55 | value="S_OK" 56 | elif [[ $last_vtype == syscall.Errno && $value == NO_ERROR ]]; then 57 | value="ERROR_SUCCESS" 58 | fi 59 | fi 60 | 61 | echo "$key $vtype = $value" 62 | done < "$winerror" 63 | 64 | while read -r line; do 65 | [[ $line =~ ^#define\ (STATUS_[^\s]+)\ +\(\(NTSTATUS\)((0x)?[0-9a-fA-F]+)L?\) ]] || continue 66 | echo "${BASH_REMATCH[1]} NTStatus = ${BASH_REMATCH[2]}" 67 | done < "$ntstatus" 68 | 69 | echo ")" 70 | } | gofmt > "zerrors_windows.go" 71 | -------------------------------------------------------------------------------- /log.go: -------------------------------------------------------------------------------- 1 | package srt 2 | 3 | import ( 4 | "runtime" 5 | "strings" 6 | "time" 7 | ) 8 | 9 | // Logger is for logging debug messages. 10 | type Logger interface { 11 | // HasTopic returns whether this Logger is logging messages of that topic. 12 | HasTopic(topic string) bool 13 | 14 | // Print adds a new message to the message queue. The message itself is 15 | // a function that returns the string to be logges. It will only be 16 | // executed if HasTopic returns true on the given topic. 17 | Print(topic string, socketId uint32, skip int, message func() string) 18 | 19 | // Listen returns a read channel for Log messages. 20 | Listen() <-chan Log 21 | 22 | // Close closes the logger. No more messages will be logged. 23 | Close() 24 | } 25 | 26 | // logger implements a Logger 27 | type logger struct { 28 | logQueue chan Log 29 | topics map[string]bool 30 | } 31 | 32 | // NewLogger returns a Logger that only listens on the given list of topics. 33 | func NewLogger(topics []string) Logger { 34 | l := &logger{ 35 | logQueue: make(chan Log, 1024), 36 | topics: make(map[string]bool), 37 | } 38 | 39 | for _, topic := range topics { 40 | l.topics[topic] = true 41 | } 42 | 43 | return l 44 | } 45 | 46 | func (l *logger) HasTopic(topic string) bool { 47 | if len(l.topics) == 0 { 48 | return false 49 | } 50 | 51 | if ok := l.topics[topic]; ok { 52 | return true 53 | } 54 | 55 | len := len(topic) 56 | 57 | for { 58 | i := strings.LastIndexByte(topic[:len], ':') 59 | if i == -1 { 60 | break 61 | } 62 | 63 | len = i 64 | 65 | if ok := l.topics[topic[:len]]; !ok { 66 | continue 67 | } 68 | 69 | return true 70 | } 71 | 72 | return false 73 | } 74 | 75 | func (l *logger) Print(topic string, socketId uint32, skip int, message func() string) { 76 | if !l.HasTopic(topic) { 77 | return 78 | } 79 | 80 | _, file, line, _ := runtime.Caller(skip) 81 | 82 | msg := Log{ 83 | Time: time.Now(), 84 | SocketId: socketId, 85 | Topic: topic, 86 | Message: message(), 87 | File: file, 88 | Line: line, 89 | } 90 | 91 | // Write to log queue, but don't block if it's full 92 | select { 93 | case l.logQueue <- msg: 94 | default: 95 | } 96 | } 97 | 98 | func (l *logger) Listen() <-chan Log { 99 | return l.logQueue 100 | } 101 | 102 | func (l *logger) Close() { 103 | close(l.logQueue) 104 | } 105 | 106 | // Log represents a log message 107 | type Log struct { 108 | Time time.Time // Time of when this message has been logged 109 | SocketId uint32 // The socketid if connection related, 0 otherwise 110 | Topic string // The topic of this message 111 | Message string // The message itself 112 | File string // The file in which this message has been dispatched 113 | Line int // The line number in the file in which this message has been dispatched 114 | } 115 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c h1:8XZeJrs4+ZYhJeJ2aZxADI2tGADS15AzIF8MQ8XAhT4= 2 | github.com/benburkert/openpgp v0.0.0-20160410205803-c2471f86866c/go.mod h1:x1vxHcL/9AVzuk5HOloOEPrtJY0MaalYr78afXZ+pWI= 3 | github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= 4 | github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= 5 | github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 8 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= 10 | github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= 11 | github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= 12 | github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= 13 | github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= 14 | github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= 15 | github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= 16 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 17 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 18 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 19 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 20 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 21 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 22 | github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= 23 | github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 24 | golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 25 | golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= 26 | golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 27 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 28 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 29 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 30 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 31 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 32 | -------------------------------------------------------------------------------- /circular/circular_test.go: -------------------------------------------------------------------------------- 1 | package circular 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/require" 8 | ) 9 | 10 | const max uint32 = 0b11111111_11111111_11111111_11111111 11 | 12 | func ExampleNumber_Inc() { 13 | a := New(42, max) 14 | b := a.Inc() 15 | 16 | fmt.Println(b.Val()) 17 | // Output: 43 18 | } 19 | 20 | func TestIncNoWrap(t *testing.T) { 21 | a := New(42, max) 22 | 23 | require.Equal(t, uint32(42), a.Val()) 24 | 25 | a = a.Inc() 26 | 27 | require.Equal(t, uint32(43), a.Val()) 28 | } 29 | 30 | func TestIncWrap(t *testing.T) { 31 | a := New(max-1, max) 32 | 33 | require.Equal(t, max-1, a.Val()) 34 | 35 | a = a.Inc() 36 | 37 | require.Equal(t, max, a.Val()) 38 | 39 | a = a.Inc() 40 | 41 | require.Equal(t, uint32(0), a.Val()) 42 | } 43 | 44 | func TestDecNoWrap(t *testing.T) { 45 | a := New(42, max) 46 | 47 | require.Equal(t, uint32(42), a.Val()) 48 | 49 | a = a.Dec() 50 | 51 | require.Equal(t, uint32(41), a.Val()) 52 | } 53 | 54 | func TestDecWrap(t *testing.T) { 55 | a := New(0, max) 56 | 57 | require.Equal(t, uint32(0), a.Val()) 58 | 59 | a = a.Dec() 60 | 61 | require.Equal(t, max, a.Val()) 62 | 63 | a = a.Dec() 64 | 65 | require.Equal(t, max-1, a.Val()) 66 | } 67 | 68 | func TestDistanceNoWrap(t *testing.T) { 69 | a := New(42, max) 70 | b := New(50, max) 71 | 72 | d := a.Distance(b) 73 | 74 | require.Equal(t, uint32(8), d) 75 | 76 | d = b.Distance(a) 77 | 78 | require.Equal(t, uint32(8), d) 79 | } 80 | 81 | func TestDistanceWrap(t *testing.T) { 82 | a := New(2, max) 83 | b := New(max-2, max) 84 | 85 | d := a.Distance(b) 86 | 87 | require.Equal(t, uint32(5), d) 88 | 89 | d = b.Distance(a) 90 | 91 | require.Equal(t, uint32(5), d) 92 | } 93 | 94 | func TestLt(t *testing.T) { 95 | a := New(42, max) 96 | b := New(50, max) 97 | c := New(max-10, max) 98 | 99 | x := a.Lt(b) 100 | 101 | require.Equal(t, true, x) 102 | 103 | x = b.Lt(a) 104 | 105 | require.Equal(t, false, x) 106 | 107 | x = a.Lt(c) 108 | 109 | require.Equal(t, false, x) 110 | 111 | x = c.Lt(a) 112 | 113 | require.Equal(t, true, x) 114 | } 115 | 116 | func TestGt(t *testing.T) { 117 | a := New(42, max) 118 | b := New(50, max) 119 | c := New(max-10, max) 120 | 121 | x := a.Gt(b) 122 | 123 | require.Equal(t, false, x) 124 | 125 | x = b.Gt(a) 126 | 127 | require.Equal(t, true, x) 128 | 129 | x = a.Gt(c) 130 | 131 | require.Equal(t, true, x) 132 | 133 | x = c.Gt(a) 134 | 135 | require.Equal(t, false, x) 136 | } 137 | 138 | func TestAdd(t *testing.T) { 139 | a := New(max-42, max) 140 | 141 | a = a.Add(42) 142 | 143 | require.Equal(t, max, a.Val()) 144 | 145 | a = a.Add(1) 146 | 147 | require.Equal(t, uint32(0), a.Val()) 148 | } 149 | 150 | func TestSub(t *testing.T) { 151 | a := New(42, max) 152 | 153 | a = a.Sub(42) 154 | 155 | require.Equal(t, uint32(0), a.Val()) 156 | 157 | a = a.Sub(1) 158 | 159 | require.Equal(t, max, a.Val()) 160 | } 161 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/assertion_order.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | ) 7 | 8 | // isOrdered checks that collection contains orderable elements. 9 | func isOrdered(t TestingT, object interface{}, allowedComparesResults []compareResult, failMessage string, msgAndArgs ...interface{}) bool { 10 | objKind := reflect.TypeOf(object).Kind() 11 | if objKind != reflect.Slice && objKind != reflect.Array { 12 | return false 13 | } 14 | 15 | objValue := reflect.ValueOf(object) 16 | objLen := objValue.Len() 17 | 18 | if objLen <= 1 { 19 | return true 20 | } 21 | 22 | value := objValue.Index(0) 23 | valueInterface := value.Interface() 24 | firstValueKind := value.Kind() 25 | 26 | for i := 1; i < objLen; i++ { 27 | prevValue := value 28 | prevValueInterface := valueInterface 29 | 30 | value = objValue.Index(i) 31 | valueInterface = value.Interface() 32 | 33 | compareResult, isComparable := compare(prevValueInterface, valueInterface, firstValueKind) 34 | 35 | if !isComparable { 36 | return Fail(t, fmt.Sprintf(`Can not compare type "%T" and "%T"`, value, prevValue), msgAndArgs...) 37 | } 38 | 39 | if !containsValue(allowedComparesResults, compareResult) { 40 | return Fail(t, fmt.Sprintf(failMessage, prevValue, value), msgAndArgs...) 41 | } 42 | } 43 | 44 | return true 45 | } 46 | 47 | // IsIncreasing asserts that the collection is increasing 48 | // 49 | // assert.IsIncreasing(t, []int{1, 2, 3}) 50 | // assert.IsIncreasing(t, []float{1, 2}) 51 | // assert.IsIncreasing(t, []string{"a", "b"}) 52 | func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { 53 | return isOrdered(t, object, []compareResult{compareLess}, "\"%v\" is not less than \"%v\"", msgAndArgs...) 54 | } 55 | 56 | // IsNonIncreasing asserts that the collection is not increasing 57 | // 58 | // assert.IsNonIncreasing(t, []int{2, 1, 1}) 59 | // assert.IsNonIncreasing(t, []float{2, 1}) 60 | // assert.IsNonIncreasing(t, []string{"b", "a"}) 61 | func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { 62 | return isOrdered(t, object, []compareResult{compareEqual, compareGreater}, "\"%v\" is not greater than or equal to \"%v\"", msgAndArgs...) 63 | } 64 | 65 | // IsDecreasing asserts that the collection is decreasing 66 | // 67 | // assert.IsDecreasing(t, []int{2, 1, 0}) 68 | // assert.IsDecreasing(t, []float{2, 1}) 69 | // assert.IsDecreasing(t, []string{"b", "a"}) 70 | func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { 71 | return isOrdered(t, object, []compareResult{compareGreater}, "\"%v\" is not greater than \"%v\"", msgAndArgs...) 72 | } 73 | 74 | // IsNonDecreasing asserts that the collection is not decreasing 75 | // 76 | // assert.IsNonDecreasing(t, []int{1, 1, 2}) 77 | // assert.IsNonDecreasing(t, []float{1, 2}) 78 | // assert.IsNonDecreasing(t, []string{"a", "b"}) 79 | func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...interface{}) bool { 80 | return isOrdered(t, object, []compareResult{compareLess, compareEqual}, "\"%v\" is not less than or equal to \"%v\"", msgAndArgs...) 81 | } 82 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: ["main"] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: ["main"] 20 | schedule: 21 | - cron: "32 23 * * 2" 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: ["go"] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v4 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v3 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 56 | # If this step fails, then you should remove it and run the build manually (see below) 57 | - name: Autobuild 58 | uses: github/codeql-action/autobuild@v3 59 | 60 | # ℹ️ Command-line programs to run using the OS shell. 61 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 62 | 63 | # If the Autobuild fails above, remove it and uncomment the following three lines. 64 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 65 | 66 | # - run: | 67 | # echo "Run, Build Application using script" 68 | # ./location_of_script_within_repo/buildscript.sh 69 | 70 | - name: Perform CodeQL Analysis 71 | uses: github/codeql-action/analyze@v3 72 | -------------------------------------------------------------------------------- /server.go: -------------------------------------------------------------------------------- 1 | package srt 2 | 3 | import ( 4 | "errors" 5 | ) 6 | 7 | // Server is a framework for a SRT server 8 | type Server struct { 9 | // The address the SRT server should listen on, e.g. ":6001". 10 | Addr string 11 | 12 | // Config is the configuration for a SRT listener. 13 | Config *Config 14 | 15 | // HandleConnect will be called for each incoming connection. This 16 | // allows you to implement your own interpretation of the streamid 17 | // and authorization. If this is nil, all connections will be 18 | // rejected. 19 | HandleConnect AcceptFunc 20 | 21 | // HandlePublish will be called for a publishing connection. 22 | HandlePublish func(conn Conn) 23 | 24 | // HandlePublish will be called for a subscribing connection. 25 | HandleSubscribe func(conn Conn) 26 | 27 | ln Listener 28 | } 29 | 30 | // ErrServerClosed is returned when the server is about to shutdown. 31 | var ErrServerClosed = errors.New("srt: server closed") 32 | 33 | // ListenAndServe starts the SRT server. It blocks until an error happens. 34 | // If the error is ErrServerClosed the server has shutdown normally. 35 | func (s *Server) ListenAndServe() error { 36 | err := s.Listen() 37 | if err != nil { 38 | return err 39 | } 40 | 41 | return s.Serve() 42 | } 43 | 44 | // Listen opens the server listener. 45 | // It returns immediately after the listener is ready. 46 | func (s *Server) Listen() error { 47 | // Set some defaults if required. 48 | if s.HandlePublish == nil { 49 | s.HandlePublish = s.defaultHandler 50 | } 51 | 52 | if s.HandleSubscribe == nil { 53 | s.HandleSubscribe = s.defaultHandler 54 | } 55 | 56 | if s.Config == nil { 57 | config := DefaultConfig() 58 | s.Config = &config 59 | } 60 | 61 | // Start listening for incoming connections. 62 | ln, err := Listen("srt", s.Addr, *s.Config) 63 | if err != nil { 64 | return err 65 | } 66 | 67 | s.ln = ln 68 | 69 | return err 70 | } 71 | 72 | // Serve starts accepting connections. It must be called after Listen(). 73 | // It blocks until an error happens. 74 | // If the error is ErrServerClosed the server has shutdown normally. 75 | func (s *Server) Serve() error { 76 | for { 77 | // Wait for connections. 78 | req, err := s.ln.Accept2() 79 | if err != nil { 80 | if err == ErrListenerClosed { 81 | return ErrServerClosed 82 | } 83 | 84 | return err 85 | } 86 | 87 | if s.HandleConnect == nil { 88 | req.Reject(REJ_PEER) 89 | continue 90 | } 91 | 92 | go func(req ConnRequest) { 93 | mode := s.HandleConnect(req) 94 | if mode == REJECT { 95 | req.Reject(REJ_PEER) 96 | return 97 | } 98 | 99 | conn, err := req.Accept() 100 | if err != nil { 101 | // rejected connection, ignore 102 | return 103 | } 104 | 105 | if mode == PUBLISH { 106 | s.HandlePublish(conn) 107 | } else { 108 | s.HandleSubscribe(conn) 109 | } 110 | }(req) 111 | } 112 | } 113 | 114 | // Shutdown will shutdown the server. ListenAndServe will return a ErrServerClosed 115 | func (s *Server) Shutdown() { 116 | if s.ln == nil { 117 | return 118 | } 119 | 120 | // Close the listener 121 | s.ln.Close() 122 | } 123 | 124 | func (s *Server) defaultHandler(conn Conn) { 125 | // Close the incoming connection 126 | conn.Close() 127 | } 128 | -------------------------------------------------------------------------------- /pubsub_test.go: -------------------------------------------------------------------------------- 1 | package srt 2 | 3 | import ( 4 | "bytes" 5 | "sync" 6 | "testing" 7 | "time" 8 | 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | func TestPubSub(t *testing.T) { 14 | message := "Hello World!" 15 | channel := NewPubSub(PubSubConfig{}) 16 | 17 | config := DefaultConfig() 18 | 19 | server := Server{ 20 | Addr: "127.0.0.1:6003", 21 | Config: &config, 22 | HandleConnect: func(req ConnRequest) ConnType { 23 | streamid := req.StreamId() 24 | 25 | if streamid == "publish" { 26 | return PUBLISH 27 | } else if streamid == "subscribe" { 28 | return SUBSCRIBE 29 | } 30 | 31 | return REJECT 32 | }, 33 | HandlePublish: func(conn Conn) { 34 | channel.Publish(conn) 35 | 36 | conn.Close() 37 | }, 38 | HandleSubscribe: func(conn Conn) { 39 | channel.Subscribe(conn) 40 | 41 | conn.Close() 42 | }, 43 | } 44 | 45 | err := server.Listen() 46 | require.NoError(t, err) 47 | 48 | go func() { 49 | err := server.Serve() 50 | if err == ErrServerClosed { 51 | return 52 | } 53 | require.NoError(t, err) 54 | }() 55 | 56 | readerReadyWg := sync.WaitGroup{} 57 | readerReadyWg.Add(2) 58 | 59 | readerDoneWg := sync.WaitGroup{} 60 | readerDoneWg.Add(2) 61 | 62 | dataReader1 := bytes.Buffer{} 63 | dataReader2 := bytes.Buffer{} 64 | 65 | go func() { 66 | config := DefaultConfig() 67 | config.StreamId = "subscribe" 68 | 69 | conn, err := Dial("srt", "127.0.0.1:6003", config) 70 | if !assert.NoError(t, err) { 71 | panic(err.Error()) 72 | } 73 | 74 | buffer := make([]byte, 2048) 75 | 76 | readerReadyWg.Done() 77 | 78 | for { 79 | n, err := conn.Read(buffer) 80 | if n != 0 { 81 | dataReader1.Write(buffer[:n]) 82 | } 83 | 84 | if err != nil { 85 | break 86 | } 87 | } 88 | 89 | err = conn.Close() 90 | require.NoError(t, err) 91 | 92 | readerDoneWg.Done() 93 | }() 94 | 95 | go func() { 96 | config := DefaultConfig() 97 | config.StreamId = "subscribe" 98 | 99 | conn, err := Dial("srt", "127.0.0.1:6003", config) 100 | if !assert.NoError(t, err) { 101 | panic(err.Error()) 102 | } 103 | 104 | buffer := make([]byte, 2048) 105 | 106 | readerReadyWg.Done() 107 | 108 | for { 109 | n, err := conn.Read(buffer) 110 | if n != 0 { 111 | dataReader2.Write(buffer[:n]) 112 | } 113 | 114 | if err != nil { 115 | break 116 | } 117 | } 118 | 119 | err = conn.Close() 120 | require.NoError(t, err) 121 | 122 | readerDoneWg.Done() 123 | }() 124 | 125 | readerReadyWg.Wait() 126 | 127 | writerWg := sync.WaitGroup{} 128 | writerWg.Add(1) 129 | 130 | go func() { 131 | config := DefaultConfig() 132 | config.StreamId = "publish" 133 | 134 | conn, err := Dial("srt", "127.0.0.1:6003", config) 135 | if !assert.NoError(t, err) { 136 | panic(err.Error()) 137 | } 138 | 139 | n, err := conn.Write([]byte(message)) 140 | require.NoError(t, err) 141 | require.Equal(t, 12, n) 142 | 143 | time.Sleep(3 * time.Second) 144 | 145 | err = conn.Close() 146 | require.NoError(t, err) 147 | 148 | writerWg.Done() 149 | }() 150 | 151 | writerWg.Wait() 152 | readerDoneWg.Wait() 153 | 154 | server.Shutdown() 155 | 156 | reader1 := dataReader1.String() 157 | reader2 := dataReader2.String() 158 | 159 | require.Equal(t, message, reader1) 160 | require.Equal(t, message, reader2) 161 | } 162 | -------------------------------------------------------------------------------- /congestion/congestion.go: -------------------------------------------------------------------------------- 1 | // Package congestions provides interfaces and types congestion control implementations for SRT 2 | package congestion 3 | 4 | import ( 5 | "github.com/datarhei/gosrt/circular" 6 | "github.com/datarhei/gosrt/packet" 7 | ) 8 | 9 | // Sender is the sending part of the congestion control 10 | type Sender interface { 11 | // Stats returns sender statistics. 12 | Stats() SendStats 13 | 14 | // Flush flushes all queued packages. 15 | Flush() 16 | 17 | // Push pushes a packet to be send on the sender queue. 18 | Push(p packet.Packet) 19 | 20 | // Tick gets called from a connection in order to proceed with the queued packets. The provided value for 21 | // now is corresponds to the timestamps in the queued packets. Those timestamps are the microseconds 22 | // since the start of the connection. 23 | Tick(now uint64) 24 | 25 | // ACK gets called when a sequence number has been confirmed from a receiver. 26 | ACK(sequenceNumber circular.Number) 27 | 28 | // NAK get called when packets with the listed sequence number should be resend. 29 | NAK(sequenceNumbers []circular.Number) 30 | 31 | // SetDropThreshold sets the threshold in microseconds for when to drop too late packages from the queue. 32 | SetDropThreshold(threshold uint64) 33 | } 34 | 35 | // Receiver is the receiving part of the congestion control 36 | type Receiver interface { 37 | // Stats returns receiver statistics. 38 | Stats() ReceiveStats 39 | 40 | // PacketRate returns the current packets and bytes per second, and the capacity of the link. 41 | PacketRate() (pps, bps, capacity float64) 42 | 43 | // Flush flushes all queued packages. 44 | Flush() 45 | 46 | // Push pushed a recieved packet to the receiver queue. 47 | Push(pkt packet.Packet) 48 | 49 | // Tick gets called from a connection in order to proceed with queued packets. The provided value for 50 | // now is corresponds to the timestamps in the queued packets. Those timestamps are the microseconds 51 | // since the start of the connection. 52 | Tick(now uint64) 53 | 54 | // SetNAKInterval sets the interval between two periodic NAK messages to the sender in microseconds. 55 | SetNAKInterval(nakInterval uint64) 56 | } 57 | 58 | // SendStats are collected statistics from a sender 59 | type SendStats struct { 60 | Pkt uint64 // Sent packets in total 61 | Byte uint64 // Sent bytes in total 62 | 63 | PktUnique uint64 64 | ByteUnique uint64 65 | 66 | PktLoss uint64 67 | ByteLoss uint64 68 | 69 | PktRetrans uint64 70 | ByteRetrans uint64 71 | 72 | UsSndDuration uint64 // microseconds 73 | 74 | PktDrop uint64 75 | ByteDrop uint64 76 | 77 | // instantaneous 78 | PktBuf uint64 79 | ByteBuf uint64 80 | MsBuf uint64 81 | 82 | PktFlightSize uint64 83 | 84 | UsPktSndPeriod float64 // microseconds 85 | BytePayload uint64 86 | 87 | MbpsEstimatedInputBandwidth float64 88 | MbpsEstimatedSentBandwidth float64 89 | 90 | PktLossRate float64 91 | } 92 | 93 | // ReceiveStats are collected statistics from a reciever 94 | type ReceiveStats struct { 95 | Pkt uint64 96 | Byte uint64 97 | 98 | PktUnique uint64 99 | ByteUnique uint64 100 | 101 | PktLoss uint64 102 | ByteLoss uint64 103 | 104 | PktRetrans uint64 105 | ByteRetrans uint64 106 | 107 | PktBelated uint64 108 | ByteBelated uint64 109 | 110 | PktDrop uint64 111 | ByteDrop uint64 112 | 113 | // instantaneous 114 | PktBuf uint64 115 | ByteBuf uint64 116 | MsBuf uint64 117 | 118 | BytePayload uint64 119 | 120 | MbpsEstimatedRecvBandwidth float64 121 | MbpsEstimatedLinkCapacity float64 122 | 123 | PktLossRate float64 124 | } 125 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/syscall.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | //go:build windows 6 | 7 | // Package windows contains an interface to the low-level operating system 8 | // primitives. OS details vary depending on the underlying system, and 9 | // by default, godoc will display the OS-specific documentation for the current 10 | // system. If you want godoc to display syscall documentation for another 11 | // system, set $GOOS and $GOARCH to the desired system. For example, if 12 | // you want to view documentation for freebsd/arm on linux/amd64, set $GOOS 13 | // to freebsd and $GOARCH to arm. 14 | // 15 | // The primary use of this package is inside other packages that provide a more 16 | // portable interface to the system, such as "os", "time" and "net". Use 17 | // those packages rather than this one if you can. 18 | // 19 | // For details of the functions and data types in this package consult 20 | // the manuals for the appropriate operating system. 21 | // 22 | // These calls return err == nil to indicate success; otherwise 23 | // err represents an operating system error describing the failure and 24 | // holds a value of type syscall.Errno. 25 | package windows // import "golang.org/x/sys/windows" 26 | 27 | import ( 28 | "bytes" 29 | "strings" 30 | "syscall" 31 | "unsafe" 32 | ) 33 | 34 | // ByteSliceFromString returns a NUL-terminated slice of bytes 35 | // containing the text of s. If s contains a NUL byte at any 36 | // location, it returns (nil, syscall.EINVAL). 37 | func ByteSliceFromString(s string) ([]byte, error) { 38 | if strings.IndexByte(s, 0) != -1 { 39 | return nil, syscall.EINVAL 40 | } 41 | a := make([]byte, len(s)+1) 42 | copy(a, s) 43 | return a, nil 44 | } 45 | 46 | // BytePtrFromString returns a pointer to a NUL-terminated array of 47 | // bytes containing the text of s. If s contains a NUL byte at any 48 | // location, it returns (nil, syscall.EINVAL). 49 | func BytePtrFromString(s string) (*byte, error) { 50 | a, err := ByteSliceFromString(s) 51 | if err != nil { 52 | return nil, err 53 | } 54 | return &a[0], nil 55 | } 56 | 57 | // ByteSliceToString returns a string form of the text represented by the slice s, with a terminating NUL and any 58 | // bytes after the NUL removed. 59 | func ByteSliceToString(s []byte) string { 60 | if i := bytes.IndexByte(s, 0); i != -1 { 61 | s = s[:i] 62 | } 63 | return string(s) 64 | } 65 | 66 | // BytePtrToString takes a pointer to a sequence of text and returns the corresponding string. 67 | // If the pointer is nil, it returns the empty string. It assumes that the text sequence is terminated 68 | // at a zero byte; if the zero byte is not present, the program may crash. 69 | func BytePtrToString(p *byte) string { 70 | if p == nil { 71 | return "" 72 | } 73 | if *p == 0 { 74 | return "" 75 | } 76 | 77 | // Find NUL terminator. 78 | n := 0 79 | for ptr := unsafe.Pointer(p); *(*byte)(ptr) != 0; n++ { 80 | ptr = unsafe.Pointer(uintptr(ptr) + 1) 81 | } 82 | 83 | return string(unsafe.Slice(p, n)) 84 | } 85 | 86 | // Single-word zero for use when we need a valid pointer to 0 bytes. 87 | // See mksyscall.pl. 88 | var _zero uintptr 89 | 90 | func (ts *Timespec) Unix() (sec int64, nsec int64) { 91 | return int64(ts.Sec), int64(ts.Nsec) 92 | } 93 | 94 | func (tv *Timeval) Unix() (sec int64, nsec int64) { 95 | return int64(tv.Sec), int64(tv.Usec) * 1000 96 | } 97 | 98 | func (ts *Timespec) Nano() int64 { 99 | return int64(ts.Sec)*1e9 + int64(ts.Nsec) 100 | } 101 | 102 | func (tv *Timeval) Nano() int64 { 103 | return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000 104 | } 105 | -------------------------------------------------------------------------------- /congestion/live/send_test.go: -------------------------------------------------------------------------------- 1 | package live 2 | 3 | import ( 4 | "net" 5 | "testing" 6 | 7 | "github.com/datarhei/gosrt/circular" 8 | "github.com/datarhei/gosrt/packet" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | func mockLiveSend(onDeliver func(p packet.Packet)) *sender { 13 | send := NewSender(SendConfig{ 14 | InitialSequenceNumber: circular.New(0, packet.MAX_SEQUENCENUMBER), 15 | DropThreshold: 10, 16 | OnDeliver: onDeliver, 17 | }) 18 | 19 | return send.(*sender) 20 | } 21 | 22 | func TestSendSequence(t *testing.T) { 23 | numbers := []uint32{} 24 | send := mockLiveSend(func(p packet.Packet) { 25 | numbers = append(numbers, p.Header().PacketSequenceNumber.Val()) 26 | }) 27 | 28 | addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") 29 | 30 | for i := 0; i < 10; i++ { 31 | p := packet.NewPacket(addr) 32 | p.Header().PktTsbpdTime = uint64(i + 1) 33 | 34 | send.Push(p) 35 | } 36 | 37 | send.Tick(5) 38 | 39 | require.Exactly(t, []uint32{0, 1, 2, 3, 4}, numbers) 40 | 41 | send.Tick(10) 42 | 43 | require.Exactly(t, []uint32{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, numbers) 44 | } 45 | 46 | func TestSendLossListACK(t *testing.T) { 47 | send := mockLiveSend(nil) 48 | 49 | addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") 50 | 51 | for i := 0; i < 10; i++ { 52 | p := packet.NewPacket(addr) 53 | p.Header().PktTsbpdTime = uint64(i + 1) 54 | 55 | send.Push(p) 56 | } 57 | 58 | send.Tick(10) 59 | 60 | require.Equal(t, 10, send.lossList.Len()) 61 | 62 | for i := 0; i < 10; i++ { 63 | send.ACK(circular.New(uint32(i+1), packet.MAX_SEQUENCENUMBER)) 64 | require.Equal(t, 10-(i+1), send.lossList.Len()) 65 | } 66 | } 67 | 68 | func TestSendRetransmit(t *testing.T) { 69 | numbers := []uint32{} 70 | nRetransmit := 0 71 | send := mockLiveSend(func(p packet.Packet) { 72 | numbers = append(numbers, p.Header().PacketSequenceNumber.Val()) 73 | if p.Header().RetransmittedPacketFlag { 74 | nRetransmit++ 75 | } 76 | }) 77 | 78 | addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") 79 | 80 | for i := 0; i < 10; i++ { 81 | p := packet.NewPacket(addr) 82 | p.Header().PktTsbpdTime = uint64(i + 1) 83 | 84 | send.Push(p) 85 | } 86 | 87 | send.Tick(10) 88 | 89 | require.Equal(t, 0, nRetransmit) 90 | 91 | send.NAK([]circular.Number{ 92 | circular.New(2, packet.MAX_SEQUENCENUMBER), 93 | circular.New(2, packet.MAX_SEQUENCENUMBER), 94 | }) 95 | 96 | require.Equal(t, 1, nRetransmit) 97 | 98 | send.NAK([]circular.Number{ 99 | circular.New(5, packet.MAX_SEQUENCENUMBER), 100 | circular.New(7, packet.MAX_SEQUENCENUMBER), 101 | }) 102 | 103 | require.Equal(t, 4, nRetransmit) 104 | } 105 | 106 | func TestSendDrop(t *testing.T) { 107 | send := mockLiveSend(nil) 108 | 109 | addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") 110 | 111 | for i := 0; i < 10; i++ { 112 | p := packet.NewPacket(addr) 113 | p.Header().PktTsbpdTime = uint64(i + 1) 114 | 115 | send.Push(p) 116 | } 117 | 118 | send.Tick(10) 119 | 120 | require.Equal(t, 10, send.lossList.Len()) 121 | 122 | send.Tick(20) 123 | 124 | require.Equal(t, 0, send.lossList.Len()) 125 | } 126 | 127 | func TestSendFlush(t *testing.T) { 128 | send := mockLiveSend(nil) 129 | 130 | addr, _ := net.ResolveIPAddr("ip", "127.0.0.1") 131 | 132 | for i := 0; i < 10; i++ { 133 | p := packet.NewPacket(addr) 134 | p.Header().PktTsbpdTime = uint64(i + 1) 135 | 136 | send.Push(p) 137 | } 138 | 139 | require.Exactly(t, 10, send.packetList.Len()) 140 | require.Exactly(t, 0, send.lossList.Len()) 141 | 142 | send.Tick(5) 143 | 144 | require.Exactly(t, 5, send.packetList.Len()) 145 | require.Exactly(t, 5, send.lossList.Len()) 146 | 147 | send.Flush() 148 | 149 | require.Exactly(t, 0, send.packetList.Len()) 150 | require.Exactly(t, 0, send.lossList.Len()) 151 | } 152 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/sorter.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2011-2019 Canonical Ltd 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | 16 | package yaml 17 | 18 | import ( 19 | "reflect" 20 | "unicode" 21 | ) 22 | 23 | type keyList []reflect.Value 24 | 25 | func (l keyList) Len() int { return len(l) } 26 | func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 27 | func (l keyList) Less(i, j int) bool { 28 | a := l[i] 29 | b := l[j] 30 | ak := a.Kind() 31 | bk := b.Kind() 32 | for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { 33 | a = a.Elem() 34 | ak = a.Kind() 35 | } 36 | for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { 37 | b = b.Elem() 38 | bk = b.Kind() 39 | } 40 | af, aok := keyFloat(a) 41 | bf, bok := keyFloat(b) 42 | if aok && bok { 43 | if af != bf { 44 | return af < bf 45 | } 46 | if ak != bk { 47 | return ak < bk 48 | } 49 | return numLess(a, b) 50 | } 51 | if ak != reflect.String || bk != reflect.String { 52 | return ak < bk 53 | } 54 | ar, br := []rune(a.String()), []rune(b.String()) 55 | digits := false 56 | for i := 0; i < len(ar) && i < len(br); i++ { 57 | if ar[i] == br[i] { 58 | digits = unicode.IsDigit(ar[i]) 59 | continue 60 | } 61 | al := unicode.IsLetter(ar[i]) 62 | bl := unicode.IsLetter(br[i]) 63 | if al && bl { 64 | return ar[i] < br[i] 65 | } 66 | if al || bl { 67 | if digits { 68 | return al 69 | } else { 70 | return bl 71 | } 72 | } 73 | var ai, bi int 74 | var an, bn int64 75 | if ar[i] == '0' || br[i] == '0' { 76 | for j := i - 1; j >= 0 && unicode.IsDigit(ar[j]); j-- { 77 | if ar[j] != '0' { 78 | an = 1 79 | bn = 1 80 | break 81 | } 82 | } 83 | } 84 | for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { 85 | an = an*10 + int64(ar[ai]-'0') 86 | } 87 | for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { 88 | bn = bn*10 + int64(br[bi]-'0') 89 | } 90 | if an != bn { 91 | return an < bn 92 | } 93 | if ai != bi { 94 | return ai < bi 95 | } 96 | return ar[i] < br[i] 97 | } 98 | return len(ar) < len(br) 99 | } 100 | 101 | // keyFloat returns a float value for v if it is a number/bool 102 | // and whether it is a number/bool or not. 103 | func keyFloat(v reflect.Value) (f float64, ok bool) { 104 | switch v.Kind() { 105 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 106 | return float64(v.Int()), true 107 | case reflect.Float32, reflect.Float64: 108 | return v.Float(), true 109 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 110 | return float64(v.Uint()), true 111 | case reflect.Bool: 112 | if v.Bool() { 113 | return 1, true 114 | } 115 | return 0, true 116 | } 117 | return 0, false 118 | } 119 | 120 | // numLess returns whether a < b. 121 | // a and b must necessarily have the same kind. 122 | func numLess(a, b reflect.Value) bool { 123 | switch a.Kind() { 124 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 125 | return a.Int() < b.Int() 126 | case reflect.Float32, reflect.Float64: 127 | return a.Float() < b.Float() 128 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 129 | return a.Uint() < b.Uint() 130 | case reflect.Bool: 131 | return !a.Bool() && b.Bool() 132 | } 133 | panic("not a number") 134 | } 135 | -------------------------------------------------------------------------------- /net/ip.go: -------------------------------------------------------------------------------- 1 | package net 2 | 3 | import ( 4 | "encoding/binary" 5 | "fmt" 6 | "net" 7 | "strings" 8 | ) 9 | 10 | type IP struct { 11 | ip net.IP 12 | } 13 | 14 | func (i *IP) setDefault() { 15 | i.ip = net.IPv4(127, 0, 0, 1) 16 | } 17 | 18 | func (i *IP) isValid() bool { 19 | if i.ip == nil || i.ip.String() == "" || i.ip.IsUnspecified() { 20 | return false 21 | } 22 | 23 | return true 24 | } 25 | 26 | func (i IP) String() string { 27 | if i.ip == nil { 28 | return "" 29 | } 30 | 31 | return i.ip.String() 32 | } 33 | 34 | func (i *IP) Parse(ip string) { 35 | i.setDefault() 36 | 37 | iip := net.ParseIP(ip) 38 | if iip == nil { 39 | return 40 | } 41 | 42 | i.ip = iip 43 | 44 | if !i.isValid() { 45 | i.setDefault() 46 | } 47 | } 48 | 49 | func (i *IP) FromNetIP(ip net.IP) { 50 | if ip == nil { 51 | return 52 | } 53 | 54 | iip := net.ParseIP(ip.String()) 55 | if iip == nil { 56 | return 57 | } 58 | 59 | i.ip = iip 60 | 61 | if !i.isValid() { 62 | i.setDefault() 63 | } 64 | } 65 | 66 | func (i *IP) FromNetAddr(addr net.Addr) { 67 | if addr == nil { 68 | i.setDefault() 69 | return 70 | } 71 | 72 | if addr.Network() != "udp" { 73 | i.setDefault() 74 | return 75 | } 76 | 77 | if a, err := net.ResolveUDPAddr("udp", addr.String()); err == nil { 78 | if a == nil || a.IP == nil { 79 | i.setDefault() 80 | } else { 81 | i.ip = a.IP 82 | } 83 | } else { 84 | i.setDefault() 85 | } 86 | } 87 | 88 | // Unmarshal converts 16 bytes in host byte order to IP 89 | func (i *IP) Unmarshal(data []byte) error { 90 | if len(data) != 4 && len(data) != 16 { 91 | return fmt.Errorf("invalid number of bytes") 92 | } 93 | 94 | if len(data) == 4 { 95 | ip0 := binary.LittleEndian.Uint32(data[0:]) 96 | 97 | i.ip = net.IPv4(byte((ip0&0xff000000)>>24), byte((ip0&0x00ff0000)>>16), byte((ip0&0x0000ff00)>>8), byte(ip0&0x0000ff)) 98 | } else { 99 | ip3 := binary.LittleEndian.Uint32(data[0:]) 100 | ip2 := binary.LittleEndian.Uint32(data[4:]) 101 | ip1 := binary.LittleEndian.Uint32(data[8:]) 102 | ip0 := binary.LittleEndian.Uint32(data[12:]) 103 | 104 | if ip0 == 0 && ip1 == 0 && ip2 == 0 { 105 | i.ip = net.IPv4(byte((ip3&0xff000000)>>24), byte((ip3&0x00ff0000)>>16), byte((ip3&0x0000ff00)>>8), byte(ip3&0x0000ff)) 106 | } else { 107 | var b strings.Builder 108 | 109 | fmt.Fprintf(&b, "%04x:", (ip0&0xffff0000)>>16) 110 | fmt.Fprintf(&b, "%04x:", ip0&0x0000ffff) 111 | fmt.Fprintf(&b, "%04x:", (ip1&0xffff0000)>>16) 112 | fmt.Fprintf(&b, "%04x:", ip1&0x0000ffff) 113 | fmt.Fprintf(&b, "%04x:", (ip2&0xffff0000)>>16) 114 | fmt.Fprintf(&b, "%04x:", ip2&0x0000ffff) 115 | fmt.Fprintf(&b, "%04x:", (ip3&0xffff0000)>>16) 116 | fmt.Fprintf(&b, "%04x", ip3&0x0000ffff) 117 | 118 | iip := net.ParseIP(b.String()) 119 | if iip == nil { 120 | return fmt.Errorf("invalid ip") 121 | } 122 | 123 | i.ip = iip 124 | } 125 | } 126 | 127 | if !i.isValid() { 128 | i.setDefault() 129 | } 130 | 131 | return nil 132 | } 133 | 134 | // Marshal converts an IP to 16 byte host byte order 135 | func (i *IP) Marshal(data []byte) { 136 | if i.ip == nil || !i.isValid() { 137 | i.setDefault() 138 | } 139 | 140 | if len([]byte(i.ip)) == 4 { 141 | i.ip = net.IPv4(i.ip[0], i.ip[1], i.ip[2], i.ip[3]) 142 | } 143 | 144 | if len(data) < 16 { 145 | return 146 | } 147 | 148 | data[0] = i.ip[15] 149 | data[1] = i.ip[14] 150 | data[2] = i.ip[13] 151 | data[3] = i.ip[12] 152 | 153 | if i.ip.To4() != nil { 154 | data[4] = 0 155 | data[5] = 0 156 | data[6] = 0 157 | data[7] = 0 158 | 159 | data[8] = 0 160 | data[9] = 0 161 | data[10] = 0 162 | data[11] = 0 163 | 164 | data[12] = 0 165 | data[13] = 0 166 | data[14] = 0 167 | data[15] = 0 168 | } else { 169 | data[4] = i.ip[11] 170 | data[5] = i.ip[10] 171 | data[6] = i.ip[9] 172 | data[7] = i.ip[8] 173 | 174 | data[8] = i.ip[7] 175 | data[9] = i.ip[6] 176 | data[10] = i.ip[5] 177 | data[11] = i.ip[4] 178 | 179 | data[12] = i.ip[3] 180 | data[13] = i.ip[2] 181 | data[14] = i.ip[1] 182 | data[15] = i.ip[0] 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/README.md: -------------------------------------------------------------------------------- 1 | # YAML support for the Go language 2 | 3 | Introduction 4 | ------------ 5 | 6 | The yaml package enables Go programs to comfortably encode and decode YAML 7 | values. It was developed within [Canonical](https://www.canonical.com) as 8 | part of the [juju](https://juju.ubuntu.com) project, and is based on a 9 | pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) 10 | C library to parse and generate YAML data quickly and reliably. 11 | 12 | Compatibility 13 | ------------- 14 | 15 | The yaml package supports most of YAML 1.2, but preserves some behavior 16 | from 1.1 for backwards compatibility. 17 | 18 | Specifically, as of v3 of the yaml package: 19 | 20 | - YAML 1.1 bools (_yes/no, on/off_) are supported as long as they are being 21 | decoded into a typed bool value. Otherwise they behave as a string. Booleans 22 | in YAML 1.2 are _true/false_ only. 23 | - Octals encode and decode as _0777_ per YAML 1.1, rather than _0o777_ 24 | as specified in YAML 1.2, because most parsers still use the old format. 25 | Octals in the _0o777_ format are supported though, so new files work. 26 | - Does not support base-60 floats. These are gone from YAML 1.2, and were 27 | actually never supported by this package as it's clearly a poor choice. 28 | 29 | and offers backwards 30 | compatibility with YAML 1.1 in some cases. 31 | 1.2, including support for 32 | anchors, tags, map merging, etc. Multi-document unmarshalling is not yet 33 | implemented, and base-60 floats from YAML 1.1 are purposefully not 34 | supported since they're a poor design and are gone in YAML 1.2. 35 | 36 | Installation and usage 37 | ---------------------- 38 | 39 | The import path for the package is *gopkg.in/yaml.v3*. 40 | 41 | To install it, run: 42 | 43 | go get gopkg.in/yaml.v3 44 | 45 | API documentation 46 | ----------------- 47 | 48 | If opened in a browser, the import path itself leads to the API documentation: 49 | 50 | - [https://gopkg.in/yaml.v3](https://gopkg.in/yaml.v3) 51 | 52 | API stability 53 | ------------- 54 | 55 | The package API for yaml v3 will remain stable as described in [gopkg.in](https://gopkg.in). 56 | 57 | 58 | License 59 | ------- 60 | 61 | The yaml package is licensed under the MIT and Apache License 2.0 licenses. 62 | Please see the LICENSE file for details. 63 | 64 | 65 | Example 66 | ------- 67 | 68 | ```Go 69 | package main 70 | 71 | import ( 72 | "fmt" 73 | "log" 74 | 75 | "gopkg.in/yaml.v3" 76 | ) 77 | 78 | var data = ` 79 | a: Easy! 80 | b: 81 | c: 2 82 | d: [3, 4] 83 | ` 84 | 85 | // Note: struct fields must be public in order for unmarshal to 86 | // correctly populate the data. 87 | type T struct { 88 | A string 89 | B struct { 90 | RenamedC int `yaml:"c"` 91 | D []int `yaml:",flow"` 92 | } 93 | } 94 | 95 | func main() { 96 | t := T{} 97 | 98 | err := yaml.Unmarshal([]byte(data), &t) 99 | if err != nil { 100 | log.Fatalf("error: %v", err) 101 | } 102 | fmt.Printf("--- t:\n%v\n\n", t) 103 | 104 | d, err := yaml.Marshal(&t) 105 | if err != nil { 106 | log.Fatalf("error: %v", err) 107 | } 108 | fmt.Printf("--- t dump:\n%s\n\n", string(d)) 109 | 110 | m := make(map[interface{}]interface{}) 111 | 112 | err = yaml.Unmarshal([]byte(data), &m) 113 | if err != nil { 114 | log.Fatalf("error: %v", err) 115 | } 116 | fmt.Printf("--- m:\n%v\n\n", m) 117 | 118 | d, err = yaml.Marshal(&m) 119 | if err != nil { 120 | log.Fatalf("error: %v", err) 121 | } 122 | fmt.Printf("--- m dump:\n%s\n\n", string(d)) 123 | } 124 | ``` 125 | 126 | This example will generate the following output: 127 | 128 | ``` 129 | --- t: 130 | {Easy! {2 [3 4]}} 131 | 132 | --- t dump: 133 | a: Easy! 134 | b: 135 | c: 2 136 | d: [3, 4] 137 | 138 | 139 | --- m: 140 | map[a:Easy! b:map[c:2 d:[3 4]]] 141 | 142 | --- m dump: 143 | a: Easy! 144 | b: 145 | c: 2 146 | d: 147 | - 3 148 | - 4 149 | ``` 150 | 151 | -------------------------------------------------------------------------------- /pubsub.go: -------------------------------------------------------------------------------- 1 | package srt 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | "io" 7 | "sync" 8 | 9 | "github.com/datarhei/gosrt/packet" 10 | ) 11 | 12 | // PubSub is a publish/subscriber service for SRT connections. 13 | type PubSub interface { 14 | // Publish accepts a SRT connection where it reads from. It blocks 15 | // until the connection closes. The returned error indicates why it 16 | // stopped. There can be only one publisher. 17 | Publish(c Conn) error 18 | 19 | // Subscribe accepts a SRT connection where it writes the data from 20 | // the publisher to. It blocks until an error happens. If the publisher 21 | // disconnects, io.EOF is returned. There can be an arbitrary number 22 | // of subscribers. 23 | Subscribe(c Conn) error 24 | } 25 | 26 | // pubSub is an implementation of the PubSub interface 27 | type pubSub struct { 28 | incoming chan packet.Packet 29 | ctx context.Context 30 | cancel context.CancelFunc 31 | publish bool 32 | publishLock sync.Mutex 33 | listeners map[uint32]chan packet.Packet 34 | listenersLock sync.Mutex 35 | logger Logger 36 | } 37 | 38 | // PubSubConfig is for configuring a new PubSub 39 | type PubSubConfig struct { 40 | Logger Logger // Optional logger 41 | } 42 | 43 | // NewPubSub returns a PubSub. After the publishing connection closed 44 | // this PubSub can't be used anymore. 45 | func NewPubSub(config PubSubConfig) PubSub { 46 | pb := &pubSub{ 47 | incoming: make(chan packet.Packet, 1024), 48 | listeners: make(map[uint32]chan packet.Packet), 49 | logger: config.Logger, 50 | } 51 | 52 | pb.ctx, pb.cancel = context.WithCancel(context.Background()) 53 | 54 | if pb.logger == nil { 55 | pb.logger = NewLogger(nil) 56 | } 57 | 58 | go pb.broadcast() 59 | 60 | return pb 61 | } 62 | 63 | func (pb *pubSub) broadcast() { 64 | defer func() { 65 | pb.logger.Print("pubsub:close", 0, 1, func() string { return "exiting broadcast loop" }) 66 | }() 67 | 68 | pb.logger.Print("pubsub:new", 0, 1, func() string { return "starting broadcast loop" }) 69 | 70 | for { 71 | select { 72 | case <-pb.ctx.Done(): 73 | return 74 | case p := <-pb.incoming: 75 | pb.listenersLock.Lock() 76 | for socketId, c := range pb.listeners { 77 | pp := p.Clone() 78 | 79 | select { 80 | case c <- pp: 81 | default: 82 | pb.logger.Print("pubsub:error", socketId, 1, func() string { return "broadcast target queue is full" }) 83 | } 84 | } 85 | pb.listenersLock.Unlock() 86 | 87 | // We don't need this packet anymore 88 | p.Decommission() 89 | } 90 | } 91 | } 92 | 93 | func (pb *pubSub) Publish(c Conn) error { 94 | pb.publishLock.Lock() 95 | defer pb.publishLock.Unlock() 96 | 97 | if pb.publish { 98 | err := fmt.Errorf("only one publisher is allowed") 99 | pb.logger.Print("pubsub:error", 0, 1, func() string { return err.Error() }) 100 | return err 101 | } 102 | 103 | var p packet.Packet 104 | var err error 105 | 106 | socketId := c.SocketId() 107 | 108 | pb.logger.Print("pubsub:publish", socketId, 1, func() string { return "new publisher" }) 109 | 110 | pb.publish = true 111 | 112 | for { 113 | p, err = c.ReadPacket() 114 | if err != nil { 115 | pb.logger.Print("pubsub:error", socketId, 1, func() string { return err.Error() }) 116 | break 117 | } 118 | 119 | select { 120 | case pb.incoming <- p: 121 | default: 122 | pb.logger.Print("pubsub:error", socketId, 1, func() string { return "incoming queue is full" }) 123 | } 124 | } 125 | 126 | pb.cancel() 127 | 128 | return err 129 | } 130 | 131 | func (pb *pubSub) Subscribe(c Conn) error { 132 | l := make(chan packet.Packet, 1024) 133 | socketId := c.SocketId() 134 | 135 | pb.logger.Print("pubsub:subscribe", socketId, 1, func() string { return "new subscriber" }) 136 | 137 | pb.listenersLock.Lock() 138 | pb.listeners[socketId] = l 139 | pb.listenersLock.Unlock() 140 | 141 | defer func() { 142 | pb.listenersLock.Lock() 143 | delete(pb.listeners, socketId) 144 | pb.listenersLock.Unlock() 145 | }() 146 | 147 | for { 148 | select { 149 | case <-pb.ctx.Done(): 150 | return io.EOF 151 | case p := <-l: 152 | err := c.WritePacket(p) 153 | p.Decommission() 154 | if err != nil { 155 | pb.logger.Print("pubsub:error", socketId, 1, func() string { return err.Error() }) 156 | return err 157 | } 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /circular/circular.go: -------------------------------------------------------------------------------- 1 | // Package circular implements "circular numbers". This is a number that can be 2 | // increased (or decreased) indefinitely while only using up a limited amount of 3 | // memory. This feature comes with the limitiation in how distant two such 4 | // numbers can be. Circular numbers have a maximum. The maximum distance is 5 | // half the maximum value. If a number that has the maximum value is 6 | // increased by 1, it becomes 0. If a number that has the value of 0 is 7 | // decreased by 1, it becomes the maximum value. By comparing two circular 8 | // numbers it is not possible to tell how often they wrapped. Therefore these 9 | // two numbers must come from the same domain in order to make sense of the 10 | // camparison. 11 | package circular 12 | 13 | // Number represents a "circular number". A Number is immutable. All modification 14 | // to a Number will result in a new instance of a Number. 15 | type Number struct { 16 | max uint32 17 | threshold uint32 18 | value uint32 19 | } 20 | 21 | // New returns a new circular number with the value of x and the maximum of max. 22 | func New(x, max uint32) Number { 23 | c := Number{ 24 | value: 0, 25 | max: max, 26 | threshold: max / 2, 27 | } 28 | 29 | if x > max { 30 | return c.Add(x) 31 | } 32 | 33 | c.value = x 34 | 35 | return c 36 | } 37 | 38 | // Val returns the current value of the number. 39 | func (a Number) Val() uint32 { 40 | return a.value 41 | } 42 | 43 | // Equals returns whether two circular numbers have the same value. 44 | func (a Number) Equals(b Number) bool { 45 | return a.value == b.value 46 | } 47 | 48 | // Distance returns the distance of two circular numbers. 49 | func (a Number) Distance(b Number) uint32 { 50 | if a.Equals(b) { 51 | return 0 52 | } 53 | 54 | d := uint32(0) 55 | 56 | if a.value > b.value { 57 | d = a.value - b.value 58 | } else { 59 | d = b.value - a.value 60 | } 61 | 62 | if d >= a.threshold { 63 | d = a.max - d + 1 64 | } 65 | 66 | return d 67 | } 68 | 69 | // Lt returns whether the circular number is lower than the circular number b. 70 | func (a Number) Lt(b Number) bool { 71 | if a.Equals(b) { 72 | return false 73 | } 74 | 75 | d := uint32(0) 76 | altb := false 77 | 78 | if a.value > b.value { 79 | d = a.value - b.value 80 | } else { 81 | d = b.value - a.value 82 | altb = true 83 | } 84 | 85 | if d < a.threshold { 86 | return altb 87 | } 88 | 89 | return !altb 90 | } 91 | 92 | // Lte returns whether the circular number is lower than or equal to the circular number b. 93 | func (a Number) Lte(b Number) bool { 94 | if a.Equals(b) { 95 | return true 96 | } 97 | 98 | return a.Lt(b) 99 | } 100 | 101 | // Gt returns whether the circular number is greather than the circular number b. 102 | func (a Number) Gt(b Number) bool { 103 | if a.Equals(b) { 104 | return false 105 | } 106 | 107 | d := uint32(0) 108 | agtb := false 109 | 110 | if a.value > b.value { 111 | d = a.value - b.value 112 | agtb = true 113 | } else { 114 | d = b.value - a.value 115 | } 116 | 117 | if d < a.threshold { 118 | return agtb 119 | } 120 | 121 | return !agtb 122 | } 123 | 124 | // Gte returns whether the circular number is greather than or equal to the circular number b. 125 | func (a Number) Gte(b Number) bool { 126 | if a.Equals(b) { 127 | return true 128 | } 129 | 130 | return a.Gt(b) 131 | } 132 | 133 | // Inc returns a new circular number with a value that is increased by 1. 134 | func (a Number) Inc() Number { 135 | b := a 136 | 137 | if b.value == b.max { 138 | b.value = 0 139 | } else { 140 | b.value++ 141 | } 142 | 143 | return b 144 | } 145 | 146 | // Add returns a new circular number with a value that is increased by b. 147 | func (a Number) Add(b uint32) Number { 148 | c := a 149 | x := c.max - c.value 150 | 151 | if b <= x { 152 | c.value += b 153 | } else { 154 | c.value = b - x - 1 155 | } 156 | 157 | return c 158 | } 159 | 160 | // Dec returns a new circular number with a value that is decreased by 1. 161 | func (a Number) Dec() Number { 162 | b := a 163 | 164 | if b.value == 0 { 165 | b.value = b.max 166 | } else { 167 | b.value-- 168 | } 169 | 170 | return b 171 | } 172 | 173 | // Sub returns a new circular number with a value that is decreased by b. 174 | func (a Number) Sub(b uint32) Number { 175 | c := a 176 | 177 | if b <= c.value { 178 | c.value -= b 179 | } else { 180 | c.value = c.max - (b - c.value) + 1 181 | } 182 | 183 | return c 184 | } 185 | -------------------------------------------------------------------------------- /congestion/live/fake.go: -------------------------------------------------------------------------------- 1 | package live 2 | 3 | import ( 4 | "sync" 5 | "time" 6 | 7 | "github.com/datarhei/gosrt/circular" 8 | "github.com/datarhei/gosrt/congestion" 9 | "github.com/datarhei/gosrt/packet" 10 | ) 11 | 12 | type fakeLiveReceive struct { 13 | maxSeenSequenceNumber circular.Number 14 | lastACKSequenceNumber circular.Number 15 | lastDeliveredSequenceNumber circular.Number 16 | 17 | nPackets uint 18 | 19 | periodicACKInterval uint64 // config 20 | periodicNAKInterval uint64 // config 21 | 22 | lastPeriodicACK uint64 23 | 24 | avgPayloadSize float64 // bytes 25 | 26 | rate struct { 27 | last time.Time 28 | period time.Duration 29 | 30 | packets uint64 31 | bytes uint64 32 | 33 | pps float64 34 | bps float64 35 | } 36 | 37 | sendACK func(seq circular.Number, light bool) 38 | sendNAK func(list []circular.Number) 39 | deliver func(p packet.Packet) 40 | 41 | lock sync.RWMutex 42 | } 43 | 44 | func NewFakeLiveReceive(config ReceiveConfig) congestion.Receiver { 45 | r := &fakeLiveReceive{ 46 | maxSeenSequenceNumber: config.InitialSequenceNumber.Dec(), 47 | lastACKSequenceNumber: config.InitialSequenceNumber.Dec(), 48 | lastDeliveredSequenceNumber: config.InitialSequenceNumber.Dec(), 49 | 50 | periodicACKInterval: config.PeriodicACKInterval, 51 | periodicNAKInterval: config.PeriodicNAKInterval, 52 | 53 | avgPayloadSize: 1456, // 5.1.2. SRT's Default LiveCC Algorithm 54 | 55 | sendACK: config.OnSendACK, 56 | sendNAK: config.OnSendNAK, 57 | deliver: config.OnDeliver, 58 | } 59 | 60 | if r.sendACK == nil { 61 | r.sendACK = func(seq circular.Number, light bool) {} 62 | } 63 | 64 | if r.sendNAK == nil { 65 | r.sendNAK = func(list []circular.Number) {} 66 | } 67 | 68 | if r.deliver == nil { 69 | r.deliver = func(p packet.Packet) {} 70 | } 71 | 72 | r.rate.last = time.Now() 73 | r.rate.period = time.Second 74 | 75 | return r 76 | } 77 | 78 | func (r *fakeLiveReceive) Stats() congestion.ReceiveStats { return congestion.ReceiveStats{} } 79 | func (r *fakeLiveReceive) PacketRate() (pps, bps, capacity float64) { 80 | r.lock.Lock() 81 | defer r.lock.Unlock() 82 | 83 | tdiff := time.Since(r.rate.last) 84 | 85 | if tdiff < r.rate.period { 86 | pps = r.rate.pps 87 | bps = r.rate.bps 88 | 89 | return 90 | } 91 | 92 | r.rate.pps = float64(r.rate.packets) / tdiff.Seconds() 93 | r.rate.bps = float64(r.rate.bytes) / tdiff.Seconds() 94 | 95 | r.rate.packets, r.rate.bytes = 0, 0 96 | r.rate.last = time.Now() 97 | 98 | pps = r.rate.pps 99 | bps = r.rate.bps 100 | 101 | return 102 | } 103 | 104 | func (r *fakeLiveReceive) Flush() {} 105 | 106 | func (r *fakeLiveReceive) Push(pkt packet.Packet) { 107 | r.lock.Lock() 108 | defer r.lock.Unlock() 109 | 110 | if pkt == nil { 111 | return 112 | } 113 | 114 | r.nPackets++ 115 | 116 | pktLen := pkt.Len() 117 | 118 | r.rate.packets++ 119 | r.rate.bytes += pktLen 120 | 121 | // 5.1.2. SRT's Default LiveCC Algorithm 122 | r.avgPayloadSize = 0.875*r.avgPayloadSize + 0.125*float64(pktLen) 123 | 124 | if pkt.Header().PacketSequenceNumber.Lte(r.lastDeliveredSequenceNumber) { 125 | // Too old, because up until r.lastDeliveredSequenceNumber, we already delivered 126 | return 127 | } 128 | 129 | if pkt.Header().PacketSequenceNumber.Lt(r.lastACKSequenceNumber) { 130 | // Already acknowledged, ignoring 131 | return 132 | } 133 | 134 | if pkt.Header().PacketSequenceNumber.Lte(r.maxSeenSequenceNumber) { 135 | return 136 | } 137 | 138 | r.maxSeenSequenceNumber = pkt.Header().PacketSequenceNumber 139 | } 140 | 141 | func (r *fakeLiveReceive) periodicACK(now uint64) (ok bool, sequenceNumber circular.Number, lite bool) { 142 | r.lock.RLock() 143 | defer r.lock.RUnlock() 144 | 145 | // 4.8.1. Packet Acknowledgement (ACKs, ACKACKs) 146 | if now-r.lastPeriodicACK < r.periodicACKInterval { 147 | if r.nPackets >= 64 { 148 | lite = true // Send light ACK 149 | } else { 150 | return 151 | } 152 | } 153 | 154 | ok = true 155 | sequenceNumber = r.maxSeenSequenceNumber.Inc() 156 | 157 | r.lastACKSequenceNumber = r.maxSeenSequenceNumber 158 | 159 | r.lastPeriodicACK = now 160 | r.nPackets = 0 161 | 162 | return 163 | } 164 | 165 | func (r *fakeLiveReceive) Tick(now uint64) { 166 | if ok, sequenceNumber, lite := r.periodicACK(now); ok { 167 | r.sendACK(sequenceNumber, lite) 168 | } 169 | 170 | // Deliver packets whose PktTsbpdTime is ripe 171 | r.lock.Lock() 172 | defer r.lock.Unlock() 173 | 174 | r.lastDeliveredSequenceNumber = r.lastACKSequenceNumber 175 | } 176 | 177 | func (r *fakeLiveReceive) SetNAKInterval(nakInterval uint64) { 178 | r.lock.Lock() 179 | defer r.lock.Unlock() 180 | 181 | r.periodicNAKInterval = nakInterval 182 | } 183 | -------------------------------------------------------------------------------- /vendor/github.com/benburkert/openpgp/aes/keywrap/keywrap.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Matthew Endsley 2 | // All rights reserved 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted providing that the following conditions 6 | // are met: 7 | // 1. Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // 2. Redistributions in binary form must reproduce the above copyright 10 | // notice, this list of conditions and the following disclaimer in the 11 | // documentation and/or other materials provided with the distribution. 12 | // 13 | // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 14 | // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 | // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 | // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 | // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 | // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 21 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 22 | // IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23 | // POSSIBILITY OF SUCH DAMAGE. 24 | 25 | package keywrap 26 | 27 | import ( 28 | "crypto/aes" 29 | "encoding/binary" 30 | "errors" 31 | ) 32 | 33 | var ( 34 | // ErrWrapPlaintext is returned if the plaintext is not a multiple 35 | // of 64 bits. 36 | ErrWrapPlaintext = errors.New("keywrap: plainText must be a multiple of 64 bits") 37 | 38 | // ErrUnwrapCiphertext is returned if the ciphertext is not a 39 | // multiple of 64 bits. 40 | ErrUnwrapCiphertext = errors.New("keywrap: cipherText must by a multiple of 64 bits") 41 | 42 | // ErrUnwrapFailed is returned if unwrapping a key fails. 43 | ErrUnwrapFailed = errors.New("keywrap: failed to unwrap key") 44 | 45 | // NB: the AES NewCipher call only fails if the key is an invalid length. 46 | 47 | // ErrInvalidKey is returned when the AES key is invalid. 48 | ErrInvalidKey = errors.New("keywrap: invalid AES key") 49 | ) 50 | 51 | // Wrap a key using the RFC 3394 AES Key Wrap Algorithm. 52 | func Wrap(key, plainText []byte) ([]byte, error) { 53 | if len(plainText)%8 != 0 { 54 | return nil, ErrWrapPlaintext 55 | } 56 | 57 | c, err := aes.NewCipher(key) 58 | if err != nil { 59 | return nil, ErrInvalidKey 60 | } 61 | 62 | nblocks := len(plainText) / 8 63 | 64 | // 1) Initialize variables. 65 | var block [aes.BlockSize]byte 66 | // - Set A = IV, an initial value (see 2.2.3) 67 | for ii := 0; ii < 8; ii++ { 68 | block[ii] = 0xA6 69 | } 70 | 71 | // - For i = 1 to n 72 | // - Set R[i] = P[i] 73 | intermediate := make([]byte, len(plainText)) 74 | copy(intermediate, plainText) 75 | 76 | // 2) Calculate intermediate values. 77 | for ii := 0; ii < 6; ii++ { 78 | for jj := 0; jj < nblocks; jj++ { 79 | // - B = AES(K, A | R[i]) 80 | copy(block[8:], intermediate[jj*8:jj*8+8]) 81 | c.Encrypt(block[:], block[:]) 82 | 83 | // - A = MSB(64, B) ^ t where t = (n*j)+1 84 | t := uint64(ii*nblocks + jj + 1) 85 | val := binary.BigEndian.Uint64(block[:8]) ^ t 86 | binary.BigEndian.PutUint64(block[:8], val) 87 | 88 | // - R[i] = LSB(64, B) 89 | copy(intermediate[jj*8:jj*8+8], block[8:]) 90 | } 91 | } 92 | 93 | // 3) Output results. 94 | // - Set C[0] = A 95 | // - For i = 1 to n 96 | // - C[i] = R[i] 97 | return append(block[:8], intermediate...), nil 98 | } 99 | 100 | // Unwrap a key using the RFC 3394 AES Key Wrap Algorithm. 101 | func Unwrap(key, cipherText []byte) ([]byte, error) { 102 | if len(cipherText)%8 != 0 { 103 | return nil, ErrUnwrapCiphertext 104 | } 105 | 106 | c, err := aes.NewCipher(key) 107 | if err != nil { 108 | return nil, ErrInvalidKey 109 | } 110 | 111 | nblocks := len(cipherText)/8 - 1 112 | 113 | // 1) Initialize variables. 114 | var block [aes.BlockSize]byte 115 | // - Set A = C[0] 116 | copy(block[:8], cipherText[:8]) 117 | 118 | // - For i = 1 to n 119 | // - Set R[i] = C[i] 120 | intermediate := make([]byte, len(cipherText)-8) 121 | copy(intermediate, cipherText[8:]) 122 | 123 | // 2) Compute intermediate values. 124 | for jj := 5; jj >= 0; jj-- { 125 | for ii := nblocks - 1; ii >= 0; ii-- { 126 | // - B = AES-1(K, (A ^ t) | R[i]) where t = n*j+1 127 | // - A = MSB(64, B) 128 | t := uint64(jj*nblocks + ii + 1) 129 | val := binary.BigEndian.Uint64(block[:8]) ^ t 130 | binary.BigEndian.PutUint64(block[:8], val) 131 | 132 | copy(block[8:], intermediate[ii*8:ii*8+8]) 133 | c.Decrypt(block[:], block[:]) 134 | 135 | // - R[i] = LSB(B, 64) 136 | copy(intermediate[ii*8:ii*8+8], block[8:]) 137 | } 138 | } 139 | 140 | // 3) Output results. 141 | // - If A is an appropriate initial value (see 2.2.3), 142 | for ii := 0; ii < 8; ii++ { 143 | if block[ii] != 0xA6 { 144 | return nil, ErrUnwrapFailed 145 | } 146 | } 147 | 148 | // - For i = 1 to n 149 | // - P[i] = R[i] 150 | return intermediate, nil 151 | } 152 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/bypass.go: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015-2016 Dave Collins 2 | // 3 | // Permission to use, copy, modify, and distribute this software for any 4 | // purpose with or without fee is hereby granted, provided that the above 5 | // copyright notice and this permission notice appear in all copies. 6 | // 7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | // NOTE: Due to the following build constraints, this file will only be compiled 16 | // when the code is not running on Google App Engine, compiled by GopherJS, and 17 | // "-tags safe" is not added to the go build command line. The "disableunsafe" 18 | // tag is deprecated and thus should not be used. 19 | // Go versions prior to 1.4 are disabled because they use a different layout 20 | // for interfaces which make the implementation of unsafeReflectValue more complex. 21 | // +build !js,!appengine,!safe,!disableunsafe,go1.4 22 | 23 | package spew 24 | 25 | import ( 26 | "reflect" 27 | "unsafe" 28 | ) 29 | 30 | const ( 31 | // UnsafeDisabled is a build-time constant which specifies whether or 32 | // not access to the unsafe package is available. 33 | UnsafeDisabled = false 34 | 35 | // ptrSize is the size of a pointer on the current arch. 36 | ptrSize = unsafe.Sizeof((*byte)(nil)) 37 | ) 38 | 39 | type flag uintptr 40 | 41 | var ( 42 | // flagRO indicates whether the value field of a reflect.Value 43 | // is read-only. 44 | flagRO flag 45 | 46 | // flagAddr indicates whether the address of the reflect.Value's 47 | // value may be taken. 48 | flagAddr flag 49 | ) 50 | 51 | // flagKindMask holds the bits that make up the kind 52 | // part of the flags field. In all the supported versions, 53 | // it is in the lower 5 bits. 54 | const flagKindMask = flag(0x1f) 55 | 56 | // Different versions of Go have used different 57 | // bit layouts for the flags type. This table 58 | // records the known combinations. 59 | var okFlags = []struct { 60 | ro, addr flag 61 | }{{ 62 | // From Go 1.4 to 1.5 63 | ro: 1 << 5, 64 | addr: 1 << 7, 65 | }, { 66 | // Up to Go tip. 67 | ro: 1<<5 | 1<<6, 68 | addr: 1 << 8, 69 | }} 70 | 71 | var flagValOffset = func() uintptr { 72 | field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") 73 | if !ok { 74 | panic("reflect.Value has no flag field") 75 | } 76 | return field.Offset 77 | }() 78 | 79 | // flagField returns a pointer to the flag field of a reflect.Value. 80 | func flagField(v *reflect.Value) *flag { 81 | return (*flag)(unsafe.Pointer(uintptr(unsafe.Pointer(v)) + flagValOffset)) 82 | } 83 | 84 | // unsafeReflectValue converts the passed reflect.Value into a one that bypasses 85 | // the typical safety restrictions preventing access to unaddressable and 86 | // unexported data. It works by digging the raw pointer to the underlying 87 | // value out of the protected value and generating a new unprotected (unsafe) 88 | // reflect.Value to it. 89 | // 90 | // This allows us to check for implementations of the Stringer and error 91 | // interfaces to be used for pretty printing ordinarily unaddressable and 92 | // inaccessible values such as unexported struct fields. 93 | func unsafeReflectValue(v reflect.Value) reflect.Value { 94 | if !v.IsValid() || (v.CanInterface() && v.CanAddr()) { 95 | return v 96 | } 97 | flagFieldPtr := flagField(&v) 98 | *flagFieldPtr &^= flagRO 99 | *flagFieldPtr |= flagAddr 100 | return v 101 | } 102 | 103 | // Sanity checks against future reflect package changes 104 | // to the type or semantics of the Value.flag field. 105 | func init() { 106 | field, ok := reflect.TypeOf(reflect.Value{}).FieldByName("flag") 107 | if !ok { 108 | panic("reflect.Value has no flag field") 109 | } 110 | if field.Type.Kind() != reflect.TypeOf(flag(0)).Kind() { 111 | panic("reflect.Value flag field has changed kind") 112 | } 113 | type t0 int 114 | var t struct { 115 | A t0 116 | // t0 will have flagEmbedRO set. 117 | t0 118 | // a will have flagStickyRO set 119 | a t0 120 | } 121 | vA := reflect.ValueOf(t).FieldByName("A") 122 | va := reflect.ValueOf(t).FieldByName("a") 123 | vt0 := reflect.ValueOf(t).FieldByName("t0") 124 | 125 | // Infer flagRO from the difference between the flags 126 | // for the (otherwise identical) fields in t. 127 | flagPublic := *flagField(&vA) 128 | flagWithRO := *flagField(&va) | *flagField(&vt0) 129 | flagRO = flagPublic ^ flagWithRO 130 | 131 | // Infer flagAddr from the difference between a value 132 | // taken from a pointer and not. 133 | vPtrA := reflect.ValueOf(&t).Elem().FieldByName("A") 134 | flagNoPtr := *flagField(&vA) 135 | flagPtr := *flagField(&vPtrA) 136 | flagAddr = flagNoPtr ^ flagPtr 137 | 138 | // Check that the inferred flags tally with one of the known versions. 139 | for _, f := range okFlags { 140 | if flagRO == f.ro && flagAddr == f.addr { 141 | return 142 | } 143 | } 144 | panic("reflect.Value read-only flag has changed semantics") 145 | } 146 | -------------------------------------------------------------------------------- /vendor/github.com/google/pprof/profile/prune.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Implements methods to remove frames from profiles. 16 | 17 | package profile 18 | 19 | import ( 20 | "fmt" 21 | "regexp" 22 | "strings" 23 | ) 24 | 25 | var ( 26 | reservedNames = []string{"(anonymous namespace)", "operator()"} 27 | bracketRx = func() *regexp.Regexp { 28 | var quotedNames []string 29 | for _, name := range append(reservedNames, "(") { 30 | quotedNames = append(quotedNames, regexp.QuoteMeta(name)) 31 | } 32 | return regexp.MustCompile(strings.Join(quotedNames, "|")) 33 | }() 34 | ) 35 | 36 | // simplifyFunc does some primitive simplification of function names. 37 | func simplifyFunc(f string) string { 38 | // Account for leading '.' on the PPC ELF v1 ABI. 39 | funcName := strings.TrimPrefix(f, ".") 40 | // Account for unsimplified names -- try to remove the argument list by trimming 41 | // starting from the first '(', but skipping reserved names that have '('. 42 | for _, ind := range bracketRx.FindAllStringSubmatchIndex(funcName, -1) { 43 | foundReserved := false 44 | for _, res := range reservedNames { 45 | if funcName[ind[0]:ind[1]] == res { 46 | foundReserved = true 47 | break 48 | } 49 | } 50 | if !foundReserved { 51 | funcName = funcName[:ind[0]] 52 | break 53 | } 54 | } 55 | return funcName 56 | } 57 | 58 | // Prune removes all nodes beneath a node matching dropRx, and not 59 | // matching keepRx. If the root node of a Sample matches, the sample 60 | // will have an empty stack. 61 | func (p *Profile) Prune(dropRx, keepRx *regexp.Regexp) { 62 | prune := make(map[uint64]bool) 63 | pruneBeneath := make(map[uint64]bool) 64 | 65 | for _, loc := range p.Location { 66 | var i int 67 | for i = len(loc.Line) - 1; i >= 0; i-- { 68 | if fn := loc.Line[i].Function; fn != nil && fn.Name != "" { 69 | funcName := simplifyFunc(fn.Name) 70 | if dropRx.MatchString(funcName) { 71 | if keepRx == nil || !keepRx.MatchString(funcName) { 72 | break 73 | } 74 | } 75 | } 76 | } 77 | 78 | if i >= 0 { 79 | // Found matching entry to prune. 80 | pruneBeneath[loc.ID] = true 81 | 82 | // Remove the matching location. 83 | if i == len(loc.Line)-1 { 84 | // Matched the top entry: prune the whole location. 85 | prune[loc.ID] = true 86 | } else { 87 | loc.Line = loc.Line[i+1:] 88 | } 89 | } 90 | } 91 | 92 | // Prune locs from each Sample 93 | for _, sample := range p.Sample { 94 | // Scan from the root to the leaves to find the prune location. 95 | // Do not prune frames before the first user frame, to avoid 96 | // pruning everything. 97 | foundUser := false 98 | for i := len(sample.Location) - 1; i >= 0; i-- { 99 | id := sample.Location[i].ID 100 | if !prune[id] && !pruneBeneath[id] { 101 | foundUser = true 102 | continue 103 | } 104 | if !foundUser { 105 | continue 106 | } 107 | if prune[id] { 108 | sample.Location = sample.Location[i+1:] 109 | break 110 | } 111 | if pruneBeneath[id] { 112 | sample.Location = sample.Location[i:] 113 | break 114 | } 115 | } 116 | } 117 | } 118 | 119 | // RemoveUninteresting prunes and elides profiles using built-in 120 | // tables of uninteresting function names. 121 | func (p *Profile) RemoveUninteresting() error { 122 | var keep, drop *regexp.Regexp 123 | var err error 124 | 125 | if p.DropFrames != "" { 126 | if drop, err = regexp.Compile("^(" + p.DropFrames + ")$"); err != nil { 127 | return fmt.Errorf("failed to compile regexp %s: %v", p.DropFrames, err) 128 | } 129 | if p.KeepFrames != "" { 130 | if keep, err = regexp.Compile("^(" + p.KeepFrames + ")$"); err != nil { 131 | return fmt.Errorf("failed to compile regexp %s: %v", p.KeepFrames, err) 132 | } 133 | } 134 | p.Prune(drop, keep) 135 | } 136 | return nil 137 | } 138 | 139 | // PruneFrom removes all nodes beneath the lowest node matching dropRx, not including itself. 140 | // 141 | // Please see the example below to understand this method as well as 142 | // the difference from Prune method. 143 | // 144 | // A sample contains Location of [A,B,C,B,D] where D is the top frame and there's no inline. 145 | // 146 | // PruneFrom(A) returns [A,B,C,B,D] because there's no node beneath A. 147 | // Prune(A, nil) returns [B,C,B,D] by removing A itself. 148 | // 149 | // PruneFrom(B) returns [B,C,B,D] by removing all nodes beneath the first B when scanning from the bottom. 150 | // Prune(B, nil) returns [D] because a matching node is found by scanning from the root. 151 | func (p *Profile) PruneFrom(dropRx *regexp.Regexp) { 152 | pruneBeneath := make(map[uint64]bool) 153 | 154 | for _, loc := range p.Location { 155 | for i := 0; i < len(loc.Line); i++ { 156 | if fn := loc.Line[i].Function; fn != nil && fn.Name != "" { 157 | funcName := simplifyFunc(fn.Name) 158 | if dropRx.MatchString(funcName) { 159 | // Found matching entry to prune. 160 | pruneBeneath[loc.ID] = true 161 | loc.Line = loc.Line[i:] 162 | break 163 | } 164 | } 165 | } 166 | } 167 | 168 | // Prune locs from each Sample 169 | for _, sample := range p.Sample { 170 | // Scan from the bottom leaf to the root to find the prune location. 171 | for i, loc := range sample.Location { 172 | if pruneBeneath[loc.ID] { 173 | sample.Location = sample.Location[i:] 174 | break 175 | } 176 | } 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /vendor/github.com/stretchr/testify/assert/http_assertions.go: -------------------------------------------------------------------------------- 1 | package assert 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "net/http/httptest" 7 | "net/url" 8 | "strings" 9 | ) 10 | 11 | // httpCode is a helper that returns HTTP code of the response. It returns -1 and 12 | // an error if building a new request fails. 13 | func httpCode(handler http.HandlerFunc, method, url string, values url.Values) (int, error) { 14 | w := httptest.NewRecorder() 15 | req, err := http.NewRequest(method, url, http.NoBody) 16 | if err != nil { 17 | return -1, err 18 | } 19 | req.URL.RawQuery = values.Encode() 20 | handler(w, req) 21 | return w.Code, nil 22 | } 23 | 24 | // HTTPSuccess asserts that a specified handler returns a success status code. 25 | // 26 | // assert.HTTPSuccess(t, myHandler, "POST", "http://www.google.com", nil) 27 | // 28 | // Returns whether the assertion was successful (true) or not (false). 29 | func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 30 | if h, ok := t.(tHelper); ok { 31 | h.Helper() 32 | } 33 | code, err := httpCode(handler, method, url, values) 34 | if err != nil { 35 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) 36 | } 37 | 38 | isSuccessCode := code >= http.StatusOK && code <= http.StatusPartialContent 39 | if !isSuccessCode { 40 | Fail(t, fmt.Sprintf("Expected HTTP success status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) 41 | } 42 | 43 | return isSuccessCode 44 | } 45 | 46 | // HTTPRedirect asserts that a specified handler returns a redirect status code. 47 | // 48 | // assert.HTTPRedirect(t, myHandler, "GET", "/a/b/c", url.Values{"a": []string{"b", "c"}} 49 | // 50 | // Returns whether the assertion was successful (true) or not (false). 51 | func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 52 | if h, ok := t.(tHelper); ok { 53 | h.Helper() 54 | } 55 | code, err := httpCode(handler, method, url, values) 56 | if err != nil { 57 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) 58 | } 59 | 60 | isRedirectCode := code >= http.StatusMultipleChoices && code <= http.StatusTemporaryRedirect 61 | if !isRedirectCode { 62 | Fail(t, fmt.Sprintf("Expected HTTP redirect status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) 63 | } 64 | 65 | return isRedirectCode 66 | } 67 | 68 | // HTTPError asserts that a specified handler returns an error status code. 69 | // 70 | // assert.HTTPError(t, myHandler, "POST", "/a/b/c", url.Values{"a": []string{"b", "c"}} 71 | // 72 | // Returns whether the assertion was successful (true) or not (false). 73 | func HTTPError(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, msgAndArgs ...interface{}) bool { 74 | if h, ok := t.(tHelper); ok { 75 | h.Helper() 76 | } 77 | code, err := httpCode(handler, method, url, values) 78 | if err != nil { 79 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) 80 | } 81 | 82 | isErrorCode := code >= http.StatusBadRequest 83 | if !isErrorCode { 84 | Fail(t, fmt.Sprintf("Expected HTTP error status code for %q but received %d", url+"?"+values.Encode(), code), msgAndArgs...) 85 | } 86 | 87 | return isErrorCode 88 | } 89 | 90 | // HTTPStatusCode asserts that a specified handler returns a specified status code. 91 | // 92 | // assert.HTTPStatusCode(t, myHandler, "GET", "/notImplemented", nil, 501) 93 | // 94 | // Returns whether the assertion was successful (true) or not (false). 95 | func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, statuscode int, msgAndArgs ...interface{}) bool { 96 | if h, ok := t.(tHelper); ok { 97 | h.Helper() 98 | } 99 | code, err := httpCode(handler, method, url, values) 100 | if err != nil { 101 | Fail(t, fmt.Sprintf("Failed to build test request, got error: %s", err), msgAndArgs...) 102 | } 103 | 104 | successful := code == statuscode 105 | if !successful { 106 | Fail(t, fmt.Sprintf("Expected HTTP status code %d for %q but received %d", statuscode, url+"?"+values.Encode(), code), msgAndArgs...) 107 | } 108 | 109 | return successful 110 | } 111 | 112 | // HTTPBody is a helper that returns HTTP body of the response. It returns 113 | // empty string if building a new request fails. 114 | func HTTPBody(handler http.HandlerFunc, method, url string, values url.Values) string { 115 | w := httptest.NewRecorder() 116 | if len(values) > 0 { 117 | url += "?" + values.Encode() 118 | } 119 | req, err := http.NewRequest(method, url, http.NoBody) 120 | if err != nil { 121 | return "" 122 | } 123 | handler(w, req) 124 | return w.Body.String() 125 | } 126 | 127 | // HTTPBodyContains asserts that a specified handler returns a 128 | // body that contains a string. 129 | // 130 | // assert.HTTPBodyContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") 131 | // 132 | // Returns whether the assertion was successful (true) or not (false). 133 | func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { 134 | if h, ok := t.(tHelper); ok { 135 | h.Helper() 136 | } 137 | body := HTTPBody(handler, method, url, values) 138 | 139 | contains := strings.Contains(body, fmt.Sprint(str)) 140 | if !contains { 141 | Fail(t, fmt.Sprintf("Expected response body for %q to contain %q but found %q", url+"?"+values.Encode(), str, body), msgAndArgs...) 142 | } 143 | 144 | return contains 145 | } 146 | 147 | // HTTPBodyNotContains asserts that a specified handler returns a 148 | // body that does not contain a string. 149 | // 150 | // assert.HTTPBodyNotContains(t, myHandler, "GET", "www.google.com", nil, "I'm Feeling Lucky") 151 | // 152 | // Returns whether the assertion was successful (true) or not (false). 153 | func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, url string, values url.Values, str interface{}, msgAndArgs ...interface{}) bool { 154 | if h, ok := t.(tHelper); ok { 155 | h.Helper() 156 | } 157 | body := HTTPBody(handler, method, url, values) 158 | 159 | contains := strings.Contains(body, fmt.Sprint(str)) 160 | if contains { 161 | Fail(t, fmt.Sprintf("Expected response body for %q to NOT contain %q but found %q", url+"?"+values.Encode(), str, body), msgAndArgs...) 162 | } 163 | 164 | return !contains 165 | } 166 | -------------------------------------------------------------------------------- /vendor/github.com/davecgh/go-spew/spew/spew.go: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2016 Dave Collins 3 | * 4 | * Permission to use, copy, modify, and distribute this software for any 5 | * purpose with or without fee is hereby granted, provided that the above 6 | * copyright notice and this permission notice appear in all copies. 7 | * 8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | */ 16 | 17 | package spew 18 | 19 | import ( 20 | "fmt" 21 | "io" 22 | ) 23 | 24 | // Errorf is a wrapper for fmt.Errorf that treats each argument as if it were 25 | // passed with a default Formatter interface returned by NewFormatter. It 26 | // returns the formatted string as a value that satisfies error. See 27 | // NewFormatter for formatting details. 28 | // 29 | // This function is shorthand for the following syntax: 30 | // 31 | // fmt.Errorf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 32 | func Errorf(format string, a ...interface{}) (err error) { 33 | return fmt.Errorf(format, convertArgs(a)...) 34 | } 35 | 36 | // Fprint is a wrapper for fmt.Fprint that treats each argument as if it were 37 | // passed with a default Formatter interface returned by NewFormatter. It 38 | // returns the number of bytes written and any write error encountered. See 39 | // NewFormatter for formatting details. 40 | // 41 | // This function is shorthand for the following syntax: 42 | // 43 | // fmt.Fprint(w, spew.NewFormatter(a), spew.NewFormatter(b)) 44 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) { 45 | return fmt.Fprint(w, convertArgs(a)...) 46 | } 47 | 48 | // Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were 49 | // passed with a default Formatter interface returned by NewFormatter. It 50 | // returns the number of bytes written and any write error encountered. See 51 | // NewFormatter for formatting details. 52 | // 53 | // This function is shorthand for the following syntax: 54 | // 55 | // fmt.Fprintf(w, format, spew.NewFormatter(a), spew.NewFormatter(b)) 56 | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) { 57 | return fmt.Fprintf(w, format, convertArgs(a)...) 58 | } 59 | 60 | // Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it 61 | // passed with a default Formatter interface returned by NewFormatter. See 62 | // NewFormatter for formatting details. 63 | // 64 | // This function is shorthand for the following syntax: 65 | // 66 | // fmt.Fprintln(w, spew.NewFormatter(a), spew.NewFormatter(b)) 67 | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) { 68 | return fmt.Fprintln(w, convertArgs(a)...) 69 | } 70 | 71 | // Print is a wrapper for fmt.Print that treats each argument as if it were 72 | // passed with a default Formatter interface returned by NewFormatter. It 73 | // returns the number of bytes written and any write error encountered. See 74 | // NewFormatter for formatting details. 75 | // 76 | // This function is shorthand for the following syntax: 77 | // 78 | // fmt.Print(spew.NewFormatter(a), spew.NewFormatter(b)) 79 | func Print(a ...interface{}) (n int, err error) { 80 | return fmt.Print(convertArgs(a)...) 81 | } 82 | 83 | // Printf is a wrapper for fmt.Printf that treats each argument as if it were 84 | // passed with a default Formatter interface returned by NewFormatter. It 85 | // returns the number of bytes written and any write error encountered. See 86 | // NewFormatter for formatting details. 87 | // 88 | // This function is shorthand for the following syntax: 89 | // 90 | // fmt.Printf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 91 | func Printf(format string, a ...interface{}) (n int, err error) { 92 | return fmt.Printf(format, convertArgs(a)...) 93 | } 94 | 95 | // Println is a wrapper for fmt.Println that treats each argument as if it were 96 | // passed with a default Formatter interface returned by NewFormatter. It 97 | // returns the number of bytes written and any write error encountered. See 98 | // NewFormatter for formatting details. 99 | // 100 | // This function is shorthand for the following syntax: 101 | // 102 | // fmt.Println(spew.NewFormatter(a), spew.NewFormatter(b)) 103 | func Println(a ...interface{}) (n int, err error) { 104 | return fmt.Println(convertArgs(a)...) 105 | } 106 | 107 | // Sprint is a wrapper for fmt.Sprint that treats each argument as if it were 108 | // passed with a default Formatter interface returned by NewFormatter. It 109 | // returns the resulting string. See NewFormatter for formatting details. 110 | // 111 | // This function is shorthand for the following syntax: 112 | // 113 | // fmt.Sprint(spew.NewFormatter(a), spew.NewFormatter(b)) 114 | func Sprint(a ...interface{}) string { 115 | return fmt.Sprint(convertArgs(a)...) 116 | } 117 | 118 | // Sprintf is a wrapper for fmt.Sprintf that treats each argument as if it were 119 | // passed with a default Formatter interface returned by NewFormatter. It 120 | // returns the resulting string. See NewFormatter for formatting details. 121 | // 122 | // This function is shorthand for the following syntax: 123 | // 124 | // fmt.Sprintf(format, spew.NewFormatter(a), spew.NewFormatter(b)) 125 | func Sprintf(format string, a ...interface{}) string { 126 | return fmt.Sprintf(format, convertArgs(a)...) 127 | } 128 | 129 | // Sprintln is a wrapper for fmt.Sprintln that treats each argument as if it 130 | // were passed with a default Formatter interface returned by NewFormatter. It 131 | // returns the resulting string. See NewFormatter for formatting details. 132 | // 133 | // This function is shorthand for the following syntax: 134 | // 135 | // fmt.Sprintln(spew.NewFormatter(a), spew.NewFormatter(b)) 136 | func Sprintln(a ...interface{}) string { 137 | return fmt.Sprintln(convertArgs(a)...) 138 | } 139 | 140 | // convertArgs accepts a slice of arguments and returns a slice of the same 141 | // length with each argument converted to a default spew Formatter interface. 142 | func convertArgs(args []interface{}) (formatters []interface{}) { 143 | formatters = make([]interface{}, len(args)) 144 | for index, arg := range args { 145 | formatters[index] = NewFormatter(arg) 146 | } 147 | return formatters 148 | } 149 | -------------------------------------------------------------------------------- /vendor/gopkg.in/yaml.v3/yamlprivateh.go: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2011-2019 Canonical Ltd 3 | // Copyright (c) 2006-2010 Kirill Simonov 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | // this software and associated documentation files (the "Software"), to deal in 7 | // the Software without restriction, including without limitation the rights to 8 | // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | // of the Software, and to permit persons to whom the Software is furnished to do 10 | // so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | package yaml 24 | 25 | const ( 26 | // The size of the input raw buffer. 27 | input_raw_buffer_size = 512 28 | 29 | // The size of the input buffer. 30 | // It should be possible to decode the whole raw buffer. 31 | input_buffer_size = input_raw_buffer_size * 3 32 | 33 | // The size of the output buffer. 34 | output_buffer_size = 128 35 | 36 | // The size of the output raw buffer. 37 | // It should be possible to encode the whole output buffer. 38 | output_raw_buffer_size = (output_buffer_size*2 + 2) 39 | 40 | // The size of other stacks and queues. 41 | initial_stack_size = 16 42 | initial_queue_size = 16 43 | initial_string_size = 16 44 | ) 45 | 46 | // Check if the character at the specified position is an alphabetical 47 | // character, a digit, '_', or '-'. 48 | func is_alpha(b []byte, i int) bool { 49 | return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' 50 | } 51 | 52 | // Check if the character at the specified position is a digit. 53 | func is_digit(b []byte, i int) bool { 54 | return b[i] >= '0' && b[i] <= '9' 55 | } 56 | 57 | // Get the value of a digit. 58 | func as_digit(b []byte, i int) int { 59 | return int(b[i]) - '0' 60 | } 61 | 62 | // Check if the character at the specified position is a hex-digit. 63 | func is_hex(b []byte, i int) bool { 64 | return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' 65 | } 66 | 67 | // Get the value of a hex-digit. 68 | func as_hex(b []byte, i int) int { 69 | bi := b[i] 70 | if bi >= 'A' && bi <= 'F' { 71 | return int(bi) - 'A' + 10 72 | } 73 | if bi >= 'a' && bi <= 'f' { 74 | return int(bi) - 'a' + 10 75 | } 76 | return int(bi) - '0' 77 | } 78 | 79 | // Check if the character is ASCII. 80 | func is_ascii(b []byte, i int) bool { 81 | return b[i] <= 0x7F 82 | } 83 | 84 | // Check if the character at the start of the buffer can be printed unescaped. 85 | func is_printable(b []byte, i int) bool { 86 | return ((b[i] == 0x0A) || // . == #x0A 87 | (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E 88 | (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF 89 | (b[i] > 0xC2 && b[i] < 0xED) || 90 | (b[i] == 0xED && b[i+1] < 0xA0) || 91 | (b[i] == 0xEE) || 92 | (b[i] == 0xEF && // #xE000 <= . <= #xFFFD 93 | !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF 94 | !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) 95 | } 96 | 97 | // Check if the character at the specified position is NUL. 98 | func is_z(b []byte, i int) bool { 99 | return b[i] == 0x00 100 | } 101 | 102 | // Check if the beginning of the buffer is a BOM. 103 | func is_bom(b []byte, i int) bool { 104 | return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF 105 | } 106 | 107 | // Check if the character at the specified position is space. 108 | func is_space(b []byte, i int) bool { 109 | return b[i] == ' ' 110 | } 111 | 112 | // Check if the character at the specified position is tab. 113 | func is_tab(b []byte, i int) bool { 114 | return b[i] == '\t' 115 | } 116 | 117 | // Check if the character at the specified position is blank (space or tab). 118 | func is_blank(b []byte, i int) bool { 119 | //return is_space(b, i) || is_tab(b, i) 120 | return b[i] == ' ' || b[i] == '\t' 121 | } 122 | 123 | // Check if the character at the specified position is a line break. 124 | func is_break(b []byte, i int) bool { 125 | return (b[i] == '\r' || // CR (#xD) 126 | b[i] == '\n' || // LF (#xA) 127 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 128 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 129 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) 130 | } 131 | 132 | func is_crlf(b []byte, i int) bool { 133 | return b[i] == '\r' && b[i+1] == '\n' 134 | } 135 | 136 | // Check if the character is a line break or NUL. 137 | func is_breakz(b []byte, i int) bool { 138 | //return is_break(b, i) || is_z(b, i) 139 | return ( 140 | // is_break: 141 | b[i] == '\r' || // CR (#xD) 142 | b[i] == '\n' || // LF (#xA) 143 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 144 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 145 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 146 | // is_z: 147 | b[i] == 0) 148 | } 149 | 150 | // Check if the character is a line break, space, or NUL. 151 | func is_spacez(b []byte, i int) bool { 152 | //return is_space(b, i) || is_breakz(b, i) 153 | return ( 154 | // is_space: 155 | b[i] == ' ' || 156 | // is_breakz: 157 | b[i] == '\r' || // CR (#xD) 158 | b[i] == '\n' || // LF (#xA) 159 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 160 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 161 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 162 | b[i] == 0) 163 | } 164 | 165 | // Check if the character is a line break, space, tab, or NUL. 166 | func is_blankz(b []byte, i int) bool { 167 | //return is_blank(b, i) || is_breakz(b, i) 168 | return ( 169 | // is_blank: 170 | b[i] == ' ' || b[i] == '\t' || 171 | // is_breakz: 172 | b[i] == '\r' || // CR (#xD) 173 | b[i] == '\n' || // LF (#xA) 174 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 175 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 176 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 177 | b[i] == 0) 178 | } 179 | 180 | // Determine the width of the character. 181 | func width(b byte) int { 182 | // Don't replace these by a switch without first 183 | // confirming that it is being inlined. 184 | if b&0x80 == 0x00 { 185 | return 1 186 | } 187 | if b&0xE0 == 0xC0 { 188 | return 2 189 | } 190 | if b&0xF0 == 0xE0 { 191 | return 3 192 | } 193 | if b&0xF8 == 0xF0 { 194 | return 4 195 | } 196 | return 0 197 | 198 | } 199 | -------------------------------------------------------------------------------- /crypto/crypto.go: -------------------------------------------------------------------------------- 1 | // Package crypto provides SRT cryptography 2 | package crypto 3 | 4 | import ( 5 | "crypto/aes" 6 | "crypto/cipher" 7 | "crypto/pbkdf2" 8 | "crypto/sha1" 9 | "encoding/binary" 10 | "errors" 11 | "fmt" 12 | 13 | "github.com/datarhei/gosrt/packet" 14 | "github.com/datarhei/gosrt/rand" 15 | 16 | "github.com/benburkert/openpgp/aes/keywrap" 17 | ) 18 | 19 | // Crypto implements the SRT data encryption and decryption. 20 | type Crypto interface { 21 | // Generate generates an even or odd SEK. 22 | GenerateSEK(key packet.PacketEncryption) error 23 | 24 | // UnmarshalMK unwraps the key with the passphrase in a Key Material Extension Message. If the passphrase 25 | // is wrong an error is returned. 26 | UnmarshalKM(km *packet.CIFKeyMaterialExtension, passphrase string) error 27 | 28 | // MarshalKM wraps the key with the passphrase and the odd/even SEK for a Key Material Extension Message. 29 | MarshalKM(km *packet.CIFKeyMaterialExtension, passphrase string, key packet.PacketEncryption) error 30 | 31 | // EncryptOrDecryptPayload encrypts or decrypts the data of a packet with an even or odd SEK and 32 | // the sequence number. 33 | EncryptOrDecryptPayload(data []byte, key packet.PacketEncryption, packetSequenceNumber uint32) error 34 | } 35 | 36 | // crypto implements the Crypto interface 37 | type crypto struct { 38 | salt []byte 39 | keyLength int 40 | 41 | evenSEK []byte 42 | oddSEK []byte 43 | } 44 | 45 | // New returns a new SRT data encryption and decryption for the keyLength. On failure 46 | // error is non-nil. 47 | func New(keyLength int) (Crypto, error) { 48 | // 3.2.2. Key Material 49 | switch keyLength { 50 | case 16: 51 | case 24: 52 | case 32: 53 | default: 54 | return nil, fmt.Errorf("crypto: invalid key size, must be either 16, 24, or 32") 55 | } 56 | 57 | c := &crypto{ 58 | keyLength: keyLength, 59 | } 60 | 61 | // 3.2.2. Key Material: "The only valid length of salt defined is 128 bits." 62 | c.salt = make([]byte, 16) 63 | if err := c.prng(c.salt); err != nil { 64 | return nil, fmt.Errorf("crypto: can't generate salt: %w", err) 65 | } 66 | 67 | sek, err := c.generateSEK(c.keyLength) 68 | if err != nil { 69 | return nil, err 70 | } 71 | c.evenSEK = sek 72 | 73 | sek, err = c.generateSEK(c.keyLength) 74 | if err != nil { 75 | return nil, err 76 | } 77 | c.oddSEK = sek 78 | 79 | return c, nil 80 | } 81 | 82 | func (c *crypto) GenerateSEK(key packet.PacketEncryption) error { 83 | if !key.IsValid() { 84 | return fmt.Errorf("crypto: unknown key type") 85 | } 86 | 87 | sek, err := c.generateSEK(c.keyLength) 88 | if err != nil { 89 | return err 90 | } 91 | 92 | switch key { 93 | case packet.EvenKeyEncrypted: 94 | c.evenSEK = sek 95 | case packet.OddKeyEncrypted: 96 | c.oddSEK = sek 97 | } 98 | 99 | return nil 100 | } 101 | 102 | func (c *crypto) generateSEK(keyLength int) ([]byte, error) { 103 | sek := make([]byte, keyLength) 104 | 105 | err := c.prng(sek) 106 | if err != nil { 107 | return nil, fmt.Errorf("crypto: can't generate SEK: %w", err) 108 | } 109 | 110 | return sek, nil 111 | } 112 | 113 | // ErrInvalidKey is returned when the packet encryption is invalid 114 | var ErrInvalidKey = errors.New("crypto: invalid key for encryption. Must be even, odd, or both") 115 | 116 | // ErrInvalidWrap is returned when the packet encryption indicates a different length of the wrapped key 117 | var ErrInvalidWrap = errors.New("crypto: the un/wrapped key has the wrong length") 118 | 119 | func (c *crypto) UnmarshalKM(km *packet.CIFKeyMaterialExtension, passphrase string) error { 120 | if km.KeyBasedEncryption == packet.UnencryptedPacket || !km.KeyBasedEncryption.IsValid() { 121 | return ErrInvalidKey 122 | } 123 | 124 | n := 1 125 | if km.KeyBasedEncryption == packet.EvenAndOddKey { 126 | n = 2 127 | } 128 | 129 | wrapLength := n * c.keyLength 130 | 131 | if len(km.Wrap)-8 != wrapLength { 132 | return ErrInvalidWrap 133 | } 134 | 135 | if len(km.Salt) != 0 { 136 | copy(c.salt, km.Salt) 137 | } 138 | 139 | kek, err := c.calculateKEK(passphrase, c.salt, c.keyLength) 140 | if err != nil { 141 | return err 142 | } 143 | 144 | unwrap, err := keywrap.Unwrap(kek, km.Wrap) 145 | if err != nil { 146 | return err 147 | } 148 | 149 | if len(unwrap) != wrapLength { 150 | return ErrInvalidWrap 151 | } 152 | 153 | switch km.KeyBasedEncryption { 154 | case packet.EvenKeyEncrypted: 155 | copy(c.evenSEK, unwrap) 156 | case packet.OddKeyEncrypted: 157 | copy(c.oddSEK, unwrap) 158 | default: 159 | copy(c.evenSEK, unwrap[:c.keyLength]) 160 | copy(c.oddSEK, unwrap[c.keyLength:]) 161 | } 162 | 163 | return nil 164 | } 165 | 166 | func (c *crypto) MarshalKM(km *packet.CIFKeyMaterialExtension, passphrase string, key packet.PacketEncryption) error { 167 | if key == packet.UnencryptedPacket || !key.IsValid() { 168 | return ErrInvalidKey 169 | } 170 | 171 | km.S = 0 172 | km.Version = 1 173 | km.PacketType = 2 174 | km.Sign = 0x2029 175 | km.KeyBasedEncryption = key // even or odd key 176 | km.KeyEncryptionKeyIndex = 0 177 | km.Cipher = 2 178 | km.Authentication = 0 179 | km.StreamEncapsulation = 2 180 | km.SLen = 16 181 | km.KLen = uint16(c.keyLength) 182 | 183 | if len(km.Salt) != 16 { 184 | km.Salt = make([]byte, 16) 185 | } 186 | copy(km.Salt, c.salt) 187 | 188 | n := 1 189 | if key == packet.EvenAndOddKey { 190 | n = 2 191 | } 192 | 193 | w := make([]byte, n*c.keyLength) 194 | 195 | switch key { 196 | case packet.EvenKeyEncrypted: 197 | copy(w, c.evenSEK) 198 | case packet.OddKeyEncrypted: 199 | copy(w, c.oddSEK) 200 | default: 201 | copy(w[:c.keyLength], c.evenSEK) 202 | copy(w[c.keyLength:], c.oddSEK) 203 | } 204 | 205 | kek, err := c.calculateKEK(passphrase, c.salt, c.keyLength) 206 | if err != nil { 207 | return err 208 | } 209 | 210 | wrap, err := keywrap.Wrap(kek, w) 211 | if err != nil { 212 | return err 213 | } 214 | 215 | if len(km.Wrap) != len(wrap) { 216 | km.Wrap = make([]byte, len(wrap)) 217 | } 218 | 219 | copy(km.Wrap, wrap) 220 | 221 | return nil 222 | } 223 | 224 | func (c *crypto) EncryptOrDecryptPayload(data []byte, key packet.PacketEncryption, packetSequenceNumber uint32) error { 225 | // 6.1.2. AES Counter 226 | // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 227 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 228 | // | 0s | psn | 0 0| 229 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 230 | // XOR 231 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 232 | // | MSB(112, Salt) | 233 | // +---+---+---+---+---+---+---+---+---+---+---+---+---+---+ 234 | // 235 | // psn (32 bit): packet sequence number 236 | // ctr (16 bit): block counter, all zeros 237 | // nonce (112 bit): 14 most significant bytes of the salt 238 | // 239 | // CTR = (MSB(112, Salt) XOR psn) << 16 240 | 241 | if len(c.salt) != 16 { 242 | return fmt.Errorf("crypto: invalid salt. Must be of length 16 bytes") 243 | } 244 | 245 | ctr := make([]byte, 16) 246 | 247 | binary.BigEndian.PutUint32(ctr[10:], packetSequenceNumber) 248 | 249 | for i := range ctr[:14] { 250 | ctr[i] ^= c.salt[i] 251 | } 252 | 253 | var sek []byte 254 | switch key { 255 | case packet.EvenKeyEncrypted: 256 | sek = c.evenSEK 257 | case packet.OddKeyEncrypted: 258 | sek = c.oddSEK 259 | default: 260 | return fmt.Errorf("crypto: invalid SEK selected. Must be either even or odd") 261 | } 262 | 263 | // 6.2.2. Encrypting the Payload 264 | // 6.3.2. Decrypting the Payload 265 | block, err := aes.NewCipher(sek) 266 | if err != nil { 267 | return err 268 | } 269 | 270 | stream := cipher.NewCTR(block, ctr) 271 | stream.XORKeyStream(data, data) 272 | 273 | return nil 274 | } 275 | 276 | // calculateKEK calculates a KEK based on the passphrase. 277 | func (c *crypto) calculateKEK(passphrase string, salt []byte, keyLength int) ([]byte, error) { 278 | // 6.1.4. Key Encrypting Key (KEK) 279 | return pbkdf2.Key(sha1.New, passphrase, salt[8:], 2048, keyLength) 280 | } 281 | 282 | // prng generates a random sequence of byte into the given slice p. 283 | func (c *crypto) prng(p []byte) error { 284 | _, err := rand.Read(p) 285 | return err 286 | } 287 | -------------------------------------------------------------------------------- /contrib/server/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "net" 7 | "net/url" 8 | "os" 9 | "os/signal" 10 | "strings" 11 | "sync" 12 | 13 | srt "github.com/datarhei/gosrt" 14 | "github.com/pkg/profile" 15 | ) 16 | 17 | // server is an implementation of the Server framework 18 | type server struct { 19 | // Configuration parameter taken from the Config 20 | addr string 21 | app string 22 | token string 23 | passphrase string 24 | logtopics string 25 | profile string 26 | 27 | server *srt.Server 28 | 29 | // Map of publishing channels and a lock to serialize 30 | // access to the map. 31 | channels map[string]srt.PubSub 32 | lock sync.RWMutex 33 | } 34 | 35 | func (s *server) ListenAndServe() error { 36 | if len(s.app) == 0 { 37 | s.app = "/" 38 | } 39 | 40 | return s.server.ListenAndServe() 41 | } 42 | 43 | func (s *server) Shutdown() { 44 | s.server.Shutdown() 45 | } 46 | 47 | func main() { 48 | s := server{ 49 | channels: make(map[string]srt.PubSub), 50 | } 51 | 52 | flag.StringVar(&s.addr, "addr", "", "address to listen on") 53 | flag.StringVar(&s.app, "app", "", "path prefix for streamid") 54 | flag.StringVar(&s.token, "token", "", "token query param for streamid") 55 | flag.StringVar(&s.passphrase, "passphrase", "", "passphrase for de- and enrcypting the data") 56 | flag.StringVar(&s.logtopics, "logtopics", "", "topics for the log output") 57 | flag.StringVar(&s.profile, "profile", "", "enable profiling (cpu, mem, allocs, heap, rate, mutex, block, thread, trace)") 58 | 59 | flag.Parse() 60 | 61 | if len(s.addr) == 0 { 62 | fmt.Fprintf(os.Stderr, "Provide a listen address with -addr\n") 63 | os.Exit(1) 64 | } 65 | 66 | var p func(*profile.Profile) 67 | switch s.profile { 68 | case "cpu": 69 | p = profile.CPUProfile 70 | case "mem": 71 | p = profile.MemProfile 72 | case "allocs": 73 | p = profile.MemProfileAllocs 74 | case "heap": 75 | p = profile.MemProfileHeap 76 | case "rate": 77 | p = profile.MemProfileRate(2048) 78 | case "mutex": 79 | p = profile.MutexProfile 80 | case "block": 81 | p = profile.BlockProfile 82 | case "thread": 83 | p = profile.ThreadcreationProfile 84 | case "trace": 85 | p = profile.TraceProfile 86 | default: 87 | } 88 | 89 | if p != nil { 90 | defer profile.Start(profile.ProfilePath("."), profile.NoShutdownHook, p).Stop() 91 | } 92 | 93 | config := srt.DefaultConfig() 94 | 95 | if len(s.logtopics) != 0 { 96 | config.Logger = srt.NewLogger(strings.Split(s.logtopics, ",")) 97 | } 98 | 99 | config.KMPreAnnounce = 200 100 | config.KMRefreshRate = 10000 101 | 102 | s.server = &srt.Server{ 103 | Addr: s.addr, 104 | HandleConnect: s.handleConnect, 105 | HandlePublish: s.handlePublish, 106 | HandleSubscribe: s.handleSubscribe, 107 | Config: &config, 108 | } 109 | 110 | fmt.Fprintf(os.Stderr, "Listening on %s\n", s.addr) 111 | 112 | go func() { 113 | if config.Logger == nil { 114 | return 115 | } 116 | 117 | for m := range config.Logger.Listen() { 118 | fmt.Fprintf(os.Stderr, "%#08x %s (in %s:%d)\n%s \n", m.SocketId, m.Topic, m.File, m.Line, m.Message) 119 | } 120 | }() 121 | 122 | go func() { 123 | if err := s.ListenAndServe(); err != nil && err != srt.ErrServerClosed { 124 | fmt.Fprintf(os.Stderr, "SRT Server: %s\n", err) 125 | os.Exit(2) 126 | } 127 | }() 128 | 129 | quit := make(chan os.Signal, 1) 130 | signal.Notify(quit, os.Interrupt) 131 | <-quit 132 | 133 | s.Shutdown() 134 | 135 | if config.Logger != nil { 136 | config.Logger.Close() 137 | } 138 | } 139 | 140 | func (s *server) log(who, action, path, message string, client net.Addr) { 141 | fmt.Fprintf(os.Stderr, "%-10s %10s %s (%s) %s\n", who, action, path, client, message) 142 | } 143 | 144 | func (s *server) handleConnect(req srt.ConnRequest) srt.ConnType { 145 | var mode srt.ConnType = srt.SUBSCRIBE 146 | client := req.RemoteAddr() 147 | 148 | channel := "" 149 | 150 | if req.Version() == 4 { 151 | mode = srt.PUBLISH 152 | channel = "/" + client.String() 153 | 154 | req.SetPassphrase(s.passphrase) 155 | } else if req.Version() == 5 { 156 | streamId := req.StreamId() 157 | path := streamId 158 | 159 | if strings.HasPrefix(streamId, "publish:") { 160 | mode = srt.PUBLISH 161 | path = strings.TrimPrefix(streamId, "publish:") 162 | } else if strings.HasPrefix(streamId, "subscribe:") { 163 | path = strings.TrimPrefix(streamId, "subscribe:") 164 | } 165 | 166 | u, err := url.Parse(path) 167 | if err != nil { 168 | return srt.REJECT 169 | } 170 | 171 | if req.IsEncrypted() { 172 | if err := req.SetPassphrase(s.passphrase); err != nil { 173 | s.log("CONNECT", "FORBIDDEN", u.Path, err.Error(), client) 174 | return srt.REJECT 175 | } 176 | } 177 | 178 | // Check the token 179 | token := u.Query().Get("token") 180 | if len(s.token) != 0 && s.token != token { 181 | s.log("CONNECT", "FORBIDDEN", u.Path, "invalid token ("+token+")", client) 182 | return srt.REJECT 183 | } 184 | 185 | // Check the app patch 186 | if !strings.HasPrefix(u.Path, s.app) { 187 | s.log("CONNECT", "FORBIDDEN", u.Path, "invalid app", client) 188 | return srt.REJECT 189 | } 190 | 191 | if len(strings.TrimPrefix(u.Path, s.app)) == 0 { 192 | s.log("CONNECT", "INVALID", u.Path, "stream name not provided", client) 193 | return srt.REJECT 194 | } 195 | 196 | channel = u.Path 197 | } else { 198 | return srt.REJECT 199 | } 200 | 201 | s.lock.RLock() 202 | pubsub := s.channels[channel] 203 | s.lock.RUnlock() 204 | 205 | if mode == srt.PUBLISH && pubsub != nil { 206 | s.log("CONNECT", "CONFLICT", channel, "already publishing", client) 207 | return srt.REJECT 208 | } 209 | 210 | if mode == srt.SUBSCRIBE && pubsub == nil { 211 | s.log("CONNECT", "NOTFOUND", channel, "not publishing", client) 212 | return srt.REJECT 213 | } 214 | 215 | return mode 216 | } 217 | 218 | func (s *server) handlePublish(conn srt.Conn) { 219 | channel := "" 220 | client := conn.RemoteAddr() 221 | if client == nil { 222 | conn.Close() 223 | return 224 | } 225 | 226 | if conn.Version() == 4 { 227 | channel = "/" + client.String() 228 | } else if conn.Version() == 5 { 229 | streamId := conn.StreamId() 230 | path := strings.TrimPrefix(streamId, "publish:") 231 | 232 | channel = path 233 | } else { 234 | s.log("PUBLISH", "INVALID", channel, "unknown connection version", client) 235 | conn.Close() 236 | return 237 | } 238 | 239 | // Look for the stream 240 | s.lock.Lock() 241 | pubsub := s.channels[channel] 242 | if pubsub == nil { 243 | pubsub = srt.NewPubSub(srt.PubSubConfig{ 244 | Logger: s.server.Config.Logger, 245 | }) 246 | s.channels[channel] = pubsub 247 | } else { 248 | pubsub = nil 249 | } 250 | s.lock.Unlock() 251 | 252 | if pubsub == nil { 253 | s.log("PUBLISH", "CONFLICT", channel, "already publishing", client) 254 | conn.Close() 255 | return 256 | } 257 | 258 | s.log("PUBLISH", "START", channel, "publishing", client) 259 | 260 | pubsub.Publish(conn) 261 | 262 | s.lock.Lock() 263 | delete(s.channels, channel) 264 | s.lock.Unlock() 265 | 266 | s.log("PUBLISH", "STOP", channel, "", client) 267 | 268 | stats := &srt.Statistics{} 269 | conn.Stats(stats) 270 | 271 | fmt.Fprintf(os.Stderr, "%+v\n", stats) 272 | 273 | conn.Close() 274 | } 275 | 276 | func (s *server) handleSubscribe(conn srt.Conn) { 277 | channel := "" 278 | client := conn.RemoteAddr() 279 | if client == nil { 280 | conn.Close() 281 | return 282 | } 283 | 284 | if conn.Version() == 4 { 285 | channel = client.String() 286 | } else if conn.Version() == 5 { 287 | streamId := conn.StreamId() 288 | path := strings.TrimPrefix(streamId, "subscribe:") 289 | 290 | channel = path 291 | } else { 292 | s.log("SUBSCRIBE", "INVALID", channel, "unknown connection version", client) 293 | conn.Close() 294 | return 295 | } 296 | 297 | s.log("SUBSCRIBE", "START", channel, "", client) 298 | 299 | // Look for the stream 300 | s.lock.RLock() 301 | pubsub := s.channels[channel] 302 | s.lock.RUnlock() 303 | 304 | if pubsub == nil { 305 | s.log("SUBSCRIBE", "NOTFOUND", channel, "not publishing", client) 306 | conn.Close() 307 | return 308 | } 309 | 310 | pubsub.Subscribe(conn) 311 | 312 | s.log("SUBSCRIBE", "STOP", channel, "", client) 313 | 314 | stats := &srt.Statistics{} 315 | conn.Stats(stats) 316 | 317 | fmt.Fprintf(os.Stderr, "%+v\n", stats) 318 | 319 | conn.Close() 320 | } 321 | -------------------------------------------------------------------------------- /vendor/golang.org/x/sys/windows/exec_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2009 The Go Authors. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Fork, exec, wait, etc. 6 | 7 | package windows 8 | 9 | import ( 10 | errorspkg "errors" 11 | "unsafe" 12 | ) 13 | 14 | // EscapeArg rewrites command line argument s as prescribed 15 | // in http://msdn.microsoft.com/en-us/library/ms880421. 16 | // This function returns "" (2 double quotes) if s is empty. 17 | // Alternatively, these transformations are done: 18 | // - every back slash (\) is doubled, but only if immediately 19 | // followed by double quote ("); 20 | // - every double quote (") is escaped by back slash (\); 21 | // - finally, s is wrapped with double quotes (arg -> "arg"), 22 | // but only if there is space or tab inside s. 23 | func EscapeArg(s string) string { 24 | if len(s) == 0 { 25 | return `""` 26 | } 27 | n := len(s) 28 | hasSpace := false 29 | for i := 0; i < len(s); i++ { 30 | switch s[i] { 31 | case '"', '\\': 32 | n++ 33 | case ' ', '\t': 34 | hasSpace = true 35 | } 36 | } 37 | if hasSpace { 38 | n += 2 // Reserve space for quotes. 39 | } 40 | if n == len(s) { 41 | return s 42 | } 43 | 44 | qs := make([]byte, n) 45 | j := 0 46 | if hasSpace { 47 | qs[j] = '"' 48 | j++ 49 | } 50 | slashes := 0 51 | for i := 0; i < len(s); i++ { 52 | switch s[i] { 53 | default: 54 | slashes = 0 55 | qs[j] = s[i] 56 | case '\\': 57 | slashes++ 58 | qs[j] = s[i] 59 | case '"': 60 | for ; slashes > 0; slashes-- { 61 | qs[j] = '\\' 62 | j++ 63 | } 64 | qs[j] = '\\' 65 | j++ 66 | qs[j] = s[i] 67 | } 68 | j++ 69 | } 70 | if hasSpace { 71 | for ; slashes > 0; slashes-- { 72 | qs[j] = '\\' 73 | j++ 74 | } 75 | qs[j] = '"' 76 | j++ 77 | } 78 | return string(qs[:j]) 79 | } 80 | 81 | // ComposeCommandLine escapes and joins the given arguments suitable for use as a Windows command line, 82 | // in CreateProcess's CommandLine argument, CreateService/ChangeServiceConfig's BinaryPathName argument, 83 | // or any program that uses CommandLineToArgv. 84 | func ComposeCommandLine(args []string) string { 85 | if len(args) == 0 { 86 | return "" 87 | } 88 | 89 | // Per https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-commandlinetoargvw: 90 | // “This function accepts command lines that contain a program name; the 91 | // program name can be enclosed in quotation marks or not.” 92 | // 93 | // Unfortunately, it provides no means of escaping interior quotation marks 94 | // within that program name, and we have no way to report them here. 95 | prog := args[0] 96 | mustQuote := len(prog) == 0 97 | for i := 0; i < len(prog); i++ { 98 | c := prog[i] 99 | if c <= ' ' || (c == '"' && i == 0) { 100 | // Force quotes for not only the ASCII space and tab as described in the 101 | // MSDN article, but also ASCII control characters. 102 | // The documentation for CommandLineToArgvW doesn't say what happens when 103 | // the first argument is not a valid program name, but it empirically 104 | // seems to drop unquoted control characters. 105 | mustQuote = true 106 | break 107 | } 108 | } 109 | var commandLine []byte 110 | if mustQuote { 111 | commandLine = make([]byte, 0, len(prog)+2) 112 | commandLine = append(commandLine, '"') 113 | for i := 0; i < len(prog); i++ { 114 | c := prog[i] 115 | if c == '"' { 116 | // This quote would interfere with our surrounding quotes. 117 | // We have no way to report an error, so just strip out 118 | // the offending character instead. 119 | continue 120 | } 121 | commandLine = append(commandLine, c) 122 | } 123 | commandLine = append(commandLine, '"') 124 | } else { 125 | if len(args) == 1 { 126 | // args[0] is a valid command line representing itself. 127 | // No need to allocate a new slice or string for it. 128 | return prog 129 | } 130 | commandLine = []byte(prog) 131 | } 132 | 133 | for _, arg := range args[1:] { 134 | commandLine = append(commandLine, ' ') 135 | // TODO(bcmills): since we're already appending to a slice, it would be nice 136 | // to avoid the intermediate allocations of EscapeArg. 137 | // Perhaps we can factor out an appendEscapedArg function. 138 | commandLine = append(commandLine, EscapeArg(arg)...) 139 | } 140 | return string(commandLine) 141 | } 142 | 143 | // DecomposeCommandLine breaks apart its argument command line into unescaped parts using CommandLineToArgv, 144 | // as gathered from GetCommandLine, QUERY_SERVICE_CONFIG's BinaryPathName argument, or elsewhere that 145 | // command lines are passed around. 146 | // DecomposeCommandLine returns an error if commandLine contains NUL. 147 | func DecomposeCommandLine(commandLine string) ([]string, error) { 148 | if len(commandLine) == 0 { 149 | return []string{}, nil 150 | } 151 | utf16CommandLine, err := UTF16FromString(commandLine) 152 | if err != nil { 153 | return nil, errorspkg.New("string with NUL passed to DecomposeCommandLine") 154 | } 155 | var argc int32 156 | argv, err := commandLineToArgv(&utf16CommandLine[0], &argc) 157 | if err != nil { 158 | return nil, err 159 | } 160 | defer LocalFree(Handle(unsafe.Pointer(argv))) 161 | 162 | var args []string 163 | for _, p := range unsafe.Slice(argv, argc) { 164 | args = append(args, UTF16PtrToString(p)) 165 | } 166 | return args, nil 167 | } 168 | 169 | // CommandLineToArgv parses a Unicode command line string and sets 170 | // argc to the number of parsed arguments. 171 | // 172 | // The returned memory should be freed using a single call to LocalFree. 173 | // 174 | // Note that although the return type of CommandLineToArgv indicates 8192 175 | // entries of up to 8192 characters each, the actual count of parsed arguments 176 | // may exceed 8192, and the documentation for CommandLineToArgvW does not mention 177 | // any bound on the lengths of the individual argument strings. 178 | // (See https://go.dev/issue/63236.) 179 | func CommandLineToArgv(cmd *uint16, argc *int32) (argv *[8192]*[8192]uint16, err error) { 180 | argp, err := commandLineToArgv(cmd, argc) 181 | argv = (*[8192]*[8192]uint16)(unsafe.Pointer(argp)) 182 | return argv, err 183 | } 184 | 185 | func CloseOnExec(fd Handle) { 186 | SetHandleInformation(Handle(fd), HANDLE_FLAG_INHERIT, 0) 187 | } 188 | 189 | // FullPath retrieves the full path of the specified file. 190 | func FullPath(name string) (path string, err error) { 191 | p, err := UTF16PtrFromString(name) 192 | if err != nil { 193 | return "", err 194 | } 195 | n := uint32(100) 196 | for { 197 | buf := make([]uint16, n) 198 | n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil) 199 | if err != nil { 200 | return "", err 201 | } 202 | if n <= uint32(len(buf)) { 203 | return UTF16ToString(buf[:n]), nil 204 | } 205 | } 206 | } 207 | 208 | // NewProcThreadAttributeList allocates a new ProcThreadAttributeListContainer, with the requested maximum number of attributes. 209 | func NewProcThreadAttributeList(maxAttrCount uint32) (*ProcThreadAttributeListContainer, error) { 210 | var size uintptr 211 | err := initializeProcThreadAttributeList(nil, maxAttrCount, 0, &size) 212 | if err != ERROR_INSUFFICIENT_BUFFER { 213 | if err == nil { 214 | return nil, errorspkg.New("unable to query buffer size from InitializeProcThreadAttributeList") 215 | } 216 | return nil, err 217 | } 218 | alloc, err := LocalAlloc(LMEM_FIXED, uint32(size)) 219 | if err != nil { 220 | return nil, err 221 | } 222 | // size is guaranteed to be ≥1 by InitializeProcThreadAttributeList. 223 | al := &ProcThreadAttributeListContainer{data: (*ProcThreadAttributeList)(unsafe.Pointer(alloc))} 224 | err = initializeProcThreadAttributeList(al.data, maxAttrCount, 0, &size) 225 | if err != nil { 226 | return nil, err 227 | } 228 | return al, err 229 | } 230 | 231 | // Update modifies the ProcThreadAttributeList using UpdateProcThreadAttribute. 232 | func (al *ProcThreadAttributeListContainer) Update(attribute uintptr, value unsafe.Pointer, size uintptr) error { 233 | al.pointers = append(al.pointers, value) 234 | return updateProcThreadAttribute(al.data, 0, attribute, value, size, nil, nil) 235 | } 236 | 237 | // Delete frees ProcThreadAttributeList's resources. 238 | func (al *ProcThreadAttributeListContainer) Delete() { 239 | deleteProcThreadAttributeList(al.data) 240 | LocalFree(Handle(unsafe.Pointer(al.data))) 241 | al.data = nil 242 | al.pointers = nil 243 | } 244 | 245 | // List returns the actual ProcThreadAttributeList to be passed to StartupInfoEx. 246 | func (al *ProcThreadAttributeListContainer) List() *ProcThreadAttributeList { 247 | return al.data 248 | } 249 | -------------------------------------------------------------------------------- /vendor/github.com/google/pprof/profile/filter.go: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package profile 16 | 17 | // Implements methods to filter samples from profiles. 18 | 19 | import "regexp" 20 | 21 | // FilterSamplesByName filters the samples in a profile and only keeps 22 | // samples where at least one frame matches focus but none match ignore. 23 | // Returns true is the corresponding regexp matched at least one sample. 24 | func (p *Profile) FilterSamplesByName(focus, ignore, hide, show *regexp.Regexp) (fm, im, hm, hnm bool) { 25 | focusOrIgnore := make(map[uint64]bool) 26 | hidden := make(map[uint64]bool) 27 | for _, l := range p.Location { 28 | if ignore != nil && l.matchesName(ignore) { 29 | im = true 30 | focusOrIgnore[l.ID] = false 31 | } else if focus == nil || l.matchesName(focus) { 32 | fm = true 33 | focusOrIgnore[l.ID] = true 34 | } 35 | 36 | if hide != nil && l.matchesName(hide) { 37 | hm = true 38 | l.Line = l.unmatchedLines(hide) 39 | if len(l.Line) == 0 { 40 | hidden[l.ID] = true 41 | } 42 | } 43 | if show != nil { 44 | l.Line = l.matchedLines(show) 45 | if len(l.Line) == 0 { 46 | hidden[l.ID] = true 47 | } else { 48 | hnm = true 49 | } 50 | } 51 | } 52 | 53 | s := make([]*Sample, 0, len(p.Sample)) 54 | for _, sample := range p.Sample { 55 | if focusedAndNotIgnored(sample.Location, focusOrIgnore) { 56 | if len(hidden) > 0 { 57 | var locs []*Location 58 | for _, loc := range sample.Location { 59 | if !hidden[loc.ID] { 60 | locs = append(locs, loc) 61 | } 62 | } 63 | if len(locs) == 0 { 64 | // Remove sample with no locations (by not adding it to s). 65 | continue 66 | } 67 | sample.Location = locs 68 | } 69 | s = append(s, sample) 70 | } 71 | } 72 | p.Sample = s 73 | 74 | return 75 | } 76 | 77 | // ShowFrom drops all stack frames above the highest matching frame and returns 78 | // whether a match was found. If showFrom is nil it returns false and does not 79 | // modify the profile. 80 | // 81 | // Example: consider a sample with frames [A, B, C, B], where A is the root. 82 | // ShowFrom(nil) returns false and has frames [A, B, C, B]. 83 | // ShowFrom(A) returns true and has frames [A, B, C, B]. 84 | // ShowFrom(B) returns true and has frames [B, C, B]. 85 | // ShowFrom(C) returns true and has frames [C, B]. 86 | // ShowFrom(D) returns false and drops the sample because no frames remain. 87 | func (p *Profile) ShowFrom(showFrom *regexp.Regexp) (matched bool) { 88 | if showFrom == nil { 89 | return false 90 | } 91 | // showFromLocs stores location IDs that matched ShowFrom. 92 | showFromLocs := make(map[uint64]bool) 93 | // Apply to locations. 94 | for _, loc := range p.Location { 95 | if filterShowFromLocation(loc, showFrom) { 96 | showFromLocs[loc.ID] = true 97 | matched = true 98 | } 99 | } 100 | // For all samples, strip locations after the highest matching one. 101 | s := make([]*Sample, 0, len(p.Sample)) 102 | for _, sample := range p.Sample { 103 | for i := len(sample.Location) - 1; i >= 0; i-- { 104 | if showFromLocs[sample.Location[i].ID] { 105 | sample.Location = sample.Location[:i+1] 106 | s = append(s, sample) 107 | break 108 | } 109 | } 110 | } 111 | p.Sample = s 112 | return matched 113 | } 114 | 115 | // filterShowFromLocation tests a showFrom regex against a location, removes 116 | // lines after the last match and returns whether a match was found. If the 117 | // mapping is matched, then all lines are kept. 118 | func filterShowFromLocation(loc *Location, showFrom *regexp.Regexp) bool { 119 | if m := loc.Mapping; m != nil && showFrom.MatchString(m.File) { 120 | return true 121 | } 122 | if i := loc.lastMatchedLineIndex(showFrom); i >= 0 { 123 | loc.Line = loc.Line[:i+1] 124 | return true 125 | } 126 | return false 127 | } 128 | 129 | // lastMatchedLineIndex returns the index of the last line that matches a regex, 130 | // or -1 if no match is found. 131 | func (loc *Location) lastMatchedLineIndex(re *regexp.Regexp) int { 132 | for i := len(loc.Line) - 1; i >= 0; i-- { 133 | if fn := loc.Line[i].Function; fn != nil { 134 | if re.MatchString(fn.Name) || re.MatchString(fn.Filename) { 135 | return i 136 | } 137 | } 138 | } 139 | return -1 140 | } 141 | 142 | // FilterTagsByName filters the tags in a profile and only keeps 143 | // tags that match show and not hide. 144 | func (p *Profile) FilterTagsByName(show, hide *regexp.Regexp) (sm, hm bool) { 145 | matchRemove := func(name string) bool { 146 | matchShow := show == nil || show.MatchString(name) 147 | matchHide := hide != nil && hide.MatchString(name) 148 | 149 | if matchShow { 150 | sm = true 151 | } 152 | if matchHide { 153 | hm = true 154 | } 155 | return !matchShow || matchHide 156 | } 157 | for _, s := range p.Sample { 158 | for lab := range s.Label { 159 | if matchRemove(lab) { 160 | delete(s.Label, lab) 161 | } 162 | } 163 | for lab := range s.NumLabel { 164 | if matchRemove(lab) { 165 | delete(s.NumLabel, lab) 166 | } 167 | } 168 | } 169 | return 170 | } 171 | 172 | // matchesName returns whether the location matches the regular 173 | // expression. It checks any available function names, file names, and 174 | // mapping object filename. 175 | func (loc *Location) matchesName(re *regexp.Regexp) bool { 176 | for _, ln := range loc.Line { 177 | if fn := ln.Function; fn != nil { 178 | if re.MatchString(fn.Name) || re.MatchString(fn.Filename) { 179 | return true 180 | } 181 | } 182 | } 183 | if m := loc.Mapping; m != nil && re.MatchString(m.File) { 184 | return true 185 | } 186 | return false 187 | } 188 | 189 | // unmatchedLines returns the lines in the location that do not match 190 | // the regular expression. 191 | func (loc *Location) unmatchedLines(re *regexp.Regexp) []Line { 192 | if m := loc.Mapping; m != nil && re.MatchString(m.File) { 193 | return nil 194 | } 195 | var lines []Line 196 | for _, ln := range loc.Line { 197 | if fn := ln.Function; fn != nil { 198 | if re.MatchString(fn.Name) || re.MatchString(fn.Filename) { 199 | continue 200 | } 201 | } 202 | lines = append(lines, ln) 203 | } 204 | return lines 205 | } 206 | 207 | // matchedLines returns the lines in the location that match 208 | // the regular expression. 209 | func (loc *Location) matchedLines(re *regexp.Regexp) []Line { 210 | if m := loc.Mapping; m != nil && re.MatchString(m.File) { 211 | return loc.Line 212 | } 213 | var lines []Line 214 | for _, ln := range loc.Line { 215 | if fn := ln.Function; fn != nil { 216 | if !re.MatchString(fn.Name) && !re.MatchString(fn.Filename) { 217 | continue 218 | } 219 | } 220 | lines = append(lines, ln) 221 | } 222 | return lines 223 | } 224 | 225 | // focusedAndNotIgnored looks up a slice of ids against a map of 226 | // focused/ignored locations. The map only contains locations that are 227 | // explicitly focused or ignored. Returns whether there is at least 228 | // one focused location but no ignored locations. 229 | func focusedAndNotIgnored(locs []*Location, m map[uint64]bool) bool { 230 | var f bool 231 | for _, loc := range locs { 232 | if focus, focusOrIgnore := m[loc.ID]; focusOrIgnore { 233 | if focus { 234 | // Found focused location. Must keep searching in case there 235 | // is an ignored one as well. 236 | f = true 237 | } else { 238 | // Found ignored location. Can return false right away. 239 | return false 240 | } 241 | } 242 | } 243 | return f 244 | } 245 | 246 | // TagMatch selects tags for filtering 247 | type TagMatch func(s *Sample) bool 248 | 249 | // FilterSamplesByTag removes all samples from the profile, except 250 | // those that match focus and do not match the ignore regular 251 | // expression. 252 | func (p *Profile) FilterSamplesByTag(focus, ignore TagMatch) (fm, im bool) { 253 | samples := make([]*Sample, 0, len(p.Sample)) 254 | for _, s := range p.Sample { 255 | focused, ignored := true, false 256 | if focus != nil { 257 | focused = focus(s) 258 | } 259 | if ignore != nil { 260 | ignored = ignore(s) 261 | } 262 | fm = fm || focused 263 | im = im || ignored 264 | if focused && !ignored { 265 | samples = append(samples, s) 266 | } 267 | } 268 | p.Sample = samples 269 | return 270 | } 271 | -------------------------------------------------------------------------------- /contrib/client/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "flag" 6 | "fmt" 7 | "io" 8 | "net" 9 | "net/url" 10 | "os" 11 | "os/signal" 12 | "strconv" 13 | "strings" 14 | "sync" 15 | "time" 16 | 17 | srt "github.com/datarhei/gosrt" 18 | ) 19 | 20 | type stats struct { 21 | bprev uint64 22 | btotal uint64 23 | prev uint64 24 | total uint64 25 | 26 | lock sync.Mutex 27 | 28 | period time.Duration 29 | last time.Time 30 | } 31 | 32 | func (s *stats) init(period time.Duration) { 33 | s.bprev = 0 34 | s.btotal = 0 35 | s.prev = 0 36 | s.total = 0 37 | 38 | s.period = period 39 | s.last = time.Now() 40 | 41 | go s.tick() 42 | } 43 | 44 | func (s *stats) tick() { 45 | ticker := time.NewTicker(s.period) 46 | defer ticker.Stop() 47 | 48 | for c := range ticker.C { 49 | s.lock.Lock() 50 | diff := c.Sub(s.last) 51 | 52 | bavg := float64(s.btotal-s.bprev) * 8 / (1000 * 1000 * diff.Seconds()) 53 | avg := float64(s.total-s.prev) / diff.Seconds() 54 | 55 | s.bprev = s.btotal 56 | s.prev = s.total 57 | s.last = c 58 | 59 | s.lock.Unlock() 60 | 61 | fmt.Fprintf(os.Stderr, "\r%-54s: %8.3f kpackets (%8.3f packets/s), %8.3f mbytes (%8.3f Mbps)", c, float64(s.total)/1024, avg, float64(s.btotal)/1024/1024, bavg) 62 | } 63 | } 64 | 65 | func (s *stats) update(n uint64) { 66 | s.lock.Lock() 67 | defer s.lock.Unlock() 68 | 69 | s.btotal += n 70 | s.total++ 71 | } 72 | 73 | func main() { 74 | var from string 75 | var to string 76 | var logtopics string 77 | 78 | flag.StringVar(&from, "from", "", "Address to read from, sources: srt://, udp://, - (stdin)") 79 | flag.StringVar(&to, "to", "", "Address to write to, targets: srt://, udp://, file://, - (stdout)") 80 | flag.StringVar(&logtopics, "logtopics", "", "topics for the log output") 81 | 82 | flag.Parse() 83 | 84 | var logger srt.Logger 85 | 86 | if len(logtopics) != 0 { 87 | logger = srt.NewLogger(strings.Split(logtopics, ",")) 88 | } 89 | 90 | go func() { 91 | if logger == nil { 92 | return 93 | } 94 | 95 | for m := range logger.Listen() { 96 | fmt.Fprintf(os.Stderr, "%#08x %s (in %s:%d)\n%s \n", m.SocketId, m.Topic, m.File, m.Line, m.Message) 97 | } 98 | }() 99 | 100 | r, err := openReader(from, logger) 101 | if err != nil { 102 | fmt.Fprintf(os.Stderr, "Error: from: %v\n", err) 103 | flag.PrintDefaults() 104 | os.Exit(1) 105 | } 106 | 107 | w, err := openWriter(to, logger) 108 | if err != nil { 109 | fmt.Fprintf(os.Stderr, "Error: to: %v\n", err) 110 | flag.PrintDefaults() 111 | os.Exit(1) 112 | } 113 | 114 | doneChan := make(chan error) 115 | 116 | go func() { 117 | buffer := make([]byte, 2048) 118 | 119 | s := stats{} 120 | s.init(200 * time.Millisecond) 121 | 122 | for { 123 | n, err := r.Read(buffer) 124 | if err != nil { 125 | doneChan <- fmt.Errorf("read: %w", err) 126 | return 127 | } 128 | 129 | s.update(uint64(n)) 130 | 131 | if _, err := w.Write(buffer[:n]); err != nil { 132 | doneChan <- fmt.Errorf("write: %w", err) 133 | return 134 | } 135 | } 136 | }() 137 | 138 | go func() { 139 | quit := make(chan os.Signal, 1) 140 | signal.Notify(quit, os.Interrupt) 141 | <-quit 142 | 143 | doneChan <- nil 144 | }() 145 | 146 | if err := <-doneChan; err != nil { 147 | fmt.Fprintf(os.Stderr, "Error: %v\n", err) 148 | } else { 149 | fmt.Fprint(os.Stderr, "\n") 150 | } 151 | 152 | w.Close() 153 | 154 | if srtconn, ok := w.(srt.Conn); ok { 155 | stats := &srt.Statistics{} 156 | srtconn.Stats(stats) 157 | 158 | data, err := json.MarshalIndent(stats, "", " ") 159 | if err != nil { 160 | fmt.Fprintf(os.Stderr, "writer: %+v\n", stats) 161 | } else { 162 | fmt.Fprintf(os.Stderr, "writer: %s\n", string(data)) 163 | } 164 | } 165 | 166 | r.Close() 167 | 168 | if srtconn, ok := r.(srt.Conn); ok { 169 | stats := &srt.Statistics{} 170 | srtconn.Stats(stats) 171 | 172 | data, err := json.MarshalIndent(stats, "", " ") 173 | if err != nil { 174 | fmt.Fprintf(os.Stderr, "reader: %+v\n", stats) 175 | } else { 176 | fmt.Fprintf(os.Stderr, "reader: %s\n", string(data)) 177 | } 178 | } 179 | 180 | if logger != nil { 181 | logger.Close() 182 | } 183 | } 184 | 185 | func openReader(addr string, logger srt.Logger) (io.ReadCloser, error) { 186 | if len(addr) == 0 { 187 | return nil, fmt.Errorf("the address must not be empty") 188 | } 189 | 190 | if addr == "-" { 191 | if os.Stdin == nil { 192 | return nil, fmt.Errorf("stdin is not defined") 193 | } 194 | 195 | return os.Stdin, nil 196 | } 197 | 198 | if strings.HasPrefix(addr, "debug://") { 199 | readerOptions := DebugReaderOptions{} 200 | parts := strings.SplitN(strings.TrimPrefix(addr, "debug://"), "?", 2) 201 | if len(parts) > 1 { 202 | options, err := url.ParseQuery(parts[1]) 203 | if err != nil { 204 | return nil, err 205 | } 206 | 207 | if x, err := strconv.ParseUint(options.Get("bitrate"), 10, 64); err == nil { 208 | readerOptions.Bitrate = x 209 | } 210 | } 211 | 212 | r, err := NewDebugReader(readerOptions) 213 | 214 | return r, err 215 | } 216 | 217 | u, err := url.Parse(addr) 218 | if err != nil { 219 | return nil, err 220 | } 221 | 222 | if u.Scheme == "srt" { 223 | config := srt.DefaultConfig() 224 | if err := config.UnmarshalQuery(u.RawQuery); err != nil { 225 | return nil, err 226 | } 227 | config.Logger = logger 228 | 229 | mode := u.Query().Get("mode") 230 | 231 | if mode == "listener" { 232 | ln, err := srt.Listen("srt", u.Host, config) 233 | if err != nil { 234 | return nil, err 235 | } 236 | 237 | conn, _, err := ln.Accept(func(req srt.ConnRequest) srt.ConnType { 238 | if config.StreamId != req.StreamId() { 239 | return srt.REJECT 240 | } 241 | 242 | req.SetPassphrase(config.Passphrase) 243 | 244 | return srt.PUBLISH 245 | }) 246 | if err != nil { 247 | return nil, err 248 | } 249 | 250 | if conn == nil { 251 | return nil, fmt.Errorf("incoming connection rejected") 252 | } 253 | 254 | return conn, nil 255 | } else if mode == "caller" { 256 | conn, err := srt.Dial("srt", u.Host, config) 257 | if err != nil { 258 | return nil, err 259 | } 260 | 261 | return conn, nil 262 | } else { 263 | return nil, fmt.Errorf("unsupported mode") 264 | } 265 | } else if u.Scheme == "udp" { 266 | laddr, err := net.ResolveUDPAddr("udp", u.Host) 267 | if err != nil { 268 | return nil, err 269 | } 270 | 271 | conn, err := net.ListenUDP("udp", laddr) 272 | if err != nil { 273 | return nil, err 274 | } 275 | 276 | return conn, nil 277 | } 278 | 279 | return nil, fmt.Errorf("unsupported reader") 280 | } 281 | 282 | func openWriter(addr string, logger srt.Logger) (io.WriteCloser, error) { 283 | if len(addr) == 0 { 284 | return nil, fmt.Errorf("the address must not be empty") 285 | } 286 | 287 | if addr == "-" { 288 | if os.Stdout == nil { 289 | return nil, fmt.Errorf("stdout is not defined") 290 | } 291 | 292 | return NewNonblockingWriter(os.Stdout, 2048), nil 293 | } 294 | 295 | if strings.HasPrefix(addr, "file://") { 296 | path := strings.TrimPrefix(addr, "file://") 297 | file, err := os.Create(path) 298 | if err != nil { 299 | return nil, err 300 | } 301 | 302 | return NewNonblockingWriter(file, 2048), nil 303 | } 304 | 305 | u, err := url.Parse(addr) 306 | if err != nil { 307 | return nil, err 308 | } 309 | 310 | if u.Scheme == "srt" { 311 | config := srt.DefaultConfig() 312 | if err := config.UnmarshalQuery(u.RawQuery); err != nil { 313 | return nil, err 314 | } 315 | config.Logger = logger 316 | 317 | mode := u.Query().Get("mode") 318 | 319 | if mode == "listener" { 320 | ln, err := srt.Listen("srt", u.Host, config) 321 | if err != nil { 322 | return nil, err 323 | } 324 | 325 | conn, _, err := ln.Accept(func(req srt.ConnRequest) srt.ConnType { 326 | if config.StreamId != req.StreamId() { 327 | return srt.REJECT 328 | } 329 | 330 | req.SetPassphrase(config.Passphrase) 331 | 332 | return srt.SUBSCRIBE 333 | }) 334 | if err != nil { 335 | return nil, err 336 | } 337 | 338 | if conn == nil { 339 | return nil, fmt.Errorf("incoming connection rejected") 340 | } 341 | 342 | return conn, nil 343 | } else if mode == "caller" { 344 | conn, err := srt.Dial("srt", u.Host, config) 345 | if err != nil { 346 | return nil, err 347 | } 348 | 349 | return conn, nil 350 | } else { 351 | return nil, fmt.Errorf("unsupported mode") 352 | } 353 | } else if u.Scheme == "udp" { 354 | raddr, err := net.ResolveUDPAddr("udp", u.Host) 355 | if err != nil { 356 | return nil, err 357 | } 358 | 359 | conn, err := net.DialUDP("udp", nil, raddr) 360 | if err != nil { 361 | return nil, err 362 | } 363 | 364 | return conn, nil 365 | } 366 | 367 | return nil, fmt.Errorf("unsupported writer") 368 | } 369 | --------------------------------------------------------------------------------