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