2 //=============================================================================
4 * @file SOCK_Connector_Test.cpp
6 * This is a test of ACE_SOCK_Connector, focusing on failure cases more
7 * than on success cases.
9 * @author Steve Huston <shuston@riverace.com>
11 //=============================================================================
14 #include "test_config.h"
15 #include "ace/OS_NS_string.h"
16 #include "ace/INET_Addr.h"
17 #include "ace/SOCK_Connector.h"
18 #include "ace/Time_Value.h"
19 #include "ace/SOCK_Stream.h"
20 #include "ace/OS_NS_sys_utsname.h"
21 #include "ace/OS_NS_netdb.h"
23 #if defined(ACE_LACKS_GETHOSTENT) || defined(ACE_LACKS_SETHOSTENT) || defined(ACE_LACKS_ENDHOSTENT)
24 # define MISSING_HOSTENT_FUNCTIONS
27 // Host candidate list
30 ACE_TCHAR host_name
[MAXHOSTNAMELEN
];
33 const int MAX_CANDIDATES
= 50;
34 Host_Candidate candidate
[MAX_CANDIDATES
];
36 #ifndef MISSING_HOSTENT_FUNCTIONS
37 // Determine if a host exists, is reachable, and is up. Attempt a
38 // blocking connection to it; if it succeeds, then the host exists, is
39 // reachable, and is up.
42 host_is_up (ACE_TCHAR hostname
[])
44 ACE_SOCK_Connector con
;
47 // The ACE_INET_Addr construction causes gethostbyname_r to be
48 // called, so we need to copy the hostname.
49 ACE_TCHAR test_host
[MAXHOSTNAMELEN
];
50 ACE_OS::strcpy (test_host
, hostname
);
52 ACE_INET_Addr
another_host ((u_short
) 7, test_host
);
53 ACE_Time_Value
timeout_value (5);
54 int const status
= con
.connect (sock
,
58 return status
== 0 ? 1 : 0;
60 #endif /* ! ACE_LACKS_GETHOSTENT */
62 // The original problem this program tested for was incorrectly saying
63 // a non-blocking connect completed successfully when it didn't. The
64 // test doesn't always work when done to localhost
65 // (platform-dependant) so we look around for another host - any other
69 find_another_host (ACE_TCHAR other_host
[])
71 static ACE_TCHAR cached_other_host
[MAXHOSTNAMELEN
] = {'\0'};
73 if (cached_other_host
[0] == '\0')
76 ACE_OS::strcpy (other_host
,
77 ACE_DEFAULT_SERVER_HOST
); // If all else fails
79 #ifndef MISSING_HOSTENT_FUNCTIONS
80 // These gethost-type things don't work everywhere.
81 struct hostent
*h
= 0;
86 h
= ACE_OS::gethostbyname (un
.nodename
);
89 ACE_OS::strcpy (other_host
, ACE_LOCALHOST
);
91 // Use me if can't find another
92 ACE_OS::strcpy (other_host
, ACE_TEXT_CHAR_TO_TCHAR (h
->h_name
));
94 // @@ We really need to add wrappers for these hostent methods.
96 // Optimize for sequential access of DNS or hosts file.
99 int candidate_count
= 0;
101 // Accumulate candidates first. There is some interaction on
102 // Linux systems between <gethostent> and <gethostbyname_r>
103 // (called by ACE_INET_Addr in host_is_up) This otherwise causes
104 // an infinite loop on Linux --mas 03-08-2001
105 while ((h
= gethostent ()) != 0)
107 if (ACE_OS::strcmp (h
->h_name
,
108 ACE_TEXT_ALWAYS_CHAR (ACE_DEFAULT_SERVER_HOST
)) == 0)
110 // AIX just _has_ to be different
111 if (ACE_OS::strcmp (h
->h_name
, "loopback") == 0)
116 (h
->h_name
, ACE_TEXT_ALWAYS_CHAR (other_host
)) != 0
117 && ACE_OS::strcmp (h
->h_name
, un
.nodename
) != 0)
119 ACE_OS::strcpy (candidate
[candidate_count
].host_name
,
120 ACE_TEXT_CHAR_TO_TCHAR (h
->h_name
));
121 if (++candidate_count
>= MAX_CANDIDATES
)
126 // Now try to connect to candidates
127 for (int i
= 0; i
< candidate_count
; i
++)
128 if (host_is_up (candidate
[i
].host_name
))
130 ACE_OS::strcpy (other_host
, candidate
[i
].host_name
);
136 #endif /* ! ACE_LACKS_GETHOSTENT */
138 ACE_OS::strcpy (cached_other_host
, other_host
);
141 ACE_OS::strcpy (other_host
, cached_other_host
);
145 fail_no_listener_nonblocking (void)
147 ACE_TCHAR test_host
[MAXHOSTNAMELEN
], test_addr
[MAXHOSTNAMELEN
+ 8];
149 ACE_INET_Addr nobody_home
;
150 ACE_SOCK_Connector con
;
151 ACE_SOCK_Stream sock
;
152 ACE_Time_Value
nonblock (0, 0);
154 find_another_host (test_host
);
155 if (nobody_home
.set ((u_short
) 42000, test_host
) == -1)
157 ACE_ERROR ((LM_ERROR
,
158 ACE_TEXT ("Host lookup for %s %p\n"),
160 ACE_TEXT ("failed")));
163 nobody_home
.addr_to_string (test_addr
, MAXHOSTNAMELEN
+ 8);
164 ACE_DEBUG ((LM_DEBUG
,
165 ACE_TEXT ("Testing to host \"%s\" (%s)\n"),
166 test_host
, test_addr
));
168 status
= con
.connect (sock
, nobody_home
, &nonblock
);
170 // Need a port that will fail.
173 ACE_ERROR ((LM_ERROR
,
174 ACE_TEXT ("Connect which should fail didn't\n")));
178 // On some systems, a failed connect to localhost will return
179 // ECONNREFUSED or ENETUNREACH directly, instead of
180 // EWOULDBLOCK. That is also fine.
182 else if (errno
== EWOULDBLOCK
||
183 errno
== ECONNREFUSED
||
184 errno
== ENETUNREACH
)
186 if (sock
.get_handle () != ACE_INVALID_HANDLE
)
187 status
= con
.complete (sock
);
191 ACE_ERROR ((LM_ERROR
,
192 ACE_TEXT ("Connect which should fail didn't\n")));
197 ACE_DEBUG ((LM_DEBUG
,
199 ACE_TEXT ("Proper fail")));
205 ACE_DEBUG ((LM_WARNING
,
206 ACE_TEXT ("Test not executed fully; ")
207 ACE_TEXT ("expected EWOULDBLOCK, %p (%d)\n"),
208 ACE_TEXT ("not"), ACE_ERRNO_GET
));
219 // This test tries to hit a port that's listening. Echo (7) is pretty
220 // popular. Just in case, though, it won't report a failure if it
221 // gets "refused" (no listener) since the real fixed bug this is
222 // testing is a returned error of EWOULDBLOCK when the connect really
223 // did work. That was a side-affect of how
224 // <ACE::handle_timed_complete> does checks on some systems.
227 succeed_nonblocking (void)
229 ACE_TCHAR test_host
[MAXHOSTNAMELEN
], test_addr
[MAXHOSTNAMELEN
+ 8];
231 ACE_INET_Addr echo_server
;
232 ACE_SOCK_Connector con
;
233 ACE_SOCK_Stream sock
;
234 ACE_Time_Value
nonblock (0, 0);
235 u_short test_port
= 7; // Echo
237 find_another_host (test_host
);
238 if (ACE_OS::strcmp (ACE_TEXT ("localhost"), test_host
) == 0)
240 #if defined (ACE_WIN32)
241 test_port
= 80; // Echo not available on Win32; try web server
242 #endif /* ACE_WIN32 */
244 if (echo_server
.set (test_port
, test_host
) == -1)
246 ACE_ERROR ((LM_ERROR
,
247 ACE_TEXT ("Host lookup for %s %p\n"),
249 ACE_TEXT ("failed")));
252 echo_server
.addr_to_string (test_addr
, MAXHOSTNAMELEN
+ 8);
253 ACE_DEBUG ((LM_DEBUG
,
254 ACE_TEXT ("Testing to host \"%s\", port %d (%s)\n"),
255 test_host
, test_port
, test_addr
));
256 status
= con
.connect (sock
, echo_server
, &nonblock
);
258 // Need to test the call to 'complete' really.
259 if (status
== 0 || (status
== -1 && errno
!= EWOULDBLOCK
))
261 ACE_DEBUG((LM_WARNING
,
262 ACE_TEXT ("Immediate success/fail; test not completed\n")));
267 if (sock
.get_handle () != ACE_INVALID_HANDLE
)
269 status
= con
.complete (sock
);
274 // Reset the status _before_ doing the printout, in case the
275 // printout overwrites errno.
276 if (errno
== ECONNREFUSED
)
279 ACE_DEBUG ((LM_DEBUG
,
280 ACE_TEXT ("Should succeed, but refused: ok\n")));
284 ACE_ERROR ((LM_ERROR
,
285 ACE_TEXT("Errno <%d>: %p\n"),
287 ACE_TEXT("connect should succeed, but")));
292 ACE_TEXT("Connect which should succeed, did\n")));
302 run_main (int, ACE_TCHAR
*[])
304 ACE_START_TEST (ACE_TEXT ("SOCK_Connector_Test"));
308 if (fail_no_listener_nonblocking () == -1)
311 if (succeed_nonblocking () == -1)