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;
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
,
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
,
47 else if (new_stream
->get_remote_addr (cli_addr
) == -1)
48 ACE_ERROR_RETURN ((LM_ERROR
,
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;
63 // Read data from client (terminate on error).
69 ssize_t r_bytes
= new_stream
->recv_n ((void *) &len
,
78 else if (r_bytes
== 0)
81 "(%P|%t) reached end of input, connection closed by client\n"));
84 else if (r_bytes
!= sizeof (ACE_INT32
))
94 ACE_NEW_RETURN (request
,
99 // Subtract off the sizeof the length prefix.
100 r_bytes
= new_stream
->recv_n (request
,
101 len
- sizeof (ACE_UINT32
));
104 ACE_ERROR ((LM_ERROR
,
109 else if (r_bytes
== 0)
111 ACE_DEBUG ((LM_DEBUG
,
112 "(%P|%t) reached end of input, "
113 "connection closed by client\n"));
117 && ACE::write_n (ACE_STDOUT
,
120 ACE_ERROR ((LM_ERROR
,
123 else if (new_stream
->send_n (request
,
125 ACE_ERROR ((LM_ERROR
,
129 total_bytes
+= size_t (r_bytes
);
136 // Close new endpoint (listening endpoint stays open).
137 new_stream
->close ();
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
,
160 else if (new_stream
->get_remote_addr (cli_addr
) == -1)
161 ACE_ERROR_RETURN ((LM_ERROR
,
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 ()));
172 ACE_Profile_Timer timer
;
175 size_t total_bytes
= 0;
176 size_t message_count
= 0;
180 // Read data from client (terminate on error).
186 ssize_t r_bytes
= new_stream
->recv_n ((void *) &len
,
190 ACE_ERROR ((LM_ERROR
,
195 else if (r_bytes
== 0)
197 ACE_DEBUG ((LM_DEBUG
,
198 "(%P|%t) reached end of input, connection closed by client\n"));
201 else if (r_bytes
!= sizeof (ACE_INT32
))
203 ACE_ERROR ((LM_ERROR
,
211 ACE_NEW_RETURN (request
,
216 // Subtract off the sizeof the length prefix.
217 r_bytes
= new_stream
->recv_n (request
,
218 len
- sizeof (ACE_UINT32
));
222 ACE_ERROR ((LM_ERROR
,
227 else if (r_bytes
== 0)
229 ACE_DEBUG ((LM_DEBUG
,
230 "(%P|%t) reached end of input, connection closed by client\n"));
234 && ACE::write_n (ACE_STDOUT
, request
, r_bytes
) != r_bytes
)
235 ACE_ERROR ((LM_ERROR
,
239 total_bytes
+= size_t (r_bytes
);
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"),
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"),
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 ();
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
,
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
,
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.
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,
337 ACE_ERROR ((LM_ERROR
,
340 else if (result
== 0 && verbose
)
341 ACE_DEBUG ((LM_DEBUG
,
342 "(%P|%t) select timed out\n"));
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
,
365 if (twoway_acceptor
.accept (*new_stream
) == -1)
367 ACE_ERROR ((LM_ERROR
,
376 ACE_DEBUG ((LM_DEBUG
,
377 "(%P|%t) spawning twoway server\n"));
379 // Run the twoway server.
380 run_server (twoway_server
,
383 if (temp
.is_set (oneway_acceptor
.get_handle ()))
385 ACE_NEW_RETURN (new_stream
,
389 if (oneway_acceptor
.accept (*new_stream
) == -1)
391 ACE_ERROR ((LM_ERROR
, "%p\n", "accept"));
398 ACE_DEBUG ((LM_DEBUG
,
399 "(%P|%t) spawning oneway server\n"));
401 // Run the oneway server.
402 run_server (oneway_server
,
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
;
422 port
= ACE_OS::atoi (argv
[1]);
424 return run_event_loop (port
);