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