diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 438443f..d284b19 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -47,5 +47,5 @@ jobs: - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: - version: v1.31 + version: v1.45.2 args: $GOLANGCI_LINT_EXRA_ARGS diff --git a/.golangci.yml b/.golangci.yml index d6162c9..d7a88ec 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -15,14 +15,22 @@ linters-settings: linters: enable: - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers + - bidichk # Checks for dangerous unicode character sequences - bodyclose # checks whether HTTP response body is closed successfully + - contextcheck # check the function whether use a non-inherited context - deadcode # Finds unused code + - decorder # check declaration order and count of types, constants, variables and functions - depguard # Go linter that checks if package imports are in a list of acceptable packages - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) - dupl # Tool for code clone detection + - durationcheck # check for two durations multiplied together - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases + - errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occations, where the check for the returned error can be omitted. + - errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. + - errorlint # errorlint is a linter for that can be used to find code that will cause problems with the error wrapping scheme introduced in Go 1.13. - exhaustive # check exhaustiveness of enum switch statements - exportloopref # checks for pointers to enclosing loop variables + - forcetypeassert # finds forced type assertions - gci # Gci control golang package import order and make it always deterministic. - gochecknoglobals # Checks that no globals are present in Go code - gochecknoinits # Checks that no init functions are present in Go code @@ -35,40 +43,62 @@ linters: - gofumpt # Gofumpt checks whether code was gofumpt-ed. - goheader # Checks is file header matches to pattern - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports - - golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes + - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. - goprintffuncname # Checks that printf-like functions are named with `f` at the end - gosec # Inspects source code for security problems - gosimple # Linter for Go source code that specializes in simplifying a code - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string + - grouper # An analyzer to analyze expression groups. + - importas # Enforces consistent import aliases - ineffassign # Detects when assignments to existing variables are not used - misspell # Finds commonly misspelled English words in comments - nakedret # Finds naked returns in functions greater than a specified function length + - nilerr # Finds the code that returns nil even if it checks that the error is not nil. + - nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. - noctx # noctx finds sending http request without context.Context - - scopelint # Scopelint checks for unpinned variables in go programs + - predeclared # find code that shadows one of Go's predeclared identifiers + - revive # golint replacement, finds style mistakes - staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks - structcheck # Finds unused struct fields - stylecheck # Stylecheck is a replacement for golint + - tagliatelle # Checks the struct tags. + - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 + - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code - unconvert # Remove unnecessary type conversions - unparam # Reports unused function parameters - unused # Checks Go code for unused constants, variables, functions and types - varcheck # Finds unused global variables and constants + - wastedassign # wastedassign finds wasted assignment statements - whitespace # Tool for detection of leading and trailing whitespace disable: + - containedctx # containedctx is a linter that detects struct contained context.Context field + - cyclop # checks function and package cyclomatic complexity + - exhaustivestruct # Checks if all struct's fields are initialized + - forbidigo # Forbids identifiers - funlen # Tool for detection of long functions - gocyclo # Computes and checks the cyclomatic complexity of functions - godot # Check if comments end in a period - gomnd # An analyzer to detect magic numbers. + - ifshort # Checks that your code uses short syntax for if-statements whenever possible + - ireturn # Accept Interfaces, Return Concrete Types - lll # Reports long lines + - maintidx # maintidx measures the maintainability index of each function. + - makezero # Finds slice declarations with non-zero initial length - maligned # Tool to detect Go structs that would take less memory if their fields were sorted - nestif # Reports deeply nested if statements - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity - nolintlint # Reports ill-formed or insufficient nolint directives + - paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test - prealloc # Finds slice declarations that could potentially be preallocated + - promlinter # Check Prometheus metrics naming via promlint - rowserrcheck # checks whether Err of rows is checked successfully - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed. - testpackage # linter that makes you use a separate _test package + - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers + - varnamelen # checks that the length of a variable's name matches its scope + - wrapcheck # Checks that errors returned from external packages are wrapped - wsl # Whitespace Linter - Forces you to use empty lines! issues: diff --git a/agent.go b/agent.go index 951103b..f8672fe 100644 --- a/agent.go +++ b/agent.go @@ -450,7 +450,7 @@ func (a *Agent) startConnectivityChecks(isControlling bool, remoteUfrag, remoteP return ErrMultipleStart default: } - if err := a.SetRemoteCredentials(remoteUfrag, remotePwd); err != nil { + if err := a.SetRemoteCredentials(remoteUfrag, remotePwd); err != nil { //nolint:contextcheck return err } @@ -477,7 +477,7 @@ func (a *Agent) startConnectivityChecks(isControlling bool, remoteUfrag, remoteP agent.updateConnectionState(ConnectionStateChecking) a.requestConnectivityCheck() - go a.connectivityChecks() + go a.connectivityChecks() //nolint:contextcheck }) } @@ -1143,7 +1143,7 @@ func (a *Agent) validateNonSTUNTraffic(local Candidate, remote net.Addr) bool { func (a *Agent) GetSelectedCandidatePair() (*CandidatePair, error) { selectedPair := a.getSelectedPair() if selectedPair == nil { - return nil, nil + return nil, nil //nolint:nilnil } local, err := selectedPair.Local.copy() @@ -1160,12 +1160,11 @@ func (a *Agent) GetSelectedCandidatePair() (*CandidatePair, error) { } func (a *Agent) getSelectedPair() *CandidatePair { - selectedPair := a.selectedPair.Load() - if selectedPair == nil { - return nil + if selectedPair, ok := a.selectedPair.Load().(*CandidatePair); ok { + return selectedPair } - return selectedPair.(*CandidatePair) + return nil } func (a *Agent) closeMulticastConn() { diff --git a/agent_stats.go b/agent_stats.go index b249560..0c25d08 100644 --- a/agent_stats.go +++ b/agent_stats.go @@ -60,7 +60,9 @@ func (a *Agent) GetLocalCandidatesStats() []CandidateStats { for _, c := range localCandidates { relayProtocol := "" if c.Type() == CandidateTypeRelay { - relayProtocol = c.(*CandidateRelay).RelayProtocol() + if cRelay, ok := c.(*CandidateRelay); ok { + relayProtocol = cRelay.RelayProtocol() + } } stat := CandidateStats{ Timestamp: time.Now(), diff --git a/agent_test.go b/agent_test.go index 24537f3..97a2d1b 100644 --- a/agent_test.go +++ b/agent_test.go @@ -433,14 +433,14 @@ func TestConnectivityOnStartup(t *testing.T) { origHdlr := aAgent.onConnectionStateChangeHdlr.Load() if origHdlr != nil { - defer check(aAgent.OnConnectionStateChange(origHdlr.(func(ConnectionState)))) + defer check(aAgent.OnConnectionStateChange(origHdlr.(func(ConnectionState)))) //nolint:forcetypeassert } check(aAgent.OnConnectionStateChange(func(s ConnectionState) { if s == ConnectionStateChecking { close(accepting) } if origHdlr != nil { - origHdlr.(func(ConnectionState))(s) + origHdlr.(func(ConnectionState))(s) //nolint:forcetypeassert } })) @@ -1862,7 +1862,7 @@ func TestAcceptAggressiveNomination(t *testing.T) { for _, candidates := range aAgent.remoteCandidates { for _, candidate := range candidates { if candidate.Equal(c) { - candidate.(*CandidateHost).priorityOverride += 1000 + candidate.(*CandidateHost).priorityOverride += 1000 //nolint:forcetypeassert break incr_priority } } diff --git a/candidate_base.go b/candidate_base.go index 7703e71..4578c46 100644 --- a/candidate_base.go +++ b/candidate_base.go @@ -249,7 +249,7 @@ func handleInboundCandidateMsg(ctx context.Context, c Candidate, buffer []byte, return } - if !c.agent().validateNonSTUNTraffic(c, srcAddr) { + if !c.agent().validateNonSTUNTraffic(c, srcAddr) { //nolint:contextcheck log.Warnf("Discarded message from %s, not a valid remote candidate", c.addr()) return } @@ -342,11 +342,10 @@ func (c *candidateBase) String() string { // LastReceived returns a time.Time indicating the last time // this candidate was received func (c *candidateBase) LastReceived() time.Time { - lastReceived := c.lastReceived.Load() - if lastReceived == nil { - return time.Time{} + if lastReceived, ok := c.lastReceived.Load().(time.Time); ok { + return lastReceived } - return lastReceived.(time.Time) + return time.Time{} } func (c *candidateBase) setLastReceived(t time.Time) { @@ -356,11 +355,10 @@ func (c *candidateBase) setLastReceived(t time.Time) { // LastSent returns a time.Time indicating the last time // this candidate was sent func (c *candidateBase) LastSent() time.Time { - lastSent := c.lastSent.Load() - if lastSent == nil { - return time.Time{} + if lastSent, ok := c.lastSent.Load().(time.Time); ok { + return lastSent } - return lastSent.(time.Time) + return time.Time{} } func (c *candidateBase) setLastSent(t time.Time) { diff --git a/external_ip_mapper.go b/external_ip_mapper.go index 5310cc0..c53e5e1 100644 --- a/external_ip_mapper.go +++ b/external_ip_mapper.go @@ -67,7 +67,7 @@ type externalIPMapper struct { func newExternalIPMapper(candidateType CandidateType, ips []string) (*externalIPMapper, error) { //nolint:gocognit if len(ips) == 0 { - return nil, nil + return nil, nil //nolint:nilnil } if candidateType == CandidateTypeUnspecified { candidateType = CandidateTypeHost // defaults to host diff --git a/gather.go b/gather.go index 36fed81..14857c7 100644 --- a/gather.go +++ b/gather.go @@ -82,7 +82,7 @@ func (a *Agent) GatherCandidates() error { func (a *Agent) gatherCandidates(ctx context.Context) { defer close(a.gatherCandidateDone) - if err := a.setGatheringState(GatheringStateGathering); err != nil { + if err := a.setGatheringState(GatheringStateGathering); err != nil { //nolint:contextcheck a.log.Warnf("failed to set gatheringState to GatheringStateGathering: %v", err) return } @@ -126,7 +126,7 @@ func (a *Agent) gatherCandidates(ctx context.Context) { // Block until all STUN and TURN URLs have been gathered (or timed out) wg.Wait() - if err := a.setGatheringState(GatheringStateComplete); err != nil { + if err := a.setGatheringState(GatheringStateComplete); err != nil { //nolint:contextcheck a.log.Warnf("failed to set gatheringState to GatheringStateComplete: %v", err) } } @@ -171,10 +171,12 @@ func (a *Agent) gatherCandidatesLocal(ctx context.Context, networkTypes []Networ } for network := range networks { - var port int - var conn net.PacketConn - var err error - var tcpType TCPType + var ( + port int + conn net.PacketConn + err error + tcpType TCPType + ) switch network { case tcp: @@ -187,7 +189,13 @@ func (a *Agent) gatherCandidatesLocal(ctx context.Context, networkTypes []Networ } continue } - port = conn.LocalAddr().(*net.TCPAddr).Port + + if tcpConn, ok := conn.LocalAddr().(*net.TCPAddr); ok { + port = tcpConn.Port + } else { + a.log.Warnf("failed to get port of conn from TCPMux: %s %s %s\n", network, ip, a.localUfrag) + continue + } tcpType = TCPTypePassive // is there a way to verify that the listen address is even // accessible from the current interface. @@ -198,7 +206,12 @@ func (a *Agent) gatherCandidatesLocal(ctx context.Context, networkTypes []Networ continue } - port = conn.LocalAddr().(*net.UDPAddr).Port + if udpConn, ok := conn.LocalAddr().(*net.UDPAddr); ok { + port = udpConn.Port + } else { + a.log.Warnf("failed to get port of UDPAddr from ListenUDPInPortRange: %s %s %s\n", network, ip, a.localUfrag) + continue + } } hostConfig := CandidateHostConfig{ Network: network, @@ -258,18 +271,23 @@ func (a *Agent) gatherCandidatesLocalUDPMux(ctx context.Context) error { if err != nil { return err } - port := conn.LocalAddr().(*net.UDPAddr).Port + + udpAddr, ok := conn.LocalAddr().(*net.UDPAddr) + if !ok { + closeConnAndLog(conn, a.log, fmt.Sprintf("Failed to create host mux candidate: %s failed to cast\n", candidateIP)) + return nil + } hostConfig := CandidateHostConfig{ Network: udp, Address: candidateIP.String(), - Port: port, + Port: udpAddr.Port, Component: ComponentRTP, } c, err := NewCandidateHost(&hostConfig) if err != nil { - closeConnAndLog(conn, a.log, fmt.Sprintf("Failed to create host mux candidate: %s %d: %v\n", candidateIP, port, err)) + closeConnAndLog(conn, a.log, fmt.Sprintf("Failed to create host mux candidate: %s %d: %v\n", candidateIP, udpAddr.Port, err)) // already logged error return nil } @@ -305,7 +323,12 @@ func (a *Agent) gatherCandidatesSrflxMapped(ctx context.Context, networkTypes [] return } - laddr := conn.LocalAddr().(*net.UDPAddr) + laddr, ok := conn.LocalAddr().(*net.UDPAddr) + if !ok { + closeConnAndLog(conn, a.log, "1:1 NAT mapping is enabled but LocalAddr is not a UDPAddr\n") + return + } + mappedIP, err := a.extIPMapper.findExternalIP(laddr.IP.String()) if err != nil { closeConnAndLog(conn, a.log, fmt.Sprintf("1:1 NAT mapping is enabled but no external IP is found for %s\n", laddr.IP.String())) @@ -340,7 +363,7 @@ func (a *Agent) gatherCandidatesSrflxMapped(ctx context.Context, networkTypes [] } } -func (a *Agent) gatherCandidatesSrflxUDPMux(ctx context.Context, urls []*URL, networkTypes []NetworkType) { +func (a *Agent) gatherCandidatesSrflxUDPMux(ctx context.Context, urls []*URL, networkTypes []NetworkType) { //nolint:gocognit var wg sync.WaitGroup defer wg.Wait() @@ -376,7 +399,12 @@ func (a *Agent) gatherCandidatesSrflxUDPMux(ctx context.Context, urls []*URL, ne ip := xoraddr.IP port := xoraddr.Port - laddr := conn.LocalAddr().(*net.UDPAddr) + laddr, ok := conn.LocalAddr().(*net.UDPAddr) + if !ok { + closeConnAndLog(conn, a.log, fmt.Sprintf("Failed to create server reflexive candidate: %s %s %d: cast failed\n", network, ip, port)) + return + } + srflxConfig := CandidateServerReflexiveConfig{ Network: network, Address: ip.String(), @@ -450,7 +478,7 @@ func (a *Agent) gatherCandidatesSrflx(ctx context.Context, urls []*URL, networkT ip := xoraddr.IP port := xoraddr.Port - laddr := conn.LocalAddr().(*net.UDPAddr) + laddr := conn.LocalAddr().(*net.UDPAddr) //nolint:forcetypeassert srflxConfig := CandidateServerReflexiveConfig{ Network: network, Address: ip.String(), @@ -512,8 +540,8 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli return } - RelAddr = locConn.LocalAddr().(*net.UDPAddr).IP.String() - RelPort = locConn.LocalAddr().(*net.UDPAddr).Port + RelAddr = locConn.LocalAddr().(*net.UDPAddr).IP.String() //nolint:forcetypeassert + RelPort = locConn.LocalAddr().(*net.UDPAddr).Port //nolint:forcetypeassert relayProtocol = udp case a.proxyDialer != nil && url.Proto == ProtoTypeTCP && (url.Scheme == SchemeTypeTURN || url.Scheme == SchemeTypeTURNS): @@ -523,8 +551,8 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli return } - RelAddr = conn.LocalAddr().(*net.TCPAddr).IP.String() - RelPort = conn.LocalAddr().(*net.TCPAddr).Port + RelAddr = conn.LocalAddr().(*net.TCPAddr).IP.String() //nolint:forcetypeassert + RelPort = conn.LocalAddr().(*net.TCPAddr).Port //nolint:forcetypeassert if url.Scheme == SchemeTypeTURN { relayProtocol = tcp } else if url.Scheme == SchemeTypeTURNS { @@ -545,8 +573,8 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli return } - RelAddr = conn.LocalAddr().(*net.TCPAddr).IP.String() - RelPort = conn.LocalAddr().(*net.TCPAddr).Port + RelAddr = conn.LocalAddr().(*net.TCPAddr).IP.String() //nolint:forcetypeassert + RelPort = conn.LocalAddr().(*net.TCPAddr).Port //nolint:forcetypeassert relayProtocol = tcp locConn = turn.NewSTUNConn(conn) case url.Proto == ProtoTypeUDP && url.Scheme == SchemeTypeTURNS: @@ -565,8 +593,8 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli return } - RelAddr = conn.LocalAddr().(*net.UDPAddr).IP.String() - RelPort = conn.LocalAddr().(*net.UDPAddr).Port + RelAddr = conn.LocalAddr().(*net.UDPAddr).IP.String() //nolint:forcetypeassert + RelPort = conn.LocalAddr().(*net.UDPAddr).Port //nolint:forcetypeassert relayProtocol = "dtls" locConn = &fakePacketConn{conn} case url.Proto == ProtoTypeTCP && url.Scheme == SchemeTypeTURNS: @@ -577,8 +605,8 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli a.log.Warnf("Failed to Dial TLS Addr %s: %v\n", TURNServerAddr, connectErr) return } - RelAddr = conn.LocalAddr().(*net.TCPAddr).IP.String() - RelPort = conn.LocalAddr().(*net.TCPAddr).Port + RelAddr = conn.LocalAddr().(*net.TCPAddr).IP.String() //nolint:forcetypeassert + RelPort = conn.LocalAddr().(*net.TCPAddr).Port //nolint:forcetypeassert relayProtocol = "tls" locConn = turn.NewSTUNConn(conn) default: @@ -612,7 +640,7 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli return } - raddr := relayConn.LocalAddr().(*net.UDPAddr) + raddr := relayConn.LocalAddr().(*net.UDPAddr) //nolint:forcetypeassert relayConfig := CandidateRelayConfig{ Network: network, Component: ComponentRTP, diff --git a/gather_vnet_test.go b/gather_vnet_test.go index fc3145a..fff589e 100644 --- a/gather_vnet_test.go +++ b/gather_vnet_test.go @@ -234,7 +234,7 @@ func TestVNetGatherWithNAT1To1(t *testing.T) { laddr := [2]*net.UDPAddr{nil, nil} for i, candi := range candidates { - laddr[i] = candi.(*CandidateHost).conn.LocalAddr().(*net.UDPAddr) + laddr[i] = candi.(*CandidateHost).conn.LocalAddr().(*net.UDPAddr) //nolint:forcetypeassert if candi.Port() != laddr[i].Port { t.Fatalf("Unexpected candidate port: %d", candi.Port()) } diff --git a/transport.go b/transport.go index 6d9aaff..08b1b6f 100644 --- a/transport.go +++ b/transport.go @@ -44,7 +44,7 @@ func (a *Agent) connect(ctx context.Context, isControlling bool, remoteUfrag, re if err != nil { return nil, err } - err = a.startConnectivityChecks(isControlling, remoteUfrag, remotePwd) + err = a.startConnectivityChecks(isControlling, remoteUfrag, remotePwd) //nolint:contextcheck if err != nil { return nil, err } diff --git a/transport_vnet_test.go b/transport_vnet_test.go index 87b9541..b2345c4 100644 --- a/transport_vnet_test.go +++ b/transport_vnet_test.go @@ -75,16 +75,16 @@ func TestRemoteLocalAddr(t *testing.T) { // Assert addresses assert.Equal(t, aLAddr.String(), - fmt.Sprintf("%s:%d", vnetLocalIPA, bRAddr.(*net.UDPAddr).Port), + fmt.Sprintf("%s:%d", vnetLocalIPA, bRAddr.(*net.UDPAddr).Port), //nolint:forcetypeassert ) assert.Equal(t, bLAddr.String(), - fmt.Sprintf("%s:%d", vnetLocalIPB, aRAddr.(*net.UDPAddr).Port), + fmt.Sprintf("%s:%d", vnetLocalIPB, aRAddr.(*net.UDPAddr).Port), //nolint:forcetypeassert ) assert.Equal(t, aRAddr.String(), - fmt.Sprintf("%s:%d", vnetGlobalIPB, bLAddr.(*net.UDPAddr).Port), + fmt.Sprintf("%s:%d", vnetGlobalIPB, bLAddr.(*net.UDPAddr).Port), //nolint:forcetypeassert ) assert.Equal(t, bRAddr.String(), - fmt.Sprintf("%s:%d", vnetGlobalIPA, aLAddr.(*net.UDPAddr).Port), + fmt.Sprintf("%s:%d", vnetGlobalIPA, aLAddr.(*net.UDPAddr).Port), //nolint:forcetypeassert ) // Close diff --git a/udp_mux.go b/udp_mux.go index 8149d28..1ee7cfe 100644 --- a/udp_mux.go +++ b/udp_mux.go @@ -1,6 +1,7 @@ package ice import ( + "errors" "io" "net" "os" @@ -242,7 +243,7 @@ func (m *UDPMuxDefault) connWorker() { } else if err != nil { if os.IsTimeout(err) { continue - } else if err != io.EOF { + } else if !errors.Is(err, io.EOF) { logger.Errorf("could not read udp packet: %v", err) } diff --git a/udp_muxed_conn.go b/udp_muxed_conn.go index 35169af..ca9113a 100644 --- a/udp_muxed_conn.go +++ b/udp_muxed_conn.go @@ -43,7 +43,7 @@ func newUDPMuxedConn(params *udpMuxedConnParams) *udpMuxedConn { } func (c *udpMuxedConn) ReadFrom(b []byte) (n int, raddr net.Addr, err error) { - buf := c.params.AddrPool.Get().(*bufferHolder) + buf := c.params.AddrPool.Get().(*bufferHolder) //nolint:forcetypeassert defer c.params.AddrPool.Put(buf) // read address @@ -171,7 +171,7 @@ func (c *udpMuxedConn) containsAddress(addr string) bool { func (c *udpMuxedConn) writePacket(data []byte, addr *net.UDPAddr) error { // write two packets, address and data - buf := c.params.AddrPool.Get().(*bufferHolder) + buf := c.params.AddrPool.Get().(*bufferHolder) //nolint:forcetypeassert defer c.params.AddrPool.Put(buf) // format of buffer | data len | data bytes | addr len | addr bytes | @@ -189,7 +189,7 @@ func (c *udpMuxedConn) writePacket(data []byte, addr *net.UDPAddr) error { // write address first, leaving room for its length n, err := encodeUDPAddr(addr, buf.buffer[offset+2:]) if err != nil { - return nil + return err } total := offset + n + 2 diff --git a/url.go b/url.go index 390591e..33082cd 100644 --- a/url.go +++ b/url.go @@ -1,6 +1,7 @@ package ice import ( + "errors" "net" "net/url" "strconv" @@ -122,7 +123,8 @@ func ParseURL(raw string) (*URL, error) { //nolint:gocognit var rawPort string if u.Host, rawPort, err = net.SplitHostPort(rawParts.Opaque); err != nil { - if e, ok := err.(*net.AddrError); ok { + var e *net.AddrError + if errors.As(err, &e) { if e.Err == "missing port in address" { nextRawURL := u.Scheme.String() + ":" + rawParts.Opaque switch { diff --git a/url_test.go b/url_test.go index 2527a10..af9d64c 100644 --- a/url_test.go +++ b/url_test.go @@ -1,6 +1,7 @@ package ice import ( + "errors" "fmt" "net" "net/url" @@ -67,11 +68,15 @@ func TestParseURL(t *testing.T) { for i, testCase := range testCases { _, err := ParseURL(testCase.rawURL) - switch e := err.(type) { - case *url.Error: - err = e.Err - case *net.AddrError: - err = fmt.Errorf(e.Err) //nolint:goerr113 + var ( + urlError *url.Error + addrError *net.AddrError + ) + switch { + case errors.As(err, &urlError): + err = urlError.Err + case errors.As(err, &addrError): + err = fmt.Errorf(addrError.Err) //nolint:goerr113 } assert.EqualError(t, err, testCase.expectedErr.Error(), "testCase: %d %v", i, testCase) } diff --git a/util.go b/util.go index 7eb13c8..af4c30c 100644 --- a/util.go +++ b/util.go @@ -218,7 +218,7 @@ func listenUDPInPortRange(vnet *vnet.Net, log logging.LeveledLogger, portMax, po laddr = &net.UDPAddr{IP: laddr.IP, Port: portCurrent} c, e := vnet.ListenUDP(network, laddr) if e == nil { - return c, e + return c, e //nolint:nilerr } log.Debugf("failed to listen %s: %v", laddr.String(), e) portCurrent++