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