// TestTCPConnectICMPError tests for the handshake to fail and the socket state
// cleaned up on receiving an ICMP error.
TestTCPConnectICMPError tests for the handshake to fail and the socket state
cleaned up on receiving an ICMP error.
// TestTCPConnectICMPError tests for the handshake to fail and the socket state // cleaned up on receiving an ICMP error .
func TestTCPConnectICMPError(t *testing.T) {
	dut := testbench.NewDUT(t)
	clientFD, clientPort := dut.CreateBoundSocket(t, unix.SOCK_STREAM|unix.SOCK_NONBLOCK, unix.IPPROTO_TCP, dut.Net.RemoteIPv4)
	port := uint16(9001)
	conn := dut.Net.NewTCPIPv4(t, testbench.TCP{SrcPort: &port, DstPort: &clientPort}, testbench.TCP{SrcPort: &clientPort, DstPort: &port})
	defer conn.Close(t)
	sa := unix.SockaddrInet4{Port: int(port)}
	copy(sa.Addr[:], dut.Net.LocalIPv4)
	dut.Connect(t, clientFD, &sa)
	tcp, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagSyn)}, time.Second)
	if err != nil {
		t.Fatalf("expected SYN, %s", err)
	}
	done := make(chan bool)
	defer close(done)
	var wg sync.WaitGroup
	defer wg.Wait()
	wg.Add(1)
	var block sync.WaitGroup
	block.Add(1)
	go func() {
		defer wg.Done()
		_, cancel := context.WithTimeout(context.Background(), time.Second*3)
		defer cancel()
		block.Done()
		for {
			select {
			case <-done:
				return
			default:
				if errno := dut.GetSockOptInt(t, clientFD, unix.SOL_SOCKET, unix.SO_ERROR); errno != 0 {
					return
				}
			}
		}
	}()
	block.Wait()
	sendICMPError(t, &conn, tcp)
	dut.PollOne(t, clientFD, unix.POLLHUP, time.Second)
	conn.Send(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagAck)})
	if _, err := conn.Expect(t, testbench.TCP{Flags: testbench.TCPFlags(header.TCPFlagRst)}, time.Second); err != nil {
		t.Fatalf("expected RST, %s", err)
	}
}
func TestTCPConnectICMPError ( t * testing . T ) { dut := testbench . NewDUT ( t ) clientFD , clientPort := dut . CreateBoundSocket ( t , unix . SOCK_STREAM | unix . SOCK_NONBLOCK , unix . IPPROTO_TCP , dut . Net . RemoteIPv4 ) port := uint16 ( 9001 ) conn := dut . Net . NewTCPIPv4 ( t , testbench . TCP { SrcPort : & port , DstPort : & clientPort } , testbench . TCP { SrcPort : & clientPort , DstPort : & port } ) defer conn . Close ( t ) sa := unix . SockaddrInet4 { Port : int ( port ) } copy ( sa . Addr [ : ] , dut . Net . LocalIPv4 ) dut . Connect ( t , clientFD , & sa ) tcp , err := conn . Expect ( t , testbench . TCP { Flags : testbench . TCPFlags ( header . TCPFlagSyn ) } , time . Second ) if err != nil { t . Fatalf ( " " , err ) } done := make ( chan bool ) defer close ( done ) var wg sync . WaitGroup defer wg . Wait ( ) wg . Add ( 1 ) var block sync . WaitGroup block . Add ( 1 ) go func ( ) { defer wg . Done ( ) _ , cancel := context . WithTimeout ( context . Background ( ) , time . Second * 3 ) defer cancel ( ) block . Done ( ) for { select { case <- done : return default : if errno := dut . GetSockOptInt ( t , clientFD , unix . SOL_SOCKET , unix . SO_ERROR ) ; errno != 0 { return } } } } ( ) block . Wait ( ) sendICMPError ( t , & conn , tcp ) dut . PollOne ( t , clientFD , unix . POLLHUP , time . Second ) conn . Send ( t , testbench . TCP { Flags : testbench . TCPFlags ( header . TCPFlagAck ) } ) if _ , err := conn . Expect ( t , testbench . TCP { Flags : testbench . TCPFlags ( header . TCPFlagRst ) } , time . Second ) ; err != nil { t . Fatalf ( " " , err ) } }
TestTCPConnectICMPError tests for the handshake to fail and the socket state
cleaned up on receiving an ICMP error.
TestTCPConnectICMPError tests for the handshake to fail and the socket state cleaned up on receiving an ICMP error .
// Bring the dut to SYN-SENT state with a non-blocking connect. // The DUT should reply with RST to our ACK as the state should have // transitioned to CLOSED because of handshake error.