Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

GIOP_Message_Base.cpp

Go to the documentation of this file.
00001 #include "tao_pch.h"
00002 // $Id: GIOP_Message_Base.cpp,v 1.1.1.3.2.5 2003/05/16 16:30:39 chad Exp $
00003 
00004 #include "GIOP_Message_Base.h"
00005 #include "operation_details.h"
00006 #include "GIOP_Utils.h"
00007 #include "debug.h"
00008 #include "ORB_Core.h"
00009 #include "Leader_Follower.h"
00010 #include "TAO_Server_Request.h"
00011 #include "GIOP_Message_Locate_Header.h"
00012 #include "Transport.h"
00013 #include "LF_Strategy.h"
00014 #include "Request_Dispatcher.h"
00015 #include "Codeset_Manager.h"
00016 
00017 #if !defined (__ACE_INLINE__)
00018 # include "GIOP_Message_Base.i"
00019 #endif /* __ACE_INLINE__ */
00020 
00021 ACE_RCSID (tao, GIOP_Message_Base, "$Id: GIOP_Message_Base.cpp,v 1.1.1.3.2.5 2003/05/16 16:30:39 chad Exp $")
00022 
00023 TAO_GIOP_Message_Base::TAO_GIOP_Message_Base (TAO_ORB_Core *orb_core,
00024                                               size_t /*input_cdr_size*/)
00025   : orb_core_ (orb_core),
00026     message_state_ (orb_core,
00027                     this)
00028 {
00029 
00030 }
00031 
00032 
00033 TAO_GIOP_Message_Base::~TAO_GIOP_Message_Base (void)
00034 {
00035 
00036 }
00037 
00038 
00039 void
00040 TAO_GIOP_Message_Base::init (CORBA::Octet /*major*/,
00041                              CORBA::Octet /*minor*/)
00042 {
00043   // Set the state
00044   // this->set_state (major, minor);
00045 }
00046 
00047 
00048 void
00049 TAO_GIOP_Message_Base::reset (void)
00050 {
00051   // no-op
00052 }
00053 
00054 int
00055 TAO_GIOP_Message_Base::generate_request_header (
00056     TAO_Operation_Details &op,
00057     TAO_Target_Specification &spec,
00058     TAO_OutputCDR &cdr
00059   )
00060 {
00061   // Get a parser for us
00062   TAO_GIOP_Message_Generator_Parser *generator_parser = 0;
00063 
00064   CORBA::Octet major, minor;
00065 
00066   cdr.get_version (major, minor);
00067 
00068   // Get the state information that we need to use
00069   this->set_state (major,
00070                    minor,
00071                    generator_parser);
00072 
00073   // Write the GIOP header first
00074   if (!this->write_protocol_header (TAO_GIOP_REQUEST,
00075                                     cdr))
00076     {
00077       if (TAO_debug_level)
00078         ACE_ERROR ((LM_ERROR,
00079                     ACE_LIB_TEXT ("(%P|%t) Error in writing GIOP header \n")));
00080 
00081       return -1;
00082     }
00083 
00084   // Now call the implementation for the rest of the header
00085   if (!generator_parser->write_request_header (op,
00086                                                spec,
00087                                                cdr))
00088     {
00089       if (TAO_debug_level)
00090         ACE_ERROR ((LM_ERROR,
00091                     ACE_LIB_TEXT ("(%P|%t) Error in writing request header \n")));
00092 
00093       return -1;
00094     }
00095 
00096   return 0;
00097 }
00098 
00099 int
00100 TAO_GIOP_Message_Base::generate_locate_request_header (
00101     TAO_Operation_Details &op,
00102     TAO_Target_Specification &spec,
00103     TAO_OutputCDR &cdr
00104  )
00105 {
00106   // Get a parser for us
00107   TAO_GIOP_Message_Generator_Parser *generator_parser = 0;
00108 
00109   CORBA::Octet major, minor;
00110 
00111   cdr.get_version (major, minor);
00112 
00113   // Get the state information that we need to use
00114   this->set_state (major,
00115                    minor,
00116                    generator_parser);
00117 
00118   // Write the GIOP header first
00119   if (!this->write_protocol_header (TAO_GIOP_LOCATEREQUEST,
00120                                     cdr))
00121     {
00122       if (TAO_debug_level)
00123         ACE_ERROR ((LM_ERROR,
00124                     ACE_LIB_TEXT ("(%P|%t) Error in writing GIOP header \n")));
00125 
00126       return -1;
00127     }
00128 
00129   // Now call the implementation for the rest of the header
00130   if (!generator_parser->write_locate_request_header
00131       (op.request_id (),
00132        spec,
00133        cdr))
00134     {
00135       if (TAO_debug_level)
00136         ACE_ERROR ((LM_ERROR,
00137                     ACE_LIB_TEXT ("(%P|%t) Error in writing locate request header \n")));
00138 
00139 
00140       return -1;
00141 
00142     }
00143 
00144   return 0;
00145 }
00146 
00147 int
00148 TAO_GIOP_Message_Base::generate_reply_header (
00149     TAO_OutputCDR &cdr,
00150     TAO_Pluggable_Reply_Params_Base &params
00151   )
00152 {
00153   // Get a parser for us
00154   TAO_GIOP_Message_Generator_Parser *generator_parser = 0;
00155 
00156   CORBA::Octet major, minor;
00157 
00158   cdr.get_version (major, minor);
00159 
00160   // Get the state information that we need to use
00161   this->set_state (major,
00162                    minor,
00163                    generator_parser);
00164 
00165   // Write the GIOP header first
00166   if (!this->write_protocol_header (TAO_GIOP_REPLY,
00167                                     cdr))
00168     {
00169       if (TAO_debug_level)
00170         ACE_ERROR ((LM_ERROR,
00171                     ACE_LIB_TEXT ("(%P|%t) Error in writing GIOP header \n")));
00172 
00173       return -1;
00174     }
00175 
00176   ACE_DECLARE_NEW_CORBA_ENV;
00177   ACE_TRY
00178     {
00179       // Now call the implementation for the rest of the header
00180       int result =
00181         generator_parser->write_reply_header (cdr,
00182                                               params
00183                                               ACE_ENV_ARG_PARAMETER);
00184       ACE_TRY_CHECK;
00185 
00186       if (!result)
00187         {
00188           if (TAO_debug_level > 4)
00189             ACE_ERROR ((LM_ERROR,
00190                         ACE_TEXT ("(%P|%t) Error in writing reply ")
00191                         ACE_TEXT ("header\n")));
00192 
00193           return -1;
00194         }
00195     }
00196   ACE_CATCHANY
00197     {
00198       if (TAO_debug_level > 4)
00199         ACE_PRINT_EXCEPTION (ACE_ANY_EXCEPTION,
00200                              "TAO_GIOP_Message_Base::generate_reply_header");
00201 
00202       return -1;
00203     }
00204   ACE_ENDTRY;
00205 
00206   return 0;
00207 }
00208 
00209 
00210 int
00211 TAO_GIOP_Message_Base::read_message (TAO_Transport * /*transport*/,
00212                                      int /*block */,
00213                                      ACE_Time_Value * /*max_wait_time*/)
00214 {
00215   return 0;
00216 }
00217 
00218 int
00219 TAO_GIOP_Message_Base::format_message (TAO_OutputCDR &stream)
00220 {
00221   // Ptr to first buffer.
00222   char *buf = (char *) stream.buffer ();
00223 
00224   // Length of all buffers.
00225   size_t total_len =
00226     stream.total_length ();
00227 
00228   // NOTE: Here would also be a fine place to calculate a digital
00229   // signature for the message and place it into a preallocated slot
00230   // in the "ServiceContext".  Similarly, this is a good spot to
00231   // encrypt messages (or just the message bodies) if that's needed in
00232   // this particular environment and that isn't handled by the
00233   // networking infrastructure (e.g., IPSEC).
00234 
00235   CORBA::ULong bodylen = ACE_static_cast(CORBA::ULong,
00236                            total_len - TAO_GIOP_MESSAGE_HEADER_LEN);
00237 
00238 #if !defined (ACE_ENABLE_SWAP_ON_WRITE)
00239   *ACE_reinterpret_cast (CORBA::ULong *, buf +
00240                          TAO_GIOP_MESSAGE_SIZE_OFFSET) = bodylen;
00241 #else
00242   if (!stream.do_byte_swap ())
00243     *ACE_reinterpret_cast (CORBA::ULong *,
00244                            buf + TAO_GIOP_MESSAGE_SIZE_OFFSET) = bodylen;
00245   else
00246     ACE_CDR::swap_4 (ACE_reinterpret_cast (char *,
00247                                            &bodylen),
00248                      buf + TAO_GIOP_MESSAGE_SIZE_OFFSET);
00249 #endif /* ACE_ENABLE_SWAP_ON_WRITE */
00250 
00251   if (TAO_debug_level > 2)
00252     {
00253       // Check whether the output cdr stream is build up of multiple
00254       // messageblocks. If so, consolidate them to one block that can be
00255       // dumped
00256       ACE_Message_Block* consolidated_block = 0;
00257       if (stream.begin()->cont () != 0)
00258         {
00259           consolidated_block = new ACE_Message_Block;
00260           ACE_CDR::consolidate (consolidated_block, stream.begin ());
00261           buf = (char *) (consolidated_block->rd_ptr ());
00262         }
00263       ///
00264       this->dump_msg ("send",
00265                       ACE_reinterpret_cast (u_char *,
00266                                             buf),
00267                       total_len);
00268 
00269       //
00270       delete consolidated_block;
00271       consolidated_block = 0;
00272       //
00273     }
00274 
00275   return 0;
00276 }
00277 
00278 TAO_Pluggable_Message_Type
00279 TAO_GIOP_Message_Base::message_type (
00280     TAO_GIOP_Message_State &msg_state)
00281 {
00282   // Convert to the right type of Pluggable Messaging message type.
00283 
00284   switch (msg_state.message_type_)
00285     {
00286     case TAO_GIOP_REQUEST:
00287       return TAO_PLUGGABLE_MESSAGE_REQUEST;
00288     case TAO_GIOP_LOCATEREQUEST:
00289       return TAO_PLUGGABLE_MESSAGE_LOCATEREQUEST;
00290 
00291     case TAO_GIOP_LOCATEREPLY:
00292       return TAO_PLUGGABLE_MESSAGE_LOCATEREPLY;
00293     case TAO_GIOP_REPLY:
00294       return TAO_PLUGGABLE_MESSAGE_REPLY;
00295 
00296     case TAO_GIOP_CLOSECONNECTION:
00297       return TAO_PLUGGABLE_MESSAGE_CLOSECONNECTION;
00298 
00299     case TAO_GIOP_FRAGMENT:
00300       return TAO_PLUGGABLE_MESSAGE_FRAGMENT;
00301 
00302     case TAO_GIOP_MESSAGERROR:
00303     case TAO_GIOP_CANCELREQUEST:
00304       // Does it happen?  why??
00305     default:
00306         ACE_ERROR ((LM_ERROR,
00307                     ACE_TEXT ("TAO (%P|%t) %N:%l        message_type : ")
00308                     ACE_TEXT ("wrong message.\n")));
00309     }
00310 
00311   return TAO_PLUGGABLE_MESSAGE_MESSAGERROR;
00312 }
00313 
00314 int
00315 TAO_GIOP_Message_Base::process_request_message (TAO_Transport *transport,
00316                                                 TAO_Queued_Data *qd)
00317 
00318 {
00319   // Set the upcall thread
00320   this->orb_core_->lf_strategy ().set_upcall_thread (this->orb_core_->leader_follower ());
00321 
00322   // Get a parser for us
00323   TAO_GIOP_Message_Generator_Parser *generator_parser = 0;
00324 
00325   // Get the state information that we need to use
00326   this->set_state (qd->major_version_,
00327                    qd->minor_version_,
00328                    generator_parser);
00329 
00330   // A buffer that we will use to initialise the CDR stream
00331   char repbuf[ACE_CDR::DEFAULT_BUFSIZE];
00332 
00333 #if defined(ACE_HAS_PURIFY)
00334   (void) ACE_OS::memset (repbuf,
00335                          '\0',
00336                          sizeof repbuf);
00337 #endif /* ACE_HAS_PURIFY */
00338 
00339   // Initialze an output CDR on the stack
00340   // NOTE: Dont jump to a conclusion as to why we are using the
00341   // inpout_cdr and hence the  global pool here. These pools will move
00342   // to the lanes anyway at some point of time. Further, it would have
00343   // been awesome to have this in TSS. But for some reason the cloning
00344   // that happens when the ORB gets flow controlled while writing a
00345   // reply is messing things up. We crash horribly. Doing this adds a
00346   // lock, we need to set things like this -- put stuff in TSS here
00347   // and transfer to global memory when we get flow controlled. We
00348   // need to work on the message block to get it right!
00349   TAO_OutputCDR output (repbuf,
00350                         sizeof repbuf,
00351                         TAO_ENCAP_BYTE_ORDER,
00352                         this->orb_core_->input_cdr_buffer_allocator (),
00353                         this->orb_core_->input_cdr_dblock_allocator (),
00354                         this->orb_core_->input_cdr_msgblock_allocator (),
00355                         this->orb_core_->orb_params ()->cdr_memcpy_tradeoff (),
00356                         qd->major_version_,
00357                         qd->minor_version_);
00358 
00359   // Get the read and write positions before we steal data.
00360   size_t rd_pos = qd->msg_block_->rd_ptr () - qd->msg_block_->base ();
00361   size_t wr_pos = qd->msg_block_->wr_ptr () - qd->msg_block_->base ();
00362   rd_pos += TAO_GIOP_MESSAGE_HEADER_LEN;
00363 
00364   if (TAO_debug_level > 0)
00365     this->dump_msg ("recv",
00366                     ACE_reinterpret_cast (u_char *,
00367                                           qd->msg_block_->rd_ptr ()),
00368                     qd->msg_block_->length ());
00369 
00370 
00371   // Create a input CDR stream. We do the following
00372   //  1 - If the incoming message block has a data block with a flag
00373   //      DONT_DELETE  (for the data block) we create an input CDR
00374   //      stream the same way.
00375   //  2 - If the incoming message block had a datablock from heap just
00376   //      use it by duplicating it and make the flag 0.
00377   // NOTE: We use the same data block in which we read the message and
00378   // we pass it on to the higher layers of the ORB. So we dont to any
00379   // copies at all here. The same is also done in the higher layers.
00380 
00381   ACE_Message_Block::Message_Flags flg = 0;
00382   ACE_Data_Block *db = 0;
00383 
00384   // Get the flag in the message block
00385   flg = qd->msg_block_->self_flags ();
00386 
00387   if (ACE_BIT_ENABLED (flg,
00388                        ACE_Message_Block::DONT_DELETE))
00389     {
00390       // Use the same datablock
00391       db = qd->msg_block_->data_block ();
00392     }
00393   else
00394     {
00395       // Use a duplicated datablock as the datablock has come off the
00396       // heap.
00397       db = qd->msg_block_->data_block ()->duplicate ();
00398     }
00399 
00400 
00401   TAO_InputCDR input_cdr (db,
00402                           flg,
00403                           rd_pos,
00404                           wr_pos,
00405                           qd->byte_order_,
00406                           qd->major_version_,
00407                           qd->minor_version_,
00408                           this->orb_core_);
00409 
00410   transport->assign_translators(&input_cdr,&output);
00411 
00412   // We know we have some request message. Check whether it is a
00413   // GIOP_REQUEST or GIOP_LOCATE_REQUEST to take action.
00414 
00415   // Once we send the InputCDR stream we need to just forget about
00416   // the stream and never touch that again for anything. We basically
00417   // loose ownership of the data_block.
00418 
00419   switch (qd->msg_type_)
00420     {
00421     case TAO_PLUGGABLE_MESSAGE_REQUEST:
00422       // Should be taken care by the state specific invocations. They
00423       // could raise an exception or write things in the output CDR
00424       // stream
00425       return this->process_request (transport,
00426                                     input_cdr,
00427                                     output,
00428                                     generator_parser);
00429 
00430     case TAO_PLUGGABLE_MESSAGE_LOCATEREQUEST:
00431       return this->process_locate_request (transport,
00432                                            input_cdr,
00433                                            output,
00434                                            generator_parser);
00435     default:
00436       return -1;
00437     }
00438 }
00439 
00440 int
00441 TAO_GIOP_Message_Base::process_reply_message (
00442     TAO_Pluggable_Reply_Params &params,
00443     TAO_Queued_Data *qd)
00444 {
00445   // Get a parser for us
00446   TAO_GIOP_Message_Generator_Parser *generator_parser = 0;
00447 
00448   // Get the state information that we need to use
00449   this->set_state (qd->major_version_,
00450                    qd->minor_version_,
00451                    generator_parser);
00452 
00453   // Get the read and write positions before we steal data.
00454   size_t rd_pos = qd->msg_block_->rd_ptr () - qd->msg_block_->base ();
00455   size_t wr_pos = qd->msg_block_->wr_ptr () - qd->msg_block_->base ();
00456   rd_pos += TAO_GIOP_MESSAGE_HEADER_LEN;
00457 
00458   if (TAO_debug_level > 0)
00459     this->dump_msg ("recv",
00460                     ACE_reinterpret_cast (u_char *,
00461                                           qd->msg_block_->rd_ptr ()),
00462                     qd->msg_block_->length ());
00463 
00464 
00465   // Create a empty buffer on stack
00466   // NOTE: We use the same data block in which we read the message and
00467   // we pass it on to the higher layers of the ORB. So we dont to any
00468   // copies at all here. The same is alos done in the higher layers.
00469   TAO_InputCDR input_cdr (qd->msg_block_->data_block (),
00470                           ACE_Message_Block::DONT_DELETE,
00471                           rd_pos,
00472                           wr_pos,
00473                           qd->byte_order_,
00474                           qd->major_version_,
00475                           qd->minor_version_,
00476                           this->orb_core_);
00477 
00478   // Reset the message state. Now, we are ready for the next nested
00479   // upcall if any.
00480   // this->message_handler_.reset (0);
00481 
00482   // We know we have some reply message. Check whether it is a
00483   // GIOP_REPLY or GIOP_LOCATE_REPLY to take action.
00484 
00485   // Once we send the InputCDR stream we need to just forget about
00486   // the stream and never touch that again for anything. We basically
00487   // loose ownership of the data_block.
00488 
00489   switch (qd->msg_type_)
00490     {
00491     case TAO_PLUGGABLE_MESSAGE_REPLY:
00492       // Should be taken care by the state specific parsing
00493       return generator_parser->parse_reply (input_cdr,
00494                                             params);
00495 
00496     case TAO_PLUGGABLE_MESSAGE_LOCATEREPLY:
00497       return generator_parser->parse_locate_reply (input_cdr,
00498                                                    params);
00499     default:
00500         return -1;
00501     }
00502 }
00503 
00504 int
00505 TAO_GIOP_Message_Base::generate_exception_reply (
00506     TAO_OutputCDR &cdr,
00507     TAO_Pluggable_Reply_Params_Base &params,
00508     CORBA::Exception &x
00509   )
00510 {
00511   // A new try/catch block, but if something goes wrong now we have no
00512   // hope, just abort.
00513   ACE_DECLARE_NEW_CORBA_ENV;
00514 
00515   ACE_TRY
00516     {
00517       // Make the GIOP & reply header.
00518       this->generate_reply_header (cdr,
00519                                    params);
00520       x._tao_encode (cdr ACE_ENV_ARG_PARAMETER);
00521       ACE_TRY_CHECK;
00522     }
00523   ACE_CATCH (CORBA_Exception, ex)
00524     {
00525       // Now we know that while handling the error an other error
00526       // happened -> no hope, close connection.
00527 
00528       // Close the handle.
00529       ACE_DEBUG ((LM_DEBUG,
00530                   ACE_TEXT ("(%P|%t|%N|%l) cannot marshal exception, ")
00531                   ACE_TEXT ("generate_exception_reply ()")));
00532       return -1;
00533     }
00534   ACE_ENDTRY;
00535   ACE_CHECK_RETURN (-1);
00536 
00537   return 0;
00538 }
00539 
00540 int
00541 TAO_GIOP_Message_Base::write_protocol_header (TAO_GIOP_Message_Type t,
00542                                               TAO_OutputCDR &msg)
00543 {
00544   // Reset the message type
00545   // Reset the message type
00546   msg.reset ();
00547 
00548   CORBA::Octet header[12] =
00549   {
00550     // The following works on non-ASCII platforms, such as MVS (which
00551     // uses EBCDIC).
00552     0x47, // 'G'
00553     0x49, // 'I'
00554     0x4f, // 'O'
00555     0x50  // 'P'
00556   };
00557 
00558   CORBA::Octet major, minor = 0;
00559   msg.get_version (major, minor);
00560 
00561   header[4] = major;
00562   header[5] = minor;
00563 
00564   // We are putting the byte order. But at a later date if we support
00565   // fragmentation and when we want to use the other 6 bits in this
00566   // octet we can have a virtual function do this for us as the
00567   // version info , Bala
00568   header[6] = (TAO_ENCAP_BYTE_ORDER ^ msg.do_byte_swap ());
00569 
00570   header[7] = CORBA::Octet(t);
00571 
00572   static int header_size = sizeof (header) / sizeof (header[0]);
00573   msg.write_octet_array (header, header_size);
00574 
00575   return msg.good_bit ();
00576 }
00577 
00578 int
00579 TAO_GIOP_Message_Base::process_request (TAO_Transport *transport,
00580                                         TAO_InputCDR &cdr,
00581                                         TAO_OutputCDR &output,
00582                                         TAO_GIOP_Message_Generator_Parser *parser)
00583 {
00584   // This will extract the request header, set <response_required>
00585   // and <sync_with_server> as appropriate.
00586   TAO_ServerRequest request (this,
00587                              cdr,
00588                              output,
00589                              transport,
00590                              this->orb_core_);
00591 
00592   CORBA::ULong request_id = 0;
00593   CORBA::Boolean response_required = 0;
00594 
00595   int parse_error = 0;
00596 
00597   ACE_DECLARE_NEW_CORBA_ENV;
00598   ACE_TRY
00599     {
00600       parse_error =
00601         parser->parse_request_header (request);
00602 
00603       TAO_Codeset_Manager *csm = request.orb_core()->codeset_manager();
00604       if (csm)
00605         csm->process_service_context(request);
00606       transport->assign_translators(&cdr,&output);
00607 
00608       // Throw an exception if the
00609       if (parse_error != 0)
00610         ACE_TRY_THROW (CORBA::MARSHAL (TAO_DEFAULT_MINOR_CODE,
00611                                        CORBA::COMPLETED_NO));
00612       request_id = request.request_id ();
00613 
00614       response_required = request.response_expected ();
00615 
00616       CORBA::Object_var forward_to;
00617 
00618       // Do this before the reply is sent.
00619       this->orb_core_->request_dispatcher ()->dispatch (
00620           this->orb_core_,
00621           request,
00622           forward_to
00623           ACE_ENV_ARG_PARAMETER);
00624       ACE_TRY_CHECK;
00625 
00626       if (!CORBA::is_nil (forward_to.in ()))
00627         {
00628           // We should forward to another object...
00629           TAO_Pluggable_Reply_Params_Base reply_params;
00630           reply_params.request_id_ = request_id;
00631           reply_params.reply_status_ = TAO_GIOP_LOCATION_FORWARD;
00632           reply_params.svc_ctx_.length (0);
00633 
00634           // Send back the reply service context.
00635           reply_params.service_context_notowned (&request.reply_service_info ());
00636 
00637           // Make the GIOP header and Reply header
00638           this->generate_reply_header (output,
00639                                        reply_params);
00640 
00641           if (!(output << forward_to.in ()))
00642             {
00643               if (TAO_debug_level > 0)
00644                 ACE_ERROR ((LM_ERROR,
00645                             ACE_TEXT ("TAO (%P|%t) ERROR: Unable to marshal ")
00646                             ACE_TEXT ("forward reference.\n")));
00647 
00648               return -1;
00649             }
00650 
00651           int result = transport->send_message (output,
00652                                                 0,
00653                                                 TAO_Transport::TAO_REPLY);
00654           if (result == -1)
00655             {
00656               if (TAO_debug_level > 0)
00657                 {
00658                   // No exception but some kind of error, yet a
00659                   // response is required.
00660                   ACE_ERROR ((LM_ERROR,
00661                               ACE_TEXT ("TAO: (%P|%t|%N|%l) %p: ")
00662                               ACE_TEXT ("cannot send reply\n"),
00663                               ACE_TEXT ("TAO_GIOP_Message_Base::process_request")));
00664                 }
00665             }
00666           return result;
00667         }
00668     }
00669   // Only CORBA exceptions are caught here.
00670   ACE_CATCHANY
00671     {
00672       int result = 0;
00673 
00674       if (response_required)
00675         {
00676           result = this->send_reply_exception (transport,
00677                                                output,
00678                                                request_id,
00679                                                &request.reply_service_info (),
00680                                                &ACE_ANY_EXCEPTION);
00681           if (result == -1)
00682             {
00683               if (TAO_debug_level > 0)
00684                 {
00685                   ACE_ERROR ((LM_ERROR,
00686                               ACE_TEXT ("TAO: (%P|%t|%N|%l) %p: ")
00687                               ACE_TEXT ("cannot send exception\n"),
00688                               ACE_TEXT ("process_connector_request ()")));
00689 
00690                   ACE_PRINT_EXCEPTION (
00691                       ACE_ANY_EXCEPTION,
00692                       "TAO_GIOP_Message_Base::process_request[1]");
00693                 }
00694             }
00695 
00696         }
00697       else if (TAO_debug_level > 0)
00698         {
00699           // It is unfotunate that an exception (probably a system
00700           // exception) was thrown by the upcall code (even by the
00701           // user) when the client was not expecting a response.
00702           // However, in this case, we cannot close the connection
00703           // down, since it really isn't the client's fault.
00704 
00705           ACE_ERROR ((LM_ERROR,
00706                       ACE_TEXT ("(%P|%t) exception thrown ")
00707                       ACE_TEXT ("but client is not waiting a response\n")));
00708 
00709           ACE_PRINT_EXCEPTION (
00710               ACE_ANY_EXCEPTION,
00711               "TAO_GIOP_Message_Base::process_request[2]");
00712         }
00713 
00714       return result;
00715     }
00716 #if defined (TAO_HAS_EXCEPTIONS)
00717   ACE_CATCHALL
00718     {
00719       // @@ TODO some c++ exception or another, but what do we do with
00720       //    it?
00721       // We are supposed to map it into a CORBA::UNKNOWN exception.
00722       // BTW, this cannot be detected if using the <env> mapping.  If
00723       // we have native exceptions but no support for them in the ORB
00724       // we should still be able to catch it.  If we don't have native
00725       // exceptions it couldn't have been raised in the first place!
00726       int result = 0;
00727 
00728       if (response_required)
00729         {
00730           CORBA::UNKNOWN exception (CORBA::SystemException::_tao_minor_code
00731                                     (TAO_UNHANDLED_SERVER_CXX_EXCEPTION, 0),
00732                                     CORBA::COMPLETED_MAYBE);
00733 
00734           result = this->send_reply_exception (transport,
00735                                                output,
00736                                                request_id,
00737                                                &request.reply_service_info (),
00738                                                &exception);
00739           if (result == -1)
00740             {
00741               if (TAO_debug_level > 0)
00742                 {
00743                   ACE_ERROR ((LM_ERROR,
00744                               ACE_TEXT ("TAO: (%P|%t|%N|%l) %p: ")
00745                               ACE_TEXT ("cannot send exception\n"),
00746                               ACE_TEXT ("process_request ()")));
00747                   ACE_PRINT_EXCEPTION (
00748                       exception,
00749                       "TAO_GIOP_Message_Base::process_request[3]");
00750                 }
00751             }
00752         }
00753       else if (TAO_debug_level > 0)
00754         {
00755           // It is unfotunate that an exception (probably a system
00756           // exception) was thrown by the upcall code (even by the
00757           // user) when the client was not expecting a response.
00758           // However, in this case, we cannot close the connection
00759           // down, since it really isn't the client's fault.
00760           ACE_ERROR ((LM_ERROR,
00761                       ACE_TEXT ("(%P|%t|%N|%l) exception thrown ")
00762                       ACE_TEXT ("but client is not waiting a response\n")));
00763         }
00764 
00765       return result;
00766     }
00767 #endif /* TAO_HAS_EXCEPTIONS */
00768   ACE_ENDTRY;
00769 
00770   return 0;
00771 }
00772 
00773 
00774 int
00775 TAO_GIOP_Message_Base::process_locate_request (TAO_Transport *transport,
00776                                                TAO_InputCDR &input,
00777                                                TAO_OutputCDR &output,
00778                                                TAO_GIOP_Message_Generator_Parser *parser)
00779 {
00780   // This will extract the request header, set <response_required> as
00781   // appropriate.
00782   TAO_GIOP_Locate_Request_Header locate_request (input,
00783                                                  this->orb_core_);
00784 
00785   TAO_GIOP_Locate_Status_Msg status_info;
00786 
00787   // Defaulting.
00788   status_info.status = TAO_GIOP_UNKNOWN_OBJECT;
00789 
00790   CORBA::Boolean response_required = 1;
00791 
00792   ACE_DECLARE_NEW_CORBA_ENV;
00793   ACE_TRY
00794     {
00795       int parse_error =
00796         parser->parse_locate_header (locate_request);
00797 
00798       if (parse_error != 0)
00799         {
00800           ACE_TRY_THROW (CORBA::MARSHAL (TAO_DEFAULT_MINOR_CODE,
00801                                          CORBA::COMPLETED_NO));
00802         }
00803 
00804       TAO_ObjectKey tmp_key (locate_request.object_key ().length (),
00805                              locate_request.object_key ().length (),
00806                              locate_request.object_key ().get_buffer (),
00807                              0);
00808 
00809       // Set it to an error state
00810       parse_error = 1;
00811       CORBA::ULong req_id = locate_request.request_id ();
00812 
00813       // We will send the reply. The ServerRequest class need not send
00814       // the reply
00815       CORBA::Boolean deferred_reply = 1;
00816       TAO_ServerRequest server_request (this,
00817                                         req_id,
00818                                         response_required,
00819                                         deferred_reply,
00820                                         tmp_key,
00821                                         "_non_existent",
00822                                         output,
00823                                         transport,
00824                                         this->orb_core_,
00825                                         parse_error);
00826 
00827       if (parse_error != 0)
00828         {
00829           ACE_TRY_THROW (CORBA::MARSHAL (TAO_DEFAULT_MINOR_CODE,
00830                                          CORBA::COMPLETED_NO));
00831         }
00832 
00833       CORBA::Object_var forward_to;
00834 
00835       this->orb_core_->request_dispatcher ()->dispatch (
00836           this->orb_core_,
00837           server_request,
00838           forward_to
00839            ACE_ENV_ARG_PARAMETER);
00840       ACE_TRY_CHECK;
00841 
00842       if (!CORBA::is_nil (forward_to.in ()))
00843         {
00844           status_info.status = TAO_GIOP_OBJECT_FORWARD;
00845           status_info.forward_location_var = forward_to;
00846           ACE_DEBUG ((LM_DEBUG,
00847                       ACE_TEXT ("handle_locate has been called: forwarding\n")));
00848         }
00849       else if (server_request.exception_type () == TAO_GIOP_NO_EXCEPTION)
00850         {
00851           // We got no exception, so the object is here.
00852           status_info.status = TAO_GIOP_OBJECT_HERE;
00853           if (TAO_debug_level > 0)
00854             ACE_DEBUG ((LM_DEBUG,
00855                         ACE_TEXT ("TAO: (%P|%t) handle_locate() : found\n")));
00856         }
00857       else
00858         {
00859           status_info.forward_location_var = server_request.forward_location ();
00860 
00861           if (!CORBA::is_nil (status_info.forward_location_var.in ()))
00862             {
00863               status_info.status = TAO_GIOP_OBJECT_FORWARD;
00864               ACE_DEBUG ((LM_DEBUG,
00865                           ACE_TEXT ("handle_locate has been called: forwarding\n")));
00866             }
00867           else
00868             {
00869               // Normal exception, so the object is not here
00870               status_info.status = TAO_GIOP_UNKNOWN_OBJECT;
00871               ACE_DEBUG ((LM_DEBUG,
00872                           ACE_TEXT ("handle_locate has been called: not here\n")));
00873             }
00874         }
00875     }
00876 
00877   ACE_CATCHANY
00878     {
00879       // Normal exception, so the object is not here
00880       status_info.status = TAO_GIOP_UNKNOWN_OBJECT;
00881       if (TAO_debug_level > 0)
00882         ACE_DEBUG ((LM_DEBUG,
00883                     ACE_TEXT ("TAO (%P|%t) TAO_GIOP_Message_Base::process_locate_request - ")
00884                     ACE_TEXT ("CORBA exception raised\n")));
00885     }
00886 #if defined (TAO_HAS_EXCEPTIONS)
00887   ACE_CATCHALL
00888     {
00889       // Normal exception, so the object is not here
00890       status_info.status = TAO_GIOP_UNKNOWN_OBJECT;
00891       if (TAO_debug_level > 0)
00892         ACE_DEBUG ((LM_DEBUG,
00893                     ACE_TEXT ("TAO (%P|%t) TAO_GIOP_Message_Base::process_locate_request - ")
00894                     ACE_TEXT ("C++ exception raised\n")));
00895     }
00896 #endif /* TAO_HAS_EXCEPTIONS */
00897   ACE_ENDTRY;
00898 
00899   return this->make_send_locate_reply (transport,
00900                                        locate_request,
00901                                        status_info,
00902                                        output,
00903                                        parser);
00904 }
00905 
00906 int
00907 TAO_GIOP_Message_Base::make_send_locate_reply (TAO_Transport *transport,
00908                                                TAO_GIOP_Locate_Request_Header &request,
00909                                                TAO_GIOP_Locate_Status_Msg &status_info,
00910                                                TAO_OutputCDR &output,
00911                                                TAO_GIOP_Message_Generator_Parser *parser)
00912 {
00913   // Note here we are making the Locate reply header which is *QUITE*
00914   // different from the reply header made by the make_reply () call..
00915   // Make the GIOP message header
00916   this->write_protocol_header (TAO_GIOP_LOCATEREPLY,
00917                                output);
00918 
00919   // This writes the header & body
00920   parser->write_locate_reply_mesg (output,
00921                                    request.request_id (),
00922                                    status_info);
00923 
00924   // Send the message
00925   int result = transport->send_message (output,
00926                                         0,
00927                                         TAO_Transport::TAO_REPLY);
00928 
00929   // Print out message if there is an error
00930   if (result == -1)
00931     {
00932       if (TAO_debug_level > 0)
00933         {
00934           ACE_ERROR ((LM_ERROR,
00935                       ACE_TEXT ("TAO: (%P|%t) %p: cannot send reply\n"),
00936                       ACE_TEXT ("TAO_GIOP_Message_Base::make_send_locate_reply")));
00937         }
00938     }
00939 
00940   return result;
00941 }
00942 
00943 // Send an "I can't understand you" message -- again, the message is
00944 // prefabricated for simplicity.  This implies abortive disconnect (at
00945 // the application level, if not at the level of TCP).
00946 //
00947 // NOTE that IIOP will still benefit from TCP's orderly disconnect.
00948 int
00949 TAO_GIOP_Message_Base::send_error (TAO_Transport *transport)
00950 {
00951   const char
00952     error_message [TAO_GIOP_MESSAGE_HEADER_LEN] =
00953   {
00954     // The following works on non-ASCII platforms, such as MVS (which
00955     // uses EBCDIC).
00956     0x47, // 'G'
00957     0x49, // 'I'
00958     0x4f, // 'O'
00959     0x50, // 'P'
00960     (CORBA::Octet) 1, // Use the lowest GIOP version
00961     (CORBA::Octet) 0,
00962     TAO_ENCAP_BYTE_ORDER,
00963     TAO_GIOP_MESSAGERROR,
00964     0, 0, 0, 0
00965   };
00966 
00967   // @@ Q: How does this works with GIOP lite?
00968   //    A: It doesn't
00969 
00970   this->dump_msg ("send_error",
00971                   (const u_char *) error_message,
00972                   TAO_GIOP_MESSAGE_HEADER_LEN);
00973 
00974   ACE_Data_Block data_block (TAO_GIOP_MESSAGE_HEADER_LEN,
00975                              ACE_Message_Block::MB_DATA,
00976                              error_message,
00977                              0,
00978                              0,
00979                              ACE_Message_Block::DONT_DELETE,
00980                              0);
00981   ACE_Message_Block message_block(&data_block,
00982                                   ACE_Message_Block::DONT_DELETE);
00983   message_block.wr_ptr (TAO_GIOP_MESSAGE_HEADER_LEN);
00984 
00985   size_t bt;
00986   int result = transport->send_message_block_chain (&message_block, bt);
00987   if (result == -1)
00988     {
00989       if (TAO_debug_level > 0)
00990         ACE_DEBUG ((LM_DEBUG,
00991                     ACE_TEXT ("TAO (%N|%l|%P|%t) error sending error to transport %lu\n"),
00992                     transport->id ()));
00993     }
00994 
00995   return result;
00996 }
00997 
00998 void
00999 TAO_GIOP_Message_Base::set_state (
01000     CORBA::Octet def_major,
01001     CORBA::Octet def_minor,
01002     TAO_GIOP_Message_Generator_Parser *&gen_parser)
01003 {
01004   switch (def_major)
01005     {
01006     case 1:
01007       switch (def_minor)
01008         {
01009         case 0:
01010           gen_parser =
01011             &this->tao_giop_impl_.tao_giop_10;
01012           break;
01013         case 1:
01014           gen_parser =
01015             &this->tao_giop_impl_.tao_giop_11;
01016           break;
01017         case 2:
01018           gen_parser =
01019             &this->tao_giop_impl_.tao_giop_12;
01020           break;
01021         default:
01022           break;
01023         }
01024       break;
01025     default:
01026       break;
01027     }
01028 }
01029 
01030 
01031 // Server sends an "I'm shutting down now, any requests you've sent me
01032 // can be retried" message to the server.  The message is prefab, for
01033 // simplicity.
01034 //
01035 // NOTE: this is IIOP-specific though it doesn't look like it is.  It
01036 // relies on a TCP-ism: orderly disconnect, which doesn't exist in all
01037 // transport protocols.  Versions of GIOP atop some transport that's
01038 // lacking orderly disconnect must define some transport-specific
01039 // handshaking (e.g. the XNS/SPP handshake convention) in order to
01040 // know that the same transport semantics are provided when shutdown
01041 // is begun with messages "in flight". (IIOP doesn't report false
01042 // errors in the case of "clean shutdown", because it relies on
01043 // orderly disconnect as provided by TCP.  This quality of service is
01044 // required to write robust distributed systems.)
01045 
01046 void
01047 TAO_GIOP_Message_Base::
01048   send_close_connection (const TAO_GIOP_Message_Version &version,
01049                          TAO_Transport *transport,
01050                          void *)
01051 {
01052 
01053   // static CORBA::Octet
01054   // I hate  this in every method. Till the time I figure out a way
01055   // around  I will have them here hanging around.
01056   const char close_message [TAO_GIOP_MESSAGE_HEADER_LEN] =
01057   {
01058     // The following works on non-ASCII platforms, such as MVS (which
01059     // uses EBCDIC).
01060     0x47, // 'G'
01061     0x49, // 'I'
01062     0x4f, // 'O'
01063     0x50, // 'P'
01064     version.major,
01065     version.minor,
01066     TAO_ENCAP_BYTE_ORDER,
01067     TAO_GIOP_CLOSECONNECTION,
01068     0, 0, 0, 0
01069   };
01070 
01071   // It's important that we use a reliable shutdown after we send this
01072   // message, so we know it's received.
01073   //
01074   // @@ should recv and discard queued data for portability; note
01075   // that this won't block (long) since we never set SO_LINGER
01076 
01077   this->dump_msg ("send_close_connection",
01078                   (const u_char *) close_message,
01079                   TAO_GIOP_MESSAGE_HEADER_LEN);
01080 
01081 #if 0
01082   // @@CJC I don't think we need this check b/c the transport's send()
01083   // will simply return -1.  However, I guess we could create something
01084   // like TAO_Tranport::is_closed() that returns whether the connection
01085   // is already closed.  The problem with that, however, is that it's
01086   // entirely possible that is_closed() could return TRUE, and then the
01087   // transport could get closed down btw. the time it gets called and the
01088   // time that the send actually occurs.
01089   ACE_HANDLE which = transport->handle ();
01090   if (which == ACE_INVALID_HANDLE)
01091     {
01092       if (TAO_debug_level > 0)
01093         ACE_DEBUG ((LM_DEBUG,
01094                     "TAO (%P|%t) TAO_GIOP_Message_Base::send_close_connection -"
01095                     " connection already closed\n"));
01096       return;
01097     }
01098 #endif
01099 
01100   ACE_Data_Block data_block (TAO_GIOP_MESSAGE_HEADER_LEN,
01101                              ACE_Message_Block::MB_DATA,
01102                              close_message,
01103                              0,
01104                              0,
01105                              ACE_Message_Block::DONT_DELETE,
01106                              0);
01107   ACE_Message_Block message_block(&data_block);
01108   message_block.wr_ptr (TAO_GIOP_MESSAGE_HEADER_LEN);
01109 
01110   size_t bt;
01111   int result = transport->send_message_block_chain (&message_block, bt);
01112   if (result == -1)
01113     {
01114       if (TAO_debug_level > 0)
01115         ACE_ERROR ((LM_ERROR,
01116                     "(%P|%t) error closing connection %lu, errno = %d\n",
01117                     transport->id (), errno));
01118     }
01119 
01120   transport->close_connection ();
01121   ACE_DEBUG ((LM_DEBUG,
01122               "(%P|%t) shut down transport, handle %d\n",
01123               transport-> id ()));
01124 
01125 }
01126 
01127 
01128 int
01129 TAO_GIOP_Message_Base::send_reply_exception (
01130     TAO_Transport *transport,
01131     TAO_OutputCDR &output,
01132     CORBA::ULong request_id,
01133     IOP::ServiceContextList *svc_info,
01134     CORBA::Exception *x
01135   )
01136 {
01137   TAO_Pluggable_Reply_Params_Base reply_params;
01138   reply_params.request_id_ = request_id;
01139   reply_params.svc_ctx_.length (0);
01140 
01141   // We are going to send some data
01142   reply_params.argument_flag_ = 1;
01143 
01144   // Send back the service context we received.  (RTCORBA relies on
01145   // this).
01146   reply_params.service_context_notowned (svc_info);
01147 
01148   reply_params.reply_status_ = TAO_GIOP_USER_EXCEPTION;
01149 
01150   if (CORBA::SystemException::_downcast (x) != 0)
01151     {
01152       reply_params.reply_status_ = TAO_GIOP_SYSTEM_EXCEPTION;
01153     }
01154 
01155   if (this->generate_exception_reply (output,
01156                                       reply_params,
01157                                       *x) == -1)
01158     return -1;
01159 
01160   return transport->send_message (output,
01161                                   0,
01162                                   TAO_Transport::TAO_REPLY);
01163 }
01164 
01165 void
01166 TAO_GIOP_Message_Base::dump_msg (const char *label,
01167                                  const u_char *ptr,
01168                                  size_t len)
01169 {
01170 
01171   if (TAO_debug_level >= 5)
01172     {
01173       static const char digits[] = "0123456789ABCD";
01174       static const char *names[] =
01175       {
01176         "Request",
01177         "Reply",
01178         "CancelRequest",
01179         "LocateRequest",
01180         "LocateReply",
01181         "CloseConnection",
01182         "MessageError",
01183         "Fragment"
01184       };
01185 
01186       // Message name.
01187       const char *message_name = "UNKNOWN MESSAGE";
01188       u_long slot = ptr[TAO_GIOP_MESSAGE_TYPE_OFFSET];
01189       if (slot < sizeof (names) / sizeof (names[0]))
01190         message_name = names[slot];
01191 
01192       // Byte order.
01193       int byte_order = ptr[TAO_GIOP_MESSAGE_FLAGS_OFFSET] & 0x01;
01194 
01195       // Get the version info
01196       // CORBA::Octet major = ptr[TAO_GIOP_VERSION_MAJOR_OFFSET];
01197       CORBA::Octet minor = ptr[TAO_GIOP_VERSION_MINOR_OFFSET];
01198 
01199       // request/reply id.
01200       CORBA::ULong tmp = 0;
01201       CORBA::ULong *id = &tmp;
01202       char *tmp_id = 0;
01203 
01204       if (ptr[TAO_GIOP_MESSAGE_TYPE_OFFSET] == TAO_GIOP_REQUEST ||
01205           ptr[TAO_GIOP_MESSAGE_TYPE_OFFSET] == TAO_GIOP_REPLY)
01206         {
01207           if (minor < 2)
01208             {
01209               // @@ Only works if ServiceContextList is empty....
01210               tmp_id = (char * ) (ptr + TAO_GIOP_MESSAGE_HEADER_LEN  + 4);
01211             }
01212           else
01213             {
01214               tmp_id = (char * ) (ptr + TAO_GIOP_MESSAGE_HEADER_LEN);
01215             }
01216 #if !defined (ACE_DISABLE_SWAP_ON_READ)
01217       if (byte_order == TAO_ENCAP_BYTE_ORDER)
01218         {
01219           id = ACE_reinterpret_cast (ACE_CDR::ULong*, tmp_id);
01220         }
01221       else
01222         {
01223           ACE_CDR::swap_4 (tmp_id, ACE_reinterpret_cast (char*,id));
01224         }
01225 #else
01226       id = ACE_reinterpret_cast(ACE_CDR::ULong*, tmp_id);
01227 #endif /* ACE_DISABLE_SWAP_ON_READ */
01228 
01229         }
01230 
01231       // Print.
01232       ACE_DEBUG ((LM_DEBUG,
01233                   "TAO (%P|%t) - GIOP_Message_Base::dump_msg, "
01234                   "%s GIOP v%c.%c msg, %d data bytes, %s endian, "
01235                   "Type %s[%u]\n",
01236                   label,
01237                   digits[ptr[TAO_GIOP_VERSION_MAJOR_OFFSET]],
01238                   digits[ptr[TAO_GIOP_VERSION_MINOR_OFFSET]],
01239                   len - TAO_GIOP_MESSAGE_HEADER_LEN ,
01240                   (byte_order == TAO_ENCAP_BYTE_ORDER) ? ACE_LIB_TEXT("my") : ACE_LIB_TEXT("other"),
01241                   ACE_TEXT_CHAR_TO_TCHAR(message_name),
01242                   *id));
01243 
01244       if (TAO_debug_level >= 10)
01245         ACE_HEX_DUMP ((LM_DEBUG,
01246                        (const char *) ptr,
01247                        len,
01248                        ACE_TEXT ("GIOP message")));
01249     }
01250 }
01251 
01252 int
01253 TAO_GIOP_Message_Base::generate_locate_reply_header (
01254     TAO_OutputCDR & /*cdr*/,
01255     TAO_Pluggable_Reply_Params_Base & /*params*/)
01256 {
01257   return 0;
01258 }
01259 
01260 int
01261 TAO_GIOP_Message_Base::is_ready_for_bidirectional (TAO_OutputCDR &msg)
01262 {
01263   // Get a parser for us
01264   TAO_GIOP_Message_Generator_Parser *parser = 0;
01265 
01266   CORBA::Octet major, minor = 0;
01267 
01268   msg.get_version (major, minor);
01269 
01270   // Get the state information that we need to use
01271   this->set_state (major,
01272                    minor,
01273                    parser);
01274 
01275   // We dont really know.. So ask the generator and parser objects that
01276   // we know.
01277   // @@ TODO: Need to make this faster, instead of making virtual
01278   // call, try todo the check within this class
01279   return parser->is_ready_for_bidirectional ();
01280 }
01281 
01282 
01283 void
01284 TAO_GIOP_Message_Base::set_queued_data_from_message_header (
01285   TAO_Queued_Data *qd,
01286   const ACE_Message_Block &mb
01287   ) const
01288 {
01289   // @@CJC: Try leaving out the declaration for this->message_state_
01290   // and see what pukes.  I don't think we need it any more.
01291   TAO_GIOP_Message_State state;
01292   if (state.take_values_from_message_block (mb) == -1)
01293     {
01294       // what the heck do we do here?!
01295       qd->current_state_ = TAO_Queued_Data::INVALID;
01296       return;
01297     }
01298 
01299   // It'd be nice to have an abstract base for GIOP_Message_State
01300   // so that there could just be a line like:
01301   //   qd->take_values_from (state);
01302   // Get the message information
01303   qd->byte_order_ = state.byte_order ();
01304   qd->major_version_ = state.giop_version ().major;
01305   qd->minor_version_ = state.giop_version ().minor;
01306   qd->more_fragments_ = state.more_fragments () ? 1 : 0;
01307   qd->request_id_ = state.request_id_;
01308   qd->msg_type_= message_type (state);
01309   qd->missing_data_bytes_ = state.payload_size ();
01310 }
01311 
01312 int
01313 TAO_GIOP_Message_Base::check_for_valid_header (
01314   const ACE_Message_Block &mb
01315   ) const
01316 {
01317   // NOTE!  We don't hardcode the length of the header b/c header_length should
01318   // be eligible for inlining by pretty much any compiler, and it should return
01319   // a constant.  The rest of this method is hard-coded and hand-optimized because
01320   // this method gets called A LOT.
01321   if (mb.length () < this->header_length ())
01322     return 0;
01323 
01324   // Is finding that it's the right length and the magic bytes present
01325   // enough to declare it a valid header?  I think so...
01326   register const char* h = mb.rd_ptr ();
01327   return (h[0] == 'G' && h[1] == 'I' && h[2] == 'O' && h[3] == 'P');
01328 }

Generated on Mon Jun 16 13:48:24 2003 for TAO by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002