diff options
Diffstat (limited to 'ACE/ace/SPIPE_Acceptor.cpp')
-rw-r--r-- | ACE/ace/SPIPE_Acceptor.cpp | 337 |
1 files changed, 337 insertions, 0 deletions
diff --git a/ACE/ace/SPIPE_Acceptor.cpp b/ACE/ace/SPIPE_Acceptor.cpp new file mode 100644 index 00000000000..960adfc786c --- /dev/null +++ b/ACE/ace/SPIPE_Acceptor.cpp @@ -0,0 +1,337 @@ +// $Id$ + +#include "ace/SPIPE_Acceptor.h" +#include "ace/Log_Msg.h" +#include "ace/OS_NS_sys_stat.h" +#include "ace/OS_NS_sys_time.h" + +#if defined (ACE_HAS_STREAM_PIPES) +# include "ace/OS_NS_unistd.h" +#endif // ACE_HAS_STREAM_PIPES + +ACE_RCSID(ace, SPIPE_Acceptor, "$Id$") + +ACE_BEGIN_VERSIONED_NAMESPACE_DECL + +ACE_SPIPE_Acceptor::ACE_SPIPE_Acceptor (void) +#if (defined (ACE_WIN32) && defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0)) + : sa_ (0), pipe_handle_ (ACE_INVALID_HANDLE) +#endif /* ACE_WIN32 */ +{ + ACE_TRACE ("ACE_SPIPE_Acceptor::ACE_SPIPE_Acceptor"); +} + +int +ACE_SPIPE_Acceptor::remove (void) +{ + ACE_TRACE ("ACE_SPIPE_Acceptor::remove"); +#if defined (ACE_HAS_STREAM_PIPES) + int result = this->close (); + + // Remove the underlying file. + return ACE_OS::unlink (this->local_addr_.get_path_name ()) == -1 + || result == -1 ? -1 : 0; +#else + this->close (); + return 0; +#endif +} + +ACE_ALLOC_HOOK_DEFINE (ACE_SPIPE_Acceptor) + +void +ACE_SPIPE_Acceptor::dump (void) const +{ +#if defined (ACE_HAS_DUMP) + ACE_TRACE ("ACE_SPIPE_Acceptor::dump"); +#endif /* ACE_HAS_DUMP */ +} + +// General purpose routine for performing server ACE_SPIPE creation. + +int +ACE_SPIPE_Acceptor::open (const ACE_SPIPE_Addr &local_sap, + int reuse_addr, + int perms, + LPSECURITY_ATTRIBUTES sa, + int pipe_mode) +{ + ACE_TRACE ("ACE_SPIPE_Acceptor::open"); + ACE_UNUSED_ARG (reuse_addr); + + this->local_addr_ = local_sap; + this->set_handle (ACE_INVALID_HANDLE); +#if (defined (ACE_WIN32) && defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0)) + this->sa_ = sa; + this->pipe_mode_ = pipe_mode; +#else + ACE_UNUSED_ARG (sa); + ACE_UNUSED_ARG (pipe_mode); +#endif /* ACE_WIN32 */ + + return this->create_new_instance (perms); +} + +int +ACE_SPIPE_Acceptor::create_new_instance (int perms) +{ +#if defined (ACE_HAS_STREAM_PIPES) + ACE_HANDLE spipe[2]; + char module[] = "connld"; + + ACE_HANDLE handle = ACE_OS::creat (this->local_addr_.get_path_name (), + perms); + if (handle == ACE_INVALID_HANDLE) + return -1; + else if (ACE_OS::close (handle) == -1) + return -1; + else if (ACE_OS::pipe (spipe) == -1) + return -1; + else if (ACE_OS::ioctl (spipe[0], + I_PUSH, + module) == -1) + return -1; + else if (-1 == ACE_OS::fattach + (spipe[0], + ACE_TEXT_ALWAYS_CHAR (this->local_addr_.get_path_name ()))) + return -1; + + this->set_duplex_handle (spipe[0]); + this->set_handle (spipe[1]); + return 0; + +#elif (defined (ACE_WIN32) && defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0)) + // Create a new instance of the Named Pipe (WIN32). A new instance + // of the named pipe must be created for every client process. If + // an instance of the named pipe that is already connected to a + // client process is reused with a new client process, + // ::ConnectNamedPipe () would fail. + + ACE_UNUSED_ARG (perms); + ACE_TRACE ("ACE_SPIPE_Acceptor::create_new_instance"); + int status; + + // Create a new instance of the named pipe + this->pipe_handle_ = +#if defined (ACE_USES_WCHAR) + ::CreateNamedPipeW ( +#else /* ACE_USES_WCHAR */ + ::CreateNamedPipeA ( +#endif /* ACE_USES_WCHAR */ + this->local_addr_.get_path_name (), + PIPE_ACCESS_DUPLEX + | FILE_FLAG_OVERLAPPED, + pipe_mode_, + PIPE_UNLIMITED_INSTANCES, + 1024 * 10, + 1024 * 10, + ACE_DEFAULT_TIMEOUT, + this->sa_); + + if (this->pipe_handle_ == ACE_INVALID_HANDLE) + return -1; + else + { + // Start the Connect (analogous to listen () for a socket). + // Completion is noted by the event being signalled. If a + // client connects before this call, the error status will be + // ERROR_PIPE_CONNECTED. If the client also disconnects before + // this call, the error status will be ERROR_NO_DATA. In both + // cases, that fact is remembered via already_connected_ and + // noted when the user calls accept(). Else the error status + // should be ERROR_IO_PENDING and the OS will signal the event + // when it's done. + this->already_connected_ = 0; + this->set_handle (this->event_.handle ()); + this->overlapped_.hEvent = this->event_.handle (); + this->event_.reset (); + + BOOL result = ::ConnectNamedPipe (this->pipe_handle_, + &this->overlapped_); + ACE_UNUSED_ARG (result); + // ConnectNamePipe is suppose to always + // "fail" when passed in overlapped i/o + ACE_ASSERT (!result); + + status = ::GetLastError (); + switch (status) + { + case ERROR_IO_PENDING: + break; + case ERROR_PIPE_CONNECTED: + case ERROR_NO_DATA: + this->already_connected_ = 1; + // Set the associated event as signaled so any reactors or + // proactors waiting for this will respond. + this->event_.signal (); + break; + default: + ACE_ASSERT (FALSE); // An undocumented error was returned. + this->close (); // Sets handle to ACE_INVALID_HANDLE. + break; + } + } + return this->get_handle () == ACE_INVALID_HANDLE ? -1 : 0; +#else + ACE_UNUSED_ARG (perms); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_STREAM_PIPES */ +} + +int +ACE_SPIPE_Acceptor::close (void) +{ + ACE_TRACE ("ACE_SPIPE_Acceptor::close"); + +#if (defined (ACE_WIN32) && defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0)) + + // Check to see if we have a valid pipe; if not, nothing to do. + if (this->pipe_handle_ == ACE_INVALID_HANDLE) + return -1; + + // Substitute the pipe handle back in so it's closed properly in the + // ACE_OS wrapper. But leave the pipe_handle_ value so we can clean up the + // hanging overlapped operation afterwards. + this->set_handle (this->pipe_handle_); + +#endif /* ACE_WIN32 */ + + // This behavior is shared by UNIX and Win32... + int result = this->ACE_SPIPE::close (); + this->set_handle (ACE_INVALID_HANDLE); + +#if defined (ACE_HAS_STREAM_PIPES) + ACE_OS::fdetach (ACE_TEXT_ALWAYS_CHAR (this->local_addr_.get_path_name ())); +#elif (defined (ACE_WIN32) && defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0)) + + // open () started the Connect in asynchronous mode, and accept() restarts + // the ConnectNamedPipe in overlapped mode. To avoid leaving a hanging + // overlapped operation that'll write into members of this object, + // wait for the event in the OVERLAPPED structure to be signalled. + if (this->already_connected_ == 0) + { + if (this->event_.wait () != -1) + { + // Should be here with the ConnectNamedPipe operation complete. + // Steal the already_connected_ flag to record the results. + DWORD unused; + ::GetOverlappedResult (this->pipe_handle_, + &this->overlapped_, + &unused, + FALSE); + } + this->pipe_handle_ = ACE_INVALID_HANDLE; + this->already_connected_ = 0; + } +#endif /* ACE_HAS_STREAM_PIPES */ + + return result; +} + +ACE_SPIPE_Acceptor::ACE_SPIPE_Acceptor (const ACE_SPIPE_Addr &local_sap, + int reuse_addr, + int perms, + LPSECURITY_ATTRIBUTES sa, + int pipe_mode) +{ + ACE_TRACE ("ACE_SPIPE_Acceptor::ACE_SPIPE_Acceptor"); + + if (this->open (local_sap, reuse_addr, perms, sa, pipe_mode) == -1) + ACE_ERROR ((LM_ERROR, + ACE_LIB_TEXT ("%p\n"), + ACE_LIB_TEXT ("ACE_SPIPE_Acceptor"))); +} + +// General purpose routine for accepting new connections. + +int +ACE_SPIPE_Acceptor::accept (ACE_SPIPE_Stream &new_io, + ACE_SPIPE_Addr *remote_addr, + ACE_Time_Value *timeout, + int restart, + int reset_new_handle) +{ + ACE_TRACE ("ACE_SPIPE_Acceptor::accept"); + ACE_UNUSED_ARG (reset_new_handle); + +#if defined (ACE_HAS_STREAM_PIPES) + strrecvfd r_handle; + + // Note that if THIS->MILLI_SECOND_DELAY == -1 we block on + // ACE_OS::ioctl (). Otherwise, we will wait for the desired number + // of milli seconds using ACE_OS::poll. + + if (timeout != 0 && + ACE::handle_timed_accept (this->get_handle (), + timeout, + restart) == -1) + return -1; + else if (ACE_OS::ioctl (this->get_handle (), + I_RECVFD, + &r_handle) == -1) + return -1; + + new_io.set_handle (r_handle.fd); + new_io.local_addr_ = this->local_addr_; + new_io.remote_addr_.set_size (sizeof r_handle.gid + sizeof r_handle.uid); + new_io.remote_addr_.group_id (r_handle.gid); + new_io.remote_addr_.user_id (r_handle.uid); + + // This is for compatibility with ACE_SOCK_Acceptor and + // ACE_TLI_Acceptor. + if (remote_addr != 0) + *remote_addr = new_io.remote_addr_; + + return 0; +#elif (defined (ACE_WIN32) && defined (ACE_HAS_WINNT4) && (ACE_HAS_WINNT4 != 0)) + ACE_UNUSED_ARG (restart); + ACE_UNUSED_ARG (remote_addr); + + // Check to see if we have a valid pipe + if (this->pipe_handle_ == ACE_INVALID_HANDLE) + return -1; + + // open () started the Connect in asynchronous mode. Wait for the event + // in the OVERLAPPED structure to be signalled, then grab the status. + if (this->already_connected_ == 0) + { + if (timeout != 0) + { + ACE_Time_Value abstime (ACE_OS::gettimeofday () + *timeout); + if (this->event_.wait (&abstime) == -1) + return -1; + } + else + if (this->event_.wait () == -1) + return -1; + + // Should be here with the ConnectNamedPipe operation complete. + // Steal the already_connected_ flag to record the results. + DWORD unused; + this->already_connected_ = ::GetOverlappedResult (this->pipe_handle_, + &this->overlapped_, + &unused, + FALSE); + } + + if (this->already_connected_) + { + new_io.set_handle (this->pipe_handle_); + this->pipe_handle_ = ACE_INVALID_HANDLE; + new_io.local_addr_ = this->local_addr_; + + // Create a new instance of the pipe for the next connection. + this->create_new_instance (); + return 0; + } + return -1; +#else + ACE_UNUSED_ARG (restart); + ACE_UNUSED_ARG (timeout); + ACE_UNUSED_ARG (remote_addr); + ACE_UNUSED_ARG (new_io); + ACE_NOTSUP_RETURN (-1); +#endif /* ACE_HAS_STREAM_PIPES */ +} + +ACE_END_VERSIONED_NAMESPACE_DECL |