TAO_Transport Class ReferenceGeneric definitions for the Transport class. More...
Inheritance diagram for TAO_Transport:
Collaboration diagram for TAO_Transport:
Detailed DescriptionGeneric definitions for the Transport class.The transport object is created in the Service handler constructor and deleted in the Service Handler's destructor!! The main responsability of a Transport object is to encapsulate a connection, and provide a transport independent way to send and receive data. Since TAO is heavily based on the Reactor for all if not all its I/O the Transport class is usually implemented with a helper Connection Handler that adapts the generic Transport interface to the Reactor types.
The outgoing data path:One of the responsibilities of the TAO_Transport class is to send out GIOP messages as efficiently as possible. In most cases messages are put out in FIFO order, the transport object will put out the message using a single system call and return control to the application. However, for oneways and AMI requests it may be more efficient (or required if the SYNC_NONE policy is in effect) to queue the messages until a large enough data set is available. Another reason to queue is that some applications cannot block for I/O, yet they want to send messages so large that a single write() operation would not be able to cope with them. In such cases we need to queue the data and use the Reactor to drain the queue. Therefore, the Transport class may need to use a queue to temporarily hold the messages, and, in some configurations, it may need to use the Reactor to concurrently drain such queues.
Out of order messages:TAO provides explicit policies to send 'urgent' messages. Such messages may put at the head of the queue. However, they cannot be sent immediately because the transport may already be sending another message in a reactive fashion. Consequently, the Transport must also know if the head of the queue has been partially sent. In that case new messages can only follow the head. Only once the head is completely sent we can start sending new messages.
Waiting threads:One or more threads can be blocked waiting for the connection to completely send the message. The thread should return as soon as its message has been sent, so a per-thread condition is required. This suggest that simply using a ACE_Message_Queue would not be enough: there is a significant amount of ancillary information, to keep on each message that the Message_Block class does not provide room for. Blocking I/O is still attractive for some applications. First, my eliminating the Reactor overhead performance is improved when sending large blocks of data. Second, using the Reactor to send out data opens the door for nested upcalls, yet some applications cannot deal with the reentrancy issues in this case.
Timeouts:Some or all messages could have a timeout period attached to them. The timeout source could either be some high-level policy or maybe some strategy to prevent denial of service attacks. In any case the timeouts are per-message, and later messages could have shorter timeouts. In fact, some kind of scheduling (such as EDF) could be required in a few applications.
Conclusions:The outgoing data path consist in several components:
The Transport object provides a single method to send request messages (send_request_message ()).
The incoming data path:One of the main responsibilities of the transport is to read and process the incoming GIOP message as quickly and efficiently as possible. There are other forces that needs to be given due consideration. They are
Parsing messages (GIOP) & processing the message:The messages should be checked for validity and the right information should be sent to the higher layer for processing. The process of doing a sanity check and preparing the messages for the higher layers of the ORB are done by the messaging protocol.
Design forces and ChallengesTo keep things as efficient as possible for medium sized requests, it would be good to minimise data copying and locking along the incoming path ie. from the time of reading the data from the handle to the application. We achieve this by creating a buffer on stack and reading the data from the handle into the buffer. We then pass the same data block (the buffer is encapsulated into a data block) to the higher layers of the ORB. The problems stem from the following (a) Data is bigger than the buffer that we have on stack (b) Transports like TCP do not guarantee availability of the whole chunk of data in one shot. Data could trickle in byte by byte. (c) Single read gives multiple messages We solve the problems as follows (a) First do a read with the buffer on stack. Query the underlying messaging object whether the message has any incomplete portion. If so, data will be copied into new buffer being able to hold full message and is queued; succeeding events will read data from socket and write directly into this buffer. Otherwise, if if the message in local buffer is complete, we free the handle and then send the message to the higher layers of the ORB for processing. (b) If buffer with incomplete message has been enqueued, while trying to do the above, the reactor will call us back when the handle becomes read ready. The read-operation will copy data directly into the enqueued buffer. If the message has bee read completely the message is sent to the higher layers of the ORB for processing. (c) If we get multiple messages (possible if the client connected to the server sends oneways or AMI requests), we parse and split the messages. Every message is put in the queue. Once the messages are queued, the thread picks up one message to send to the higher layers of the ORB. Before doing that, if it finds more messages, it sends a notify to the reactor without resuming the handle. The next thread picks up a message from the queue and processes that. Once the queue is drained the last thread resumes the handle.
Sending RepliesWe could use the outgoing path of the ORB to send replies. This would allow us to reuse most of the code in the outgoing data path. We were doing this till TAO-1.2.3. We run in to problems. When writing the reply the ORB gets flow controlled, and the ORB tries to flush the message by going into the reactor. This resulted in unnecessary nesting. The thread that gets into the Reactor could potentially handle other messages (incoming or outgoing) and the stack starts growing leading to crashes.
Solution to the nesting problemThe solution that we (plan to) adopt is pretty straight forward. The thread sending replies will not block to send the replies but queue the replies and return to the Reactor. (Note the careful usages of the terms "blocking in the Reactor" as opposed to "return back to the Reactor". See Also: Member Enumeration Documentation
Constructor & Destructor Documentation
Default creator, requires the tag value be supplied.
Destructor.
Member Function Documentation
Return the protocol tag. The OMG assigns unique tags (a 32-bit unsigned number) to each protocol. New protocol tags can be obtained free of charge from the OMG, check the documents in corbafwd.h for more details.
Access the ORB that owns this connection.
Get the TAO_Tranport_Mux_Strategy used by this object. The role of the TAO_Transport_Mux_Strategy is described in more detail in that class' documentation. Enough is to say that the class is used to control how many threads can have pending requests over the same connection. Multiplexing multiple threads over the same connection conserves resources and is almost required for AMI, but having only one pending request per connection is more efficient and reduces the possibilities of priority inversions.
Return the TAO_Wait_Strategy used by this object. The role of the TAO_Wait_Strategy is described in more detail in that class' documentation. Enough is to say that the ORB can wait for a reply blocking on read(), using the Reactor to wait for multiple events concurrently or using the Leader/Followers protocol.
Callback method to reactively drain the outgoing data queue.
Get the bidirectional flag.
Set the bidirectional flag.
Set the Cache Map entry.
Get the Cache Map entry.
Set and Get the identifier for this transport instance.
If not set, this will return an integer representation of the
Methods dealing with the role of the connection, e.g., CLIENT or SERVER. See CORBA 2.6 Specification, Section 15.5.1 for origin of definitions.
Get and Set the purging order. The purging strategy uses the set version to set the purging order.
Check if there are messages pending in the queue.
Register with the reactor via the wait strategy.
Added event handler to the handlers set. Called by the cache when the cache is closing.
Add event handlers corresponding to transports that have RW wait strategy to the handlers set. Called by the cache when the ORB is shuting down.
Register the handler with the reactor. Register the handler with the reactor. This method is used by the Wait_On_Reactor strategy. The transport must register its event handler with the ORB's Reactor.
Write the complete Message_Block chain to the connection. This method serializes on handler_lock_, guaranteeing that only thread can execute it on the same instance concurrently. Often the implementation simply forwards the arguments to the underlying ACE_Svc_Handler class. Using the code factored out into ACE. Be careful with protocols that perform non-trivial transformations of the data, such as SSLIOP or protocols that compress the stream.
ENOENT .
Implemented in TAO_IIOP_Transport.
Read len bytes from into buf. This method serializes on handler_lock_, guaranteeing that only thread can execute it on the same instance concurrently.
Implemented in TAO_IIOP_Transport.
Request has been just sent, but the reply is not received. Idle the transport now.
Request is sent and the reply is received. Idle the transport now.
Call the implementation method after obtaining the lock.
Initialising the messaging object. This would be used by the connector side. On the acceptor side the connection handler would take care of the messaging objects.
Extracts the list of listen points from the cdr stream. The list would have the protocol specific details of the ListenPoints Reimplemented in TAO_IIOP_Transport.
Hooks that can be overridden in concrete transports. These hooks are invoked just after connection establishment (or after a connection is fetched from cache). The return value signifies whether the invoker should proceed with post connection establishment activities. Protocols like SSLIOP need this to verify whether connections already established have valid certificates. There are no pre_connect_hooks () since the transport doesn't exist before a connection establishment. :-)
Memory management routines.
Initialising the messaging object. This would be used by the connector side. On the acceptor side the connection handler would take care of the messaging objects.
Return the messaging object that is used to format the data that needs to be sent.
Return the event handler used to receive notifications from the Reactor. Normally a concrete TAO_Transport object has-a ACE_Event_Handler member that functions as an adapter between the ACE_Reactor framework and the TAO pluggable protocol framework. In all the protocols implemented so far this role is fullfilled by an instance of ACE_Svc_Handler.
Implemented in TAO_IIOP_Transport.
Is this transport really connected.
Perform all the actions when this transport get opened.
do what needs to be done when closing the transport
Get the connection handler for this transport.
Accessor for the output CDR stream.
Accessor for synchronizing Transport OutputCDR access.
Set the flush in post open flag.
Implemented in TAO_IIOP_Transport.
This is a request for the transport object to write a LocateRequest header before it is sent out.
This is a request for the transport object to write a request header before it sends out the request Reimplemented in TAO_IIOP_Transport.
Callback to read incoming data. The ACE_Event_Handler adapter invokes this method as part of its handle_input() operation.
Prepare the waiting and demuxing strategy to receive a reply for a new request. Preparing the ORB to receive the reply only once the request is completely sent opens the system to some subtle race conditions: suppose the ORB is running in a multi-threaded configuration, thread A makes a request while thread B is using the Reactor to process all incoming requests. Thread A could be implemented as follows: 1) send the request 2) setup the ORB to receive the reply 3) wait for the request but in this case thread B may receive the reply between step (1) and (2), and drop it as an invalid or unexpected message. Consequently the correct implementation is: 1) setup the ORB to receive the reply 2) send the request 3) wait for the reply The following method encapsulates this idiom.
Implemented in TAO_IIOP_Transport.
This method formats the stream and then sends the message on the transport. Once the ORB is prepared to receive a reply (see send_request() above), and all the arguments have been marshaled the CDR stream must be 'formatted', i.e. the message_size field in the GIOP header can finally be set to the proper value. Implemented in TAO_IIOP_Transport.
Sent the contents of message_block.
Process the message by sending it to the higher layers of the ORB.
Implement send_message_shared() assuming the handler_lock_ is held.
Queue a message for message_block
Format and queue a message for stream
Send a message block chain,.
Send a message block chain, assuming the lock is held.
Cache management.
Cache management.
Cache management.
The timeout callback, invoked when any of the timers related to this transport expire.
This is the only legal ACT in the current configuration....
Accessor to recv_buffer_size_.
Accessor to sent_byte_count_.
CodeSet Negotiation - Get the char codeset translator factory.
CodeSet Negotiation - Get the wchar codeset translator factory.
CodeSet negotiation - Set the char codeset translator factory.
CodeSet negotiation - Set the wchar codeset translator factory.
Use the Transport's codeset factories to set the translator for input and output CDRs.
It is necessary to clear the codeset translator when a CDR stream is used for more than one GIOP message. This is required since the header must not be translated, whereas the body must be.
Return true if the tcs has been set. CodeSet negotiation.
Set the state of the first_request_ flag to false.
Get the first request flag.
Notify all the components inside a Transport when the underlying connection is closed.
Transport statistics.
Helper method that returns the Transport Cache Manager.
Send some of the data in the queue. As the outgoing data is drained this method is invoked to send as much of the current message as possible. Returns 0 if there is more data to send, -1 if there was an error and 1 if the message was completely sent.
Implement drain_queue() assuming the lock is held.
Check if there are messages pending in the queue. This version assumes that the lock is already held. Use with care!
A helper routine used in drain_queue_i().
Schedule handle_output() callbacks.
Cancel handle_output() callbacks.
Cleanup the queue. Exactly byte_count bytes have been sent, the queue must be cleaned up as potentially several messages have been completely sent out. It leaves on head_ the next message to send out.
Cleanup the complete queue.
Check if the buffering constraints have been reached.
Send a synchronous message, i.e. block until the message is on the wire
Send a reply message, i.e. do not block until the message is on the wire, but just return after adding them to the queue.
Send an asynchronous message, i.e. do not block until the message is on the wire
A helper method used by send_synchronous_message_i() and send_reply_message_i(). Reusable code that could be used by both the methods.
Check if the flush timer is still pending.
The flush timer expired or was explicitly cancelled, mark it as not pending
Print out error messages if the event handler is not valid.
Is invoked by handle_input operation. It consolidate message on top of incoming_message_stack. The amount of missing data is known and recv operation copies data directly into message buffer, as much as a single recv-invocation provides.
Is invoked by handle_input operation. It parses new messages from input stream or consolidates messages whose header has been partially read, the message size being unknown so far. It parses as much data as a single recv-invocation provides.
Is invoked by handle_input_parse_data. Parses all messages remaining in message_block.
Assume the lock is held.
Allocate a partial message block and store it in our partial_message_ data member.
Friends And Related Function Documentation
These classes need privileged access to:
Needs priveleged access to event_handler_i ()
Member Data Documentation
IOP protocol tag.
Global orbcore resource.
Our entry in the cache. We don't own this. It is here for our convenience. We cannot just change things around.
Strategy to decide whether multiple requests can be sent over the same connection or the connection is exclusive for a request.
Strategy for waiting for the reply after sending the request.
Use to check if bidirectional info has been synchronized with the peer. Have we sent any info on bidirectional information or have we received any info regarding making the connection served by this transport bidirectional. The flag is used as follows: + We dont want to send the bidirectional context info more than once on the connection. Why? Waste of marshalling and demarshalling time on the client. + On the server side -- once a client that has established the connection asks the server to use the connection both ways, we *dont* want the server to pack service info to the client. That is not allowed. We need a flag to prevent such a things from happening. The value of this flag will be 0 if the client sends info and 1 if the server receives the info.
Implement the outgoing data queue.
Queue of the consolidated, incoming messages..
Stack of incoming fragments, consolidated messages are going to be enqueued in "incoming_message_queue_"
The queue will start draining no later than <queeing_deadline_> if* the deadline is
The timer ID.
The adapter used to receive timeout callbacks from the Reactor.
Lock that insures that activities that *might* use handler-related resources (such as a connection handler) get serialized. This is an
A unique identifier for the transport. This never *never* changes over the lifespan, so we don't have to worry about locking it. HINT: Protocol-specific transports that use connection handler might choose to set this to the handle for their connection.
Used by the LRU, LFU and FIFO Connection Purging Strategies.
Size of the buffer received.
Number of bytes sent.
Is this transport really connected or not. In case of oneways with SYNC_NONE Policy we don't wait until the connection is ready and we buffer the requests in this transport until the connection is ready Our messaging object.
Additional member values required to support codeset translation. @Phil, I think it would be nice if we could think of a way to do the following. We have been trying to use the transport for marking about translator factories and such! IMHO this is a wrong encapulation ie. trying to populate the transport object with these details. We should probably have a class something like TAO_Message_Property or TAO_Message_Translator or whatever (I am sure you get the idea) and encapsulate all these details. Coupling these seems odd. if I have to be more cynical we can move this to the connection_handler and it may more sense with the DSCP stuff around there. Do you agree?
The tcs_set_ flag indicates that negotiation has occured and so the translators are correct, since a null translator is valid if both ends are using the same codeset, whatever that codeset might be.
First_request_ is true until the first request is sent or received. This is necessary since codeset context information is necessary only on the first request. After that, the translators are fixed for the life of the connection.
Holds the partial GIOP message (if there is one).
Statistics.
Indicate that flushing needs to be done in post_open().
lock for synchronizing Transport OutputCDR access
The documentation for this class was generated from the following files: Generated on Mon Sep 15 07:42:59 2008 for TAO by 1.5.5 |