// Author: Egon Pavlica <http://www.p-ng.si/~pavlica/>

//________________________________________
//  This is server class
//   modified to conect to LClient
//
//
//
// Logs:
//
//  $Log: LServer.cc,v $
//  Revision 1.10  2004/03/12 14:52:33  cvs
//  a bug was found and repaired, when data was saved over other one, so directories and jobID in data didnt matched!
//
//  Revision 1.9  2004/02/11 11:23:47  cvs
//  found and resolved some bugs in LServer.cc and hoppserv.cc
//
//  Revision 1.8  2003/11/24 17:06:23  cvs
//  a bug was corrected in LServer::GetLData and the error bars were corrected when drawing Draw(".tof.")
//
//  Revision 1.7  2003/11/15 17:17:26  cvs
//  new scheme is working...
//  Clients (hoppclient) are connected as kLC_AMAX and free socket is given
//  TLServer (lserver) is multithreading
//  LServer (hoppserver) has a file which is always in memory - faster but needs more memory
//
//  Revision 1.6  2003/11/11 17:33:03  cvs
//  LServer upgraded
//
//  Revision 1.5  2003/07/09 10:53:13  cvs
//  added some verbosity and changed LContainer class. The LData isnt changed. Corrected daemon mode of hoppserv, since network connection is dependend on process pid. So the connection should be opened by child processes.
//
//  Revision 1.4  2003/06/26 09:27:11  cvs
//  added log fields...
//
#include "LServer.h"

#include <iostream>
#include <syslog.h>

#include <TCollection.h>
#include <TKey.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <TH1.h>


ClassImp(LServer)



 LServer::LServer(TLClient* calling,const char* filename,int syslogd){
  //and open (update) root file of name filename
  fsocket=calling;
  fname=new TString(filename); //ROOT filename
  fdatabase=0;//dynamically open
  fdata=0;//dynamically open
  fheader=0;//dynamically open
  if (syslogd) SetSysLog(); else fsyslog=0;

  char message[80];
  sprintf(message,"Database is ready (%s)",filename);
  SendLog(message);
}

 LServer::~LServer(){
  //default destructor
  if (fname) {
    delete fname;
    fname=0;
  }
  CloseDataBase();
}

void
 LServer::SetSysLog(){
  //set the server to send logs to syslogd -> e.g. /var/log/messages 
  fsyslog=1;
}

Int_t 
 LServer::SendLog(const char* message){
  if(fverbose) std::cout<<message<<std::endl;
  if (fsyslog) syslog(LOG_INFO,message);
  if(!fsocket->IsConnected()) {
    if(fverbose) std::cerr<<"Error:LServer no network connectionn";
    return 0;
  }
  fsocket->SendTo(kLC_RC,kRC_NEW_MESSAGE);
  fsocket->SendTo(kLC_RC,message);
  return 1;
}


Bool_t 
 LServer::ReceiveString() {
  //goes through all clients that thinks will talk to
  //receive fStr from client fclient
  //if something is wrong, then returns kFALSE
  Int_t rc;
  Bool_t wait=kFALSE;
  fclient=kLC_MAX;

  if ((rc=fsocket->RecvFrom(kLC_RC,fStr,wait)) && rc && (fclient=kLC_RC))
    return kTRUE;
  if ((rc=fsocket->RecvFrom(kLC_CLIENT,fStr,wait)) && rc && (fclient=kLC_CLIENT))
    return kTRUE;
  if ((rc=fsocket->RecvFrom(kLC_HDELIVER,fStr,wait)) && rc && (fclient=kLC_HDELIVER))
    return kTRUE;
  if ((rc=fsocket->RecvFrom(kLC_ANA1,fStr,wait)) && rc && (fclient=kLC_ANA1))
    return kTRUE;
  if ((rc=fsocket->RecvFrom(kLC_ANA2,fStr,wait)) && rc && (fclient=kLC_ANA2))
    return kTRUE;
  if ((rc=fsocket->RecvFrom(kLC_ANA3,fStr,wait)) && rc && (fclient=kLC_ANA3))
    return kTRUE;

  //  if (fverbose) std::cout<<"rc:"<<rc<<"n";
  if(rc==-4) {
    return kFALSE;
  }
  if(rc==-1) {
    fsocket->SetDisconnected();
    return kFALSE;
  }
  return kFALSE;
}

int 
 LServer::WaitConnection(){
  //this is only filter, which captures kRC_STOP_RUN
  if (ReceiveString()){
    //    if (fverbose) std::cout<<"Something recived:"<<fStr<<"n";
    if(!strcmp(fStr,kRC_STOP_RUN)) {
      if (fverbose) std::cout<<"received stop run commandn";
      return 0;
    }
    if(!strcmp(fStr,kRC_UPDATE_FILE)) {
      if (fverbose) std::cout<<"received update file commandn";
      CloseDataBase();
      OpenDataBase();      
      return 1;
    }       
    return 1;
  }
  sleep(1);//something goes wrong better to sleep for a while
  return 1;//and continue to serving
}



void
 LServer::Serving(){
  char str[32];
  TObject* obj=0;
  fStr[0]='X';
  while(WaitConnection()){
    if(fclient!=kLC_MAX){//someone is connected
      if(!strcmp(fStr,kRC_UPDATE_STATE)) {
	//receive an object
	fsocket->RecvFrom(fclient,obj);

	sprintf(str,"%s",obj->ClassName());
	if (fverbose>2) std::cout<<"RECV: "<<str<<"n";
	
	if(!strcmp(str,"LData")) 
	  DataTransfer((LData*)obj);
	
	if(!strcmp(str,"LContainer")) 
	  DataContainerTransfer((LContainer*)obj);
	
	if(!strcmp(str,"LDataHeader")) 
	  DataHeaderTransfer((LDataHeader*)obj);
	//BUG HERE? 
	if (obj) delete obj;
	obj=0;
	//empty buffer string
	fStr[0]='X';
      }
    }
  }
  if (obj) delete obj;
  CloseDataBase();
  return;
}

 Int_t LServer::DataTransfer(LData* data){
  //connection for data transfer is handled 

  if (fverbose>1) std::cout<<"data transfer...n";

  char messag[256];
  char* datum;
  time_t t1;
  time(&t1);datum=ctime(&t1);datum[strlen(datum)-1]='0';

  if (!data->GetJobID()) {
    sprintf(messag,"%s:Data without JobID - Ignored!",datum);
  } else {
    LData* old=GetLData(data->GetJobID());
    if (!old)
      sprintf(messag,"%s:Data ignored",datum);
    else {
      old->Add(data);//add new data
      sprintf(messag,"%s:Data added",datum);
    }
  }
  SendLog(messag);
  return 1;
}


 Int_t LServer::DataContainerTransfer(LContainer* data){
  //connection for data container transfer is handled 

  if (fverbose>1) std::cout<<"data container transfer...n";
  //create message
  char messag[256];
  char* datum;
  time_t t1;
  time(&t1);datum=ctime(&t1);datum[strlen(datum)-1]='0';
  //open file for reading
  if (!data->GetJobID()) {
    //if container has no jobID so is useless!!
    sprintf(messag,"%s:Data container without jobID:%s",datum,data->GetLog());
  } else {
    LData* old=GetLData(data->GetJobID());
    if (!old)
      sprintf(messag,"%s:Data ignored:%s",datum,data->GetLog());
    else {
      old->Add(data);//add new data from container
      sprintf(messag,"%s:Data added:%s",datum,data->GetLog());
    }
  }
  SendLog(messag);
  return 1;
}


 Int_t LServer::DataHeaderTransfer(LDataHeader* header){
  //connection for data transfer is handled 
  if (fverbose>1) std::cout<<"data header transfer...n";
  if (!header->GetJobID()) {
    SendLog("Header without JobID!- Ignored");
    return 1;
  }
  //check if already exists and is loaded
  if (fheader && fheader->GetJobID()==header->GetJobID()) return 1;
  //check the database
  TFile* datoteka=OpenDataBase();
  datoteka->cd();
  MkDirectory(header);
  LDataHeader* old=(LDataHeader*)gDirectory->Get("header");
  if (old) {//header already exist 
    if (old->GetJobID()==header->GetJobID()){ //check
      if (fheader) {
	//fheader->Write("header",TObject::kOverwrite);
	delete fheader;
      }
      fheader=old; return 1;
    } else {
      delete old; return 1;
    }//end check
  } else {//new one
    header->Write("header");  return(1);
  }
  return 1;
}
  
 TDirectory* LServer::MkDirectory(LDataHeader* header){
  //this function cd fname to last directory regarding jobID it returns the pointer to created  directory. if directory already exist 0 is returned
  
  char jobid[256];
  sprintf(jobid,"%ld",header->GetJobID());

  TDirectory* created; created=0;
  if (!gDirectory->cd(jobid)) {
    created=gDirectory->mkdir(jobid);
    gDirectory->cd(jobid);
    
    char* datum;
    time_t t1;
    char message[256];
    time(&t1);datum=ctime(&t1);datum[strlen(datum)-1]='0';
    sprintf(message,"%s:Directory %s created",datum,jobid);
    SendLog(message);
    
    if (fverbose>1) std::cout<<"Directory "<<jobid<<" created!"<<std::endl;
  }
  return created;
}



 TDirectory* LServer::CdDirectory(Long_t jobID){
  //this function cd fname to last directory of specific jobID and returns the pointer to it
  TFile* Rootfile=OpenDataBase();
  Rootfile->cd(); 
  char dirname[256];
  sprintf(dirname,"%ld",jobID);
  Rootfile->cd(dirname);
  return gDirectory;//CORRECTION OF MEMORY LEAK
}

 TFile* LServer::OpenDataBase(){
  //open ROOT file for writing
  if (!fdatabase) 
    fdatabase=new TFile((const char*)fname->Data(),(const char*)"update",(const char*)"",0);
  return fdatabase;
}

 void LServer::CloseDataBase(){
  if (fdata){
    CdDirectory(fdata->GetJobID());
    fdata->Write("data",TObject::kOverwrite);
    delete fdata; fdata=0;
  }
  if (fheader){
    //    fheader->Write("header",TObject::kOverwrite);
    delete fheader;
    fheader=0;
  }
  if (fdatabase) {
    fdatabase->Close();
    delete fdatabase;
    fdatabase=0;
  }
}


 LData* LServer::GetLData(Long_t jobID){
  //we suppose here, the file is already open
  //this return pointer to data if already exists, or load new data from file 
  //or create new data from header in file (header must be there!)
  if (fdata && fdata->GetJobID()==jobID) return fdata;

  
  //new jobID has came searching directory with that name in database
  CdDirectory(jobID);
  int found=0;
  TIter* next=new TIter(gDirectory->GetListOfKeys());
  TKey* key;
  while((key=(TKey*)(*next)()))
    if (!strcmp("data",key->GetName())) {found=1;break;}        
  delete next;
  
  if (found) {
    //old data found - yuhu
    if (fdata){
      CdDirectory(fdata->GetJobID());
      fdata->Write("data",TObject::kOverwrite);
      delete fdata; fdata=0;
      CdDirectory(jobID);
    }
    fdata=(LData*)gDirectory->Get("data");
    return fdata;
    
  } else {
    //find header,make new data, add container
    //header should be always presented before data arives
    if (fheader && fheader->GetJobID()!=jobID) {delete fheader;fheader=0;}
    if (!fheader) fheader=(LDataHeader*)gDirectory->Get("header");
    if (!fheader) {
      if (fverbose){
	std::cerr<<"Error: adding container:no header with jobID:"<<jobID<<std::endl;
	std::cerr<<"Received data ignored!"<<std::endl;
	std::cerr<<"Hint: You have probably changed file name in hoppserv. So your header is stored in another file, while you want to store simulated data in another file. If this error repeates several times for the same JobID, you should worry about!"<<std::endl;
      }
      return 0;
    }
    
    fdata=new LData(fheader);//creating data
    //delete oldh;
    return fdata;
  }
  return 0;
}








ROOT page - Class index - 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.