Document return values
[ACE_TAO.git] / ACE / ace / SOCK_Connector.cpp
blobdf7cb39adc44f0e70887a0548ca2d9979dad70e5
1 #include "ace/SOCK_Connector.h"
2 #include "ace/INET_Addr.h"
3 #include "ace/Log_Category.h"
4 #include "ace/OS_NS_unistd.h"
5 #include "ace/OS_NS_sys_socket.h"
6 #include "ace/os_include/os_fcntl.h"
7 #if defined (ACE_HAS_ALLOC_HOOKS)
8 # include "ace/Malloc_Base.h"
9 #endif /* ACE_HAS_ALLOC_HOOKS */
11 #include "ace/OS_QoS.h"
13 #if !defined (__ACE_INLINE__)
14 #include "ace/SOCK_Connector.inl"
15 #endif /* __ACE_INLINE__ */
17 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
19 ACE_ALLOC_HOOK_DEFINE(ACE_SOCK_Connector)
21 void
22 ACE_SOCK_Connector::dump () const
24 #if defined (ACE_HAS_DUMP)
25 ACE_TRACE ("ACE_SOCK_Connector::dump");
26 #endif /* ACE_HAS_DUMP */
29 int
30 ACE_SOCK_Connector::shared_open (ACE_SOCK_Stream &new_stream,
31 int protocol_family,
32 int protocol,
33 int reuse_addr)
35 ACE_TRACE ("ACE_SOCK_Connector::shared_open");
37 // Only open a new socket if we don't already have a valid handle.
38 if (new_stream.get_handle () == ACE_INVALID_HANDLE
39 && new_stream.open (SOCK_STREAM,
40 protocol_family,
41 protocol,
42 reuse_addr) == -1)
43 return -1;
44 else
45 return 0;
48 int
49 ACE_SOCK_Connector::shared_open (ACE_SOCK_Stream &new_stream,
50 int protocol_family,
51 int protocol,
52 ACE_Protocol_Info *protocolinfo,
53 ACE_SOCK_GROUP g,
54 u_long flags,
55 int reuse_addr)
57 ACE_TRACE ("ACE_SOCK_Connector::shared_open");
59 // Only open a new socket if we don't already have a valid handle.
60 if (new_stream.get_handle () == ACE_INVALID_HANDLE
61 && new_stream.open (SOCK_STREAM,
62 protocol_family,
63 protocol,
64 protocolinfo,
66 flags,
67 reuse_addr) == -1)
68 return -1;
69 else
70 return 0;
73 int
74 ACE_SOCK_Connector::shared_connect_start (ACE_SOCK_Stream &new_stream,
75 const ACE_Time_Value *timeout,
76 const ACE_Addr &local_sap)
78 ACE_TRACE ("ACE_SOCK_Connector::shared_connect_start");
80 if (local_sap != ACE_Addr::sap_any)
82 sockaddr *laddr = reinterpret_cast<sockaddr *> (local_sap.get_addr ());
83 int const size = local_sap.get_size ();
85 if (ACE_OS::bind (new_stream.get_handle (), laddr, size) == -1)
87 // Save/restore errno.
88 ACE_Errno_Guard error (errno);
89 new_stream.close ();
90 return -1;
94 // Enable non-blocking, if required.
95 if (timeout != 0 && new_stream.enable (ACE_NONBLOCK) == -1)
96 return -1;
97 else
98 return 0;
102 ACE_SOCK_Connector::shared_connect_finish (ACE_SOCK_Stream &new_stream,
103 const ACE_Time_Value *timeout,
104 int result)
106 ACE_TRACE ("ACE_SOCK_Connector::shared_connect_finish");
107 // Save/restore errno.
108 ACE_Errno_Guard error (errno);
110 if (result == -1 && timeout != 0)
112 // Check whether the connection is in progress.
113 if (error == EINPROGRESS || error == EWOULDBLOCK)
115 // This expression checks if we were polling.
116 if (*timeout == ACE_Time_Value::zero)
118 #if defined(ACE_WIN32)
119 // In order to detect when the socket that has been
120 // bound to is in TIME_WAIT we need to do the connect
121 // (which will always return EWOULDBLOCK) and then do an
122 // ACE::handle_timed_complete() (with timeout==0,
123 // i.e. poll). This will do a select() on the handle
124 // which will immediately return with the handle in an
125 // error state. The error code is then retrieved with
126 // getsockopt(). Good sockets however will return from
127 // the select() with ETIME - in this case return
128 // EWOULDBLOCK so the wait strategy can complete the
129 // connection.
130 if(ACE::handle_timed_complete (new_stream.get_handle (),
131 timeout) == ACE_INVALID_HANDLE)
133 int const tmp = errno;
134 if (tmp != ETIME)
136 error = tmp;
138 else
139 error = EWOULDBLOCK;
141 else
142 result = 0;
143 #else /* ACE_WIN32 */
144 error = EWOULDBLOCK;
145 #endif /* ACE_WIN32 */
147 // Wait synchronously using timeout.
148 else if (this->complete (new_stream, 0, timeout) == -1)
149 error = errno;
150 else
151 return 0;
155 // EISCONN is treated specially since this routine may be used to
156 // check if we are already connected.
157 if (result != -1 || error == EISCONN)
159 // Start out with non-blocking disabled on the new_stream.
160 result = new_stream.disable (ACE_NONBLOCK);
161 if (result == -1)
163 new_stream.close ();
166 else if (!(error == EWOULDBLOCK || error == ETIMEDOUT))
168 new_stream.close ();
171 return result;
174 // Actively connect and produce a new ACE_SOCK_Stream if things go well...
176 ACE_SOCK_Connector::connect (ACE_SOCK_Stream &new_stream,
177 const ACE_Addr &remote_sap,
178 const ACE_Time_Value *timeout,
179 const ACE_Addr &local_sap,
180 int reuse_addr,
181 int /* flags */,
182 int /* perms */,
183 int protocol)
185 ACE_TRACE ("ACE_SOCK_Connector::connect");
187 if (this->shared_open (new_stream,
188 remote_sap.get_type (),
189 protocol,
190 reuse_addr) == -1)
191 return -1;
192 else if (this->shared_connect_start (new_stream,
193 timeout,
194 local_sap) == -1)
195 return -1;
197 #if defined(ACE_WIN32) && defined(ACE_HAS_IPV6)
198 // On windows, the IPv4-mapped IPv6 address format can only be used on a dual-stack socket.
199 const ACE_INET_Addr& remote_address = static_cast<const ACE_INET_Addr&>(remote_sap);
200 if (remote_address.is_ipv4_mapped_ipv6()) {
201 int zero = 0;
202 ACE_OS::setsockopt(new_stream.get_handle(),
203 IPPROTO_IPV6,
204 IPV6_V6ONLY,
205 (char *)&zero,
206 sizeof(zero));
208 #endif
210 int result = ACE_OS::connect (new_stream.get_handle (),
211 reinterpret_cast<sockaddr *> (remote_sap.get_addr ()),
212 remote_sap.get_size ());
214 return this->shared_connect_finish (new_stream, timeout, result);
218 ACE_SOCK_Connector::connect (ACE_SOCK_Stream &new_stream,
219 const ACE_Addr &remote_sap,
220 ACE_QoS_Params qos_params,
221 const ACE_Time_Value *timeout,
222 const ACE_Addr &local_sap,
223 ACE_Protocol_Info * protocolinfo,
224 ACE_SOCK_GROUP g,
225 u_long flags,
226 int reuse_addr,
227 int /* perms */)
229 ACE_TRACE ("ACE_SOCK_Connector::connect");
231 if (this->shared_open (new_stream,
232 remote_sap.get_type (),
234 protocolinfo,
236 flags,
237 reuse_addr) == -1)
238 return -1;
239 else if (this->shared_connect_start (new_stream,
240 timeout,
241 local_sap) == -1)
242 return -1;
244 #if defined(ACE_WIN32) && defined(ACE_HAS_IPV6)
245 // On windows, the IPv4-mapped IPv6 address format can only be used on a dual-stack socket.
246 const ACE_INET_Addr& remote_address = static_cast<const ACE_INET_Addr&>(remote_sap);
247 if (remote_address.is_ipv4_mapped_ipv6()) {
248 int zero = 0;
249 ACE_OS::setsockopt(new_stream.get_handle(),
250 IPPROTO_IPV6,
251 IPV6_V6ONLY,
252 (char *)&zero,
253 sizeof(zero));
255 #endif
257 int result = ACE_OS::connect (new_stream.get_handle (),
258 reinterpret_cast<sockaddr *> (remote_sap.get_addr ()),
259 remote_sap.get_size (),
260 qos_params);
262 return this->shared_connect_finish (new_stream, timeout, result);
265 // Try to complete a non-blocking connection.
267 ACE_SOCK_Connector::complete (ACE_SOCK_Stream &new_stream,
268 ACE_Addr *remote_sap,
269 const ACE_Time_Value *tv)
271 ACE_TRACE ("ACE_SOCK_Connector::complete");
272 ACE_HANDLE h = ACE::handle_timed_complete (new_stream.get_handle (), tv);
273 // We failed to get connected.
274 if (h == ACE_INVALID_HANDLE)
276 #if defined (ACE_NON_BLOCKING_BUG_DELAY) && ACE_NON_BLOCKING_BUG_DELAY > 0
277 // Win32 has a timing problem - if you check to see if the
278 // connection has completed too fast, it will fail - so wait
279 // <ACE_NON_BLOCKING_BUG_DELAY> microseconds to let it catch up
280 // then retry to see if it's a real failure.
281 ACE_Time_Value time (0, ACE_NON_BLOCKING_BUG_DELAY);
282 ACE_OS::sleep (time);
283 h = ACE::handle_timed_complete (new_stream.get_handle (), tv);
284 if (h == ACE_INVALID_HANDLE)
286 #endif /* ACE_NON_BLOCKING_BUG_DELAY */
287 // Save/restore errno.
288 ACE_Errno_Guard error (errno);
289 new_stream.close ();
290 return -1;
291 #if defined (ACE_NON_BLOCKING_BUG_DELAY) && ACE_NON_BLOCKING_BUG_DELAY > 0
293 #endif /* ACE_NON_BLOCKING_BUG_DELAY */
296 if (remote_sap != 0)
298 int len = remote_sap->get_size ();
299 sockaddr *addr = reinterpret_cast<sockaddr *> (remote_sap->get_addr ());
300 if (ACE_OS::getpeername (h,
301 addr,
302 &len) == -1)
304 // Save/restore errno.
305 ACE_Errno_Guard error (errno);
306 new_stream.close ();
307 return -1;
311 // Start out with non-blocking disabled on the <new_stream>.
312 new_stream.disable (ACE_NONBLOCK);
313 return 0;
316 ACE_SOCK_Connector::ACE_SOCK_Connector (ACE_SOCK_Stream &new_stream,
317 const ACE_Addr &remote_sap,
318 const ACE_Time_Value *timeout,
319 const ACE_Addr &local_sap,
320 int reuse_addr,
321 int flags,
322 int perms,
323 int protocol)
325 ACE_TRACE ("ACE_SOCK_Connector::ACE_SOCK_Connector");
327 if (this->connect (new_stream,
328 remote_sap,
329 timeout,
330 local_sap,
331 reuse_addr,
332 flags,
333 perms,
334 protocol) == -1
335 && timeout != 0
336 && !(errno == EWOULDBLOCK || errno == ETIME || errno == ETIMEDOUT))
337 ACELIB_ERROR ((LM_ERROR,
338 ACE_TEXT ("%p\n"),
339 ACE_TEXT ("ACE_SOCK_Connector::ACE_SOCK_Connector")));
342 ACE_SOCK_Connector::ACE_SOCK_Connector (ACE_SOCK_Stream &new_stream,
343 const ACE_Addr &remote_sap,
344 ACE_QoS_Params qos_params,
345 const ACE_Time_Value *timeout,
346 const ACE_Addr &local_sap,
347 ACE_Protocol_Info *protocolinfo,
348 ACE_SOCK_GROUP g,
349 u_long flags,
350 int reuse_addr,
351 int perms)
353 ACE_TRACE ("ACE_SOCK_Connector::ACE_SOCK_Connector");
355 if (this->connect (new_stream,
356 remote_sap,
357 qos_params,
358 timeout,
359 local_sap,
360 protocolinfo,
362 flags,
363 reuse_addr,
364 perms) == -1
365 && timeout != 0
366 && !(errno == EWOULDBLOCK || errno == ETIME || errno == ETIMEDOUT))
367 ACELIB_ERROR ((LM_ERROR,
368 ACE_TEXT ("%p\n"),
369 ACE_TEXT ("ACE_SOCK_Connector::ACE_SOCK_Connector")));
372 ACE_END_VERSIONED_NAMESPACE_DECL