2 * @file Bug_2740_Regression_Test.cpp
4 * Reproduces the problems reported in bug 2740
5 * http://bugzilla.dre.vanderbilt.edu/show_bug.cgi?id=2740
7 * @author paolo.volpi@tvblob.com
10 #include "test_config.h"
12 #if defined (ACE_HAS_DEV_POLL) || defined (ACE_HAS_EVENT_POLL)
14 #include "ace/Atomic_Op.h"
15 #include "ace/Reactor.h"
16 #include "ace/Dev_Poll_Reactor.h"
17 #include "ace/Connector.h"
18 #include "ace/SOCK_Connector.h"
19 #include "ace/Acceptor.h"
20 #include "ace/SOCK_Acceptor.h"
21 #include "ace/Svc_Handler.h"
22 #include "ace/Signal.h"
23 #include "ace/Time_Value.h"
24 #include "ace/OS_NS_string.h"
26 const ACE_Time_Value
MAX_CLIENT_TIMEOUT(30); // 30 secs
28 // The number of clients we'll run. When the ClientsLeft gets back to 0 (it's
29 // decremented when a ClientSvcHandler is deleted) the event loop can stop.
30 const long NrClients
= 10;
31 static ACE_Atomic_Op
<ACE_Thread_Mutex
, long> ClientsLeft (10);
34 class ClientSvcHandler
: public ACE_Svc_Handler
<ACE_SOCK_STREAM
, ACE_NULL_SYNCH
>
37 // Default ctor needed to satisfy ACE_Connector template, but not used.
39 { ACE_ERROR((LM_ERROR
, ACE_TEXT ("%t: Wrong ClientSvcHandler ctor!!\n"))); }
41 // Each client will send/recv 'echo_cnt' times, close/reopen the socket,
42 // then echo, etc. for ACE_MAX_ITERATIONS times.
43 ClientSvcHandler (const ACE_INET_Addr
&addr
, int echo_cnt
);
44 ~ClientSvcHandler () override
;
46 int open (void* factory
) override
;
47 int handle_input (ACE_HANDLE handle
= ACE_INVALID_HANDLE
) override
;
48 int handle_timeout (const ACE_Time_Value
&now
, const void *act
= 0) override
;
49 int handle_close (ACE_HANDLE handle
= ACE_INVALID_HANDLE
,
50 ACE_Reactor_Mask mask
= 0) override
;
53 static const char *send_str
;
55 ACE_INET_Addr server_addr_
;
56 // Know when we've received 'echo_cnt' echoes of the data. Don't want to
57 // get into record-marking, short-reads/writes, etc. so just count the number
58 // of bytes it takes to echo the data. Don't care about verifying the
59 // content - this is mostly a stress test for multithreaded reactor.
65 const char *ClientSvcHandler::send_str
=
66 "1234567890123456789012345678901234567890";
68 class ServerSvcHandler
: public ACE_Svc_Handler
<ACE_SOCK_STREAM
, ACE_NULL_SYNCH
>
71 int open (void* factory
) override
;
72 int handle_input (ACE_HANDLE handle
= ACE_INVALID_HANDLE
) override
;
73 int handle_close (ACE_HANDLE handle
= ACE_INVALID_HANDLE
,
74 ACE_Reactor_Mask mask
= 0) override
;
78 ClientSvcHandler::ClientSvcHandler (const ACE_INET_Addr
&addr
, int echo_cnt
)
79 : ACE_Svc_Handler
<ACE_SOCK_STREAM
, ACE_NULL_SYNCH
>(),
81 echo_cnt_ (ACE_OS::strlen (ClientSvcHandler::send_str
) * echo_cnt
),
86 ClientSvcHandler::~ClientSvcHandler ()
88 if (--ClientsLeft
== 0)
91 ACE_TEXT ("%t: No more clients; ending reactor loop\n")));
92 this->reactor ()->end_reactor_event_loop ();
97 ClientSvcHandler::open (void* factory
)
100 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("%t: client h %d, open for iteration %B\n"),
101 this->peer ().get_handle (), this->iter_
));
103 if (ACE_Svc_Handler
<ACE_SOCK_STREAM
, ACE_NULL_SYNCH
>::open (factory
) == 0)
105 this->timer_
= this->reactor ()->schedule_timer (this,
109 size_t send_len
= ACE_OS::strlen (ClientSvcHandler::send_str
);
110 if (-1 == this->peer().send_n (ClientSvcHandler::send_str
, send_len
))
111 ACE_ERROR_RETURN ((LM_ERROR
,
112 ACE_TEXT ("%t: client h %d, %p\n"),
113 this->peer ().get_handle(),
119 ACE_ERROR_RETURN ((LM_ERROR
,
120 ACE_TEXT ("%t: %p\n"),
121 ACE_TEXT ("Client open")),
126 ClientSvcHandler::handle_input (ACE_HANDLE handle
)
129 char buffer
[ACE_DEFAULT_MAX_SOCKET_BUFSIZ
];
131 bc
= this->peer ().recv (buffer
, sizeof (buffer
));
132 ACE_DEBUG ((LM_DEBUG
,
133 ACE_TEXT ("%t: client h %d recv %b bytes\n"),
138 // Reset Client timeout timer
139 this->reactor ()->cancel_timer (this->timer_
);
141 // Reduce the echo count by what was received; if not there, send
142 // more data and await more echo.
143 size_t ubc
= (size_t)bc
;
144 if (ubc
<= this->echo_cnt_
)
145 this->echo_cnt_
-= ubc
;
146 if (this->echo_cnt_
== 0)
148 ACE_DEBUG ((LM_DEBUG
,
149 ACE_TEXT ("%t: client h %d end of echo\n"),
154 // Not done yet; send more data and resched timer.
155 size_t send_len
= ACE_OS::strlen (ClientSvcHandler::send_str
);
156 if (-1 == this->peer().send_n (ClientSvcHandler::send_str
, send_len
))
157 ACE_ERROR_RETURN ((LM_ERROR
, ACE_TEXT ("%t: client h %d: %p\n"),
158 ACE_TEXT ("resending")),
160 this->timer_
= reactor ()->schedule_timer (this, 0, MAX_CLIENT_TIMEOUT
);
162 else if (bc
== 0) // Socket was closed by server
164 ACE_ERROR_RETURN ((LM_ERROR
,
165 ACE_TEXT ("%t: client h %d: closed by server\n"),
169 else if (errno
== EWOULDBLOCK
) // no data ready on socket
171 ACE_ERROR_RETURN ((LM_DEBUG
,
172 ACE_TEXT ("%t: client h %d: recv no data\n"),
177 ACE_ERROR_RETURN ((LM_ERROR
,
178 ACE_TEXT ("%t: client h %d: %p\n"),
187 ClientSvcHandler::handle_timeout (const ACE_Time_Value
&, const void*)
189 ACE_DEBUG ((LM_DEBUG
,
190 ACE_TEXT ("%t: client h %d: timeout\n"),
191 this->peer ().get_handle ()));
192 reactor()->remove_handler (this, ACE_Event_Handler::ALL_EVENTS_MASK
);
197 ClientSvcHandler::handle_close (ACE_HANDLE handle
, ACE_Reactor_Mask mask
)
199 ACE_DEBUG ((LM_DEBUG
,
200 ACE_TEXT ("%t: client h %d handle_close\n"),
203 // If not done iterating, just close the socket and reopen the connection.
204 // Else shut down and delete.
205 if (this->iter_
>= ACE_MAX_ITERATIONS
)
206 return ACE_Svc_Handler
<ACE_SOCK_STREAM
, ACE_NULL_SYNCH
>::handle_close(handle
,
209 ClientSvcHandler
*p
= const_cast<ClientSvcHandler
*>(this);
210 ACE_Connector
<ClientSvcHandler
, ACE_SOCK_CONNECTOR
>
211 connector (this->reactor (), ACE_NONBLOCK
);
212 connector
.connect (p
, this->server_addr_
);
217 ServerSvcHandler::open (void* factory
)
219 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("%t: server h %d open\n"),
220 this->peer ().get_handle ()));
222 return ACE_Svc_Handler
<ACE_SOCK_STREAM
, ACE_NULL_SYNCH
>::open (factory
);
226 ServerSvcHandler::handle_input (ACE_HANDLE handle
)
228 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("%t: server h %d input\n"), handle
));
230 // Receive whatever is here and send it back.
231 char buffer
[ACE_DEFAULT_MAX_SOCKET_BUFSIZ
];
233 bc
= this->peer ().recv (buffer
, sizeof (buffer
));
236 ACE_DEBUG ((LM_DEBUG
,
237 ACE_TEXT ("%t: server h %d recv %b bytes\n"),
240 if (-1 == this->peer ().send_n (buffer
, bc
))
241 ACE_ERROR_RETURN ((LM_ERROR
,
242 ACE_TEXT ("%t: server h %d: %p\n"),
243 handle
, ACE_TEXT ("send")),
246 else if (bc
== 0 || errno
== ECONNRESET
) // Socket was closed by client
248 ACE_ERROR_RETURN ((LM_DEBUG
,
249 ACE_TEXT ("%t: server h %d: closed by client\n"),
253 else if (errno
== EWOULDBLOCK
) // no data ready on socket
255 // The reactor shouldn't call back for input if there's no data, so
256 // log an error, but keep running.
257 ACE_ERROR_RETURN ((LM_ERROR
,
258 ACE_TEXT ("%t: server h %d: recv no data\n"),
263 ACE_ERROR_RETURN ((LM_ERROR
, ACE_TEXT ("%t: server h %d: %p\n"),
272 ServerSvcHandler::handle_close(ACE_HANDLE handle
, ACE_Reactor_Mask mask
)
274 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("%t: server h %d: handle_close\n"), handle
));
275 return ACE_Svc_Handler
<ACE_SOCK_STREAM
, ACE_NULL_SYNCH
>::handle_close (handle
,
280 disable_signal (int sigmin
, int sigmax
)
282 #if !defined (ACE_LACKS_UNIX_SIGNALS)
284 if (ACE_OS::sigemptyset (&signal_set
) == - 1)
285 ACE_ERROR ((LM_ERROR
,
286 ACE_TEXT ("Error: (%P|%t):%p\n"),
287 ACE_TEXT ("sigemptyset failed")));
289 for (int i
= sigmin
; i
<= sigmax
; i
++)
290 ACE_OS::sigaddset (&signal_set
, i
);
292 // Put the <signal_set>.
293 # if defined (ACE_LACKS_PTHREAD_THR_SIGSETMASK)
294 // In multi-threaded application this is not POSIX compliant
295 // but let's leave it just in case.
296 if (ACE_OS::sigprocmask (SIG_BLOCK
, &signal_set
, 0) != 0)
298 if (ACE_OS::thr_sigsetmask (SIG_BLOCK
, &signal_set
, 0) != 0)
299 # endif /* ACE_LACKS_PTHREAD_THR_SIGSETMASK */
300 ACE_ERROR_RETURN ((LM_ERROR
,
301 ACE_TEXT ("Error: (%P|%t): %p\n"),
302 ACE_TEXT ("SIG_BLOCK failed")),
305 ACE_UNUSED_ARG (sigmin
);
306 ACE_UNUSED_ARG (sigmax
);
307 #endif /* ACE_LACKS_UNIX_SIGNALS */
313 event_loop(void *arg
)
315 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("%t: Starting reactor event loop\n")));
317 disable_signal (SIGPIPE
, SIGPIPE
);
319 ACE_Reactor
*reactor
= static_cast<ACE_Reactor
*>(arg
);
320 int s
= reactor
->run_reactor_event_loop();
322 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("%t: reactor loop done; status %d\n"), s
));
327 int run_main(int, ACE_TCHAR
*[])
329 ACE_START_TEST (ACE_TEXT ("Bug_2740_Regression_Test"));
331 // Make sure we ignore SIGPIPE
332 disable_signal (SIGPIPE
, SIGPIPE
);
334 ACE_Dev_Poll_Reactor dp_reactor
;
335 dp_reactor
.restart (1); // Restart on EINTR
336 ACE_Reactor
reactor (&dp_reactor
);
338 // Bind acceptor to any port and then find out what the port was.
339 ACE_Acceptor
<ServerSvcHandler
, ACE_SOCK_Acceptor
> acceptor (&reactor
,
341 ACE_SOCK_Acceptor::PEER_ADDR server_addr
;
342 if (acceptor
.open (ACE_sap_any_cast (const ACE_INET_Addr
&), &reactor
) == -1
343 || acceptor
.acceptor ().get_local_addr (server_addr
) == -1)
345 ACE_ERROR_RETURN ((LM_ERROR
,
346 ACE_TEXT ("(%P|%t) %p\n"),
347 ACE_TEXT ("acceptor open")),
351 ACE_DEBUG ((LM_DEBUG
,
352 ACE_TEXT ("(%P|%t) starting server at port %d\n"),
353 server_addr
.get_port_number ()));
355 ACE_Thread_Manager::instance ()->spawn_n (ACE_MAX_THREADS
,
359 ACE_Connector
<ClientSvcHandler
, ACE_SOCK_CONNECTOR
> connector (&reactor
,
361 // Spin up clients to connect and iterate
363 for (i
= 0; i
< NrClients
; ++i
)
365 ClientSvcHandler
*c
= new ClientSvcHandler (server_addr
, i
% 4);
366 connector
.connect(c
, server_addr
);
369 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("%d clients connected\n"), (int)i
));
370 ACE_Thread_Manager::instance ()->wait ();
378 run_main (int, ACE_TCHAR
*[])
380 ACE_START_TEST (ACE_TEXT ("Bug_2740_Regression_Test"));
382 ACE_TEXT ("Dev Poll and Event Poll are not supported ")
383 ACE_TEXT ("on this platform\n")));
388 #endif /* ACE_HAS_DEV_POLL || ACE_HAS_EVENT_POLL */