Also use Objects as part of an operation but as a result don't generate Any operation...
[ACE_TAO.git] / ACE / ace / SOCK_Connector.cpp
blobe84767064f9e263ebc501ffd3efcc3b07b20e473
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)
23 void
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 */
31 int
32 ACE_SOCK_Connector::shared_open (ACE_SOCK_Stream &new_stream,
33 int protocol_family,
34 int protocol,
35 int reuse_addr)
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,
42 protocol_family,
43 protocol,
44 reuse_addr) == -1)
45 return -1;
46 else
47 return 0;
50 int
51 ACE_SOCK_Connector::shared_open (ACE_SOCK_Stream &new_stream,
52 int protocol_family,
53 int protocol,
54 ACE_Protocol_Info *protocolinfo,
55 ACE_SOCK_GROUP g,
56 u_long flags,
57 int reuse_addr)
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,
64 protocol_family,
65 protocol,
66 protocolinfo,
68 flags,
69 reuse_addr) == -1)
70 return -1;
71 else
72 return 0;
75 int
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);
91 new_stream.close ();
92 return -1;
96 // Enable non-blocking, if required.
97 if (timeout != 0 && new_stream.enable (ACE_NONBLOCK) == -1)
98 return -1;
99 else
100 return 0;
104 ACE_SOCK_Connector::shared_connect_finish (ACE_SOCK_Stream &new_stream,
105 const ACE_Time_Value *timeout,
106 int result)
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
131 // connection.
132 if(ACE::handle_timed_complete (new_stream.get_handle (),
133 timeout) == ACE_INVALID_HANDLE)
135 int const tmp = errno;
136 if (tmp != ETIME)
138 error = tmp;
140 else
141 error = EWOULDBLOCK;
143 else
144 result = 0;
145 #else /* ACE_WIN32 */
146 error = EWOULDBLOCK;
147 #endif /* ACE_WIN32 */
149 // Wait synchronously using timeout.
150 else if (this->complete (new_stream, 0, timeout) == -1)
151 error = errno;
152 else
153 return 0;
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);
163 if (result == -1)
165 new_stream.close ();
168 else if (!(error == EWOULDBLOCK || error == ETIMEDOUT))
170 new_stream.close ();
173 return result;
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,
182 int reuse_addr,
183 int /* flags */,
184 int /* perms */,
185 int protocol)
187 ACE_TRACE ("ACE_SOCK_Connector::connect");
189 if (this->shared_open (new_stream,
190 remote_sap.get_type (),
191 protocol,
192 reuse_addr) == -1)
193 return -1;
194 else if (this->shared_connect_start (new_stream,
195 timeout,
196 local_sap) == -1)
197 return -1;
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()) {
203 int zero = 0;
204 ACE_OS::setsockopt(new_stream.get_handle(),
205 IPPROTO_IPV6,
206 IPV6_V6ONLY,
207 (char *)&zero,
208 sizeof(zero));
210 #endif
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,
227 ACE_SOCK_GROUP g,
228 u_long flags,
229 int reuse_addr,
230 int /* perms */)
232 ACE_TRACE ("ACE_SOCK_Connector::connect");
234 if (this->shared_open (new_stream,
235 remote_sap.get_type (),
237 protocolinfo,
239 flags,
240 reuse_addr) == -1)
241 return -1;
242 else if (this->shared_connect_start (new_stream,
243 timeout,
244 local_sap) == -1)
245 return -1;
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()) {
251 int zero = 0;
252 ACE_OS::setsockopt(new_stream.get_handle(),
253 IPPROTO_IPV6,
254 IPV6_V6ONLY,
255 (char *)&zero,
256 sizeof(zero));
258 #endif
260 int result = ACE_OS::connect (new_stream.get_handle (),
261 reinterpret_cast<sockaddr *> (remote_sap.get_addr ()),
262 remote_sap.get_size (),
263 qos_params);
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);
294 new_stream.close ();
295 return -1;
296 #if defined (ACE_NON_BLOCKING_BUG_DELAY) && ACE_NON_BLOCKING_BUG_DELAY > 0
298 #endif /* ACE_NON_BLOCKING_BUG_DELAY */
301 if (remote_sap != 0)
303 int len = remote_sap->get_size ();
304 sockaddr *addr = reinterpret_cast<sockaddr *> (remote_sap->get_addr ());
305 if (ACE_OS::getpeername (h,
306 addr,
307 &len) == -1)
309 // Save/restore errno.
310 ACE_Errno_Guard error (errno);
311 new_stream.close ();
312 return -1;
316 // Start out with non-blocking disabled on the <new_stream>.
317 new_stream.disable (ACE_NONBLOCK);
318 return 0;
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,
325 int reuse_addr,
326 int flags,
327 int perms,
328 int protocol)
330 ACE_TRACE ("ACE_SOCK_Connector::ACE_SOCK_Connector");
332 if (this->connect (new_stream,
333 remote_sap,
334 timeout,
335 local_sap,
336 reuse_addr,
337 flags,
338 perms,
339 protocol) == -1
340 && timeout != 0
341 && !(errno == EWOULDBLOCK || errno == ETIME || errno == ETIMEDOUT))
342 ACELIB_ERROR ((LM_ERROR,
343 ACE_TEXT ("%p\n"),
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,
354 ACE_SOCK_GROUP g,
355 u_long flags,
356 int reuse_addr,
357 int perms)
359 ACE_TRACE ("ACE_SOCK_Connector::ACE_SOCK_Connector");
361 if (this->connect (new_stream,
362 remote_sap,
363 qos_params,
364 timeout,
365 local_sap,
366 protocolinfo,
368 flags,
369 reuse_addr,
370 perms) == -1
371 && timeout != 0
372 && !(errno == EWOULDBLOCK || errno == ETIME || errno == ETIMEDOUT))
373 ACELIB_ERROR ((LM_ERROR,
374 ACE_TEXT ("%p\n"),
375 ACE_TEXT ("ACE_SOCK_Connector::ACE_SOCK_Connector")));
377 #endif // ACE_HAS_WINCE
379 ACE_END_VERSIONED_NAMESPACE_DECL