Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

Connection_Handler.cpp

Go to the documentation of this file.
00001 #include "tao_pch.h"
00002 //$Id: Connection_Handler.cpp,v 1.1.1.2.2.4 2003/04/22 16:23:53 cleeland Exp $
00003 
00004 #include "Connection_Handler.h"
00005 #include "ORB_Core.h"
00006 #include "Server_Strategy_Factory.h"
00007 #include "debug.h"
00008 #include "Object.h"
00009 #include "Resume_Handle.h"
00010 #include "Transport.h"
00011 #include "Wait_Strategy.h"
00012 
00013 #include "ace/SOCK.h"
00014 #include "ace/Reactor.h"
00015 
00016 #if !defined (__ACE_INLINE__)
00017 #include "tao/Connection_Handler.inl"
00018 #endif /* __ACE_INLINE__ */
00019 
00020 ACE_RCSID (tao,
00021            Connection_Handler,
00022            "$Id: Connection_Handler.cpp,v 1.1.1.2.2.4 2003/04/22 16:23:53 cleeland Exp $")
00023 
00024 TAO_Connection_Handler::TAO_Connection_Handler (TAO_ORB_Core *orb_core)
00025   : orb_core_ (orb_core)
00026   , transport_ (0)
00027   , tss_resources_ (orb_core->get_tss_resources ())
00028   , reference_count_ (1)
00029 {
00030   // @@todo: We need to have a distinct option/ method in the resource
00031   // factory for this and TAO_Transport.
00032 
00033   this->refcount_lock_ =
00034     this->orb_core_->resource_factory ()->create_cached_connection_lock ();
00035 
00036   this->lock_ =
00037     this->orb_core_->resource_factory ()->create_cached_connection_lock ();
00038 
00039   // Put ourselves in the connection wait state as soon as we get
00040   // created
00041   this->state_changed (TAO_LF_Event::LFS_CONNECTION_WAIT);
00042 }
00043 
00044 
00045 TAO_Connection_Handler::~TAO_Connection_Handler (void)
00046 {
00047   ACE_ASSERT(this->transport_ == 0);
00048   ACE_ASSERT(this->reference_count_ == 0);
00049 
00050   // @@ TODO Use auto_ptr<>
00051   delete this->lock_;
00052   delete this->refcount_lock_;
00053 }
00054 
00055 
00056 int
00057 TAO_Connection_Handler::set_socket_option (ACE_SOCK &sock,
00058                                            int snd_size,
00059                                            int rcv_size)
00060 {
00061 #if !defined (ACE_LACKS_SOCKET_BUFSIZ)
00062 
00063   if (sock.set_option (SOL_SOCKET,
00064                        SO_SNDBUF,
00065                        (void *) &snd_size,
00066                        sizeof (snd_size)) == -1
00067       && errno != ENOTSUP)
00068     return -1;
00069   else if (sock.set_option (SOL_SOCKET,
00070                             SO_RCVBUF,
00071                             (void *) &rcv_size,
00072                             sizeof (int)) == -1
00073            && errno != ENOTSUP)
00074     return -1;
00075 #else
00076    ACE_UNUSED_ARG (snd_size);
00077    ACE_UNUSED_ARG (rcv_size);
00078 #endif /* !ACE_LACKS_SOCKET_BUFSIZ */
00079 
00080   (void) sock.enable (ACE_CLOEXEC);
00081   // Set the close-on-exec flag for that file descriptor. If the
00082   // operation fails we are out of luck (some platforms do not support
00083   // it and return -1).
00084 
00085   return 0;
00086 }
00087 
00088 int
00089 TAO_Connection_Handler::svc_i (void)
00090 {
00091   int result = 0;
00092 
00093   // Inheriting the ORB_Core tss stuff from the parent thread.
00094   this->orb_core_->inherit_from_parent_thread (this->tss_resources_);
00095 
00096   if (TAO_debug_level > 0)
00097     ACE_DEBUG ((LM_DEBUG,
00098                 ACE_TEXT ("TAO (%P|%t) TAO_Connection_Handler::svc_i begin\n")));
00099 
00100   // Here we simply synthesize the "typical" event loop one might find
00101   // in a reactive handler, except that this can simply block waiting
00102   // for input.
00103 
00104   ACE_Time_Value *max_wait_time = 0;
00105   ACE_Time_Value timeout;
00106   ACE_Time_Value current_timeout;
00107 
00108   if (this->orb_core_->thread_per_connection_timeout (timeout))
00109     {
00110       current_timeout = timeout;
00111       max_wait_time = &current_timeout;
00112     }
00113 
00114   TAO_Resume_Handle rh (this->orb_core_,
00115                         ACE_INVALID_HANDLE);
00116 
00117   while (!this->orb_core_->has_shutdown ()
00118          && result >= 0)
00119     {
00120       result =
00121         this->transport ()->handle_input_i (rh,
00122                                             max_wait_time);
00123 
00124       if (result == -1 && errno == ETIME)
00125         {
00126           // Ignore timeouts, they are only used to wake up and
00127           // shutdown.
00128           result = 0;
00129 
00130           // Reset errno to make sure we don't trip over an old value
00131           // of errno in case it is not reset when the recv() call
00132           // fails if the socket has been closed.
00133           errno = 0;
00134         }
00135 
00136       current_timeout = timeout;
00137 
00138       if (TAO_debug_level > 0)
00139         ACE_DEBUG ((LM_DEBUG,
00140                     "TAO (%P|%t) - Connection_Handler::svc_i - "
00141                     "loop <%d>\n", current_timeout.msec ()));
00142     }
00143 
00144   if (TAO_debug_level > 0)
00145     ACE_DEBUG  ((LM_DEBUG,
00146                  "TAO (%P|%t) - Connection_Handler::svc_i end\n"));
00147 
00148   return result;
00149 }
00150 
00151 void
00152 TAO_Connection_Handler::transport (TAO_Transport* transport)
00153 {
00154   // The transport can be reset, but not changed!
00155   ACE_ASSERT(this->transport_ == 0 || transport == 0);
00156 
00157   TAO_Transport * tmp = 0;
00158   {
00159     // Make the change atomic
00160     ACE_GUARD (ACE_Lock, ace_mon, *this->lock_);
00161     tmp = this->transport_;
00162     this->transport_ = TAO_Transport::_duplicate (transport);
00163   }
00164 
00165   if (tmp != 0) {
00166     tmp->connection_handler_closing ();
00167     TAO_Transport::release (tmp);
00168   }
00169 }
00170 
00171 long
00172 TAO_Connection_Handler::incr_refcount (void)
00173 {
00174   ACE_GUARD_RETURN (ACE_Lock, ace_mon, *this->refcount_lock_, -1);
00175 
00176   ACE_ASSERT(this->reference_count_ > 0);
00177   return ++this->reference_count_;
00178 }
00179 
00180 long
00181 TAO_Connection_Handler::decr_refcount (void)
00182 {
00183   {
00184     ACE_GUARD_RETURN (ACE_Lock, ace_mon, *this->refcount_lock_, -1);
00185 
00186     if(--this->reference_count_ > 0)
00187       return this->reference_count_;
00188   }
00189 
00190   ACE_ASSERT(this->reference_count_ == 0);
00191 
00192 
00193   int r = this->release_os_resources ();
00194 
00195   if (r == -1 && TAO_debug_level)
00196     {
00197       ACE_ERROR ((LM_ERROR,
00198                   "TAO (%P|%t) - Connection_Handler::"
00199                   "decr_refcount, release_os_resources() failed %p\n"));
00200     }
00201 
00202   delete this;
00203 
00204   return 0;
00205 }
00206 
00207 void
00208 TAO_Connection_Handler::connection_close_wait (void)
00209 {
00210   ACE_GUARD (ACE_Lock, ace_mon, *this->lock_);
00211   this->state_changed (TAO_LF_Event::LFS_CONNECTION_CLOSE_WAIT);
00212 }
00213 
00214 
00215 
00216 int
00217 TAO_Connection_Handler::handle_close_eh (
00218     ACE_HANDLE handle, unsigned long reactor_mask, ACE_Event_Handler * eh)
00219 {
00220   ACE_HANDLE my_handle = eh->get_handle ();
00221 
00222   if (TAO_debug_level)
00223     {
00224       ACE_DEBUG  ((LM_DEBUG,
00225                    "TAO (%P|%t) - Connection_Handler[%d]::handle_close_eh, "
00226                    "(%d, %d)\n",
00227                    my_handle, handle, reactor_mask));
00228     }
00229 
00230   if (this->close_connection () == 0)
00231     {
00232       if (TAO_debug_level)
00233         ACE_DEBUG  ((LM_DEBUG,
00234                      "TAO (%P|%t) - Connection_Handler[%d]::"
00235                      "handle_close, connection closing or already closed\n",
00236                      my_handle));
00237       return 0;
00238     }
00239 
00240   if (TAO_debug_level)
00241     ACE_DEBUG  ((LM_DEBUG,
00242                  "TAO (%P|%t) - Connection_Handler[%d]::"
00243                  "handle_close, connection fully closed\n",
00244                  my_handle));
00245 
00246   return 0;
00247 }
00248 
00249 int
00250 TAO_Connection_Handler::handle_output_eh (
00251     ACE_HANDLE, ACE_Event_Handler * eh)
00252 {
00253   // We are going to use the transport object to write data. Just make
00254   // sure that we have transport objects to proceed. This  is
00255   // perfectly valid assert
00256   ACE_ASSERT (this->transport () != 0);
00257 
00258   // Let the transport that it is going to be used
00259   (void) this->transport ()->update_transport ();
00260 
00261   // Instantiate the resume handle here.. This will automatically
00262   // resume the handle once data is written..
00263   TAO_Resume_Handle resume_handle (this->orb_core (),
00264                                    eh->get_handle ());
00265 
00266   int return_value = 0;
00267   this->pre_io_hook (return_value);
00268   if (return_value != 0)
00269     {
00270       resume_handle.set_flag (TAO_Resume_Handle::TAO_HANDLE_LEAVE_SUSPENDED);
00271       return return_value;
00272     }
00273 
00274   return_value = this->transport ()->handle_output ();
00275 
00276   this->pos_io_hook(return_value);
00277   if (return_value != 0)
00278     {
00279       resume_handle.set_flag (TAO_Resume_Handle::TAO_HANDLE_LEAVE_SUSPENDED);
00280     }
00281 
00282   return return_value;
00283 }
00284 
00285 int
00286 TAO_Connection_Handler::handle_input_eh (
00287     ACE_HANDLE h, ACE_Event_Handler * eh)
00288 {
00289   // We are going to use the transport object to read data. Just make
00290   // sure that we have transport objects to proceed. This  is
00291   // perfectly valid assert
00292   ACE_ASSERT (this->transport () != 0);
00293 
00294   // Let the transport know that it is used
00295   (void) this->transport ()->update_transport ();
00296 
00297   // Grab the transport id now and use the cached value for printing
00298   // since the  transport could dissappear by the time the thread
00299   // returns.
00300   size_t t_id =
00301     this->transport ()->id ();
00302 
00303 
00304   // Increase the reference count on the upcall that have passed us.
00305   //
00306   // REFCNT: Matches decr_refcount() in this function...
00307   long refcount = this->incr_refcount ();
00308   ACE_ASSERT (refcount > 0);
00309 
00310   if (TAO_debug_level > 6)
00311     {
00312       ACE_HANDLE handle = eh->get_handle();
00313       ACE_DEBUG ((LM_DEBUG,
00314                   "TAO (%P|%t) - Connection_Handler[%d]::handle_input, "
00315                   "handle = %d/%d, refcount = %d\n",
00316                   t_id, handle, h, refcount));
00317     }
00318 
00319   TAO_Resume_Handle resume_handle (this->orb_core (),
00320                                    eh->get_handle ());
00321 
00322   int return_value = 0;
00323 
00324   this->pre_io_hook (return_value);
00325   if (return_value != 0)
00326     {
00327       // REFCNT: Matches incr_refcount() at the beginning...
00328       refcount = this->decr_refcount ();
00329       ACE_ASSERT (refcount >= 0);
00330       return return_value;
00331     }
00332 
00333 
00334   return_value = this->transport ()->handle_input_i (resume_handle);
00335 
00336   this->pos_io_hook(return_value);
00337 
00338   // REFCNT: Matches incr_refcount() at the beginning...
00339   refcount = this->decr_refcount ();
00340   ACE_ASSERT (refcount >= 0);
00341 
00342   if (TAO_debug_level > 6)
00343     {
00344       ACE_HANDLE handle = eh->get_handle ();
00345       ACE_DEBUG ((LM_DEBUG,
00346                   "TAO (%P|%t) Connection_Handler[%d]::handle_input, "
00347                   "handle = %d/%d, refcount = %d, retval = %d\n",
00348                   t_id, handle, h, refcount, return_value));
00349     }
00350 
00351   if (return_value != 0 || refcount == 0)
00352     {
00353       // This is really a odd case. We could have a race condition if
00354       // we dont do this. Looks like this what happens
00355       // - imagine we have more than 1 server threads
00356       // - The server has got more than one connection from the
00357       //   clients
00358       // - The clients make requests and they start dissappearing.
00359       // - The connections start getting closed
00360       // - at that point one of the server threads is woken up to
00361       //   and handle_input () is called.
00362       // - the handle_input sees no data and so is about return a -1.
00363       // - if the handle is resumed, it looks like the oen more thread
00364       //   gets access to the handle and the handle_input is called by
00365       //   another thread.
00366       // - at that point of time if the thread returning -1 to the
00367       //   reactor starts closing down the handler, bad things start
00368       //   happening.
00369       // Looks subtle though. After adding this I dont see anything
00370       // bad happenin and so let us stick with it...
00371       resume_handle.set_flag (TAO_Resume_Handle::TAO_HANDLE_LEAVE_SUSPENDED);
00372     }
00373 
00374   return return_value;
00375 }
00376 
00377 int
00378 TAO_Connection_Handler::close_connection_eh (ACE_Event_Handler * eh)
00379 {
00380   // Perform a double checked locking on the underlying ACE_HANDLE
00381   ACE_HANDLE handle = eh->get_handle ();
00382 
00383   // If the handle is ACE_INVALID_HANDLE then there is no work to be
00384   // done in this function, and we return immediately.  Returning 0
00385   // indicates the caller (handle_close() most likely), that there is
00386   // no work to be done.
00387   if (handle == ACE_INVALID_HANDLE)
00388     {
00389       return 0;
00390     }
00391 
00392   size_t id = 0;
00393   {
00394     ACE_GUARD_RETURN (ACE_Lock, ace_mon, *this->lock_, 0);
00395 
00396     handle = eh->get_handle ();
00397 
00398     // Double-checked locking.
00399     if(handle == ACE_INVALID_HANDLE)
00400       {
00401         return 0;
00402       }
00403 
00404     // Before closing the socket we need to remove ourselves from the
00405     // Reactor.  Sounds silly, as supposedly handle_close() was called
00406     // *BY* the Reactor, but the Reactor calls handle_close() with
00407     // only the masks implied by the handle_XXX() call that returned
00408     // -1, and it does *NOT* remove the Event Handler from all masks.
00409     // Furthermore, this method is also called outside the Reactor
00410     // event loop, for example, when an I/O error is detected during a
00411     // write().
00412 
00413     // The following assertion is true because:
00414     //
00415     //
00416     // 1) When a connection handler is initialized Transport is not zero
00417     //    and the handle is *NOT* ACE_INVALID_HANDLE.
00418     // 2) The code here is run only once, if we get to this point the
00419     //    handle was not ACE_INVALID_HANDLE
00420     // 3) this->transport() is only reset after we run this code
00421     //    successfully
00422     //
00423     // Or: for this code to run the handle must have changed state from
00424     // something valid to ACE_INVALID_HANDLE, and the transport() field
00425     // will not be changed before that state transition.
00426     //
00427     ACE_ASSERT (this->transport () != 0);
00428 
00429     // Save the ID for debugging messages
00430     id = this->transport()->id ();
00431     if (TAO_debug_level)
00432       {
00433         ACE_DEBUG  ((LM_DEBUG,
00434                      "TAO (%P|%t) - Connection_Handler[%d]::"
00435                      "close_connection, purging entry from cache\n",
00436                      handle));
00437       }
00438     this->transport ()->purge_entry ();
00439 
00440     // @@ This seems silly, but if we have no reason to be in the
00441     // reactor, then we dont remove ourselves.
00442     if (this->transport ()->wait_strategy ()->is_registered ())
00443       {
00444         ACE_Reactor * eh_reactor = eh->reactor ();
00445 
00446         // These checks are valid as long as the ORB_Core is not
00447         // shutdown. It is good to have these checks and they are valid
00448         // for most of the cases. Please see below for exceptions
00449         if (this->orb_core_->has_shutdown () == 0)
00450           {
00451             // The exception when these are not valid is for RTCORBA. With
00452             // RTCORBA on, you can threads in different lanes creating
00453             // handlers and registering them with reactor in those
00454             // respective lanes. These threads could then even go away
00455             // leaving the task of reclaiming these resources to the main
00456             // thread. For the main thread that takes the responsibility
00457             // of finalizing () the lanes and the pools, the calls and
00458             // comparison make no sense.
00459             ACE_Reactor * reactor =
00460               this->transport()->orb_core()->reactor ();
00461             ACE_ASSERT (eh_reactor == 0 || eh_reactor == reactor);
00462 
00463             ACE_Reactor * orb_core_reactor = this->orb_core_->reactor ();
00464             ACE_ASSERT (reactor == orb_core_reactor);
00465 
00466             if (eh_reactor == 0)
00467               eh_reactor = reactor;
00468 
00469             ACE_UNUSED_ARG (orb_core_reactor);
00470           }
00471 
00472         // The Reactor must not be null, otherwise something else is
00473         // horribly broken.
00474         ACE_ASSERT (eh_reactor != 0);
00475 
00476         if (TAO_debug_level)
00477           {
00478             ACE_DEBUG  ((LM_DEBUG,
00479                          "TAO (%P|%t) - Connection_Handler[%d]::"
00480                          "close_connection, removing from the reactor\n",
00481                          handle));
00482           }
00483 
00484         int r =
00485           eh_reactor->remove_handler (handle,
00486                                       (ACE_Event_Handler::ALL_EVENTS_MASK
00487                                        | ACE_Event_Handler::DONT_CALL));
00488         if(r == -1 && TAO_debug_level)
00489           {
00490             ACE_ERROR ((LM_ERROR,
00491                         "TAO (%P|%t) - Connection_Handler[%d]::"
00492                         "close_connection, problem in remove_handler (%d)\n",
00493                         handle, r));
00494           }
00495 
00496         // Also cancel any timers, we may create those for time-limited
00497         // buffering
00498         if (TAO_debug_level)
00499           {
00500             ACE_DEBUG  ((LM_DEBUG,
00501                          "TAO (%P|%t) - Connection_Handler[%d]::"
00502                          "close_connection, cancel all timers and refcount [%d]\n",
00503                          handle, reference_count_));
00504           }
00505         r = eh_reactor->cancel_timer (eh);
00506         if (r == -1 && TAO_debug_level)
00507           {
00508             ACE_ERROR ((LM_ERROR,
00509                         "TAO (%P|%t) - Connection_Handler[%d]::"
00510                         "close_connection, error cancelling timers\n",
00511                         handle));
00512           }
00513 
00514         // @@ This seems silly, the reactor is a much better authority to
00515         //    find out if a handle is registered...
00516         this->transport ()->wait_strategy ()->is_registered (0);
00517       }
00518 
00519     this->state_changed (TAO_LF_Event::LFS_CONNECTION_CLOSED);
00520   }
00521 
00522   ACE_ASSERT (this->transport () != 0);
00523 
00524   // Signal the transport that we will no longer have
00525   // a reference to it.  This will eventually call
00526   // TAO_Transport::release ().
00527   this->transport (0);
00528 
00529   // The Reactor (or the Connector) holds an implicit reference.
00530   // REFCNT: Matches start count
00531   // REFCNT: only this or handle_input_eh() are called
00532   long refcount = this->decr_refcount ();
00533 
00534   if (TAO_debug_level)
00535     {
00536       ACE_DEBUG  ((LM_DEBUG,
00537                    "TAO (%P|%t) - Connection_Handler[%d]::"
00538                    "close_connection, refcount = %d\n",
00539                    id, refcount));
00540     }
00541 
00542   return 1;
00543 }
00544 
00545 int
00546 TAO_Connection_Handler::release_os_resources (void)
00547 {
00548   return 0;
00549 }
00550 
00551 void
00552 TAO_Connection_Handler::pre_io_hook (int & )
00553 {
00554 }
00555 
00556 void
00557 TAO_Connection_Handler::pos_io_hook (int & )
00558 {
00559 }

Generated on Mon Jun 16 13:48:05 2003 for TAO by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002