Correct feature names
[ACE_TAO.git] / ACE / ace / SPIPE_Acceptor.cpp
blob84420da62bc6209d7fccb36214a4ae46dff21e05
1 #include "ace/SPIPE_Acceptor.h"
2 #include "ace/Log_Category.h"
3 #include "ace/OS_NS_sys_stat.h"
4 #include "ace/OS_NS_sys_time.h"
5 #if defined (ACE_HAS_ALLOC_HOOKS)
6 # include "ace/Malloc_Base.h"
7 #endif /* ACE_HAS_ALLOC_HOOKS */
9 #if defined (ACE_HAS_STREAM_PIPES)
10 # include "ace/OS_NS_unistd.h"
11 #endif // ACE_HAS_STREAM_PIPES
15 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
17 ACE_SPIPE_Acceptor::ACE_SPIPE_Acceptor (void)
18 #if defined (ACE_HAS_WIN32_NAMED_PIPES)
19 : sa_ (0), pipe_handle_ (ACE_INVALID_HANDLE)
20 #endif /* ACE_HAS_WIN32_NAMED_PIPES */
22 ACE_TRACE ("ACE_SPIPE_Acceptor::ACE_SPIPE_Acceptor");
25 int
26 ACE_SPIPE_Acceptor::remove (void)
28 ACE_TRACE ("ACE_SPIPE_Acceptor::remove");
29 #if defined (ACE_HAS_STREAM_PIPES)
30 int result = this->close ();
32 // Remove the underlying file.
33 return ACE_OS::unlink (this->local_addr_.get_path_name ()) == -1
34 || result == -1 ? -1 : 0;
35 #else
36 this->close ();
37 return 0;
38 #endif
41 ACE_ALLOC_HOOK_DEFINE (ACE_SPIPE_Acceptor)
43 void
44 ACE_SPIPE_Acceptor::dump (void) const
46 #if defined (ACE_HAS_DUMP)
47 ACE_TRACE ("ACE_SPIPE_Acceptor::dump");
48 #endif /* ACE_HAS_DUMP */
51 // General purpose routine for performing server ACE_SPIPE creation.
53 int
54 ACE_SPIPE_Acceptor::open (const ACE_SPIPE_Addr &local_sap,
55 int reuse_addr,
56 int perms,
57 LPSECURITY_ATTRIBUTES sa,
58 int pipe_mode)
60 ACE_TRACE ("ACE_SPIPE_Acceptor::open");
61 ACE_UNUSED_ARG (reuse_addr);
63 this->local_addr_ = local_sap;
64 this->set_handle (ACE_INVALID_HANDLE);
65 #if defined (ACE_HAS_WIN32_NAMED_PIPES)
66 this->sa_ = sa;
67 this->pipe_mode_ = pipe_mode;
68 #else
69 ACE_UNUSED_ARG (sa);
70 ACE_UNUSED_ARG (pipe_mode);
71 #endif /* ACE_HAS_WIN32_NAMED_PIPES */
73 return this->create_new_instance (perms);
76 int
77 ACE_SPIPE_Acceptor::create_new_instance (int perms)
79 #if defined (ACE_HAS_STREAM_PIPES)
80 ACE_HANDLE spipe[2];
81 char module[] = "connld";
83 ACE_HANDLE handle = ACE_OS::creat (this->local_addr_.get_path_name (),
84 perms);
85 if (handle == ACE_INVALID_HANDLE)
86 return -1;
87 else if (ACE_OS::close (handle) == -1)
88 return -1;
89 else if (ACE_OS::pipe (spipe) == -1)
90 return -1;
91 else if (ACE_OS::ioctl (spipe[0],
92 I_PUSH,
93 module) == -1)
94 return -1;
95 else if (-1 == ACE_OS::fattach(spipe[0],
96 ACE_TEXT_ALWAYS_CHAR (
97 this->local_addr_.get_path_name ())))
98 return -1;
100 this->set_duplex_handle (spipe[0]);
101 this->set_handle (spipe[1]);
102 return 0;
104 #elif defined (ACE_HAS_WIN32_NAMED_PIPES)
105 // Create a new instance of the Named Pipe (WIN32). A new instance
106 // of the named pipe must be created for every client process. If
107 // an instance of the named pipe that is already connected to a
108 // client process is reused with a new client process,
109 // ::ConnectNamedPipe () would fail.
111 ACE_UNUSED_ARG (perms);
112 ACE_TRACE ("ACE_SPIPE_Acceptor::create_new_instance");
113 int status;
115 // Create a new instance of the named pipe
116 this->pipe_handle_ =
117 #if defined (ACE_USES_WCHAR)
118 ::CreateNamedPipeW (
119 #else /* ACE_USES_WCHAR */
120 ::CreateNamedPipeA (
121 #endif /* ACE_USES_WCHAR */
122 this->local_addr_.get_path_name (),
123 PIPE_ACCESS_DUPLEX
124 | FILE_FLAG_OVERLAPPED,
125 pipe_mode_,
126 PIPE_UNLIMITED_INSTANCES,
127 1024 * 10,
128 1024 * 10,
129 ACE_DEFAULT_TIMEOUT,
130 this->sa_);
132 if (this->pipe_handle_ == ACE_INVALID_HANDLE)
133 return -1;
134 else
136 // Start the Connect (analogous to listen () for a socket).
137 // Completion is noted by the event being signalled. If a
138 // client connects before this call, the error status will be
139 // ERROR_PIPE_CONNECTED. If the client also disconnects before
140 // this call, the error status will be ERROR_NO_DATA. In both
141 // cases, that fact is remembered via already_connected_ and
142 // noted when the user calls accept(). Else the error status
143 // should be ERROR_IO_PENDING and the OS will signal the event
144 // when it's done.
145 this->already_connected_ = 0;
146 this->set_handle (this->event_.handle ());
147 this->overlapped_.hEvent = this->event_.handle ();
148 this->event_.reset ();
150 BOOL result = ::ConnectNamedPipe (this->pipe_handle_,
151 &this->overlapped_);
152 ACE_UNUSED_ARG (result);
153 // ConnectNamePipe is suppose to always
154 // "fail" when passed in overlapped i/o
155 ACE_ASSERT (!result);
157 status = ::GetLastError ();
158 switch (status)
160 case ERROR_IO_PENDING:
161 break;
162 case ERROR_PIPE_CONNECTED:
163 case ERROR_NO_DATA:
164 this->already_connected_ = 1;
165 // Set the associated event as signaled so any reactors or
166 // proactors waiting for this will respond.
167 this->event_.signal ();
168 break;
169 default:
170 ACE_ASSERT (FALSE); // An undocumented error was returned.
171 this->close (); // Sets handle to ACE_INVALID_HANDLE.
172 break;
175 return this->get_handle () == ACE_INVALID_HANDLE ? -1 : 0;
176 #else
177 ACE_UNUSED_ARG (perms);
178 ACE_NOTSUP_RETURN (-1);
179 #endif /* ACE_HAS_STREAM_PIPES */
183 ACE_SPIPE_Acceptor::close (void)
185 ACE_TRACE ("ACE_SPIPE_Acceptor::close");
187 #if defined (ACE_HAS_WIN32_NAMED_PIPES)
189 // Check to see if we have a valid pipe; if not, nothing to do.
190 if (this->pipe_handle_ == ACE_INVALID_HANDLE)
191 return -1;
193 // Substitute the pipe handle back in so it's closed properly in the
194 // ACE_OS wrapper. But leave the pipe_handle_ value so we can clean up the
195 // hanging overlapped operation afterwards.
196 this->set_handle (this->pipe_handle_);
198 #endif /* ACE_HAS_WIN32_NAMED_PIPES */
200 // This behavior is shared by UNIX and Win32...
201 int result = this->ACE_SPIPE::close ();
202 this->set_handle (ACE_INVALID_HANDLE);
204 #if defined (ACE_HAS_STREAM_PIPES)
205 ACE_OS::fdetach (ACE_TEXT_ALWAYS_CHAR (this->local_addr_.get_path_name ()));
206 #elif defined (ACE_HAS_WIN32_NAMED_PIPES)
208 // open () started the Connect in asynchronous mode, and accept() restarts
209 // the ConnectNamedPipe in overlapped mode. To avoid leaving a hanging
210 // overlapped operation that'll write into members of this object,
211 // wait for the event in the OVERLAPPED structure to be signalled.
212 if (this->already_connected_ == 0)
214 if (this->event_.wait () != -1)
216 // Should be here with the ConnectNamedPipe operation complete.
217 // Steal the already_connected_ flag to record the results.
218 DWORD unused;
219 ::GetOverlappedResult (this->pipe_handle_,
220 &this->overlapped_,
221 &unused,
222 FALSE);
224 this->pipe_handle_ = ACE_INVALID_HANDLE;
225 this->already_connected_ = 0;
227 #endif /* ACE_HAS_STREAM_PIPES */
229 return result;
232 ACE_SPIPE_Acceptor::ACE_SPIPE_Acceptor (const ACE_SPIPE_Addr &local_sap,
233 int reuse_addr,
234 int perms,
235 LPSECURITY_ATTRIBUTES sa,
236 int pipe_mode)
238 ACE_TRACE ("ACE_SPIPE_Acceptor::ACE_SPIPE_Acceptor");
240 if (this->open (local_sap, reuse_addr, perms, sa, pipe_mode) == -1)
241 ACELIB_ERROR ((LM_ERROR,
242 ACE_TEXT ("%p\n"),
243 ACE_TEXT ("ACE_SPIPE_Acceptor")));
246 // General purpose routine for accepting new connections.
249 ACE_SPIPE_Acceptor::accept (ACE_SPIPE_Stream &new_io,
250 ACE_SPIPE_Addr *remote_addr,
251 ACE_Time_Value *timeout,
252 bool restart,
253 bool reset_new_handle)
255 ACE_TRACE ("ACE_SPIPE_Acceptor::accept");
256 ACE_UNUSED_ARG (reset_new_handle);
258 #if defined (ACE_HAS_STREAM_PIPES)
259 strrecvfd r_handle;
261 // Note that if THIS->MILLI_SECOND_DELAY == -1 we block on
262 // ACE_OS::ioctl (). Otherwise, we will wait for the desired number
263 // of milli seconds using ACE_OS::poll.
265 if (timeout != 0 &&
266 ACE::handle_timed_accept (this->get_handle (),
267 timeout,
268 restart) == -1)
269 return -1;
270 else if (ACE_OS::ioctl (this->get_handle (),
271 I_RECVFD,
272 &r_handle) == -1)
273 return -1;
275 new_io.set_handle (r_handle.fd);
276 new_io.local_addr_ = this->local_addr_;
277 new_io.remote_addr_.set_size (sizeof r_handle.gid + sizeof r_handle.uid);
278 new_io.remote_addr_.group_id (r_handle.gid);
279 new_io.remote_addr_.user_id (r_handle.uid);
281 // This is for compatibility with ACE_SOCK_Acceptor and
282 // ACE_TLI_Acceptor.
283 if (remote_addr != 0)
284 *remote_addr = new_io.remote_addr_;
286 return 0;
287 #elif defined (ACE_HAS_WIN32_NAMED_PIPES)
288 ACE_UNUSED_ARG (restart);
289 ACE_UNUSED_ARG (remote_addr);
291 // Check to see if we have a valid pipe
292 if (this->pipe_handle_ == ACE_INVALID_HANDLE)
293 return -1;
295 // open () started the Connect in asynchronous mode. Wait for the event
296 // in the OVERLAPPED structure to be signalled, then grab the status.
297 if (this->already_connected_ == 0)
299 if (timeout != 0)
301 ACE_Time_Value abstime (ACE_OS::gettimeofday () + *timeout);
302 if (this->event_.wait (&abstime) == -1)
303 return -1;
305 else
306 if (this->event_.wait () == -1)
307 return -1;
309 // Should be here with the ConnectNamedPipe operation complete.
310 // Steal the already_connected_ flag to record the results.
311 DWORD unused;
312 this->already_connected_ = ::GetOverlappedResult (this->pipe_handle_,
313 &this->overlapped_,
314 &unused,
315 FALSE);
318 if (this->already_connected_)
320 new_io.set_handle (this->pipe_handle_);
321 this->pipe_handle_ = ACE_INVALID_HANDLE;
322 new_io.local_addr_ = this->local_addr_;
324 // Create a new instance of the pipe for the next connection.
325 this->create_new_instance ();
326 return 0;
328 return -1;
329 #else
330 ACE_UNUSED_ARG (restart);
331 ACE_UNUSED_ARG (timeout);
332 ACE_UNUSED_ARG (remote_addr);
333 ACE_UNUSED_ARG (new_io);
334 ACE_NOTSUP_RETURN (-1);
335 #endif /* ACE_HAS_STREAM_PIPES */
338 ACE_END_VERSIONED_NAMESPACE_DECL