summaryrefslogtreecommitdiff
path: root/libgo/go/net/rawconn_unix_test.go
blob: 294249ba5d1b9726c92cb48058c72fac59bb63d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// +build darwin dragonfly freebsd linux netbsd openbsd solaris

package net

import (
	"bytes"
	"syscall"
	"testing"
)

func TestRawConn(t *testing.T) {
	handler := func(ls *localServer, ln Listener) {
		c, err := ln.Accept()
		if err != nil {
			t.Error(err)
			return
		}
		defer c.Close()
		var b [32]byte
		n, err := c.Read(b[:])
		if err != nil {
			t.Error(err)
			return
		}
		if _, err := c.Write(b[:n]); err != nil {
			t.Error(err)
			return
		}
	}
	ls, err := newLocalServer("tcp")
	if err != nil {
		t.Fatal(err)
	}
	defer ls.teardown()
	if err := ls.buildup(handler); err != nil {
		t.Fatal(err)
	}

	c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
	if err != nil {
		t.Fatal(err)
	}
	defer c.Close()
	cc, err := c.(*TCPConn).SyscallConn()
	if err != nil {
		t.Fatal(err)
	}

	var operr error
	data := []byte("HELLO-R-U-THERE")
	err = cc.Write(func(s uintptr) bool {
		_, operr = syscall.Write(int(s), data)
		if operr == syscall.EAGAIN {
			return false
		}
		return true
	})
	if err != nil || operr != nil {
		t.Fatal(err, operr)
	}

	var nr int
	var b [32]byte
	err = cc.Read(func(s uintptr) bool {
		nr, operr = syscall.Read(int(s), b[:])
		if operr == syscall.EAGAIN {
			return false
		}
		return true
	})
	if err != nil || operr != nil {
		t.Fatal(err, operr)
	}
	if bytes.Compare(b[:nr], data) != 0 {
		t.Fatalf("got %#v; want %#v", b[:nr], data)
	}

	fn := func(s uintptr) {
		operr = syscall.SetsockoptInt(int(s), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
	}
	err = cc.Control(fn)
	if err != nil || operr != nil {
		t.Fatal(err, operr)
	}
	c.Close()
	err = cc.Control(fn)
	if err == nil {
		t.Fatal("should fail")
	}
}