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 #if !defined (ACE_HAS_WINCE)
12 #include "ace/OS_QoS.h"
13 #endif // ACE_HAS_WINCE
15 #if !defined (__ACE_INLINE__)
16 #include "ace/SOCK_Connector.inl"
17 #endif /* __ACE_INLINE__ */
19 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
21 ACE_ALLOC_HOOK_DEFINE(ACE_SOCK_Connector
)
24 ACE_SOCK_Connector::dump (void) const
26 #if defined (ACE_HAS_DUMP)
27 ACE_TRACE ("ACE_SOCK_Connector::dump");
28 #endif /* ACE_HAS_DUMP */
32 ACE_SOCK_Connector::shared_open (ACE_SOCK_Stream
&new_stream
,
37 ACE_TRACE ("ACE_SOCK_Connector::shared_open");
39 // Only open a new socket if we don't already have a valid handle.
40 if (new_stream
.get_handle () == ACE_INVALID_HANDLE
41 && new_stream
.open (SOCK_STREAM
,
51 ACE_SOCK_Connector::shared_open (ACE_SOCK_Stream
&new_stream
,
54 ACE_Protocol_Info
*protocolinfo
,
59 ACE_TRACE ("ACE_SOCK_Connector::shared_open");
61 // Only open a new socket if we don't already have a valid handle.
62 if (new_stream
.get_handle () == ACE_INVALID_HANDLE
63 && new_stream
.open (SOCK_STREAM
,
76 ACE_SOCK_Connector::shared_connect_start (ACE_SOCK_Stream
&new_stream
,
77 const ACE_Time_Value
*timeout
,
78 const ACE_Addr
&local_sap
)
80 ACE_TRACE ("ACE_SOCK_Connector::shared_connect_start");
82 if (local_sap
!= ACE_Addr::sap_any
)
84 sockaddr
*laddr
= reinterpret_cast<sockaddr
*> (local_sap
.get_addr ());
85 int const size
= local_sap
.get_size ();
87 if (ACE_OS::bind (new_stream
.get_handle (), laddr
, size
) == -1)
89 // Save/restore errno.
90 ACE_Errno_Guard
error (errno
);
96 // Enable non-blocking, if required.
97 if (timeout
!= 0 && new_stream
.enable (ACE_NONBLOCK
) == -1)
104 ACE_SOCK_Connector::shared_connect_finish (ACE_SOCK_Stream
&new_stream
,
105 const ACE_Time_Value
*timeout
,
108 ACE_TRACE ("ACE_SOCK_Connector::shared_connect_finish");
109 // Save/restore errno.
110 ACE_Errno_Guard
error (errno
);
112 if (result
== -1 && timeout
!= 0)
114 // Check whether the connection is in progress.
115 if (error
== EINPROGRESS
|| error
== EWOULDBLOCK
)
117 // This expression checks if we were polling.
118 if (*timeout
== ACE_Time_Value::zero
)
120 #if defined(ACE_WIN32)
121 // In order to detect when the socket that has been
122 // bound to is in TIME_WAIT we need to do the connect
123 // (which will always return EWOULDBLOCK) and then do an
124 // ACE::handle_timed_complete() (with timeout==0,
125 // i.e. poll). This will do a select() on the handle
126 // which will immediately return with the handle in an
127 // error state. The error code is then retrieved with
128 // getsockopt(). Good sockets however will return from
129 // the select() with ETIME - in this case return
130 // EWOULDBLOCK so the wait strategy can complete the
132 if(ACE::handle_timed_complete (new_stream
.get_handle (),
133 timeout
) == ACE_INVALID_HANDLE
)
135 int const tmp
= errno
;
145 #else /* ACE_WIN32 */
147 #endif /* ACE_WIN32 */
149 // Wait synchronously using timeout.
150 else if (this->complete (new_stream
, 0, timeout
) == -1)
157 // EISCONN is treated specially since this routine may be used to
158 // check if we are already connected.
159 if (result
!= -1 || error
== EISCONN
)
161 // Start out with non-blocking disabled on the new_stream.
162 result
= new_stream
.disable (ACE_NONBLOCK
);
168 else if (!(error
== EWOULDBLOCK
|| error
== ETIMEDOUT
))
176 // Actively connect and produce a new ACE_SOCK_Stream if things go well...
178 ACE_SOCK_Connector::connect (ACE_SOCK_Stream
&new_stream
,
179 const ACE_Addr
&remote_sap
,
180 const ACE_Time_Value
*timeout
,
181 const ACE_Addr
&local_sap
,
187 ACE_TRACE ("ACE_SOCK_Connector::connect");
189 if (this->shared_open (new_stream
,
190 remote_sap
.get_type (),
194 else if (this->shared_connect_start (new_stream
,
199 #if defined(ACE_WIN32) && defined(ACE_HAS_IPV6)
200 // On windows, the IPv4-mapped IPv6 address format can only be used on a dual-stack socket.
201 const ACE_INET_Addr
& remote_address
= static_cast<const ACE_INET_Addr
&>(remote_sap
);
202 if (remote_address
.is_ipv4_mapped_ipv6()) {
204 ACE_OS::setsockopt(new_stream
.get_handle(),
212 int result
= ACE_OS::connect (new_stream
.get_handle (),
213 reinterpret_cast<sockaddr
*> (remote_sap
.get_addr ()),
214 remote_sap
.get_size ());
216 return this->shared_connect_finish (new_stream
, timeout
, result
);
219 #if !defined (ACE_HAS_WINCE)
221 ACE_SOCK_Connector::connect (ACE_SOCK_Stream
&new_stream
,
222 const ACE_Addr
&remote_sap
,
223 ACE_QoS_Params qos_params
,
224 const ACE_Time_Value
*timeout
,
225 const ACE_Addr
&local_sap
,
226 ACE_Protocol_Info
* protocolinfo
,
232 ACE_TRACE ("ACE_SOCK_Connector::connect");
234 if (this->shared_open (new_stream
,
235 remote_sap
.get_type (),
242 else if (this->shared_connect_start (new_stream
,
247 #if defined(ACE_WIN32) && defined(ACE_HAS_IPV6)
248 // On windows, the IPv4-mapped IPv6 address format can only be used on a dual-stack socket.
249 const ACE_INET_Addr
& remote_address
= static_cast<const ACE_INET_Addr
&>(remote_sap
);
250 if (remote_address
.is_ipv4_mapped_ipv6()) {
252 ACE_OS::setsockopt(new_stream
.get_handle(),
260 int result
= ACE_OS::connect (new_stream
.get_handle (),
261 reinterpret_cast<sockaddr
*> (remote_sap
.get_addr ()),
262 remote_sap
.get_size (),
265 return this->shared_connect_finish (new_stream
, timeout
, result
);
267 #endif // ACE_HAS_WINCE
269 // Try to complete a non-blocking connection.
272 ACE_SOCK_Connector::complete (ACE_SOCK_Stream
&new_stream
,
273 ACE_Addr
*remote_sap
,
274 const ACE_Time_Value
*tv
)
276 ACE_TRACE ("ACE_SOCK_Connector::complete");
277 ACE_HANDLE h
= ACE::handle_timed_complete (new_stream
.get_handle (), tv
);
278 // We failed to get connected.
279 if (h
== ACE_INVALID_HANDLE
)
281 #if defined (ACE_NON_BLOCKING_BUG_DELAY) && ACE_NON_BLOCKING_BUG_DELAY > 0
282 // Win32 has a timing problem - if you check to see if the
283 // connection has completed too fast, it will fail - so wait
284 // <ACE_NON_BLOCKING_BUG_DELAY> microseconds to let it catch up
285 // then retry to see if it's a real failure.
286 ACE_Time_Value
time (0, ACE_NON_BLOCKING_BUG_DELAY
);
287 ACE_OS::sleep (time
);
288 h
= ACE::handle_timed_complete (new_stream
.get_handle (), tv
);
289 if (h
== ACE_INVALID_HANDLE
)
291 #endif /* ACE_NON_BLOCKING_BUG_DELAY */
292 // Save/restore errno.
293 ACE_Errno_Guard
error (errno
);
296 #if defined (ACE_NON_BLOCKING_BUG_DELAY) && ACE_NON_BLOCKING_BUG_DELAY > 0
298 #endif /* ACE_NON_BLOCKING_BUG_DELAY */
303 int len
= remote_sap
->get_size ();
304 sockaddr
*addr
= reinterpret_cast<sockaddr
*> (remote_sap
->get_addr ());
305 if (ACE_OS::getpeername (h
,
309 // Save/restore errno.
310 ACE_Errno_Guard
error (errno
);
316 // Start out with non-blocking disabled on the <new_stream>.
317 new_stream
.disable (ACE_NONBLOCK
);
321 ACE_SOCK_Connector::ACE_SOCK_Connector (ACE_SOCK_Stream
&new_stream
,
322 const ACE_Addr
&remote_sap
,
323 const ACE_Time_Value
*timeout
,
324 const ACE_Addr
&local_sap
,
330 ACE_TRACE ("ACE_SOCK_Connector::ACE_SOCK_Connector");
332 if (this->connect (new_stream
,
341 && !(errno
== EWOULDBLOCK
|| errno
== ETIME
|| errno
== ETIMEDOUT
))
342 ACELIB_ERROR ((LM_ERROR
,
344 ACE_TEXT ("ACE_SOCK_Connector::ACE_SOCK_Connector")));
347 #if !defined (ACE_HAS_WINCE)
348 ACE_SOCK_Connector::ACE_SOCK_Connector (ACE_SOCK_Stream
&new_stream
,
349 const ACE_Addr
&remote_sap
,
350 ACE_QoS_Params qos_params
,
351 const ACE_Time_Value
*timeout
,
352 const ACE_Addr
&local_sap
,
353 ACE_Protocol_Info
*protocolinfo
,
359 ACE_TRACE ("ACE_SOCK_Connector::ACE_SOCK_Connector");
361 if (this->connect (new_stream
,
372 && !(errno
== EWOULDBLOCK
|| errno
== ETIME
|| errno
== ETIMEDOUT
))
373 ACELIB_ERROR ((LM_ERROR
,
375 ACE_TEXT ("ACE_SOCK_Connector::ACE_SOCK_Connector")));
377 #endif // ACE_HAS_WINCE
379 ACE_END_VERSIONED_NAMESPACE_DECL