// Copyright 2012 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 freebsd linux netbsd openbsd windows

package ipv4_test

import (
	"code.google.com/p/go.net/ipv4"
	"errors"
	"net"
	"os"
	"runtime"
	"testing"
)

type testUnicastConn interface {
	TOS() (int, error)
	SetTOS(int) error
	TTL() (int, error)
	SetTTL(int) error
}

type unicastSockoptTest struct {
	tos int
	ttl int
}

var unicastSockoptTests = []unicastSockoptTest{
	{ipv4.DSCP_CS0 | ipv4.ECN_NOTECT, 127},
	{ipv4.DSCP_AF11 | ipv4.ECN_NOTECT, 255},
}

func TestTCPUnicastSockopt(t *testing.T) {
	for _, tt := range unicastSockoptTests {
		listener := make(chan net.Listener)
		go tcpListener(t, "127.0.0.1:0", listener)
		ln := <-listener
		if ln == nil {
			return
		}
		defer ln.Close()
		c, err := net.Dial("tcp4", ln.Addr().String())
		if err != nil {
			t.Errorf("net.Dial failed: %v", err)
			return
		}
		defer c.Close()

		cc := ipv4.NewConn(c)
		if err := testUnicastSockopt(t, tt, cc); err != nil {
			break
		}
	}
}

func tcpListener(t *testing.T, addr string, listener chan<- net.Listener) {
	ln, err := net.Listen("tcp4", addr)
	if err != nil {
		t.Errorf("net.Listen failed: %v", err)
		listener <- nil
		return
	}
	listener <- ln
	c, err := ln.Accept()
	if err != nil {
		return
	}
	c.Close()
}

func TestUDPUnicastSockopt(t *testing.T) {
	for _, tt := range unicastSockoptTests {
		c, err := net.ListenPacket("udp4", "127.0.0.1:0")
		if err != nil {
			t.Errorf("net.ListenPacket failed: %v", err)
			return
		}
		defer c.Close()

		p := ipv4.NewPacketConn(c)
		if err := testUnicastSockopt(t, tt, p); err != nil {
			break
		}
	}
}

func TestIPUnicastSockopt(t *testing.T) {
	if os.Getuid() != 0 {
		t.Skip("must be root")
	}

	for _, tt := range unicastSockoptTests {
		c, err := net.ListenPacket("ip4:icmp", "127.0.0.1")
		if err != nil {
			t.Errorf("net.ListenPacket failed: %v", err)
			return
		}
		defer c.Close()

		r, err := ipv4.NewRawConn(c)
		if err != nil {
			t.Errorf("ipv4.NewRawConn failed: %v", err)
			return
		}
		if err := testUnicastSockopt(t, tt, r); err != nil {
			break
		}
	}
}

func testUnicastSockopt(t *testing.T, tt unicastSockoptTest, c testUnicastConn) error {
	switch runtime.GOOS {
	case "windows":
		// IP_TOS option is supported on Windows 8 and beyond.
		t.Logf("skipping IP_TOS test on %q", runtime.GOOS)
	default:
		if err := c.SetTOS(tt.tos); err != nil {
			t.Errorf("ipv4.Conn.SetTOS failed: %v", err)
			return err
		}
		if v, err := c.TOS(); err != nil {
			t.Errorf("ipv4.Conn.TOS failed: %v", err)
			return err
		} else if v != tt.tos {
			t.Errorf("Got unexpected TOS value %v; expected %v", v, tt.tos)
			return errors.New("Got unexpected TOS value")
		}
	}

	if err := c.SetTTL(tt.ttl); err != nil {
		t.Errorf("ipv4.Conn.SetTTL failed: %v", err)
		return err
	}
	if v, err := c.TTL(); err != nil {
		t.Errorf("ipv4.Conn.TTL failed: %v", err)
		return err
	} else if v != tt.ttl {
		t.Errorf("Got unexpected TTL value %v; expected %v", v, tt.ttl)
		return errors.New("Got unexpected TTL value")
	}

	return nil
}
