Home | History | Annotate | Download | only in net
      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 // +build darwin dragonfly freebsd linux netbsd openbsd solaris
      6 
      7 package net
      8 
      9 import (
     10 	"bytes"
     11 	"syscall"
     12 	"testing"
     13 )
     14 
     15 func TestRawConn(t *testing.T) {
     16 	handler := func(ls *localServer, ln Listener) {
     17 		c, err := ln.Accept()
     18 		if err != nil {
     19 			t.Error(err)
     20 			return
     21 		}
     22 		defer c.Close()
     23 		var b [32]byte
     24 		n, err := c.Read(b[:])
     25 		if err != nil {
     26 			t.Error(err)
     27 			return
     28 		}
     29 		if _, err := c.Write(b[:n]); err != nil {
     30 			t.Error(err)
     31 			return
     32 		}
     33 	}
     34 	ls, err := newLocalServer("tcp")
     35 	if err != nil {
     36 		t.Fatal(err)
     37 	}
     38 	defer ls.teardown()
     39 	if err := ls.buildup(handler); err != nil {
     40 		t.Fatal(err)
     41 	}
     42 
     43 	c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
     44 	if err != nil {
     45 		t.Fatal(err)
     46 	}
     47 	defer c.Close()
     48 	cc, err := c.(*TCPConn).SyscallConn()
     49 	if err != nil {
     50 		t.Fatal(err)
     51 	}
     52 
     53 	var operr error
     54 	data := []byte("HELLO-R-U-THERE")
     55 	err = cc.Write(func(s uintptr) bool {
     56 		_, operr = syscall.Write(int(s), data)
     57 		if operr == syscall.EAGAIN {
     58 			return false
     59 		}
     60 		return true
     61 	})
     62 	if err != nil || operr != nil {
     63 		t.Fatal(err, operr)
     64 	}
     65 
     66 	var nr int
     67 	var b [32]byte
     68 	err = cc.Read(func(s uintptr) bool {
     69 		nr, operr = syscall.Read(int(s), b[:])
     70 		if operr == syscall.EAGAIN {
     71 			return false
     72 		}
     73 		return true
     74 	})
     75 	if err != nil || operr != nil {
     76 		t.Fatal(err, operr)
     77 	}
     78 	if bytes.Compare(b[:nr], data) != 0 {
     79 		t.Fatalf("got %#v; want %#v", b[:nr], data)
     80 	}
     81 
     82 	fn := func(s uintptr) {
     83 		operr = syscall.SetsockoptInt(int(s), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1)
     84 	}
     85 	err = cc.Control(fn)
     86 	if err != nil || operr != nil {
     87 		t.Fatal(err, operr)
     88 	}
     89 	c.Close()
     90 	err = cc.Control(fn)
     91 	if err == nil {
     92 		t.Fatal("should fail")
     93 	}
     94 }
     95 
     96 func TestRawConnListener(t *testing.T) {
     97 	ln, err := newLocalListener("tcp")
     98 	if err != nil {
     99 		t.Fatal(err)
    100 	}
    101 	defer ln.Close()
    102 
    103 	cc, err := ln.(*TCPListener).SyscallConn()
    104 	if err != nil {
    105 		t.Fatal(err)
    106 	}
    107 
    108 	called := false
    109 	op := func(uintptr) bool {
    110 		called = true
    111 		return true
    112 	}
    113 
    114 	err = cc.Write(op)
    115 	if err == nil {
    116 		t.Error("Write should return an error")
    117 	}
    118 	if called {
    119 		t.Error("Write shouldn't call op")
    120 	}
    121 
    122 	called = false
    123 	err = cc.Read(op)
    124 	if err == nil {
    125 		t.Error("Read should return an error")
    126 	}
    127 	if called {
    128 		t.Error("Read shouldn't call op")
    129 	}
    130 
    131 	var operr error
    132 	fn := func(s uintptr) {
    133 		_, operr = syscall.GetsockoptInt(int(s), syscall.SOL_SOCKET, syscall.SO_REUSEADDR)
    134 	}
    135 	err = cc.Control(fn)
    136 	if err != nil || operr != nil {
    137 		t.Fatal(err, operr)
    138 	}
    139 	ln.Close()
    140 	err = cc.Control(fn)
    141 	if err == nil {
    142 		t.Fatal("Control after Close should fail")
    143 	}
    144 }
    145