#ifndef __SOCKIOREADER_HH_ #define __SOCKIOREADER_HH_ #include "Arch.h" #include "IO.hh" #include "IEEEIO.hh" #include "RawTCP.H" #include "PortMux.H" /*========================================================================= class: SockIOreader description: Implements IEEEIO IO interface described in http://bach.ncsa.uiuc.edu/IEEEIO over a socket connection. The interface is read-only. This is the client and the SockIOwriter is a server which sends data out to the SockIOreader from the application. All data is cached in an IEEEIO file on the client end (this side) for rapid local access by the client application. Problems: The background IO methods are kludgy at best. Currently it depends on SigIO in order to determine when some new data is availible on the socket. However, it is very difficult to demultiplex that signal when you have more than one instance of SockIOreader active. Need a garaunteed method to determine if a client has dropped it connection. A dropped connection can cause a lockup if it occurs during a blocking read. This needs to have a SigALRM in order to recover from such errors. ===========================================================================*/ //void IOsigHandler(int sig); // prototype class SockIOreader : public IObase { // The following data structures come straight out of IEEEIO and // are necessary for interpreting the data coming in through the // socket connection. Other than that, you can completely ignore them // or refer directly to the docs in IEEEIO.hh if you really feel the // need to understand what is happening here. enum RecordType {DataRecord=1,AnnotationRecord,AttributeRecord}; #ifdef __hpux // silly HPUX compiler doesn't allow FileHdr access to btorder... public: #endif // Structure for determining the native byte-order of data stored in the file union btorder { char c[4]; // write as int, read as int int i; }; // File header describes how many data records are in the file and what the // version of the IEEEIO wrote this data. struct FileHdr { // do magic twice so we can figure out which byte-order // the current machine is in addition (without hardcoding) in // addition to which byte order the file is in btorder magic; btorder byteorder; Long ndatasets; short majorversion; short minorversion; }; // At the head of each data or attribute record. Identifies the type of // record and how large it is so that it can be skipped if it doesn't contain // relevant data. struct RecordHdr { int recordtype; Long recordsize; int sequenceID; }; // This immediately follows a RecordHeader if the record contains raw data. // this stores the number of dimensions and the datatype of the record struct DataRecordHdr { Long datasize; int numbertype; int rank; }; // The immediately follows the RecordHeader if the record contains a // NetCDF attribute. It stores the datatype, name and datasize of the // attribute vector. struct AttributeRecordHdr { Long datasize; int numbertype; int namesize; // attributes are named }; char scratchfilename[256]; // name of scratchfile in which to store the IEEEIO data IEEEIO *scratchfile; // IEEEIO file descriptor for the scratch file FastTCPserver ServerPort; // Server port from which connections from SockIOwriters are accept()'ed RawTCPport *connected_client; // Only one client can be attached at a time. //**** State information for IEEEIO management RecordHdr current_rec; DataRecordHdr current_data_rec; AttributeRecordHdr current_att_rec; //**** master_mux is the serverport (accept calls) and mux is the connected ports (new data) PortMux master_mux,mux; int n_complete_ds,current_ds,last_ds; // number of completely received datasets + current&last int pending; // Flag if a new dataset transfer is currently in progress in the background. // Make this functionality inacessible since this class is read-only. virtual int write(IObase::DataType typeID,int rank,CONST int *dims,void *data){return 0;} virtual int writeAnnotation(CONST char *annotation){return 0;} virtual int writeAttribute(CONST char *name,IObase::DataType typeID,Long length,const void *data){return 0;} virtual int reserveChunk(IObase::DataType typeID,int rank,CONST int *dims){return 0;} virtual int reserveStream(IObase::DataType typeID,int rank,CONST int *dims){return 0;} virtual int writeChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data){return 0;} virtual int writeStream(void *data,int length){return 0;} protected: int blockingRead(void *buffer,int size); // kludge //static void halt(){} //static int sendInProgress(){return 0;} public: void sigHandler(int sig); friend void IOsigHandler(int *handler); // give the sighandler internal access to sigHandler(); //------------------------core stuff..................... SockIOreader(CONST char *scratchfilenm,int port); SockIOreader(CONST char *scratchfilenm,int port,int tcpwindowsize); virtual ~SockIOreader(); // should check server status too virtual int isValid(); // could use overloading to differentiate type here... (but I'm going simple) virtual int readInfo(IObase::DataType &typeID,int &rank,int *dims,int maxdims=3); virtual int read(void *data); virtual int seek(int dataset_index); virtual int nDatasets(); virtual int readAnnotationInfo(int number,int &length); virtual int readAnnotation(int number,char *annotation,int maxsize=128); virtual int nAnnotations(); virtual int readAttributeInfo(int number,char *name,IObase::DataType &typeID,Long &nelem,int maxnamelen=128); virtual int readAttributeInfo(CONST char *name,IObase::DataType &typeID,Long &nelem); virtual int readAttribute(int number,void *data); virtual int nAttributes(); //-----------------Chunking Utilities.................. //---Not implemented quite yet on server side, but you can read in chunks on client. virtual int readChunk(CONST int *chunkdims,CONST int *chunkorigin,void *data); virtual int readStream(void *data,int length){return 0;} }; #endif