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