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 <glib-object.h>
21 #include <signal.h>
22 #include <stdio.h>
23 #include <string.h>
24
25 #include <thrift/c_glib/thrift.h>
26 #include <thrift/c_glib/processor/thrift_multiplexed_processor.h>
27 #include <thrift/c_glib/protocol/thrift_binary_protocol_factory.h>
28 #include <thrift/c_glib/protocol/thrift_compact_protocol_factory.h>
29 #include <thrift/c_glib/server/thrift_server.h>
30 #include <thrift/c_glib/server/thrift_simple_server.h>
31 #include <thrift/c_glib/transport/thrift_buffered_transport.h>
32 #include <thrift/c_glib/transport/thrift_buffered_transport_factory.h>
33 #include <thrift/c_glib/transport/thrift_framed_transport.h>
34 #include <thrift/c_glib/transport/thrift_framed_transport_factory.h>
35 #include <thrift/c_glib/transport/thrift_server_socket.h>
36 #include <thrift/c_glib/transport/thrift_server_transport.h>
37 #include <thrift/c_glib/transport/thrift_transport.h>
38 #include <thrift/c_glib/transport/thrift_transport_factory.h>
39
40 #include "../gen-c_glib/t_test_thrift_test.h"
41 #include "../gen-c_glib/t_test_second_service.h"
42
43 #include "thrift_test_handler.h"
44 #include "thrift_second_service_handler.h"
45
46 /* Our server object, declared globally so it is accessible within the SIGINT
47 signal handler */
48 ThriftServer *server = NULL;
49
50 /* A flag that indicates whether the server was interrupted with SIGINT
51 (i.e. Ctrl-C) so we can tell whether its termination was abnormal */
52 gboolean sigint_received = FALSE;
53
54 /* Handle SIGINT ("Ctrl-C") signals by gracefully stopping the server */
55 static void
sigint_handler(int signal_number)56 sigint_handler (int signal_number)
57 {
58 THRIFT_UNUSED_VAR (signal_number);
59
60 /* Take note we were called */
61 sigint_received = TRUE;
62
63 /* Shut down the server gracefully */
64 if (server != NULL)
65 thrift_server_stop (server);
66 }
67
68 int
main(int argc,char ** argv)69 main (int argc, char **argv)
70 {
71 static gint port = 9090;
72 static gchar *server_type_option = NULL;
73 static gchar *transport_option = NULL;
74 static gchar *protocol_option = NULL;
75 static gint string_limit = 0;
76 static gint container_limit = 0;
77
78 static
79 GOptionEntry option_entries[] = {
80 { "port", 0, 0, G_OPTION_ARG_INT, &port,
81 "Port number to connect (=9090)", NULL },
82 { "server-type", 0, 0, G_OPTION_ARG_STRING, &server_type_option,
83 "Type of server: simple (=simple)", NULL },
84 { "transport", 0, 0, G_OPTION_ARG_STRING, &transport_option,
85 "Transport: buffered, framed (=buffered)", NULL },
86 { "protocol", 0, 0, G_OPTION_ARG_STRING, &protocol_option,
87 "Protocol: binary, compact (=binary)", NULL },
88 { "string-limit", 0, 0, G_OPTION_ARG_INT, &string_limit,
89 "Max string length (=none)", NULL },
90 { "container-limit", 0, 0, G_OPTION_ARG_INT, &container_limit,
91 "Max container length (=none)", NULL },
92 { NULL }
93 };
94
95 gchar *server_name = "simple";
96 gchar *transport_name = "buffered";
97 GType transport_factory_type = THRIFT_TYPE_BUFFERED_TRANSPORT_FACTORY;
98 gchar *protocol_name = "binary";
99 GType protocol_factory_type = THRIFT_TYPE_BINARY_PROTOCOL_FACTORY;
100
101 TTestThriftTestHandler *handler;
102 TTestThriftTestHandler *handler_second_service = NULL;
103 ThriftProcessor *processor;
104 ThriftProcessor *processor_test = NULL;
105 ThriftProcessor *processor_second_service = NULL;
106 ThriftServerTransport *server_transport;
107 ThriftTransportFactory *transport_factory;
108 ThriftProtocolFactory *protocol_factory;
109
110 struct sigaction sigint_action;
111
112 GOptionContext *option_context;
113 gboolean options_valid = TRUE;
114
115 GError *error = NULL;
116
117 #if (!GLIB_CHECK_VERSION (2, 36, 0))
118 g_type_init ();
119 #endif
120
121 /* Configure and parse our command-line options */
122 option_context = g_option_context_new (NULL);
123 g_option_context_add_main_entries (option_context,
124 option_entries,
125 NULL);
126 if (g_option_context_parse (option_context,
127 &argc,
128 &argv,
129 &error) == FALSE) {
130 fprintf (stderr, "%s\n", error->message);
131 return 255;
132 }
133 g_option_context_free (option_context);
134
135 /* Validate the parsed options */
136 if (server_type_option != NULL &&
137 strncmp (server_type_option, "simple", 7) != 0) {
138 fprintf (stderr, "Unknown server type %s\n", protocol_option);
139 options_valid = FALSE;
140 }
141
142 if (protocol_option != NULL) {
143 if (strncmp (protocol_option, "compact", 8) == 0) {
144 protocol_factory_type = THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY;
145 protocol_name = "compact";
146 }
147 else if (strncmp (protocol_option, "multi", 6) == 0) {
148 protocol_name = "binary:multi";
149 }
150 else if (strncmp (protocol_option, "multic", 7) == 0) {
151 protocol_factory_type = THRIFT_TYPE_COMPACT_PROTOCOL_FACTORY;
152 protocol_name = "compact:multic";
153 }
154 else if (strncmp (protocol_option, "binary", 7) != 0) {
155 fprintf (stderr, "Unknown protocol type %s\n", protocol_option);
156 options_valid = FALSE;
157 }
158 }
159
160 if (transport_option != NULL) {
161 if (strncmp (transport_option, "framed", 7) == 0) {
162 transport_factory_type = THRIFT_TYPE_FRAMED_TRANSPORT_FACTORY;
163 transport_name = "framed";
164 }
165 else if (strncmp (transport_option, "buffered", 9) != 0) {
166 fprintf (stderr, "Unknown transport type %s\n", transport_option);
167 options_valid = FALSE;
168 }
169 }
170
171 if (!options_valid)
172 return 254;
173
174 /* Establish all our connection objects */
175 handler = g_object_new (TYPE_THRIFT_TEST_HANDLER,
176 NULL);
177
178
179
180 if(strstr(protocol_name, ":multi")){
181 /* When a multiplexed processor is involved the handler is not
182 registered as usual. We create the processor and the real
183 processor is registered. Multiple processors can be registered
184 at once. This is why we don't have a constructor property */
185 processor = g_object_new (THRIFT_TYPE_MULTIPLEXED_PROCESSOR,
186 NULL);
187
188 handler_second_service = g_object_new (TYPE_SECOND_SERVICE_HANDLER,
189 NULL);
190
191 processor_test = g_object_new (T_TEST_TYPE_THRIFT_TEST_PROCESSOR,
192 "handler", handler,
193 NULL);
194 processor_second_service = g_object_new (T_TEST_TYPE_SECOND_SERVICE_PROCESSOR,
195 "handler", handler_second_service,
196 NULL);
197
198 /* We register a test processor with Multiplexed name ThriftTest */
199 if(!thrift_multiplexed_processor_register_processor(processor,
200 "ThriftTest", processor_test,
201 &error)){
202 g_message ("thrift_server_serve: %s",
203 error != NULL ? error->message : "(null)");
204 g_clear_error (&error);
205 }
206 /* We register a second test processor with Multiplexed name SecondService
207 * we are responsible of freeing the processor when it's not used anymore */
208 if(!thrift_multiplexed_processor_register_processor(processor,
209 "SecondService", processor_second_service,
210 &error)){
211 g_message ("thrift_server_serve: %s",
212 error != NULL ? error->message : "(null)");
213 g_clear_error (&error);
214 }
215
216 }else{
217 processor = g_object_new (T_TEST_TYPE_THRIFT_TEST_PROCESSOR,
218 "handler", handler,
219 NULL);
220 }
221 server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
222 "port", port,
223 NULL);
224 transport_factory = g_object_new (transport_factory_type,
225 NULL);
226
227 if (strstr (protocol_name, "compact") != NULL) {
228 protocol_factory = g_object_new (protocol_factory_type,
229 "string_limit", string_limit,
230 "container_limit", container_limit,
231 NULL);
232 } else {
233 protocol_factory = g_object_new (protocol_factory_type,
234 NULL);
235 }
236
237 server = g_object_new (THRIFT_TYPE_SIMPLE_SERVER,
238 "processor", processor,
239 "server_transport", server_transport,
240 "input_transport_factory", transport_factory,
241 "output_transport_factory", transport_factory,
242 "input_protocol_factory", protocol_factory,
243 "output_protocol_factory", protocol_factory,
244 NULL);
245
246 /* Install our SIGINT handler, which handles Ctrl-C being pressed by stopping
247 the server gracefully */
248 memset (&sigint_action, 0, sizeof (sigint_action));
249 sigint_action.sa_handler = sigint_handler;
250 sigint_action.sa_flags = SA_RESETHAND;
251 sigaction (SIGINT, &sigint_action, NULL);
252
253 printf ("Starting \"%s\" server (%s/%s) listen on: %d\n",
254 server_name,
255 transport_name,
256 protocol_name,
257 port);
258 fflush (stdout);
259
260 /* Serve clients until SIGINT is received (Ctrl-C is pressed) */
261 thrift_server_serve (server, &error);
262
263 /* If the server stopped for any reason other than being interrupted by the
264 user, report the error */
265 if (!sigint_received) {
266 g_message ("thrift_server_serve: %s",
267 error != NULL ? error->message : "(null)");
268 g_clear_error (&error);
269 }
270
271 puts ("done.");
272
273 g_object_unref (server);
274 g_object_unref (protocol_factory);
275 g_object_unref (transport_factory);
276 g_object_unref (server_transport);
277 g_object_unref (processor);
278 g_object_unref (handler);
279 if(handler_second_service){
280 g_object_unref (handler_second_service);
281 }
282 if(processor_test){
283 g_object_unref (processor_test);
284 }
285 if(processor_second_service){
286 g_object_unref (processor_second_service);
287 }
288
289 return 0;
290 }
291