// @(#)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.