1 /* 2 * Copyright 2018 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; 18 19 import static com.google.common.base.Preconditions.checkNotNull; 20 import static com.google.common.base.Preconditions.checkState; 21 22 import com.google.common.annotations.VisibleForTesting; 23 import com.google.common.base.MoreObjects; 24 import com.google.common.base.Objects; 25 import java.net.SocketAddress; 26 import java.security.cert.Certificate; 27 import java.util.ArrayList; 28 import java.util.Collections; 29 import java.util.HashMap; 30 import java.util.Iterator; 31 import java.util.List; 32 import java.util.Map; 33 import java.util.concurrent.ConcurrentHashMap; 34 import java.util.concurrent.ConcurrentMap; 35 import java.util.concurrent.ConcurrentNavigableMap; 36 import java.util.concurrent.ConcurrentSkipListMap; 37 import java.util.logging.Level; 38 import java.util.logging.Logger; 39 import javax.annotation.Nullable; 40 import javax.annotation.concurrent.Immutable; 41 import javax.net.ssl.SSLPeerUnverifiedException; 42 import javax.net.ssl.SSLSession; 43 44 /** 45 * This is an internal API. Do NOT use. 46 */ 47 @Internal 48 public final class InternalChannelz { 49 private static final Logger log = Logger.getLogger(InternalChannelz.class.getName()); 50 private static final InternalChannelz INSTANCE = new InternalChannelz(); 51 52 private final ConcurrentNavigableMap<Long, InternalInstrumented<ServerStats>> servers 53 = new ConcurrentSkipListMap<>(); 54 private final ConcurrentNavigableMap<Long, InternalInstrumented<ChannelStats>> rootChannels 55 = new ConcurrentSkipListMap<>(); 56 private final ConcurrentMap<Long, InternalInstrumented<ChannelStats>> subchannels 57 = new ConcurrentHashMap<>(); 58 // An InProcessTransport can appear in both otherSockets and perServerSockets simultaneously 59 private final ConcurrentMap<Long, InternalInstrumented<SocketStats>> otherSockets 60 = new ConcurrentHashMap<>(); 61 private final ConcurrentMap<Long, ServerSocketMap> perServerSockets 62 = new ConcurrentHashMap<>(); 63 64 // A convenience class to avoid deeply nested types. 65 private static final class ServerSocketMap 66 extends ConcurrentSkipListMap<Long, InternalInstrumented<SocketStats>> { 67 private static final long serialVersionUID = -7883772124944661414L; 68 } 69 70 @VisibleForTesting InternalChannelz()71 public InternalChannelz() { 72 } 73 instance()74 public static InternalChannelz instance() { 75 return INSTANCE; 76 } 77 78 /** Adds a server. */ addServer(InternalInstrumented<ServerStats> server)79 public void addServer(InternalInstrumented<ServerStats> server) { 80 ServerSocketMap prev = perServerSockets.put(id(server), new ServerSocketMap()); 81 assert prev == null; 82 add(servers, server); 83 } 84 85 /** Adds a subchannel. */ addSubchannel(InternalInstrumented<ChannelStats> subchannel)86 public void addSubchannel(InternalInstrumented<ChannelStats> subchannel) { 87 add(subchannels, subchannel); 88 } 89 90 /** Adds a root channel. */ addRootChannel(InternalInstrumented<ChannelStats> rootChannel)91 public void addRootChannel(InternalInstrumented<ChannelStats> rootChannel) { 92 add(rootChannels, rootChannel); 93 } 94 95 /** Adds a socket. */ addClientSocket(InternalInstrumented<SocketStats> socket)96 public void addClientSocket(InternalInstrumented<SocketStats> socket) { 97 add(otherSockets, socket); 98 } 99 addListenSocket(InternalInstrumented<SocketStats> socket)100 public void addListenSocket(InternalInstrumented<SocketStats> socket) { 101 add(otherSockets, socket); 102 } 103 104 /** Adds a server socket. */ addServerSocket( InternalInstrumented<ServerStats> server, InternalInstrumented<SocketStats> socket)105 public void addServerSocket( 106 InternalInstrumented<ServerStats> server, InternalInstrumented<SocketStats> socket) { 107 ServerSocketMap serverSockets = perServerSockets.get(id(server)); 108 assert serverSockets != null; 109 add(serverSockets, socket); 110 } 111 112 /** Removes a server. */ removeServer(InternalInstrumented<ServerStats> server)113 public void removeServer(InternalInstrumented<ServerStats> server) { 114 remove(servers, server); 115 ServerSocketMap prev = perServerSockets.remove(id(server)); 116 assert prev != null; 117 assert prev.isEmpty(); 118 } 119 removeSubchannel(InternalInstrumented<ChannelStats> subchannel)120 public void removeSubchannel(InternalInstrumented<ChannelStats> subchannel) { 121 remove(subchannels, subchannel); 122 } 123 removeRootChannel(InternalInstrumented<ChannelStats> channel)124 public void removeRootChannel(InternalInstrumented<ChannelStats> channel) { 125 remove(rootChannels, channel); 126 } 127 removeClientSocket(InternalInstrumented<SocketStats> socket)128 public void removeClientSocket(InternalInstrumented<SocketStats> socket) { 129 remove(otherSockets, socket); 130 } 131 removeListenSocket(InternalInstrumented<SocketStats> socket)132 public void removeListenSocket(InternalInstrumented<SocketStats> socket) { 133 remove(otherSockets, socket); 134 } 135 136 /** Removes a server socket. */ removeServerSocket( InternalInstrumented<ServerStats> server, InternalInstrumented<SocketStats> socket)137 public void removeServerSocket( 138 InternalInstrumented<ServerStats> server, InternalInstrumented<SocketStats> socket) { 139 ServerSocketMap socketsOfServer = perServerSockets.get(id(server)); 140 assert socketsOfServer != null; 141 remove(socketsOfServer, socket); 142 } 143 144 /** Returns a {@link RootChannelList}. */ getRootChannels(long fromId, int maxPageSize)145 public RootChannelList getRootChannels(long fromId, int maxPageSize) { 146 List<InternalInstrumented<ChannelStats>> channelList 147 = new ArrayList<>(); 148 Iterator<InternalInstrumented<ChannelStats>> iterator 149 = rootChannels.tailMap(fromId).values().iterator(); 150 151 while (iterator.hasNext() && channelList.size() < maxPageSize) { 152 channelList.add(iterator.next()); 153 } 154 return new RootChannelList(channelList, !iterator.hasNext()); 155 } 156 157 /** Returns a channel. */ 158 @Nullable getChannel(long id)159 public InternalInstrumented<ChannelStats> getChannel(long id) { 160 return rootChannels.get(id); 161 } 162 163 /** Returns a subchannel. */ 164 @Nullable getSubchannel(long id)165 public InternalInstrumented<ChannelStats> getSubchannel(long id) { 166 return subchannels.get(id); 167 } 168 169 /** Returns a server list. */ getServers(long fromId, int maxPageSize)170 public ServerList getServers(long fromId, int maxPageSize) { 171 List<InternalInstrumented<ServerStats>> serverList 172 = new ArrayList<>(maxPageSize); 173 Iterator<InternalInstrumented<ServerStats>> iterator 174 = servers.tailMap(fromId).values().iterator(); 175 176 while (iterator.hasNext() && serverList.size() < maxPageSize) { 177 serverList.add(iterator.next()); 178 } 179 return new ServerList(serverList, !iterator.hasNext()); 180 } 181 182 /** Returns a server. */ 183 @Nullable getServer(long id)184 public InternalInstrumented<ServerStats> getServer(long id) { 185 return servers.get(id); 186 } 187 188 /** Returns socket refs for a server. */ 189 @Nullable getServerSockets(long serverId, long fromId, int maxPageSize)190 public ServerSocketsList getServerSockets(long serverId, long fromId, int maxPageSize) { 191 ServerSocketMap serverSockets = perServerSockets.get(serverId); 192 if (serverSockets == null) { 193 return null; 194 } 195 List<InternalWithLogId> socketList = new ArrayList<>(maxPageSize); 196 Iterator<InternalInstrumented<SocketStats>> iterator 197 = serverSockets.tailMap(fromId).values().iterator(); 198 while (socketList.size() < maxPageSize && iterator.hasNext()) { 199 socketList.add(iterator.next()); 200 } 201 return new ServerSocketsList(socketList, !iterator.hasNext()); 202 } 203 204 /** Returns a socket. */ 205 @Nullable getSocket(long id)206 public InternalInstrumented<SocketStats> getSocket(long id) { 207 InternalInstrumented<SocketStats> clientSocket = otherSockets.get(id); 208 if (clientSocket != null) { 209 return clientSocket; 210 } 211 return getServerSocket(id); 212 } 213 getServerSocket(long id)214 private InternalInstrumented<SocketStats> getServerSocket(long id) { 215 for (ServerSocketMap perServerSockets : perServerSockets.values()) { 216 InternalInstrumented<SocketStats> serverSocket = perServerSockets.get(id); 217 if (serverSocket != null) { 218 return serverSocket; 219 } 220 } 221 return null; 222 } 223 224 @VisibleForTesting containsServer(InternalLogId serverRef)225 public boolean containsServer(InternalLogId serverRef) { 226 return contains(servers, serverRef); 227 } 228 229 @VisibleForTesting containsSubchannel(InternalLogId subchannelRef)230 public boolean containsSubchannel(InternalLogId subchannelRef) { 231 return contains(subchannels, subchannelRef); 232 } 233 getRootChannel(long id)234 public InternalInstrumented<ChannelStats> getRootChannel(long id) { 235 return rootChannels.get(id); 236 } 237 238 @VisibleForTesting containsClientSocket(InternalLogId transportRef)239 public boolean containsClientSocket(InternalLogId transportRef) { 240 return contains(otherSockets, transportRef); 241 } 242 add(Map<Long, T> map, T object)243 private static <T extends InternalInstrumented<?>> void add(Map<Long, T> map, T object) { 244 T prev = map.put(object.getLogId().getId(), object); 245 assert prev == null; 246 } 247 remove(Map<Long, T> map, T object)248 private static <T extends InternalInstrumented<?>> void remove(Map<Long, T> map, T object) { 249 T prev = map.remove(id(object)); 250 assert prev != null; 251 } 252 contains( Map<Long, T> map, InternalLogId id)253 private static <T extends InternalInstrumented<?>> boolean contains( 254 Map<Long, T> map, InternalLogId id) { 255 return map.containsKey(id.getId()); 256 } 257 258 public static final class RootChannelList { 259 public final List<InternalInstrumented<ChannelStats>> channels; 260 public final boolean end; 261 262 /** Creates an instance. */ RootChannelList(List<InternalInstrumented<ChannelStats>> channels, boolean end)263 public RootChannelList(List<InternalInstrumented<ChannelStats>> channels, boolean end) { 264 this.channels = checkNotNull(channels); 265 this.end = end; 266 } 267 } 268 269 public static final class ServerList { 270 public final List<InternalInstrumented<ServerStats>> servers; 271 public final boolean end; 272 273 /** Creates an instance. */ ServerList(List<InternalInstrumented<ServerStats>> servers, boolean end)274 public ServerList(List<InternalInstrumented<ServerStats>> servers, boolean end) { 275 this.servers = checkNotNull(servers); 276 this.end = end; 277 } 278 } 279 280 public static final class ServerSocketsList { 281 public final List<InternalWithLogId> sockets; 282 public final boolean end; 283 284 /** Creates an instance. */ ServerSocketsList(List<InternalWithLogId> sockets, boolean end)285 public ServerSocketsList(List<InternalWithLogId> sockets, boolean end) { 286 this.sockets = sockets; 287 this.end = end; 288 } 289 } 290 291 @Immutable 292 public static final class ServerStats { 293 public final long callsStarted; 294 public final long callsSucceeded; 295 public final long callsFailed; 296 public final long lastCallStartedNanos; 297 public final List<InternalInstrumented<SocketStats>> listenSockets; 298 299 /** 300 * Creates an instance. 301 */ ServerStats( long callsStarted, long callsSucceeded, long callsFailed, long lastCallStartedNanos, List<InternalInstrumented<SocketStats>> listenSockets)302 public ServerStats( 303 long callsStarted, 304 long callsSucceeded, 305 long callsFailed, 306 long lastCallStartedNanos, 307 List<InternalInstrumented<SocketStats>> listenSockets) { 308 this.callsStarted = callsStarted; 309 this.callsSucceeded = callsSucceeded; 310 this.callsFailed = callsFailed; 311 this.lastCallStartedNanos = lastCallStartedNanos; 312 this.listenSockets = checkNotNull(listenSockets); 313 } 314 315 public static final class Builder { 316 private long callsStarted; 317 private long callsSucceeded; 318 private long callsFailed; 319 private long lastCallStartedNanos; 320 public List<InternalInstrumented<SocketStats>> listenSockets = new ArrayList<>(); 321 setCallsStarted(long callsStarted)322 public Builder setCallsStarted(long callsStarted) { 323 this.callsStarted = callsStarted; 324 return this; 325 } 326 setCallsSucceeded(long callsSucceeded)327 public Builder setCallsSucceeded(long callsSucceeded) { 328 this.callsSucceeded = callsSucceeded; 329 return this; 330 } 331 setCallsFailed(long callsFailed)332 public Builder setCallsFailed(long callsFailed) { 333 this.callsFailed = callsFailed; 334 return this; 335 } 336 setLastCallStartedNanos(long lastCallStartedNanos)337 public Builder setLastCallStartedNanos(long lastCallStartedNanos) { 338 this.lastCallStartedNanos = lastCallStartedNanos; 339 return this; 340 } 341 342 /** Sets the listen sockets. */ addListenSockets(List<InternalInstrumented<SocketStats>> listenSockets)343 public Builder addListenSockets(List<InternalInstrumented<SocketStats>> listenSockets) { 344 checkNotNull(listenSockets, "listenSockets"); 345 for (InternalInstrumented<SocketStats> ss : listenSockets) { 346 this.listenSockets.add(checkNotNull(ss, "null listen socket")); 347 } 348 return this; 349 } 350 351 /** 352 * Builds an instance. 353 */ build()354 public ServerStats build() { 355 return new ServerStats( 356 callsStarted, 357 callsSucceeded, 358 callsFailed, 359 lastCallStartedNanos, 360 listenSockets); 361 } 362 } 363 } 364 365 /** 366 * A data class to represent a channel's stats. 367 */ 368 @Immutable 369 public static final class ChannelStats { 370 public final String target; 371 public final ConnectivityState state; 372 @Nullable public final ChannelTrace channelTrace; 373 public final long callsStarted; 374 public final long callsSucceeded; 375 public final long callsFailed; 376 public final long lastCallStartedNanos; 377 public final List<InternalWithLogId> subchannels; 378 public final List<InternalWithLogId> sockets; 379 380 /** 381 * Creates an instance. 382 */ ChannelStats( String target, ConnectivityState state, @Nullable ChannelTrace channelTrace, long callsStarted, long callsSucceeded, long callsFailed, long lastCallStartedNanos, List<InternalWithLogId> subchannels, List<InternalWithLogId> sockets)383 private ChannelStats( 384 String target, 385 ConnectivityState state, 386 @Nullable ChannelTrace channelTrace, 387 long callsStarted, 388 long callsSucceeded, 389 long callsFailed, 390 long lastCallStartedNanos, 391 List<InternalWithLogId> subchannels, 392 List<InternalWithLogId> sockets) { 393 checkState( 394 subchannels.isEmpty() || sockets.isEmpty(), 395 "channels can have subchannels only, subchannels can have either sockets OR subchannels, " 396 + "neither can have both"); 397 this.target = target; 398 this.state = state; 399 this.channelTrace = channelTrace; 400 this.callsStarted = callsStarted; 401 this.callsSucceeded = callsSucceeded; 402 this.callsFailed = callsFailed; 403 this.lastCallStartedNanos = lastCallStartedNanos; 404 this.subchannels = checkNotNull(subchannels); 405 this.sockets = checkNotNull(sockets); 406 } 407 408 public static final class Builder { 409 private String target; 410 private ConnectivityState state; 411 private ChannelTrace channelTrace; 412 private long callsStarted; 413 private long callsSucceeded; 414 private long callsFailed; 415 private long lastCallStartedNanos; 416 private List<InternalWithLogId> subchannels = Collections.emptyList(); 417 private List<InternalWithLogId> sockets = Collections.emptyList(); 418 setTarget(String target)419 public Builder setTarget(String target) { 420 this.target = target; 421 return this; 422 } 423 setState(ConnectivityState state)424 public Builder setState(ConnectivityState state) { 425 this.state = state; 426 return this; 427 } 428 setChannelTrace(ChannelTrace channelTrace)429 public Builder setChannelTrace(ChannelTrace channelTrace) { 430 this.channelTrace = channelTrace; 431 return this; 432 } 433 setCallsStarted(long callsStarted)434 public Builder setCallsStarted(long callsStarted) { 435 this.callsStarted = callsStarted; 436 return this; 437 } 438 setCallsSucceeded(long callsSucceeded)439 public Builder setCallsSucceeded(long callsSucceeded) { 440 this.callsSucceeded = callsSucceeded; 441 return this; 442 } 443 setCallsFailed(long callsFailed)444 public Builder setCallsFailed(long callsFailed) { 445 this.callsFailed = callsFailed; 446 return this; 447 } 448 setLastCallStartedNanos(long lastCallStartedNanos)449 public Builder setLastCallStartedNanos(long lastCallStartedNanos) { 450 this.lastCallStartedNanos = lastCallStartedNanos; 451 return this; 452 } 453 454 /** Sets the subchannels. */ setSubchannels(List<InternalWithLogId> subchannels)455 public Builder setSubchannels(List<InternalWithLogId> subchannels) { 456 checkState(sockets.isEmpty()); 457 this.subchannels = Collections.unmodifiableList(checkNotNull(subchannels)); 458 return this; 459 } 460 461 /** Sets the sockets. */ setSockets(List<InternalWithLogId> sockets)462 public Builder setSockets(List<InternalWithLogId> sockets) { 463 checkState(subchannels.isEmpty()); 464 this.sockets = Collections.unmodifiableList(checkNotNull(sockets)); 465 return this; 466 } 467 468 /** 469 * Builds an instance. 470 */ build()471 public ChannelStats build() { 472 return new ChannelStats( 473 target, 474 state, 475 channelTrace, 476 callsStarted, 477 callsSucceeded, 478 callsFailed, 479 lastCallStartedNanos, 480 subchannels, 481 sockets); 482 } 483 } 484 } 485 486 @Immutable 487 public static final class ChannelTrace { 488 public final long numEventsLogged; 489 public final long creationTimeNanos; 490 public final List<Event> events; 491 ChannelTrace(long numEventsLogged, long creationTimeNanos, List<Event> events)492 private ChannelTrace(long numEventsLogged, long creationTimeNanos, List<Event> events) { 493 this.numEventsLogged = numEventsLogged; 494 this.creationTimeNanos = creationTimeNanos; 495 this.events = events; 496 } 497 498 public static final class Builder { 499 private Long numEventsLogged; 500 private Long creationTimeNanos; 501 private List<Event> events = Collections.emptyList(); 502 setNumEventsLogged(long numEventsLogged)503 public Builder setNumEventsLogged(long numEventsLogged) { 504 this.numEventsLogged = numEventsLogged; 505 return this; 506 } 507 setCreationTimeNanos(long creationTimeNanos)508 public Builder setCreationTimeNanos(long creationTimeNanos) { 509 this.creationTimeNanos = creationTimeNanos; 510 return this; 511 } 512 setEvents(List<Event> events)513 public Builder setEvents(List<Event> events) { 514 this.events = Collections.unmodifiableList(new ArrayList<>(events)); 515 return this; 516 } 517 518 /** Builds a new ChannelTrace instance. */ build()519 public ChannelTrace build() { 520 checkNotNull(numEventsLogged, "numEventsLogged"); 521 checkNotNull(creationTimeNanos, "creationTimeNanos"); 522 return new ChannelTrace(numEventsLogged, creationTimeNanos, events); 523 } 524 } 525 526 @Immutable 527 public static final class Event { 528 public final String description; 529 public final Severity severity; 530 public final long timestampNanos; 531 532 // the oneof child_ref field in proto: one of channelRef and channelRef 533 @Nullable public final InternalWithLogId channelRef; 534 @Nullable public final InternalWithLogId subchannelRef; 535 536 public enum Severity { 537 CT_UNKNOWN, CT_INFO, CT_WARNING, CT_ERROR 538 } 539 Event( String description, Severity severity, long timestampNanos, @Nullable InternalWithLogId channelRef, @Nullable InternalWithLogId subchannelRef)540 private Event( 541 String description, Severity severity, long timestampNanos, 542 @Nullable InternalWithLogId channelRef, @Nullable InternalWithLogId subchannelRef) { 543 this.description = description; 544 this.severity = checkNotNull(severity, "severity"); 545 this.timestampNanos = timestampNanos; 546 this.channelRef = channelRef; 547 this.subchannelRef = subchannelRef; 548 } 549 550 @Override hashCode()551 public int hashCode() { 552 return Objects.hashCode(description, severity, timestampNanos, channelRef, subchannelRef); 553 } 554 555 @Override equals(Object o)556 public boolean equals(Object o) { 557 if (o instanceof Event) { 558 Event that = (Event) o; 559 return Objects.equal(description, that.description) 560 && Objects.equal(severity, that.severity) 561 && timestampNanos == that.timestampNanos 562 && Objects.equal(channelRef, that.channelRef) 563 && Objects.equal(subchannelRef, that.subchannelRef); 564 } 565 return false; 566 } 567 568 @Override toString()569 public String toString() { 570 return MoreObjects.toStringHelper(this) 571 .add("description", description) 572 .add("severity", severity) 573 .add("timestampNanos", timestampNanos) 574 .add("channelRef", channelRef) 575 .add("subchannelRef", subchannelRef) 576 .toString(); 577 } 578 579 public static final class Builder { 580 private String description; 581 private Severity severity; 582 private Long timestampNanos; 583 private InternalWithLogId channelRef; 584 private InternalWithLogId subchannelRef; 585 setDescription(String description)586 public Builder setDescription(String description) { 587 this.description = description; 588 return this; 589 } 590 setTimestampNanos(long timestampNanos)591 public Builder setTimestampNanos(long timestampNanos) { 592 this.timestampNanos = timestampNanos; 593 return this; 594 } 595 setSeverity(Severity severity)596 public Builder setSeverity(Severity severity) { 597 this.severity = severity; 598 return this; 599 } 600 setChannelRef(InternalWithLogId channelRef)601 public Builder setChannelRef(InternalWithLogId channelRef) { 602 this.channelRef = channelRef; 603 return this; 604 } 605 setSubchannelRef(InternalWithLogId subchannelRef)606 public Builder setSubchannelRef(InternalWithLogId subchannelRef) { 607 this.subchannelRef = subchannelRef; 608 return this; 609 } 610 611 /** Builds a new Event instance. */ build()612 public Event build() { 613 checkNotNull(description, "description"); 614 checkNotNull(severity, "severity"); 615 checkNotNull(timestampNanos, "timestampNanos"); 616 checkState( 617 channelRef == null || subchannelRef == null, 618 "at least one of channelRef and subchannelRef must be null"); 619 return new Event(description, severity, timestampNanos, channelRef, subchannelRef); 620 } 621 } 622 } 623 } 624 625 public static final class Security { 626 @Nullable 627 public final Tls tls; 628 @Nullable 629 public final OtherSecurity other; 630 Security(Tls tls)631 public Security(Tls tls) { 632 this.tls = checkNotNull(tls); 633 this.other = null; 634 } 635 Security(OtherSecurity other)636 public Security(OtherSecurity other) { 637 this.tls = null; 638 this.other = checkNotNull(other); 639 } 640 } 641 642 public static final class OtherSecurity { 643 public final String name; 644 @Nullable 645 public final Object any; 646 647 /** 648 * Creates an instance. 649 * @param name the name. 650 * @param any a com.google.protobuf.Any object 651 */ OtherSecurity(String name, @Nullable Object any)652 public OtherSecurity(String name, @Nullable Object any) { 653 this.name = checkNotNull(name); 654 checkState( 655 any == null || any.getClass().getName().endsWith("com.google.protobuf.Any"), 656 "the 'any' object must be of type com.google.protobuf.Any"); 657 this.any = any; 658 } 659 } 660 661 @Immutable 662 public static final class Tls { 663 public final String cipherSuiteStandardName; 664 @Nullable public final Certificate localCert; 665 @Nullable public final Certificate remoteCert; 666 667 /** 668 * A constructor only for testing. 669 */ Tls(String cipherSuiteName, Certificate localCert, Certificate remoteCert)670 public Tls(String cipherSuiteName, Certificate localCert, Certificate remoteCert) { 671 this.cipherSuiteStandardName = cipherSuiteName; 672 this.localCert = localCert; 673 this.remoteCert = remoteCert; 674 } 675 676 /** 677 * Creates an instance. 678 */ Tls(SSLSession session)679 public Tls(SSLSession session) { 680 String cipherSuiteStandardName = session.getCipherSuite(); 681 Certificate localCert = null; 682 Certificate remoteCert = null; 683 Certificate[] localCerts = session.getLocalCertificates(); 684 if (localCerts != null) { 685 localCert = localCerts[0]; 686 } 687 try { 688 Certificate[] peerCerts = session.getPeerCertificates(); 689 if (peerCerts != null) { 690 // The javadoc of getPeerCertificate states that the peer's own certificate is the first 691 // element of the list. 692 remoteCert = peerCerts[0]; 693 } 694 } catch (SSLPeerUnverifiedException e) { 695 // peer cert is not available 696 log.log( 697 Level.FINE, 698 String.format("Peer cert not available for peerHost=%s", session.getPeerHost()), 699 e); 700 } 701 this.cipherSuiteStandardName = cipherSuiteStandardName; 702 this.localCert = localCert; 703 this.remoteCert = remoteCert; 704 } 705 } 706 707 public static final class SocketStats { 708 @Nullable public final TransportStats data; 709 @Nullable public final SocketAddress local; 710 @Nullable public final SocketAddress remote; 711 public final SocketOptions socketOptions; 712 // Can be null if plaintext 713 @Nullable public final Security security; 714 715 /** Creates an instance. */ SocketStats( TransportStats data, @Nullable SocketAddress local, @Nullable SocketAddress remote, SocketOptions socketOptions, Security security)716 public SocketStats( 717 TransportStats data, 718 @Nullable SocketAddress local, 719 @Nullable SocketAddress remote, 720 SocketOptions socketOptions, 721 Security security) { 722 this.data = data; 723 this.local = checkNotNull(local, "local socket"); 724 this.remote = remote; 725 this.socketOptions = checkNotNull(socketOptions); 726 this.security = security; 727 } 728 } 729 730 public static final class TcpInfo { 731 public final int state; 732 public final int caState; 733 public final int retransmits; 734 public final int probes; 735 public final int backoff; 736 public final int options; 737 public final int sndWscale; 738 public final int rcvWscale; 739 public final int rto; 740 public final int ato; 741 public final int sndMss; 742 public final int rcvMss; 743 public final int unacked; 744 public final int sacked; 745 public final int lost; 746 public final int retrans; 747 public final int fackets; 748 public final int lastDataSent; 749 public final int lastAckSent; 750 public final int lastDataRecv; 751 public final int lastAckRecv; 752 public final int pmtu; 753 public final int rcvSsthresh; 754 public final int rtt; 755 public final int rttvar; 756 public final int sndSsthresh; 757 public final int sndCwnd; 758 public final int advmss; 759 public final int reordering; 760 TcpInfo(int state, int caState, int retransmits, int probes, int backoff, int options, int sndWscale, int rcvWscale, int rto, int ato, int sndMss, int rcvMss, int unacked, int sacked, int lost, int retrans, int fackets, int lastDataSent, int lastAckSent, int lastDataRecv, int lastAckRecv, int pmtu, int rcvSsthresh, int rtt, int rttvar, int sndSsthresh, int sndCwnd, int advmss, int reordering)761 TcpInfo(int state, int caState, int retransmits, int probes, int backoff, int options, 762 int sndWscale, int rcvWscale, int rto, int ato, int sndMss, int rcvMss, int unacked, 763 int sacked, int lost, int retrans, int fackets, int lastDataSent, int lastAckSent, 764 int lastDataRecv, int lastAckRecv, int pmtu, int rcvSsthresh, int rtt, int rttvar, 765 int sndSsthresh, int sndCwnd, int advmss, int reordering) { 766 this.state = state; 767 this.caState = caState; 768 this.retransmits = retransmits; 769 this.probes = probes; 770 this.backoff = backoff; 771 this.options = options; 772 this.sndWscale = sndWscale; 773 this.rcvWscale = rcvWscale; 774 this.rto = rto; 775 this.ato = ato; 776 this.sndMss = sndMss; 777 this.rcvMss = rcvMss; 778 this.unacked = unacked; 779 this.sacked = sacked; 780 this.lost = lost; 781 this.retrans = retrans; 782 this.fackets = fackets; 783 this.lastDataSent = lastDataSent; 784 this.lastAckSent = lastAckSent; 785 this.lastDataRecv = lastDataRecv; 786 this.lastAckRecv = lastAckRecv; 787 this.pmtu = pmtu; 788 this.rcvSsthresh = rcvSsthresh; 789 this.rtt = rtt; 790 this.rttvar = rttvar; 791 this.sndSsthresh = sndSsthresh; 792 this.sndCwnd = sndCwnd; 793 this.advmss = advmss; 794 this.reordering = reordering; 795 } 796 797 public static final class Builder { 798 private int state; 799 private int caState; 800 private int retransmits; 801 private int probes; 802 private int backoff; 803 private int options; 804 private int sndWscale; 805 private int rcvWscale; 806 private int rto; 807 private int ato; 808 private int sndMss; 809 private int rcvMss; 810 private int unacked; 811 private int sacked; 812 private int lost; 813 private int retrans; 814 private int fackets; 815 private int lastDataSent; 816 private int lastAckSent; 817 private int lastDataRecv; 818 private int lastAckRecv; 819 private int pmtu; 820 private int rcvSsthresh; 821 private int rtt; 822 private int rttvar; 823 private int sndSsthresh; 824 private int sndCwnd; 825 private int advmss; 826 private int reordering; 827 setState(int state)828 public Builder setState(int state) { 829 this.state = state; 830 return this; 831 } 832 setCaState(int caState)833 public Builder setCaState(int caState) { 834 this.caState = caState; 835 return this; 836 } 837 setRetransmits(int retransmits)838 public Builder setRetransmits(int retransmits) { 839 this.retransmits = retransmits; 840 return this; 841 } 842 setProbes(int probes)843 public Builder setProbes(int probes) { 844 this.probes = probes; 845 return this; 846 } 847 setBackoff(int backoff)848 public Builder setBackoff(int backoff) { 849 this.backoff = backoff; 850 return this; 851 } 852 setOptions(int options)853 public Builder setOptions(int options) { 854 this.options = options; 855 return this; 856 } 857 setSndWscale(int sndWscale)858 public Builder setSndWscale(int sndWscale) { 859 this.sndWscale = sndWscale; 860 return this; 861 } 862 setRcvWscale(int rcvWscale)863 public Builder setRcvWscale(int rcvWscale) { 864 this.rcvWscale = rcvWscale; 865 return this; 866 } 867 setRto(int rto)868 public Builder setRto(int rto) { 869 this.rto = rto; 870 return this; 871 } 872 setAto(int ato)873 public Builder setAto(int ato) { 874 this.ato = ato; 875 return this; 876 } 877 setSndMss(int sndMss)878 public Builder setSndMss(int sndMss) { 879 this.sndMss = sndMss; 880 return this; 881 } 882 setRcvMss(int rcvMss)883 public Builder setRcvMss(int rcvMss) { 884 this.rcvMss = rcvMss; 885 return this; 886 } 887 setUnacked(int unacked)888 public Builder setUnacked(int unacked) { 889 this.unacked = unacked; 890 return this; 891 } 892 setSacked(int sacked)893 public Builder setSacked(int sacked) { 894 this.sacked = sacked; 895 return this; 896 } 897 setLost(int lost)898 public Builder setLost(int lost) { 899 this.lost = lost; 900 return this; 901 } 902 setRetrans(int retrans)903 public Builder setRetrans(int retrans) { 904 this.retrans = retrans; 905 return this; 906 } 907 setFackets(int fackets)908 public Builder setFackets(int fackets) { 909 this.fackets = fackets; 910 return this; 911 } 912 setLastDataSent(int lastDataSent)913 public Builder setLastDataSent(int lastDataSent) { 914 this.lastDataSent = lastDataSent; 915 return this; 916 } 917 setLastAckSent(int lastAckSent)918 public Builder setLastAckSent(int lastAckSent) { 919 this.lastAckSent = lastAckSent; 920 return this; 921 } 922 setLastDataRecv(int lastDataRecv)923 public Builder setLastDataRecv(int lastDataRecv) { 924 this.lastDataRecv = lastDataRecv; 925 return this; 926 } 927 setLastAckRecv(int lastAckRecv)928 public Builder setLastAckRecv(int lastAckRecv) { 929 this.lastAckRecv = lastAckRecv; 930 return this; 931 } 932 setPmtu(int pmtu)933 public Builder setPmtu(int pmtu) { 934 this.pmtu = pmtu; 935 return this; 936 } 937 setRcvSsthresh(int rcvSsthresh)938 public Builder setRcvSsthresh(int rcvSsthresh) { 939 this.rcvSsthresh = rcvSsthresh; 940 return this; 941 } 942 setRtt(int rtt)943 public Builder setRtt(int rtt) { 944 this.rtt = rtt; 945 return this; 946 } 947 setRttvar(int rttvar)948 public Builder setRttvar(int rttvar) { 949 this.rttvar = rttvar; 950 return this; 951 } 952 setSndSsthresh(int sndSsthresh)953 public Builder setSndSsthresh(int sndSsthresh) { 954 this.sndSsthresh = sndSsthresh; 955 return this; 956 } 957 setSndCwnd(int sndCwnd)958 public Builder setSndCwnd(int sndCwnd) { 959 this.sndCwnd = sndCwnd; 960 return this; 961 } 962 setAdvmss(int advmss)963 public Builder setAdvmss(int advmss) { 964 this.advmss = advmss; 965 return this; 966 } 967 setReordering(int reordering)968 public Builder setReordering(int reordering) { 969 this.reordering = reordering; 970 return this; 971 } 972 973 /** Builds an instance. */ build()974 public TcpInfo build() { 975 return new TcpInfo( 976 state, caState, retransmits, probes, backoff, options, sndWscale, rcvWscale, 977 rto, ato, sndMss, rcvMss, unacked, sacked, lost, retrans, fackets, lastDataSent, 978 lastAckSent, lastDataRecv, lastAckRecv, pmtu, rcvSsthresh, rtt, rttvar, sndSsthresh, 979 sndCwnd, advmss, reordering); 980 } 981 } 982 } 983 984 public static final class SocketOptions { 985 public final Map<String, String> others; 986 // In netty, the value of a channel option may be null. 987 @Nullable public final Integer soTimeoutMillis; 988 @Nullable public final Integer lingerSeconds; 989 @Nullable public final TcpInfo tcpInfo; 990 991 /** Creates an instance. */ SocketOptions( @ullable Integer timeoutMillis, @Nullable Integer lingerSeconds, @Nullable TcpInfo tcpInfo, Map<String, String> others)992 public SocketOptions( 993 @Nullable Integer timeoutMillis, 994 @Nullable Integer lingerSeconds, 995 @Nullable TcpInfo tcpInfo, 996 Map<String, String> others) { 997 checkNotNull(others); 998 this.soTimeoutMillis = timeoutMillis; 999 this.lingerSeconds = lingerSeconds; 1000 this.tcpInfo = tcpInfo; 1001 this.others = Collections.unmodifiableMap(new HashMap<>(others)); 1002 } 1003 1004 public static final class Builder { 1005 private final Map<String, String> others = new HashMap<>(); 1006 1007 private TcpInfo tcpInfo; 1008 private Integer timeoutMillis; 1009 private Integer lingerSeconds; 1010 1011 /** The value of {@link java.net.Socket#getSoTimeout()}. */ setSocketOptionTimeoutMillis(Integer timeoutMillis)1012 public Builder setSocketOptionTimeoutMillis(Integer timeoutMillis) { 1013 this.timeoutMillis = timeoutMillis; 1014 return this; 1015 } 1016 1017 /** The value of {@link java.net.Socket#getSoLinger()}. 1018 * Note: SO_LINGER is typically expressed in seconds. 1019 */ setSocketOptionLingerSeconds(Integer lingerSeconds)1020 public Builder setSocketOptionLingerSeconds(Integer lingerSeconds) { 1021 this.lingerSeconds = lingerSeconds; 1022 return this; 1023 } 1024 setTcpInfo(TcpInfo tcpInfo)1025 public Builder setTcpInfo(TcpInfo tcpInfo) { 1026 this.tcpInfo = tcpInfo; 1027 return this; 1028 } 1029 addOption(String name, String value)1030 public Builder addOption(String name, String value) { 1031 others.put(name, checkNotNull(value)); 1032 return this; 1033 } 1034 addOption(String name, int value)1035 public Builder addOption(String name, int value) { 1036 others.put(name, Integer.toString(value)); 1037 return this; 1038 } 1039 addOption(String name, boolean value)1040 public Builder addOption(String name, boolean value) { 1041 others.put(name, Boolean.toString(value)); 1042 return this; 1043 } 1044 build()1045 public SocketOptions build() { 1046 return new SocketOptions(timeoutMillis, lingerSeconds, tcpInfo, others); 1047 } 1048 } 1049 } 1050 1051 /** 1052 * A data class to represent transport stats. 1053 */ 1054 @Immutable 1055 public static final class TransportStats { 1056 public final long streamsStarted; 1057 public final long lastLocalStreamCreatedTimeNanos; 1058 public final long lastRemoteStreamCreatedTimeNanos; 1059 public final long streamsSucceeded; 1060 public final long streamsFailed; 1061 public final long messagesSent; 1062 public final long messagesReceived; 1063 public final long keepAlivesSent; 1064 public final long lastMessageSentTimeNanos; 1065 public final long lastMessageReceivedTimeNanos; 1066 public final long localFlowControlWindow; 1067 public final long remoteFlowControlWindow; 1068 // TODO(zpencer): report socket flags and other info 1069 1070 /** 1071 * Creates an instance. 1072 */ TransportStats( long streamsStarted, long lastLocalStreamCreatedTimeNanos, long lastRemoteStreamCreatedTimeNanos, long streamsSucceeded, long streamsFailed, long messagesSent, long messagesReceived, long keepAlivesSent, long lastMessageSentTimeNanos, long lastMessageReceivedTimeNanos, long localFlowControlWindow, long remoteFlowControlWindow)1073 public TransportStats( 1074 long streamsStarted, 1075 long lastLocalStreamCreatedTimeNanos, 1076 long lastRemoteStreamCreatedTimeNanos, 1077 long streamsSucceeded, 1078 long streamsFailed, 1079 long messagesSent, 1080 long messagesReceived, 1081 long keepAlivesSent, 1082 long lastMessageSentTimeNanos, 1083 long lastMessageReceivedTimeNanos, 1084 long localFlowControlWindow, 1085 long remoteFlowControlWindow) { 1086 this.streamsStarted = streamsStarted; 1087 this.lastLocalStreamCreatedTimeNanos = lastLocalStreamCreatedTimeNanos; 1088 this.lastRemoteStreamCreatedTimeNanos = lastRemoteStreamCreatedTimeNanos; 1089 this.streamsSucceeded = streamsSucceeded; 1090 this.streamsFailed = streamsFailed; 1091 this.messagesSent = messagesSent; 1092 this.messagesReceived = messagesReceived; 1093 this.keepAlivesSent = keepAlivesSent; 1094 this.lastMessageSentTimeNanos = lastMessageSentTimeNanos; 1095 this.lastMessageReceivedTimeNanos = lastMessageReceivedTimeNanos; 1096 this.localFlowControlWindow = localFlowControlWindow; 1097 this.remoteFlowControlWindow = remoteFlowControlWindow; 1098 } 1099 } 1100 1101 /** Unwraps a {@link InternalLogId} to return a {@code long}. */ id(InternalWithLogId withLogId)1102 public static long id(InternalWithLogId withLogId) { 1103 return withLogId.getLogId().getId(); 1104 } 1105 } 1106