1/*
2 *
3 * Copyright 2018 gRPC authors.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18
19package service
20
21import (
22	"time"
23
24	"github.com/golang/protobuf/ptypes"
25	durpb "github.com/golang/protobuf/ptypes/duration"
26	channelzpb "google.golang.org/grpc/channelz/grpc_channelz_v1"
27	"google.golang.org/grpc/internal/channelz"
28)
29
30func convertToPtypesDuration(sec int64, usec int64) *durpb.Duration {
31	return ptypes.DurationProto(time.Duration(sec*1e9 + usec*1e3))
32}
33
34func sockoptToProto(skopts *channelz.SocketOptionData) []*channelzpb.SocketOption {
35	var opts []*channelzpb.SocketOption
36	if skopts.Linger != nil {
37		additional, err := ptypes.MarshalAny(&channelzpb.SocketOptionLinger{
38			Active:   skopts.Linger.Onoff != 0,
39			Duration: convertToPtypesDuration(int64(skopts.Linger.Linger), 0),
40		})
41		if err == nil {
42			opts = append(opts, &channelzpb.SocketOption{
43				Name:       "SO_LINGER",
44				Additional: additional,
45			})
46		}
47	}
48	if skopts.RecvTimeout != nil {
49		additional, err := ptypes.MarshalAny(&channelzpb.SocketOptionTimeout{
50			Duration: convertToPtypesDuration(int64(skopts.RecvTimeout.Sec), int64(skopts.RecvTimeout.Usec)),
51		})
52		if err == nil {
53			opts = append(opts, &channelzpb.SocketOption{
54				Name:       "SO_RCVTIMEO",
55				Additional: additional,
56			})
57		}
58	}
59	if skopts.SendTimeout != nil {
60		additional, err := ptypes.MarshalAny(&channelzpb.SocketOptionTimeout{
61			Duration: convertToPtypesDuration(int64(skopts.SendTimeout.Sec), int64(skopts.SendTimeout.Usec)),
62		})
63		if err == nil {
64			opts = append(opts, &channelzpb.SocketOption{
65				Name:       "SO_SNDTIMEO",
66				Additional: additional,
67			})
68		}
69	}
70	if skopts.TCPInfo != nil {
71		additional, err := ptypes.MarshalAny(&channelzpb.SocketOptionTcpInfo{
72			TcpiState:       uint32(skopts.TCPInfo.State),
73			TcpiCaState:     uint32(skopts.TCPInfo.Ca_state),
74			TcpiRetransmits: uint32(skopts.TCPInfo.Retransmits),
75			TcpiProbes:      uint32(skopts.TCPInfo.Probes),
76			TcpiBackoff:     uint32(skopts.TCPInfo.Backoff),
77			TcpiOptions:     uint32(skopts.TCPInfo.Options),
78			// https://golang.org/pkg/syscall/#TCPInfo
79			// TCPInfo struct does not contain info about TcpiSndWscale and TcpiRcvWscale.
80			TcpiRto:          skopts.TCPInfo.Rto,
81			TcpiAto:          skopts.TCPInfo.Ato,
82			TcpiSndMss:       skopts.TCPInfo.Snd_mss,
83			TcpiRcvMss:       skopts.TCPInfo.Rcv_mss,
84			TcpiUnacked:      skopts.TCPInfo.Unacked,
85			TcpiSacked:       skopts.TCPInfo.Sacked,
86			TcpiLost:         skopts.TCPInfo.Lost,
87			TcpiRetrans:      skopts.TCPInfo.Retrans,
88			TcpiFackets:      skopts.TCPInfo.Fackets,
89			TcpiLastDataSent: skopts.TCPInfo.Last_data_sent,
90			TcpiLastAckSent:  skopts.TCPInfo.Last_ack_sent,
91			TcpiLastDataRecv: skopts.TCPInfo.Last_data_recv,
92			TcpiLastAckRecv:  skopts.TCPInfo.Last_ack_recv,
93			TcpiPmtu:         skopts.TCPInfo.Pmtu,
94			TcpiRcvSsthresh:  skopts.TCPInfo.Rcv_ssthresh,
95			TcpiRtt:          skopts.TCPInfo.Rtt,
96			TcpiRttvar:       skopts.TCPInfo.Rttvar,
97			TcpiSndSsthresh:  skopts.TCPInfo.Snd_ssthresh,
98			TcpiSndCwnd:      skopts.TCPInfo.Snd_cwnd,
99			TcpiAdvmss:       skopts.TCPInfo.Advmss,
100			TcpiReordering:   skopts.TCPInfo.Reordering,
101		})
102		if err == nil {
103			opts = append(opts, &channelzpb.SocketOption{
104				Name:       "TCP_INFO",
105				Additional: additional,
106			})
107		}
108	}
109	return opts
110}
111