Skip to content

Commit

Permalink
fix(network): deadlock in lwIP UDP handler's Close function
Browse files Browse the repository at this point in the history
  • Loading branch information
jyyi1 committed Jul 21, 2023
1 parent fc75f57 commit 09d310e
Showing 1 changed file with 86 additions and 0 deletions.
86 changes: 86 additions & 0 deletions network/lwip2transport/udp_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2023 Jigsaw Operations LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package lwip2transport

import (
"errors"
"fmt"
"net"
"net/netip"
"testing"

"github.com/Jigsaw-Code/outline-internal-sdk/network"
"github.com/stretchr/testify/require"
)

// Make sure we can successfully Close the request sender and response receiver only once
func TestUDPResponseWriterClose(t *testing.T) {
proxy := &noopSingleSessionPacketProxy{}
h := newUDPHandler(proxy)

// Create one and only one session in the proxy
localAddr := net.UDPAddrFromAddrPort(netip.MustParseAddrPort("127.0.0.1:60127"))
destAddr := net.UDPAddrFromAddrPort(netip.MustParseAddrPort("1.2.3.4:4321"))
err := h.ReceiveTo(&noopLwIPUDPConn{localAddr}, []byte{}, destAddr)
require.NoError(t, err)

// Close this single session (i.e. the request sender), it will close proxy.respWriter
// udpHandler must make sure only one `Close()` is called, and there should be no deadlocks
err = proxy.Close()
require.NoError(t, err)
}

/********** Test Utilities **********/

type noopSingleSessionPacketProxy struct {
respWriter network.PacketResponseReceiver
}

func (p *noopSingleSessionPacketProxy) NewSession(respWriter network.PacketResponseReceiver) (network.PacketRequestSender, error) {
if p.respWriter != nil {
return nil, errors.New("don't support multiple sessions in this proxy")
}
p.respWriter = respWriter
return p, nil
}

func (p *noopSingleSessionPacketProxy) Close() error {
fmt.Println("Closing !!!!!")
return p.respWriter.Close()
}

func (p *noopSingleSessionPacketProxy) WriteTo([]byte, net.Addr) (int, error) {
return 0, nil
}

type noopLwIPUDPConn struct {
localAddr *net.UDPAddr
}

func (*noopLwIPUDPConn) Close() error {
return nil
}

func (conn *noopLwIPUDPConn) LocalAddr() *net.UDPAddr {
return conn.localAddr
}

func (*noopLwIPUDPConn) ReceiveTo(data []byte, addr *net.UDPAddr) error {
return nil
}

func (*noopLwIPUDPConn) WriteFrom(data []byte, addr *net.UDPAddr) (int, error) {
return 0, nil
}

0 comments on commit 09d310e

Please sign in to comment.