Make x.0.10 publicly available
[ACE_TAO.git] / ACE / tests / SOCK_Connector_Test.cpp
blob40296f00f84fda27a889351f39c3bd47f2c8e50b
2 //=============================================================================
3 /**
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
25 #endif
27 // Host candidate list
28 struct Host_Candidate
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.
41 static u_int
42 host_is_up (ACE_TCHAR hostname[])
44 ACE_SOCK_Connector con;
45 ACE_SOCK_Stream sock;
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,
55 another_host,
56 &timeout_value);
57 sock.close ();
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-dependent) so we look around for another host - any other
66 // one will do.
68 static void
69 find_another_host (ACE_TCHAR other_host[])
71 static ACE_TCHAR cached_other_host[MAXHOSTNAMELEN] = {'\0'};
73 if (cached_other_host[0] == '\0')
75 ACE_OS::strcpy (other_host,
76 ACE_DEFAULT_SERVER_HOST); // If all else fails
78 #ifndef MISSING_HOSTENT_FUNCTIONS
79 // These gethost-type things don't work everywhere.
80 struct hostent *h = 0;
81 ACE_utsname un;
83 ACE_OS::uname (&un);
85 h = ACE_OS::gethostbyname (un.nodename);
87 if (h == 0)
88 ACE_OS::strcpy (other_host, ACE_LOCALHOST);
89 else
90 // Use me if can't find another
91 ACE_OS::strcpy (other_host, ACE_TEXT_CHAR_TO_TCHAR (h->h_name));
93 // @@ We really need to add wrappers for these hostent methods.
95 // Optimize for sequential access of DNS or hosts file.
96 sethostent (1);
98 int candidate_count = 0;
100 // Accumulate candidates first. There is some interaction on
101 // Linux systems between <gethostent> and <gethostbyname_r>
102 // (called by ACE_INET_Addr in host_is_up) This otherwise causes
103 // an infinite loop on Linux --mas 03-08-2001
104 while ((h = gethostent ()) != 0)
106 if (ACE_OS::strcmp (h->h_name,
107 ACE_TEXT_ALWAYS_CHAR (ACE_DEFAULT_SERVER_HOST)) == 0)
108 continue;
109 // AIX just _has_ to be different
110 if (ACE_OS::strcmp (h->h_name, "loopback") == 0)
111 continue;
113 // If not me.
114 if (ACE_OS::strcmp
115 (h->h_name, ACE_TEXT_ALWAYS_CHAR (other_host)) != 0
116 && ACE_OS::strcmp (h->h_name, un.nodename) != 0)
118 ACE_OS::strcpy (candidate[candidate_count].host_name,
119 ACE_TEXT_CHAR_TO_TCHAR (h->h_name));
120 if (++candidate_count >= MAX_CANDIDATES)
121 break;
125 // Now try to connect to candidates
126 for (int i = 0; i < candidate_count; i++)
127 if (host_is_up (candidate[i].host_name))
129 ACE_OS::strcpy (other_host, candidate[i].host_name);
130 break;
133 sethostent (0);
134 endhostent ();
135 #endif /* ! ACE_LACKS_GETHOSTENT */
137 ACE_OS::strcpy (cached_other_host, other_host);
139 else
140 ACE_OS::strcpy (other_host, cached_other_host);
143 static int
144 fail_no_listener_nonblocking ()
146 ACE_TCHAR test_host[MAXHOSTNAMELEN], test_addr[MAXHOSTNAMELEN + 8];
147 int status;
148 ACE_INET_Addr nobody_home;
149 ACE_SOCK_Connector con;
150 ACE_SOCK_Stream sock;
151 ACE_Time_Value nonblock (0, 0);
153 find_another_host (test_host);
154 if (nobody_home.set ((u_short) 42000, test_host) == -1)
156 ACE_ERROR ((LM_ERROR,
157 ACE_TEXT ("Host lookup for %s %p\n"),
158 test_host,
159 ACE_TEXT ("failed")));
160 return -1;
162 nobody_home.addr_to_string (test_addr, MAXHOSTNAMELEN + 8);
163 ACE_DEBUG ((LM_DEBUG,
164 ACE_TEXT ("Testing to host \"%s\" (%s)\n"),
165 test_host, test_addr));
167 status = con.connect (sock, nobody_home, &nonblock);
169 // Need a port that will fail.
170 if (status == 0)
172 ACE_ERROR ((LM_ERROR,
173 ACE_TEXT ("Connect which should fail didn't\n")));
174 status = -1;
177 // On some systems, a failed connect to localhost will return
178 // ECONNREFUSED or ENETUNREACH directly, instead of
179 // EWOULDBLOCK. That is also fine.
181 else if (errno == EWOULDBLOCK ||
182 errno == ECONNREFUSED ||
183 errno == ENETUNREACH)
185 if (sock.get_handle () != ACE_INVALID_HANDLE)
186 status = con.complete (sock);
188 if (status != -1)
190 ACE_ERROR ((LM_ERROR,
191 ACE_TEXT ("Connect which should fail didn't\n")));
192 status = -1;
194 else
196 ACE_DEBUG ((LM_DEBUG,
197 ACE_TEXT ("%p\n"),
198 ACE_TEXT ("Proper fail")));
199 status = 0;
202 else
204 ACE_DEBUG ((LM_WARNING,
205 ACE_TEXT ("Test not executed fully; ")
206 ACE_TEXT ("expected EWOULDBLOCK, %p (%d)\n"),
207 ACE_TEXT ("not"), ACE_ERRNO_GET));
208 status = -1;
211 // Just in case.
212 sock.close ();
214 return status;
218 // This test tries to hit a port that's listening. Echo (7) is pretty
219 // popular. Just in case, though, it won't report a failure if it
220 // gets "refused" (no listener) since the real fixed bug this is
221 // testing is a returned error of EWOULDBLOCK when the connect really
222 // did work. That was a side-affect of how
223 // <ACE::handle_timed_complete> does checks on some systems.
225 static int
226 succeed_nonblocking ()
228 ACE_TCHAR test_host[MAXHOSTNAMELEN], test_addr[MAXHOSTNAMELEN + 8];
229 int status;
230 ACE_INET_Addr echo_server;
231 ACE_SOCK_Connector con;
232 ACE_SOCK_Stream sock;
233 ACE_Time_Value nonblock (0, 0);
234 u_short test_port = 7; // Echo
236 find_another_host (test_host);
237 if (ACE_OS::strcmp (ACE_TEXT ("localhost"), test_host) == 0)
239 #if defined (ACE_WIN32)
240 test_port = 80; // Echo not available on Win32; try web server
241 #endif /* ACE_WIN32 */
243 if (echo_server.set (test_port, test_host) == -1)
245 ACE_ERROR ((LM_ERROR,
246 ACE_TEXT ("Host lookup for %s %p\n"),
247 test_host,
248 ACE_TEXT ("failed")));
249 return -1;
251 echo_server.addr_to_string (test_addr, MAXHOSTNAMELEN + 8);
252 ACE_DEBUG ((LM_DEBUG,
253 ACE_TEXT ("Testing to host \"%s\", port %d (%s)\n"),
254 test_host, test_port, test_addr));
255 status = con.connect (sock, echo_server, &nonblock);
257 // Need to test the call to 'complete' really.
258 if (status == 0 || (status == -1 && errno != EWOULDBLOCK))
260 ACE_DEBUG((LM_WARNING,
261 ACE_TEXT ("Immediate success/fail; test not completed\n")));
262 status = 0;
264 else
266 if (sock.get_handle () != ACE_INVALID_HANDLE)
268 status = con.complete (sock);
271 if (status == -1)
273 // Reset the status _before_ doing the printout, in case the
274 // printout overwrites errno.
275 if (errno == ECONNREFUSED)
277 status = 0;
278 ACE_DEBUG ((LM_DEBUG,
279 ACE_TEXT ("Should succeed, but refused: ok\n")));
281 else
283 ACE_ERROR ((LM_ERROR,
284 ACE_TEXT("Errno <%d>: %p\n"),
285 ACE_ERRNO_GET,
286 ACE_TEXT("connect should succeed, but")));
289 else
290 ACE_DEBUG((LM_DEBUG,
291 ACE_TEXT("Connect which should succeed, did\n")));
294 // Just in case.
295 sock.close ();
297 return status;
301 run_main (int, ACE_TCHAR *[])
303 ACE_START_TEST (ACE_TEXT ("SOCK_Connector_Test"));
305 int status = 0;
307 if (fail_no_listener_nonblocking () == -1)
308 status = 1;
310 if (succeed_nonblocking () == -1)
311 status = 1;
313 ACE_END_TEST;
314 return status;