1 /*
2  * Copyright (c) 2006- Facebook
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 /*
7  * Licensed to the Apache Software Foundation (ASF) under one
8  * or more contributor license agreements. See the NOTICE file
9  * distributed with this work for additional information
10  * regarding copyright ownership. The ASF licenses this file
11  * to you under the Apache License, Version 2.0 (the
12  * "License"); you may not use this file except in compliance
13  * with the License. You may obtain a copy of the License at
14  *
15  *   http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing,
18  * software distributed under the License is distributed on an
19  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20  * KIND, either express or implied. See the License for the
21  * specific language governing permissions and limitations
22  * under the License.
23  */
24 
25 #ifndef _THRIFT_SERVER_TSERVERFRAMEWORK_H_
26 #define _THRIFT_SERVER_TSERVERFRAMEWORK_H_ 1
27 
28 #include <memory>
29 #include <stdint.h>
30 #include <thrift/TProcessor.h>
31 #include <thrift/server/TConnectedClient.h>
32 #include <thrift/server/TServer.h>
33 #include <thrift/transport/TServerTransport.h>
34 #include <thrift/transport/TTransport.h>
35 
36 namespace apache
37 {
38 namespace thrift
39 {
40 namespace server
41 {
42 
43 /**
44  * TServerFramework provides a single consolidated processing loop for
45  * servers.  By having a single processing loop, behavior between servers
46  * is more predictable and maintenance cost is lowered.  Implementations
47  * of TServerFramework must provide a method to deal with a client that
48  * connects and one that disconnects.
49  *
50  * While this functionality could be rolled directly into TServer, and
51  * probably should be, it would break the TServer interface contract so
52  * to maintain backwards compatibility for third party servers, no TServers
53  * were harmed in the making of this class.
54  */
55 class TServerFramework : public TServer
56 {
57 public:
58 	TServerFramework(
59 		const std::shared_ptr<apache::thrift::TProcessorFactory> &processorFactory,
60 		const std::shared_ptr<apache::thrift::transport::TServerTransport> &serverTransport,
61 		const std::shared_ptr<apache::thrift::transport::TTransportFactory>
62 			&transportFactory,
63 		const std::shared_ptr<apache::thrift::protocol::TProtocolFactory> &protocolFactory);
64 
65 	TServerFramework(
66 		const std::shared_ptr<apache::thrift::TProcessor> &processor,
67 		const std::shared_ptr<apache::thrift::transport::TServerTransport> &serverTransport,
68 		const std::shared_ptr<apache::thrift::transport::TTransportFactory>
69 			&transportFactory,
70 		const std::shared_ptr<apache::thrift::protocol::TProtocolFactory> &protocolFactory);
71 
72 	TServerFramework(
73 		const std::shared_ptr<apache::thrift::TProcessorFactory> &processorFactory,
74 		const std::shared_ptr<apache::thrift::transport::TServerTransport> &serverTransport,
75 		const std::shared_ptr<apache::thrift::transport::TTransportFactory>
76 			&inputTransportFactory,
77 		const std::shared_ptr<apache::thrift::transport::TTransportFactory>
78 			&outputTransportFactory,
79 		const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>
80 			&inputProtocolFactory,
81 		const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>
82 			&outputProtocolFactory);
83 
84 	TServerFramework(
85 		const std::shared_ptr<apache::thrift::TProcessor> &processor,
86 		const std::shared_ptr<apache::thrift::transport::TServerTransport> &serverTransport,
87 		const std::shared_ptr<apache::thrift::transport::TTransportFactory>
88 			&inputTransportFactory,
89 		const std::shared_ptr<apache::thrift::transport::TTransportFactory>
90 			&outputTransportFactory,
91 		const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>
92 			&inputProtocolFactory,
93 		const std::shared_ptr<apache::thrift::protocol::TProtocolFactory>
94 			&outputProtocolFactory);
95 
96 	~TServerFramework();
97 
98 	/**
99 	 * Accept clients from the TServerTransport and add them for processing.
100 	 * Call stop() on another thread to interrupt processing
101 	 * and return control to the caller.
102 	 * Post-conditions (return guarantees):
103 	 *   The serverTransport will be closed.
104 	 */
105 	virtual void serve() override;
106 
107 	/**
108 	 * Interrupt serve() so that it meets post-conditions and returns.
109 	 */
110 	virtual void stop() override;
111 
112 	/**
113 	 * Get the concurrent client limit.
114 	 * \returns the concurrent client limit
115 	 */
116 	virtual int64_t getConcurrentClientLimit() const;
117 
118 	/**
119 	 * Get the number of currently connected clients.
120 	 * \returns the number of currently connected clients
121 	 */
122 	virtual int64_t getConcurrentClientCount() const;
123 
124 	/**
125 	 * Get the highest number of concurrent clients.
126 	 * \returns the highest number of concurrent clients
127 	 */
128 	virtual int64_t getConcurrentClientCountHWM() const;
129 
130 	/**
131 	 * Set the concurrent client limit.  This can be changed while
132 	 * the server is serving however it will not necessarily be
133 	 * enforced until the next client is accepted and added.  If the
134 	 * limit is lowered below the number of connected clients, no
135 	 * action is taken to disconnect the clients.
136 	 * The default value used if this is not called is INT64_MAX.
137 	 * \param[in]  newLimit  the new limit of concurrent clients
138 	 * \throws std::invalid_argument if newLimit is less than 1
139 	 */
140 	virtual void setConcurrentClientLimit(int64_t newLimit);
141 
142 protected:
143 	/**
144 	 * A client has connected.  The implementation is responsible for managing the
145 	 * lifetime of the client object.  This is called during the serve() thread,
146 	 * therefore a failure to return quickly will result in new client connection
147 	 * delays.
148 	 *
149 	 * \param[in]  pClient  the newly connected client
150 	 */
151 	virtual void onClientConnected(const std::shared_ptr<TConnectedClient> &pClient) = 0;
152 
153 	/**
154 	 * A client has disconnected.
155 	 * When called:
156 	 *   The server no longer tracks the client.
157 	 *   The client TTransport has already been closed.
158 	 *   The implementation must not delete the pointer.
159 	 *
160 	 * \param[in]  pClient  the disconnected client
161 	 */
162 	virtual void onClientDisconnected(TConnectedClient *pClient) = 0;
163 
164 private:
165 	/**
166 	 * Common handling for new connected clients.  Implements concurrent
167 	 * client rate limiting after onClientConnected returns by blocking the
168 	 * serve() thread if the limit has been reached.
169 	 */
170 	void newlyConnectedClient(const std::shared_ptr<TConnectedClient> &pClient);
171 
172 	/**
173 	 * Smart pointer client deletion.
174 	 * Calls onClientDisconnected and then deletes pClient.
175 	 */
176 	void disposeConnectedClient(TConnectedClient *pClient);
177 
178 	/**
179 	 * The number of concurrent clients.
180 	 */
181 	int64_t clients_;
182 
183 	/**
184 	 * The high water mark of concurrent clients.
185 	 */
186 	int64_t hwm_;
187 
188 	/**
189 	 * The limit on the number of concurrent clients.
190 	 */
191 	int64_t limit_;
192 };
193 } // namespace server
194 } // namespace thrift
195 } // namespace apache
196 
197 #endif // #ifndef _THRIFT_SERVER_TSERVERFRAMEWORK_H_
198