IIOP_Transport.cpp

Go to the documentation of this file.
00001 #include "tao/IIOP_Transport.h"
00002 
00003 #if defined (TAO_HAS_IIOP) && (TAO_HAS_IIOP != 0)
00004 
00005 #include "tao/IIOP_Acceptor.h"
00006 #include "tao/IIOPC.h"
00007 #include "tao/Acceptor_Registry.h"
00008 #include "tao/operation_details.h"
00009 #include "tao/Wait_Strategy.h"
00010 #include "tao/debug.h"
00011 #include "tao/GIOP_Message_Base.h"
00012 #include "tao/Protocols_Hooks.h"
00013 #include "tao/ORB_Core.h"
00014 #include "tao/Thread_Lane_Resources.h"
00015 #include "tao/Transport_Mux_Strategy.h"
00016 #include "tao/MMAP_Allocator.h"
00017 
00018 #include "ace/OS_NS_sys_sendfile.h"
00019 
00020 ACE_RCSID (tao,
00021            IIOP_Transport,
00022            "IIOP_Transport.cpp,v 1.141 2006/06/20 06:03:47 jwillemsen Exp")
00023 
00024 TAO_BEGIN_VERSIONED_NAMESPACE_DECL
00025 
00026 TAO_IIOP_Transport::TAO_IIOP_Transport (TAO_IIOP_Connection_Handler *handler,
00027                                         TAO_ORB_Core *orb_core,
00028                                         CORBA::Boolean )
00029   : TAO_Transport (IOP::TAG_INTERNET_IOP,
00030                    orb_core)
00031   , connection_handler_ (handler)
00032   , messaging_object_ (0)
00033 {
00034   // Use the normal GIOP object
00035   ACE_NEW (this->messaging_object_,
00036            TAO_GIOP_Message_Base (orb_core, this));
00037 }
00038 
00039 TAO_IIOP_Transport::~TAO_IIOP_Transport (void)
00040 {
00041   delete this->messaging_object_;
00042 }
00043 
00044 /*
00045  * Hook to copy over all concrete implementations
00046  * of Transport class from this class to the base
00047  * class as a part of the specialization.
00048  * All enhancements to the IIOP_Transport
00049  * class, i.e., addition of new concrete non virtual
00050  * methods should be added within this hook.
00051  */
00052 
00053 //@@ TAO_TRANSPORT_SPL_COPY_HOOK_START
00054 ACE_Event_Handler *
00055 TAO_IIOP_Transport::event_handler_i (void)
00056 {
00057   return this->connection_handler_;
00058 }
00059 
00060 TAO_Connection_Handler *
00061 TAO_IIOP_Transport::connection_handler_i (void)
00062 {
00063   return this->connection_handler_;
00064 }
00065 
00066 TAO_Pluggable_Messaging *
00067 TAO_IIOP_Transport::messaging_object (void)
00068 {
00069   return this->messaging_object_;
00070 }
00071 
00072 ssize_t
00073 TAO_IIOP_Transport::send (iovec *iov, int iovcnt,
00074                           size_t &bytes_transferred,
00075                           const ACE_Time_Value *max_wait_time)
00076 {
00077   ssize_t const retval =
00078     this->connection_handler_->peer ().sendv (iov,
00079                                               iovcnt,
00080                                               max_wait_time);
00081 
00082   if (retval > 0)
00083     bytes_transferred = retval;
00084   else
00085     {
00086       if (TAO_debug_level > 4)
00087         {
00088           ACE_DEBUG ((LM_DEBUG,
00089                       ACE_TEXT ("TAO (%P|%t) - IIOP_Transport[%d]::send, ")
00090                       ACE_TEXT ("send failure - %m (errno: %d)\n"),
00091                       this->id (), errno));
00092         }
00093     }
00094 
00095   return retval;
00096 }
00097 
00098 #ifdef ACE_HAS_SENDFILE
00099 ssize_t
00100 TAO_IIOP_Transport::sendfile (TAO_MMAP_Allocator * allocator,
00101                               iovec * iov,
00102                               int iovcnt,
00103                               size_t &bytes_transferred,
00104                               ACE_Time_Value const * timeout)
00105 {
00106   // @@ We should probably set the TCP_CORK socket option to minimize
00107   //    network operations.  It may also be useful to adjust the
00108   //    socket send buffer size accordingly.
00109 
00110   // If we don't have an allocator, fallback to the regular way of sending
00111   // data
00112   if (allocator == 0)
00113     return this->send (iov, iovcnt, bytes_transferred, timeout);
00114 
00115   // We can only use sendfile when all data is coming from the mmap allocator,
00116   // if not, we just fallback to to the regular way of sending data
00117   iovec * const off_check_begin = iov;
00118   iovec * const off_check_end   = iov + iovcnt;
00119   for (iovec * index = off_check_begin; index != off_check_end; ++index)
00120     {
00121       if (-1 == allocator->offset (index->iov_base))
00122         return this->send (iov, iovcnt, bytes_transferred, timeout);
00123     }
00124 
00125   ssize_t retval = -1;
00126 
00127   ACE_HANDLE const in_fd = allocator->handle ();
00128 
00129   if (in_fd == ACE_INVALID_HANDLE)
00130     return retval;
00131 
00132   ACE_HANDLE const out_fd =
00133     this->connection_handler_->peer ().get_handle ();
00134 
00135   iovec * const begin = iov;
00136   iovec * const end   = iov + iovcnt;
00137   for (iovec * i = begin; i != end; ++i)
00138     {
00139       off_t offset = allocator->offset (i->iov_base);
00140 
00141       if (timeout)
00142         {
00143           int val = 0;
00144           if (ACE::enter_send_timedwait (out_fd, timeout, val) == -1)
00145             return retval;
00146           else
00147             {
00148               retval =
00149                 ACE_OS::sendfile (out_fd, in_fd, &offset, i->iov_len);
00150               ACE::restore_non_blocking_mode (out_fd, val);
00151 
00152             }
00153         }
00154       else
00155         {
00156           retval = ACE_OS::sendfile (out_fd, in_fd, &offset, i->iov_len);
00157         }
00158 
00159       if (retval <= 0)  // Report errors below.
00160         break;
00161 
00162       bytes_transferred += static_cast<size_t> (retval);
00163     }
00164 
00165   if (retval <= 0 && TAO_debug_level > 4)
00166     {
00167       ACE_DEBUG ((LM_DEBUG,
00168                   ACE_TEXT ("TAO (%P|%t) - IIOP_Transport[%d]::sendfile, ")
00169                   ACE_TEXT ("sendfile failure - %m (errno: %d)\n"),
00170                   this->id (),
00171                   errno));
00172     }
00173 
00174   return retval;
00175 }
00176 #endif  /* ACE_HAS_SENDFILE */
00177 
00178 ssize_t
00179 TAO_IIOP_Transport::recv (char *buf,
00180                           size_t len,
00181                           const ACE_Time_Value *max_wait_time)
00182 {
00183   ssize_t const n = this->connection_handler_->peer ().recv (buf,
00184                                                              len,
00185                                                              max_wait_time);
00186 
00187   // Do not print the error message if it is a timeout, which could
00188   // occur in thread-per-connection.
00189   if (n == -1 &&
00190       TAO_debug_level > 4 &&
00191       errno != ETIME)
00192     {
00193 
00194       ACE_DEBUG ((LM_DEBUG,
00195                   ACE_TEXT ("TAO (%P|%t) - IIOP_Transport[%d]::recv, ")
00196                   ACE_TEXT ("read failure - %m\n"),
00197                   this->id ()));
00198     }
00199 
00200   // Error handling
00201   if (n == -1)
00202     {
00203       if (errno == EWOULDBLOCK)
00204         return 0;
00205 
00206       return -1;
00207     }
00208 
00209   // Most of the errors handling is common for
00210   // Now the message has been read
00211 
00212   // @@ What are the other error handling here??
00213   else if (n == 0)
00214     {
00215       return -1;
00216     }
00217 
00218   return n;
00219 }
00220 
00221 int
00222 TAO_IIOP_Transport::send_request (TAO_Stub *stub,
00223                                   TAO_ORB_Core *orb_core,
00224                                   TAO_OutputCDR &stream,
00225                                   int message_semantics,
00226                                   ACE_Time_Value *max_wait_time)
00227 {
00228   if (this->ws_->sending_request (orb_core,
00229                                   message_semantics) == -1)
00230 
00231     return -1;
00232 
00233   if (this->send_message (stream,
00234                           stub,
00235                           message_semantics,
00236                           max_wait_time) == -1)
00237     return -1;
00238 
00239   this->first_request_sent();
00240 
00241   return 0;
00242 }
00243 
00244 int
00245 TAO_IIOP_Transport::send_message (TAO_OutputCDR &stream,
00246                                   TAO_Stub *stub,
00247                                   int message_semantics,
00248                                   ACE_Time_Value *max_wait_time)
00249 {
00250   // Format the message in the stream first
00251   if (this->messaging_object_->format_message (stream) != 0)
00252     return -1;
00253 
00254   // This guarantees to send all data (bytes) or return an error.
00255   ssize_t const n = this->send_message_shared (stub,
00256                                                message_semantics,
00257                                                stream.begin (),
00258                                                max_wait_time);
00259 
00260   if (n == -1)
00261     {
00262       // Dont try to be smart and request for %p in the debug
00263       // statement.  If the event handler is destroyed the transport
00264       // would return -1 with errno set to ENOENT. %p then would dump
00265       // a core. %m would then be softer on this.
00266       if (TAO_debug_level)
00267         ACE_DEBUG ((LM_DEBUG,
00268                     ACE_TEXT ("TAO (%P|%t) - IIOP_Transport[%d]::send_message, ")
00269                     ACE_TEXT ("write failure - %m\n"),
00270                     this->id ()));
00271       return -1;
00272     }
00273 
00274   return 1;
00275 }
00276 
00277 int
00278 TAO_IIOP_Transport::send_message_shared (
00279   TAO_Stub *stub,
00280   int message_semantics,
00281   const ACE_Message_Block *message_block,
00282   ACE_Time_Value *max_wait_time)
00283 {
00284   int r;
00285 
00286   {
00287     ACE_GUARD_RETURN (ACE_Lock, ace_mon, *this->handler_lock_, -1);
00288 
00289     r = this->send_message_shared_i (stub, message_semantics,
00290                                      message_block, max_wait_time);
00291   }
00292 
00293   if (r == -1)
00294     {
00295       this->close_connection ();
00296     }
00297 
00298   return r;
00299 }
00300 
00301 int
00302 TAO_IIOP_Transport::generate_request_header (TAO_Operation_Details &opdetails,
00303                                              TAO_Target_Specification &spec,
00304                                              TAO_OutputCDR &msg)
00305 {
00306   // Check whether we have a Bi Dir IIOP policy set, whether the
00307   // messaging objects are ready to handle bidirectional connections
00308   // and also make sure that we have not recd. or sent any information
00309   // regarding this before...
00310   if (this->orb_core ()->bidir_giop_policy () &&
00311       this->messaging_object_->is_ready_for_bidirectional (msg) &&
00312       this->bidirectional_flag () < 0)
00313     {
00314       this->set_bidir_context_info (opdetails);
00315 
00316       // Set the flag to 1 (i.e., originating side)
00317       this->bidirectional_flag (1);
00318 
00319       // At the moment we enable BiDIR giop we have to get a new
00320       // request id to make sure that we follow the even/odd rule
00321       // for request id's. We only need to do this when enabled
00322       // it, after that the Transport Mux Strategy will make sure
00323       // that the rule is followed
00324       opdetails.request_id (this->tms ()->request_id ());
00325     }
00326 
00327   return TAO_Transport::generate_request_header (opdetails,
00328                                                  spec,
00329                                                  msg);
00330 }
00331 
00332 int
00333 TAO_IIOP_Transport::messaging_init (CORBA::Octet major,
00334                                     CORBA::Octet minor)
00335 {
00336   this->messaging_object_->init (major, minor);
00337 
00338   return 1;
00339 }
00340 
00341 int
00342 TAO_IIOP_Transport::tear_listen_point_list (TAO_InputCDR &cdr)
00343 {
00344   CORBA::Boolean byte_order;
00345   if ((cdr >> ACE_InputCDR::to_boolean (byte_order)) == 0)
00346     return -1;
00347 
00348   cdr.reset_byte_order (static_cast<int> (byte_order));
00349 
00350   IIOP::ListenPointList listen_list;
00351   if ((cdr >> listen_list) == 0)
00352     return -1;
00353 
00354   // As we have received a bidirectional information, set the flag to
00355   // 0 (i.e., non-originating side)
00356   this->bidirectional_flag (0);
00357 
00358   return this->connection_handler_->process_listen_point_list (listen_list);
00359 }
00360 
00361 void
00362 TAO_IIOP_Transport::set_bidir_context_info (TAO_Operation_Details &opdetails)
00363 {
00364   // Get a handle to the acceptor registry
00365   TAO_Acceptor_Registry &ar =
00366     this->orb_core ()->lane_resources ().acceptor_registry ();
00367 
00368   IIOP::ListenPointList listen_point_list;
00369 
00370   const TAO_AcceptorSetIterator end = ar.end ();
00371 
00372   for (TAO_AcceptorSetIterator acceptor = ar.begin ();
00373        acceptor != end;
00374        ++acceptor)
00375     {
00376       // Check whether it is an IIOP acceptor
00377       if ((*acceptor)->tag () == IOP::TAG_INTERNET_IOP)
00378         {
00379           if (this->get_listen_point (listen_point_list, *acceptor) == -1)
00380             {
00381               if (TAO_debug_level > 0)
00382                 ACE_ERROR ((LM_ERROR,
00383                             "TAO (%P|%t) - IIOP_Transport::set_bidir_context_info, "
00384                             "error getting listen_point\n"));
00385 
00386               return;
00387             }
00388         }
00389     }
00390 
00391   if (listen_point_list.length () == 0)
00392     {
00393       if (TAO_debug_level > 0)
00394         ACE_ERROR ((LM_ERROR,
00395                     "TAO (%P|%t) - IIOP_Transport::set_bidir_context_info, "
00396                     "listen_point list is empty, client should send a list "
00397                     "with at least one point\n"));
00398 
00399       return;
00400     }
00401 
00402   // We have the ListenPointList at this point. Create a output CDR
00403   // stream at this point
00404   TAO_OutputCDR cdr;
00405 
00406   // Marshal the information into the stream
00407   if ((cdr << ACE_OutputCDR::from_boolean (TAO_ENCAP_BYTE_ORDER) == 0)
00408       || (cdr << listen_point_list) == 0)
00409     return;
00410 
00411   // Add this info in to the svc_list
00412   opdetails.request_service_context ().set_context (IOP::BI_DIR_IIOP,
00413                                                     cdr);
00414 
00415   return;
00416 }
00417 
00418 int
00419 TAO_IIOP_Transport::get_listen_point (
00420     IIOP::ListenPointList &listen_point_list,
00421     TAO_Acceptor *acceptor)
00422 {
00423   TAO_IIOP_Acceptor *iiop_acceptor =
00424     dynamic_cast<TAO_IIOP_Acceptor *> (acceptor);
00425 
00426   if (iiop_acceptor == 0)
00427     return -1;
00428 
00429   // Get the array of endpoints serviced by TAO_IIOP_Acceptor
00430   const ACE_INET_Addr *endpoint_addr =
00431     iiop_acceptor->endpoints ();
00432 
00433   // Get the endpoint count
00434   size_t const count =
00435     iiop_acceptor->endpoint_count ();
00436 
00437   // Get the local address of the connection
00438   ACE_INET_Addr local_addr;
00439 
00440   if (this->connection_handler_->peer ().get_local_addr (local_addr)
00441       == -1)
00442     {
00443       ACE_ERROR_RETURN ((LM_ERROR,
00444                          ACE_TEXT ("TAO (%P|%t) - IIOP_Transport::get_listen_point, ")
00445                          ACE_TEXT ("could not resolve local host address\n")),
00446                         -1);
00447     }
00448 
00449   // Note: Looks like there is no point in sending the list of
00450   // endpoints on interfaces on which this connection has not
00451   // been established. If this is wrong, please correct me.
00452   CORBA::String_var local_interface;
00453 
00454   // Get the hostname for the local address
00455   if (iiop_acceptor->hostname (this->orb_core_,
00456                                local_addr,
00457                                local_interface.out ()) == -1)
00458     {
00459       ACE_ERROR_RETURN ((LM_ERROR,
00460                          ACE_TEXT ("TAO (%P|%t) - IIOP_Transport::get_listen_point, ")
00461                          ACE_TEXT ("could not resolve local host name\n")),
00462                         -1);
00463     }
00464 #if defined (ACE_HAS_IPV6)
00465   // If this is an IPv6 decimal linklocal address containing a scopeid than
00466   // remove the scopeid from the information being sent.
00467   const char *cp_scope = 0;
00468   if (local_addr.get_type () == PF_INET6 &&
00469         (cp_scope = ACE_OS::strchr (local_interface.in (), '%')) != 0)
00470     {
00471       CORBA::ULong len = cp_scope - local_interface.in ();
00472       local_interface[len] = '\0';
00473     }
00474 #endif /* ACE_HAS_IPV6 */
00475 
00476   for (size_t index = 0;
00477        index < count;
00478        ++index)
00479     {
00480       // Make sure port numbers are equal so the following comparison
00481       // only concerns the IP(v4/v6) address.
00482       local_addr.set_port_number (endpoint_addr[index].get_port_number ());
00483 
00484       if (local_addr == endpoint_addr[index])
00485         {
00486           // Get the count of the number of elements
00487           const CORBA::ULong len = listen_point_list.length ();
00488 
00489           // Increase the length by 1
00490           listen_point_list.length (len + 1);
00491 
00492           // We have the connection and the acceptor endpoint on the
00493           // same interface
00494           IIOP::ListenPoint & point = listen_point_list[len];
00495           point.host = CORBA::string_dup (local_interface.in ());
00496           point.port = endpoint_addr[index].get_port_number ();
00497 
00498           if (TAO_debug_level >= 5)
00499           {
00500             ACE_DEBUG ((LM_DEBUG,
00501                         ACE_TEXT("TAO (%P|%t) - Listen_Point_List[%d] = <%s:%d>\n"),
00502                         len,
00503                         point.host.in (),
00504                         point.port));
00505           }
00506 
00507         }
00508     }
00509 
00510   return 1;
00511 }
00512 //@@ TAO_TRANSPORT_SPL_COPY_HOOK_END
00513 /*
00514  * End of copy hook.
00515  */
00516 
00517 TAO_END_VERSIONED_NAMESPACE_DECL
00518 
00519 #endif /* TAO_HAS_IIOP && TAO_HAS_IIOP != 0 */

Generated on Thu Nov 9 11:54:13 2006 for TAO by doxygen 1.3.6