2 //=============================================================================
4 * @file SOCK_Send_Recv_Test.cpp
6 * This is a test of the <ACE_SOCK>'s various send and receive
7 * methods. The test forks two processes or spawns two threads
8 * (depending upon the platform) and then executes client and
9 * server allowing them to connect and exchange data in ways
10 * designed to exercise the send and recv functions.
12 * Right now, it primarily tests the iov-like send and recv
13 * functions, but others should be added to completely cover the
16 * @author Steve Huston <shuston@riverace.com>
18 //=============================================================================
21 #include "test_config.h"
22 #include "ace/OS_NS_sys_wait.h"
23 #include "ace/OS_NS_unistd.h"
24 #include "ace/Thread.h"
25 #include "ace/Thread_Manager.h"
26 #include "ace/Time_Value.h"
27 #include "ace/SOCK_Connector.h"
28 #include "ace/SOCK_Acceptor.h"
29 #include "ace/SOCK_Stream.h"
32 // Change to non-zero if test fails
33 static int Test_Result
= 0;
35 #if !defined (ACE_LACKS_FORK) || defined (ACE_HAS_THREADS)
37 // In test 3, a large amount of data is sent. The purpose is to overflow the
38 // TCP send window, causing the sender to block (it's a send_n). This value
39 // is the amount to send. The assumption is that no implementation has a
40 // receive window larger than 128K bytes. If one is found, this is the place
42 // For some odd reason, NT will try to send a single large buffer, but not
43 // multiple smaller ones that add up to the large size.
44 const size_t Test3_Send_Size
= 4*1024;
45 const size_t Test3_Loops
= 10;
46 const size_t Test3_Total_Size
= Test3_Send_Size
* Test3_Loops
;
52 ACE_INET_Addr
*remote_addr
= reinterpret_cast<ACE_INET_Addr
*> (arg
);
53 ACE_INET_Addr
server_addr (remote_addr
->get_port_number (),
55 ACE_SOCK_Stream cli_stream
;
56 ACE_SOCK_Connector con
;
57 ACE_Time_Value
timeout (ACE_DEFAULT_TIMEOUT
);
60 ACE_TEXT ("(%P|%t) Connecting to port %d\n"),
61 server_addr
.get_port_number()));
63 // Initiate connection with server; don't wait forever
64 if (con
.connect (cli_stream
,
69 ACE_TEXT ("(%P|%t) %p\n"),
70 ACE_TEXT ("connection failed")));
76 ACE_TEXT ("(%P|%t) connected to %C\n"),
77 server_addr
.get_host_name ()));
79 //******************* TEST 0 ******************************
81 // First make sure that non-blocking receive works as intended.
82 // Set the socket to non-blocking and do a recv() - the server side
83 // will send a short piece of data after sleeping for a few seconds.
84 // This means we should get a EWOULDBLOCK first; then change to
85 // blocking for the rest of the tests.
91 if (-1 == cli_stream
.enable (ACE_NONBLOCK
))
93 ACE_TEXT ("(%P|%t) %p\n"),
94 ACE_TEXT ("Can't enable test 0 nonblocking")));
96 len
= cli_stream
.recv (buffer
, sizeof (buffer
));
97 cli_stream
.disable (ACE_NONBLOCK
);
100 if (errno
== EWOULDBLOCK
)
101 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("(%P|%t) Nonblocking recv ok!\n")));
104 ACE_ERROR ((LM_ERROR
,
105 ACE_TEXT ("(%P|%t) %p\n"),
106 ACE_TEXT ("Nonblocking recv")));
109 cli_stream
.recv (buffer
, sizeof (buffer
)); // Drain the sent data
113 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("(%P|%t) Nonblocking recv blocked\n")));
117 //******************* TEST 1 ******************************
119 // Do a iovec sendv - send the 255 byte buffer in 5 chunks. The
120 // server will verify that the correct data is sent, and that there
121 // is no more and no less.
123 // The server will verify that this data pattern gets there intact.
125 for (i
= 0; i
< sizeof buffer
; ++i
)
126 buffer
[i
] = static_cast<u_char
> (i
);
130 iov
[0].iov_base
= reinterpret_cast<char *> (&buffer
[0]);
133 iov
[1].iov_base
= reinterpret_cast<char *> (&buffer
[50]);
136 iov
[2].iov_base
= reinterpret_cast<char *> (&buffer
[75]);
137 iov
[2].iov_len
= 150;
139 iov
[3].iov_base
= reinterpret_cast<char *> (&buffer
[225]);
142 iov
[4].iov_base
= reinterpret_cast<char *> (&buffer
[254]);
145 len
= cli_stream
.sendv (iov
, 5);
148 ACE_ERROR ((LM_ERROR
,
149 ACE_TEXT ("(%P|%t) %p\n"),
150 ACE_TEXT ("Test 1, sendv failed")));
154 ACE_ERROR ((LM_ERROR
,
155 ACE_TEXT ("(%P|%t) test 1 recvd %d; should be 255\n"),
156 static_cast<int> (len
)));
158 //******************* TEST 2 ******************************
160 // The same data is coming back - receive it using recv (size_t n,
161 // ...) and compare it to the original data.
164 // Give it a chance to get here
166 #ifndef ACE_LACKS_VA_FUNCTIONS
167 len
= cli_stream
.recv (4,
175 ACE_ERROR ((LM_ERROR
,
176 ACE_TEXT ("(%P|%t) %m; len is %d, but should be 255!\n"),
180 for (i
= 0; i
< 255; i
++)
181 if (buffer2
[i
] != buffer
[i
])
183 ACE_ERROR ((LM_ERROR
,
184 ACE_TEXT ("(%P|%t) Test 2, rcvd byte %d is %d, not %d\n"),
185 i
, buffer2
[i
], buffer
[i
]));
189 //******************* TEST 3 ******************************
191 // Do a send_n of a large size. The receive should sleep some to
192 // cause the data reception to be delayed, which will fill up the
193 // TCP window and cause send_n to block at some point. The particular
194 // case this tests only needs to be exercised if the socket is
195 // non-blocking, so set that first.
197 char buff
[Test3_Send_Size
];
198 if (-1 == cli_stream
.enable (ACE_NONBLOCK
))
199 ACE_ERROR ((LM_ERROR
,
200 ACE_TEXT ("(%P|%t) %p\n"),
201 ACE_TEXT ("Can't enable test 3 nonblocking")));
202 for (i
= 0; i
< Test3_Loops
; ++i
)
205 ssize_t sent
= cli_stream
.send_n (buff
, sizeof (buff
));
206 if (sent
!= (ssize_t
) sizeof (buff
) && errno
!= 0)
208 ACE_ERROR ((LM_ERROR
,
209 ACE_TEXT ("(%P|%t) Test 3, pass %d, sent %d, %p\n"),
210 i
, sent
, ACE_TEXT ("error")));
211 Test_Result
= 1; // Fail
223 ACE_SOCK_Acceptor
*peer_acceptor
= (ACE_SOCK_Acceptor
*) arg
;
224 ACE_SOCK_Stream sock_str
;
225 ACE_INET_Addr cli_addr
;
226 ACE_Time_Value
timeout (ACE_DEFAULT_TIMEOUT
);
228 // Accept the connection over which the stream tests will run.
229 // Don't lock up if client doesn't connect
230 if (peer_acceptor
->accept (sock_str
,
234 ACE_ERROR ((LM_ERROR
,
235 ACE_TEXT ("(%P|%t) %p\n"),
236 ACE_TEXT ("accept")));
241 ACE_DEBUG ((LM_DEBUG
,
242 ACE_TEXT ("(%P|%t) client %C connected from %d\n"),
243 cli_addr
.get_host_name (),
244 cli_addr
.get_port_number ()));
246 //******************* TEST 1 ******************************
248 // The client will be expecting to not see data for a few seconds.
249 // Wait a bit then send a short blurb to complete the client's recv.
252 sock_str
.send ("abc", 3);
254 //******************* TEST 1 ******************************
256 // Do a iovec recvv - the client should send 255 bytes, which we
257 // will be detected and read into a ACE-allocated buffer. Use a 5
258 // second timeout to give the client a chance to send it all.
267 iov
[0].iov_base
= reinterpret_cast<char *> (&buffer
[0]);
270 iov
[1].iov_base
= reinterpret_cast<char *> (&buffer
[75]);
271 iov
[1].iov_len
= 100;
273 iov
[2].iov_base
= reinterpret_cast<char *> (&buffer
[175]);
276 len
= sock_str
.recvv_n (iov
, 3);
279 ACE_ERROR ((LM_ERROR
,
280 ACE_TEXT ("(%P|%t) %p\n"),
281 ACE_TEXT ("Test 1, recvv failed")));
287 ACE_ERROR ((LM_ERROR
,
288 ACE_TEXT ("(%P|%t) Test 1 recvd %d; should be 255\n"),
289 static_cast<int> (len
)));
292 for (i
= 0; i
< 255; i
++)
295 ACE_ERROR ((LM_ERROR
,
296 ACE_TEXT ("(%P|%t) Test 1, rcvd byte %d is %d, not %d\n"),
303 //******************* TEST 2 ******************************
305 // Send the buffer back, using send (size_t n, ...) in 3 pieces.
307 #ifndef ACE_LACKS_VA_FUNCTIONS
308 len
= sock_str
.send (6,
319 ACE_ERROR ((LM_ERROR
,
320 ACE_TEXT ("(%P|%t) Test 2 sent %d; should be 255\n"),
321 static_cast<int> (len
)));
325 //******************* TEST 3 ******************************
327 // The sender is testing send_n to make sure it blocks if the TCP
328 // window fills. So sleep here for a bit to avoid getting the data
329 // yet. Then just read and empty out the received data.
331 // Keep reading until the peer closes.
332 sock_str
.disable (ACE_NONBLOCK
);
334 size_t total_recv
= 0;
338 got
= sock_str
.recv (buffer
, sizeof (buffer
));
344 ACE_DEBUG ((LM_DEBUG
, ACE_TEXT ("(%P|%t) Test 3 received %d bytes\n"),
347 if (total_recv
== Test3_Total_Size
)
349 if (got
!= 0 || errno
!= 0)
351 ACE_ERROR ((LM_ERROR
,
352 ACE_TEXT ("(%P|%t) Test 3 final recv status %d, expected 0\n"),
354 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("(%P|%t) %p\n"),
355 ACE_TEXT ("expected errno == 0, instead")));
356 Test_Result
= 1; // Fail
361 ACE_ERROR ((LM_ERROR
, ACE_TEXT ("(%P|%t) Test 3 expected %d %p\n"),
362 Test3_Total_Size
, ACE_TEXT ("bytes")));
371 #endif /* !ACE_LACKS_FORK || ACE_HAS_THREADS */
377 ACE_SOCK_Acceptor peer_acceptor
;
379 // Create a server address.
380 ACE_INET_Addr server_addr
;
382 // Bind listener to any port and then find out what the port was.
383 if (peer_acceptor
.open (ACE_Addr::sap_any
) == -1
384 || peer_acceptor
.get_local_addr (server_addr
) == -1)
385 ACE_ERROR ((LM_ERROR
,
386 ACE_TEXT ("(%P|%t) %p\n"),
390 ACE_DEBUG ((LM_DEBUG
,
391 ACE_TEXT ("(%P|%t) starting server at port %d\n"),
392 server_addr
.get_port_number ()));
394 #if !defined (ACE_LACKS_FORK)
395 switch (ACE_OS::fork (ACE_TEXT ("child")))
398 ACE_ERROR ((LM_ERROR
,
399 ACE_TEXT ("(%P|%t) %p\n"),
400 ACE_TEXT ("fork failed"),
404 ACE_LOG_MSG
->sync (ACE_TEXT ("SOCK_Send_Recv_Test-child"));
405 client (&server_addr
);
409 server (reinterpret_cast<void *> (&peer_acceptor
));
410 ACE_OS::waitpid (0, 0, 0);
412 #elif defined (ACE_HAS_THREADS)
413 if (ACE_Thread_Manager::instance ()->spawn
414 (ACE_THR_FUNC (server
),
415 reinterpret_cast<void *> (&peer_acceptor
),
416 THR_NEW_LWP
| THR_DETACHED
) == -1)
417 ACE_ERROR ((LM_ERROR
,
418 ACE_TEXT ("(%P|%t) %p\n%a"),
419 ACE_TEXT ("thread create failed"),
422 if (ACE_Thread_Manager::instance ()->spawn
423 (ACE_THR_FUNC (client
),
424 reinterpret_cast<void *> (&server_addr
),
425 THR_NEW_LWP
| THR_DETACHED
) == -1)
426 ACE_ERROR ((LM_ERROR
,
427 ACE_TEXT ("(%P|%t) %p\n%a"),
428 ACE_TEXT ("thread create failed"),
431 // Wait for the threads to exit.
432 ACE_Thread_Manager::instance ()->wait ();
435 ACE_TEXT ("(%P|%t) ")
436 ACE_TEXT ("only one thread may be run ")
437 ACE_TEXT ("in a process on this platform\n")));
438 #endif /* ACE_HAS_THREADS */
440 peer_acceptor
.close ();
445 run_main (int, ACE_TCHAR
*[])
447 ACE_START_TEST (ACE_TEXT ("SOCK_Send_Recv_Test"));
449 #ifndef ACE_LACKS_ACCEPT