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_TTRANSPORT_H_
21#define _THRIFT_TRANSPORT_TTRANSPORT_H_ 1
22
23#include <thrift/Thrift.h>
24#include <thrift/transport/TTransportException.h>
25#include <memory>
26#include <string>
27
28namespace apache {
29namespace thrift {
30namespace transport {
31
32/**
33 * Helper template to hoist readAll implementation out of TTransport
34 */
35template <class Transport_>
36uint32_t readAll(Transport_& trans, uint8_t* buf, uint32_t len) {
37 uint32_t have = 0;
38 uint32_t get = 0;
39
40 while (have < len) {
41 get = trans.read(buf + have, len - have);
42 if (get <= 0) {
43 throw TTransportException(TTransportException::END_OF_FILE, "No more data to read.");
44 }
45 have += get;
46 }
47
48 return have;
49}
50
51/**
52 * Generic interface for a method of transporting data. A TTransport may be
53 * capable of either reading or writing, but not necessarily both.
54 *
55 */
56class TTransport {
57public:
58 /**
59 * Virtual deconstructor.
60 */
61 virtual ~TTransport() = default;
62
63 /**
64 * Whether this transport is open.
65 */
66 virtual bool isOpen() const { return false; }
67
68 /**
69 * Tests whether there is more data to read or if the remote side is
70 * still open. By default this is true whenever the transport is open,
71 * but implementations should add logic to test for this condition where
72 * possible (i.e. on a socket).
73 * This is used by a server to check if it should listen for another
74 * request.
75 */
76 virtual bool peek() { return isOpen(); }
77
78 /**
79 * Opens the transport for communications.
80 *
81 * @return bool Whether the transport was successfully opened
82 * @throws TTransportException if opening failed
83 */
84 virtual void open() {
85 throw TTransportException(TTransportException::NOT_OPEN, "Cannot open base TTransport.");
86 }
87
88 /**
89 * Closes the transport.
90 */
91 virtual void close() {
92 throw TTransportException(TTransportException::NOT_OPEN, "Cannot close base TTransport.");
93 }
94
95 /**
96 * Attempt to read up to the specified number of bytes into the string.
97 *
98 * @param buf Reference to the location to write the data
99 * @param len How many bytes to read
100 * @return How many bytes were actually read
101 * @throws TTransportException If an error occurs
102 */
103 uint32_t read(uint8_t* buf, uint32_t len) {
104 T_VIRTUAL_CALL();
105 return read_virt(buf, len);
106 }
107 virtual uint32_t read_virt(uint8_t* /* buf */, uint32_t /* len */) {
108 throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot read.");
109 }
110
111 /**
112 * Reads the given amount of data in its entirety no matter what.
113 *
114 * @param s Reference to location for read data
115 * @param len How many bytes to read
116 * @return How many bytes read, which must be equal to size
117 * @throws TTransportException If insufficient data was read
118 */
119 uint32_t readAll(uint8_t* buf, uint32_t len) {
120 T_VIRTUAL_CALL();
121 return readAll_virt(buf, len);
122 }
123 virtual uint32_t readAll_virt(uint8_t* buf, uint32_t len) {
124 return apache::thrift::transport::readAll(*this, buf, len);
125 }
126
127 /**
128 * Called when read is completed.
129 * This can be over-ridden to perform a transport-specific action
130 * e.g. logging the request to a file
131 *
132 * @return number of bytes read if available, 0 otherwise.
133 */
134 virtual uint32_t readEnd() {
135 // default behaviour is to do nothing
136 return 0;
137 }
138
139 /**
140 * Writes the string in its entirety to the buffer.
141 *
142 * Note: You must call flush() to ensure the data is actually written,
143 * and available to be read back in the future. Destroying a TTransport
144 * object does not automatically flush pending data--if you destroy a
145 * TTransport object with written but unflushed data, that data may be
146 * discarded.
147 *
148 * @param buf The data to write out
149 * @throws TTransportException if an error occurs
150 */
151 void write(const uint8_t* buf, uint32_t len) {
152 T_VIRTUAL_CALL();
153 write_virt(buf, len);
154 }
155 virtual void write_virt(const uint8_t* /* buf */, uint32_t /* len */) {
156 throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot write.");
157 }
158
159 /**
160 * Called when write is completed.
161 * This can be over-ridden to perform a transport-specific action
162 * at the end of a request.
163 *
164 * @return number of bytes written if available, 0 otherwise
165 */
166 virtual uint32_t writeEnd() {
167 // default behaviour is to do nothing
168 return 0;
169 }
170
171 /**
172 * Flushes any pending data to be written. Typically used with buffered
173 * transport mechanisms.
174 *
175 * @throws TTransportException if an error occurs
176 */
177 virtual void flush() {
178 // default behaviour is to do nothing
179 }
180
181 /**
182 * Attempts to return a pointer to \c len bytes, possibly copied into \c buf.
183 * Does not consume the bytes read (i.e.: a later read will return the same
184 * data). This method is meant to support protocols that need to read
185 * variable-length fields. They can attempt to borrow the maximum amount of
186 * data that they will need, then consume (see next method) what they
187 * actually use. Some transports will not support this method and others
188 * will fail occasionally, so protocols must be prepared to use read if
189 * borrow fails.
190 *
191 * @oaram buf A buffer where the data can be stored if needed.
192 * If borrow doesn't return buf, then the contents of
193 * buf after the call are undefined. This parameter may be
194 * NULL to indicate that the caller is not supplying storage,
195 * but would like a pointer into an internal buffer, if
196 * available.
197 * @param len *len should initially contain the number of bytes to borrow.
198 * If borrow succeeds, *len will contain the number of bytes
199 * available in the returned pointer. This will be at least
200 * what was requested, but may be more if borrow returns
201 * a pointer to an internal buffer, rather than buf.
202 * If borrow fails, the contents of *len are undefined.
203 * @return If the borrow succeeds, return a pointer to the borrowed data.
204 * This might be equal to \c buf, or it might be a pointer into
205 * the transport's internal buffers.
206 * @throws TTransportException if an error occurs
207 */
208 const uint8_t* borrow(uint8_t* buf, uint32_t* len) {
209 T_VIRTUAL_CALL();
210 return borrow_virt(buf, len);
211 }
212 virtual const uint8_t* borrow_virt(uint8_t* /* buf */, uint32_t* /* len */) { return nullptr; }
213
214 /**
215 * Remove len bytes from the transport. This should always follow a borrow
216 * of at least len bytes, and should always succeed.
217 * TODO(dreiss): Is there any transport that could borrow but fail to
218 * consume, or that would require a buffer to dump the consumed data?
219 *
220 * @param len How many bytes to consume
221 * @throws TTransportException If an error occurs
222 */
223 void consume(uint32_t len) {
224 T_VIRTUAL_CALL();
225 consume_virt(len);
226 }
227 virtual void consume_virt(uint32_t /* len */) {
228 throw TTransportException(TTransportException::NOT_OPEN, "Base TTransport cannot consume.");
229 }
230
231 /**
232 * Returns the origin of the transports call. The value depends on the
233 * transport used. An IP based transport for example will return the
234 * IP address of the client making the request.
235 * If the transport doesn't know the origin Unknown is returned.
236 *
237 * The returned value can be used in a log message for example
238 */
239 virtual const std::string getOrigin() const { return "Unknown"; }
240
241protected:
242 /**
243 * Simple constructor.
244 */
245 TTransport() = default;
246};
247
248/**
249 * Generic factory class to make an input and output transport out of a
250 * source transport. Commonly used inside servers to make input and output
251 * streams out of raw clients.
252 *
253 */
254class TTransportFactory {
255public:
256 TTransportFactory() = default;
257
258 virtual ~TTransportFactory() = default;
259
260 /**
261 * Default implementation does nothing, just returns the transport given.
262 */
263 virtual std::shared_ptr<TTransport> getTransport(std::shared_ptr<TTransport> trans) {
264 return trans;
265 }
266};
267}
268}
269} // apache::thrift::transport
270
271#endif // #ifndef _THRIFT_TRANSPORT_TTRANSPORT_H_
272