Merge pull request #2216 from jwillemsen/jwi-cxxversionchecks
[ACE_TAO.git] / ACE / examples / IPC_SAP / SSL_SAP / SSL-server.cpp
blob012ac569d993c001b4a1e2f74e9045b71e112a81
1 // This example tests the features of the <ACE_SSL_SOCK_Acceptor>,
2 // <ACE_SSL_SOCK_Stream>, and <ACE_Svc_Handler> classes. If the platform
3 // supports threads it uses a thread-per-connection concurrency model.
4 // Otherwise, it uses a single-threaded iterative server model.
6 #include "ace/Thread_Manager.h"
7 #include "ace/Handle_Set.h"
8 #include "ace/Profile_Timer.h"
9 #include "ace/OS_NS_sys_select.h"
11 #include "ace/SSL/SSL_SOCK_Acceptor.h"
13 // Are we running verbosely?
14 static bool verbose = false;
16 static void
17 run_server (ACE_THR_FUNC server,
18 ACE_SSL_SOCK_Stream * new_stream)
20 #if defined (ACE_HAS_THREADS)
21 // Spawn a new thread and run the new connection in that thread of
22 // control using the <server> function as the entry point.
23 if (ACE_Thread_Manager::instance ()->spawn (server,
24 (void *) new_stream,
25 THR_DETACHED) == -1)
26 ACE_ERROR ((LM_ERROR,
27 "(%P|%t) %p\n",
28 "spawn"));
29 #else
30 (*server) ((void *) new_stream);
31 #endif /* ACE_HAS_THREADS */
34 // Function entry point into the twoway server task.
35 static ACE_THR_FUNC_RETURN
36 twoway_server (void *arg)
38 ACE_INET_Addr cli_addr;
39 ACE_SSL_SOCK_Stream * new_stream = (ACE_SSL_SOCK_Stream *) arg;
41 // Make sure we're not in non-blocking mode.
42 if (new_stream->disable (ACE_NONBLOCK) == -1)
43 ACE_ERROR_RETURN ((LM_ERROR,
44 "%p\n",
45 "disable"),
46 0);
47 else if (new_stream->get_remote_addr (cli_addr) == -1)
48 ACE_ERROR_RETURN ((LM_ERROR,
49 "%p\n",
50 "get_remote_addr"),
51 0);
53 ACE_DEBUG ((LM_DEBUG,
54 "(%P|%t) client %s connected from %d\n",
55 cli_addr.get_host_name (),
56 cli_addr.get_port_number ()));
58 size_t total_bytes = 0;
59 size_t message_count = 0;
61 char *request = 0;
63 // Read data from client (terminate on error).
65 for (;;)
67 ACE_INT32 len;
69 ssize_t r_bytes = new_stream->recv_n ((void *) &len,
70 sizeof (ACE_INT32));
71 if (r_bytes == -1)
73 ACE_ERROR ((LM_ERROR,
74 "%p\n",
75 "recv"));
76 break;
78 else if (r_bytes == 0)
80 ACE_DEBUG ((LM_DEBUG,
81 "(%P|%t) reached end of input, connection closed by client\n"));
82 break;
84 else if (r_bytes != sizeof (ACE_INT32))
86 ACE_ERROR ((LM_ERROR,
87 "(%P|%t) %p\n",
88 "recv_n failed"));
89 break;
91 else
93 len = ntohl (len);
94 ACE_NEW_RETURN (request,
95 char [len],
96 0);
99 // Subtract off the sizeof the length prefix.
100 r_bytes = new_stream->recv_n (request,
101 len - sizeof (ACE_UINT32));
102 if (r_bytes == -1)
104 ACE_ERROR ((LM_ERROR,
105 "%p\n",
106 "recv"));
107 break;
109 else if (r_bytes == 0)
111 ACE_DEBUG ((LM_DEBUG,
112 "(%P|%t) reached end of input, "
113 "connection closed by client\n"));
114 break;
116 else if (verbose
117 && ACE::write_n (ACE_STDOUT,
118 request,
119 r_bytes) != r_bytes)
120 ACE_ERROR ((LM_ERROR,
121 "%p\n",
122 "ACE::write_n"));
123 else if (new_stream->send_n (request,
124 r_bytes) != r_bytes)
125 ACE_ERROR ((LM_ERROR,
126 "%p\n",
127 "send_n"));
129 total_bytes += size_t (r_bytes);
130 message_count++;
132 delete [] request;
133 request = 0;
136 // Close new endpoint (listening endpoint stays open).
137 new_stream->close ();
139 delete new_stream;
141 delete [] request;
143 return 0;
146 // Function entry point into the oneway server task.
148 static ACE_THR_FUNC_RETURN
149 oneway_server (void *arg)
151 ACE_INET_Addr cli_addr;
152 ACE_SSL_SOCK_Stream * new_stream = (ACE_SSL_SOCK_Stream *) arg;
154 // Make sure we're not in non-blocking mode.
155 if (new_stream->disable (ACE_NONBLOCK) == -1)
156 ACE_ERROR_RETURN ((LM_ERROR,
157 "%p\n",
158 "disable"),
160 else if (new_stream->get_remote_addr (cli_addr) == -1)
161 ACE_ERROR_RETURN ((LM_ERROR,
162 "%p\n",
163 "get_remote_addr"),
166 ACE_DEBUG ((LM_DEBUG,
167 "(%P|%t) client %s connected from %d\n",
168 cli_addr.get_host_name (),
169 cli_addr.get_port_number ()));
171 // Timer business
172 ACE_Profile_Timer timer;
173 timer.start ();
175 size_t total_bytes = 0;
176 size_t message_count = 0;
178 char *request = 0;
180 // Read data from client (terminate on error).
182 for (;;)
184 ACE_INT32 len;
186 ssize_t r_bytes = new_stream->recv_n ((void *) &len,
187 sizeof (ACE_INT32));
188 if (r_bytes == -1)
190 ACE_ERROR ((LM_ERROR,
191 "%p\n",
192 "recv"));
193 break;
195 else if (r_bytes == 0)
197 ACE_DEBUG ((LM_DEBUG,
198 "(%P|%t) reached end of input, connection closed by client\n"));
199 break;
201 else if (r_bytes != sizeof (ACE_INT32))
203 ACE_ERROR ((LM_ERROR,
204 "(%P|%t) %p\n",
205 "recv_n failed"));
206 break;
208 else
210 len = ntohl (len);
211 ACE_NEW_RETURN (request,
212 char [len],
216 // Subtract off the sizeof the length prefix.
217 r_bytes = new_stream->recv_n (request,
218 len - sizeof (ACE_UINT32));
220 if (r_bytes == -1)
222 ACE_ERROR ((LM_ERROR,
223 "%p\n",
224 "recv"));
225 break;
227 else if (r_bytes == 0)
229 ACE_DEBUG ((LM_DEBUG,
230 "(%P|%t) reached end of input, connection closed by client\n"));
231 break;
233 else if (verbose
234 && ACE::write_n (ACE_STDOUT, request, r_bytes) != r_bytes)
235 ACE_ERROR ((LM_ERROR,
236 "%p\n",
237 "ACE::write_n"));
239 total_bytes += size_t (r_bytes);
240 message_count++;
242 delete [] request;
243 request = 0;
246 timer.stop ();
248 ACE_Profile_Timer::ACE_Elapsed_Time et;
249 timer.elapsed_time (et);
251 ACE_DEBUG ((LM_DEBUG,
252 ACE_TEXT ("\t\treal time = %f secs\n")
253 ACE_TEXT ("\t\tuser time = %f secs\n")
254 ACE_TEXT ("\t\tsystem time = %f secs\n"),
255 et.real_time,
256 et.user_time,
257 et.system_time));
259 double messages_per_sec = double (message_count) / et.real_time;
261 ACE_DEBUG ((LM_DEBUG,
262 ACE_TEXT ("\t\tmessages = %d\n")
263 ACE_TEXT ("\t\ttotal bytes = %d\n")
264 ACE_TEXT ("\t\tmbits/sec = %f\n")
265 ACE_TEXT ("\t\tusec-per-message = %f\n")
266 ACE_TEXT ("\t\tmessages-per-second = %0.00f\n"),
267 message_count,
268 total_bytes,
269 (((double) total_bytes * 8) / et.real_time) / (double) (1024 * 1024),
270 (et.real_time / (double) message_count) * 1000000,
271 messages_per_sec < 0 ? 0 : messages_per_sec));
273 // Close new endpoint (listening endpoint stays open).
274 new_stream->close ();
276 delete new_stream;
278 delete [] request;
280 return 0;
283 static int
284 run_event_loop (u_short port)
286 // Raise the socket handle limit to the maximum.
287 ACE::set_handle_limit ();
289 // Create the oneway and twoway acceptors.
290 ACE_SSL_SOCK_Acceptor twoway_acceptor;
291 ACE_SSL_SOCK_Acceptor oneway_acceptor;
293 // Create the oneway and twoway server addresses.
294 ACE_INET_Addr twoway_server_addr (port);
295 ACE_INET_Addr oneway_server_addr (port + 1);
297 // Create acceptors, reuse the address.
298 if (twoway_acceptor.open (twoway_server_addr, 1) == -1
299 || oneway_acceptor.open (oneway_server_addr, 1) == -1)
300 ACE_ERROR_RETURN ((LM_ERROR,
301 "%p\n",
302 "open"),
304 else if (twoway_acceptor.get_local_addr (twoway_server_addr) == -1
305 || oneway_acceptor.get_local_addr (oneway_server_addr) == -1)
306 ACE_ERROR_RETURN ((LM_ERROR,
307 "%p\n",
308 "get_local_addr"),
311 ACE_DEBUG ((LM_DEBUG,
312 "(%P|%t) starting twoway server at port %d and oneway server at port %d\n",
313 twoway_server_addr.get_port_number (),
314 oneway_server_addr.get_port_number ()));
316 // Keep these objects out here to prevent excessive constructor
317 // calls within the loop.
319 ACE_Handle_Set handle_set;
320 handle_set.set_bit (twoway_acceptor.get_handle ());
321 handle_set.set_bit (oneway_acceptor.get_handle ());
323 ACE_SSL_SOCK_Stream * new_stream = 0;
325 // Performs the iterative server activities.
326 for (;;)
328 ACE_Time_Value timeout (ACE_DEFAULT_TIMEOUT);
329 ACE_Handle_Set temp = handle_set;
331 int result = ACE_OS::select (int (oneway_acceptor.get_handle ()) + 1,
332 (fd_set *) temp,
335 timeout);
336 if (result == -1)
337 ACE_ERROR ((LM_ERROR,
338 "(%P|%t) %p\n",
339 "select"));
340 else if (result == 0 && verbose)
341 ACE_DEBUG ((LM_DEBUG,
342 "(%P|%t) select timed out\n"));
343 else
345 // A new ACE_SSL_SOCK_Stream must be initialized for each
346 // connection. However, it retains (SSL) state so simply
347 // initializing a new ACE_SSL_SOCK_Stream by passing it a
348 // handle isn't enough, nor is it allowed. Such a scheme is
349 // is sometimes done with the non-SSL aware
350 // ACE_SOCK_Stream. An ACE_SSL_SOCK_Stream should only be
351 // initialized by an ACE_SSL_SOCK_Acceptor (server side), or an
352 // ACE_SSL_SOCK_Connector (client side).
354 // It is also possible to copy or assign an
355 // ACE_SSL_SOCK_Stream since it implements both
356 // methods/operators. However, the user must ensure that
357 // the copy or assignment is atomic.
359 if (temp.is_set (twoway_acceptor.get_handle ()))
361 ACE_NEW_RETURN (new_stream,
362 ACE_SSL_SOCK_Stream,
363 -1);
365 if (twoway_acceptor.accept (*new_stream) == -1)
367 ACE_ERROR ((LM_ERROR,
368 "%p\n",
369 "accept"));
371 delete new_stream;
373 continue;
375 else
376 ACE_DEBUG ((LM_DEBUG,
377 "(%P|%t) spawning twoway server\n"));
379 // Run the twoway server.
380 run_server (twoway_server,
381 new_stream);
383 if (temp.is_set (oneway_acceptor.get_handle ()))
385 ACE_NEW_RETURN (new_stream,
386 ACE_SSL_SOCK_Stream,
387 -1);
389 if (oneway_acceptor.accept (*new_stream) == -1)
391 ACE_ERROR ((LM_ERROR, "%p\n", "accept"));
393 delete new_stream;
395 continue;
397 else
398 ACE_DEBUG ((LM_DEBUG,
399 "(%P|%t) spawning oneway server\n"));
401 // Run the oneway server.
402 run_server (oneway_server,
403 new_stream);
408 /* NOTREACHED */
412 ACE_TMAIN (int argc, ACE_TCHAR *argv[])
414 ACE_SSL_Context *context = ACE_SSL_Context::instance ();
416 context->certificate ("./dummy.pem", SSL_FILETYPE_PEM);
417 context->private_key ("./key.pem", SSL_FILETYPE_PEM);
419 u_short port = ACE_DEFAULT_SERVER_PORT;
421 if (argc > 1)
422 port = ACE_OS::atoi (argv[1]);
424 return run_event_loop (port);