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

Generated on Tue Feb 2 17:37:52 2010 for TAO by  doxygen 1.4.7