1 // This example tests the features of the <ACE_SOCK_Acceptor>,
2 // <ACE_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/OS_main.h"
7 #include "ace/SOCK_Acceptor.h"
8 #include "ace/Svc_Handler.h"
9 #include "ace/Singleton.h"
10 #include "ace/Profile_Timer.h"
11 #include "ace/Get_Opt.h"
12 #include "ace/OS_NS_sys_select.h"
14 #include "CPP-inserver-fancy.h"
17 // Forward declaration.
23 // Creates the oneway or twoway handlers.
32 // Run the main event loop.
35 int init_acceptors ();
36 // Initialize the acceptors.
38 int create_handler (ACE_SOCK_Acceptor
&acceptor
,
39 Handler
*(*handler_factory
) (ACE_HANDLE
),
40 const char *handler_type
);
41 // Factory that creates the right kind of <Handler>.
43 // = Factory functions.
44 static Handler
*make_twoway_handler (ACE_HANDLE
);
45 // Create a twoway handler.
47 static Handler
*make_oneway_handler (ACE_HANDLE
);
48 // Create a oneway handler.
50 ACE_SOCK_Acceptor twoway_acceptor_
;
51 // Twoway acceptor factory.
53 ACE_SOCK_Acceptor oneway_acceptor_
;
54 // Oneway acceptor factory.
57 class Handler
: public ACE_Svc_Handler
<ACE_SOCK_STREAM
, ACE_NULL_SYNCH
>
60 // Base class for the oneway and twoway handlers.
62 friend class Handler_Factory
;
63 // The factory has special permission. (to access svc ()).
66 //FUZZ: disable check_for_lack_ACE_OS
67 virtual int open (void * = 0);
68 // Generic initialization method.
70 virtual int close (u_long
);
71 // Close down and delete this.
72 //FUZZ: enable check_for_lack_ACE_OS
75 Handler (ACE_HANDLE handle
);
78 int parse_header_and_allocate_buffer (char *&buf
,
80 // Implement the generic code that's called from any of the subclass
81 // <run> methods to get the header and the buffer to read the data.
82 // This method factors out common code.
84 virtual int run () = 0;
85 // Hook method called by the <svc> template method to do the actual
86 // protocol. Must be overridden by the subclass.
89 // Template method entry point into the handler task.
91 virtual void print_results ();
95 // Total number of bytes received.
97 size_t message_count_
;
98 // Number of messages received.
100 ACE_Profile_Timer timer_
;
101 // Keeps track of how much time we're using.
104 class Twoway_Handler
: public Handler
107 // Performs the twoway protocol.
109 Twoway_Handler (ACE_HANDLE handle
);
114 // Template Method hook called by <svc>.
117 class Oneway_Handler
: public Handler
121 Oneway_Handler (ACE_HANDLE handle
);
126 // Template Method hook called by <svc>.
128 virtual void print_results ();
129 // Print the results.
133 Options::port () const
139 Options::verbose () const
141 return this->verbose_
;
145 Options::reply_message_len () const
147 return this->reply_message_len_
;
156 port_ (ACE_DEFAULT_SERVER_PORT
),
157 reply_message_len_ (24) // Default to the approximate size of an
158 // GIOP reply message.
163 Options::parse_args (int argc
, ACE_TCHAR
*argv
[])
165 //FUZZ: disable check_for_lack_ACE_OS
166 ACE_Get_Opt
getopt (argc
, argv
, ACE_TEXT("p:r:v"), 1);
168 for (int c
; (c
= getopt ()) != -1; )
169 //FUZZ: enable check_for_lack_ACE_OS
173 this->port_
= ACE_OS::atoi (getopt
.opt_arg ());
176 this->reply_message_len_
= ACE_OS::atoi (getopt
.opt_arg ());
182 ACE_ERROR_RETURN ((LM_ERROR
,
183 "(%P|%t) usage: %n [-p <port>] [-v]"),
190 // Options Singleton.
191 typedef ACE_Singleton
<Options
, ACE_SYNCH_RECURSIVE_MUTEX
> OPTIONS
;
193 Handler::Handler (ACE_HANDLE handle
)
197 this->peer ().set_handle (handle
);
201 Handler::open (void *)
203 ACE_INET_Addr cli_addr
;
205 // Make sure we're not in non-blocking mode.
206 if (this->peer ().disable (ACE_NONBLOCK
) == -1)
207 ACE_ERROR_RETURN ((LM_ERROR
,
212 ACE_DEBUG ((LM_DEBUG
,
213 "(%P|%t) client %s connected from %d on handle %d\n",
214 cli_addr
.get_host_name (),
215 cli_addr
.get_port_number (),
216 this->peer ().get_handle ()));
221 Handler::close (u_long
)
223 ACE_DEBUG ((LM_DEBUG
,
224 "(%P|%t) closing down %x\n",
234 this->timer_
.start ();
236 // Invoke the hook method to run the specific test.
237 int result
= this->run ();
239 this->timer_
.stop ();
241 this->print_results ();
247 Handler::parse_header_and_allocate_buffer (char *&request
,
250 ssize_t result
= this->peer ().recv_n ((void *) len
,
254 ACE_DEBUG ((LM_DEBUG
,
255 "(%P|%t) connected closed\n"));
258 else if (result
== -1 || result
!= sizeof (ACE_INT32
))
259 ACE_ERROR_RETURN ((LM_ERROR
,
266 ACE_NEW_RETURN (request
,
275 Handler::print_results ()
279 Twoway_Handler::Twoway_Handler (ACE_HANDLE handle
)
284 // Function entry point into the twoway server task.
287 Twoway_Handler::run ()
289 // Read data from client (terminate on error).
297 if (parse_header_and_allocate_buffer (request
,
301 // Subtract off the sizeof the length prefix.
302 ssize_t r_bytes
= this->peer ().recv_n (request
,
303 len
- sizeof (ACE_UINT32
));
307 ACE_ERROR ((LM_ERROR
,
312 else if (r_bytes
== 0)
314 ACE_DEBUG ((LM_DEBUG
,
315 "(%P|%t) reached end of input, connection closed by client\n"));
318 else if (OPTIONS::instance ()->verbose ()
319 && ACE::write_n (ACE_STDOUT
,
322 ACE_ERROR ((LM_ERROR
,
327 ssize_t s_bytes
= (ssize_t
) OPTIONS::instance ()->reply_message_len ();
329 // Don't try to send more than is in the request buffer!
330 if (s_bytes
> r_bytes
)
333 if (this->peer ().send_n (request
,
335 ACE_ERROR ((LM_ERROR
,
339 this->total_bytes_
+= size_t (r_bytes
);
340 this->message_count_
++;
350 Oneway_Handler::Oneway_Handler (ACE_HANDLE handle
)
356 Oneway_Handler::print_results ()
358 ACE_Profile_Timer::ACE_Elapsed_Time et
;
359 this->timer_
.elapsed_time (et
);
361 ACE_DEBUG ((LM_DEBUG
,
362 ACE_TEXT ("\t\treal time = %f secs \n\t\tuser time = %f secs \n\t\tsystem time = %f secs\n"),
367 ACE_DEBUG ((LM_DEBUG
,
368 ACE_TEXT ("\t\tmessages = %d\n\t\ttotal bytes = %d\n\t\tmbits/sec = %f\n\t\tusec-per-message = %f\n"),
369 this->message_count_
,
371 (((double) this->total_bytes_
* 8) / et
.real_time
) / (double) (1024 * 1024),
372 ((et
.user_time
+ et
.system_time
) / (double) this->message_count_
) * ACE_ONE_SECOND_IN_USECS
));
375 // Function entry point into the oneway server task.
378 Oneway_Handler::run ()
380 // Read data from client (terminate on error).
388 if (parse_header_and_allocate_buffer (request
,
392 // Subtract off the sizeof the length prefix.
393 ssize_t r_bytes
= this->peer ().recv_n (request
,
394 len
- sizeof (ACE_UINT32
));
398 ACE_ERROR ((LM_ERROR
,
403 else if (r_bytes
== 0)
405 ACE_DEBUG ((LM_DEBUG
,
406 "(%P|%t) reached end of input, connection closed by client\n"));
409 else if (OPTIONS::instance ()->verbose ()
410 && ACE::write_n (ACE_STDOUT
,
413 ACE_ERROR ((LM_ERROR
,
417 this->total_bytes_
+= size_t (r_bytes
);
418 this->message_count_
++;
427 // Create a twoway handler.
430 Handler_Factory::make_twoway_handler (ACE_HANDLE handle
)
432 return new Twoway_Handler (handle
);
435 // Create a oneway handler.
438 Handler_Factory::make_oneway_handler (ACE_HANDLE handle
)
440 return new Oneway_Handler (handle
);
444 Handler_Factory::init_acceptors ()
446 // Create the oneway and twoway server addresses.
447 ACE_INET_Addr
twoway_server_addr (OPTIONS::instance ()->port ());
448 ACE_INET_Addr
oneway_server_addr (OPTIONS::instance ()->port () + 1);
450 // Create acceptors, reuse the address.
451 if (this->twoway_acceptor_
.open (twoway_server_addr
, 1) == -1
452 || this->oneway_acceptor_
.open (oneway_server_addr
, 1) == -1)
453 ACE_ERROR_RETURN ((LM_ERROR
,
457 else if (this->twoway_acceptor_
.get_local_addr (twoway_server_addr
) == -1
458 || this->oneway_acceptor_
.get_local_addr (oneway_server_addr
) == -1)
459 ACE_ERROR_RETURN ((LM_ERROR
,
463 ACE_DEBUG ((LM_DEBUG
,
464 "(%P|%t) starting twoway server at port %d and oneway server at port %d\n",
465 twoway_server_addr
.get_port_number (),
466 oneway_server_addr
.get_port_number ()));
471 Handler_Factory::create_handler (ACE_SOCK_Acceptor
&acceptor
,
472 Handler
* (*handler_factory
) (ACE_HANDLE
),
473 const char *handler_type
)
475 ACE_SOCK_Stream new_stream
;
477 if (acceptor
.accept (new_stream
) == -1)
478 ACE_ERROR_RETURN ((LM_ERROR
,
485 ACE_ALLOCATOR_RETURN (handler
,
486 (*handler_factory
) (new_stream
.get_handle ()),
489 ACE_DEBUG ((LM_DEBUG
,
490 "(%P|%t) spawning %s handler\n",
493 if (handler
->open () == -1)
496 #if defined (ACE_MT_SAFE)
497 // Spawn a new thread and run the new connection in that thread of
498 // control using the <server> function as the entry point.
499 return handler
->activate ();
504 #endif /* ACE_HAS_THREADS */
507 Handler_Factory::Handler_Factory ()
511 Handler_Factory::~Handler_Factory ()
513 this->twoway_acceptor_
.close ();
514 this->oneway_acceptor_
.close ();
517 // Run the main event loop.
520 Handler_Factory::handle_events ()
522 if (this->init_acceptors () == -1)
528 FD_SET ((ACE_SOCKET
) this->twoway_acceptor_
.get_handle (),
530 FD_SET ((ACE_SOCKET
) this->oneway_acceptor_
.get_handle (),
533 // Performs the iterative server activities.
537 ACE_Time_Value
timeout (ACE_DEFAULT_TIMEOUT
);
538 fd_set temp
= handles
;
540 int result
= ACE_OS::select (int (this->oneway_acceptor_
.get_handle ()) + 1,
546 ACE_ERROR ((LM_ERROR
,
549 else if (result
== 0 && OPTIONS::instance ()->verbose ())
550 ACE_DEBUG ((LM_DEBUG
,
551 "(%P|%t) select timed out\n"));
554 if (FD_ISSET ((ACE_SOCKET
) this->twoway_acceptor_
.get_handle (),
556 this->create_handler (this->twoway_acceptor_
,
557 &Handler_Factory::make_twoway_handler
,
559 if (FD_ISSET ((ACE_SOCKET
) this->oneway_acceptor_
.get_handle (),
561 this->create_handler (this->oneway_acceptor_
,
562 &Handler_Factory::make_oneway_handler
,
567 ACE_NOTREACHED (return 0;)
571 ACE_TMAIN (int argc
, ACE_TCHAR
*argv
[])
573 OPTIONS::instance ()->parse_args (argc
, argv
);
575 Handler_Factory server
;
577 return server
.handle_events ();
579 ACE_SINGLETON_TEMPLATE_INSTANTIATE(ACE_Singleton
, Options
, ACE_SYNCH_RECURSIVE_MUTEX
);