// @(#)root/netx:$Name:  $:$Id: TXSocket.cxx,v 1.5 2004/12/16 19:23:18 rdm Exp $
// Author: Alvise Dorigo, Fabrizio Furano

/*************************************************************************
 * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TXSocket                                                             //
//                                                                      //
// Extension of TSocket to handle read/write and connection timeouts.   //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TXSocket.h"
#include "TEnv.h"
#include "TError.h"
#include "TException.h"
#include "TXDebug.h"

ClassImp(TXSocket);

//_____________________________________________________________________________
 TXSocket::TXSocket(TString TcpAddress, Int_t TcpPort, Int_t TcpWindowSize)
         : TSocket()
{
   // Create a TXSocket object (that doesn't actually connect to any server.

   // Init of the separate connect parms
   fHost2contact.TcpAddress = TcpAddress;
   fHost2contact.TcpPort = TcpPort;
   fHost2contact.TcpWindowSize = TcpWindowSize;
   fRequestTimeout = gEnv->GetValue("XNet.RequestTimeout",
                                     DFLT_REQUESTTIMEOUT);
   fASYNC = gEnv->GetValue("XNet.GoAsynchronous", DFLT_GOASYNC);

}

//_____________________________________________________________________________
 TXSocket::~TXSocket()
{
   // Destructor
}

//_____________________________________________________________________________
 Int_t TXSocket::RecvRaw(void* buffer, Int_t length, ESendRecvOptions opt)
{
   // Override of TSocket::RecvRaw. Before calling TSocket::RecvRaw we poll for a
   // while on the socket descriptor waiting for a POLLIN event (data to read).

   time_t starttime;
   Int_t bytesread = 0, n;

   SetOption(kNoBlock, 0);

   // We cycle until we have all the data we are waiting for
   // Or until a timeout occurs
   starttime = time(0);
   while (bytesread < length) {

      Int_t ReadyToRecv = 0;
      // We cycle on the poll, ignoring the possible interruptions
      do {
         // If too much time has elapsed, then we return an error
         if ((time(0) - starttime) > fRequestTimeout) {
            if (!fASYNC || (DebugLevel() >= kDUMPDEBUG))
               Error("RecvRaw","Request timed out %d seconds reading %d bytes"
                     " from socket %d (server[%s:%d])",
                     fRequestTimeout, length, fSocket,
                     GetInetAddress().GetHostName(), GetPort());

	    return TXSOCK_ERR_TIMEOUT;
         }

         // Wait for a socket ready for receiving
         ReadyToRecv = TSocket::Select(TSocket::kRead,1000);

      } while (!ReadyToRecv);

      if (ReadyToRecv < 0)
         return TXSOCK_ERR;

      n = TSocket::RecvRaw((char *)buffer + bytesread, length - bytesread, opt);
      if (!n)
         return (0);

      bytesread += n;

   } // while

   return bytesread;
}

//_____________________________________________________________________________
 Int_t TXSocket::SendRaw(const void* buffer, Int_t length, ESendRecvOptions opt)
{
   // Override of TSocket::SendRaw. Before calling TSocket::SendRaw we poll
   // for a while on the socket descriptor waiting for a POLLOUT event
   // (writes will not hang)

   time_t starttime;
   Int_t byteswritten = 0, n;

   if (!TSocket::IsValid())
      return TXSOCK_ERR;

   SetOption(kNoBlock, 0);

   // We cycle until we have all the data we are waiting for
   // Or until a timeout occurs
   starttime = time(0);
   while (byteswritten < length) {

      Int_t ReadyToWrite = 0;

      do {
         // If too much time has elapsed, then we return an error
         if ( (time(0) - starttime) > fRequestTimeout ) {
            Error("SendRaw","Request timed out %d seconds writing %d bytes"
                  " from socket %d (server[%s:%d])", fRequestTimeout, length,
                  fSocket, GetInetAddress().GetHostName(), GetPort());

	    return TXSOCK_ERR_TIMEOUT;
         }

         // Wait for a socket ready for sending
         ReadyToWrite = TSocket::Select(TSocket::kWrite,1000);

      } while (!ReadyToWrite);

      if (ReadyToWrite < 0)
         return TXSOCK_ERR;

      n = TSocket::SendRaw((char *)buffer + byteswritten,
                                   length - byteswritten, opt);
      if (!n)
         return (0);

      byteswritten += n;

   } // while

   return byteswritten;
}

//_____________________________________________________________________________
 void TXSocket::TryConnect()
{
   // Connection attempt

   this->Create(this->fHost2contact.TcpAddress,
                this->fHost2contact.TcpPort,
                this->fHost2contact.TcpWindowSize);

   // Now, we know the result of the connect process from the
   // socket descriptor. If and when needed.

}

//_____________________________________________________________________________
 void TXSocket::CatchTimeOut()
{
   // Called in connection with a timer timeout

   ::Error("TXSocket::CatchTimeOut",
           "Timeout elapsed after %d seconds for connection to server",
           gEnv->GetValue("XNet.ConnectTimeout", DFLT_CONNECTTIMEOUT));
   return;
}

//_____________________________________________________________________________
 void TXSocket::Create(TString host, Int_t port, Int_t tcpwindowsize)
{
   // Create a connection

   Assert(gSystem);

   if (DebugLevel() >= kHIDEBUG)
      Info("Create","Setting fService to %s", gSystem->GetServiceByPort(port));
   fService = gSystem->GetServiceByPort(port);

   fAddress = gSystem->GetHostByName(host.Data());

   if (DebugLevel() >= kHIDEBUG)
      Info("Create","Setting fAddress.fPort to %d", port);

   fAddress.fPort = port;
   SetName(fAddress.GetHostName());
   SetTitle(fService);

   fUrl = host;
   fTcpWindowSize = tcpwindowsize;
   fServType = TSocket::kROOTD;

   if (DebugLevel() >= kHIDEBUG)
      Info("Create","Calling TUnixSystem::OpenConnection with params"
           " %s:%d tcpwin=%d", host.Data(), port, tcpwindowsize);

   // set an alarm that will send a SIGALARM after
   // XNet.ConnectTimeout
   // in order to stop the syscalls and retry
   TTimer alarm(0, kFALSE);
   alarm.SetInterruptSyscalls();

   // The static method CatchTimeOut will be called at timeout
   alarm.Connect("Timeout()", "TXSocket", 0, "CatchTimeOut()");

   // TTimer::Starts wants millisec
   Int_t to = gEnv->GetValue("XNet.ConnectTimeout",DFLT_CONNECTTIMEOUT);
   alarm.Start(to*1000, kTRUE);

   // Now connect
   fSocket = gSystem->OpenConnection(host.Data(), port, tcpwindowsize);

   if (fSocket == -1) {
      fAddress.fPort = -1;
      if(DebugLevel() >= kHIDEBUG)
         Info("Create","Connection failed. Setting fSocket to -1");
   } else {
      // Add to the list
      gROOT->GetListOfSockets()->Add(this);
   }
}

//____________________________________________________________________________
 TSocket *TXSocket::ExtractSocket()
{
   // Return copy of the underlying TSocket part and set the descriptor
   // to -1 (so that the connection is not closed when the TXSocket is
   // deleted).
   // Used to save an open connection to rootd daemons

   TSocket *sock = 0;
   if (IsValid()) {
      sock = new TSocket((const TSocket &)(*this));
      SetDescriptor(-1);
   }
   return sock;
}


ROOT page - Class index - Class Hierarchy - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.