| // +build linux,!appengine |
| |
| /* |
| * |
| * 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) |
| } |
| } |