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