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 #include <thrift/server/TSimpleServer.h>
21 #include <thrift/transport/TTransportException.h>
22 #include <string>
23 #include <iostream>
24
25 namespace apache
26 {
27 namespace thrift
28 {
29 namespace server
30 {
31
32 using namespace std;
33 using namespace apache::thrift;
34 using namespace apache::thrift::protocol;
35 using namespace apache::thrift::transport;
36 using boost::shared_ptr;
37
38 /**
39 * A simple single-threaded application server. Perfect for unit tests!
40 *
41 */
serve()42 void TSimpleServer::serve()
43 {
44
45 shared_ptr<TTransport> client;
46 shared_ptr<TTransport> inputTransport;
47 shared_ptr<TTransport> outputTransport;
48 shared_ptr<TProtocol> inputProtocol;
49 shared_ptr<TProtocol> outputProtocol;
50
51 // Start the server listening
52 serverTransport_->listen();
53
54 // Run the preServe event
55 if (eventHandler_)
56 {
57 eventHandler_->preServe();
58 }
59
60 // Fetch client from server
61 while (!stop_)
62 {
63 try
64 {
65 client = serverTransport_->accept();
66 inputTransport = inputTransportFactory_->getTransport(client);
67 outputTransport = outputTransportFactory_->getTransport(client);
68 inputProtocol = inputProtocolFactory_->getProtocol(inputTransport);
69 outputProtocol = outputProtocolFactory_->getProtocol(outputTransport);
70 }
71 catch (TTransportException& ttx)
72 {
73 if (inputTransport)
74 {
75 inputTransport->close();
76 }
77
78 if (outputTransport)
79 {
80 outputTransport->close();
81 }
82
83 if (client)
84 {
85 client->close();
86 }
87
88 if (!stop_ || ttx.getType() != TTransportException::INTERRUPTED)
89 {
90 string errStr = string("TServerTransport died on accept: ") + ttx.what();
91 GlobalOutput(errStr.c_str());
92 }
93
94 continue;
95 }
96 catch (TException& tx)
97 {
98 if (inputTransport)
99 {
100 inputTransport->close();
101 }
102
103 if (outputTransport)
104 {
105 outputTransport->close();
106 }
107
108 if (client)
109 {
110 client->close();
111 }
112
113 string errStr = string("Some kind of accept exception: ") + tx.what();
114 GlobalOutput(errStr.c_str());
115 continue;
116 }
117 catch (string s)
118 {
119 if (inputTransport)
120 {
121 inputTransport->close();
122 }
123
124 if (outputTransport)
125 {
126 outputTransport->close();
127 }
128
129 if (client)
130 {
131 client->close();
132 }
133
134 string errStr = string("Some kind of accept exception: ") + s;
135 GlobalOutput(errStr.c_str());
136 break;
137 }
138
139 // Get the processor
140 shared_ptr<TProcessor> processor = getProcessor(inputProtocol,
141 outputProtocol, client);
142
143 void* connectionContext = NULL;
144
145 if (eventHandler_)
146 {
147 connectionContext = eventHandler_->createContext(inputProtocol, outputProtocol);
148 }
149
150 try
151 {
152 for (;;)
153 {
154 if (eventHandler_)
155 {
156 eventHandler_->processContext(connectionContext, client);
157 }
158
159 if (!processor->process(inputProtocol, outputProtocol,
160 connectionContext) ||
161 // Peek ahead, is the remote side closed?
162 !inputProtocol->getTransport()->peek())
163 {
164 break;
165 }
166 }
167 }
168 catch (const TTransportException& ttx)
169 {
170 string errStr = string("TSimpleServer client died: ") + ttx.what();
171 GlobalOutput(errStr.c_str());
172 }
173 catch (const std::exception& x)
174 {
175 GlobalOutput.printf("TSimpleServer exception: %s: %s",
176 typeid(x).name(), x.what());
177 }
178 catch (...)
179 {
180 GlobalOutput("TSimpleServer uncaught exception.");
181 }
182
183 if (eventHandler_)
184 {
185 eventHandler_->deleteContext(connectionContext, inputProtocol, outputProtocol);
186 }
187
188 try
189 {
190 inputTransport->close();
191 }
192 catch (const TTransportException& ttx)
193 {
194 string errStr = string("TSimpleServer input close failed: ")
195 + ttx.what();
196 GlobalOutput(errStr.c_str());
197 }
198
199 try
200 {
201 outputTransport->close();
202 }
203 catch (const TTransportException& ttx)
204 {
205 string errStr = string("TSimpleServer output close failed: ")
206 + ttx.what();
207 GlobalOutput(errStr.c_str());
208 }
209
210 try
211 {
212 client->close();
213 }
214 catch (const TTransportException& ttx)
215 {
216 string errStr = string("TSimpleServer client close failed: ")
217 + ttx.what();
218 GlobalOutput(errStr.c_str());
219 }
220 }
221
222 if (stop_)
223 {
224 try
225 {
226 serverTransport_->close();
227 }
228 catch (TTransportException& ttx)
229 {
230 string errStr = string("TServerTransport failed on close: ") + ttx.what();
231 GlobalOutput(errStr.c_str());
232 }
233
234 stop_ = false;
235 }
236 }
237
238 }
239 }
240 } // apache::thrift::server
241