Bump version to 52:0
[folly.git] / folly / wangle / acceptor / TransportInfo.h
1 /*
2  *  Copyright (c) 2015, Facebook, Inc.
3  *  All rights reserved.
4  *
5  *  This source code is licensed under the BSD-style license found in the
6  *  LICENSE file in the root directory of this source tree. An additional grant
7  *  of patent rights can be found in the PATENTS file in the same directory.
8  *
9  */
10 #pragma once
11
12 #include <folly/wangle/ssl/SSLUtil.h>
13
14 #include <chrono>
15 #include <netinet/tcp.h>
16 #include <string>
17
18 namespace folly {
19 class AsyncSocket;
20
21 /**
22  * A structure that encapsulates byte counters related to the HTTP headers.
23  */
24 struct HTTPHeaderSize {
25   /**
26    * The number of bytes used to represent the header after compression or
27    * before decompression. If header compression is not supported, the value
28    * is set to 0.
29    */
30   size_t compressed{0};
31
32   /**
33    * The number of bytes used to represent the serialized header before
34    * compression or after decompression, in plain-text format.
35    */
36   size_t uncompressed{0};
37 };
38
39 struct TransportInfo {
40   /*
41    * timestamp of when the connection handshake was completed
42    */
43   std::chrono::steady_clock::time_point acceptTime{};
44
45   /*
46    * connection RTT (Round-Trip Time)
47    */
48   std::chrono::microseconds rtt{0};
49
50   /*
51    *  the estimated ratio of packet retransmisions in current socket
52    */
53   double rtx{-1};
54
55 #if defined(__linux__) || defined(__FreeBSD__)
56   /*
57    * TCP information as fetched from getsockopt(2)
58    */
59   tcp_info tcpinfo {
60 #if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 17
61     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // 32
62 #else
63     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 // 29
64 #endif  // __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 17
65   };
66 #endif  // defined(__linux__) || defined(__FreeBSD__)
67
68   /*
69    * time for setting the connection, from the moment in was accepted until it
70    * is established.
71    */
72   std::chrono::milliseconds setupTime{0};
73
74   /*
75    * time for setting up the SSL connection or SSL handshake
76    */
77   std::chrono::milliseconds sslSetupTime{0};
78
79   /*
80    * The name of the SSL ciphersuite used by the transaction's
81    * transport.  Returns null if the transport is not SSL.
82    */
83   std::shared_ptr<std::string> sslCipher{nullptr};
84
85   /*
86    * The SSL server name used by the transaction's
87    * transport.  Returns null if the transport is not SSL.
88    */
89   std::shared_ptr<std::string> sslServerName{nullptr};
90
91   /*
92    * list of ciphers sent by the client
93    */
94   std::shared_ptr<std::string> sslClientCiphers{nullptr};
95
96   /*
97    * list of compression methods sent by the client
98    */
99   std::shared_ptr<std::string> sslClientComprMethods{nullptr};
100
101   /*
102    * list of TLS extensions sent by the client
103    */
104   std::shared_ptr<std::string> sslClientExts{nullptr};
105
106   /*
107    * hash of all the SSL parameters sent by the client
108    */
109   std::shared_ptr<std::string> sslSignature{nullptr};
110
111   /*
112    * list of ciphers supported by the server
113    */
114   std::shared_ptr<std::string> sslServerCiphers{nullptr};
115
116   /*
117    * guessed "(os) (browser)" based on SSL Signature
118    */
119   std::shared_ptr<std::string> guessedUserAgent{nullptr};
120
121   /**
122    * The result of SSL NPN negotiation.
123    */
124   std::shared_ptr<std::string> sslNextProtocol{nullptr};
125
126   /*
127    * total number of bytes sent over the connection
128    */
129   int64_t totalBytes{0};
130
131   /**
132    * If the client passed through one of our L4 proxies (using PROXY Protocol),
133    * then this will contain the IP address of the proxy host.
134    */
135   std::shared_ptr<folly::SocketAddress> clientAddrOriginal;
136
137   /**
138    * header bytes read
139    */
140   HTTPHeaderSize ingressHeader;
141
142   /*
143    * header bytes written
144    */
145   HTTPHeaderSize egressHeader;
146
147   /*
148    * Here is how the timeToXXXByte variables are planned out:
149    * 1. All timeToXXXByte variables are measuring the ByteEvent from reqStart_
150    * 2. You can get the timing between two ByteEvents by calculating their
151    *    differences. For example:
152    *    timeToLastBodyByteAck - timeToFirstByte
153    *    => Total time to deliver the body
154    * 3. The calculation in point (2) is typically done outside acceptor
155    *
156    * Future plan:
157    * We should log the timestamps (TimePoints) and allow
158    * the consumer to calculate the latency whatever it
159    * wants instead of calculating them in wangle, for the sake of flexibility.
160    * For example:
161    * 1. TimePoint reqStartTimestamp;
162    * 2. TimePoint firstHeaderByteSentTimestamp;
163    * 3. TimePoint firstBodyByteTimestamp;
164    * 3. TimePoint lastBodyByteTimestamp;
165    * 4. TimePoint lastBodyByteAckTimestamp;
166    */
167
168   /*
169    * time to first header byte written to the kernel send buffer
170    * NOTE: It is not 100% accurate since TAsyncSocket does not do
171    * do callback on partial write.
172    */
173   int32_t timeToFirstHeaderByte{-1};
174
175   /*
176    * time to first body byte written to the kernel send buffer
177    */
178   int32_t timeToFirstByte{-1};
179
180   /*
181    * time to last body byte written to the kernel send buffer
182    */
183   int32_t timeToLastByte{-1};
184
185   /*
186    * time to TCP Ack received for the last written body byte
187    */
188   int32_t timeToLastBodyByteAck{-1};
189
190   /*
191    * time it took the client to ACK the last byte, from the moment when the
192    * kernel sent the last byte to the client and until it received the ACK
193    * for that byte
194    */
195   int32_t lastByteAckLatency{-1};
196
197   /*
198    * time spent inside wangle
199    */
200   int32_t proxyLatency{-1};
201
202   /*
203    * time between connection accepted and client message headers completed
204    */
205   int32_t clientLatency{-1};
206
207   /*
208    * latency for communication with the server
209    */
210   int32_t serverLatency{-1};
211
212   /*
213    * time used to get a usable connection.
214    */
215   int32_t connectLatency{-1};
216
217   /*
218    * body bytes written
219    */
220   uint32_t egressBodySize{0};
221
222   /*
223    * value of errno in case of getsockopt() error
224    */
225   int tcpinfoErrno{0};
226
227   /*
228    * bytes read & written during SSL Setup
229    */
230   uint32_t sslSetupBytesWritten{0};
231   uint32_t sslSetupBytesRead{0};
232
233   /**
234    * SSL error detail
235    */
236   uint32_t sslError{0};
237
238   /**
239    * body bytes read
240    */
241   uint32_t ingressBodySize{0};
242
243   /*
244    * The SSL version used by the transaction's transport, in
245    * OpenSSL's format: 4 bits for the major version, followed by 4 bits
246    * for the minor version.  Returns zero for non-SSL.
247    */
248   uint16_t sslVersion{0};
249
250   /*
251    * The SSL certificate size.
252    */
253   uint16_t sslCertSize{0};
254
255   /**
256    * response status code
257    */
258   uint16_t statusCode{0};
259
260   /*
261    * The SSL mode for the transaction's transport: new session,
262    * resumed session, or neither (non-SSL).
263    */
264   SSLResumeEnum sslResume{SSLResumeEnum::NA};
265
266   /*
267    * true if the tcpinfo was successfully read from the kernel
268    */
269   bool validTcpinfo{false};
270
271   /*
272    * true if the connection is SSL, false otherwise
273    */
274   bool ssl{false};
275
276   /*
277    * get the RTT value in milliseconds
278    */
279   std::chrono::milliseconds getRttMs() const {
280     return std::chrono::duration_cast<std::chrono::milliseconds>(rtt);
281   }
282
283   /*
284    * initialize the fields related with tcp_info
285    */
286   bool initWithSocket(const AsyncSocket* sock);
287
288   /*
289    * Get the kernel's estimate of round-trip time (RTT) to the transport's peer
290    * in microseconds. Returns -1 on error.
291    */
292   static int64_t readRTT(const AsyncSocket* sock);
293
294 #if defined(__linux__) || defined(__FreeBSD__)
295   /*
296    * perform the getsockopt(2) syscall to fetch TCP info for a given socket
297    */
298   static bool readTcpInfo(struct tcp_info* tcpinfo,
299                           const AsyncSocket* sock);
300 #endif
301 };
302
303 } // folly