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 79159 2007-08-01 16:41:24Z wilsond $")
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   , messaging_object_ (0)
00032 {
00033   // Use the normal GIOP object
00034   ACE_NEW (this->messaging_object_,
00035            TAO_GIOP_Message_Base (orb_core, this));
00036 }
00037 
00038 TAO_IIOP_Transport::~TAO_IIOP_Transport (void)
00039 {
00040   delete this->messaging_object_;
00041 }
00042 
00043 /*
00044  * Hook to copy over all concrete implementations
00045  * of Transport class from this class to the base
00046  * class as a part of the specialization.
00047  * All enhancements to the IIOP_Transport
00048  * class, i.e., addition of new concrete non virtual
00049  * methods should be added within this hook.
00050  */
00051 
00052 //@@ TAO_TRANSPORT_SPL_COPY_HOOK_START
00053 ACE_Event_Handler *
00054 TAO_IIOP_Transport::event_handler_i (void)
00055 {
00056   return this->connection_handler_;
00057 }
00058 
00059 TAO_Connection_Handler *
00060 TAO_IIOP_Transport::connection_handler_i (void)
00061 {
00062   return this->connection_handler_;
00063 }
00064 
00065 TAO_Pluggable_Messaging *
00066 TAO_IIOP_Transport::messaging_object (void)
00067 {
00068   return this->messaging_object_;
00069 }
00070 
00071 ssize_t
00072 TAO_IIOP_Transport::send (iovec *iov, int iovcnt,
00073                           size_t &bytes_transferred,
00074                           const ACE_Time_Value *max_wait_time)
00075 {
00076   ssize_t const retval =
00077     this->connection_handler_->peer ().sendv (iov,
00078                                               iovcnt,
00079                                               max_wait_time);
00080 
00081   if (retval > 0)
00082     bytes_transferred = retval;
00083   else
00084     {
00085       if (TAO_debug_level > 4)
00086         {
00087           ACE_DEBUG ((LM_DEBUG,
00088                       ACE_TEXT ("TAO (%P|%t) - IIOP_Transport[%d]::send, ")
00089                       ACE_TEXT ("send failure - %m (errno: %d)\n"),
00090                       this->id (), errno));
00091         }
00092     }
00093 
00094   return retval;
00095 }
00096 
00097 #if TAO_HAS_SENDFILE == 1
00098 ssize_t
00099 TAO_IIOP_Transport::sendfile (TAO_MMAP_Allocator * allocator,
00100                               iovec * iov,
00101                               int iovcnt,
00102                               size_t &bytes_transferred,
00103                               ACE_Time_Value const * timeout)
00104 {
00105   // @@ We should probably set the TCP_CORK socket option to minimize
00106   //    network operations.  It may also be useful to adjust the
00107   //    socket send buffer size accordingly.
00108 
00109   // If we don't have an allocator, fallback to the regular way of sending
00110   // data
00111   if (allocator == 0)
00112     return this->send (iov, iovcnt, bytes_transferred, timeout);
00113 
00114   // We can only use sendfile when all data is coming from the mmap allocator,
00115   // if not, we just fallback to to the regular way of sending data
00116   iovec * const off_check_begin = iov;
00117   iovec * const off_check_end   = iov + iovcnt;
00118   for (iovec * index = off_check_begin; index != off_check_end; ++index)
00119     {
00120       if (-1 == allocator->offset (index->iov_base))
00121         return this->send (iov, iovcnt, bytes_transferred, timeout);
00122     }
00123 
00124   ssize_t retval = -1;
00125 
00126   ACE_HANDLE const in_fd = allocator->handle ();
00127 
00128   if (in_fd == ACE_INVALID_HANDLE)
00129     return retval;
00130 
00131   ACE_HANDLE const out_fd =
00132     this->connection_handler_->peer ().get_handle ();
00133 
00134   iovec * const begin = iov;
00135   iovec * const end   = iov + iovcnt;
00136   for (iovec * i = begin; i != end; ++i)
00137     {
00138       off_t offset = allocator->offset (i->iov_base);
00139 
00140       if (timeout)
00141         {
00142           int val = 0;
00143           if (ACE::enter_send_timedwait (out_fd, timeout, val) == -1)
00144             return retval;
00145           else
00146             {
00147               retval =
00148                 ACE_OS::sendfile (out_fd, in_fd, &offset, i->iov_len);
00149               ACE::restore_non_blocking_mode (out_fd, val);
00150 
00151             }
00152         }
00153       else
00154         {
00155           retval = ACE_OS::sendfile (out_fd, in_fd, &offset, i->iov_len);
00156         }
00157 
00158       if (retval <= 0)  // Report errors below.
00159         break;
00160 
00161       bytes_transferred += static_cast<size_t> (retval);
00162     }
00163 
00164   if (retval <= 0 && TAO_debug_level > 4)
00165     {
00166       ACE_DEBUG ((LM_DEBUG,
00167                   ACE_TEXT ("TAO (%P|%t) - IIOP_Transport[%d]::sendfile, ")
00168                   ACE_TEXT ("sendfile failure - %m (errno: %d)\n"),
00169                   this->id (),
00170                   errno));
00171     }
00172 
00173   return retval;
00174 }
00175 #endif  /* TAO_HAS_SENDFILE==1 */
00176 
00177 ssize_t
00178 TAO_IIOP_Transport::recv (char *buf,
00179                           size_t len,
00180                           const ACE_Time_Value *max_wait_time)
00181 {
00182   ssize_t const n = this->connection_handler_->peer ().recv (buf,
00183                                                              len,
00184                                                              max_wait_time);
00185 
00186   // Do not print the error message if it is a timeout, which could
00187   // occur in thread-per-connection.
00188   if (n == -1 &&
00189       TAO_debug_level > 4 &&
00190       errno != ETIME)
00191     {
00192 
00193       ACE_DEBUG ((LM_DEBUG,
00194                   ACE_TEXT ("TAO (%P|%t) - IIOP_Transport[%d]::recv, ")
00195                   ACE_TEXT ("read failure - %m errno %d\n"),
00196                   this->id (),
00197                   errno));
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 Sun Jan 27 13:07:33 2008 for TAO by doxygen 1.3.6