You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

153 lines
4.9 KiB

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