// @(#)root/netx:$Name:  $:$Id: TXNetConn.h,v 1.5 2005/05/01 10:00:07 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.             *
 *************************************************************************/

#ifndef ROOT_TXNetConn
#define ROOT_TXNetConn

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TXNetConn                                                            //
//                                                                      //
// Authors: Alvise Dorigo, Fabrizio Furano                              //
//          INFN Padova, 2003                                           //
//                                                                      //
// High level handler of connections to xrootd.                         //
// Instantiated by TXNetFile.                                           //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#define DFLT_MAXREDIRECTCOUNT        255
#define DFLT_DEBUG                   0
#define DFLT_RECONNECTTIMEOUT        10
#define DFLT_REQUESTTIMEOUT          60
#define REDIRCNTTIMEOUT		     3600

#include "time.h"
#ifndef ROOT_TString
#include "TString.h"
#endif
#ifndef ROOT_TXAbsNetCommon
#include "TXAbsNetCommon.h"
#endif
#ifndef ROOT_TXMessage
#include "TXMessage.h"
#endif
#ifndef ROOT_TUrl
#include "TUrl.h"
#endif

class TXConnectionMgr;

class TXNetConn {

public:
   enum ServerType {
      kSTError      = -1,  // Some error occurred: server type undetermined
      kSTNone       = 0,   // Remote server type un-recognized
      kSTRootd      = 1,   // Remote server type: old rootd server
      kSTBaseXrootd = 2,   // Remote server type: xrootd dynamic load balancer
      kSTDataXrootd = 3    // Remote server type: xrootd data server
   };
   enum ESrvErrorHandlerRetval {
      kSEHRReturnMsgToCaller   = 0,
      kSEHRBreakLoop           = 1,
      kSEHRContinue            = 2,
      kSEHRReturnNoMsgToCaller = 3,
      kSEHRRedirLimitReached   = 4
   };
   enum EThreeStateReadHandler {
      kTSRHReturnMex     = 0,
      kTSRHReturnNullMex = 1,
      kTSRHContinue      = 2
   };

   Int_t             fLastDataBytesRecv;
   Int_t             fLastDataBytesSent;
   XErrorCode        fOpenError;
   TString           fOpenErrorMsg;

   ServerResponseHeader fLastServerResp;

   TXNetConn();
   virtual ~TXNetConn();

   Bool_t           CheckHostDomain(TString hostToCheck, TString allow,
                                                         TString deny);
   Short_t          Connect(TString newHost, Int_t newPort, Int_t netopt);
   void             Disconnect(Bool_t ForcePhysicalDisc);
   Bool_t           GetAccessToSrv();
   TString          GetClientHostDomain() const { return fClientHostDomain; }
   Int_t            GetLogConnID() const { return fLogConnID; }
   TUrl            *GetLBSUrl() const { return fLBSUrl; }
   XErrorCode       GetOpenError() const { return fOpenError; }
   TSocket         *GetRootdSocket() const { return fLastRootdSocket; }
   XReqErrorType    GoToAnotherServer(TString, Int_t, Int_t);
   Bool_t           IsConnected() const { return fConnected; }
   Int_t            LastBytesRecv();
   Int_t            LastBytesSent();
   Int_t            LastDataBytesRecv();
   Int_t            LastDataBytesSent();
   Bool_t           SendGenCommand(ClientRequest *req,
                                   const void *reqMoreData,
                                   void **answMoreDataAllocated,
                                   void *answMoreData, Bool_t HasToAlloc,
                                   char *CmdName,
                                   struct ServerResponseHeader *srh = 0);
   ServerType       GetServerType() const { return fServerType; }
   void             SetClientHostDomain(const char *src)
                                                { fClientHostDomain = src; }
   void             SetConnected(Bool_t conn) { fConnected = conn; }
   void             SetLogConnID(Short_t logconnid) { fLogConnID = logconnid;}
   void             SetOpenError(XErrorCode err) { fOpenError = err; }
   void             SetRedirHandler(TXAbsNetCommon *rh) { fRedirHandler = rh; }
   void             SetServerType(ServerType type) { fServerType = type; }
   void             SetSID(kXR_char *sid);
   inline void      SetUrl(TUrl thisUrl) { fUrl = thisUrl; }

   static void      SetTXConnectionMgr(TXConnectionMgr *connmgr);

private:

   TString             fClientHostDomain; // Save the client's domain name
   Bool_t              fConnected;
   Short_t             fGlobalRedirCnt;    // Number of redirections
   time_t              fGlobalRedirLastUpdateTimestamp; // Timestamp of last redirection
   Int_t               fLastNetopt;
   TUrl               *fLBSUrl;            // Needed to save the load balancer url
   Short_t             fLogConnID;        // Logical connection ID of the current
                                          // TXNetFile object
   Short_t             fMaxGlobalRedirCnt;
   TXAbsNetCommon     *fRedirHandler;     // Pointer to a class inheriting from
                                         // TXAbsNetCommon providing methods
                                         // to handle the redir at higher level
   TString             fRedirInternalToken; // Token returned by the server when
                                           // redirecting
   Long_t              fServerProto;      // The server protocol
   ServerType          fServerType;       // Server type as returned by doHandShake()
                                         // (see enum ServerType)
   TUrl                fUrl;

   TSocket            *fLastRootdSocket;  // rootd case: socket of the last open
                                          // connection
   Int_t               fLastRootdProto;  // rootd case: remote server protocol

   static TXConnectionMgr *fgConnectionManager; //Connection Manager

   Bool_t              CheckErrorStatus(TXMessage *, Short_t &, char *);
   void                CheckPort(Int_t &port);
   Bool_t              CheckResp(struct ServerResponseHeader *resp, const char *method);
   TXMessage          *ClientServerCmd(ClientRequest *req, const void *reqMoreData,
                                   void **answMoreDataAllocated, void *answMoreData,
                                   Bool_t HasToAlloc);
   Bool_t              DoAuthentication(char *list, int lsiz);
   ServerType          DoHandShake(Short_t log);
   Bool_t              DoLogin();

   TString             GetDomainToMatch(TString hostname);

   ESrvErrorHandlerRetval HandleServerError(XReqErrorType &, TXMessage *,
                                            ClientRequest *);
   Bool_t              MatchStreamid(struct ServerResponseHeader *ServerResponse);

   TString             ParseDomainFromHostname(TString hostname);

   TXMessage          *ReadPartialAnswer(XReqErrorType &, size_t &,
                                         ClientRequest *, Bool_t, void**,
                                         EThreeStateReadHandler &);
   XReqErrorType       WriteToServer(ClientRequest *, ClientRequest *,
                                         const void*, Short_t);

   ClassDef(TXNetConn, 0); //A high level connection class for TXNetAdmin.
};


//
// Class implementing a trick to automatically unlock a TXPhyConnection.
// Used only by TXNetConn.
//
class TXPhyConnection;

class TXPhyConnLocker {
private:
   TXPhyConnection *phyconn;

public:
   TXPhyConnLocker(TXPhyConnection *phyc);
   ~TXPhyConnLocker();
};

#endif
