// $Id$ #include "ace/TLI_Acceptor.h" ACE_RCSID(ace, TLI_Acceptor, "$Id$") #if defined (ACE_HAS_TLI) // Put the actual definitions of the ACE_TLI_Request and // ACE_TLI_Request_Queue classes here to hide them from clients... struct ACE_TLI_Request { struct t_call *callp_; ACE_HANDLE handle_; ACE_TLI_Request *next_; }; class ACE_TLI_Request_Queue { public: ACE_TLI_Request_Queue (void); int open (int fd, int size); int close (void); int enqueue (const char device[], int restart, int rwflag); int dequeue (ACE_TLI_Request *&ptr); int remove (int sequence_number); int is_empty (void) const; int is_full (void) const; ACE_TLI_Request *alloc (void); void free (ACE_TLI_Request *node); void dump (void) const; // Dump the state of an object. ACE_ALLOC_HOOK_DECLARE; // Declare the dynamic allocation hooks. private: int handle_; int size_; int current_count_; ACE_TLI_Request *base_; ACE_TLI_Request *tail_; ACE_TLI_Request *free_list_; }; ACE_ALLOC_HOOK_DEFINE(ACE_TLI_Request_Queue) void ACE_TLI_Request_Queue::dump (void) const { ACE_TRACE ("ACE_TLI_Request_Queue::dump"); } int ACE_TLI_Request_Queue::is_empty (void) const { ACE_TRACE ("ACE_TLI_Request_Queue::is_empty"); return this->current_count_ == 0; } int ACE_TLI_Request_Queue::is_full (void) const { ACE_TRACE ("ACE_TLI_Request_Queue::is_full"); return this->current_count_ + 1 == this->size_; // Add 1 for the dummy. } // Add a node to the free list stack. void ACE_TLI_Request_Queue::free (ACE_TLI_Request *node) { ACE_TRACE ("ACE_TLI_Request_Queue::free"); node->next_ = this->free_list_; this->free_list_ = node; } // Remove a node from the free list stack. ACE_TLI_Request * ACE_TLI_Request_Queue::alloc (void) { ACE_TRACE ("ACE_TLI_Request_Queue::alloc"); ACE_TLI_Request *temp = this->free_list_; this->free_list_ = this->free_list_->next_; return temp; } ACE_ALLOC_HOOK_DEFINE(ACE_TLI_Acceptor) void ACE_TLI_Acceptor::dump (void) const { ACE_TRACE ("ACE_TLI_Acceptor::dump"); } ACE_TLI_Acceptor::ACE_TLI_Acceptor (void) : queue_ (0) { ACE_TRACE ("ACE_TLI_Acceptor::ACE_TLI_Acceptor"); } int ACE_TLI_Request_Queue::dequeue (ACE_TLI_Request *&ptr) { ACE_TRACE ("ACE_TLI_Request_Queue::dequeue"); ptr = this->tail_->next_; this->tail_->next_ = ptr->next_; this->current_count_--; return 0; } // This is hideous... static ACE_HANDLE open_new_endpoint (ACE_HANDLE listen_handle, const char dev[], struct t_call *callp, int rwf) { ACE_TRACE ("open_new_endpoint"); #if defined (ACE_PSOS) ACE_HANDLE fd = ACE_OS::t_open ((char *) dev, S_IRUSR | S_IWUSR, 0); #else ACE_HANDLE fd = ACE_OS::t_open ((char *) dev, O_RDWR, 0); #endif /* ACE_PSOS */ if (fd == ACE_INVALID_HANDLE || ACE_OS::t_bind (fd, 0, 0) == ACE_INVALID_HANDLE) fd = ACE_INVALID_HANDLE; #if defined (I_PUSH) && !defined (ACE_HAS_FORE_ATM_XTI) else if (rwf != 0 && ACE_OS::ioctl (fd, I_PUSH, ACE_const_cast (char *, "tirdwr")) == ACE_INVALID_HANDLE) fd = ACE_INVALID_HANDLE; #endif /* I_PUSH */ if (fd == ACE_INVALID_HANDLE) ACE_OS::t_snddis (listen_handle, callp); return fd; } // Close down the acceptor and release resources. int ACE_TLI_Request_Queue::close (void) { ACE_TRACE ("ACE_TLI_Request_Queue::close"); int res = 0; for (int i = 0; i < this->size_; i++) { ACE_TLI_Request &item = this->base_[i]; item.handle_ = ACE_INVALID_HANDLE; if (ACE_OS::t_free ((char *) item.callp_, T_CALL) != 0) res = ACE_INVALID_HANDLE; } delete [] this->base_; this->base_ = 0; return res; } ACE_HANDLE ACE_TLI_Request_Queue::open (ACE_HANDLE f, int sz) { ACE_TRACE ("ACE_TLI_Request_Queue::open"); this->handle_ = f; this->size_ = sz + 1; // Add one more for the dummy node. ACE_NEW_RETURN (this->base_, ACE_TLI_Request[this->size_], ACE_INVALID_HANDLE); // Initialize the ACE_Queue and the free list. for (int i = 0; i < this->size_; i++) { ACE_TLI_Request *item = &this->base_[i]; this->free (item); item->handle_ = ACE_INVALID_HANDLE; item->callp_ = (t_call *) ACE_OS::t_alloc (this->handle_, T_CALL, T_ALL); if (item->callp_ == 0) return ACE_INVALID_HANDLE; } this->tail_ = this->alloc (); this->tail_->next_ = this->tail_; return 0; } ACE_TLI_Request_Queue::ACE_TLI_Request_Queue (void) : size_ (0), current_count_ (0), base_ (0), tail_ (0), free_list_ (0) { ACE_TRACE ("ACE_TLI_Request_Queue::ACE_TLI_Request_Queue"); } // Listen for a new connection request and allocate appropriate data // structures when one arrives. int ACE_TLI_Request_Queue::enqueue (const char device[], int restart, int rwflag) { ACE_TRACE ("ACE_TLI_Request_Queue::enqueue"); ACE_TLI_Request *temp = this->alloc (); ACE_TLI_Request &req = *this->tail_; int res; do res = ACE_OS::t_listen (this->handle_, req.callp_); while (res == ACE_INVALID_HANDLE && restart && t_errno == TSYSERR && errno == EINTR); if (res != ACE_INVALID_HANDLE) { req.handle_ = open_new_endpoint (this->handle_, device, req.callp_, rwflag); if (req.handle_ != ACE_INVALID_HANDLE) { temp->next_ = this->tail_->next_; this->tail_->next_ = temp; this->tail_ = temp; this->current_count_++; return 0; } } // Something must have gone wrong, so free up allocated space. this->free (temp); return ACE_INVALID_HANDLE; } // Locate and remove SEQUENCE_NUMBER from the list of pending // connections. int ACE_TLI_Request_Queue::remove (int sequence_number) { ACE_TRACE ("ACE_TLI_Request_Queue::remove"); ACE_TLI_Request *prev = this->tail_; // Put the sequence # in the dummy node to simply the search... prev->callp_->sequence = sequence_number; ACE_TLI_Request *temp; for (temp = this->tail_->next_; temp->callp_->sequence != sequence_number; temp = temp->next_) prev = temp; if (temp == this->tail_) // Sequence # was not found, since we're back at the dummy node! return -1; else { prev->next_ = temp->next_; ACE_OS::t_close (temp->handle_); this->current_count_--; this->free (temp); return 0; } } ACE_HANDLE ACE_TLI_Acceptor::open (const ACE_Addr &remote_sap, int reuse_addr, int oflag, struct t_info *info, int qlen, const char dev[]) { ACE_TRACE ("ACE_TLI_Acceptor::open"); int res = 0; int one = 1; this->disp_ = 0; ACE_ALLOCATOR_RETURN (this->device_, ACE_OS::strdup (dev), ACE_INVALID_HANDLE); if (this->ACE_TLI::open (dev, oflag, info) == ACE_INVALID_HANDLE) res = ACE_INVALID_HANDLE; #if !defined (ACE_HAS_FORE_ATM_XTI) // Reusing the address causes problems with FORE's API. The issue // may be that t_optmgmt isn't fully supported by FORE. t_errno is // TBADOPT after the t_optmgmt call so maybe options are configured // differently for XTI than for TLI (at least for FORE's // implementation - XTI is supposed to be a superset of TLI). else if (reuse_addr && this->set_option (SOL_SOCKET, SO_REUSEADDR, &one, sizeof one) == ACE_INVALID_HANDLE) res = ACE_INVALID_HANDLE; #endif /* ACE_HAS_FORE_ATM_XTI */ else if ((this->disp_ = (struct t_discon *) ACE_OS::t_alloc (this->get_handle (), T_DIS, T_ALL)) == 0) res = ACE_INVALID_HANDLE; else { struct t_bind req; #if defined (ACE_HAS_FORE_ATM_XTI) // Not sure why but FORE's t_bind call won't work if t_bind.qlen // != 1 Adjust the backlog accordingly. this->backlog_ = 1; req.qlen = 1; #else this->backlog_ = qlen; req.qlen = qlen; #endif /* ACE_HAS_FORE_ATM_XTI */ req.addr.maxlen = remote_sap.get_size (); if (remote_sap == ACE_Addr::sap_any) // Note that if addr.len == 0 then ACE_TLI selects the port // number. req.addr.len = 0; else { req.addr.len = remote_sap.get_size (); req.addr.buf = (char *) remote_sap.get_addr (); } res = ACE_OS::t_bind (this->get_handle (), &req, 0); if (res != ACE_INVALID_HANDLE) { ACE_NEW_RETURN (this->queue_, ACE_TLI_Request_Queue, -1); res = this->queue_->open (this->get_handle (), this->backlog_); } } if (res == ACE_INVALID_HANDLE) this->close (); return this->get_handle (); } ACE_TLI_Acceptor::ACE_TLI_Acceptor (const ACE_Addr &remote_sap, int reuse_addr, int oflag, struct t_info *info, int back, const char dev[]) { ACE_TRACE ("ACE_TLI_Acceptor::ACE_TLI_Acceptor"); if (this->open (remote_sap, reuse_addr, oflag, info, back, dev) == ACE_INVALID_HANDLE) ACE_ERROR ((LM_ERROR, ASYS_TEXT ("%p\n"), ASYS_TEXT ("ACE_TLI_Acceptor::ACE_TLI_Acceptor"))); } int ACE_TLI_Acceptor::close (void) { ACE_TRACE ("ACE_TLI_Acceptor::close"); if (this->device_ != 0) { if (this->queue_ != 0) { this->queue_->close (); delete this->queue_; } ACE_OS::t_free ((char *) this->disp_, T_DIS); ACE_OS::free (ACE_MALLOC_T (this->device_)); this->disp_ = 0; this->device_ = 0; return this->ACE_TLI::close (); } return 0; } // Perform the logic required to handle the arrival of asynchronous // events while we are trying to accept a new connection request. int ACE_TLI_Acceptor::handle_async_event (int restart, int rwf) { ACE_TRACE ("ACE_TLI_Acceptor::handle_async_event"); int event = this->look (); switch (event) { case T_DISCONNECT: this->rcvdis (this->disp_); this->queue_->remove (this->disp_->sequence); break; case T_LISTEN: this->queue_->enqueue (this->device_, restart, rwf); break; default: return -1; } return 0; } int ACE_TLI_Acceptor::accept (ACE_TLI_Stream &new_tli_sap, ACE_Addr *remote_addr, ACE_Time_Value *timeout, int restart, int reset_new_handle, int rwf, netbuf *udata, netbuf *opt) { ACE_TRACE ("ACE_TLI_Acceptor::accept"); ACE_UNUSED_ARG (reset_new_handle); ACE_TLI_Request *req = 0; int res = 0; if (timeout != 0 && ACE::handle_timed_accept (this->get_handle (), timeout, restart) == -1) return -1; else if (this->queue_->is_empty ()) { req = this->queue_->alloc (); do res = ACE_OS::t_listen (this->get_handle (), req->callp_); while (res == ACE_INVALID_HANDLE && restart && errno == EINTR); if (res != ACE_INVALID_HANDLE) res = req->handle_ = open_new_endpoint (this->get_handle (), this->device_, req->callp_, rwf); } else res = this->queue_->dequeue (req); if (udata != 0) ACE_OS::memcpy ((void *) &req->callp_->udata, (void *) udata, sizeof *udata); if (opt != 0) ACE_OS::memcpy ((void *) &req->callp_->opt, (void *) opt, sizeof *opt); while (res != ACE_INVALID_HANDLE) if ((res = ACE_OS::t_accept (this->get_handle (), req->handle_, req->callp_)) != ACE_INVALID_HANDLE) break; // Got one! else if (t_errno == TLOOK) res = this->handle_async_event (restart, rwf); else if (restart && t_errno == TSYSERR && errno == EINTR) res = 0; if (res == ACE_INVALID_HANDLE) { if (errno != EWOULDBLOCK) { new_tli_sap.set_handle (ACE_INVALID_HANDLE); if (req->handle_ != ACE_INVALID_HANDLE) ACE_OS::t_close (req->handle_); } } else { new_tli_sap.set_handle (req->handle_); if (remote_addr != 0) remote_addr->set_addr ((void *) req->callp_->addr.buf, req->callp_->addr.len); } req->handle_ = ACE_INVALID_HANDLE; this->queue_->free (req); new_tli_sap.set_rwflag (rwf); return new_tli_sap.get_handle () == ACE_INVALID_HANDLE ? -1 : 0; } #endif /* ACE_HAS_TLI */