00001 // -*- C++ -*- 00002 00003 //============================================================================= 00004 /** 00005 * @file Transport.h 00006 * 00007 * $Id: Transport.h 85817 2009-06-26 20:44:58Z mitza $ 00008 * 00009 * Define the interface for the Transport component in TAO's 00010 * pluggable protocol framework. 00011 * 00012 * @author Fred Kuhns <fredk@cs.wustl.edu> 00013 */ 00014 //============================================================================= 00015 00016 #ifndef TAO_TRANSPORT_H 00017 #define TAO_TRANSPORT_H 00018 00019 #include /**/ "ace/pre.h" 00020 00021 #include "tao/Transport_Cache_Manager.h" 00022 00023 #if !defined (ACE_LACKS_PRAGMA_ONCE) 00024 # pragma once 00025 #endif /* ACE_LACKS_PRAGMA_ONCE */ 00026 00027 #include "tao/Transport_Timer.h" 00028 #include "tao/Incoming_Message_Queue.h" 00029 #include "tao/Incoming_Message_Stack.h" 00030 #include "tao/Message_Semantics.h" 00031 #include "ace/Time_Value.h" 00032 #include "ace/Basic_Stats.h" 00033 #include "ace/Copy_Disabled.h" 00034 00035 struct iovec; 00036 00037 TAO_BEGIN_VERSIONED_NAMESPACE_DECL 00038 00039 class TAO_ORB_Core; 00040 class TAO_Target_Specification; 00041 class TAO_Operation_Details; 00042 class TAO_Transport_Mux_Strategy; 00043 class TAO_Wait_Strategy; 00044 class TAO_Connection_Handler; 00045 class TAO_GIOP_Message_Base; 00046 class TAO_Codeset_Translator_Base; 00047 00048 class TAO_Queued_Message; 00049 class TAO_Synch_Queued_Message; 00050 class TAO_Resume_Handle; 00051 class TAO_Stub; 00052 class TAO_MMAP_Allocator; 00053 00054 namespace TAO 00055 { 00056 /** 00057 * @note Should this be in TAO namespace. Seems like a candidate 00058 * that should be in the transport 00059 */ 00060 enum Connection_Role 00061 { 00062 TAO_UNSPECIFIED_ROLE = 0, 00063 TAO_SERVER_ROLE = 1, 00064 TAO_CLIENT_ROLE = 2 00065 }; 00066 00067 namespace Transport 00068 { 00069 /// Transport-level statistics. Initially introduced to support 00070 /// the "Transport Current" functionality. 00071 class Stats; 00072 00073 /** 00074 * @struct Drain_Constraints 00075 * 00076 * @brief Encapsulate the flushing control parameters. 00077 * 00078 * At several points, the ORB needs to flush data from a transport to the 00079 * underlying I/O mechanisms. How this data is flushed depends on the 00080 * context where the request is made, the ORB configuration and the 00081 * application level policies in effect. 00082 * 00083 * Some examples: 00084 * 00085 * # When idle, the ORB will want to send data on any socket that has 00086 * space available. In this case, the queue must be drained on 00087 * a best-effort basis, without any blocking. 00088 * # If the ORB is configured to handle nested upcalls, any two-way 00089 * request should block and push data to the underlying socket as fast 00090 * as possible. 00091 * # In the same use-case, but now with a timeout policy in 00092 * effect, the ORB will need to send the data use I/O operations with 00093 * timeouts (as implemented by ACE::sendv() 00094 * # When the ORB is configured to support nested upcalls, any two-way, 00095 * reliable oneway or similar should wait using the reactor or 00096 * Leader-Follower implementation. While still respecting the timeout 00097 * policies. 00098 * 00099 * Instead of sprinkling if() statements throughput the critical path 00100 * trying to determine how the I/O operations should be performed, we 00101 * pass the information encapsulated in this class. The caller into the 00102 * Transport object determines the right parameters to use, and the 00103 * Transport object simply obeys those instructions. 00104 */ 00105 class Drain_Constraints : private ACE_Copy_Disabled 00106 { 00107 public: 00108 /// Default constructor 00109 Drain_Constraints() 00110 : timeout_(0) 00111 , block_on_io_(false) 00112 { 00113 } 00114 00115 /// Constructor 00116 Drain_Constraints( 00117 ACE_Time_Value * timeout, 00118 bool block_on_io) 00119 : timeout_(timeout) 00120 , block_on_io_(block_on_io) 00121 { 00122 } 00123 00124 /** 00125 * If true, then the ORB should block on I/O operations instead of 00126 * using non-blocking I/O. 00127 */ 00128 bool block_on_io() const 00129 { 00130 return block_on_io_; 00131 } 00132 00133 /** 00134 * The maximum time to block on I/O operations (or nested loops) based 00135 * on the current timeout policies. 00136 */ 00137 ACE_Time_Value * timeout() const 00138 { 00139 return timeout_; 00140 } 00141 00142 private: 00143 ACE_Time_Value * timeout_; 00144 bool block_on_io_; 00145 }; 00146 } 00147 } 00148 00149 /* 00150 * Specialization hook for the TAO's transport implementation. 00151 */ 00152 //@@ TAO_TRANSPORT_SPL_INCLUDE_FORWARD_DECL_ADD_HOOK 00153 00154 /** 00155 * @class TAO_Transport 00156 * 00157 * @brief Generic definitions for the Transport class. 00158 * 00159 * The transport object is created in the Service handler 00160 * constructor and deleted in the Service Handler's destructor!! 00161 * 00162 * The main responsability of a Transport object is to encapsulate a 00163 * connection, and provide a transport independent way to send and 00164 * receive data. Since TAO is heavily based on the Reactor for all if 00165 * not all its I/O the Transport class is usually implemented with a 00166 * helper Connection Handler that adapts the generic Transport 00167 * interface to the Reactor types. 00168 * 00169 * <H3>The outgoing data path:</H3> 00170 * 00171 * One of the responsibilities of the TAO_Transport class is to send 00172 * out GIOP messages as efficiently as possible. In most cases 00173 * messages are put out in FIFO order, the transport object will put 00174 * out the message using a single system call and return control to 00175 * the application. However, for oneways and AMI requests it may be 00176 * more efficient (or required if the SYNC_NONE policy is in effect) 00177 * to queue the messages until a large enough data set is available. 00178 * Another reason to queue is that some applications cannot block for 00179 * I/O, yet they want to send messages so large that a single write() 00180 * operation would not be able to cope with them. In such cases we 00181 * need to queue the data and use the Reactor to drain the queue. 00182 * 00183 * Therefore, the Transport class may need to use a queue to 00184 * temporarily hold the messages, and, in some configurations, it may 00185 * need to use the Reactor to concurrently drain such queues. 00186 * 00187 * <H4>Out of order messages:</H4> TAO provides explicit policies to 00188 * send 'urgent' messages. Such messages may put at the head of the 00189 * queue. However, they cannot be sent immediately because the 00190 * transport may already be sending another message in a reactive 00191 * fashion. 00192 * 00193 * Consequently, the Transport must also know if the head of the queue 00194 * has been partially sent. In that case new messages can only follow 00195 * the head. Only once the head is completely sent we can start 00196 * sending new messages. 00197 * 00198 * <H4>Waiting threads:</H4> One or more threads can be blocked 00199 * waiting for the connection to completely send the message. 00200 * The thread should return as soon as its message has been sent, so a 00201 * per-thread condition is required. This suggest that simply using a 00202 * ACE_Message_Queue would not be enough: there is a significant 00203 * amount of ancillary information, to keep on each message that the 00204 * Message_Block class does not provide room for. 00205 * 00206 * Blocking I/O is still attractive for some applications. First, my 00207 * eliminating the Reactor overhead performance is improved when 00208 * sending large blocks of data. Second, using the Reactor to send 00209 * out data opens the door for nested upcalls, yet some applications 00210 * cannot deal with the reentrancy issues in this case. 00211 * 00212 * <H4>Timeouts:</H4> Some or all messages could have a timeout period 00213 * attached to them. The timeout source could either be some 00214 * high-level policy or maybe some strategy to prevent denial of 00215 * service attacks. In any case the timeouts are per-message, and 00216 * later messages could have shorter timeouts. 00217 * In fact, some kind of scheduling (such as EDF) could be required in 00218 * a few applications. 00219 * 00220 * <H4>Conclusions:</H4> The outgoing data path consist in several 00221 * components: 00222 * 00223 * - A queue of pending messages 00224 * - A message currently being transmitted 00225 * - A per-transport 'send strategy' to choose between blocking on 00226 * write, blocking on the reactor or blockin on leader/follower. 00227 * - A per-message 'waiting object' 00228 * - A per-message timeout 00229 * 00230 * The Transport object provides a single method to send request 00231 * messages (send_request_message ()). 00232 * 00233 * <H3>The incoming data path:</H3> 00234 * 00235 * One of the main responsibilities of the transport is to read and 00236 * process the incoming GIOP message as quickly and efficiently as 00237 * possible. There are other forces that needs to be given due 00238 * consideration. They are 00239 * - Multiple threads should be able to traverse along the same data 00240 * path but should not be able to read from the same handle at the 00241 * same time ie. the handle should not be shared between threads at 00242 * any instant. 00243 * - Reads on the handle could give one or more messages. 00244 * - Minimise locking and copying overhead when trying to attack the 00245 * above. 00246 * 00247 * <H3> Parsing messages (GIOP) & processing the message:</H3> 00248 * 00249 * The messages should be checked for validity and the right 00250 * information should be sent to the higher layer for processing. The 00251 * process of doing a sanity check and preparing the messages for the 00252 * higher layers of the ORB are done by the messaging protocol. 00253 * 00254 * <H3> Design forces and Challenges </H3> 00255 * 00256 * To keep things as efficient as possible for medium sized requests, 00257 * it would be good to minimise data copying and locking along the 00258 * incoming path ie. from the time of reading the data from the handle 00259 * to the application. We achieve this by creating a buffer on stack 00260 * and reading the data from the handle into the buffer. We then pass 00261 * the same data block (the buffer is encapsulated into a data block) 00262 * to the higher layers of the ORB. The problems stem from the 00263 * following 00264 * (a) Data is bigger than the buffer that we have on stack 00265 * (b) Transports like TCP do not guarantee availability of the whole 00266 * chunk of data in one shot. Data could trickle in byte by byte. 00267 * (c) Single read gives multiple messages 00268 * 00269 * We solve the problems as follows 00270 * 00271 * (a) First do a read with the buffer on stack. Query the underlying 00272 * messaging object whether the message has any incomplete 00273 * portion. If so, data will be copied into new buffer being able 00274 * to hold full message and is queued; succeeding events will read 00275 * data from socket and write directly into this buffer. 00276 * Otherwise, if if the message in local buffer is complete, we free 00277 * the handle and then send the message to the higher layers of the 00278 * ORB for processing. 00279 * 00280 * (b) If buffer with incomplete message has been enqueued, while trying 00281 * to do the above, the reactor will call us back when the handle 00282 * becomes read ready. The read-operation will copy data directly 00283 * into the enqueued buffer. If the message has bee read completely 00284 * the message is sent to the higher layers of the ORB for processing. 00285 * 00286 * (c) If we get multiple messages (possible if the client connected 00287 * to the server sends oneways or AMI requests), we parse and 00288 * split the messages. Every message is put in the queue. Once 00289 * the messages are queued, the thread picks up one message to 00290 * send to the higher layers of the ORB. Before doing that, if 00291 * it finds more messages, it sends a notify to the reactor 00292 * without resuming the handle. The next thread picks up a 00293 * message from the queue and processes that. Once the queue 00294 * is drained the last thread resumes the handle. 00295 * 00296 * <H3> Sending Replies </H3> 00297 * 00298 * We could use the outgoing path of the ORB to send replies. This 00299 * would allow us to reuse most of the code in the outgoing data 00300 * path. We were doing this till TAO-1.2.3. We run in to 00301 * problems. When writing the reply the ORB gets flow controlled, and the 00302 * ORB tries to flush the message by going into the reactor. This 00303 * resulted in unnecessary nesting. The thread that gets into the 00304 * Reactor could potentially handle other messages (incoming or 00305 * outgoing) and the stack starts growing leading to crashes. 00306 * 00307 * <H4> Solution to the nesting problem </H4> 00308 * 00309 * The solution that we (plan to) adopt is pretty straight 00310 * forward. The thread sending replies will not block to send the 00311 * replies but queue the replies and return to the Reactor. (Note the 00312 * careful usages of the terms "blocking in the Reactor" as opposed to 00313 * "return back to the Reactor". 00314 * 00315 * 00316 * <B>See Also:</B> 00317 * 00318 * https://svn.dre.vanderbilt.edu/viewvc/Middleware/trunk/TAO/docs/pluggable_protocols/index.html?revision=HEAD 00319 * 00320 */ 00321 class TAO_Export TAO_Transport : private ACE_Copy_Disabled 00322 { 00323 public: 00324 00325 /// Default creator, requires the tag value be supplied. 00326 TAO_Transport (CORBA::ULong tag, 00327 TAO_ORB_Core *orb_core, 00328 size_t input_cdr_size = ACE_CDR::DEFAULT_BUFSIZE); 00329 00330 /// Destructor 00331 virtual ~TAO_Transport (void); 00332 00333 /// Return the protocol tag. 00334 /** 00335 * The OMG assigns unique tags (a 32-bit unsigned number) to each 00336 * protocol. New protocol tags can be obtained free of charge from 00337 * the OMG, check the documents in corbafwd.h for more details. 00338 */ 00339 CORBA::ULong tag (void) const; 00340 00341 /// Access the ORB that owns this connection. 00342 TAO_ORB_Core *orb_core (void) const; 00343 00344 /// Get the TAO_Tranport_Mux_Strategy used by this object. 00345 /** 00346 * The role of the TAO_Transport_Mux_Strategy is described in more 00347 * detail in that class' documentation. Enough is to say that the 00348 * class is used to control how many threads can have pending 00349 * requests over the same connection. Multiplexing multiple threads 00350 * over the same connection conserves resources and is almost 00351 * required for AMI, but having only one pending request per 00352 * connection is more efficient and reduces the possibilities of 00353 * priority inversions. 00354 */ 00355 TAO_Transport_Mux_Strategy *tms (void) const; 00356 00357 /// Return the TAO_Wait_Strategy used by this object. 00358 /** 00359 * The role of the TAO_Wait_Strategy is described in more detail in 00360 * that class' documentation. Enough is to say that the ORB can wait 00361 * for a reply blocking on read(), using the Reactor to wait for 00362 * multiple events concurrently or using the Leader/Followers 00363 * protocol. 00364 */ 00365 TAO_Wait_Strategy *wait_strategy (void) const; 00366 00367 enum Drain_Result_Enum 00368 { 00369 DR_ERROR = -1, 00370 DR_OK = 0, 00371 DR_QUEUE_EMPTY = 1, // used internally, not returned from drain_queue() 00372 DR_WOULDBLOCK = 2 00373 }; 00374 00375 /// The handle_output and drain_queue* functions return objects of this 00376 /// struct instead of the enum value directly so the compiler will catch 00377 /// any uses that assign the return value to an int. 00378 struct Drain_Result 00379 { 00380 Drain_Result (Drain_Result_Enum dre) : dre_(dre) {} 00381 Drain_Result_Enum dre_; 00382 00383 bool operator== (Drain_Result rhs) const 00384 { 00385 return this->dre_ == rhs.dre_; 00386 } 00387 00388 bool operator!= (Drain_Result rhs) const 00389 { 00390 return this->dre_ != rhs.dre_; 00391 } 00392 }; 00393 00394 /// Callback method to reactively drain the outgoing data queue 00395 Drain_Result handle_output (TAO::Transport::Drain_Constraints const & c); 00396 00397 /// Get the bidirectional flag 00398 int bidirectional_flag (void) const; 00399 00400 /// Set the bidirectional flag 00401 void bidirectional_flag (int flag); 00402 00403 /// Set the Cache Map entry 00404 void cache_map_entry (TAO::Transport_Cache_Manager::HASH_MAP_ENTRY *entry); 00405 00406 /// Get the Cache Map entry 00407 TAO::Transport_Cache_Manager::HASH_MAP_ENTRY *cache_map_entry (void); 00408 00409 /// Set and Get the identifier for this transport instance. 00410 /** 00411 * If not set, this will return an integer representation of 00412 * the <code>this</code> pointer for the instance on which 00413 * it's called. 00414 */ 00415 size_t id (void) const; 00416 void id (size_t id); 00417 00418 /** 00419 * Methods dealing with the role of the connection, e.g., CLIENT or SERVER. 00420 * See CORBA 2.6 Specification, Section 15.5.1 for origin of definitions. 00421 */ 00422 TAO::Connection_Role opened_as (void) const; 00423 void opened_as (TAO::Connection_Role); 00424 00425 /// Get and Set the purging order. The purging strategy uses the set 00426 /// version to set the purging order. 00427 unsigned long purging_order (void) const; 00428 void purging_order(unsigned long value); 00429 00430 /// Check if there are messages pending in the queue 00431 /** 00432 * @return true if the queue is empty 00433 */ 00434 bool queue_is_empty (void); 00435 00436 /// Register with the reactor via the wait strategy 00437 bool register_if_necessary (void); 00438 00439 00440 /// Added event handler to the handlers set. 00441 /** 00442 * Called by the cache when the cache is closing. 00443 * 00444 * @param handlers The TAO_Connection_Handler_Set into which the 00445 * transport should place its handler 00446 */ 00447 void provide_handler (TAO::Connection_Handler_Set &handlers); 00448 00449 /// Add event handlers corresponding to transports that have RW wait 00450 /// strategy to the handlers set. 00451 /** 00452 * Called by the cache when the ORB is shuting down. 00453 * 00454 * @param handlers The TAO_Connection_Handler_Set into which the 00455 * transport should place its handler if the transport has RW 00456 * strategy on. 00457 * 00458 * @return true indicates a handler was added to the handler set. 00459 * false indocates that the transport did not have a 00460 * blockable handler that could be added. 00461 */ 00462 bool provide_blockable_handler (TAO::Connection_Handler_Set &handlers); 00463 00464 /// Register the handler with the reactor. 00465 /** 00466 * Register the handler with the reactor. This method is used by the 00467 * Wait_On_Reactor strategy. The transport must register its event 00468 * handler with the ORB's Reactor. 00469 * 00470 * @todo I think this method is pretty much useless, the 00471 * connections are *always* registered with the Reactor, except in 00472 * thread-per-connection mode. In that case putting the connection 00473 * in the Reactor would produce unpredictable results anyway. 00474 */ 00475 virtual int register_handler (void); 00476 00477 /// Write the complete Message_Block chain to the connection. 00478 /** 00479 * This method serializes on handler_lock_, guaranteeing that only 00480 * thread can execute it on the same instance concurrently. 00481 * 00482 * Often the implementation simply forwards the arguments to the 00483 * underlying ACE_Svc_Handler class. Using the code factored out 00484 * into ACE. 00485 * 00486 * Be careful with protocols that perform non-trivial 00487 * transformations of the data, such as SSLIOP or protocols that 00488 * compress the stream. 00489 * 00490 * @param iov contains the data that must be sent. 00491 * 00492 * @param timeout is the maximum time that the application is 00493 * willing to wait for the data to be sent, useful in platforms that 00494 * implement timed writes. 00495 * The timeout value is obtained from the policies set by the 00496 * application. 00497 * 00498 * @param bytes_transferred should return the total number of bytes 00499 * successfully transferred before the connection blocked. This is 00500 * required because in some platforms and/or protocols multiple 00501 * system calls may be required to send the chain of message 00502 * blocks. The first few calls can work successfully, but the final 00503 * one can fail or signal a flow control situation (via EAGAIN). 00504 * In this case the ORB expects the function to return -1, errno to 00505 * be appropriately set and this argument to return the number of 00506 * bytes already on the OS I/O subsystem. 00507 * 00508 * This call can also fail if the transport instance is no longer 00509 * associated with a connection (e.g., the connection handler closed 00510 * down). In that case, it returns -1 and sets errno to 00511 * <code>ENOENT</code>. 00512 */ 00513 virtual ssize_t send (iovec *iov, 00514 int iovcnt, 00515 size_t &bytes_transferred, 00516 ACE_Time_Value const * timeout) = 0; 00517 00518 #if TAO_HAS_SENDFILE == 1 00519 /// Send data through zero-copy write mechanism, if available. 00520 /** 00521 * This method sends the data in the I/O vector through the platform 00522 * sendfile() function to perform a zero-copy write, if available. 00523 * Otherwise, the default fallback implementation simply delegates 00524 * to the TAO_Transport::send() method. 00525 * 00526 * @note This method is best used when sending very large blocks of 00527 * data. 00528 */ 00529 virtual ssize_t sendfile (TAO_MMAP_Allocator * allocator, 00530 iovec * iov, 00531 int iovcnt, 00532 size_t &bytes_transferred, 00533 TAO::Transport::Drain_Constraints const & dc); 00534 #endif /* TAO_HAS_SENDFILE==1 */ 00535 00536 00537 /// Read len bytes from into buf. 00538 /** 00539 * This method serializes on handler_lock_, guaranteeing that only 00540 * thread can execute it on the same instance concurrently. 00541 * 00542 * @param buffer ORB allocated buffer where the data should be 00543 * @@ The ACE_Time_Value *s is just a place holder for now. It is 00544 * not clear this this is the best place to specify this. The actual 00545 * timeout values will be kept in the Policies. 00546 */ 00547 virtual ssize_t recv (char *buffer, 00548 size_t len, 00549 const ACE_Time_Value *timeout = 0) = 0; 00550 00551 /** 00552 * @name Control connection lifecycle 00553 * 00554 * These methods are routed through the TMS object. The TMS 00555 * strategies implement them correctly. 00556 */ 00557 //@{ 00558 00559 /// Request has been just sent, but the reply is not received. Idle 00560 /// the transport now. 00561 bool idle_after_send (void); 00562 00563 /// Request is sent and the reply is received. Idle the transport 00564 /// now. 00565 bool idle_after_reply (void); 00566 00567 /// Call the implementation method after obtaining the lock. 00568 virtual void close_connection (void); 00569 00570 //@} 00571 00572 /** @name Template methods 00573 * 00574 * The Transport class uses the Template Method Pattern to implement 00575 * the protocol specific functionality. 00576 * Implementors of a pluggable protocol should override the 00577 * following methods with the semantics documented below. 00578 */ 00579 /** 00580 * Initialising the messaging object. This would be used by the 00581 * connector side. On the acceptor side the connection handler 00582 * would take care of the messaging objects. 00583 */ 00584 void messaging_init (TAO_GIOP_Message_Version const &version); 00585 00586 /// Extracts the list of listen points from the @a cdr stream. The 00587 /// list would have the protocol specific details of the 00588 /// ListenPoints 00589 virtual int tear_listen_point_list (TAO_InputCDR &cdr); 00590 00591 /// Hooks that can be overridden in concrete transports. 00592 /** 00593 * These hooks are invoked just after connection establishment (or 00594 * after a connection is fetched from cache). The 00595 * return value signifies whether the invoker should proceed with 00596 * post connection establishment activities. Protocols like SSLIOP 00597 * need this to verify whether connections already established have 00598 * valid certificates. There are no pre_connect_hooks () since the 00599 * transport doesn't exist before a connection establishment. :-) 00600 * 00601 * @note The methods are not made const with a reason. 00602 */ 00603 virtual bool post_connect_hook (void); 00604 00605 /// Memory management routines. 00606 /* 00607 * Forwards to event handler. 00608 */ 00609 ACE_Event_Handler::Reference_Count add_reference (void); 00610 ACE_Event_Handler::Reference_Count remove_reference (void); 00611 00612 /// Return the messaging object that is used to format the data that 00613 /// needs to be sent. 00614 TAO_GIOP_Message_Base * messaging_object (void); 00615 00616 /** @name Template methods 00617 * 00618 * The Transport class uses the Template Method Pattern to implement 00619 * the protocol specific functionality. 00620 * Implementors of a pluggable protocol should override the 00621 * following methods with the semantics documented below. 00622 */ 00623 //@{ 00624 00625 /// Return the event handler used to receive notifications from the 00626 /// Reactor. 00627 /** 00628 * Normally a concrete TAO_Transport object has-a ACE_Event_Handler 00629 * member that functions as an adapter between the ACE_Reactor 00630 * framework and the TAO pluggable protocol framework. 00631 * In all the protocols implemented so far this role is fullfilled 00632 * by an instance of ACE_Svc_Handler. 00633 * 00634 * @todo Since we only use a limited functionality of 00635 * ACE_Svc_Handler we could probably implement a generic 00636 * adapter class (TAO_Transport_Event_Handler or something), this 00637 * will reduce footprint and simplify the process of implementing a 00638 * pluggable protocol. 00639 * 00640 * @todo This method has to be renamed to event_handler() 00641 */ 00642 virtual ACE_Event_Handler * event_handler_i (void) = 0; 00643 00644 /// Is this transport really connected 00645 bool is_connected (void) const; 00646 00647 /// Perform all the actions when this transport get opened 00648 bool post_open (size_t id); 00649 00650 /// do what needs to be done when closing the transport 00651 void pre_close (void); 00652 00653 /// Get the connection handler for this transport 00654 TAO_Connection_Handler * connection_handler (void); 00655 00656 /// Accessor for the output CDR stream 00657 TAO_OutputCDR &out_stream (void); 00658 00659 /// Accessor for synchronizing Transport OutputCDR access 00660 TAO_SYNCH_MUTEX &output_cdr_lock (void); 00661 00662 /// Set the flush in post open flag 00663 void set_flush_in_post_open (void); 00664 00665 /// Can the transport be purged? 00666 bool can_be_purged (void); 00667 00668 virtual void set_bidir_context_info (TAO_Operation_Details &opdetails); 00669 00670 /* 00671 * Specialization hook to add public methods from 00672 * concrete transport implementations to TAO's transport 00673 * class 00674 */ 00675 //@@ TAO_TRANSPORT_SPL_PUBLIC_METHODS_ADD_HOOK 00676 00677 protected: 00678 00679 virtual TAO_Connection_Handler * connection_handler_i (void) = 0; 00680 00681 public: 00682 00683 /// This is a request for the transport object to write a 00684 /// LocateRequest header before it is sent out. 00685 int generate_locate_request (TAO_Target_Specification &spec, 00686 TAO_Operation_Details &opdetails, 00687 TAO_OutputCDR &output); 00688 00689 /// This is a request for the transport object to write a request 00690 /// header before it sends out the request 00691 virtual int generate_request_header (TAO_Operation_Details &opd, 00692 TAO_Target_Specification &spec, 00693 TAO_OutputCDR &msg); 00694 00695 /// Recache ourselves in the cache 00696 int recache_transport (TAO_Transport_Descriptor_Interface* desc); 00697 00698 /// Callback to read incoming data 00699 /** 00700 * The ACE_Event_Handler adapter invokes this method as part of its 00701 * handle_input() operation. 00702 * 00703 * @todo the method name is confusing! Calling it handle_input() 00704 * would probably make things easier to understand and follow! 00705 * 00706 * Once a complete message is read the Transport class delegates on 00707 * the Messaging layer to invoke the right upcall (on the server) or 00708 * the TAO_Reply_Dispatcher (on the client side). 00709 * 00710 * @param max_wait_time In some cases the I/O is synchronous, e.g. a 00711 * thread-per-connection server or when Wait_On_Read is enabled. In 00712 * those cases a maximum read time can be specified. 00713 */ 00714 virtual int handle_input (TAO_Resume_Handle &rh, 00715 ACE_Time_Value *max_wait_time = 0); 00716 00717 /// Prepare the waiting and demuxing strategy to receive a reply for 00718 /// a new request. 00719 /** 00720 * Preparing the ORB to receive the reply only once the request is 00721 * completely sent opens the system to some subtle race conditions: 00722 * suppose the ORB is running in a multi-threaded configuration, 00723 * thread A makes a request while thread B is using the Reactor to 00724 * process all incoming requests. 00725 * Thread A could be implemented as follows: 00726 * 1) send the request 00727 * 2) setup the ORB to receive the reply 00728 * 3) wait for the request 00729 * 00730 * but in this case thread B may receive the reply between step (1) 00731 * and (2), and drop it as an invalid or unexpected message. 00732 * Consequently the correct implementation is: 00733 * 1) setup the ORB to receive the reply 00734 * 2) send the request 00735 * 3) wait for the reply 00736 * 00737 * The following method encapsulates this idiom. 00738 * 00739 * @todo This is generic code, it should be factored out into the 00740 * Transport class. 00741 */ 00742 // @nolock b/c this calls send_or_buffer 00743 virtual int send_request (TAO_Stub *stub, 00744 TAO_ORB_Core *orb_core, 00745 TAO_OutputCDR &stream, 00746 TAO_Message_Semantics message_semantics, 00747 ACE_Time_Value *max_time_wait) = 0; 00748 00749 /// This method formats the stream and then sends the message on the 00750 /// transport. 00751 /** 00752 * Once the ORB is prepared to receive a reply (see send_request() 00753 * above), and all the arguments have been marshaled the CDR stream 00754 * must be 'formatted', i.e. the message_size field in the GIOP 00755 * header can finally be set to the proper value. 00756 * 00757 */ 00758 virtual int send_message (TAO_OutputCDR &stream, 00759 TAO_Stub *stub = 0, 00760 TAO_Message_Semantics message_semantics = TAO_TWOWAY_REQUEST, 00761 ACE_Time_Value *max_time_wait = 0) = 0; 00762 00763 /// Sent the contents of @a message_block 00764 /** 00765 * @param stub The object reference used for this operation, useful 00766 * to obtain the current policies. 00767 * @param message_semantics If this is set to TAO_TWO_REQUEST 00768 * this method will block until the operation is completely 00769 * written on the wire. If it is set to other values this 00770 * operation could return. 00771 * @param message_block The CDR encapsulation of the GIOP message 00772 * that must be sent. The message may consist of 00773 * multiple Message Blocks chained through the cont() 00774 * field. 00775 * @param max_wait_time The maximum time that the operation can 00776 * block, used in the implementation of timeouts. 00777 */ 00778 virtual int send_message_shared (TAO_Stub *stub, 00779 TAO_Message_Semantics message_semantics, 00780 const ACE_Message_Block *message_block, 00781 ACE_Time_Value *max_wait_time); 00782 00783 protected: 00784 00785 /// Process the message by sending it to the higher layers of the 00786 /// ORB. 00787 int process_parsed_messages (TAO_Queued_Data *qd, 00788 TAO_Resume_Handle &rh); 00789 00790 /// Implement send_message_shared() assuming the handler_lock_ is 00791 /// held. 00792 int send_message_shared_i (TAO_Stub *stub, 00793 TAO_Message_Semantics message_semantics, 00794 const ACE_Message_Block *message_block, 00795 ACE_Time_Value *max_wait_time); 00796 00797 /// Queue a message for @a message_block 00798 /// @param max_wait_time The maximum time that the operation can 00799 /// block, used in the implementation of timeouts. 00800 /// @param back If true, the message will be pushed to the back of the queue. 00801 /// If false, the message will be pushed to the front of the queue. 00802 int queue_message_i (const ACE_Message_Block *message_block, 00803 ACE_Time_Value *max_wait_time, bool back=true); 00804 00805 /** 00806 * @brief Re-factor computation of I/O timeouts based on operation 00807 * timeouts. 00808 * Depending on the wait strategy, we need to timeout I/O operations or 00809 * not. For example, if we are using a non-blocking strategy, we want 00810 * to pass 0 to all I/O operations, and rely on the ACE_NONBLOCK 00811 * settings on the underlying sockets. However, for blocking strategies 00812 * we want to pass the operation timeouts, to respect the application 00813 * level policies. 00814 * 00815 * This function was introduced as part of the fixes for bug 3647. 00816 */ 00817 ACE_Time_Value const *io_timeout( 00818 TAO::Transport::Drain_Constraints const & dc) const; 00819 00820 public: 00821 /// Format and queue a message for @a stream 00822 /// @param max_wait_time The maximum time that the operation can 00823 /// block, used in the implementation of timeouts. 00824 int format_queue_message (TAO_OutputCDR &stream, 00825 ACE_Time_Value *max_wait_time, 00826 TAO_Stub* stub); 00827 00828 /** 00829 * This is a very specialized interface to send a simple chain of 00830 * messages through the Transport. The only place we use this interface 00831 * is in GIOP_Message_Base.cpp, to send error messages (i.e., an 00832 * indication that we received a malformed GIOP message,) and to close 00833 * the connection. 00834 * 00835 */ 00836 int send_message_block_chain (const ACE_Message_Block *message_block, 00837 size_t &bytes_transferred, 00838 ACE_Time_Value *max_wait_time = 0); 00839 00840 /// Send a message block chain, assuming the lock is held 00841 int send_message_block_chain_i (const ACE_Message_Block *message_block, 00842 size_t &bytes_transferred, 00843 TAO::Transport::Drain_Constraints const & dc); 00844 00845 /// Cache management 00846 int purge_entry (void); 00847 00848 /// Cache management 00849 int make_idle (void); 00850 00851 /// Cache management 00852 int update_transport (void); 00853 00854 /// The timeout callback, invoked when any of the timers related to 00855 /// this transport expire. 00856 /** 00857 * @param current_time The current time as reported from the Reactor 00858 * @param act The Asynchronous Completion Token. Currently it is 00859 * interpreted as follows: 00860 * - If the ACT is the address of this->current_deadline_ the 00861 * queueing timeout has expired and the queue should start 00862 * flushing. 00863 * 00864 * @return Returns 0 if there are no problems, -1 if there is an 00865 * error 00866 * 00867 * @todo In the future this function could be used to expire 00868 * messages (oneways) that have been sitting for too long on 00869 * the queue. 00870 */ 00871 int handle_timeout (const ACE_Time_Value ¤t_time, const void* act); 00872 00873 /// Accessor to recv_buffer_size_ 00874 size_t recv_buffer_size (void) const; 00875 00876 /// Accessor to sent_byte_count_ 00877 size_t sent_byte_count (void) const; 00878 00879 /// CodeSet Negotiation - Get the char codeset translator factory 00880 TAO_Codeset_Translator_Base *char_translator (void) const; 00881 00882 /// CodeSet Negotiation - Get the wchar codeset translator factory 00883 TAO_Codeset_Translator_Base *wchar_translator (void) const; 00884 00885 /// CodeSet negotiation - Set the char codeset translator factory 00886 void char_translator (TAO_Codeset_Translator_Base *); 00887 00888 /// CodeSet negotiation - Set the wchar codeset translator factory 00889 void wchar_translator (TAO_Codeset_Translator_Base *); 00890 00891 /// Use the Transport's codeset factories to set the translator for input 00892 /// and output CDRs. 00893 void assign_translators (TAO_InputCDR *, TAO_OutputCDR *); 00894 00895 /// It is necessary to clear the codeset translator when a CDR stream 00896 /// is used for more than one GIOP message. This is required since the 00897 /// header must not be translated, whereas the body must be. 00898 void clear_translators (TAO_InputCDR *, TAO_OutputCDR *); 00899 00900 /// Return true if the tcs has been set 00901 CORBA::Boolean is_tcs_set() const; 00902 00903 /// Set the state of the first_request_ to flag. 00904 void first_request_sent (bool flag = false); 00905 00906 /// Get the first request flag 00907 bool first_request () const; 00908 00909 /// Notify all the components inside a Transport when the underlying 00910 /// connection is closed. 00911 void send_connection_closed_notifications (void); 00912 00913 /// Transport statistics 00914 TAO::Transport::Stats* stats (void) const; 00915 00916 private: 00917 00918 /// Helper method that returns the Transport Cache Manager. 00919 TAO::Transport_Cache_Manager &transport_cache_manager (void); 00920 00921 /// Send some of the data in the queue. 00922 /** 00923 * As the outgoing data is drained this method is invoked to send as 00924 * much of the current message as possible. 00925 */ 00926 Drain_Result drain_queue (TAO::Transport::Drain_Constraints const & dc); 00927 00928 /// Implement drain_queue() assuming the lock is held 00929 Drain_Result drain_queue_i (TAO::Transport::Drain_Constraints const & dc); 00930 00931 /// Check if there are messages pending in the queue 00932 /** 00933 * This version assumes that the lock is already held. Use with 00934 * care! 00935 * 00936 * @return true if the queue is empty 00937 */ 00938 bool queue_is_empty_i (void) const; 00939 00940 /// A helper routine used in drain_queue_i() 00941 Drain_Result drain_queue_helper (int &iovcnt, iovec iov[], 00942 TAO::Transport::Drain_Constraints const & dc); 00943 00944 /// These classes need privileged access to: 00945 /// - schedule_output_i() 00946 /// - cancel_output_i() 00947 friend class TAO_Reactive_Flushing_Strategy; 00948 friend class TAO_Leader_Follower_Flushing_Strategy; 00949 00950 /// Needs priveleged access to 00951 /// event_handler_i () 00952 friend class TAO_Thread_Per_Connection_Handler; 00953 00954 /// Schedule handle_output() callbacks 00955 int schedule_output_i (void); 00956 00957 /// Cancel handle_output() callbacks 00958 int cancel_output_i (void); 00959 00960 /// Cleanup the queue. 00961 /** 00962 * Exactly @a byte_count bytes have been sent, the queue must be 00963 * cleaned up as potentially several messages have been completely 00964 * sent out. 00965 * It leaves on head_ the next message to send out. 00966 */ 00967 void cleanup_queue (size_t byte_count); 00968 00969 /// Cleanup the complete queue 00970 void cleanup_queue_i (); 00971 00972 /// Check if the buffering constraints have been reached 00973 int check_buffering_constraints_i (TAO_Stub *stub, bool &must_flush); 00974 00975 /// Send a synchronous message, i.e. block until the message is on 00976 /// the wire 00977 int send_synchronous_message_i (const ACE_Message_Block *message_block, 00978 ACE_Time_Value *max_wait_time); 00979 00980 /// Send a reply message, i.e. do not block until the message is on 00981 /// the wire, but just return after adding them to the queue. 00982 int send_reply_message_i (const ACE_Message_Block *message_block, 00983 ACE_Time_Value *max_wait_time); 00984 00985 /// Send an asynchronous message, i.e. do not block until the message is on 00986 /// the wire 00987 int send_asynchronous_message_i (TAO_Stub *stub, 00988 const ACE_Message_Block *message_block, 00989 ACE_Time_Value *max_wait_time); 00990 00991 /// A helper method used by send_synchronous_message_i() and 00992 /// send_reply_message_i(). Reusable code that could be used by both 00993 /// the methods. 00994 int send_synch_message_helper_i (TAO_Synch_Queued_Message &s, 00995 ACE_Time_Value *max_wait_time); 00996 00997 /// Check if the flush timer is still pending 00998 int flush_timer_pending (void) const; 00999 01000 /// The flush timer expired or was explicitly cancelled, mark it as 01001 /// not pending 01002 void reset_flush_timer (void); 01003 01004 /// Print out error messages if the event handler is not valid 01005 void report_invalid_event_handler (const char *caller); 01006 01007 /// Is invoked by handle_input operation. It consolidate message on 01008 /// top of incoming_message_stack. The amount of missing data is 01009 /// known and recv operation copies data directly into message buffer, 01010 /// as much as a single recv-invocation provides. 01011 int handle_input_missing_data (TAO_Resume_Handle &rh, 01012 ACE_Time_Value *max_wait_time, 01013 TAO_Queued_Data *q_data); 01014 01015 /// Is invoked by handle_input operation. It parses new messages from input stream 01016 /// or consolidates messages whose header has been partially read, the message 01017 /// size being unknown so far. It parses as much data as a single recv-invocation provides. 01018 int handle_input_parse_data (TAO_Resume_Handle &rh, 01019 ACE_Time_Value *max_wait_time); 01020 01021 /// Is invoked by handle_input_parse_data. Parses all messages remaining 01022 /// in @a message_block. 01023 int handle_input_parse_extra_messages (ACE_Message_Block &message_block); 01024 01025 /// @return -1 error, otherwise 0 01026 int consolidate_enqueue_message (TAO_Queued_Data *qd); 01027 01028 /// @return -1 error, otherwise 0 01029 int consolidate_process_message (TAO_Queued_Data *qd, TAO_Resume_Handle &rh); 01030 01031 /* 01032 * Process the message that is in the head of the incoming queue. 01033 * If there are more messages in the queue, this method calls 01034 * this->notify_reactor () to wake up a thread 01035 * @retval -1 on error 01036 * @retval 0 if successfully processing enqueued messages 01037 * @retval 1 if no message present in queue 01038 */ 01039 int process_queue_head (TAO_Resume_Handle &rh); 01040 01041 /* 01042 * This call prepares a new handler for the notify call and sends a 01043 * notify () call to the reactor. 01044 */ 01045 int notify_reactor (void); 01046 01047 /// Assume the lock is held 01048 void send_connection_closed_notifications_i (void); 01049 01050 /// Allocate a partial message block and store it in our 01051 /// partial_message_ data member. 01052 void allocate_partial_message_block (void); 01053 01054 /** 01055 * Return true if blocking I/O should be used for sending synchronous 01056 * (two-way, reliable oneways, etc.) messages. This is determined based 01057 * on the current flushing and waiting strategies. 01058 */ 01059 bool using_blocking_io_for_synch_messages() const; 01060 01061 /** 01062 * Return true if blocking I/O should be used for sending asynchronous 01063 * (AMI calls, non-blocking oneways, responses to operations, etc.) 01064 * messages. This is determined based on the current flushing strategy. 01065 */ 01066 bool using_blocking_io_for_asynch_messages() const; 01067 01068 /* 01069 * Specialization hook to add concrete private methods from 01070 * TAO's protocol implementation onto the base Transport class 01071 */ 01072 01073 //@@ TAO_TRANSPORT_SPL_PRIVATE_METHODS_ADD_HOOK 01074 01075 protected: 01076 01077 /// IOP protocol tag. 01078 CORBA::ULong const tag_; 01079 01080 /// Global orbcore resource. 01081 TAO_ORB_Core * const orb_core_; 01082 01083 /// Our entry in the cache. We don't own this. It is here for our 01084 /// convenience. We cannot just change things around. 01085 TAO::Transport_Cache_Manager::HASH_MAP_ENTRY *cache_map_entry_; 01086 01087 /// Strategy to decide whether multiple requests can be sent over the 01088 /// same connection or the connection is exclusive for a request. 01089 TAO_Transport_Mux_Strategy *tms_; 01090 01091 /// Strategy for waiting for the reply after sending the request. 01092 TAO_Wait_Strategy *ws_; 01093 01094 /// Use to check if bidirectional info has been synchronized with 01095 /// the peer. 01096 /** 01097 * Have we sent any info on bidirectional information or have we 01098 * received any info regarding making the connection served by this 01099 * transport bidirectional. 01100 * The flag is used as follows: 01101 * + We dont want to send the bidirectional context info more than 01102 * once on the connection. Why? Waste of marshalling and 01103 * demarshalling time on the client. 01104 * + On the server side -- once a client that has established the 01105 * connection asks the server to use the connection both ways, we 01106 * *dont* want the server to pack service info to the client. That 01107 * is not allowed. We need a flag to prevent such a things from 01108 * happening. 01109 * 01110 * The value of this flag will be 0 if the client sends info and 1 01111 * if the server receives the info. 01112 */ 01113 int bidirectional_flag_; 01114 01115 TAO::Connection_Role opening_connection_role_; 01116 01117 /// Implement the outgoing data queue 01118 TAO_Queued_Message *head_; 01119 TAO_Queued_Message *tail_; 01120 01121 /// Queue of the consolidated, incoming messages.. 01122 TAO_Incoming_Message_Queue incoming_message_queue_; 01123 01124 /// Stack of incoming fragments, consolidated messages 01125 /// are going to be enqueued in "incoming_message_queue_" 01126 TAO::Incoming_Message_Stack incoming_message_stack_; 01127 01128 /// The queue will start draining no later than <queeing_deadline_> 01129 /// *if* the deadline is 01130 ACE_Time_Value current_deadline_; 01131 01132 /// The timer ID 01133 long flush_timer_id_; 01134 01135 /// The adapter used to receive timeout callbacks from the Reactor 01136 TAO_Transport_Timer transport_timer_; 01137 01138 /// Lock that insures that activities that *might* use handler-related 01139 /// resources (such as a connection handler) get serialized. 01140 /** 01141 * This is an <code>ACE_Lock</code> that gets initialized from 01142 * @c TAO_ORB_Core::resource_factory()->create_cached_connection_lock(). 01143 * This way, one can use a lock appropriate for the type of system, i.e., 01144 * a null lock for single-threaded systems, and a real lock for 01145 * multi-threaded systems. 01146 */ 01147 mutable ACE_Lock *handler_lock_; 01148 01149 /// A unique identifier for the transport. 01150 /** 01151 * This never *never* changes over the lifespan, so we don't have to worry 01152 * about locking it. 01153 * 01154 * HINT: Protocol-specific transports that use connection handler 01155 * might choose to set this to the handle for their connection. 01156 */ 01157 size_t id_; 01158 01159 /// Used by the LRU, LFU and FIFO Connection Purging Strategies. 01160 unsigned long purging_order_; 01161 01162 /// Size of the buffer received. 01163 size_t recv_buffer_size_; 01164 01165 /// Number of bytes sent. 01166 size_t sent_byte_count_; 01167 01168 /// Is this transport really connected or not. In case of oneways with 01169 /// SYNC_NONE Policy we don't wait until the connection is ready and we 01170 /// buffer the requests in this transport until the connection is ready 01171 bool is_connected_; 01172 01173 private: 01174 01175 /// Our messaging object. 01176 TAO_GIOP_Message_Base *messaging_object_; 01177 01178 /// @@Phil, I think it would be nice if we could think of a way to 01179 /// do the following. 01180 /// We have been trying to use the transport for marking about 01181 /// translator factories and such! IMHO this is a wrong encapulation 01182 /// ie. trying to populate the transport object with these 01183 /// details. We should probably have a class something like 01184 /// TAO_Message_Property or TAO_Message_Translator or whatever (I am 01185 /// sure you get the idea) and encapsulate all these 01186 /// details. Coupling these seems odd. if I have to be more cynical 01187 /// we can move this to the connection_handler and it may more sense 01188 /// with the DSCP stuff around there. Do you agree? 01189 01190 /// Additional member values required to support codeset translation 01191 TAO_Codeset_Translator_Base *char_translator_; 01192 TAO_Codeset_Translator_Base *wchar_translator_; 01193 01194 /// The tcs_set_ flag indicates that negotiation has occured and so the 01195 /// translators are correct, since a null translator is valid if both ends 01196 /// are using the same codeset, whatever that codeset might be. 01197 CORBA::Boolean tcs_set_; 01198 01199 /// First_request_ is true until the first request is sent or received. This 01200 /// is necessary since codeset context information is necessary only on the 01201 /// first request. After that, the translators are fixed for the life of the 01202 /// connection. 01203 bool first_request_; 01204 01205 /// Holds the partial GIOP message (if there is one) 01206 ACE_Message_Block* partial_message_; 01207 01208 #if TAO_HAS_SENDFILE == 1 01209 /// mmap()-based allocator used to allocator output CDR buffers. 01210 /** 01211 * If this pointer is non-zero, sendfile() will be used to send data 01212 * in a TAO_OutputCDR stream instance. 01213 */ 01214 TAO_MMAP_Allocator * const mmap_allocator_; 01215 #endif /* TAO_HAS_SENDFILE==1 */ 01216 01217 #if TAO_HAS_TRANSPORT_CURRENT == 1 01218 /// Statistics 01219 TAO::Transport::Stats* stats_; 01220 #endif /* TAO_HAS_TRANSPORT_CURRENT == 1 */ 01221 01222 /// Indicate that flushing needs to be done in post_open() 01223 bool flush_in_post_open_; 01224 01225 /// lock for synchronizing Transport OutputCDR access 01226 mutable TAO_SYNCH_MUTEX output_cdr_mutex_; 01227 01228 /* 01229 * specialization hook to add class members from concrete 01230 * transport class onto the base transport class. Please 01231 * add any private members to this class *before* this hook. 01232 */ 01233 //@@ TAO_TRANSPORT_SPL_DATA_MEMBERS_ADD_HOOK 01234 }; 01235 01236 /* 01237 * Hook to add external typedefs and specializations to 01238 * TAO's transport implementation. 01239 */ 01240 01241 //@@ TAO_TRANSPORT_SPL_EXTERN_ADD_HOOK 01242 01243 #if TAO_HAS_TRANSPORT_CURRENT == 1 01244 namespace TAO 01245 { 01246 namespace Transport 01247 { 01248 /* 01249 * @class Stats 01250 * 01251 * @brief Used to collect stats on a transport. 01252 * 01253 * The base class in (potentialy) extensible hierarchy used to 01254 * specialize the information available for a specific protocol. 01255 * 01256 * This class is necessary for the implementation of the Transport 01257 * Current feature. 01258 * 01259 * <B>See Also:</B> 01260 * 01261 * https://svn.dre.vanderbilt.edu/viewvc/Middleware/trunk/TAO/docs/transport_current/index.html?revision=HEAD 01262 * 01263 */ 01264 class TAO_Export Stats 01265 { 01266 public: 01267 Stats (); 01268 virtual ~Stats (); 01269 01270 void messages_sent (size_t message_length); 01271 CORBA::LongLong messages_sent (void) const; 01272 CORBA::LongLong bytes_sent (void) const; 01273 01274 void messages_received (size_t message_length); 01275 CORBA::LongLong messages_received (void) const; 01276 CORBA::LongLong bytes_received (void) const; 01277 01278 void opened_since (const ACE_Time_Value& tv); 01279 const ACE_Time_Value& opened_since (void) const; 01280 01281 private: 01282 // The bytes_rcvd_.samples_count() could have been used instead, 01283 // however there was a suspicion that 32 bits would be 01284 // insufficient. 01285 CORBA::LongLong messages_rcvd_; 01286 01287 // The bytes_sent_.samples_count() could have been used instead, 01288 // however there was a suspicion that 32 bits would be 01289 // insufficient. 01290 CORBA::LongLong messages_sent_; 01291 01292 ACE_Basic_Stats bytes_rcvd_; 01293 ACE_Basic_Stats bytes_sent_; 01294 01295 ACE_Time_Value opened_since_; 01296 }; 01297 } 01298 } 01299 #endif /* TAO_HAS_TRANSPORT_CURRENT == 1 */ 01300 01301 TAO_END_VERSIONED_NAMESPACE_DECL 01302 01303 #if defined (__ACE_INLINE__) 01304 # include "tao/Transport.inl" 01305 #endif /* __ACE_INLINE__ */ 01306 01307 #include /**/ "ace/post.h" 01308 01309 #endif /* TAO_TRANSPORT_H */