• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 The gRPC Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.grpc.okhttp;
18 
19 import com.google.common.base.Preconditions;
20 import io.grpc.InternalChannelz;
21 import io.grpc.InternalMetadata;
22 import io.grpc.Metadata;
23 import io.grpc.internal.TransportFrameUtil;
24 import io.grpc.okhttp.internal.CipherSuite;
25 import io.grpc.okhttp.internal.ConnectionSpec;
26 import io.grpc.okhttp.internal.framed.Header;
27 import java.net.Socket;
28 import java.net.SocketException;
29 import java.util.List;
30 import java.util.logging.Level;
31 import java.util.logging.Logger;
32 import javax.annotation.CheckReturnValue;
33 
34 /**
35  * Common utility methods for OkHttp transport.
36  */
37 class Utils {
38   private static final Logger log = Logger.getLogger(Utils.class.getName());
39 
40   /**
41    * The default ratio of window size to initial window size below which a {@code WINDOW_UPDATE}
42    * is sent to expand the window.
43    */
44   static final float DEFAULT_WINDOW_UPDATE_RATIO = 0.5f;
45   static final int DEFAULT_WINDOW_SIZE = 65535;
46   static final int CONNECTION_STREAM_ID = 0;
47 
convertHeaders(List<Header> http2Headers)48   public static Metadata convertHeaders(List<Header> http2Headers) {
49     return InternalMetadata.newMetadata(convertHeadersToArray(http2Headers));
50   }
51 
convertTrailers(List<Header> http2Headers)52   public static Metadata convertTrailers(List<Header> http2Headers) {
53     return InternalMetadata.newMetadata(convertHeadersToArray(http2Headers));
54   }
55 
56   @CheckReturnValue
convertHeadersToArray(List<Header> http2Headers)57   private static byte[][] convertHeadersToArray(List<Header> http2Headers) {
58     byte[][] headerValues = new byte[http2Headers.size() * 2][];
59     int i = 0;
60     for (Header header : http2Headers) {
61       headerValues[i++] = header.name.toByteArray();
62       headerValues[i++] = header.value.toByteArray();
63     }
64     return TransportFrameUtil.toRawSerializedHeaders(headerValues);
65   }
66 
67   /**
68    * Converts an instance of {@link com.squareup.okhttp.ConnectionSpec} for a secure connection into
69    * that of {@link ConnectionSpec} in the current package.
70    *
71    * @throws IllegalArgumentException
72    *         If {@code spec} is not with TLS
73    */
convertSpec(com.squareup.okhttp.ConnectionSpec spec)74   static ConnectionSpec convertSpec(com.squareup.okhttp.ConnectionSpec spec) {
75     Preconditions.checkArgument(spec.isTls(), "plaintext ConnectionSpec is not accepted");
76 
77     List<com.squareup.okhttp.TlsVersion> tlsVersionList = spec.tlsVersions();
78     String[] tlsVersions = new String[tlsVersionList.size()];
79     for (int i = 0; i < tlsVersions.length; i++) {
80       tlsVersions[i] = tlsVersionList.get(i).javaName();
81     }
82 
83     List<com.squareup.okhttp.CipherSuite> cipherSuiteList = spec.cipherSuites();
84     CipherSuite[] cipherSuites = new CipherSuite[cipherSuiteList.size()];
85     for (int i = 0; i < cipherSuites.length; i++) {
86       cipherSuites[i] = CipherSuite.valueOf(cipherSuiteList.get(i).name());
87     }
88 
89     return new ConnectionSpec.Builder(spec.isTls())
90         .supportsTlsExtensions(spec.supportsTlsExtensions())
91         .tlsVersions(tlsVersions)
92         .cipherSuites(cipherSuites)
93         .build();
94   }
95 
96   /**
97    * Attempts to capture all known socket options and return the results as a
98    * {@link InternalChannelz.SocketOptions}. If getting a socket option threw an exception,
99    * log the error to the logger and report the value as an error in the response.
100    */
getSocketOptions(Socket socket)101   static InternalChannelz.SocketOptions getSocketOptions(Socket socket) {
102     InternalChannelz.SocketOptions.Builder builder = new InternalChannelz.SocketOptions.Builder();
103     try {
104       builder.setSocketOptionLingerSeconds(socket.getSoLinger());
105     } catch (SocketException e) {
106       log.log(Level.SEVERE, "Exception caught while reading socket option", e);
107       builder.addOption("SO_LINGER", "channelz_internal_error");
108     }
109 
110     try {
111       builder.setSocketOptionTimeoutMillis(socket.getSoTimeout());
112     } catch (Exception e) {
113       log.log(Level.SEVERE, "Exception caught while reading socket option", e);
114       builder.addOption("SO_TIMEOUT", "channelz_internal_error");
115     }
116 
117     try {
118       builder.addOption("TCP_NODELAY", socket.getTcpNoDelay());
119     } catch (SocketException e) {
120       log.log(Level.SEVERE, "Exception caught while reading socket option", e);
121       builder.addOption("TCP_NODELAY", "channelz_internal_error");
122     }
123 
124     try {
125       builder.addOption("SO_REUSEADDR", socket.getReuseAddress());
126     } catch (SocketException e) {
127       log.log(Level.SEVERE, "Exception caught while reading socket option", e);
128       builder.addOption("SO_REUSEADDR", "channelz_internal_error");
129     }
130 
131     try {
132       builder.addOption("SO_SNDBUF", socket.getSendBufferSize());
133     } catch (SocketException e) {
134       log.log(Level.SEVERE, "Exception caught while reading socket option", e);
135       builder.addOption("SO_SNDBUF", "channelz_internal_error");
136     }
137 
138     try {
139       builder.addOption("SO_RECVBUF", socket.getReceiveBufferSize());
140     } catch (SocketException e) {
141       log.log(Level.SEVERE, "Exception caught while reading socket option", e);
142       builder.addOption("SO_RECVBUF", "channelz_internal_error");
143     }
144 
145     try {
146       builder.addOption("SO_KEEPALIVE", socket.getKeepAlive());
147     } catch (SocketException e) {
148       log.log(Level.SEVERE, "Exception caught while reading socket option", e);
149       builder.addOption("SO_KEEPALIVE", "channelz_internal_error");
150     }
151 
152     try {
153       builder.addOption("SO_OOBINLINE", socket.getOOBInline());
154     } catch (SocketException e) {
155       log.log(Level.SEVERE, "Exception caught while reading socket option", e);
156       builder.addOption("SO_OOBINLINE", "channelz_internal_error");
157     }
158 
159     try {
160       builder.addOption("IP_TOS", socket.getTrafficClass());
161     } catch (SocketException e) {
162       log.log(Level.SEVERE, "Exception caught while reading socket option", e);
163       builder.addOption("IP_TOS", "channelz_internal_error");
164     }
165     return builder.build();
166   }
167 
Utils()168   private Utils() {
169     // Prevents instantiation
170   }
171 }
172