github.com/hxx258456/ccgo@v0.0.5-0.20230213014102-48b35f46f66f/grpc/channelz/service/service_sktopt_test.go (about) 1 //go:build linux && (386 || amd64) 2 // +build linux 3 // +build 386 amd64 4 5 /* 6 * 7 * Copyright 2018 gRPC authors. 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * 21 */ 22 23 // SocketOptions is only supported on linux system. The functions defined in 24 // this file are to parse the socket option field and the test is specifically 25 // to verify the behavior of socket option parsing. 26 27 package service 28 29 import ( 30 "context" 31 "reflect" 32 "strconv" 33 "testing" 34 35 "github.com/golang/protobuf/ptypes" 36 durpb "github.com/golang/protobuf/ptypes/duration" 37 channelzpb "github.com/hxx258456/ccgo/grpc/channelz/grpc_channelz_v1" 38 "github.com/hxx258456/ccgo/grpc/internal/channelz" 39 "golang.org/x/sys/unix" 40 ) 41 42 func init() { 43 // Assign protoToSocketOption to protoToSocketOpt in order to enable socket option 44 // data conversion from proto message to channelz defined struct. 45 protoToSocketOpt = protoToSocketOption 46 } 47 48 func convertToDuration(d *durpb.Duration) (sec int64, usec int64) { 49 if d != nil { 50 if dur, err := ptypes.Duration(d); err == nil { 51 sec = int64(int64(dur) / 1e9) 52 usec = (int64(dur) - sec*1e9) / 1e3 53 } 54 } 55 return 56 } 57 58 func protoToLinger(protoLinger *channelzpb.SocketOptionLinger) *unix.Linger { 59 linger := &unix.Linger{} 60 if protoLinger.GetActive() { 61 linger.Onoff = 1 62 } 63 lv, _ := convertToDuration(protoLinger.GetDuration()) 64 linger.Linger = int32(lv) 65 return linger 66 } 67 68 func protoToSocketOption(skopts []*channelzpb.SocketOption) *channelz.SocketOptionData { 69 skdata := &channelz.SocketOptionData{} 70 for _, opt := range skopts { 71 switch opt.GetName() { 72 case "SO_LINGER": 73 protoLinger := &channelzpb.SocketOptionLinger{} 74 err := ptypes.UnmarshalAny(opt.GetAdditional(), protoLinger) 75 if err == nil { 76 skdata.Linger = protoToLinger(protoLinger) 77 } 78 case "SO_RCVTIMEO": 79 protoTimeout := &channelzpb.SocketOptionTimeout{} 80 err := ptypes.UnmarshalAny(opt.GetAdditional(), protoTimeout) 81 if err == nil { 82 skdata.RecvTimeout = protoToTime(protoTimeout) 83 } 84 case "SO_SNDTIMEO": 85 protoTimeout := &channelzpb.SocketOptionTimeout{} 86 err := ptypes.UnmarshalAny(opt.GetAdditional(), protoTimeout) 87 if err == nil { 88 skdata.SendTimeout = protoToTime(protoTimeout) 89 } 90 case "TCP_INFO": 91 tcpi := &channelzpb.SocketOptionTcpInfo{} 92 err := ptypes.UnmarshalAny(opt.GetAdditional(), tcpi) 93 if err == nil { 94 skdata.TCPInfo = &unix.TCPInfo{ 95 State: uint8(tcpi.TcpiState), 96 Ca_state: uint8(tcpi.TcpiCaState), 97 Retransmits: uint8(tcpi.TcpiRetransmits), 98 Probes: uint8(tcpi.TcpiProbes), 99 Backoff: uint8(tcpi.TcpiBackoff), 100 Options: uint8(tcpi.TcpiOptions), 101 Rto: tcpi.TcpiRto, 102 Ato: tcpi.TcpiAto, 103 Snd_mss: tcpi.TcpiSndMss, 104 Rcv_mss: tcpi.TcpiRcvMss, 105 Unacked: tcpi.TcpiUnacked, 106 Sacked: tcpi.TcpiSacked, 107 Lost: tcpi.TcpiLost, 108 Retrans: tcpi.TcpiRetrans, 109 Fackets: tcpi.TcpiFackets, 110 Last_data_sent: tcpi.TcpiLastDataSent, 111 Last_ack_sent: tcpi.TcpiLastAckSent, 112 Last_data_recv: tcpi.TcpiLastDataRecv, 113 Last_ack_recv: tcpi.TcpiLastAckRecv, 114 Pmtu: tcpi.TcpiPmtu, 115 Rcv_ssthresh: tcpi.TcpiRcvSsthresh, 116 Rtt: tcpi.TcpiRtt, 117 Rttvar: tcpi.TcpiRttvar, 118 Snd_ssthresh: tcpi.TcpiSndSsthresh, 119 Snd_cwnd: tcpi.TcpiSndCwnd, 120 Advmss: tcpi.TcpiAdvmss, 121 Reordering: tcpi.TcpiReordering} 122 } 123 } 124 } 125 return skdata 126 } 127 128 func (s) TestGetSocketOptions(t *testing.T) { 129 czCleanup := channelz.NewChannelzStorage() 130 defer cleanupWrapper(czCleanup, t) 131 ss := []*dummySocket{ 132 { 133 socketOptions: &channelz.SocketOptionData{ 134 Linger: &unix.Linger{Onoff: 1, Linger: 2}, 135 RecvTimeout: &unix.Timeval{Sec: 10, Usec: 1}, 136 SendTimeout: &unix.Timeval{}, 137 TCPInfo: &unix.TCPInfo{State: 1}, 138 }, 139 }, 140 } 141 svr := newCZServer() 142 ids := make([]int64, len(ss)) 143 svrID := channelz.RegisterServer(&dummyServer{}, "") 144 defer channelz.RemoveEntry(svrID) 145 for i, s := range ss { 146 ids[i] = channelz.RegisterNormalSocket(s, svrID, strconv.Itoa(i)) 147 defer channelz.RemoveEntry(ids[i]) 148 } 149 ctx, cancel := context.WithTimeout(context.Background(), defaultTestTimeout) 150 defer cancel() 151 for i, s := range ss { 152 resp, _ := svr.GetSocket(ctx, &channelzpb.GetSocketRequest{SocketId: ids[i]}) 153 metrics := resp.GetSocket() 154 if !reflect.DeepEqual(metrics.GetRef(), &channelzpb.SocketRef{SocketId: ids[i], Name: strconv.Itoa(i)}) || !reflect.DeepEqual(socketProtoToStruct(metrics), s) { 155 t.Fatalf("resp.GetSocket() want: metrics.GetRef() = %#v and %#v, got: metrics.GetRef() = %#v and %#v", &channelzpb.SocketRef{SocketId: ids[i], Name: strconv.Itoa(i)}, s, metrics.GetRef(), socketProtoToStruct(metrics)) 156 } 157 } 158 }