// This may look like C code, but it is really -*- C++ -*-
// 
// <copyright> 
//  
//  Copyright (c) 1997
//  Institute for Information Processing and Computer Supported New Media (IICM), 
//  Graz University of Technology, Austria. 
//  
// </copyright> 
// 
// 
// <file> 
// 
// Name:        tiorpchdr.C
// 
// Purpose:     
// 
// Created:     20 Feb 1997   Joerg Faschingbauer
// 
// Modified:    
// 
// Description: 
// 
// $Id: tiorpchdr.C,v 1.1 1997/02/20 19:32:25 jfasch Exp $
// 
// $Log: tiorpchdr.C,v $
// Revision 1.1  1997/02/20 19:32:25  jfasch
// Initial revision
//
// 
// </file> 
#include "tiorpchdr.h"
#include "tiorpcstream.h"

// Initialize the header for an outgoing RPC request.

TIORpcHdr::TIORpcHdr(void* writer, int request) :
//    _writer(writer),
    _request(request),
    _ndata(0)
{
    _writer = writer;
}

// Initialize the header for an incoming RPC request.

TIORpcHdr::TIORpcHdr() :
//    _reader(0),
    _request(0),
    _ndata(0)
{
    _reader = 0;
}

// If incomplete_request was set, explicitly call underflow in an
// attempt to complete an incoming RPC request by reading additional
// data and reset the flag.  Set the stream in eof state if no
// additional data was available or in fail state if it was already in
// eof state.  If the stream is still good, call read_request to check
// if the incoming RPC request is complete yet.  If it is, extract its
// header, else set incomplete_request to note so.  Decrement the
// length (which counted the entire request) by the space that the
// header occupied to count only the data following the header.

TIOrpcstream& operator>>(TIOrpcstream& client, TIORpcHdr& hdr) {
   // jfasch 20.3.1995: have to call read_request() of the stream's
   // rpcbuf. iostreamb's negotiate() works fine in principle, but
   // sometimes the other side may write a request immediately after
   // it (in fact, mostly). in most cases the last byte read by
   // iostreamb::negotiate() comes in a single packet (the other side
   // has called flush() after writing it).

   // but sometimes the other side's system collects that last byte
   // together with the first request into one packet, so that my side
   // will read a part of the first request TOGETHER with the last
   // byte of iostreamb::negotiate().

   // HAVE TO CATCH THAT:
   if (client.good() && client.incomplete_request() &&
      (client.rdbuf()->read_request() == EOF)) { // <--- here
#ifdef WIN32
     if (client.rdbuf()->readon() != EOF) 
     {
#else
     if (client.rdbuf()->underflow() != EOF) {
#endif
         client.incomplete_request(false);
      } else {
         client.clear(client.rdstate() | ios::eofbit);
      }
   } else if (client.eof()) {
      client.clear(client.rdstate() | ios::failbit);
   }

   if (client.good()) {
      if (client.rdbuf()->read_request() != EOF) {
         streampos beginning = client.tellg();
         client >> hdr._ndata >> hdr._reader >> hdr._request;
         hdr._ndata -= (int)(client.tellg() - beginning);
      } else {
         client.incomplete_request(true);
      }
   }
   return client;
}

// Store the beginning of a new RPC request.  The rpcbuf automatically
// initializes the length field of the previous RPC request and skips
// the put pointer past the length field of the new RPC request so
// there's no need to examine hdr._ndata or insert its value.

TIOrpcstream& operator<<(TIOrpcstream& server, const TIORpcHdr& hdr) {
   if (!(!server) // hack for msvc++ because of lacking void*()
       && server.rdbuf()->start_request() != EOF) {
      server << hdr._reader << hdr._request;
   } else {
      server.clear(server.rdstate() | ios::failbit);
   }
   return server;
}
