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