1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #ifndef _THRIFT_TRANSPORT_TSOCKET_H_
21 #define _THRIFT_TRANSPORT_TSOCKET_H_ 1
22 
23 #include <string>
24 
25 #include <thrift/transport/TTransport.h>
26 #include <thrift/transport/TVirtualTransport.h>
27 #include <thrift/transport/TServerSocket.h>
28 #include <thrift/transport/PlatformSocket.h>
29 
30 #ifdef HAVE_ARPA_INET_H
31 #include <arpa/inet.h>
32 #endif
33 #ifdef HAVE_SYS_TIME_H
34 #include <sys/time.h>
35 #endif
36 #ifdef HAVE_NETDB_H
37 #include <netdb.h>
38 #endif
39 
40 namespace apache {
41 namespace thrift {
42 namespace transport {
43 
44 /**
45  * TCP Socket implementation of the TTransport interface.
46  *
47  */
48 class TSocket : public TVirtualTransport<TSocket> {
49 public:
50   /**
51    * Constructs a new socket. Note that this does NOT actually connect the
52    * socket.
53    *
54    */
55   TSocket(std::shared_ptr<TConfiguration> config = nullptr);
56 
57   /**
58    * Constructs a new socket. Note that this does NOT actually connect the
59    * socket.
60    *
61    * @param host An IP address or hostname to connect to
62    * @param port The port to connect on
63    */
64   TSocket(const std::string& host, int port, std::shared_ptr<TConfiguration> config = nullptr);
65 
66   /**
67    * Constructs a new Unix domain socket.
68    * Note that this does NOT actually connect the socket.
69    *
70    * @param path The Unix domain socket e.g. "/tmp/ThriftTest.binary.thrift"
71    * or a zero-prefixed string to create an abstract domain socket on Linux.
72    */
73   TSocket(const std::string& path, std::shared_ptr<TConfiguration> config = nullptr);
74 
75   /**
76    * Destroyes the socket object, closing it if necessary.
77    */
78   ~TSocket() override;
79 
80   /**
81    * Whether the socket is alive.
82    *
83    * @return Is the socket alive?
84    */
85   bool isOpen() const override;
86 
87   /**
88    * Checks whether there is more data available in the socket to read.
89    *
90    * This call blocks until at least one byte is available or the socket is closed.
91    */
92   bool peek() override;
93 
94   /**
95    * Creates and opens the UNIX socket.
96    *
97    * @throws TTransportException If the socket could not connect
98    */
99   void open() override;
100 
101   /**
102    * Shuts down communications on the socket.
103    */
104   void close() override;
105 
106   /**
107    * Determines whether there is pending data to read or not.
108    *
109    * This call does not block.
110    * \throws TTransportException of types:
111    *           NOT_OPEN means the socket has been closed
112    *           UNKNOWN means something unexpected happened
113    * \returns true if there is pending data to read, false otherwise
114    */
115   virtual bool hasPendingDataToRead();
116 
117   /**
118    * Reads from the underlying socket.
119    * \returns the number of bytes read or 0 indicates EOF
120    * \throws TTransportException of types:
121    *           INTERRUPTED means the socket was interrupted
122    *                       out of a blocking call
123    *           NOT_OPEN means the socket has been closed
124    *           TIMED_OUT means the receive timeout expired
125    *           UNKNOWN means something unexpected happened
126    */
127   virtual uint32_t read(uint8_t* buf, uint32_t len);
128 
129   /**
130    * Writes to the underlying socket.  Loops until done or fail.
131    */
132   virtual void write(const uint8_t* buf, uint32_t len);
133 
134   /**
135    * Writes to the underlying socket.  Does single send() and returns result.
136    */
137   virtual uint32_t write_partial(const uint8_t* buf, uint32_t len);
138 
139   /**
140    * Get the host that the socket is connected to
141    *
142    * @return string host identifier
143    */
144   std::string getHost() const;
145 
146   /**
147    * Get the port that the socket is connected to
148    *
149    * @return int port number
150    */
151   int getPort() const;
152 
153   /**
154    * Get the Unix domain socket path that the socket is connected to
155    *
156    * @return std::string path
157    */
158   std::string getPath() const;
159 
160   /**
161    * Whether the socket is a Unix domain socket. This is the same as checking
162    * if getPath() is not empty.
163    *
164    * @return Is the socket a Unix domain socket?
165    */
166   bool isUnixDomainSocket() const;
167 
168   /**
169    * Set the host that socket will connect to
170    *
171    * @param host host identifier
172    */
173   void setHost(std::string host);
174 
175   /**
176    * Set the port that socket will connect to
177    *
178    * @param port port number
179    */
180   void setPort(int port);
181 
182   /**
183    * Set the Unix domain socket path for the socket
184    *
185    * @param path std::string path
186    */
187   void setPath(std::string path);
188 
189   /**
190    * Controls whether the linger option is set on the socket.
191    *
192    * @param on      Whether SO_LINGER is on
193    * @param linger  If linger is active, the number of seconds to linger for
194    */
195   void setLinger(bool on, int linger);
196 
197   /**
198    * Whether to enable/disable Nagle's algorithm.
199    *
200    * @param noDelay Whether or not to disable the algorithm.
201    * @return
202    */
203   void setNoDelay(bool noDelay);
204 
205   /**
206    * Set the connect timeout
207    */
208   void setConnTimeout(int ms);
209 
210   /**
211    * Set the receive timeout
212    */
213   void setRecvTimeout(int ms);
214 
215   /**
216    * Set the send timeout
217    */
218   void setSendTimeout(int ms);
219 
220   /**
221    * Set the max number of recv retries in case of an THRIFT_EAGAIN
222    * error
223    */
224   void setMaxRecvRetries(int maxRecvRetries);
225 
226   /**
227    * Set SO_KEEPALIVE
228    */
229   void setKeepAlive(bool keepAlive);
230 
231   /**
232    * Get socket information formatted as a string <Host: x Port: x>
233    */
234   std::string getSocketInfo() const;
235 
236   /**
237    * Returns the DNS name of the host to which the socket is connected
238    */
239   std::string getPeerHost() const;
240 
241   /**
242    * Returns the address of the host to which the socket is connected
243    */
244   std::string getPeerAddress() const;
245 
246   /**
247    * Returns the port of the host to which the socket is connected
248    **/
249   int getPeerPort() const;
250 
251   /**
252    * Returns the underlying socket file descriptor.
253    */
getSocketFD()254   THRIFT_SOCKET getSocketFD() { return socket_; }
255 
256   /**
257    * (Re-)initialize a TSocket for the supplied descriptor.  This is only
258    * intended for use by TNonblockingServer -- other use may result in
259    * unfortunate surprises.
260    *
261    * @param fd the descriptor for an already-connected socket
262    */
263   void setSocketFD(THRIFT_SOCKET fd);
264 
265   /*
266    * Returns a cached copy of the peer address.
267    */
268   sockaddr* getCachedAddress(socklen_t* len) const;
269 
270   /**
271    * Sets whether to use a low minimum TCP retransmission timeout.
272    */
273   static void setUseLowMinRto(bool useLowMinRto);
274 
275   /**
276    * Gets whether to use a low minimum TCP retransmission timeout.
277    */
278   static bool getUseLowMinRto();
279 
280   /**
281    * Get the origin the socket is connected to
282    *
283    * @return string peer host identifier and port
284    */
285   const std::string getOrigin() const override;
286 
287   /**
288    * Constructor to create socket from file descriptor.
289    */
290   TSocket(THRIFT_SOCKET socket, std::shared_ptr<TConfiguration> config = nullptr);
291 
292   /**
293    * Constructor to create socket from file descriptor that
294    * can be interrupted safely.
295    */
296   TSocket(THRIFT_SOCKET socket, std::shared_ptr<THRIFT_SOCKET> interruptListener,
297          std::shared_ptr<TConfiguration> config = nullptr);
298 
299   /**
300    * Set a cache of the peer address (used when trivially available: e.g.
301    * accept() or connect()). Only caches IPV4 and IPV6; unset for others.
302    */
303   void setCachedAddress(const sockaddr* addr, socklen_t len);
304 
305 protected:
306   /** connect, called by open */
307   void openConnection(struct addrinfo* res);
308 
309   /** Host to connect to */
310   std::string host_;
311 
312   /** Port number to connect on */
313   int port_;
314 
315   /** UNIX domain socket path */
316   std::string path_;
317 
318   /** Underlying socket handle */
319   THRIFT_SOCKET socket_;
320 
321   /** Peer hostname */
322   mutable std::string peerHost_;
323 
324   /** Peer address */
325   mutable std::string peerAddress_;
326 
327   /** Peer port */
328   mutable int peerPort_;
329 
330   /**
331    * A shared socket pointer that will interrupt a blocking read if data
332    * becomes available on it
333    */
334   std::shared_ptr<THRIFT_SOCKET> interruptListener_;
335 
336   /** Connect timeout in ms */
337   int connTimeout_;
338 
339   /** Send timeout in ms */
340   int sendTimeout_;
341 
342   /** Recv timeout in ms */
343   int recvTimeout_;
344 
345   /** Keep alive on */
346   bool keepAlive_;
347 
348   /** Linger on */
349   bool lingerOn_;
350 
351   /** Linger val */
352   int lingerVal_;
353 
354   /** Nodelay */
355   bool noDelay_;
356 
357   /** Recv EGAIN retries */
358   int maxRecvRetries_;
359 
360   /** Cached peer address */
361   union {
362     sockaddr_in ipv4;
363     sockaddr_in6 ipv6;
364   } cachedPeerAddr_;
365 
366   /** Whether to use low minimum TCP retransmission timeout */
367   static bool useLowMinRto_;
368 
369 private:
370   void unix_open();
371   void local_open();
372 };
373 }
374 }
375 } // apache::thrift::transport
376 
377 #endif // #ifndef _THRIFT_TRANSPORT_TSOCKET_H_
378