//go:build linux // +build linux /* * * Copyright 2018 gRPC authors. * * 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 * * http://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. * */ // The test in this file should be run in an environment that has go1.10 or later, // as the function SyscallConn() (required to get socket option) was introduced // to net.TCPListener in go1.10. package channelz_test import ( "net" "reflect" "syscall" "testing" "golang.org/x/sys/unix" "google.golang.org/grpc/internal/channelz" "google.golang.org/grpc/internal/grpctest" ) type s struct { grpctest.Tester } func Test(t *testing.T) { grpctest.RunSubTests(t, s{}) } func (s) TestGetSocketOpt(t *testing.T) { network, addr := "tcp", ":0" ln, err := net.Listen(network, addr) if err != nil { t.Fatalf("net.Listen(%s,%s) failed with err: %v", network, addr, err) } defer ln.Close() go func() { ln.Accept() }() conn, _ := net.Dial(network, ln.Addr().String()) defer conn.Close() tcpc := conn.(*net.TCPConn) raw, err := tcpc.SyscallConn() if err != nil { t.Fatalf("SyscallConn() failed due to %v", err) } l := &unix.Linger{Onoff: 1, Linger: 5} recvTimout := &unix.Timeval{Sec: 100} sendTimeout := &unix.Timeval{Sec: 8888} raw.Control(func(fd uintptr) { err := unix.SetsockoptLinger(int(fd), syscall.SOL_SOCKET, syscall.SO_LINGER, l) if err != nil { t.Fatalf("failed to SetsockoptLinger(%v,%v,%v,%v) due to %v", int(fd), syscall.SOL_SOCKET, syscall.SO_LINGER, l, err) } err = unix.SetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, recvTimout) if err != nil { t.Fatalf("failed to SetsockoptTimeval(%v,%v,%v,%v) due to %v", int(fd), syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, recvTimout, err) } err = unix.SetsockoptTimeval(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, sendTimeout) if err != nil { t.Fatalf("failed to SetsockoptTimeval(%v,%v,%v,%v) due to %v", int(fd), syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, sendTimeout, err) } }) sktopt := channelz.GetSocketOption(conn) if !reflect.DeepEqual(sktopt.Linger, l) { t.Fatalf("get socket option linger, want: %v, got %v", l, sktopt.Linger) } if !reflect.DeepEqual(sktopt.RecvTimeout, recvTimout) { t.Logf("get socket option recv timeout, want: %v, got %v, may be caused by system allowing non or partial setting of this value", recvTimout, sktopt.RecvTimeout) } if !reflect.DeepEqual(sktopt.SendTimeout, sendTimeout) { t.Logf("get socket option send timeout, want: %v, got %v, may be caused by system allowing non or partial setting of this value", sendTimeout, sktopt.SendTimeout) } if sktopt == nil || sktopt.TCPInfo != nil && sktopt.TCPInfo.State != 1 { t.Fatalf("TCPInfo.State want 1 (TCP_ESTABLISHED), got %v", sktopt) } sktopt = channelz.GetSocketOption(ln) if sktopt == nil || sktopt.TCPInfo == nil || sktopt.TCPInfo.State != 10 { t.Fatalf("TCPInfo.State want 10 (TCP_LISTEN), got %v", sktopt) } }