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 33 /** 34 * Common utility methods for OkHttp transport. 35 */ 36 class Utils { 37 private static final Logger log = Logger.getLogger(Utils.class.getName()); 38 39 static final int DEFAULT_WINDOW_SIZE = 65535; 40 static final int CONNECTION_STREAM_ID = 0; 41 convertHeaders(List<Header> http2Headers)42 public static Metadata convertHeaders(List<Header> http2Headers) { 43 return InternalMetadata.newMetadata(convertHeadersToArray(http2Headers)); 44 } 45 convertTrailers(List<Header> http2Headers)46 public static Metadata convertTrailers(List<Header> http2Headers) { 47 return InternalMetadata.newMetadata(convertHeadersToArray(http2Headers)); 48 } 49 convertHeadersToArray(List<Header> http2Headers)50 private static byte[][] convertHeadersToArray(List<Header> http2Headers) { 51 byte[][] headerValues = new byte[http2Headers.size() * 2][]; 52 int i = 0; 53 for (Header header : http2Headers) { 54 headerValues[i++] = header.name.toByteArray(); 55 headerValues[i++] = header.value.toByteArray(); 56 } 57 return TransportFrameUtil.toRawSerializedHeaders(headerValues); 58 } 59 60 /** 61 * Converts an instance of {@link com.squareup.okhttp.ConnectionSpec} for a secure connection into 62 * that of {@link ConnectionSpec} in the current package. 63 * 64 * @throws IllegalArgumentException 65 * If {@code spec} is not with TLS 66 */ convertSpec(com.squareup.okhttp.ConnectionSpec spec)67 static ConnectionSpec convertSpec(com.squareup.okhttp.ConnectionSpec spec) { 68 Preconditions.checkArgument(spec.isTls(), "plaintext ConnectionSpec is not accepted"); 69 70 List<com.squareup.okhttp.TlsVersion> tlsVersionList = spec.tlsVersions(); 71 String[] tlsVersions = new String[tlsVersionList.size()]; 72 for (int i = 0; i < tlsVersions.length; i++) { 73 tlsVersions[i] = tlsVersionList.get(i).javaName(); 74 } 75 76 List<com.squareup.okhttp.CipherSuite> cipherSuiteList = spec.cipherSuites(); 77 CipherSuite[] cipherSuites = new CipherSuite[cipherSuiteList.size()]; 78 for (int i = 0; i < cipherSuites.length; i++) { 79 cipherSuites[i] = CipherSuite.valueOf(cipherSuiteList.get(i).name()); 80 } 81 82 return new ConnectionSpec.Builder(spec.isTls()) 83 .supportsTlsExtensions(spec.supportsTlsExtensions()) 84 .tlsVersions(tlsVersions) 85 .cipherSuites(cipherSuites) 86 .build(); 87 } 88 89 /** 90 * Attempts to capture all known socket options and return the results as a 91 * {@link InternalChannelz.SocketOptions}. If getting a socket option threw an exception, 92 * log the error to the logger and report the value as an error in the response. 93 */ getSocketOptions(Socket socket)94 static InternalChannelz.SocketOptions getSocketOptions(Socket socket) { 95 InternalChannelz.SocketOptions.Builder builder = new InternalChannelz.SocketOptions.Builder(); 96 try { 97 builder.setSocketOptionLingerSeconds(socket.getSoLinger()); 98 } catch (SocketException e) { 99 log.log(Level.SEVERE, "Exception caught while reading socket option", e); 100 builder.addOption("SO_LINGER", "channelz_internal_error"); 101 } 102 103 try { 104 builder.setSocketOptionTimeoutMillis(socket.getSoTimeout()); 105 } catch (Exception e) { 106 log.log(Level.SEVERE, "Exception caught while reading socket option", e); 107 builder.addOption("SO_TIMEOUT", "channelz_internal_error"); 108 } 109 110 try { 111 builder.addOption("TCP_NODELAY", socket.getTcpNoDelay()); 112 } catch (SocketException e) { 113 log.log(Level.SEVERE, "Exception caught while reading socket option", e); 114 builder.addOption("TCP_NODELAY", "channelz_internal_error"); 115 } 116 117 try { 118 builder.addOption("SO_REUSEADDR", socket.getReuseAddress()); 119 } catch (SocketException e) { 120 log.log(Level.SEVERE, "Exception caught while reading socket option", e); 121 builder.addOption("SO_REUSEADDR", "channelz_internal_error"); 122 } 123 124 try { 125 builder.addOption("SO_SNDBUF", socket.getSendBufferSize()); 126 } catch (SocketException e) { 127 log.log(Level.SEVERE, "Exception caught while reading socket option", e); 128 builder.addOption("SO_SNDBUF", "channelz_internal_error"); 129 } 130 131 try { 132 builder.addOption("SO_RECVBUF", socket.getReceiveBufferSize()); 133 } catch (SocketException e) { 134 log.log(Level.SEVERE, "Exception caught while reading socket option", e); 135 builder.addOption("SO_RECVBUF", "channelz_internal_error"); 136 } 137 138 try { 139 builder.addOption("SO_KEEPALIVE", socket.getKeepAlive()); 140 } catch (SocketException e) { 141 log.log(Level.SEVERE, "Exception caught while reading socket option", e); 142 builder.addOption("SO_KEEPALIVE", "channelz_internal_error"); 143 } 144 145 try { 146 builder.addOption("SO_OOBINLINE", socket.getOOBInline()); 147 } catch (SocketException e) { 148 log.log(Level.SEVERE, "Exception caught while reading socket option", e); 149 builder.addOption("SO_OOBINLINE", "channelz_internal_error"); 150 } 151 152 try { 153 builder.addOption("IP_TOS", socket.getTrafficClass()); 154 } catch (SocketException e) { 155 log.log(Level.SEVERE, "Exception caught while reading socket option", e); 156 builder.addOption("IP_TOS", "channelz_internal_error"); 157 } 158 return builder.build(); 159 } 160 Utils()161 private Utils() { 162 // Prevents instantiation 163 } 164 } 165