diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9564a59 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build/ +scripts/StartServer diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..f96d84e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 2.6) + +PROJECT(DDServer) + +configure_file ( + "${CMAKE_SOURCE_DIR}/scripts/StartServer.in" + "${CMAKE_SOURCE_DIR}/scripts/StartServer" +) + +set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/build/${CMAKE_BUILD_TYPE}/bin/) +set(LIBRARY_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/build/${CMAKE_BUILD_TYPE}/lib/) + +if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + #64 bits + set(CMAKE_C_FLAGS_DEBUG "-ggdb -DLINUX -Dlinux -m64 -march=core2 -fPIC -D_REENTRANT -pthread") + set(CMAKE_C_FLAGS_RELEASE "-DLINUX -Dlinux -m64 -march=core2 -fPIC -D_REENTRANT -pthread") +else( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + #32 bits + set(CMAKE_C_FLAGS_DEBUG "-ggdb -DLINUX -march=i686 -fPIC -Dlinux -D_REENTRANT -malign-double -pthread") + set(CMAKE_C_FLAGS_DEBUG "-DLINUX -march=i686 -fPIC -Dlinux -D_REENTRANT -malign-double -pthread") +endif( CMAKE_SIZEOF_VOID_P EQUAL 8 ) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/") + +find_package( Threads REQUIRED ) +find_package( CRYPT REQUIRED ) +find_package( NetCDF REQUIRED ) + +MESSAGE( STATUS "Build DDServer Project" ) +add_subdirectory(src/CLIENT) +add_subdirectory(src/SERVER) + +install(FILES "scripts/StartServer" DESTINATION . PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +install(DIRECTORY "src/INCLUDE/" DESTINATION include) + +SET(CMAKE_VERBOSE_MAKEFILE ON) diff --git a/README b/README new file mode 100644 index 0000000..c6ede39 --- /dev/null +++ b/README @@ -0,0 +1,20 @@ +1. Set NETCDF_ROOT to use a specific netcdf installation directory : +> export NETCDF_ROOT="/home/benjamin/AMDA-GIT/AMDA_COTS/netcdf/install" + +2. Make the build directory : +> cmake -E make_directory build + +3. Configure the build. Set CMAKE_BUILD_TYPE to Debug or Release to configure the build type. Set CMAKE_INSTALL_PREFIX to configure the install directory : +> cmake -E chdir build cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/home/benjamin/DDServer .. + +4. Build DDServer : +> cmake --build build + +5. Install DDServer : +> make -C build install VERBOSE=1 + +6. Configure DDServer : +In the install directory, open "StartServer" and set DDPATH and DDBASE. + +7. Run DDServer: +> ./StartServer diff --git a/cmake/modules/FindCRYPT.cmake b/cmake/modules/FindCRYPT.cmake new file mode 100644 index 0000000..b1580cf --- /dev/null +++ b/cmake/modules/FindCRYPT.cmake @@ -0,0 +1,32 @@ +FIND_PATH(CRYPT_INCLUDE_DIR crypt.h + /usr/local/include/crypt + /usr/local/include + /usr/include/crypt + /usr/include +) + +SET(CRYPT_NAMES crypt) + +FIND_LIBRARY(CRYPT_LIBRARY + NAMES ${CRYPT_NAMES} + PATHS /usr/lib /usr/local/lib +) + +IF(CRYPT_INCLUDE_DIR AND CRYPT_LIBRARY) + SET(CRYPT_FOUND TRUE) + SET(CRYPT_LIBRARIES ${CRYPT_LIBRARY} ) +ELSE(CRYPT_INCLUDE_DIR AND CRYPT_LIBRARY) + SET(CRYPT_FOUND FALSE) + SET(CRYPT_LIBRARIES) +ENDIF(CRYPT_INCLUDE_DIR AND CRYPT_LIBRARY) + +IF(NOT CRYPT_FOUND) + IF(CRYPT_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "crypt library and headers required.") + ENDIF(CRYPT_FIND_REQUIRED) +ENDIF(NOT CRYPT_FOUND) + +MARK_AS_ADVANCED( + CRYPT_LIBRARY + CRYPT_INCLUDE_DIR +) diff --git a/cmake/modules/FindNetCDF.cmake b/cmake/modules/FindNetCDF.cmake new file mode 100644 index 0000000..2c7c7c5 --- /dev/null +++ b/cmake/modules/FindNetCDF.cmake @@ -0,0 +1,24 @@ +FIND_PATH(NETCDFINCLUDE_DIR netcdf.h + HINTS + $ENV{NETCDF_ROOT}/include + ${NETCDF_ROOT}/include +) +mark_as_advanced(NETCDFINCLUDE_DIR) + +find_library(NETCDFLIBRARY + NAMES netcdf + HINTS + $ENV{NETCDF_ROOT} + ${NETCDF_ROOT} + PATH_SUFFIXES lib +) +mark_as_advanced(NETCDFLIBRARY) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(NetCdf DEFAULT_MSG NETCDFLIBRARY NETCDFINCLUDE_DIR) + +if(NETCDF_FOUND) + set(NETCDFINCLUDE_DIRS ${NETCDFINCLUDE_DIR}) + set(NETCDFLIBRARIES ${NETCDFLIBRARY}) +endif() + diff --git a/scripts/StartServer.in b/scripts/StartServer.in new file mode 100755 index 0000000..edbb3a0 --- /dev/null +++ b/scripts/StartServer.in @@ -0,0 +1,13 @@ +#!/bin/bash +#------------------------------------------------------------------- +# StartServer +#------------------------------------------------------------------- +DDBASE=@CMAKE_INSTALL_PREFIX@/DDBASE/DATA +DDPATH=@CMAKE_INSTALL_PREFIX@/DDBASE +DDLIB=@CMAKE_INSTALL_PREFIX@/lib +DDBASEBIN=@CMAKE_INSTALL_PREFIX@/bin +LD_LIBRARY_PATH=$DDLIB/:/usr/local/lib64/ +export DDBASE DDPATH DDBASEBIN DDLIB LD_LIBRARY_PATH + +#$DDBASEBIN/DD_Server 1>/dev/null 2>/dev/null& +$DDBASEBIN/DD_Server -V diff --git a/src/CLIENT/CMakeLists.txt b/src/CLIENT/CMakeLists.txt new file mode 100644 index 0000000..ec237a6 --- /dev/null +++ b/src/CLIENT/CMakeLists.txt @@ -0,0 +1,22 @@ + +PROJECT(DDClient) + +include_directories( + ${CMAKE_HOME_DIRECTORY}/src/INCLUDE/ +) + +#Library configuration +file( + GLOB_RECURSE + source_files + ./* +) + +ADD_LIBRARY( DDClient SHARED ${source_files} ) + +target_link_libraries( + DDClient + ${CMAKE_THREAD_LIBS_INIT} +) + +install (TARGETS DDClient DESTINATION lib) diff --git a/src/CLIENT/DD_client.c b/src/CLIENT/DD_client.c new file mode 100755 index 0000000..59286ab --- /dev/null +++ b/src/CLIENT/DD_client.c @@ -0,0 +1,931 @@ +/* $Id: DD_client.c,v 1.4 2012/10/18 09:25:58 budnik Exp $ */ +/*============================================================== + * DD SYSTEM + * DD_client.c + * V.6.0 + * List of changes: + * November 1995, Version 1.0 + * August 1999 :Access security system was installed by Alexandr Grigoriev (v3.0) + * October 22, 2002 - Communication ideology is changed (V.4.0) + * Oct 29, 2002 - Add DD_GetVersion() and some bags are corrected (V.4.1) + * May 1, 2003 - Network error is developped. (The header receiving is changed): V.4.2 + * Nov 18, 2004 - Cach error is fixed. + * Jun 17, 2007 - Fedorov, V.4.5 Create new VI and Update data requests + * Sep 24, 2007 - Fedorov, V.4.6 Processing of return of Get_Data + * Dec 03, 2007 - Budnik, V.4.7 There may be several sessions with DD Server inside ONE + * Client session. Keep UserHost & UserName + * Oct 18, 2012 - Knizhnikova, V.4.8 new DD_SetTimeInfo() function + * Dec 15, 2012 - Fedorov, V.6.0. DD_GetMultiData(). Request structure is very changed, CurrentData is not a global structure + *===============================================================*/ + +#include <unistd.h> +#include "DD.h" +#include "DD_comm.h" +#include "DD_Access.h" +#include <stdio.h> +#include <string.h> + +#define VERSION "V.6.0" + +/*------------------ GLOBAL STATIC VARIABLES --------------------------*/ +int SocketID = -1; /* Global socket id for this communication session */ +char UserName[USRLENGTH]="\0"; /* string for user name */ +char UserHost[MAXHOSTLENGTH] = "\0"; /* IP of user's host in a string form */ +int UserID; /* ID of user at the user's host */ +extern int errno; + +/*================== FUNCTIONS =================================*/ +/*----------------------- GET User Host-------------------------------*/ +int GetUserHost() +{ + char HostName[HOSTNAMELENGTH]; + struct hostent *Host; + unsigned int HostAddress; + int userid; + static unsigned int m1 = 0X000000FF; + static unsigned int m2 = 0X0000FF00; + static unsigned int m3 = 0X00FF0000; + static unsigned int m4 = 0XFF000000; + unsigned int b1,b2,b3,b4; + + userid = getuid(); /* Get a client user ID */ + +/* UserHost can be set by extern WEB function in case of WEB communicatio, + * or it should be defined as local host if DD_client is installed at USER + * computer + */ + if(UserHost[0] == '\0') + { + gethostname(HostName,HOSTNAMELENGTH); /* Get a client host name */ + + if((Host = gethostbyname(HostName)) == NULL) return NOHOST; + HostAddress = *((unsigned int *)Host->h_addr_list[0]); + + b1 = HostAddress & m1; + b2 = (HostAddress & m2) >> 8; + b3 = (HostAddress & m3) >> 16; + b4 = (HostAddress & m4) >> 24; + + sprintf(UserHost,"%03u.%03u.%03u.%03u\0",b1,b2,b3,b4); + } + return userid; +} +/*-------------------------------------------------------------------*/ + +/*------------------ MAKE_CONNECTION ---------------------------*/ +/* + * The function returns opened socket, ready to read and write + */ +int GetSocket() +/* + * Connect with remote server, and returns socket ID + * In case of error return error number according DD_comm.h + */ +{ +/*-------- Variables for resource file -----------------*/ + char rname[PATHLENGTH]; /* name of res file */ + char line[PATHLENGTH]; + char *path; + FILE *resfile; /* resource file */ + char *pline; + +/*---------- Variables for network ---------------------*/ + static struct hostent *Host; /* name & internet (32b) address for + remout hosts (see netdb.h) */ + static char RemSerName[PATHLENGTH]; /* name of remote server */ + + struct servent *serv; /* pointer to static structure of + port number of registrated service */ + + static struct sockaddr_in IntAFAddr; /* structure of internet address of type AF_INET + see <netinet/in.h> + to get name of socket we should + to convert pointer to this structure + to pointer to "srtruct sockaddr" where + all fields are "char array". */ + + int AFAddrLen = sizeof(struct sockaddr_in); /* size of internet address, <netinet/in.h> 18 bytes*/ + int ScAddrLen = sizeof(struct sockaddr); /* size of socket address, <sys/socket.h> 18 bytes*/ + + int cc,i; + int arg = 0; + int normaddr; +/* + *---------- Getting socket and its address ---------------------*/ +/*---------------- HOST and PORT ------------------------------*/ + if((path = getenv("DDPATH")) == NULL) + { + strcpy(rname,"DD.res"); + } + else + { + strcpy(rname,path); + strcat(rname, "/DD.res"); + } +/* + (void *)strcpy(rname,"./DD.res"); +*/ + if((resfile = fopen(rname,"r")) == NULL) + { + fprintf(stderr,"No resource file, sorry\n"); + exit(1); + } + + pline = fgets(RemSerName, PATHLENGTH-1, resfile); + pline = fgets(line, PATHLENGTH-1, resfile); + fclose(resfile); + + RemSerName[strlen(RemSerName)-1] = '\0'; + sscanf(line,"%d",&(normaddr)); + + IntAFAddr.sin_port = htons((uint16_t)normaddr); /* Conversion of the port number to + universal net form */ +/*---------------- END of FILE READING --------------------------*/ +/* + *------- Trying to open socket with this address and name --------- + */ + if((Host = gethostbyname(RemSerName)) == NULL) /* Get address and other information by + host name, see netdb.h */ + { + fprintf(stderr,"Server %s not found\n",RemSerName); + return(-1); + } + + if((SocketID = socket(AF_INET,SOCK_STREAM,PROTOCOL)) < 0) + { + perror("Socket:"); return(-1); + } + +/* Filling full internet address for socket "name" + * this address will be used to get communication point */ + + IntAFAddr.sin_family = Host->h_addrtype; + memcpy(&IntAFAddr.sin_addr.s_addr,Host->h_addr_list[0],Host->h_length); + + /* Connection to server socket on remote computer */ + if(connect(SocketID,(struct sockaddr *)&IntAFAddr,AFAddrLen) < 0) + { perror("connect"); return(-1); } + +/* + * Get Host name and Host ID for security application + */ + if((UserID = GetUserHost()) < 0) return(NOHOST); + + return SocketID; +} +/*------------------- end of GetSocket ---------------------*/ + +/*==================== Receive From Net ======================*/ +/* + * Smart buffered receiver + */ +int ReceiveFromNet(char *buf, int PacketSize) +{ + int CurLength = 0; + int i,cc; + do + { + i = 0; + while(((cc = recv(SocketID,buf+ CurLength,PacketSize - CurLength,0)) < 0) && (i < TRY)) i++; + if(cc < 0) return -1; + CurLength = CurLength + cc; + } while(CurLength < PacketSize); + return 1; +} + +/*------------------ Open Virtual Instrument -----------------------*/ +/* + * If no connection, connect to server, then try to order data set and return + * ID if OK or ErrorNumber if not + */ +int DD_SetVariable(char *InstrName) +{ + static caddr_t buff = NULL; + static XDR xdrs; + int InstrID; /* Instrumnet ID to return */ + int cc,i; + int Request = OPENINSREQ; + int hostlen,userlen; + char *PUserHost = UserHost, *PUserName = UserName; + /* We need this because XDR works with adresses of pointers */ + +/* If there is no connection, try to get it */ + if(SocketID < 0) + if((SocketID = GetSocket()) < 0) return(NOCONNECTION); + +/* Encoding request by XDR to buf */ +/* Buffer and stream allocation */ + buff = (caddr_t)malloc(REQUESTLENGTH); + + xdrmem_create(&xdrs, buff, REQUESTLENGTH, XDR_ENCODE); + + xdr_int(&xdrs,&Request); + xdr_string(&xdrs, &InstrName, strlen(InstrName)); + +/* Send Open Virtual Instrument request */ + + if((cc = send(SocketID,buff,REQUESTLENGTH,0)) < 0) + { + perror("DD_SetVariable:"); + free(buff); + xdr_destroy(&xdrs); + return(REQSENDERR); + } + xdrmem_create(&xdrs, buff, REQUESTLENGTH, XDR_FREE); + +/*-------- preparation an authorization request ----------------*/ + if(UserName[0] == '\0') strcpy(UserName,NONAME); + hostlen = strlen(UserHost); + userlen = strlen(UserName); + + xdrmem_create(&xdrs, buff,REQUESTLENGTH, XDR_ENCODE); + + xdr_int(&xdrs,&UserID); + xdr_string(&xdrs, &PUserHost, hostlen); + xdr_string(&xdrs, &PUserName, userlen); +/* fprintf(stderr,"userid %d host %s DD_name %s\n",UserID,UserHost,UserName); */ + +/* Send request */ + if((cc = send(SocketID,buff,REQUESTLENGTH,0)) < 0) + { + perror("DD_Set_Variable:"); + free(buff); + xdr_destroy(&xdrs); + return(REQSENDERR); + } + + free(buff); + xdr_destroy(&xdrs); + +/* Get reply */ + buff = (caddr_t)malloc(REPLYLENGTH); +/* + i=0; + while(((cc = recv(SocketID,buff,REPLYLENGTH,0)) < 0) && (i < TRY)) i++; +*/ + if((cc = ReceiveFromNet(buff, REPLYLENGTH)) < 0) + { + perror("DD_SET_Variable:"); + free(buff); + return(REPLYRECERR); + } + + xdrmem_create(&xdrs, buff, REPLYLENGTH, XDR_DECODE); + xdr_int(&xdrs,&InstrID); + +/* Free all */ + free(buff); + xdr_destroy(&xdrs); + + return InstrID; +} + +/*----------------------- DD_GetInform -----------------------------*/ +/* + * Returns "OK" if OK, fill DD_Data structure + * Return negative value if error + */ + +int DD_GetInform(int VarID,char *AttrName,DD_data_t **data) +{ + static void *v = NULL; + static DD_data_t idd = {DD_CHAR, 0, NULL,1, &v}; + static caddr_t buf = NULL; + static XDR xdrs; + int id; + int cc; + int length; + int op = DATAINFOREQ; + int type; /* type of information or error */ + int DimNumbers; + int PacketSize; + int CurLength; + int i; + u_int count; + u_int MaxNumber; + +/*------------------- Empty static data ------------------------*/ + if(idd.Dimensions != NULL) + { + free(idd.Dimensions); + idd.Dimensions = NULL; + } + if(idd.Variables[0] != NULL) + { + free(idd.Variables[0]); + idd.Variables[0] = NULL; + } + +/*------------------ Check the Name length -----------------------*/ + if(strlen(AttrName) > MAXVARLENGTH) length = MAXVARLENGTH; + else length = strlen(AttrName); + +/*----------- Allocation of memory and stream --------------------*/ + buf = (caddr_t)malloc(REQUESTLENGTH); + xdrmem_create(&xdrs, buf, REQUESTLENGTH, XDR_ENCODE); + +/*------------------- Encoding the request ----------------------*/ + xdr_int(&xdrs,&op); + xdr_int(&xdrs,&VarID); + xdr_string(&xdrs, &AttrName, length); + +/*------------------------ Send request ---------------------------*/ + if((cc = send(SocketID,buf,REQUESTLENGTH,0)) < 0) + { + perror("DD_GetInform:"); + free(buf); + xdr_destroy(&xdrs); + return(REQSENDERR); + } + free(buf); + xdr_destroy(&xdrs); + +/*------------------------ Get reply header ------------------------*/ + + buf = (caddr_t)malloc(REPLYLENGTH); +/* + i=0; + while(((cc = recv(SocketID,buf,REPLYLENGTH,0)) < 0) && (i < TRY)) i++; + if(cc < 0) +*/ + if((cc = ReceiveFromNet(buf, REPLYLENGTH)) < 0) + { + perror("DD_GetInform:"); + free(buf); + return(REPLYRECERR); + } + + xdrmem_create(&xdrs, buf, REPLYLENGTH, XDR_DECODE); + xdr_int(&xdrs,&type); + if(type < 0) + { + free(buf); + xdr_destroy(&xdrs); + return(type); + } + xdr_int(&xdrs,&DimNumbers); + xdr_int(&xdrs,&PacketSize); + free(buf); + xdr_destroy(&xdrs); + + idd.DimNumber = DimNumbers; + idd.type = type; + +/*---------------------------- Get Data Packet ----------------------*/ + if(PacketSize > 0) buf = (caddr_t)malloc(PacketSize); + else return(REPLYRECERR); + + if((cc = ReceiveFromNet(buf, PacketSize)) < 0) + { + perror("DD_GetInform:"); + free(buf); + return(REPLYRECERR); + } + +/*--------------------- Decoding data packet ------------------------*/ + if(DimNumbers > 0) + { +/*----------- Memory allocation and xdr creating -----------------*/ + xdrmem_create(&xdrs, buf, (u_int)PacketSize, XDR_DECODE); + +/*----------------- Dimensions decoding -------------------------*/ + if(idd.Dimensions !=NULL) free(idd.Dimensions); + idd.Dimensions = (int *)malloc(DimNumbers*sizeof(int)); + + xdr_array(&xdrs, (caddr_t *)&(idd.Dimensions), + &count, + (u_int )DimNumbers, + unixlen[DD_INT], + (xdrproc_t)xdr_int); + + count = 1; + for(i=0; i < DimNumbers;i++) + count = count*idd.Dimensions[i]; + MaxNumber = count; + } + else + { + free(buf); + return(REPLYRECERR); + } + +/*---------------- Allocate memory for Variables and decoding ------------------*/ + if(idd.Variables[0] != NULL) free(idd.Variables[0]); + idd.Variables[0] = (int *)malloc(unixlen[type] * MaxNumber); + + xdr_array(&xdrs,((caddr_t*)(&idd.Variables[0])),&count, + MaxNumber, unixlen[type], (xdrproc_t)ConvFunc[type]); + +/*-------------------------- Free all ------------------------------*/ + free(buf); + xdr_destroy(&xdrs); + + *data = &idd; + return OK; +} + +/*==================================================== + * DD_SetTime() + *====================================================*/ +/*----------------------------------------------------- + * VarID - ID of Data Set + * Time - string in DD type + * Returns 1 if OK and negative in case of err + *---------------------------------------------------*/ + +int DD_SetTime(int VarID,char *Time) +{ + static caddr_t buf = NULL; + static XDR xdrs; + static int op = TIMESETREQ; + int type; + int cc,i; + int DoneFlag = 0; + + while(DoneFlag == 0) + { +/* Allocatein memory and stream */ + buf = (caddr_t)malloc(REQUESTLENGTH); + xdrmem_create(&xdrs, buf, REQUESTLENGTH, XDR_ENCODE); + +/* Encoding the request */ + xdr_int(&xdrs,&op); + xdr_int(&xdrs,&VarID); + xdr_string(&xdrs, &Time, TIMELENGTH); + +/* Send request */ + if((cc = send(SocketID,buf,REQUESTLENGTH,0)) < 0) + { + perror("DD_SetTime:"); + free(buf); + xdr_destroy(&xdrs); + return(REQSENDERR); + } + free(buf); + xdr_destroy(&xdrs); + +/* Get reply header */ + + buf = (caddr_t)malloc(REPLYLENGTH); + if((cc = ReceiveFromNet(buf, REPLYLENGTH)) < 0) + { + perror("DD_SetTime:"); + free(buf); + return(REPLYRECERR); + } + + xdrmem_create(&xdrs, buf, REPLYLENGTH, XDR_DECODE); + xdr_int(&xdrs,&type); + + free(buf); + xdr_destroy(&xdrs); + + if(type < 0) + { + if(type == CACHTOOREC) sleep((unsigned )(FILEACCMARG)); + else return type; + } + else DoneFlag = 1; + } + return 1 ; +} + +/*================================================================== + * DD_SetTimeInfo() + *=================================================================*/ +/*---------------------------------------------------------- + * VarID - ID of Data Set + * Time - string in DD type + * RealTime - double : time value pointer points to + * Returns 1 if OK and negative in case of err + *----------------------------------------------------------*/ + +int DD_SetTimeInfo(int VarID, char *Time, double *RealTime) +{ + int err; + static char TimeInt[17] = "0000000000001000\0"; + DD_data_t *data; + + err = DD_SetTime(VarID, Time); + if (err < 1) return err; + + err = DD_GetData(VarID, "Time", TimeInt, &data); + if (err < 0) return err; + if (data->VarNumber < 1) return OUTOFTIME; + + *RealTime = DD_Time2Double((char *)data->Variables[0]); + + return 1 ; +} + +/*========================================================= + * DD_GetData() + * Just an interface to the DD_GetMultiData() + *========================================================*/ +int DD_GetData(int VarID, char *VarName, char *TimeInt, DD_data_t **data) +{ + char *xxx=VarName; + int err; + err = DD_GetMultiData(VarID, 1, &xxx, TimeInt, data, 1); + return err; +} +/*========================================================= + * DD_GetMultiData() + *========================================================*/ +/*--------------------------------------------------------- + * VarID - ID of open virtual instrument + * VarSize - the size of the array names + * VarNames - araay of the variables names + * TimeInt - Time interval in DD_time style + * data - returned data + * Return values: + * positives: + * MOREDELAY - call this function again after delay + * MOREDATA - call this function again to complete request + * OK - all data received + * negative value - error (see DD.h) + *---------------------------------------------------------*/ + +int DD_GetMultiData(int VarID,size_t VarSize, char **VarNames,char *TimeInt,DD_data_t **data, int BackFlag) +{ + static DD_data_t *CurrentData = NULL; /* Data records array to keep until the next call */ + static size_t OldVarSize = 0; + static caddr_t buf = NULL; + static XDR xdrs; + static int LastPacketFlag = OK; + int id; + int cc; + int *NameLength = NULL; /* Array of lengths */ + int XDRStrLen; /* xdr length of a string */ + int XDRReqlength; // Length in bytes the XDR stream + int op = DATAGETREQ; + int type; /* type of information or error */ + int DimNumbers; + int PacketSize; + int CurLength; + u_int count, MaxSize; + int i; + + /* Empty static data */ + for(id = 0; id < OldVarSize; id++) + { + if(CurrentData[id].Dimensions != NULL) + { + free(CurrentData[id].Dimensions); + CurrentData[id].Dimensions = NULL; + } + if(CurrentData[id].Variables != NULL) + { + for(i = 0; i< CurrentData[id].VarNumber; i++) + free(CurrentData[id].Variables[i]); + free(CurrentData[id].Variables); + CurrentData[id].Variables = NULL; + } + } + free(CurrentData); + + /*-------------------------------------- + * Create a new Current Data empty array + *-------------------------------------*/ + OldVarSize = VarSize; + CurrentData = (DD_data_t *)malloc(sizeof(DD_data_t)*VarSize); + for(id = 0; id < VarSize; id++) + { + CurrentData[id].Dimensions = NULL; + CurrentData[id].Variables = NULL; + CurrentData[id].DimNumber = 0; + CurrentData[id].VarNumber = 0; + CurrentData[id].type = 0; + } + /*-------------------------------------------------------------- + * The follows request preparation and send is performed only + * if the priveous data packed is completely received + *--------------------------------------------------------------*/ + if((LastPacketFlag == OK) || (LastPacketFlag == MOREDELAY)) + { + /*--------------------------------------- + * Preparation of the array the name lengths + * Note that the names are cut down to the MAXVARLENGTH + * Calculation the packet size + *---------------------------------------*/ + NameLength = (int *)malloc(sizeof(int)*VarSize); + XDRReqlength = 8; /* the length of the first+last arguments */ + for(id = 0; id < VarSize; id++) + { + if(strlen(VarNames[id]) > MAXVARLENGTH) NameLength[id] = MAXVARLENGTH; + else NameLength[id] = strlen(VarNames[id]); + XDRStrLen = (NameLength[id] / 4) * 4; + if((NameLength[id] % 4) > 0) XDRStrLen += 4; + XDRReqlength += XDRStrLen + 4; // String length + 4 bytes length coding + //fprintf(stderr,"Variable %s, length %d, total %d\n",VarNames[id],XDRStrLen,XDRReqlength); + } + /*-------------------------------- + * The first packet of the request of the standard size + * Allocation corresponding memory and stream + *------------------------------*/ + buf = (caddr_t)malloc(REQUESTLENGTH); + xdrmem_create(&xdrs, buf, REQUESTLENGTH, XDR_ENCODE); + + /* Encoding the request */ + xdr_int(&xdrs,&op); + xdr_int(&xdrs,&VarID); + xdr_string(&xdrs,&TimeInt,TIMELENGTH); + xdr_int(&xdrs,&XDRReqlength); + + /* Send the first request */ + if((cc = send(SocketID,buf,REQUESTLENGTH,0)) < 0) + { + perror("DD_GetData: First Request"); + free(buf); + xdr_destroy(&xdrs); + return(REQSENDERR); + } + free(buf); + xdr_destroy(&xdrs); + + /*-------------------------------- + * The Second packet of XDRReqlength size + * Allocation corresponding memory and stream + *------------------------------*/ + buf = (caddr_t)malloc(XDRReqlength); + xdrmem_create(&xdrs, buf, XDRReqlength, XDR_ENCODE); + xdr_int(&xdrs,(int *)(&VarSize)); + for(id = 0; id < VarSize; id++) xdr_string(&xdrs, &VarNames[id], NameLength[id]); + xdr_int(&xdrs,&BackFlag); + + /* Send the second request */ + if((cc = send(SocketID,buf,XDRReqlength,0)) < 0) + { + perror("DD_GetData:Second Packet"); + free(buf); + xdr_destroy(&xdrs); + return(REQSENDERR); + } + free(buf); + xdr_destroy(&xdrs); + } + + /*----------------------------------------------------------- + * Get the VarSize reply headers and VarSize data + *----------------------------------------------------------*/ + for(id = 0; id < VarSize; id++) + { + /*------------------- + * The header + *-----------------*/ + buf = (caddr_t)malloc(REPLYLENGTH); + if((cc = ReceiveFromNet(buf, REPLYLENGTH)) < 0) + { + perror("DD_GetData:Error while header receive"); + free(buf); + return(REPLYRECERR); + } + + xdrmem_create(&xdrs, buf, REPLYLENGTH, XDR_DECODE); + xdr_int(&xdrs,&type); + xdr_int(&xdrs,&DimNumbers); + xdr_int(&xdrs,&PacketSize); + free(buf); + xdr_destroy(&xdrs); + + if((type < 0) && (type != NOVAR)) /* Server returns unrecoverable error */ + { + fprintf(stderr,"DD_GetData: Server returns %d, unrecovable error\n",type); + return type; + } + + /*----------- Header is received ----------------------*/ + CurrentData[id].DimNumber = DimNumbers - 1; + CurrentData[id].type = type; + + /*--------------- Receive Data Packet ------------------------------*/ + if(PacketSize > 0) buf = (caddr_t)malloc(PacketSize); + else return(REPLYRECERR); + if((cc = ReceiveFromNet(buf, PacketSize)) < 0) + { + perror("DD_GetData: Error while data packet receive"); + free(buf); + return(REPLYRECERR); + } + /*----------------- Decoding data packet --------------------*/ + if(DimNumbers > 1) + { + xdrmem_create(&xdrs, buf, (u_int)PacketSize, XDR_DECODE); + count = DimNumbers-1; + /* allocation memory for dimensions */ + CurrentData[id].Dimensions = (int *)malloc((DimNumbers-1)*sizeof(int)); + + xdr_int(&xdrs,&LastPacketFlag); /* Last Paket Indicatort*/ + xdr_int(&xdrs,&CurrentData[id].VarNumber); /* Variables number */ + + if(LastPacketFlag > 2) + { + LastPacketFlag = OK; + CurrentData[id].VarNumber = 0; + free(buf); + return(REPLYRECERR); + } + + /*----- Decoding dimensions array -------------------*/ + xdr_array(&xdrs, (caddr_t *)&(CurrentData[id].Dimensions), + &count, + (u_int )DimNumbers-1, + unixlen[DD_INT], + (xdrproc_t)xdr_int); + + count = 1; + for(i=0; i < DimNumbers-1;i++) + { + count = count*CurrentData[id].Dimensions[i]; + } + MaxSize = count; + } + else + { + if(type != NOVAR) + { + free(buf); + return(REPLYRECERR); + } + else + { + CurrentData[id].VarNumber = 0; + } + } + + /*---------- Decoding variables -------------------------*/ + if(CurrentData[id].VarNumber != 0) CurrentData[id].Variables = (void *)malloc(CurrentData[id].VarNumber*sizeof(void *)); + else CurrentData[id].Variables = NULL; + + for(i = 0; i < CurrentData[id].VarNumber; i++) + { + CurrentData[id].Variables[i] = (void *)malloc(unixlen[type]*MaxSize); + count = MaxSize; + xdr_array(&xdrs,(caddr_t *)(&(CurrentData[id].Variables[i])),&count,MaxSize,unixlen[type], (xdrproc_t)ConvFunc[type]); + } + + /* Free all */ + free(buf); + xdr_destroy(&xdrs); + } + *data = CurrentData; + return(LastPacketFlag); +} +/*===================================================================*/ + +/*-------------------------- DD_CLOSE --------------------------------*/ +/* + * + * VarID - entry point of ID table + * Returns 1 if OK or negative err + * Close Socket if no VarID more ( this information supplyed by server ) + */ + +int DD_Close(int VarID) +{ + static caddr_t buf = NULL; + static XDR xdrs; + static int op = CLOSEINSREQ; + int RemainedID; /* Server returns number of remained ID */ + int cc,i; +/* Allocatein memory and stream */ + buf = (caddr_t)malloc(REQUESTLENGTH); + xdrmem_create(&xdrs, buf, REQUESTLENGTH, XDR_ENCODE); + +/* Encoding the request */ + xdr_int(&xdrs,&op); + xdr_int(&xdrs,&VarID); + +/* Send request */ + if((cc = send(SocketID,buf,REQUESTLENGTH,0)) < 0) + { + perror("DD_Close:"); + free(buf); + xdr_destroy(&xdrs); + return(REQSENDERR); + } + free(buf); + xdr_destroy(&xdrs); + +/* Get reply header */ + + buf = (caddr_t)malloc(REPLYLENGTH); +/* + i = 0; + while(((cc = recv(SocketID,buf,REPLYLENGTH,0)) < 0) && (i < TRY)) i++; + if(cc < 0) +*/ + if((cc = ReceiveFromNet(buf, REPLYLENGTH)) < 0) + { + perror("DD_Close:"); + free(buf); + return(REPLYRECERR); + } + + xdrmem_create(&xdrs, buf, REPLYLENGTH, XDR_DECODE); + xdr_int(&xdrs,&RemainedID); + if(RemainedID< 0) + { + free(buf); + xdr_destroy(&xdrs); + return(RemainedID); + } + free(buf); + xdr_destroy(&xdrs); + + if(RemainedID == 0) + { + shutdown(SocketID,2); + close(SocketID); + SocketID = -1; +/* + UserHost[0] = '\0'; + UserName[0] = '\0'; +*/ + } + + return(1); +} +/*------------------------------------------------------------------------------*/ + +/*=============== DATABASE UPDATE FUNCTIONS ====================================*/ +/*------------------ DD_AddDataSet() -------------------------------------------*/ +int DD_AddDataSet(char *DataSetName, char *RemSetID, char *BaseName) +{ + static caddr_t buf = NULL; + static XDR xdrs; + static int op = ADDVIREQ; + int Err; /* Server returns OK or NOEXEC */ + int cc,i,length; + int CloseFlag = 0; + +/* If there is no connection, try to get it */ + if(SocketID < 0) + { + if((SocketID = GetSocket()) < 0) return(NOCONNECTION); + CloseFlag = 1; // To close Connection at the end + } + +/* Allocatein memory and stream */ + buf = (caddr_t)malloc(REQUESTLENGTH); + xdrmem_create(&xdrs, buf, REQUESTLENGTH, XDR_ENCODE); + +/* Encoding the request */ + xdr_int(&xdrs,&op); + +/* Coding DataSetName */ + if((length = strlen(DataSetName)) > MAXSETLENGTH) length = MAXSETLENGTH; + xdr_string(&xdrs, &DataSetName, length); +/* Coding RemSetID */ + if((length = strlen(RemSetID)) > MAXVARLENGTH) length = MAXVARLENGTH; + xdr_string(&xdrs, &RemSetID, length); +/* Coding BaseName */ + if((length = strlen(BaseName)) > MAXVARLENGTH) length = MAXVARLENGTH; + xdr_string(&xdrs, &BaseName, length); + +/* Send request */ + if((cc = send(SocketID,buf,REQUESTLENGTH,0)) < 0) + { + perror("DD_AddDataSet:"); + free(buf); + xdr_destroy(&xdrs); + return(REQSENDERR); + } + free(buf); + xdr_destroy(&xdrs); + +/* Get reply header */ + buf = (caddr_t)malloc(REPLYLENGTH); + if((cc = ReceiveFromNet(buf, REPLYLENGTH)) < 0) + { + perror("DD_AddDataSet:"); + free(buf); + return(REPLYRECERR); + } + + xdrmem_create(&xdrs, buf, REPLYLENGTH, XDR_DECODE); + xdr_int(&xdrs,&Err); + + if(CloseFlag) // Close everything if function established connection + { + shutdown(SocketID,2); + close(SocketID); + SocketID = -1; +/* Session with DD Server was closed, but User Session continues !!!!! */ + /* UserHost[0] = '\0'; + UserName[0] = '\0'; */ + } + return Err; +} +/*-----------------------------------------------------------------------------*/ + +/*---------------------- DD GET VERSION ---------------------------------------*/ +char *DD_GetVersion() +/* + * return static pointer to internal string with the DDLIB-SERVER package version + */ +{ + static char Version[] = VERSION; + return (char *)Version; +} +/*------------------------- End Library -------------------------------*/ diff --git a/src/CLIENT/DD_time.c b/src/CLIENT/DD_time.c new file mode 100755 index 0000000..946432a --- /dev/null +++ b/src/CLIENT/DD_time.c @@ -0,0 +1,321 @@ +/* =================================================================== + * Name : DD_time.c + * Version: : 4.1 + * Author : Andrey Fedorov + * Institution : IRAP/UPS/CNRS Toulouse + * Modifications list: + * Oct 5, 2002: V.3.0, New functions DD_Time2Double and Double2DD_Time were added. + * March 26, 2010: V.3.1 YEARS up to 2025 + * May 17, 2011: V.4.0 Fedorov, completely revised version. + * There is no more confuse between Time and Time Interval + * Sept 05, 2011: V.4.1 SetIntNew => arg TimeKind => to work with 1970-1973 : BR + *==================================================================*/ + +#include "DD_time.h" +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +#define YEARS 56 +#define STARTYEAR 1970 + +/*---- Static array of days shift from Jan-1-1970 -------*/ +/* 1970 1971 1972 1973 1974 1975 1976 + * 1977 1978 1979 1980 1981 1982 1983 + * 1984 1985 1986 1987 1988 1989 1990 + * 1991 1992 1993 1994 1995 1996 1997 + * 1998 1999 2000 2001 2002 2003 2004 + * 2005 2006 2007 2008 2009 2010 2011 + * 2012 2013 2014 2015 2016 2017 2018 + * 2019 2020 2021 2022 2023 2024 2025 + */ +static double + YearDays[YEARS] = { 0.0, 365.0, 730.0, 1096.0, 1461.0, 1826.0, 2191.0, + 2557.0, 2922.0, 3287.0, 3652.0, 4018.0, 4383.0, 4748.0, + 5113.0, 5479.0, 5844.0, 6209.0, 6574.0, 6940.0, 7305.0, + 7670.0, 8035.0, 8401.0, 8766.0, 9131.0, 9496.0, 9862.0, + 10227.0, 10592.0, 10957.0, 11323.0, 11688.0, 12053.0, 12418.0, + 12784.0, 13149.0, 13514.0, 13879.0, 14245.0, 14610.0, 14975.0, + 15340.0, 15706.0, 16071.0, 16436.0, 16801.0, 17167.0, 17532.0, + 17897.0, 18262.0, 18628.0, 18993.0, 19358.0, 19723.0, 20089.0}; + +/*------------------------------------------------------------- + * DAY_OF_YEAR = monthday[*][month-1]+day_of_month -1 + *------------------------------------------------------------*/ +static int monthday[2][12] = +{ +{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, +{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} +}; + +/*------------------------------------------------------------ + * Global static Flag to show the current state of the time + * processor. Is it Time interval (0), or DD Time (1) + *----------------------------------------------------------*/ +static int TimeFlag = 1; +/*================== INTERNAL FUNCTION ====================*/ +/*-------------------- SetInt ----------------------------*/ +void SetInt(dd_tmstr_t *UT) +{ + SetIntNew(UT,DD_TM_UNKNOWN); +} + +void SetIntNew(dd_tmstr_t *UT,t_DDTimeKind timeKind) /* Fill int values of dd_tmstr_t */ +/* If the double times field of UT structure is defined, + * this function fills remains fields of Year, day .... separately + */ +{ + static double msofday = 24.0*60.0*60.0; + static double msofhour = 60.0*60.0; + static double msofmin = 60.0; + long daynumber; + double msrest; + int i; + + daynumber = (long)(UT->times / msofday); + for(i=0;i<YEARS;i++) if(daynumber < (long)YearDays[i]) break; + i--; + + switch(timeKind) + { + case DD_TM_DATE : + { + //it's a date + UT->year = i+1970; + UT->day = (int)(daynumber - (long)YearDays[i]); + break; + } + case DD_TM_TIME_INTERVAL : + { + //it's a time interval + UT->year = 0; + UT->day = (int)(daynumber); + break; + } + default : + //compatibility mode + if(i > 3) + { + UT->year = i+1970; + UT->day = (int)(daynumber - (long)YearDays[i]); + } + else + { + UT->year = 0; + UT->day = (int)(daynumber); + } + break; + } + + msrest = UT->times - (double)daynumber * msofday; + UT->hour = (int)(msrest / msofhour); + msrest -= (double)(UT->hour)*msofhour; + UT->min = (int)(msrest / msofmin); + msrest -= (double)(UT->min)*msofmin; + UT->sec = (int)(msrest); + UT->msec = (int)((msrest - (double)(UT->sec))*1000.0); + return; +} + +/*---------------- end of SetInt -----------------------*/ + +/*------------------------------------------------------- + * SetDouble() + * Returns the double value of seconds since 1 Jan 1970 + * The calculations are made from already filled dd_tmstr_t. + * If UT->year + *------------------------------------------------------*/ +void SetDouble(dd_tmstr_t *UT) +{ + static double SecInMls = 1.0/1000.0; + static double SecImMin = 60.0; + static double SecInHour = 60.0*60.0; + static double SecInDay = 60.0*60.0*24.0; + if(UT->year >= STARTYEAR) // This is DD Time ! + UT->times = (double)UT->msec*SecInMls + + (double)UT->sec + + (double)UT->min*SecImMin + + (double)UT->hour*SecInHour + + (double)UT->day*SecInDay + + YearDays[(UT->year - 1970)]*SecInDay; + else if(UT->year < STARTYEAR) // This is Time Interval + UT->times = (double)UT->msec*SecInMls + + (double)UT->sec + + (double)UT->min*SecImMin + + (double)UT->hour*SecInHour + + (double)UT->day*SecInDay + + YearDays[UT->year]*SecInDay; + else + UT->times = 0.0; + return; +} +/*----------------- end of SetDouble ---------------------*/ + +/*=================== PUBLIC FUNCTIONS ==================*/ +/*------------------- DD_Time2Double --------------------*/ +double DD_Time2Double(dd_time_t UTstring) +{ + static dd_tmstr_t UT; + static char year[5] = "0000\0"; + static char day[4] = "000\0"; + static char hour[3]= "00\0"; + static char min[3] = "00\0"; + static char sec[3]= "00\0"; + static char msec[4] = "000\0"; + + strncpy(year,UTstring,4); + strncpy(day,UTstring+4,3); + strncpy(hour,UTstring+7,2); + strncpy(min,UTstring+9,2); + strncpy(sec,UTstring+11,2); + strncpy(msec,UTstring+13,3); + + sscanf(year,"%d",&(UT.year)); + sscanf(day,"%d",&(UT.day)); + sscanf(min,"%d",&(UT.min)); + sscanf(hour,"%d",&(UT.hour)); + sscanf(sec,"%d",&(UT.sec)); + sscanf(msec,"%d",&(UT.msec)); + if(UT.year < STARTYEAR) TimeFlag = 0; // Time Inetrval + + SetDouble(&UT); + return UT.times; +} +/*------------------------------------------------------*/ + +/*------------------- Double2DD_Time ---------------------*/ + char *Double2DD_Time(double Time) + { + static dd_time_t UTstring; + dd_tmstr_t UT; + + UT.times = Time; + SetInt(&UT); + sprintf(UTstring,"%04d%03d%02d%02d%02d%03d",(UT.year),(UT.day),(UT.hour), (UT.min), (UT.sec),(UT.msec)); + return &(UTstring[0]); + } +/*------------------------------------------------------------*/ + +/*================== BACKUP COMPABILITY FUNCTIONS =================*/ +/*----------------------------------------------------------------- + * ReadTime() + * Reads a standard DD time string as an argument + * and converts it into dd_tmstr_t structure. + * Function returns the pointer to the internal startic structure dd_tmstr_t. + * Function redefines TimeFlag. + *----------------------------------------------------------------*/ +dd_tmstr_t *ReadTime(char *UTstring) +{ + static dd_tmstr_t UT; + static char year[5] = "0000\0"; + static char day[4] = "000\0"; + static char hour[3]= "00\0"; + static char min[3] = "00\0"; + static char sec[3]= "00\0"; + static char msec[4] = "000\0"; + + strncpy(year,UTstring,4); + strncpy(day,UTstring+4,3); + strncpy(hour,UTstring+7,2); + strncpy(min,UTstring+9,2); + strncpy(sec,UTstring+11,2); + strncpy(msec,UTstring+13,3); + + sscanf(year,"%d",&(UT.year)); + sscanf(day,"%d",&(UT.day)); + sscanf(min,"%d",&(UT.min)); + sscanf(hour,"%d",&(UT.hour)); + sscanf(sec,"%d",&(UT.sec)); + sscanf(msec,"%d",&(UT.msec)); + + if(UT.year < STARTYEAR) TimeFlag = 0; // Time Inetrval + + SetDouble(&UT); + return(&UT); +} +/*-------------------- end of ReadTime ------------------------*/ + +/*---------------------- Write Time ---------------------------*/ +/* Function Write time convert use only double times field + * of dd_tmstr_t structure to print time in DD style + * in internal static string. The integer fields redefined. + * Function return string pointer. + */ + +char *WriteTime(dd_tmstr_t *UT) +{ + static dd_time_t UTstring; + + SetInt(UT); + sprintf(UTstring,"%04d%03d%02d%02d%02d%03d",(UT->year),(UT->day),(UT->hour), + (UT->min), (UT->sec),(UT->msec)); + return(UTstring); +} +/*------------------- end of WriteTime -------------------*/ + +void WriteFmtTime(dd_tmstr_t *UT,char *UTstring) +{ + SetInt(UT); + sprintf(UTstring,"%04d:%03d:%02d:%02d:%02d",(UT->year),(UT->day),(UT->hour), + (UT->min), (UT->sec)); +} +/*------------------- end of WriteFmtTime -------------------*/ + +/*========================================================= + * Functions for DECODERs + * These functions make conversion from/to DD double/DD_time_structure and + * a integer array as follows: + * {Year, Month, Day_Of_Month, Hour, Min, Sec, Mls} + *========================================================*/ +/*-------------------------------------------------------- + * UT2double() + * Fille the DD_time_structure with double fild from the + * integer array (see the section header) + *-------------------------------------------------------*/ +dd_tmstr_t *UT2double(unsigned *ut) +/* Fill the standard structure with double too using as + * argument 7 int length array in Gavrilova Passport Standard + */ +{ +static dd_tmstr_t UT; +int visocos; + +if(ut[0]%4 == 0) visocos = 1; else visocos = 0; +UT.year = ut[0]; +UT.day = monthday[visocos][ut[1] - 1]+ut[2] - 1; +UT.hour = ut[3]; +UT.min = ut[4]; +UT.sec = ut[5]; +UT.msec = ut[6]; + +SetDouble(&UT); +return(&UT); +} +/*-------------------------------------------------------*/ +/*------------------------------------------------------- + * Double2UT() + * Converts Standard DD double time to interger array (see + * the section header) + *--------------------------------------------------------*/ +unsigned *Double2UT(double t) +{ + static unsigned UT[7]; + dd_tmstr_t tm; + int i,visocos; + + tm.times = t; + SetInt(&tm); + if(tm.year % 4 == 0) visocos = 1; else visocos = 0; + i = 0; + while((i < 12) && (tm.day >= monthday[visocos][i])) i++; + UT[0] = tm.year; + UT[1] = i; + UT[2] = tm.day +1 - monthday[visocos][i-1]; + UT[3] = tm.hour; + UT[4] = tm.min; + UT[5] = tm.sec; + UT[6] = tm.msec; + + return( (unsigned *)UT); +} +/*=======================================================================*/ diff --git a/src/INCLUDE/DD.h b/src/INCLUDE/DD.h new file mode 100755 index 0000000..7ce65d8 --- /dev/null +++ b/src/INCLUDE/DD.h @@ -0,0 +1,135 @@ +/*================================================================================================= + * DD SYSTEM + * DD.h + * Version: 6.0 + * Description: The public header to use DD library libDD.a + * List of changes: + * Apr. 17, 2002 Fedorov, - New error constant to interrupt the + * transmission if data dimensions are changed from file + * to file + * Nov 18, 2004 - V.4.2 - Fedorov, New errors for CACH manipulating + * Jun 17, 2007 - V.4.6 Fedorov New requestes and external executables + * Aug 02, 2007 - V.4.7 Fedorov Modification of call external executables + * Sep 24, 2007 - V.5.0 Fedorov New status of Get Data: MOREDELAY + * May 21, 2008 - V.5.1 Fedorov New Status of SetTime: CTIMEISSHIFTED + * Oct 18, 2012 - V.5.2 Knizhnikova New DD_SetTimeInfo() function + *=================================================================================================*/ + +#include "DD_time.h" + +typedef struct { int type; /* Type of variable in netcdf style */ + int DimNumber; /* number of dimensions */ + int *Dimensions; /* Dimensions array + * fastest change is last */ + int VarNumber; /* Dimension of variable array */ + void **Variables;/* Variables array pointer + * It is static array refreshed + * each call + */ + } DD_data_t; + +/*------------------- FUNCTIONS ---------------------------*/ + +extern int DD_SetVariable(char *VarName); +/* + * VarName - full name of variable <project>:<instrument>:<Variable> + * Returns VarID or negative in case of error (see bellow) + */ + +extern int DD_GetInform(int VarID,char *AttrName, DD_data_t **data); +/* + * VarID - Variable ID from DD_SetVariable + * AttrName - name of attribute ( defined by konvention ) + * data - address of data structure + * Returns 1 if OK and negative value in case of error (see bellow) + */ + +extern int DD_SetTime(int VarID, char *Time); +/* + * VarID - Variable ID from DD_SetVariable + * Time - string defined in DD_time.h + * Returns 1 if OK and negative value in case of error (see bellow) + */ + +extern int DD_SetTimeInfo(int VarID, char *Time, double *RealTime); +/* + * VarID - Variable ID from DD_SetVariable + * Time - string defined in DD_time.h + * RealTime - time pointer was set to + * Returns 1 if OK and negative value in case of error (see bellow) + */ + +extern int DD_GetMultiData(int VarID, size_t VarSize, char **VarNames, char *TimeInt, DD_data_t **data, int BackFlag); +/* + * VarID - Variable ID from DD_SetVariable + * VarSize - number of variables to return + * VarNames - the array of Names of the requested Variable + * TimeInt - String of Time interval in DD_time style + * data - Data structures array + * BackFlag - 0 - pointer is at the lasy position, 1 - pointer returns to the start point + * Returns 1 if OK and negative value in case of error (see bellow) + */ + +/* ---------------------------------------- + * This function below just call DD_GetMultiData + * for backup + *---------------------------------------*/ +extern int DD_GetData(int VarID, char *VarName, char *TimeInt, DD_data_t **data); + +extern int DD_MovePoint(int VarID, int RecordNumber); +/* + * VarID - Open virtual instrument ID + * int RecordNumber - +/- records to move + * Move pointer in the open instrument and return 1 or negative if error + */ + +extern int DD_Close(int VarID); +/* + * VarID - Variable ID from DD_SetVariable + * Returns 1 if OK and negative value in case of error (see bellow) + */ + +extern char *DD_GetVersion(); +/* + * return static pointer to internal string with the DDLIB-SERVER package version + */ + +/*----------- Data Update functions -----------------------------------*/ +extern int DD_AddDataSet(char *DataSetName, char *RemSetID, char *BaseName); +/* + * Request for new VI. See ../DOC/TECHDOC/DDServFunct.html + */ + +/*--------------------- CONSTANTS -----------------------------------------*/ +#define MOREDATA 1 /* There is data, but we have to call GetData again right now*/ +#define MOREDELAY 2 /* There is data, but we have to call GetData again after delay */ +#define OK 0 /* It is last data packet */ +#define NOCONNECTION -1 +#define TOOMANYREQ -2 +#define REQSENDERR -3 +#define REPLYRECERR -4 +#define NOID -5 +#define NOREFFILE -6 +#define NOTIMESFILE -7 +#define NOINFOFILE -8 +#define NOVAR -9 +#define OUTOFTIME -10 +#define CACHERR -11 /* The error occured when program manipulated the cach */ +#define CACHTOOREC -33 /* Off files in the CASH are created less then 5 sec ago */ +#define WAITEXTCALL -34 /* Server Waits external call finish */ +#define TRYAGAIN -35 /* Times file is locked. This request should be repeated again */ +#define NODATAATTIME -36 /* Requested time is inside NODATA time interval */ +#define GAPISSMALL -37 /* Gap is too small to call external archive */ +#define CTIMEISSHIFTED -38 /* The request was in NoData interval, try again with time at the end */ +#define DATAFILEERR -12 /* The error while manipulate with data file */ +#define ENVIRERROR -13 /* Error in Environments */ +#define NOPOINTER -14 /* The pointer points nowhere, SetTime were failed */ +#define INTSERERR -15 /* Server internal error */ +#define TIMEINEMPTY -16 /* No data for specified time interval */ +#define NOEXEC -17 /* No executable */ + +#define DD_SHORT 4 +#define DD_INT 1 +#define DD_FLOAT 2 +#define DD_DOUBLE 3 +#define DD_CHAR 0 diff --git a/src/INCLUDE/DD_Access.h b/src/INCLUDE/DD_Access.h new file mode 100755 index 0000000..a1d3b10 --- /dev/null +++ b/src/INCLUDE/DD_Access.h @@ -0,0 +1,93 @@ +/* ====================================================== + * + * DD_Access.h + * V.2.0 + * Last revision: Oct 7, 2002 + * List of revisions: 1997 - version 1.0 + * Oct 7, 2002 - version 2.0 (update a little ) + */ + +#define MAXHOSTLENGTH 16 /* IP-address: "255.255.255.255\0" */ +#define USRLENGTH 21 /* Length of UserName: + \0 */ +#define TICKETLENGTH 9 /* Length of passwd: 8 + \0 */ +#define HOSTNAMELENGTH 120 /* Length of the user host name */ +#define USERCASHLEN 100 /* Size of user_ticket.nc file must be 300 */ +#define NONAME "no_name\0" /* Name of user in case of non-WEB connection */ +#define ACCINSTR "iball:acc:all" /* Instrument which watch the access */ +#define TICKET_PATH "/ACC/user_ticket.nc" +#define USERREFNAME "/ACC/user_info.nc" +#define LOGFILE "/ACC/login.log" + +/*------------ Errors of ACCESS ---------------------*/ +#define NOPERMISSION -100 +#define NOHOST -101 +#define NOUSERSFILE -102 + +/*--------------- Extern global variables -------------------*/ +extern char UserName[USRLENGTH]; /* defined in DD_client.c */ +extern char UserHost[MAXHOSTLENGTH]; /* defined in DD_client.c */ +extern int UserID; /* defined in DD_client.c */ + +/*--------------- Extern Functions ---------------------------*/ +extern int FillStruct (int argc, void **argv); +/* This function used to set up the host address from IDL (when WWW access used) + * Arguments allocation is as follows: + * UserName - 0 + * UserHost - 1 + * Location: DD_idl.c -> DD_idl.so +*/ + +extern int GetTicket(int UID, char *HostName, int DD_user_id); +/* Description: This function find the user data in user_cash.nc + * If O'k rewrite the line with new time. + * In case of a new user, remove the first line with + * older time data then a current time + 4.5 hours. + * + Takes 3 arguments: UserId (id in the romote host) + Remote host address(string,like "193.232.6.60\0") + DD_user_id(can see in user_info.nc) + + Returns 0 if O'k or NOPERMISSIONS, or ERROR + + If DD_log_name equal NULL searching for UserId, IP-address + If DD_log_name nonequal NULL searching for IP-address,DD_log_name* + * + */ +extern int CheckTicket(char *NameUsr, char *Ticket); +/* Description: This function check if user exosts + * in user_info.nc file. Returns DD_id if O'k. + * It returns NOPERMISSION or other errors + */ + +extern int ShowTicket(int userid, char *hostname, char *DD_name); +/* + * Show if user has authorisation to work + */ + +extern int LoginRequest(char *UserPasswd, char *UserLogin, char *HostName); +/* Description: Library function for client-server using. + * Send ID, Password,UserLogin, and host to server. + * Compares the information with your {id,hostname and other}. + * Returns 0 if O'k, or a negative value in case + * of "NOPERMISSION" or error. + * + */ +extern int SetUser(int UserID, char *HostName, char *LogName); +/* Description: Library function for client-server using. + * Send UserID, HostName to server. + * Compares the information with your {id,hostname}. + * Returns 1 if O'k, or a NOPERMISSION, or error number + */ + +extern int CheckID(char *NameUsr); +/* Description: This function check the user name in user_info.nc file. + * Returns DD_id if exists. + * It returns NOPERMISSION or other errors + */ + +extern void Put2Log(int UID, char *Host, char *LogName, int error); +/* Description: This function logs a user's ID, IP-address of a local host, + * login name and permission information into log file. + * + */ + diff --git a/src/INCLUDE/DD_comm.h b/src/INCLUDE/DD_comm.h new file mode 100755 index 0000000..bc0cef2 --- /dev/null +++ b/src/INCLUDE/DD_comm.h @@ -0,0 +1,383 @@ +/*================================================================================= + * DD SYSTEM base package + * DD_Server DD_Client library + * DD_comm.h + * V. 6.0 + * Changes listing: + * Feb 27 1995 - V 1.0 + * 13 Apr. 2002 - changed for NetCDF 3.3 + * 03 Oct. 2002 - v.4.0 Fedorov, communication ideology is changed + * Oct 31, 2002 - V.4.1 Fedorov, UserName, UserHost and UserID transferred into DD_Access.h + * May 7, 2003 - V.4.2 Fedorov, The Cash structure is changed (flag of open file ) + * June 17, 2003 - V.4.3 Fedorov, The Maximal Packet Size is changed + * Nov 18, 2004 - V.4.4 Fedorov, Some changes + * Aug 17, 2005 - V.4.5 Fedorov, Cach Time constant is changed + * Jun 17, 2007 - V.4.6 Fedorov, New requestes and external executables + * Aug 01, 2007 - V.4.7 Fedorov, Cache length = 20, New DD_Var_t structure + * Sep 20, 2007 - V.5.0 Fedorov, Update Time Info library now in the separate file + * Sep 23, 2007 - V.5.1 Fedorov, New interface of SetTime + * Sep 25, 2007 - V.5.2 Fedorov, Individual minimal gap + * Oct 08, 2007 - V.5.3 Budnik, php createVI.php <baseID> <remSetID> <ddSetID> + * Jan 25, 2008 - V.5.3.1 Budnik, min data gap = 1 day!!!! + * May 22, 2008 - V.5.4 Fedorov, DD_Var_t has a LockStartTime value + * May 27, 2008 - V.5.5 Fedorov, Maximal tracnsmition buffer + * Sep 19, 2008 - V.5.6 MAXVARLENGTH=64 REQUESTLENGTH 184 + * Dec 15, 2012 - V.6.0 New multiparam Get_MultiData() function + *===================================================================================*/ + +#include <stdio.h> +#include <sys/errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#include <time.h> +#include "DD_Access.h" + +#ifdef SOLARIS +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> /* internet stile addres */ +#include <rpc/types.h> +#include <rpc/xdr.h> +#include <rpc/rpc.h> +#endif /* SOLARIS */ + +#ifdef HPUX +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <sys/un.h> +#include <rpc/xdr.h> +#include <rpc/rpc.h> +#endif + +#ifdef OSF1 +#include <sys/socket.h> +#include <netdb.h> +#include <arpa/inet.h> +#include <rpc/xdr.h> +#endif /* OSF1 */ + +#ifdef LINUX +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <rpc/rpc.h> +#include <rpc/xdr.h> +#endif /* LINUX */ + +#ifdef SUNOS +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <netinet/in.h> +#include <netdb.h> +#include <rpc/xdr.h> +#endif /* SUNOS */ + +/*----------------- Defenitions of request and server replies --------------------*/ +/* 1. Data manipulation requests */ +#define OPENINSREQ 0 /* Open virtual instrument */ +#define DATAINFOREQ 1 /* Request of constant info */ +#define TIMESETREQ 2 /* Position of pointer by StartTime*/ +#define DATAGETREQ 3 /* Data request by time interval */ +#define CLOSEINSREQ 4 /* Request to close virtual instrument */ +#define MOVPOINTREQ 5 /* Move the pointer od data request*/ +#define ADDVIREQ 6 /* Add New virtual instrument */ + +/* 2. Security requests */ +#define GETTICKETREQ 10 +#define SHOWTICKETREQ 11 + +/*-------- Some constants ------------------*/ +#define EMPTY 0 /* Filler of the trailer */ +#define FILEACCMARG 1 /* The minimum time from the last access to remove this file */ + +/*------------ Important lengths and pathes ----------------*/ +#define PROTOCOL 0 /* protocol TCP */ +#define REPLYLENGTH 12 /* Length of header of reply packet */ +#define REQUESTLENGTH 196 /* Length of request packets MAXSETLENGTH + 2*MAXVARLENGTH + 16 */ +#define MAXVARLENGTH 64 /* Length (with \0) of Variable Name */ +#define MAXSETLENGTH 52 /* Max Length of VI name */ +#define PATHLENGTH 128 /* Length of complete path */ +#define MAXFILENAME 32 /* The maximal length of the data file (info, cach, times as well)*/ +#define REFNAME "/refer.nc" /* path name for databse refer file */ +#define CASHLEN 20 /* Length of cash array */ +#define TRY 100 /* How many tymes to ask the socket */ +#define MAXPACKSIZE 5000000 /* Maximal size of one packet of transmission in bytes */ +#define MAXCOMMANDL 300 /* Command in system() maximal length +/*------------------------------------------------- + * XDR length to calcolate the total len + *-------------------------------------------------*/ +#define XDRINTLEN 4 +#define XDRFLOATLEN 4 +#define XDRDOUBLELEN 8 +// String length is counted as 4B + N + r (to completed to 4 bytes) + +/*------------ List of External Call of DD_Server and ERRORS -------------------*/ +#define ADDDATASETCALL "php %s/createVI.php %s %s %s" /* Format to call to create new VI */ +#define GETNEWDATACALL "php %s/getData%s.php %s %s %s %s &" /* Format to call to get new data */ +#define NOPHP 32512 +#define NOSCRIPT 256 +#define PHPOK 0 + +/*------ Constant to understand data availabilities -------------------------------*/ +#define GLOBSTARTNAME "GlobalStart" +#define GLOBSTOPNAME "GlobalStop" +#define SAMPLNAME "MinSampling" +#define REMARCHNAME "DataBaseID" +#define REMINSTNAME "DataSetID" +#define MINGAP 86400.0 /*Seconds. The minimal time gap to set up the flag DATAGAP */ +#define REQTIMEINT 86400.0 /* One day, +/- of request time interval */ +#define ISOTIMEF "%4u%*1c%2u%*1c%2u%*1c%2u%*1c%2u%*1c%2u%*1c%3u" /* Format to READ time in ISO format */ +#define ISOTIMEP "%04u-%02u-%02uT%02u:%02u:%02u.%03uZ" /* Format to PRINT time in ISO format */ +#define NODATASTR "NODATA" +#define DIRLOCK "LOCK" + +#define QUANTOFFSET 0.01 +/*------------- More internal specifications -----------------------*/ +/* + * See ../DOC/TECHDOC/DDGenProt.html (lyx) + */ + +/* Reply variables: + * Error - negative value described in DD.h + * Type - int (see DD.h) + * Dim_Number - int ( the dimension (vector, matrix, cube, etc) ov the variable) + * Data_Size - int (the size of the data packet in bytes) + * RemID - int (number of virtual instruments still open in this session) + * Dim - int (the particular dimension ) + * LastPacketFlag - int ( == OK in this packet is last, or MOREDATA) + * Data - array of Type of Dim X Dim X....X Dim size + * -------------------- + * Dim_Number + * DataPacket: + * + * <LastPacketFlag> | + * <Dim> | | + * <.....> | Dim_Number | Data_Size bytes + * <Dim> | | + * <data> | + * ..... | only for real data | + * <data> | | + * + * Note is the value is scalar - the Dim = 0 (???) + */ + +/* REPLY SPECIFICATION + * + * Reply consists Header 12 bytes length and Data Block + * + * on Open Virtual instrument: + * <OPENINSREQ><ID/Eroor><EMPTY><EMPTY> + * on Constant Info request: + * <DATAINFOREQ><Type/Error><Dim_Number><Data_Size><DataPacket> + * on Set pointer by StartTime: + * <SETTIMEREQ><EMPTY/Error><EMPTY><EMPTY> + * on Get Data by TimeInt : + * <DATAGETREQ><Type/Error><Dim_Numbers><Data_Size><LastRecordFlag><DataPacket> + * on Move pointer with records number + * <MOVPOINTREQ><EMPTY/Error><EMPTY><EMPTY> + * on Close Virtual Instrument + * <CLOSEINSREQ><RemID/Error><EMPTY><EMPTY> + */ + +/*-------------------- TYPEDEF ---------------------------*/ +typedef struct { char names[CASHLEN][MAXSETLENGTH]; + long times[CASHLEN]; + int FileOpen[CASHLEN]; /* 1 if file is open */ + int ID; /* ID of open cach file */ + int nameID; /* ID of names array */ + int timeID; /* ID of times array */ + int fopenID; /* ID of fopen flag */ + } DD_cash_t; /* The structure holding cash informaton + * of particular virtual instrument DataBase + */ + +/* + * This structure corresponds to ONE requested variable + * of some Virtual instrument + */ +typedef struct { char InstrName[MAXSETLENGTH]; /* Virtual Instrument Name */ + char path[PATHLENGTH]; /* Path to directory of open virtual instrument */ + /*--------------------------------------- + * Cache part + *--------------------------------------*/ + DD_cash_t Cash; /* Cash holder */ + int CurrCushN; /* Current cash pointer */ + /*-------------------------------------- + * This is the part of open data file and corresponding data set + *-------------------------------------*/ + int ncID; /* ID of open nc_file */ + size_t nc_rec; /* the current record number nc_file */ + size_t Maxnc_rec; /* Maximum of records number in in the current nc file */ + DD_data_t *VarData; /* Static pointer. Variables Holder */ + size_t ParamSize; /* Number or requested variables to save */ + /*--------------------------------------------- + * This is part of times file of given VI + *--------------------------------------------*/ + char TimesFileName[PATHLENGTH]; + double SDTime; /* Requested Start Time in double form */ + double FDTime; /* Requested Stop Time in double form */ + double CDTime; /* Current Time in double form */ + int tmID; /* ID of "times" file of this virtual instrument*/ + int NameID; /* ID of FileName variable in times file */ + int StartID; /* ID of Start variable in times file */ + int StopID; /* ID of Stop variable in times file */ + size_t TimeRecNumber; /* Current Record number in the "times" file */ + size_t MaxTimeRecNum; /* Maximum records number in the "times" file */ + int RValidMin; /* Minimal record with valid data */ + int RValidMax; /* Maximal record with valid data */ + double MinValidTime; + double MaxValidTime; /* Start of RValidMin, and stop of RValidMax */ + int CurrRmin; /* Sure that looking time is greater than stop; -1 if NOT */ + int CurrRmax; /* Sure that looking time is less than start; -1 if NOT */ + /*------- Working with external Data Base ------------------------------*/ + int VILocked; /* Flag to show that request to remote database has been sent */ + time_t LockStartTime; /* Value to calculate a time elapsed from lock made by THIS VI */ + /*---------- This is the part of Info file of given VI -----------------*/ + int attrID; /* ID of constant information nc_file */ + char AttrName[PATHLENGTH]; /* Name of constant information file */ + DD_data_t AttrData; /* Dimensions of Attributes */ + /*---- Part concerning External call ------------------*/ + double MinGap; /* The minimal gap between two files */ + double GlobalStart; /* The principal begin of data */ + double GlobalStop; /* The principal end of data */ + char BaseName[MAXSETLENGTH]; /* The name of external data archive */ + char RemSetID[MAXSETLENGTH]; /* The name of VI in exterval archiving */ + int ExtCallAllowed; /* 1 If Server can call external archiving */ + /*------------ Flow Control -----------------------------*/ + int LastPacketFlag; /* OK - request is completed, + * MOREDATA - one or several blocks expected, + * MOREDELAY - wait, system is blocked */ + int LastFileStatus; /* The file status after the last SetNewFile */ + int NewFile; /* 1 if File was changed, VI has to be refreshed*/ + int NewFileWasOpen; /* 1 if the original position of pointer + * (in data file, times file) was lost after open + * a new data file */ + } DD_Var_t; + +/*---------------- Usefull enumerations ---------------------*/ +enum SearchRet {REACHLEFT, REACHRIGHT, OKLEFT, OKRIGHT}; + /* + * enumerate of the status of time inteval searching + * NOONEDATA - no data at al in this VI + * INSIDE - CTime is inside valid data interval (tolerance is MINGAP) + * DATAATRIGHT, DATAATLEFT - Valid interval is on the right/left from CTime + */ +enum SearchIntRet {NOONEDATA, INSIDE, DATAATRIGHT, DATAATLEFT, IDLE}; + +/* Return function IsTimesLocked */ +enum LockStatus {NOLOCK, LOCKED, LOCKREMOVED}; + + +/*------------------ Function for Server ---------------------*/ +extern int OpenInstr(char *InstrName); +/* + * Open Virtual instrument by name and returns the ID + * Returns negative value in case of error (see DD.h)or OK + */ +extern int GetAttribute(int ID, char *Name); +/* + * Variable - address of structure with variable description + * Name - name of attribute + * Returns OK or an error (see DD.h) + */ +extern int GetMultiData(int ID, int VarSize, char **VarNames, char *TimeInterval, int BackFlag); +/* + * VarSize - size of the array of Names + * Names - array of strings with names of requested variables, + * TimeInterval - Time in DD_time.h style + * Returns negative value in case of error (see bellow) + * Returnes MOREDATA if "there is more data", and OK if data is finished. + */ + +extern int SetTime(DD_Var_t *D, double CTime); +/*################################################################# + * SET TIME + * Set time and try to open appropriate data file. If not try to + * call external archive + * D - address of VI holder + * Time - Time in DD_time.h style + * Return: + * OK + * NOID - call with uncorrect VI holder + * OUTOFTIME - Requested time is out of General time limitation + * WAITEXTCALL - Server sent request to external archive + * TRYAGAIN - VI is blocked by call to external database + * NODATAATTIME - request time is inside NODATA time interval + * some return of SetNewFile(); see ... + *#################################################################*/ + +extern int CloseID(int ID); +/* ID - integer identificator of opened Data Set + * Returns number of remained IDs of this communication seasson + * in case of 0 the server closes this comminication session + */ + +int SetNewFile(DD_Var_t *D, int N); +/* + * Function tries to get new data for the gap beetween files, or just + * open a new data file according to offset N referring to current position in the times file. + * The current position changed if file is succesefully open. + * Return values: + * OK + * OUTOFTIME - next interval exceeeds GlobalStart/Stop + * TIMEINEMPTY - next interval marked as "NODATA" + * TRYAGAIN - the VI is blocked while new data is arriving + * WAITEXTCALL - new data is requested + * CACHTOOREC - now free space in the CACH + * CHACHERR - unrecovable error in CACH + * DATAFILEERR - unrecovable error in data file + */ + +size_t MaxRecord(int ncID); +/* + * Inspect all variables and dimensions of the file (exept Time associated) and + * returm maximal record number to transmit + */ +/*------------------ Global constants ----------------------------------*/ +static u_int xdrlen[] = {4,4,4,8,4}; +static size_t unixlen[] = {sizeof(char),sizeof(int),sizeof(float),sizeof(double),sizeof(short)}; +static bool_t ( *ConvFunc[5])() = {xdr_char, xdr_int, xdr_float, xdr_double, xdr_short}; + +/*------------------ Global data variable for entire session --------------------*/ +extern DD_Var_t **DD_Var ; /* Actually this variable is implimented + * in DD_GetData.c . The dimension of this array is defined + * by sysconf(_SC_OPEN_MAX)*/ +extern size_t MaxIDNumber; /* Size of DD_Var array. Defined actually in DD_GetData.c */ + +/* + * Fuctions prototypes in ExtDataRequest.c file + */ +/*====================================================================== + * IsTimesLocked + * Return 1 if there is LOCK in the VI directory + *======================================================================*/ +extern int IsTimesLocked(DD_Var_t *DD_Var); + +/*====================================================================== + * ExtDataRequest + * Return folowing values: + * OK - request is accepted SERVER has to wait when LOCK file is gone + * NOEXEC - error in external executable + * NODATAATTIME - time corresponds to the NODATA interval + * GAPISSMALL - Time is inside too small gap + *======================================================================*/ +extern int ExtDataRequest(DD_Var_t *DD_Var, double CurrTime); + +/*======================================================================= + * UpdateTimeInfo.c + * int SearchLeft(DD_Var_t *DD_VarL, size_t Rmin, size_t Rmax) + * int SearchRight(DD_Var_t *DD_VarL, size_t Rmin, size_t Rmax) + * Search the next to the left(right) non-empty time interval + * DD_VarL - common data structure corresponding to THIS open VI + * Rmin, Rmax - start points + * + * int UpdateTimeInfo(DD_Var_t *DD_VarL) + * Function reopen "times" file and update all time constants + *======================================================================*/ +extern int SearchLeft(DD_Var_t *DD_VarL, size_t Rmin, size_t Rmax); +extern int SearchRight(DD_Var_t *DD_VarL, size_t Rmin, size_t Rmax); +extern int UpdateTimeInfo(DD_Var_t *DD_VarL); + diff --git a/src/INCLUDE/DD_time.h b/src/INCLUDE/DD_time.h new file mode 100755 index 0000000..51c4720 --- /dev/null +++ b/src/INCLUDE/DD_time.h @@ -0,0 +1,59 @@ +/* This is header file for working with DD time */ +/* V.4.1 */ +/* name: DD_time.h + * Author: Andrey Fredorov + * Institution: IKI RAN + * Date: 21-Feb-1995 + * Last update Sept 05, 2011 + * Sept 05, 2011: V.3.2 SetIntNew => arg TimeKind => to work with 1970-1973 : BR + */ + +#define TIMELENGTH 17 + +typedef char dd_time_t[TIMELENGTH]; /* YYYYDDDHHMMSSMLS */ + +/* ---------------- Functions prototypes ----------------------*/ +extern double DD_Time2Double(dd_time_t DD_Time); +/* Convert string to double and return. + * Return negative value in case of error string format + */ +extern char *Double2DD_Time(double Time); +/* Convert double Time value into string form and return pointer to static string + * allocated INSIDE the library. Thus the value is renoveted each function call. + */ + +/*---------------- Backup compability with V.3.0 and earlier ----------*/ +typedef struct { double times; /* time sec from 1970 */ + int year; + int day; + int hour; + int min; + int sec; + int msec; + } dd_tmstr_t ; + + +extern dd_tmstr_t *ReadTime(char *UT); /* Read time from sring and fill static + * structure defined IN function. + * Returns pointer of strusture */ +extern char *WriteTime(dd_tmstr_t *UT); /* Get pointer of time structure + * and convert it into string + * Function returns pointer of + * internal string */ + +extern void WriteFmtTime(dd_tmstr_t *UT,char *UTstring); + +extern void SetDouble(dd_tmstr_t *UT); /* Fill double value of dd_tmstr_t */ + +typedef enum {DD_TM_UNKNOWN, DD_TM_TIME_INTERVAL, DD_TM_DATE} t_DDTimeKind; + +extern void SetInt(dd_tmstr_t *UT); /* Fill int values of dd_tmstr_t */ +extern void SetIntNew(dd_tmstr_t *UT,t_DDTimeKind timeKind); + +/*------- Functions for DECODERS ------------------------ + *These functions works with with Gavrilova's UT representation */ +extern dd_tmstr_t *UT2double(unsigned *UT); /* Set standard time + * structure and return + * its pointer + */ +extern unsigned *Double2UT(double Time); /*Converts Double to Gavrilova array */ diff --git a/src/SERVER/CMakeLists.txt b/src/SERVER/CMakeLists.txt new file mode 100644 index 0000000..8084f6c --- /dev/null +++ b/src/SERVER/CMakeLists.txt @@ -0,0 +1,26 @@ + +PROJECT(DDServer) + +include_directories( + ${CMAKE_HOME_DIRECTORY}/src/INCLUDE/ + ${NETCDFINCLUDE_DIR} +) + +#Configuration de l'exécutable +file( + GLOB_RECURSE + source_files + ./* +) + +ADD_EXECUTABLE (DDServer ${source_files} ) + +target_link_libraries( + DDServer + ${CMAKE_THREAD_LIBS_INIT} + DDClient + ${NETCDFLIBRARY} + ${CRYPT_LIBRARY} +) + +install (TARGETS DDServer DESTINATION bin) diff --git a/src/SERVER/DD_Access_sr.c b/src/SERVER/DD_Access_sr.c new file mode 100644 index 0000000..1ae7e5f --- /dev/null +++ b/src/SERVER/DD_Access_sr.c @@ -0,0 +1,655 @@ +/* + *-------------------- DD_ACCESS ------------------------------- + * + * name: DD_Access.c V4.0 + * author: Alexander Grigoriev , Andrei Fedorov + * Insitution: IKI RAN lab.546 aug@afed.iki.rssi.ru + * Description: Set of function for access to DD system + * Last revision: Oct 10, 2002 + * List of revisions: + * March 1999 V1.0 + * 20 Oct 1999 ; ShowTicket was corrected. V2.0 + * 28 Oct 1999 ; Added LOGINS,ddcheck V3.0 + * Oct 10, 2002 - revised by A. Fedorov V 4.0 + */ +/*#define _XOPEN_SOURCE*/ /* for crypt function */ + +#define _XOPEN_SOURCE +#include <unistd.h> +#include <time.h> +#include <DD.h> +#include <netcdf.h> +#include <DD_comm.h> +#include <DD_Access.h> + +/*=========== Global Variables ===============================*/ + size_t CashStart[2]={0L,0L}; + size_t CashCount[2]={1, MAXHOSTLENGTH}; + size_t CashCountInt[2]={1, 1}; + extern int Verbose; + +/*############################################################################*/ + +/*----------------GETTICKET------------------------------------*/ + +/* Description: This function find the user data in user_cash.nc + * If O'k rewrite the line with new time. + * In case of a new user, remove the first line with + * older time data then a current time + 4.5 hours. + * + Take 3 arguments: UserId, + IP-address(string,like "193.232.6.60\0") + DD_user_id(can see in user_info.nc) + + Returns 0 if O'k or NOPERMISSION if error + + If DD_log_name equal NULL searching for UserId, IP-address + If DD_log_name nonequal NULL searching for IP-address,DD_log_name* + * + */ + +int GetTicket(int UID, char *HostName, int DD_user_id) + { + char *ddbase; + char refname[PATHLENGTH]; + int TicketID, Comp=1, Flag,OldFlag=0, Find=0, dltt; + int CurIDID,HostID,TimeID, DD_id_ID; /* Variable IDs in the NC ticket file */ + int TimeFinish; + int Clock; + char CurHostName[MAXHOSTLENGTH]; + int CurID, CurTime,DD_id, MemTime,OldestStart; /* Values to read and write to ticket file */ + size_t CurCashStart[2]={0,0}; + size_t HostCount[2] = {1,MAXHOSTLENGTH}; + int ACCESS = NOPERMISSION; + int status; /* Return value of any NC routine */ + + if(Verbose) fprintf(stderr,"GetTicket: UID = %d, HostName <%s>, DD_user_id = <%d> is going to work\n",UID, HostName,DD_user_id); + +/*------------- OpenUserNC ---------------------------------*/ + + if((ddbase = getenv("DDBASE")) == NULL) + { + if(Verbose) fprintf(stderr,"GETTICKET: No DDBASE environment.\n"); + return(ENVIRERROR); + } + strcpy(refname,ddbase); + strcat(refname,TICKET_PATH); + if(Verbose) fprintf(stderr,"GETTICKET: TICKET_PATH is %s \n",refname); + + if((status = nc_open(refname, NC_WRITE,&TicketID)) != NC_NOERR) + { + if(Verbose) fprintf(stderr,"GETTICKET: %s\n", nc_strerror(status)); + return(NOUSERSFILE); + } + +/*------------------ Working with -------------------------------*/ + + status = nc_inq_varid(TicketID,"id",&CurIDID); + status = nc_inq_varid(TicketID,"host",&HostID); + status = nc_inq_varid(TicketID,"time",&TimeID); + status = nc_inq_varid(TicketID,"DD_id",&DD_id_ID); + status = nc_sync(TicketID); + + Clock = (int)time(NULL); + + // TimeFinish = Clock+16200; // 4.5 hours + TimeFinish = Clock+172800; // 48 hours + HostName[strlen(HostName)] = '\0'; + CashStart[0]=0; + OldestStart = 0; + + do + { + status = nc_get_var1_int(TicketID, CurIDID, CashStart,&CurID); + nc_get_var1_int(TicketID, DD_id_ID, CashStart,&DD_id); + nc_get_vara_text(TicketID, HostID,CashStart,HostCount,CurHostName); + nc_get_var1_int(TicketID, TimeID,CashStart,&CurTime); + + if(CashStart[0] == 0) MemTime=CurTime; + + Comp=strcmp(CurHostName,HostName); + + if((CurID == UID)&&(Comp == 0)&&(DD_id == DD_user_id)) + { + CurCashStart[0]=CashStart[0]; + Find = 1; + } + dltt = (CurTime - MemTime); + + if((dltt < 0) && (CurHostName[0] != '\0')) + { + OldestStart=CashStart[0]; + MemTime = CurTime; + } + + CashStart[0]++; + } + while((Find != 1) && (CurHostName[0] != '\0') && (CashStart[0] < USERCASHLEN)); + + if(Verbose) fprintf(stderr,"FINISH TIME : %ld\n",TimeFinish); + + CashStart[0]--; + + if(MemTime < Clock) { + OldFlag = 1; + } + if(Find == 1) + { + nc_put_var1_int(TicketID,TimeID,CurCashStart,&TimeFinish); + if(Verbose) fprintf(stderr,"User: ID = %d, DD_id = %d, HostName <%s> continue work.\n ",UID,DD_user_id,HostName); + ACCESS = 0; + } + else + if(OldFlag == 1) + { + CashStart[0]=OldestStart; + + nc_put_var1_int(TicketID,CurIDID, CashStart,&UID); + nc_put_var1_int(TicketID,DD_id_ID, CashStart,&DD_user_id); + nc_put_vara_text(TicketID,HostID,CashStart,HostCount,HostName); + nc_put_var1_int(TicketID,TimeID,CashStart,&TimeFinish); + if(Verbose) fprintf(stderr,"User: ID = %d, DD_id = %d, \n HostName <%s> started work.\n ",UID,DD_user_id,HostName); + ACCESS = 0; + } + else + if((CashStart[0]<USERCASHLEN) && (CurHostName[0] == '\0')) + { + nc_put_var1_int(TicketID,CurIDID, CashStart,&UID); + nc_put_var1_int(TicketID,DD_id_ID, CashStart,&DD_user_id); + nc_put_vara_text(TicketID,HostID,CashStart,HostCount,HostName); + nc_put_var1_int(TicketID,TimeID,CashStart,&TimeFinish); + if(Verbose) fprintf(stderr,"User: ID = %d, DD_id = %d, \n HostName <%s> started work.\n ",UID,DD_user_id,HostName); + ACCESS = 0; + } + else {fprintf(stderr,"Too many members!\n");ACCESS = NOPERMISSION;} + + + /*if((CurID == UID)&&(Comp == 0)) fprintf(stderr,"Exists...\n");*/ + + nc_sync(TicketID); + nc_close(TicketID); + +return((int)ACCESS); +} + +/*############################################################################*/ + +/*-------------------CHECK TICKET-----------------------*/ + +/* Description: This function check the user for accessability + * in user_info.nc file. Returns DD_id if O'k. + * Returns NOPERMISSION in case of unaccessability, neagative value (DD_access.h) + * in case of error. + */ + +int CheckTicket(char *NameUsr, char *Ticket) +{ + int i=0; + int DD_id; + int Right = NOPERMISSION; + char salt[2],newkey[USRLENGTH]; + + int UsrRefID; /* ID of reference file which consists description of all users */ + char *ddbase; + char refname[PATHLENGTH]; + + int UserDimID,UserLenDimID,PasLenDimID; /* ID of dimensions in NC file */ + int MemID, PasID; /* ID of variables in NC file */ + size_t MaxRecords, UserLength, PasswdLength; /* Dimensions */ + size_t start[2] = {0,0}, UserCount[2] = {1,0}, PasswdCount[2] = {1,0}; + static char UserDimName[] = "user", UserLenDimName[] = "UserLength"; /* Dimensions names */ + static char PasLenDimName[] = "PasswdLength"; /* Dimensions names */ + static char MemName[] = "member", PasName[] = "passwd"; /* Variable Names */ + char PasChar[USRLENGTH],MemChar[USRLENGTH]; + int status; /* Return of any NC call */ + +/*------------- Open User reference NC ---------------------------------*/ + if((ddbase = getenv("DDBASE")) == NULL) + { + if(Verbose) fprintf(stderr,"CHECKTICKET: No DDBASE environment.\n"); + return(ENVIRERROR); + } + strcpy(refname,ddbase); + strcat(refname,USERREFNAME); + if(Verbose) fprintf(stderr," CHECHTICKET: PATH is %s \n",refname); +// sleep(40); + if((status = nc_open(refname, NC_WRITE,&UsrRefID)) != NC_NOERR) + { + if(Verbose) fprintf(stderr,"CHECHTICKET: %s\n", nc_strerror(status)); + return(NOUSERSFILE); + } + +/*------------------ Define all dimensions -------------------------------*/ + + status = nc_inq_dimid(UsrRefID,UserDimName,&UserDimID); + status = nc_inq_dimlen(UsrRefID, UserDimID, &MaxRecords); + status = nc_inq_dimid(UsrRefID,UserLenDimName,&UserLenDimID); + status = nc_inq_dimlen(UsrRefID, UserLenDimID, &UserLength); + UserCount[1] = UserLength; + status = nc_inq_dimid(UsrRefID,PasLenDimName,&PasLenDimID); + status = nc_inq_dimlen(UsrRefID, PasLenDimID, &PasswdLength); + PasswdCount[1] = PasswdLength; + +/*fprintf(stderr,"CheckTicket:Rec: %d %d %d\n",MaxRecords,UserLength,PasswdLength);*/ + +/*------------------ Define all variables ID -------------------------------*/ + status = nc_inq_varid(UsrRefID, MemName,&MemID); + status = nc_inq_varid(UsrRefID, PasName,&PasID); + + + for(i=0;i<MaxRecords;i++) + { + start[0]=(size_t)i; + nc_get_vara_text(UsrRefID, MemID, start,UserCount, MemChar); + + if(strcmp(MemChar,NameUsr)==0) + { + nc_get_vara_text(UsrRefID, PasID, start, PasswdCount, PasChar); + + /*fprintf(stderr,"Your dd_id is %u\n",i);*/ + DD_id = i; + Ticket[strlen(Ticket)]='\0'; + NameUsr[strlen(NameUsr)]='\0'; + newkey[PasswdLength-1]='\0'; + + strncpy(salt,PasChar,2); + + strcpy(newkey,(char *)crypt(Ticket,salt)); + + if(strcmp(PasChar,newkey) == 0) + { + if(Verbose) fprintf(stderr,"User %s is logged in\n",NameUsr); + Right = DD_id; + } + else + { + if(Verbose) fprintf(stderr,"for user %s permission denied.\n",NameUsr); + Right = NOPERMISSION; + } + } + } + nc_close(UsrRefID); +return((int)Right); +} + +/* + *-------------------- SHOW TICKET -------------------------------*/ +/* + * Description: Library function. Used by DD_Server. It reads the + * content of user_ticket.nc file. Compares the information + * with your {id,hostname,DD_id,time}. + * If id and hostname(IP_address) and DD_id exists in table of registarated + * users, check the working time. If one has any time for work, returns 0, + * or a negative value "NOPERMISSION". + * It IS DD_Check ! + */ + +int ShowTicket(int userID, char *hostname, char *DD_name) + { + char *ddbase; + char refname[PATHLENGTH]; + int TicketID; /* Ticket file ID */ + int Comp=1, Time_is=0, Find=0; + int CurIDID,HostID,TimeID, DD_id_ID; /* NC variables ID */ + time_t Clock; + char CurHostName[MAXHOSTLENGTH]; + int CurID, CurTime, RefTime, DD_id; /* Variables */ + size_t CurCashStart[2]={0,0}; + size_t HostCount[2] = {1,MAXHOSTLENGTH}; + int ServerReply = NOPERMISSION; + int DD_user_id = -1; + int status; /* Return of any NC call */ + + hostname[strlen(hostname)]='\0'; + DD_name[strlen(DD_name)]='\0'; + if((strcmp(DD_name,NONAME))!=0) DD_user_id = CheckID(DD_name); + +/*------------- OpenUserNC ---------------------------------*/ + + if((ddbase = getenv("DDBASE")) == NULL) + { + if(Verbose) fprintf(stderr,"SHOWTICKET: No DDBASE environment.\n"); + return(ENVIRERROR); + } + strcpy(refname,ddbase); + strcat(refname,TICKET_PATH); + if(Verbose) fprintf(stderr,"SHOWTICKET: TICKET_PATH is %s \n",refname); + + if((status = nc_open(refname, NC_WRITE,&TicketID)) != NC_NOERR) + { + if(Verbose) fprintf(stderr,"SHOWTICKET: %s\n", nc_strerror(status)); + return(NOUSERSFILE); + } + +/*------------------Info about source.file-------------------------------*/ + status = nc_inq_varid(TicketID,"id",&CurIDID); + status = nc_inq_varid(TicketID,"host",&HostID); + status = nc_inq_varid(TicketID,"time",&TimeID); + status = nc_inq_varid(TicketID,"DD_id",&DD_id_ID); + + nc_sync(TicketID); + CashStart[0]=0; + + do + { + status = nc_get_var1_int(TicketID, CurIDID, CashStart,&CurID); + status = nc_get_var1_int(TicketID, DD_id_ID, CashStart,&DD_id); + status = nc_get_vara_text(TicketID, HostID,CashStart,HostCount,CurHostName); + status = nc_get_var1_int(TicketID, TimeID,CashStart,&CurTime); + + Comp=strcmp(CurHostName,hostname); + if((strcmp(DD_name,NONAME)) == 0) DD_user_id = DD_id; + + if((CurID == userID) && (Comp == 0) && (DD_id == DD_user_id)) + { + RefTime = CurTime; + CurCashStart[0]=CashStart[0]; + Find = 1; + } + + CashStart[0]++; + } + while((CurHostName[0] != '\0') && (CashStart[0] < USERCASHLEN)); + + if(Find == 1) + { + CashStart[0]=CurCashStart[0]; + status = nc_get_var1_int(TicketID, CurIDID, CashStart,&CurID); + status = nc_get_var1_int(TicketID, DD_id_ID, CashStart,&DD_id); + status = nc_get_vara_text(TicketID, HostID,CashStart,HostCount,CurHostName); + status = nc_get_var1_int(TicketID, TimeID,CashStart,&CurTime); + if((strcmp(DD_name,NONAME))==0) DD_user_id = (int)DD_id; + } + CashStart[0]--; + + Clock=(int)time(NULL); + + if(CurTime > Clock) Time_is = 1; + + if((Find == 1) && (Time_is == 1)) + { + fprintf(stderr,"User: ID = %d, DD_id = %d, host %s, timework=%d, is connected. \n",CurID,DD_user_id,hostname,Time_is); + ServerReply = 0; + } + else { + + fprintf(stderr,"User: ID = %d, DD_id = %d, host %s, timework=%d, Permission denied!. \n",CurID,DD_user_id,hostname,Time_is); + ServerReply=NOPERMISSION; + } + + nc_sync(TicketID); + nc_close(TicketID); + return ServerReply; +} + +/* + *------------------------ SETUSER -------------------------------*/ +/* + * Description: Library function for client-server using. + * Send ID, HostName to server. + * Compares the information with your {id,hostname}. + * Returns 1 if O'k, or a negative value in case + * of "NOPERMISSION". + * + */ +int SetUser(int UserID, char *HostName, char *LogName) +{ + + int SocketID = -1; /* Global socket id for this communication session */ + static DD_data_t dd = {DD_CHAR,0,NULL,0,NULL}; + static caddr_t buf = NULL; + static XDR xdrs; + int cc,i, hostlen, ticketlen, userlen; + int op = SHOWTICKETREQ; + int SHOW_ACCESS; + + SHOW_ACCESS = NOPERMISSION; + /* fprintf(stderr,"after CLIENT int SetUser: SocketID = %d\n",SocketID); + fprintf(stderr,"after CLIENT int SetUser: User = %d Host %s\n",UserID,HostName); + */ + +/*------------------CONNECTION to SERVER---------------------------*/ +/* + * If no connection, connect to server, try to order data set and return + * ID if OK or ErrorNumber if not + */ + + + /* fprintf(stderr,"Try to connect Server\n");*/ +/* If there is no connection, try to get it */ + if(SocketID < 0) + if((SocketID = GetSocket()) < 0) return(NOCONNECTION); + /* fprintf(stderr,"Server3 connected\n");*/ + + +/*---------------------REQUEST TO SERVER-----------------------------*/ + +/* Check the HostName length */ + if(strlen(HostName) > MAXHOSTLENGTH) hostlen = MAXHOSTLENGTH; + else hostlen = strlen(HostName); + if(strlen(LogName) > USRLENGTH) userlen = USRLENGTH; + else userlen = strlen(LogName); + +/* Allocation memory and stream */ + buf = (caddr_t)malloc(REQUESTLENGTH); + xdrmem_create(&xdrs, buf, REQUESTLENGTH, XDR_ENCODE); + +/* Encoding the request */ + xdr_int(&xdrs,&op); + xdr_int(&xdrs,&UserID); + xdr_string(&xdrs, &HostName, hostlen); + xdr_string(&xdrs, &LogName, userlen); +/* fprintf(stderr,"UserID, HostName just more : %d %s\n",UserID,HostName);*/ +/* Send request */ + if((cc = send(SocketID,buf,REQUESTLENGTH,0)) < 0) + { + perror("DD_GetTicket:"); + free(buf); + xdr_destroy(&xdrs); + return(REQSENDERR); + } + free(buf); + xdr_destroy(&xdrs); + +/* Get reply header */ + + buf = (caddr_t)malloc(REPLYLENGTH); + i =0; + while(((cc = recv(SocketID,buf,REPLYLENGTH,0)) < 0) && (i < TRY)) i++; + if(cc < 0) + { + perror("DD_SetUser:"); + free(buf); + return(REPLYRECERR); + } + + xdrmem_create(&xdrs, buf, REPLYLENGTH, XDR_DECODE); + xdr_int(&xdrs,&SHOW_ACCESS); + + free(buf); + xdr_destroy(&xdrs); + shutdown(SocketID,2); + close(SocketID); + /*SocketID = -1;*/ +/* fprintf(stderr,"SetUser,End; UserID, HostName just more : %d %s\n",UserID,HostName); + fprintf(stderr,"SHOW_ACCES %d \n",SHOW_ACCESS); +*/ + if(Verbose) fprintf(stderr,"SetUser: ACCES = %d \n",SHOW_ACCESS); + +return((int)SHOW_ACCESS); +} + +/*############################################################################*/ + +/*-------------------CHECK ID-----------------------*/ + +/* Description: This function check the user name in user_info.nc file. + * Returns DD_id if exists. + * Returns OK, or NOPERMISSION, or an ERROR + */ + +int CheckID(char *NameUsr) +{ + int i=0,Find=0; + int DD_id = NOPERMISSION; + + int UsrRefID; /* ID of NC file */ + char *ddbase; + char refname[PATHLENGTH]; + int UserDimID,UserLenDimID; /* Dimennsions ID */ + int MemID; /* Variable ID */ + size_t MaxRecords, UserLength; /* Dimensions */ + size_t start[2]= {0,0}; + size_t UserCount[2] = {1,0}; + char UserDimName[] = "user", UserLenDimName[] = "UserLength"; /* Dimensions names */ + char MemName[] = "member"; /* Variable name */ + char MemChar[USRLENGTH]; + int status; + +/*------------- Open User Reference file ---------------------------------*/ + if((ddbase = getenv("DDBASE")) == NULL) + { + if(Verbose) fprintf(stderr,"CHECKID: No DDBASE environment.\n"); + return(ENVIRERROR); + } + strcpy(refname,ddbase); + strcat(refname,USERREFNAME); + if(Verbose) fprintf(stderr," CHECKID: PATH is %s \n",refname); + + if((status = nc_open(refname, NC_WRITE,&UsrRefID)) != NC_NOERR) + { + if(Verbose) fprintf(stderr,"CHECKID: %s\n", nc_strerror(status)); + return(NOUSERSFILE); + } + +/*------------------ Define all dimensions -------------------------------*/ + + status = nc_inq_dimid(UsrRefID,UserDimName,&UserDimID); + status = nc_inq_dimlen(UsrRefID, UserDimID, &MaxRecords); + status = nc_inq_dimid(UsrRefID,UserLenDimName,&UserLenDimID); + status = nc_inq_dimlen(UsrRefID, UserLenDimID, &UserLength); + UserCount[1] = UserLength; + +/*fprintf(stderr,"CheckTicket:Rec: %d %d %d\n",MaxRecords,UserLength,PasswdLength);*/ + +/*------------------ Define all variables ID -------------------------------*/ + status = nc_inq_varid(UsrRefID, MemName,&MemID); + + while((i<MaxRecords) && (Find != 1)) + { + start[0]=i; + status = nc_get_vara_text(UsrRefID, MemID, start,UserCount,MemChar); + if(strcmp(MemChar,NameUsr)==0) {DD_id = i;Find=1;} + i++; + } + nc_close(UsrRefID); + return(DD_id); +} + +/*----------------Put into LOG file------------------------------------*/ + +/* Description: This function requires ID of local host, IP-address of +* local host and Login Name. +* +*/ + +void Put2Log(int UID, char *Host, char *LogName, int error) + { + FILE *log; + time_t Clock; + char *ddbase; + char refname[PATHLENGTH], right[]=" normal \0",noright[]="no permission\0"; + + if((ddbase = getenv("DDBASE")) == NULL) + { + fprintf(stderr,"No DDBASE info. Check your profile... \n"); + return; + } + strcpy(refname,ddbase); + strcat(refname,LOGFILE); + if(Verbose) fprintf(stderr,"LOG file: %s \n",refname); + if((log = fopen(refname, "a")) == NULL) + { + fprintf(stderr,"Error in opening log file. \n"); + return; + } + + Clock=time(NULL); + + if(error>=0) + fprintf(log,"%s\t%s\t%u %s\t%s",Host,LogName,UID,right,ctime(&Clock)); + else fprintf(log,"%s\t%s\t%u %s\t%s",Host,LogName,UID,noright,ctime(&Clock)); + + fclose(log); + + return; + } + +/*---------------------LOGINS----------------------------------*/ + +/* Description: This function uses by ddcheck */ +/* Compare two passwords */ + +int LOGINS(char *password) +{ + char salt[3],newkey[13]; + char pas[80]; + char PName[]="Administrator password: "; + int ACCESS_ = 0; + +/*--------------Password----------------------------*/ + + strncpy(salt,password,2); + salt[2]='\0'; + strcpy(pas,getpass(PName)); + pas[strlen(pas)] = '\0'; + strcpy(newkey,(char *)crypt(pas,salt)); + newkey[strlen(newkey)] = '\0'; + if(strcmp(newkey, password) == 0) ACCESS_=1; + + return ACCESS_; +} + +/*---------------------DDCHECK----------------------------------*/ + +/* Description: This function check user for dd administrator access to DD_System +* Require only dd password from you. +* Returns 0 if o'k or -1 in case of unaccessability. +* +*/ + +int ddcheck() +{ + int FL=1,coun,i; + char lines[256],ref[40]; + FILE *files; + +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + files=fopen("/etc/passwd","r"); + while(FL != 0) + { + if(fgets(lines, 255, files) != NULL) + { + coun=(strlen(lines)-strlen(strchr(lines,':'))); + strncpy(ref,lines,coun); + ref[(strlen(lines)-strlen(strchr(lines,':')))]='\0'; + if(strcmp(ref,"dd") == 0) + { + coun=(strlen(&(lines[0])+3)-strlen(strchr(&(lines[0])+3,':'))); + strncpy(ref,&lines[0]+3,coun); + ref[coun]='\0'; + i=LOGINS(ref); + } + + } + else FL=0; + } + fclose(files); + if(i == 0) return(-1); + return(0); +} +/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/ + + + + diff --git a/src/SERVER/DD_GetData.c b/src/SERVER/DD_GetData.c new file mode 100755 index 0000000..f06c055 --- /dev/null +++ b/src/SERVER/DD_GetData.c @@ -0,0 +1,1415 @@ +/*===================================================================== + * DD SYSTEM base package + * DD_Server library + * DD_GetData.c + * V. 6.1 + * author: Andrey Fedorov + * + * Last revision: + * May 19 1997: Version 1.0 + * 25 February 1999 by A.Grigoriev + * DD_GetData was updated. V.2.0 + * Methods of search in SetTime are changed. + * April 12, 2002: NETCDF lib is changed V.3.0 + * Oct 10, 2002 Communication prorocol is changed. V 4.0 + * Oct 24, 2002 New calculation of thremaximum record size V. 4.1 + * work with NC files is now in file ncfileop.c + * May 7, 2003 : V 4.2 Cash work improoved (ncfileop.c also) + * Jan 6, 2004: V 4.3 Error in ID closing is fixed + * Jan 21, 2004: V.4.4 Error in free memory fixed, + * Server can path several new files, and then return + * Aug 12, 2004: V.4.5 New verbatim in the CLOSEID + * Nov 18, 2004: V.4.6 Accomodation of new ncfileop.c + * Mar 15, 2007 V.4.7 Fixed cash bag + * Jul 10, 2007 V.5.0 According to Server protocol 4.5.1 + * If "times" has "NODATA" string as name of the file, return "NOTIME" + * New format of VI name (see DDGenProt.lyx) + * Aug 02, 2007 V.5.1 Add WAITEXTCALL flag and LOCK file to GetData routines + * Also global time limits + * Sep 20, 2007 V.5.2 Refrech time limits after database update, database update after Get_Data call + * Sep 23, 2007 V.5.3 Fedorov, New interface for SetTime() + * Sep 24, 2007 V.5.4 Fedorov, Get_Data return is changed + * Sep 25, 2007 V.5.5 Fedorov, Variable minimal gap + * Feb 22, 2008, V.5.6 SetTime bug corrected -> nc_get,,,(...StartID...) not VarL->StartID !!!! + * Mar 06, 2008, V.5.7 SetTime bug corrected -> + * May 03, 2008, V.5.8 GlobalTime limits + * May 06, 2008 V.5.9 Fedorov, Max Records number processing + * May 15, 2008 V.5.10 Fedorov, NoData interval processing. Just go to the next correct data interval. + * May 19, 2008 V.5.11 Fedorov, One record data interval. Time is interpreted as scalar + * May 21, 2008 V.5.12 Fedorov, No data processing + * Apr 11, 2009 V.5.13 Fedorov, Out of global limits + * Apr 13, 2009 V.5.20 Fedorov, Reset of the pointer is in a spectal function + * Apr 13, 2009 V.5.21 Fedorov, Set time between the last record and Stop time + * Dec 8, 2012 V.6.0 Fedorov, New call to get the data structure, New multiparam call + * Jan 11, 2013 V.6.1 Knizhnikova, Fedorov, SlobalStart check, If there is NOVAR, set the corresponding data constants to send the corresponding packet. + *=====================================================================*/ +#include <netcdf.h> +#include "DD.h" +#include "DD_comm.h" + +/*------------------ GLOBAL VARIABLES --------------------------*/ + +DD_Var_t **DD_Var ; /* Common for entire server session , all files */ +size_t MaxIDNumber; /* The size of DD_Var array. Defined when new DD_Server session starts*/ + +extern int Verbose; +extern LocalOrigSync(DD_Var_t *Local, DD_Var_t *Orig); + +/*#################################################################*/ +/*----------------------- OpenInstr -------------------------------*/ +/*#################################################################*/ +/* + * Open Virtual instrument by VInstrName and return ID. + * Make entry point of DD_Var table + * Fill General attributes fron the INFO file + */ +int OpenInstr(char *VInstrName) +{ + char refname[PATHLENGTH]; /* full name of the reference file */ + char *ddbase; /* Environment variable DDBASE (path to the DDBASE ROOT)*/ + char RInstrName[MAXSETLENGTH]; /* Requested virtual instrument name */ + int id; /* ID of open Virtual Instrument */ + int refID,nameID; /* ID of reference file and Var in */ + static size_t RefStart[2] = {0,0}; + static size_t RefCount[2] = {4,PATHLENGTH}; + static char RefVar[4][PATHLENGTH]; + int len, status; + char *VirInstrP; //Pointer to some part of virtual instrument + unsigned UT[7]; // Buffer array to decode global time + dd_tmstr_t *GTimeP; // Buffer structure to decode global time + + /** sleep(60); **/ + + if(Verbose) + { + fprintf(stderr,"OpenInstr(%s): begin\n",VInstrName); + } +/* Converting original name to the name in database */ + strcpy(RInstrName,VInstrName); + VirInstrP = (char *)RInstrName; + while((VirInstrP = strchr(VirInstrP,':')) != NULL) *VirInstrP = '_'; + +/* Is this name in DD_Var structure ? */ + for(id = 0; id < MaxIDNumber; id++) + { + if(DD_Var[id] != NULL) + if(strcmp(RInstrName, DD_Var[id]->InstrName) == 0) + { + if(Verbose) fprintf(stderr,"OpenInstr(%s): VI is already open with ID = %d\n",VInstrName,id); + return(id); + } + } + if(Verbose) fprintf(stderr,"OpenInstr(%s): No such VI in DD_Var array. Create New Entry.\n",VInstrName); + +/* Is the empty space in DD_Var table */ + id =0; + while((DD_Var[id] != NULL) && (id < MaxIDNumber)) id++; + if(id >= MaxIDNumber) + { + if(Verbose) fprintf(stderr,"OpenInstr(%s): No Room in DD_Var table\n",VInstrName); + return(TOOMANYREQ); /* No room */ + } +/** + if(Verbose) fprintf(stderr,"OpenInstr(%s): There is empty plase at %d\n",VInstrName,id); +**/ +/* Open reference NC file */ + if((ddbase = getenv("DDBASE")) == NULL) return(NOREFFILE); + strcpy(refname,ddbase); + strcat(refname,REFNAME); + + status = nc_open(refname, NC_NOWRITE|NC_SHARE,&refID); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"OpentInstr(%s): open file %s, message: %s\n",VInstrName,refname,nc_strerror(status)); + return(NOREFFILE); + } + + status = nc_inq_varid(refID,RInstrName,&nameID); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"OpentInstr(%s): read %s, message: %s\n",VInstrName,RInstrName, nc_strerror(status)); + return(NOVAR); + } + + status = nc_get_vara_text(refID,nameID,RefStart,RefCount,(char *)RefVar); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"OpentInstr(%s): %s\n",VInstrName,nc_strerror(status)); + return(NOVAR); + } + + len = strcspn(RefVar[1]," "); RefVar[1][len] = '\0'; + len = strcspn(RefVar[2]," "); RefVar[2][len] = '\0'; + len = strcspn(RefVar[0]," "); RefVar[0][len] = '\0'; + len = strcspn(RefVar[3]," "); RefVar[3][len] = '\0'; + status = nc_close(refID); + +/* Create VI holder*/ + DD_Var[id] = (DD_Var_t *)malloc(sizeof(DD_Var_t)); + +/* Init Values */ + strcpy(DD_Var[id]->InstrName,RInstrName); + DD_Var[id]->VarData = NULL; + DD_Var[id]->ParamSize = 0; + DD_Var[id]->AttrData.Dimensions = NULL; + DD_Var[id]->AttrData.Variables = NULL; + DD_Var[id]->ncID = -1; + DD_Var[id]->Maxnc_rec = 0; + strcpy(DD_Var[id]->path, RefVar[0]); + + /*----- Init control Flags ---------------*/ + DD_Var[id]->LastPacketFlag = OK; + DD_Var[id]->NewFile = 0; + DD_Var[id]->NewFileWasOpen = 0; +/* ---------------------------------------------------------------- + * Open and init "Times" file + * -----------------------------------------------------------------*/ + DD_Var[id]->VILocked = 0; + DD_Var[id]->tmID = -1; + strcpy(DD_Var[id]->TimesFileName,RefVar[1]); + if((status = UpdateTimeInfo(DD_Var[id])) < 0) return status; + +/* ---------------------------------------------------------------- + * Open "Info" file + * -----------------------------------------------------------------*/ +/* Attention: Constant information file open and close by request in GetAttribute() */ + strcpy(DD_Var[id]->AttrName,RefVar[2]); + DD_Var[id]->attrID = -1; + /* + * Important to make NULL all variables + */ + DD_Var[id]->AttrData.Dimensions = NULL; + DD_Var[id]->AttrData.Variables = NULL; +/** + if(Verbose) fprintf(stderr,"OpentInstr(%s): ID = %d, Atributes are resetted\n",VInstrName,id); +**/ +/* ---------------------------------------------------------------- + * Open "CACHE" file + * -----------------------------------------------------------------*/ + status = nc_open(RefVar[3],NC_WRITE|NC_SHARE,&(DD_Var[id]->Cash.ID)); /* Cach file */ + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"OpentInstr(): open cash %s, message:%s\n",RefVar[3], nc_strerror(status)); + return(CACHERR); + } + status = nc_inq_varid(DD_Var[id]->Cash.ID,"name",&(DD_Var[id]->Cash.nameID)); + status = nc_inq_varid(DD_Var[id]->Cash.ID,"time",&(DD_Var[id]->Cash.timeID)); + status = nc_inq_varid(DD_Var[id]->Cash.ID,"fopen",&(DD_Var[id]->Cash.fopenID)); + DD_Var[id]->CurrCushN = -1; + + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"OpentInstr(): %s\n",nc_strerror(status)); + return(CACHERR); + } +/** + if(Verbose) fprintf(stderr,"OpentInstr(%s): ID = %d, Cache is open\n",VInstrName,id); +**/ +/* ---------------------------------------------------------------- + * Read Global timing and minimal gap from INFO file + * -----------------------------------------------------------------*/ + if((status = GetAttribute(id, GLOBSTARTNAME)) < 0) DD_Var[id]->GlobalStart = 0.0; + else + { + sscanf((char *)((DD_Var[id]->AttrData).Variables[0]), ISOTIMEF, &UT[0],&UT[1],&UT[2],&UT[3],&UT[4],&UT[5],&UT[6]); + SetDouble(GTimeP = UT2double(UT)); + DD_Var[id]->GlobalStart = GTimeP->times; + } + if((status = GetAttribute(id, GLOBSTOPNAME)) < 0) DD_Var[id]->GlobalStop = 1.0e11; + else + { + sscanf((char *)((DD_Var[id]->AttrData).Variables[0]), ISOTIMEF, &UT[0],&UT[1],&UT[2],&UT[3],&UT[4],&UT[5],&UT[6]); + SetDouble(GTimeP = UT2double(UT)); + DD_Var[id]->GlobalStop = GTimeP->times; + } + if((status = GetAttribute(id, SAMPLNAME)) < 0) DD_Var[id]->MinGap = MINGAP; + else + { + DD_Var[id]->MinGap = *((double *)((DD_Var[id]->AttrData).Variables[0])) * 5.0; + if(DD_Var[id]->MinGap < MINGAP) DD_Var[id]->MinGap = MINGAP; + } +/* ---------------------------------------------------------------- + * Read External archiving info + * -----------------------------------------------------------------*/ + DD_Var[id]->ExtCallAllowed = 0; + if((status = GetAttribute(id, REMARCHNAME)) < 0) + { + if(Verbose) fprintf(stderr,"OpentInstr(%s):RemBase:GetAttribute(%s): %s\n", VInstrName,REMARCHNAME, nc_strerror(status)); + DD_Var[id]->ExtCallAllowed = 0; + DD_Var[id]->BaseName[0] = '\0'; + DD_Var[id]->RemSetID[0] = '\0'; + } + else + { + strcpy(DD_Var[id]->BaseName,(DD_Var[id]->AttrData).Variables[0]); + if((status = GetAttribute(id, REMINSTNAME)) < 0) + { + DD_Var[id]->ExtCallAllowed = 0; + if(Verbose) fprintf(stderr,"OpentInstr(%s):RemInstr: %s\n",VInstrName,nc_strerror(status)); + } + else + { + DD_Var[id]->ExtCallAllowed = 1; + strcpy(DD_Var[id]->RemSetID,(DD_Var[id]->AttrData).Variables[0]); + } + } + + if(Verbose) fprintf(stderr,"OpentInstr(%s): GStart: %f GStop: %f\n",VInstrName,DD_Var[id]->GlobalStart,DD_Var[id]->GlobalStop); + if(Verbose) fprintf(stderr,"OpentInstr(%s): RemBase: %s RemInstr: %s\n",VInstrName,DD_Var[id]->BaseName,DD_Var[id]->RemSetID); + + + if(Verbose) fprintf(stderr,"DD_GetData:OpentInstr: New ID = %d\n",id); + return(id); +} +/*-------------------------------------------------------------------------------*/ + +/*###########################################################*/ +/*------------------- CLOSEID -------------------------------*/ +/*###########################################################*/ +int CloseID(int ID) +/* + * Closes this ID and return number of IDs remained in use + */ + +{ + size_t CashStart[2] = {0L,0L}; + size_t CashCount[2] = {1L,MAXFILENAME}; + int status; + int i,il, count = 0; +/* Is this ID */ + if(Verbose) fprintf(stderr,"CloseID(%d)\n",ID); + if(ID >= MaxIDNumber) return(1); /* Everythig is OK */ + if(DD_Var[ID] != NULL) + { +/** + if(Verbose) fprintf(stderr,"CloseID(%d): ID exists, start termination\n",ID); +**/ +/*------ Close all netCDF files -----*/ + if(DD_Var[ID]->ncID >= 0) + { + status = nc_close(DD_Var[ID]->ncID); + DD_Var[ID]->ncID = -1; + /** + if(Verbose) fprintf(stderr,"CloseID(%d): Data File is closed\n",ID); + **/ + } + if(DD_Var[ID]->Cash.ID >= 0) + { + status = nc_close(DD_Var[ID]->Cash.ID); + DD_Var[ID]->Cash.ID = -1; + if(Verbose) + { + if(DD_Var[ID]->CurrCushN >= 0) + fprintf(stderr,"CloseID(%d): File %s, N %d closed\n",ID, &(DD_Var[ID]->Cash.names[DD_Var[ID]->CurrCushN][0]),DD_Var[ID]->CurrCushN); + else fprintf(stderr,"CloseID(%d): cash closed\n",ID); + } + } + if(DD_Var[ID]->attrID >= 0) + { + status = nc_close(DD_Var[ID]->attrID); + DD_Var[ID]->attrID = -1; + /** + if(Verbose) fprintf(stderr,"CloseID(%d): Info File is closed\n",ID); + **/ + } + if(DD_Var[ID]->tmID >= 0) + { + status = nc_close(DD_Var[ID]->tmID); + DD_Var[ID]->tmID = -1; + /** + if(Verbose) fprintf(stderr,"CloseID(%d): Times File is closed\n",ID); + **/ + } + +/*========================================================== + * FREE MEMORY Variable Data + *==========================================================*/ + for(il = 0; il < DD_Var[ID]->ParamSize; il++) + { + for(i = 0; i < DD_Var[ID]->VarData[il].VarNumber; i++) + { + if (Verbose) fprintf(stderr,"CloseID(%d): %d, ptr %p\n",ID,i,DD_Var[ID]->VarData[il].Variables[i]); + free(DD_Var[ID]->VarData[il].Variables[i]); + DD_Var[ID]->VarData[il].VarNumber = 0; + } + free(DD_Var[ID]->VarData[il].Dimensions); + } + if(DD_Var[ID]->ParamSize > 0) free(DD_Var[ID]->VarData); + +/** + if(Verbose) fprintf(stderr,"CloseID(%d): Free VarData\n",ID); +**/ + + if(DD_Var[ID]->AttrData.Variables != NULL) + { +/** + if (Verbose) + fprintf(stderr,"CloseID(%d): Free AttrData.Variables[0] = %p\n",ID,DD_Var[ID]->AttrData.Variables[0]); +**/ + if (DD_Var[ID]->AttrData.Variables[0] != NULL) + { + free(DD_Var[ID]->AttrData.Variables[0]); + DD_Var[ID]->AttrData.Variables[0] = NULL; + } + } + + free(DD_Var[ID]); + DD_Var[ID] = NULL; + if(Verbose) fprintf(stderr,"CloseID(%d): Free DD_Var\n",ID); + } + +/* Count determination */ + for(i = 0; i < MaxIDNumber; i++) if(DD_Var[i] != NULL) count++; + + return(count); +} + +/*###########################################################*/ +/*------------------ GETATTRIBUTE ---------------------------*/ +/*###########################################################*/ +int GetAttribute(int ID, char *VarName) +/* + * Get information variable by ID and variable + * name. Fill Variable structure + */ + +{ + int VarID; /* ID of requested Variable */ + static size_t DimArray[NC_MAX_DIMS]; + static int IntDimArray[NC_MAX_DIMS]; + static int DimIDArray[NC_MAX_DIMS]; + static size_t start[NC_MAX_DIMS]; + static void *CommonAttrPnt = NULL; /* Pointer to the Atributes for ALL ID's */ + static nc_type type; + size_t count = 1; + int i, status; + +/* Check the ID */ + if(DD_Var[ID] == NULL) return(NOID); + + if(Verbose) fprintf(stderr,"GetAttribute(%d): Name = %s\n",ID,VarName); + +/* Free memory for data */ + if(DD_Var[ID]->AttrData.Dimensions == NULL) + DD_Var[ID]->AttrData.Dimensions = (int *)IntDimArray; + + if(DD_Var[ID]->AttrData.Variables == NULL) + DD_Var[ID]->AttrData.Variables = &CommonAttrPnt; /* Static pointer -> Variables[0] */ + if(DD_Var[ID]->AttrData.Variables[0] != NULL) /* Only one variable exists (no time) */ + { +/**/ + if (Verbose) fprintf(stderr,"GetAttribute(%d):Free AttrData.Variables[0] = %p\n", ID,DD_Var[ID]->AttrData.Variables[0]); +/**/ + free(DD_Var[ID]->AttrData.Variables[0]); + DD_Var[ID]->AttrData.Variables[0] = NULL; + } + +/* Try to open constant information data */ + status = nc_open(DD_Var[ID]->AttrName,NC_NOWRITE,&(DD_Var[ID]->attrID)); /* Constant information */ + if(status!= NC_NOERR) + { + if(Verbose) fprintf(stderr,"GetAttribute(%d): %s\n",ID,nc_strerror(status)); + return(NOINFOFILE); + } +/* Get ID for queired variable. If not return */ + status = nc_inq_varid(DD_Var[ID]->attrID,VarName,&VarID); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"GetAttribute(%d): %s\n",ID,nc_strerror(status)); + return(NOVAR); + } + +/* Get invormation about queried variable */ + status = nc_inq_vartype(DD_Var[ID]->attrID,VarID,&type); /* Type of variable */ + status = nc_inq_varndims(DD_Var[ID]->attrID,VarID,&(DD_Var[ID]->AttrData.DimNumber)); /* Number of dimansions */ + status = nc_inq_vardimid(DD_Var[ID]->attrID,VarID,DimIDArray); /* Array of dimensions IDs */ + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"GETATTR: %s\n",nc_strerror(status)); + return(NOVAR); + } + + if(DD_Var[ID]->AttrData.DimNumber == 0) + { + DD_Var[ID]->AttrData.DimNumber = 1; + DimArray[0] = 1; + IntDimArray[0] = 1; + } + else + for(i = 0; i < DD_Var[ID]->AttrData.DimNumber; i++) + { + status = nc_inq_dimlen( DD_Var[ID]->attrID,DimIDArray[i],&(DimArray[i])); /* Dimensions values */ + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"GETATTR: %s\n",nc_strerror(status)); + return(NOVAR); + } + IntDimArray[i] = (int)DimArray[i]; + } + + +/* Define type of variable */ + switch(type) + { + case NC_DOUBLE: DD_Var[ID]->AttrData.type = DD_DOUBLE; break; + case NC_CHAR: DD_Var[ID]->AttrData.type = DD_CHAR; break; + case NC_FLOAT: DD_Var[ID]->AttrData.type = DD_FLOAT; break; + case NC_SHORT: DD_Var[ID]->AttrData.type = DD_SHORT; break; + case NC_INT: DD_Var[ID]->AttrData.type = DD_INT; + } + +/* Setting Dimensions attributes to get data */ + for(i = 0; i < DD_Var[ID]->AttrData.DimNumber; i++) count = count * DimArray[i]; + +/* Alocating memory for data */ + DD_Var[ID]->AttrData.Variables[0] = (void *)malloc(unixlen[DD_Var[ID]->AttrData.type]*count); + +/* + if (Verbose) + fprintf(stderr,"Malloc DD_Var[%d]->AttrData.Variables[0] = %p\n",ID,DD_Var[ID]->AttrData.Variables[0]); +*/ + + switch(type) + { + case NC_DOUBLE: status = nc_get_vara_double(DD_Var[ID]->attrID,VarID,start,DimArray,(double *)DD_Var[ID]->AttrData.Variables[0]); + if (status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"GETATTR: %s\n",nc_strerror(status)); + return(NOVAR); + } + break; + case NC_CHAR: status = nc_get_vara_text(DD_Var[ID]->attrID,VarID,start,DimArray,(char *)DD_Var[ID]->AttrData.Variables[0]); + if (status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"GETATTR: %s\n",nc_strerror(status)); + return(NOVAR); + } + break; + case NC_FLOAT: status = nc_get_vara_float(DD_Var[ID]->attrID,VarID,start,DimArray,(float *)DD_Var[ID]->AttrData.Variables[0]); + if (status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"GETATTR: %s\n",nc_strerror(status)); + return(NOVAR); + } + break; + case NC_SHORT: status = nc_get_vara_short(DD_Var[ID]->attrID,VarID,start,DimArray,(short *)DD_Var[ID]->AttrData.Variables[0]); + if (status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"GETATTR: %s\n",nc_strerror(status)); + return(NOVAR); + } + break; + case NC_INT: status = nc_get_vara_long(DD_Var[ID]->attrID,VarID,start,DimArray,(long *)DD_Var[ID]->AttrData.Variables[0]); + if (status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"GETATTR: %s\n",nc_strerror(status)); + return(NOVAR); + } + } + if(DD_Var[ID]->attrID >= 0) nc_close(DD_Var[ID]->attrID); + DD_Var[ID]->attrID = -1; + return(1); +} +/*--------------------------------------------------------------*/ + +/*############################################################## + *# GetMultiData() # +/*##############################################################*/ + int GetMultiData(int ID, int VarSize, char **VarNames, char *TimeInt, int BackFlag) +/* + * Create static DD_data_t variables array and return its pointer. + * After open a new file the function refreshes variable dimensions + * Data are returned by portions until end of requested interval. + * Return MOREDATA or OK, or error value. + * If requsted variable is "Time", then it converts into "double" form. + * The rool of this routine: DO NOT CALL SetNewFile if VI is locked, + * If VI have been locked and then have been releesed, Times has to be updated and + * SetTime has to be redone. + */ +{ + static int *VarID = NULL; /* IDs of requested Parameters of this VI */ + static char TimeStr[TIMELENGTH]; + static char TimeName[] = "Time"; + static int TimeID; + //static size_t DimArray[NC_MAX_DIMS]; + static size_t **DimArrayS = NULL; /* Several Dimensions arrays */ + size_t *DimArray; /* Local Dimension Array (for the specific parameter */ + static int DimIDArray[NC_MAX_DIMS]; + static nc_type type; + static size_t start[NC_MAX_DIMS]; + static size_t TimeCount[2] = {1,TIMELENGTH}; + static size_t TimeStart[2] = {0,0}; + static int Scalar = 0; /* indicator of scalar value */ + static int String = 0; /* indicator of single (not timed) string March 9 1997 */ + static int TimeTypeValue = 0; /* indicator of time type value */ + static size_t RecordSize; /* Size of one record in terms of variables of specified type */ + static size_t *PacketSize=NULL; /* Packets sizes of one record (of specified variable) */ + static size_t RecordNumber; /* Variable maximal number of records in one packet */ + int i,il; + int DimNumber; + int err2,status; + int CurrncID; + + /*------------------------------------------------------------- + * Following variables subsitute fields in DD_Var to save a time + *------------------------------------------------------------*/ + static DD_Var_t Local; + + /** sleep(60); **/ + /** if(Verbose) + { + for(il = 0; il < VarSize; il++) + fprintf(stderr,"GetMultiData(ID=%d), VarName=%s,Timeint=%s)\n",ID,VarNames[il],TimeInt); + fprintf(stderr,"GeMultitData(ID=%d) LastPacket: %d FileStatus: %d NewFile: %d NFWasOpen: %d\n",ID, + DD_Var[ID]->LastPacketFlag, + DD_Var[ID]->LastFileStatus, + DD_Var[ID]->NewFile, + DD_Var[ID]->NewFileWasOpen); + fprintf(stderr,"GetMultiData(ID=%d), DD_Var[ID]->VarData = %p\n",ID,DD_Var[ID]->VarData); + } + **/ + /* Check the ID and reset the variable number*/ + if(DD_Var[ID] == NULL) return(NOID); + //if(FirstFlag) { DD_Var[ID]->ParamSize = 0; FirstFlag = 0;} + + /* sleep(30); */ /* To give possibility to start gdb */ + + /*=================================================== + * Free data from the previous requests + * BUT the data dimensions are not removed YET + * Probably we have just fill new portion of the same data + *==================================================*/ + for(il = 0; il < DD_Var[ID]->ParamSize; il++) + { + for(i = 0; i < DD_Var[ID]->VarData[il].VarNumber; i++) + { + //if (Verbose) fprintf(stderr," FREE ID = %d, il = %d, i = %d ptr %p\n",ID,il,i,DD_Var[ID]->VarData[il].Variables[i]); + free(DD_Var[ID]->VarData[il].Variables[i]); + DD_Var[ID]->VarData[il].VarNumber = 0; + } + } + + /*============================================================================ + *###### Check if we need to refresh entire information about parameters ##### + *###### We have to renovate ALL if previous request been finished or ##### + *###### new file was open during previous entry ##### + *============================================================================*/ + if((DD_Var[ID]->LastPacketFlag == OK) || DD_Var[ID]->NewFile) // Request been finished or + // System was trying to open new file + { + if(DD_Var[ID]->ncID < 0) return NOPOINTER; /* Time has been not set */ + if(Verbose) fprintf(stderr,"GetMultiData(%d): Parameters Info should be updated\n", ID); + /** sleep(60); **/ + /*--------------------------------------------------------------------- + * Look if the LastFileStatus has an error + *--------------------------------------------------------------------*/ + switch(DD_Var[ID]->LastFileStatus) + { + case OK: break; /* Data file was open succesfully */ + case CACHTOOREC: /* There was no free place in the CACH */ + case TRYAGAIN: /* VI was blocked */ + case WAITEXTCALL: /* New data was requested at external database */ + if(Verbose) fprintf(stderr,"GetData(%d): There was WAITEXTCALL, I am trying again\n",ID); + /* We have to check if VI is unlocked */ + switch(IsTimesLocked(&Local)) + { + case NOLOCK: break; + case LOCKED: + if(Verbose) fprintf(stderr,"GetData(%d): Data base is still locked\n",ID); + DD_Var[ID]->VILocked = Local.VILocked; + return MOREDELAY; break; + case LOCKREMOVED: UpdateTimeInfo(&Local); + LocalOrigSync(&Local,DD_Var[ID]); + SetTime(&Local,Local.CDTime); /* Return to the original status */ + if(Verbose) fprintf(stderr,"GetData(%d):Lock Was removed, SetTime again",ID); + } + switch(DD_Var[ID]->LastFileStatus = SetNewFile(&Local,1)) /* Only LOCAL work in our case !*/ + { + case OK: break; /* New file is open, go on */ + case CACHTOOREC: /* There was no free place in the CACH */ + case TRYAGAIN: /* VI was blocked */ + case WAITEXTCALL: /* New data was requested */ + DD_Var[ID]->VILocked = Local.VILocked; /* Tell Original holder that it is locked */ + DD_Var[ID]->NewFile = 1; + DD_Var[ID]->NewFileWasOpen = 1; + DD_Var[ID]->LastPacketFlag = MOREDELAY; + if(Verbose) fprintf(stderr,"GetData(%d): We have to waite again: %d\n",ID,status); + return MOREDELAY; + break; + case OUTOFTIME: + if(Verbose) fprintf(stderr,"GetData(%d): OUTOFTIME while requested new file %d\n",ID,status); + DD_Var[ID]->LastFileStatus = OUTOFTIME; + DD_Var[ID]->LastPacketFlag = OK; /* Just to show that this request is completed */ + return DD_Var[ID]->LastFileStatus; + break; + default: + if(Verbose) fprintf(stderr,"GetData(%d): Unrecoverable error: %d\n",ID,status); + DD_Var[ID]->LastPacketFlag = OK; /* Just to show that this request is completed */ + return DD_Var[ID]->LastFileStatus; + } + break; + case OUTOFTIME: // Nothing to do with this request. New set time is needed + if(Verbose) fprintf(stderr,"GetData(%d): Previous call gave OUTOFTIME, return\n",ID); + return DD_Var[ID]->LastFileStatus; + break; + default: /* The error is unrecoverable */ + if(Verbose) fprintf(stderr,"GetData(%d): Unrecoverable error: %d\n",ID,status); + return DD_Var[ID]->LastFileStatus; + } + + /*----------------------------------------------------------------------------- + * Data file is open. It is time to refresh information about parameters + *----------------------------------------------------------------------------*/ + for(il = 0; il < DD_Var[ID]->ParamSize; il++) // Free existing dimensions + { + if(DD_Var[ID]->VarData[il].Dimensions != NULL) {free(DD_Var[ID]->VarData[il].Dimensions); DD_Var[ID]->VarData[il].Dimensions = NULL;} + if(DimArrayS[il] != NULL) {free(DimArrayS[il]); DimArrayS[il] = NULL;} + } + if(DD_Var[ID]->ParamSize > 0) + { + if(DD_Var[ID]->VarData != NULL) { free(DD_Var[ID]->VarData); DD_Var[ID]->VarData = NULL;} + free(VarID); + free(PacketSize); + free(DimArrayS); + } + DD_Var[ID]->ParamSize = (size_t)VarSize; + /*-------------------------------------------- + * Create a new holder according to the parameters number + *--------------------------------------------*/ + DD_Var[ID]->VarData = (DD_data_t *)malloc(sizeof(DD_data_t) * VarSize); + VarID = (int *)malloc(sizeof(int) * VarSize); + PacketSize = (size_t *)malloc(sizeof(size_t) * VarSize); + DimArrayS = (size_t **)malloc(sizeof(size_t *) * VarSize); + for(il = 0; il < DD_Var[ID]->ParamSize; il++) DimArrayS[il] = NULL; + + /*---------------------------------------------------- + * Decide which ncID we are using + *---------------------------------------------------*/ + if(DD_Var[ID]->NewFile == 1) CurrncID = Local.ncID; + else CurrncID = DD_Var[ID]->ncID; + + /*------------------------------------------------ + * Calculation what number of records + * of the maximaly sized variable we can transmit + *-----------------------------------------------*/ + RecordNumber = MaxRecord(CurrncID); + if(RecordNumber <= 0) + { + if(Verbose) fprintf(stderr,"GetMultiData(%d): Error in calculation of records number\n",ID); + return(INTSERERR); + } + + /*--------------------------------------------- + * Define time ID + *--------------------------------------------*/ + status = nc_inq_varid(CurrncID,TimeName,&TimeID); + /*------------------------------------------------------------------------------------------ + * Reseting VarNumber and create a new local data structure + * Also we need to set Time limit constants + *------------------------------------------------------------------------------------------*/ + if(DD_Var[ID]->LastPacketFlag == OK) /* Very new request, after SetTime() */ + { + TimeStart[0] = DD_Var[ID]->nc_rec; + status = nc_get_vara_text(DD_Var[ID]->ncID,TimeID,TimeStart,TimeCount,TimeStr); + DD_Var[ID]->CDTime = DD_Time2Double(TimeStr); /* Current time of record */ + DD_Var[ID]->SDTime = DD_Var[ID]->CDTime; /* Start time of record */ + DD_Var[ID]->FDTime = DD_Var[ID]->SDTime + DD_Time2Double(TimeInt); + } + + DD_Var[ID]->NewFile = 0; /* Forget that it was new file */ + + /*-------------------------------------------------- + * Get Dimensions and allocate memory for all + * requested parameters + *-------------------------------------------------*/ + for(il = 0; il < VarSize; il++) + { + DD_Var[ID]->VarData[il].VarNumber = 0; + status = nc_inq_varid(CurrncID,VarNames[il],&(VarID[il])); + if (status != NC_NOERR) + { + if(Verbose) + { + fprintf(stderr,"MultiData(%d): NCDF message: %s\n",ID,nc_strerror(status)); + fprintf(stderr,"MultiData(%d): Parameter %s not found\n",ID,VarNames[il]); + } + VarID[il] = NOVAR; /* NOVAR */ + } + /*-------------------------------------------------------- + * Get dimensions number and its type + *------------------------------------------------------*/ + if(VarID[il] != NOVAR) + { + DimArrayS[il] = (size_t *)malloc(sizeof(size_t) * NC_MAX_DIMS); + DimArray = DimArrayS[il]; // Just a local pointer + status = nc_inq_vartype(CurrncID,VarID[il],&type); + status = nc_inq_varndims(CurrncID,VarID[il],&DimNumber); + //if(Verbose) fprintf(stderr,"GetMultiData(%d): Dimensions(%d) number = %d\n",ID,il,DimNumber); + + status = nc_inq_vardimid(CurrncID,VarID[il],DimIDArray); + if(DimNumber == 0) + { + DD_Var[ID]->VarData[il].DimNumber = 1; + DimArray[1] = 1; + Scalar = 1; // For one parameter call only + } + else /* Filling the array of Dimensions */ + { + for(i = 0; i < DimNumber; i++) status = nc_inq_dimlen(CurrncID,DimIDArray[i],&(DimArray[i])); + } + + /*--------------- Several special trucks for single variables (without time) ---------*/ + if((DimArray[0]<2) && (DimIDArray[0] != 0)) Scalar = 1; /* If the first dimension is not TIME and lenrgth is 1 or 0 */ + if((type == NC_CHAR) && (DimNumber < 2)) String = 1; + if(String == 0) DimArray[0] = 1; else DimArray[1] = DimArray[0]; + if((String == 0) && (DimNumber == 1)) { DimArray[1] = 1; DimNumber = 2;} + if(DimNumber > 1) DD_Var[ID]->VarData[il].DimNumber = DimNumber -1; + else DD_Var[ID]->VarData[il].DimNumber = 1; + + /*---------------------------------------------------------- + * Create dimensions, and fill the dimensions array + *--------------------------------------------------------*/ + DD_Var[ID]->VarData[il].Dimensions = (int *)malloc(sizeof(int)*DimNumber); + for(i = 0; i < DD_Var[ID]->VarData[il].DimNumber; i++) + { + (DD_Var[ID]->VarData[il].Dimensions)[i] = (int)DimArray[i+1]; + //if(Verbose) fprintf(stderr,"GetMultiData(%d): Dimensions(%d): dim[%d] = %d\n",ID,il,i,(int)DimArray[i+1]); + } + + /*--------------------------------------------------------------------- + * Set Variable type + *-------------------------------------------------------------------*/ + switch(type) + { + case NC_DOUBLE: DD_Var[ID]->VarData[il].type = DD_DOUBLE; break; + case NC_CHAR: DD_Var[ID]->VarData[il].type = DD_CHAR; break; + case NC_FLOAT: DD_Var[ID]->VarData[il].type = DD_FLOAT; break; + case NC_SHORT: DD_Var[ID]->VarData[il].type = DD_SHORT; break; + case NC_INT: DD_Var[ID]->VarData[il].type = DD_INT; break; + case NC_BYTE: DD_Var[ID]->VarData[il].type = DD_CHAR; break; + default: DD_Var[ID]->VarData[il].type = DD_CHAR; + } + + /*------------------------------------------------------------------------- + * Calculate the corresponding record size, + * an allocate memory to fit the RecordNumber records + *------------------------------------------------------------------------*/ + RecordSize = 1; + for(i = 1; i < DimNumber; i++) + { + RecordSize = RecordSize * DimArray[i]; + start[i] = 0; + } + if(String == 1) RecordSize = DimArray[0]; /* March 9 1997 */ + PacketSize[il] = RecordSize*unixlen[DD_Var[ID]->VarData[il].type]; + + DD_Var[ID]->VarData[il].Variables = (void **)malloc(sizeof(void *) * RecordNumber); + /* + if (Verbose) + fprintf(stderr," Malloc: DD_Var[%d]->VarData[%d].Variables = %p\n",ID, il, DD_Var[ID]->VarData[il].Variables); + */ + } + else + { + DD_Var[ID]->VarData[il].type = NOVAR; /* To indicate absence of this variable */ + PacketSize[il] = 0; + DD_Var[ID]->VarData[il].DimNumber = 0; + DD_Var[ID]->VarData[il].VarNumber = 0; + PacketSize[il] = 0; + } + } /* FOR il */ + + /*------------------------------------------- + * Create a Local structure + *------------------------------------------- */ + if(DD_Var[ID]->LastPacketFlag == OK) /* Very new request, after SetTime() */ + { + memcpy((void *)&Local, (void *)DD_Var[ID], sizeof(DD_Var_t)); /*--- Local structure if it is new request */ + //if(Verbose) fprintf(stderr,"GetData(%d): DD_Var[ID] -> Local\n",ID); + } + if(Verbose) fprintf(stderr,"GetMultiData(ID=%d), Created Local, DD_Var[ID]->VarData = %p\n",ID,DD_Var[ID]->VarData); + } + /*#######################################################################*/ + /* End of refresh information about variable in case of new file + * or new request */ + /*#######################################################################*/ + + /*================================================================= + * GET DATA + *=================================================================*/ + if ((Scalar == 1) || (String == 1)) DD_Var[ID]->LastPacketFlag = OK; + else DD_Var[ID]->LastPacketFlag = MOREDATA; + + /*=========================================================== + * The loop to get data until time or file finish + *===========================================================*/ + do + { + /*---------------------------------------- + * Get memory for each variable + *-----------------------------------------*/ + for(il = 0; il < VarSize; il++) + { + if( DD_Var[ID]->VarData[il].type >= 0) + { + DD_Var[ID]->VarData[il].Variables[DD_Var[ID]->VarData[il].VarNumber] = (void *)malloc(PacketSize[il]); + /* + if (Verbose) + fprintf(stderr,"Malloc: DD_Var[%d]->VarData[%d].Variables[%d] = %p, Size = %d\n",ID, il, + DD_Var[ID]->VarData[il].VarNumber, + DD_Var[ID]->VarData[il].Variables[DD_Var[ID]->VarData[il].VarNumber], + PacketSize[il]); + */ + } + } + if((Scalar == 1) || (String == 1)) + { + start[0] = 0; + } + else /* Setup start and looking for a time limit */ + { + + /*---------- Define START from LOCAL struct and read current Time ----------*/ + start[0] = Local.nc_rec; + TimeStart[0] = Local.nc_rec; + status = nc_get_vara_text(Local.ncID,TimeID,TimeStart,TimeCount,TimeStr); + Local.CDTime = DD_Time2Double(TimeStr); /* Current time of record */ + //fprintf(stderr,"GetData(%d): Start %f Current %f Stop %f\n",ID,Local.SDTime,Local.CDTime,Local.FDTime); + + //-------------- Check if we have to return by time -------------- + if(Local.CDTime > Local.FDTime) /* Return by time. All problem will path to the next GetData */ + { + /* If new file was open we have to return to original file */ + if(Verbose) fprintf(stderr,"GetData(%d): Stop By Time\n",ID); + SetOriginPointer(&Local, ID); + /*------- Free reserved for nothing last array -------------*/ + for(il = 0; il < VarSize; il++) + { + if(DD_Var[ID]->VarData[il].type >= 0) + { + free(DD_Var[ID]->VarData[il].Variables[DD_Var[ID]->VarData[il].VarNumber]); + /* + if (Verbose) + fprintf(stderr,"Free: DD_Var[%d]->VarData[%d].Variables[%d], Pntr %p\n",ID, il, DD_Var[ID]->VarData[il].VarNumber, DD_Var[ID]->VarData[il].Variables[DD_Var[ID]->VarData[il].VarNumber]); + */ + } + } + return OK; + } //--------- End return by time --------------- + } + + /*------------------------------------------------------- + * Get Data according to its type + *-------------------------------------------------------*/ + for(il = 0; il < VarSize; il++) + { + if( DD_Var[ID]->VarData[il].type >= 0) + { + DimArray = DimArrayS[il]; + /* + if(Verbose) + { + for (i = 0; i < DD_Var[ID]->VarData[il].DimNumber+1; i++) + fprintf(stderr,"GetMultiData(%d): Variable[%d], Dimension[%d] DimSize = %d\n", ID, il, i,DimArray[i]); + fprintf(stderr,"VarID[%d] = %d, type = %d\n",il, VarID[il],DD_Var[ID]->VarData[il].type); + } + */ + switch(DD_Var[ID]->VarData[il].type) + { + case DD_DOUBLE: status = nc_get_vara_double(Local.ncID, VarID[il], start, DimArray, + (double *)DD_Var[ID]->VarData[il].Variables[DD_Var[ID]->VarData[il].VarNumber]); + break; + case DD_INT: status = nc_get_vara_int(Local.ncID, VarID[il], start, DimArray, + (int *)DD_Var[ID]->VarData[il].Variables[DD_Var[ID]->VarData[il].VarNumber]); + break; + case DD_FLOAT: status = nc_get_vara_float(Local.ncID, VarID[il], start, DimArray, + (float *)DD_Var[ID]->VarData[il].Variables[DD_Var[ID]->VarData[il].VarNumber]); + // if(Verbose) fprintf(stderr,"(Variable[%d])[0] = %f\n",il,((float *)DD_Var[ID]->VarData[il].Variables[DD_Var[ID]->VarData[il].VarNumber])[0]); + break; + case DD_SHORT: status = nc_get_vara_short(Local.ncID, VarID[il], start, DimArray, + (short *)DD_Var[ID]->VarData[il].Variables[DD_Var[ID]->VarData[il].VarNumber]); + break; + case DD_CHAR: status = nc_get_vara_text(Local.ncID, VarID[il], start, DimArray, + (char *)DD_Var[ID]->VarData[il].Variables[DD_Var[ID]->VarData[il].VarNumber]); + } /* End of switch */ + DD_Var[ID]->VarData[il].VarNumber++; + } /* if not NOVAR */ + } /* for il */ + /*------ Return immediately if it is just one record ------------*/ + if ((Scalar == 1) || (String == 1)) return OK; + + /*---- Now we have to decide if we opVarNamesen a new file to continue ------------*/ + if(DD_Var[ID]->LastPacketFlag == MOREDATA) /* Timed variable (no scalar) */ + { + Local.nc_rec++; + + /*====================================================================== + * The next procedure runs if the current file is finished and we have + * to open a new file (or look for external data source + *=====================================================================*/ + if(Local.nc_rec > Local.Maxnc_rec - 1) + { + if(Verbose) fprintf(stderr,"GetData(%d): Stop By EOF\n",ID); + /* Before open new file we have to check the LOCK status */ + switch(IsTimesLocked(&Local)) + { + case NOLOCK: break; + case LOCKED: DD_Var[ID]->LastFileStatus = TRYAGAIN; + DD_Var[ID]->VILocked = Local.VILocked; /* Tell Original holder that it is locked */ + DD_Var[ID]->NewFile = 1; + DD_Var[ID]->NewFileWasOpen = 1; + return MOREDELAY; break; + case LOCKREMOVED: UpdateTimeInfo(&Local); + LocalOrigSync(&Local,DD_Var[ID]); + SetTime(&Local,Local.CDTime); /* Return to the original status */ + } + switch(DD_Var[ID]->LastFileStatus = SetNewFile(&Local,1)) + { + case OK: // Everything is OK + DD_Var[ID]->LastPacketFlag = MOREDATA; + DD_Var[ID]->NewFile = 1; // We have to reset all variables + DD_Var[ID]->NewFileWasOpen = 1; + if(Verbose) fprintf(stderr,"GetMultiData(ID=%d), Retun by EOF, MOREDATA, DD_Var[ID]->VarData = %p\n",ID,DD_Var[ID]->VarData); + return MOREDATA; + case TRYAGAIN: // just wait and try again + if(Verbose) fprintf(stderr,"GetData(%d): Open New File return TRYAGAIN\n",ID); + DD_Var[ID]->NewFile = 1; + DD_Var[ID]->NewFileWasOpen = 1; + DD_Var[ID]->LastPacketFlag = MOREDELAY; + DD_Var[ID]->VILocked = Local.VILocked; /* Tell Original holder that it is locked */ + return MOREDELAY; + case WAITEXTCALL: // just wait and try again + if(Verbose) fprintf(stderr,"GetData(%d): Open New File returned WAITEXTCALL\n",ID); + DD_Var[ID]->VILocked = Local.VILocked; /* Tell Original holder that it is locked */ + DD_Var[ID]->NewFile = 1; + DD_Var[ID]->NewFileWasOpen = 1; + DD_Var[ID]->LastPacketFlag = MOREDELAY; + return MOREDELAY; + case CACHTOOREC: // just wait and try again + if(Verbose) fprintf(stderr,"GetData(%d): Open New File returned CACHTOOREC\n",ID); + DD_Var[ID]->NewFile = 1; + DD_Var[ID]->NewFileWasOpen = 1; + DD_Var[ID]->LastPacketFlag = MOREDELAY; + return MOREDELAY; + case OUTOFTIME: // Return data as the last packet (as well as it was finished by time + if(Verbose) fprintf(stderr,"GetData(%d): New file is out of time\n",ID); + SetOriginPointer(&Local, ID); + DD_Var[ID]->LastPacketFlag = OK; + DD_Var[ID]->NewFile = 1; + return OK; + break; + default: // Unrecoverable error in the database or out of time + if(Verbose) fprintf(stderr,"GetData(%d): Unrecoverable error in the new file\n",ID); + Local.nc_rec--; + DD_Var[ID]->LastPacketFlag = OK; + DD_Var[ID]->NewFile = 0; + return DD_Var[ID]->LastFileStatus; + } + } /* End of file finish processing */ + + if(DD_Var[ID]->VarData[0].VarNumber >= RecordNumber) /* Packet size exceeded */ + { + DD_Var[ID]->LastPacketFlag = MOREDATA; + return MOREDATA; + } + } /* End of check of status */ + } while(1); + + return OK; +} +/*-----------------------------------------------------------------*/ + +/*################################################################# + * SET TIME + * Set time and try to open appropriate data file. If not try to + * call external archive + * Return: + * NOID - call with uncorrect VI holder + * OUTOFTIME - Requested time is out of General time limitation + * WAITEXTCALL - Server sent request to external archive + * TRYAGAIN - VI is blocked by call to external database + * NODATAATTIME - request time is inside NODATA time interval + * some return of SetNewFile(); see ... + *#################################################################*/ + +int SetTime(DD_Var_t *DD_VarL, double VCTime) +{ + char Name[MAXSETLENGTH]; /* Name of data nc file */ + char FullName[PATHLENGTH]; /* Full name of nc file */ + char StartTime[TIMELENGTH]; + char StopTime[TIMELENGTH]; + static char StartName[] = "StartTime"; + static char StopName[] = "StopTime"; + static char TimeName[] = "Time"; + int StartID,StopID,TimeID; + size_t Rmin,Rmax,RLeft,RRight; /* Limits of record num */ + double dt, TestTime,MinTime,MaxTime; + dd_tmstr_t *tt; + int More; /* InsideFlag - we are inside good time interval */ + /* NoDataFlag - we in the time record marked "NODATA" */ + char TimeIntName[MAXSETLENGTH]; /* File name associated with the given time interval */ + + static size_t start[2] = {0,0}; + static size_t TimeCount[2] = {1,TIMELENGTH}; + static size_t FileCount[2] = {1,MAXFILENAME}; + static void *p; + static double CTime = 0.0; /* Real working requested time */ + int status; + int SearchStatus; /* Status at the end of interval search */ + int ExternalReqStatus; /* Status at return of extenal call */ + +/* Check the ID */ +/** sleep(40); **/ + + if(Verbose) fprintf(stderr,"SetTime(%f): Start\n",VCTime); + if(DD_VarL == NULL) return(NOID); + +/*=========================================================== + * Set CTime if need + *===========================================================*/ + if(VCTime > 0) + { + CTime = VCTime; + if(Verbose) fprintf(stderr,"SetTime(%f): CTime is from argument\n",CTime); + } + else if(Verbose) fprintf(stderr,"SetTime(%f): CTime is from saved value\n",CTime); + +/*---------------------------------------------------- + * Check if is out of Global Time Limits + * If the requested time is out of Global Time Limit, the time is reset to the + * correct time interval + *----------------------------------------------------*/ + if (CTime <= DD_VarL->GlobalStart) CTime = DD_VarL->GlobalStart + QUANTOFFSET; + if (CTime > DD_VarL->GlobalStop) return OUTOFTIME; + +/* + * Check if this VI is not blocked by this or another server + */ + switch(IsTimesLocked(DD_VarL)) + { + case NOLOCK: break; + case LOCKED: return TRYAGAIN; break; + case LOCKREMOVED: UpdateTimeInfo(DD_VarL); + } + +/* + * If Ctime out of valid interval, we can try to get new data in external archive + */ + if((DD_VarL->MinValidTime > CTime)||(DD_VarL->MaxValidTime < CTime)) + { + if(Verbose) fprintf(stderr,"SetTime(): Start Time is out of current data interval\n"); + if(DD_VarL->ExtCallAllowed) + { + switch(ExternalReqStatus = ExtDataRequest(DD_VarL,CTime)) + { + case OK: return WAITEXTCALL; /* Request is gone */ + case NOEXEC: break; /* Call is impossible */ + case NODATAATTIME: return NODATAATTIME; /* CTime in side NODATA interval */ + case GAPISSMALL: break; /* Out of data, but gap is too small */ + case OUTOFTIME: return OUTOFTIME; + default: return OUTOFTIME; + } + } else return OUTOFTIME; + } + +/* + * Now we know that CTime SURE in between Tmin and TMax + * We start from the middle of the maximal valid interval + */ + Rmin = (size_t)DD_VarL->RValidMin; + Rmax = (size_t)DD_VarL->RValidMax; + More = 1; + while(More) + { + DD_VarL->TimeRecNumber = (Rmin + Rmax)/2; + SearchRight(DD_VarL,Rmin,Rmax); /*--- Go right up to valid interval */ + start[0] = DD_VarL->TimeRecNumber; + status = nc_get_vara_text(DD_VarL->tmID, DD_VarL->StartID,start,TimeCount,StartTime); + TestTime = DD_Time2Double(StartTime); + + if(CTime > TestTime) // StartTime(R) < CTime + { + status = nc_get_vara_text(DD_VarL->tmID, DD_VarL->StopID,start,TimeCount,StopTime); + TestTime = DD_Time2Double(StopTime); + if(TestTime >= CTime) /* CTime is really inside this interval */ + { + More = 0; + SearchStatus = INSIDE; + } + else /* CTime is at the right of the R */ + { + RLeft = DD_VarL->TimeRecNumber; + DD_VarL->TimeRecNumber++; + SearchRight(DD_VarL,Rmin,Rmax); /*R shift right up to the next valid interval */ + start[0] = DD_VarL->TimeRecNumber; + status = nc_get_vara_text(DD_VarL->tmID, DD_VarL->StopID,start,TimeCount,StopTime); + TestTime = DD_Time2Double(StopTime); + if(TestTime >= CTime) /* CTime is between Stop(R)-1 and Stop(R) */ + { + More = 0; + DD_VarL->CurrRmin = (int)RLeft; + DD_VarL->CurrRmax = (int)DD_VarL->TimeRecNumber; + /*--- Test if it is inside interval ------*/ + status = nc_get_vara_text(DD_VarL->tmID, DD_VarL->StartID,start,TimeCount,StartTime); + TestTime = DD_Time2Double(StartTime); + if(TestTime < CTime) SearchStatus = INSIDE; + else SearchStatus = DATAATRIGHT; /* Ctime is inbetween the valid intervals */ + } + else /* CTime is on the right from the Stop(R) */ + { + Rmin = DD_VarL->TimeRecNumber; + More = 1; + } + } /* else of CTime is at the right of the R */ + } + else /* StartTime(R) > CTime */ + { + RRight = DD_VarL->TimeRecNumber; + DD_VarL->TimeRecNumber--; + SearchLeft(DD_VarL,Rmin,Rmax); /*R shift left down to the next valid interval */ + start[0] = DD_VarL->TimeRecNumber; + status = nc_get_vara_text(DD_VarL->tmID, DD_VarL->StartID,start,TimeCount,StartTime); + TestTime = DD_Time2Double(StartTime); + if(CTime > TestTime) // CTime is inbetween Start(R) and Start(RRight) + { + More = 0; + DD_VarL->CurrRmax = (int)RRight; + DD_VarL->CurrRmin = (int)DD_VarL->TimeRecNumber; + /*--- Test if it is inside interval ------*/ + status = nc_get_vara_text(DD_VarL->tmID, DD_VarL->StopID,start,TimeCount,StopTime); + TestTime = DD_Time2Double(StopTime); + if(TestTime > CTime) SearchStatus = INSIDE; + else /* Ctime is inbetween the valid intervals */ + { + DD_VarL->TimeRecNumber++; /* Return to the right interval */ + SearchStatus = DATAATRIGHT; /* Ctime is inbetween the valid intervals */ + } + } + else /* CTime is to the left from Start(R) */ + { + Rmax = DD_VarL->TimeRecNumber; + More =1; + } + } // else StartTime(R) > CTime + } // while(More); +/*------------------------------------------------------------------------------*/ + if(Verbose) fprintf(stderr,"SetTime(): Search Status is %d\n",SearchStatus); + +/*----------------------------------------------------------------------- + * Now we check if we can and need to require new data in external archive + *-----------------------------------------------------------------------*/ + if((SearchStatus != INSIDE)&&(DD_VarL->ExtCallAllowed)) + { + switch(ExternalReqStatus = ExtDataRequest(DD_VarL,CTime)) + { + case OK: return WAITEXTCALL; /* Request is gone */ + case NOEXEC: return NODATAATTIME; /* Call is impossible */ + case NODATAATTIME: + start[0] = DD_VarL->TimeRecNumber; + status = nc_get_vara_text(DD_VarL->tmID, DD_VarL->StopID,start,TimeCount,StopTime); + CTime = DD_Time2Double(StopTime) + 0.001; + if(Verbose) fprintf(stderr,"SetTime(): There was NO Data intreval, CTime is scrolled to %f\n",CTime); + return CTIMEISSHIFTED; + case GAPISSMALL: DD_VarL->TimeRecNumber = DD_VarL->CurrRmax; break; /* Out of data, but gap is too small */ + case OUTOFTIME: return OUTOFTIME; break; + default: return OUTOFTIME; + } + } + +/* Get the file Name and open file */ + if(Verbose) fprintf(stderr,"SetTime(): File found: %d\n",DD_VarL->TimeRecNumber); + if((status = SetNewFile(DD_VarL,0)) < 0) return status; + +/*===================================================================== + * Fit the CTime inside data file + *=====================================================================*/ +/* Get MinTime and MaxTime */ + status = nc_inq_varid(DD_VarL->ncID,StartName, &StartID); + status = nc_inq_varid(DD_VarL->ncID,StopName, &StopID); + status = nc_inq_varid(DD_VarL->ncID,TimeName, &TimeID); + + if (status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"SetTime(): %s\n",nc_strerror(status)); + return(DATAFILEERR); + } + + start[0] = 0; + + + status = nc_get_vara_text(DD_VarL->ncID, StartID, start,&TimeCount[1],StartTime); + MinTime = DD_Time2Double(StartTime); + status = nc_get_vara_text(DD_VarL->ncID, StopID, start,&TimeCount[1],StopTime); + MaxTime = DD_Time2Double(StopTime); + + +/* circle of finding of time */ + More = 1; + Rmin = 0; Rmax = DD_VarL->Maxnc_rec - 1; + + do + { + start[0] = (Rmin + Rmax)/2; + if(start[0] < Rmin) { DD_VarL->nc_rec = Rmin; More = 0;} + if(start[0] > Rmax) { DD_VarL->nc_rec = Rmax; More = 0;} + if(More > 0) + { + status = nc_get_vara_text(DD_VarL->ncID, TimeID,start,TimeCount,StartTime); + TestTime = DD_Time2Double(StartTime); + + if(CTime >= TestTime) + { +// if(start[0] +1 >= DD_VarL->Maxnc_rec) return(OUTOFTIME); + if(start[0] +1 >= DD_VarL->Maxnc_rec) // We are in the gap between the last record + // and the StopTime of this file + { + if(Verbose) fprintf(stderr,"SetTime(): The gap between the last record and stop time\n"); + if((status = SetNewFile(DD_VarL,1)) < 0) return status; + DD_VarL->nc_rec = 0; + More = 0; + if(Verbose) fprintf(stderr,"SetTime(): Pointer is set as %s, TimesRecord %d FileRecord %d\n",StartTime,DD_VarL->TimeRecNumber, DD_VarL->nc_rec); + return 1; + } + start[0]++; + status = nc_get_vara_text(DD_VarL->ncID, TimeID,start,TimeCount,StartTime); + TestTime = DD_Time2Double(StartTime); + if(CTime <= TestTime) + { + DD_VarL->nc_rec = start[0]; + More = 0; + } + else + { + MinTime = TestTime; + Rmin = start[0]; + More = 1; + } + } + else + { + if(start[0] <= Rmin) /* 25 Feb 1999 */ + { + DD_VarL->nc_rec = Rmin; + More = 0; + } + else + { + start[0]--; + status = nc_get_vara_text(DD_VarL->ncID, TimeID,start,TimeCount,StartTime); + TestTime = DD_Time2Double(StartTime); + if(CTime >= TestTime) + { + DD_VarL->nc_rec = start[0] +1; + More = 0; + } + else + { + MaxTime = TestTime; + Rmax = start[0]; + More = 1; + } + } + } + } + if(MaxTime - MinTime < 0.0001) + { + DD_VarL->nc_rec = start[0]; + More = 0; + } + } while(More == 1); + if(Verbose) fprintf(stderr,"SetTime(): Pointer is set as %s, TimesRecord %d FileRecord %d\n",StartTime,DD_VarL->TimeRecNumber, DD_VarL->nc_rec); + + return(1); +} +/*======================================================================================*/ + +/*--------------------------------------------------------------------------------------*/ +/* If There was TimeUpdate in one VI, vi have to update all other values in another VI */ +/*--------------------------------------------------------------------------------------*/ +int LocalOrigSync(DD_Var_t *Local, DD_Var_t *Orig) +{ + Orig->tmID = Local->tmID; + Orig->NameID = Local->NameID; + Orig->StartID = Local->StartID; + Orig->StopID = Local->StopID; + Orig->RValidMin = Local->RValidMin; + Orig->RValidMax = Local->RValidMax; + Orig->MinValidTime = Local->MinValidTime; + Orig->MaxValidTime = Local->MaxValidTime; + Orig->CurrRmin = -1; + Orig->CurrRmax = -1; + Orig->VILocked = Local->VILocked; + return 1; +} + +/*--------------------------------------------------------------------------------------*/ +/* Recovering of the original pointer */ +/*--------------------------------------------------------------------------------------*/ +int SetOriginPointer(DD_Var_t *LocalVI, int ID) +{ + if(DD_Var[ID]->NewFileWasOpen) + { + switch(IsTimesLocked(LocalVI)) + { + case NOLOCK: break; + case LOCKED: DD_Var[ID]->LastFileStatus = TRYAGAIN; + DD_Var[ID]->LastPacketFlag = MOREDELAY; + DD_Var[ID]->VILocked = LocalVI->VILocked; /* Tell Original holder that it is locked */ + DD_Var[ID]->NewFile = 0; + DD_Var[ID]->NewFileWasOpen = 1; + return MOREDELAY; break; + case LOCKREMOVED: UpdateTimeInfo(LocalVI); + LocalOrigSync(LocalVI,DD_Var[ID]); + SetTime(DD_Var[ID],DD_Var[ID]->SDTime); /* Return to the original status */ + DD_Var[ID]->LastPacketFlag = OK; + DD_Var[ID]->NewFileWasOpen = 0; + DD_Var[ID]->NewFile = 0; + DD_Var[ID]->LastFileStatus = OK; /* Total reset */ + return OK; + } + /* If VI is not locked, try to set new file */ + switch(DD_Var[ID]->LastFileStatus = SetNewFile(DD_Var[ID],0)) + { + case OK: // Everything is OK + DD_Var[ID]->LastPacketFlag = OK; + DD_Var[ID]->NewFile = 0; // We have to reset all variables + DD_Var[ID]->NewFileWasOpen = 0; + return OK; + case TRYAGAIN: // just wait and try again + if(Verbose) fprintf(stderr,"GetData(%d): Reset to Origin return TRYAGAIN\n",ID); + DD_Var[ID]->NewFile = 0; + DD_Var[ID]->NewFileWasOpen = 1; + DD_Var[ID]->LastPacketFlag = MOREDELAY; + DD_Var[ID]->VILocked = LocalVI->VILocked; /* Tell Original holder that it is locked */ + return MOREDELAY; + case WAITEXTCALL: // just wait and try again + if(Verbose) fprintf(stderr,"GetData(%d): Reset to Origin return WAITEXTCALL\n",ID); + DD_Var[ID]->VILocked = LocalVI->VILocked; /* Tell Original holder that it is locked */ + DD_Var[ID]->NewFile = 0; + DD_Var[ID]->NewFileWasOpen = 1; + DD_Var[ID]->LastPacketFlag = MOREDELAY; + return MOREDELAY; + case CACHTOOREC: // just wait and try again + if(Verbose) fprintf(stderr,"GetData(%d): Reset to Origin returnCACHTOOREC\n",ID); + DD_Var[ID]->NewFile = 0; + DD_Var[ID]->NewFileWasOpen = 1; + DD_Var[ID]->LastPacketFlag = MOREDELAY; + return MOREDELAY; + case OUTOFTIME: // An accident when we were trying to return to original file + default: // Unrecoverable error in the database or out of time + if(Verbose) fprintf(stderr,"GetData(%d): Reset to origin: Unrecovararable errorn (including OUT OF TIME)\n",ID); + DD_Var[ID]->LastPacketFlag = OK; + DD_Var[ID]->NewFile = 0; + DD_Var[ID]->NewFileWasOpen = 1; + return DD_Var[ID]->LastFileStatus; + } + } + /* If we did not transfer to new file, we can just reset all */ + DD_Var[ID]->VILocked = LocalVI->VILocked; /* Tell Original the locking state */ + DD_Var[ID]->LastPacketFlag = OK; + DD_Var[ID]->NewFileWasOpen = 0; + DD_Var[ID]->NewFile = 0; + DD_Var[ID]->LastFileStatus = OK; + +} +/*######################################################################################*/ diff --git a/src/SERVER/DD_Server.c b/src/SERVER/DD_Server.c new file mode 100644 index 0000000..5da9054 --- /dev/null +++ b/src/SERVER/DD_Server.c @@ -0,0 +1,701 @@ +/*============================================================== + * DD SYSTEM + * DD_Server.c + * V. 6.0 + * + * Description: + * + * See ../DOC/TECHDOC/DDServFunct.html for complete information + * + * List of revisions: + * September, 1995 - Fedorov, First realisation: V 1.0 + * Oct 1997 - Fedorov, Acces security V 3.0 + * Sep 4, 2002 - Fedorov, Some changes V 3.5 + * Oct 28, 2002 - Fedorov, Communication ideology is changed V 4.1 + * May 1, 2003 - Fedorov, The buffered send is added V.4.2 + * Jul 16, 2004 - Fedorov, Check the buffer state V.4.3 + * March 15, 2007 - Fedorov, V.5.0 Bug in cach, Fedorov + * March 24, 2007 - Fedorov, V.5.2 Bug in free memory + * Jun 17, 2007 - Fedorov, V.5.5 Create new VI and Fill data via external calls + * Jun 20, 2007 - Fedorov, V.5.51 Adjust to createVI**.php + * Sep 23, 2007 - Fedorov, V.5.6 SetTime has another interface + * Sep 24, 2007 - Fedorov, V.5.6 New Get_Data processing + * May 21, 2008 - Fedorov, V.5.7 Try SetTime several times + * Apr 12, 2009 - Fedorov, V.5.8 Correct procession of OUTOFTIME + * Nov 18, 2012 - Fedorov, V.6.0 New call to get the variable info + *===============================================================*/ +#include "DD_Access.h" +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include "DD.h" +#include "DD_comm.h" + +/*-------------- Global definitions ------------------------*/ +extern int errno; +int Verbose; /* Verbose mode (variable for all subroutines)*/ +static int err; /* Common error for this file */ +static fd_set rfds; // For function select to look +static struct timeval tv; // if send can be done + + +/*--------------------- SET_LISTENER ------------------------*/ +/* function returns socket ID of listener or -1 as ERROR */ + +int SetListener() +{ +/*-------- Variables for resource file -----------------*/ + char rname[PATHLENGTH]; /* name of res file */ + char line[PATHLENGTH]; + char *path; + FILE *resfile; /* resource file */ + +/*---------- Variables for network ---------------------*/ + static struct hostent *Host; /* name & internet (32b) address for + remote hosts (see netdb.h) */ + static char RemSerName[PATHLENGTH]; /* name of remote server */ + + static struct sockaddr_in IntAFAddr; /* structure of internet address of type AF_INET + see <netinet/in.h> + to get name of socket we should + to convert pointer to this structure + to pointer to "srtruct sockaddr" where + all fields are "char array". */ + + int SocketID; /* socket ID (use as well file ID) */ + + int cc,i,j; + int arg = 0; + +/* + *---------- Getting socket and its address --------------------- +*/ +/*---------------- HOST and PORT ------------------------------*/ + if((path = getenv("DDPATH")) == NULL) + { + (void *)strcpy(rname,"DD.res"); + } + else + { + (void *)strcpy(rname,path); + (void *)strcpy(rname + strlen(rname), "/DD.res"); + } + + if((resfile = fopen(rname,"r")) == NULL) + { + fprintf(stderr,"No resource file, sorry\n"); + exit(1); + } + + fgets(RemSerName, PATHLENGTH, resfile); + RemSerName[strlen(RemSerName)-1] = '\0'; + fgets(line, PATHLENGTH, resfile); + sscanf(line,"%hu",&(IntAFAddr.sin_port)); + IntAFAddr.sin_port = htons(IntAFAddr.sin_port); /* Conversion of the port number to + universal network form */ + fclose(resfile); +/*---------------- END of FILE READING --------------------------*/ + +/* + *------- Trying to open socket with this address and name --------- + */ + if((Host = gethostbyname(RemSerName)) == NULL) /* Get address and other information by + host name, see netdb.h */ + { + fprintf(stderr,"Server %s not found\n",RemSerName); + return(-1); + } + + if((SocketID = socket(PF_INET,SOCK_STREAM,PROTOCOL)) < 0) + { + perror("Socket:"); return(-1); + } +/* + * Filling full internet address for socket "name" + * this address will be used to bind point + */ + IntAFAddr.sin_family = AF_INET; + memcpy(&IntAFAddr.sin_addr.s_addr,Host->h_addr_list[0],Host->h_length); +/* + IntAFAddr.sin_family = Host->h_addrtype; + IntAFAddr.sin_addr.s_addr = INADDR_ANY; +*/ +/* Naming of socket */ + if(bind(SocketID,(struct sockaddr *)&IntAFAddr,sizeof(IntAFAddr))<0) + { + perror("Bind:"); return(-1); + } + + /* Registration of socket as passive for external requests */ + if(listen(SocketID,SOMAXCONN) < 0) + { + perror("Listen:"); return(-1); + } + fprintf(stderr, "DD_SERVER was connected...!\n"); + + /* Watch sochet before each send. */ + FD_ZERO(&rfds); + FD_SET(SocketID, &rfds); + + + + return(SocketID); +} +/*---------------- End of SET_LISTENER ---------------------*/ + +/*----------------- SendToNet ------------------------------*/ +/* + * Enhanced send function. + * It buffers the packed end trying to send it by several attampts + */ +int SendToNet(int SocketID, char *buff, int length) +{ + int cc, pointer; + int retval; + + pointer = 0; + while(pointer < length) + { + /* Wait up to 30 seconds. */ +// tv.tv_sec = 30; +// tv.tv_usec = 0; + +// retval = select(SocketID+1,NULL, &rfds, NULL, &tv); +// if(retval < 0) return -1; + if((cc = send(SocketID,buff+pointer,length - pointer,0)) < 0) + { + if(Verbose) perror("Send Data:"); + return -1; + } +/* + fprintf(stderr,"send: p = %d, l = %d, cc = %d\n",pointer, length,cc); + fprintf(stderr,"buff: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n", + buff[0],buff[1],buff[2],buff[3],buff[4],buff[5],buff[6], + buff[7],buff[8],buff[9],buff[10],buff[11]); +*/ + pointer += cc; + } + return 0; +} + +/*------------------ PUTHEADER -----------------------------* +/* + * Encode end send Reply Header + */ +int PutHeader(int a1, int a2, int a3,int SocketID) +{ + int cc; + XDR xdrs; + char buf[REPLYLENGTH]; + + xdrmem_create(&xdrs, buf, REPLYLENGTH, XDR_ENCODE); + xdr_int(&xdrs,&a1); + xdr_int(&xdrs,&a2); + xdr_int(&xdrs,&a3); + + xdr_destroy(&xdrs); + +/* if((cc = send(SocketID,buf,REPLYLENGTH,0)) < 0) */ + if((cc = SendToNet(SocketID,buf, REPLYLENGTH)) < 0) + { + if(Verbose) perror("PutHeader:"); + return(REPLYRECERR); + } + return(0); +} +/*------------------------end of PutHeader ------------------------*/ + +/*===================== Send Constant Packet ====================)*/ +int SendConstantPacket(DD_Var_t *Data,int SocketID) +{ + caddr_t buff; + XDR xdrs; + int PacketSize,i,cc; + u_int MaxNumber,Number; + int error = OK; + + MaxNumber = 1; + for(i = 0;i < Data->AttrData.DimNumber; i++) + MaxNumber = MaxNumber * Data->AttrData.Dimensions[i]; + PacketSize = xdrlen[DD_INT] + /* Number of elements in Dimensions array */ + xdrlen[DD_INT] * Data->AttrData.DimNumber + /* Dimensions array */ + xdrlen[DD_INT] + /* Number of elements in data array */ + MaxNumber * xdrlen[Data->AttrData.type]; /* Data Array */ + +/* Sending Header */ + if((error = PutHeader(Data->AttrData.type, + Data->AttrData.DimNumber, + PacketSize,SocketID)) < 0) return error; + + buff =(caddr_t)malloc(PacketSize); + xdrmem_create(&xdrs, buff, (u_int)PacketSize, XDR_ENCODE); + +/* Packing Dimensions */ + if(Data->AttrData.DimNumber > 0) + { + Number = (u_int)Data->AttrData.DimNumber; + xdr_array(&xdrs, (caddr_t *)&(Data->AttrData.Dimensions), + &Number, + (u_int)Data->AttrData.DimNumber, + unixlen[DD_INT], + (xdrproc_t)xdr_int); + } + +/* Packing Variables */ + xdr_array(&xdrs,(caddr_t *)&(Data->AttrData.Variables[0]), + &MaxNumber, + MaxNumber, + unixlen[Data->AttrData.type], + (xdrproc_t)ConvFunc[Data->AttrData.type]); + +/* Sending Packet */ +/* if((cc = send(SocketID,buff,PacketSize,0)) < 0)*/ + if((cc = SendToNet(SocketID,buff, PacketSize)) < 0) + { + if(Verbose) perror("Send Constant Packet: "); + error = REPLYRECERR; + } + xdr_destroy(&xdrs); + free(buff); + return error; +} +/*------------------- End Send Constant Packet -------------------------------*/ + +/*===================== Send Data Packet ====================)*/ +int SendDataPacket(DD_Var_t *Data, int SocketID, int LastFlag) +{ + caddr_t buff; + XDR xdrs; + int PacketSize,i,cc,il; + u_int MaxNumber,Number; + int error = OK; + + for(il = 0; il < Data->ParamSize; il++) + { + MaxNumber = 1; + for(i = 0;i < Data->VarData[il].DimNumber; i++) + MaxNumber = MaxNumber * Data->VarData[il].Dimensions[i]; + + PacketSize = xdrlen[DD_INT] + /* Flag */ + xdrlen[DD_INT] + /* arrays number */ + xdrlen[DD_INT] + /* Sise of dimensions array */ + xdrlen[DD_INT] *(Data->VarData[il].DimNumber+1) + /* dimensions array */ + MaxNumber*xdrlen[Data->VarData[il].type]*Data->VarData[il].VarNumber + /* set if data arrays */ + xdrlen[DD_INT] * Data->VarData[il].VarNumber; /* data arrays sizes */ + + /* Sending header */ + if((error = PutHeader(Data->VarData[il].type, + Data->VarData[il].DimNumber+1, + PacketSize,SocketID)) < 0) return error; + + buff =(caddr_t)malloc(PacketSize); + xdrmem_create(&xdrs, buff, (u_int)PacketSize, XDR_ENCODE); + + /* Packing flag and Variables number */ + xdr_int(&xdrs, &LastFlag); + xdr_int(&xdrs, &Data->VarData[il].VarNumber); + + /* Packing dimensions */ + if(Data->VarData[il].DimNumber > 0) + { + Number = (u_int)Data->VarData[il].DimNumber; + xdr_array(&xdrs, + (caddr_t*)(&Data->VarData[il].Dimensions), + &Number, + (u_int )Data->VarData[il].DimNumber, + unixlen[DD_INT], + (xdrproc_t)xdr_int); + } + + /*Packing Variables */ + for(i = 0; i < Data->VarData[il].VarNumber; i++) + { + Number = MaxNumber; + xdr_array(&xdrs, + (caddr_t *)(&Data->VarData[il].Variables[i]), + &Number, + MaxNumber, + unixlen[Data->VarData[il].type], + (xdrproc_t)ConvFunc[Data->VarData[il].type]); + } + + /* Sending Data Packet */ + if((cc = SendToNet(SocketID,buff, PacketSize)) < 0) + { + if(Verbose) perror("SendDataPacket(): "); + error = REPLYRECERR; + } + xdr_destroy(&xdrs); + free(buff); + if(Verbose) fprintf(stderr,"SendDataPacket()[%d] succesful\n",il); + } // FOR il + return error; +} +/*----------------------- End Send Data Packet -------------*/ + +/*--------------------- SERV -------------------------------*/ +/* + * Read requests from socket, call appropriate function and + * return packets with information + * Start of this subroutine is the start of new communication session + */ + +void Serv(int SocketID) +{ + int cc; + int i,nlen; + char *bbt, GetTime[20];int bbtt[100],j, NoAccessToWork = 0,DD_id; + char Acc_Int[20]; double TimeInt,TimeStart,TimeStop; + int ReqType; + static char *ReqName = NULL; + static char *ReqTime = NULL; + static char *ReqHost = NULL; + static char *ReqTicket = NULL; + static char *ReqLogin = NULL; + static char *STReqLogin = NULL; + + /*------- Variables to create new VI ---------------*/ + static char *NewVIName = NULL; /* Full name of VI (data set to generate )*/ + static char *RemSetID = NULL; /* ID of remote Data Set */ + static char *RemBaseName = NULL; /* Base Name of remote WEB service */ + static char Command[MAXCOMMANDL]; /*Memory for command in system() + /*--------------------------------------------------*/ + + /*--------------------------------------------------- + * Variables need for the multy variavles + * Data Get + *---------------------------------------------------*/ + int PacketSize; // The size of the packet to get after the header packet + static int VarSize=0; // The number of variables to get + static char **VarNames = NULL; // Pointer to the C strings with the variable names + char *VarBuffer = NULL; + int BackFlag; // Variable for multi variable call + int il; + /*---------------------------------------------------*/ + + char *STReqHost = NULL; + int STid; + char *ReqBuf= NULL; + XDR xdrs; + int id=-1,lenall; + int op; + int errTick,serr; + DD_Var_t *Data; + int RemainID =0; /* Number of remained ID in use */ + static int TicketID = NOPERMISSION; + static int uid, FileAccID; + int GoOut = 0; /* The flag of finishing of session */ + int LastFlag; /* The flag of the end of data transmission */ + +/* WORKING */ + if(ReqName == NULL) ReqName = malloc(MAXSETLENGTH); + if(ReqTime == NULL) ReqTime = malloc(TIMELENGTH); + if(ReqBuf == NULL) ReqBuf = malloc(REQUESTLENGTH); + if(ReqHost == NULL) ReqHost = malloc(MAXHOSTLENGTH); + if(ReqTicket == NULL) ReqTicket = malloc(TICKETLENGTH); + if(ReqLogin == NULL) ReqLogin = malloc(USRLENGTH); + if(STReqLogin == NULL) STReqLogin = malloc(USRLENGTH); + if(STReqHost == NULL) STReqHost = malloc(MAXHOSTLENGTH); + /*==============================================*/ + +/*------------------------- General Data Array Preparation ---------------------------*/ + + DD_Var = (DD_Var_t **)malloc(MaxIDNumber * sizeof(DD_Var_t *)); + for(i=0;i<MaxIDNumber;i++) DD_Var[i] = NULL; + +/*-----------------------Open Access Virtual instrument ----------------------------------*/ +/** + sleep(60); +**/ + FileAccID = OpenInstr(ACCINSTR); + if(FileAccID < 0) + { + err = FileAccID; + fprintf(stderr,"Error while open %s VI\n",ACCINSTR); + goto endend; + } + +/*------------------------- Read Requests ---------------------------------------*/ + do + { + /* Get request from client */ + while((cc = recv(SocketID,ReqBuf,REQUESTLENGTH,0)) < 0); + + err = 0; + +/* Decode Request */ + xdrmem_create(&xdrs, ReqBuf, REQUESTLENGTH, XDR_DECODE); + xdr_int(&xdrs,&ReqType); + + switch (ReqType) + { + case OPENINSREQ: + xdr_string(&xdrs,&ReqName,MAXSETLENGTH); + + xdrmem_create(&xdrs, ReqBuf,REQUESTLENGTH , XDR_FREE); + while((cc = recv(SocketID,ReqBuf,REQUESTLENGTH,0)) < 0); /* Receive identification packet */ + xdrmem_create(&xdrs, ReqBuf,REQUESTLENGTH, XDR_DECODE); + xdr_int(&xdrs,&uid); + xdr_string(&xdrs,&ReqHost,MAXHOSTLENGTH); + xdr_string(&xdrs,&ReqLogin,USRLENGTH); + if(Verbose)printf("Serv():OPENINSREQ: Client Pasport: ID = %d, Host <%s>\n",uid,ReqHost); + + break; + + case CLOSEINSREQ : + xdr_int(&xdrs,&id); + break; + + case TIMESETREQ: + xdr_int(&xdrs,&id); + xdr_string(&xdrs,&ReqTime,TIMELENGTH); + break; + + case DATAINFOREQ: + xdr_int(&xdrs,&id); + xdr_string(&xdrs,&ReqName,MAXVARLENGTH); + break; + + /*-------------------------------------------- + * This request needs to receive the + * additinal information from the client + *------------------------------------------*/ + case DATAGETREQ: + /** sleep(60); **/ + /*---------------------------------------- + * Clear the list of variables + *---------------------------------------*/ + if(VarNames != NULL) + { + for(il=0;il < VarSize; il++) free(VarNames[il]); + free(VarNames); + VarNames = NULL; + VarSize = 0; + } + /*----------------------------------------- + * Decode the heading packet + *---------------------------------------*/ + xdr_int(&xdrs,&id); + xdr_string(&xdrs,&ReqTime,TIMELENGTH); + xdr_int(&xdrs,&PacketSize); + xdr_destroy(&xdrs); + /*----------------------------------------- + * Receive and Decode the variable packet + *---------------------------------------*/ + if(VarBuffer != NULL) free(VarBuffer); + VarBuffer = (char *)malloc(sizeof(char)*PacketSize); + while((cc = recv(SocketID,VarBuffer,PacketSize,0)) < 0); + xdrmem_create(&xdrs, VarBuffer,PacketSize, XDR_DECODE); + xdr_int(&xdrs,&VarSize); + VarNames = (char **)malloc(sizeof(char *) * VarSize); + for(il=0;il < VarSize; il++) + { + VarNames[il] = (char *)malloc(sizeof(char) * MAXVARLENGTH); + xdr_string(&xdrs,&(VarNames[il]),MAXVARLENGTH); + if(Verbose) fprintf(stderr,"Serv():DATAGETREQ: Variable[%d] %s\n",il,VarNames[il]); + } + xdr_int(&xdrs,&BackFlag); + break; + + case ADDVIREQ: + xdr_string(&xdrs,&NewVIName,MAXSETLENGTH); + xdr_string(&xdrs,&RemSetID,MAXVARLENGTH); + xdr_string(&xdrs,&RemBaseName,MAXVARLENGTH); + break; + + case GETTICKETREQ: + xdrmem_create(&xdrs, ReqBuf,REQUESTLENGTH , XDR_FREE); + while((cc = recv(SocketID,ReqBuf,REQUESTLENGTH,0)) < 0); + xdrmem_create(&xdrs, ReqBuf, REQUESTLENGTH, XDR_DECODE); + + xdr_int(&xdrs,&uid); + xdr_string(&xdrs,&ReqLogin,USRLENGTH); + xdr_string(&xdrs,&ReqTicket,TICKETLENGTH); + xdr_string(&xdrs,&ReqHost,MAXHOSTLENGTH); + + break; + + + case SHOWTICKETREQ: + xdr_int(&xdrs,&STid); + xdr_string(&xdrs,&STReqHost,MAXHOSTLENGTH); + xdr_string(&xdrs,&STReqLogin,USRLENGTH); + break; + default: err = REQSENDERR; + } /* switch REQTYPE */ + xdr_destroy(&xdrs); + + /*------------------------------------------------ + * Call data functions and response generation + *----------------------------------------------*/ + + switch(ReqType) + { + case OPENINSREQ: + if(Verbose) fprintf(stderr,"Serv():OPENINSREQ:ShowTicket; Host %s\n",ReqHost); + err = ShowTicket(uid,ReqHost,ReqLogin); + if(err >= 0) + { + id = OpenInstr(ReqName); + err = id; + if(id >= 0) strcpy(DD_Var[id]->InstrName,ReqName); + err = PutHeader(id,0,0,SocketID); /* return error if something is wrong */ + } + else PutHeader(err,0,0,SocketID); + break; + case CLOSEINSREQ: + if(id < 0){err = NOID;PutHeader(err,0,0,SocketID);} + if(Verbose) fprintf(stderr,"Serv():CLOSEINSREQ: ID = %d\n",id); + RemainID = CloseID(id); + if(RemainID < 1) + { + err = NOID; + PutHeader(err,0,0,SocketID); + } + else + { + err = PutHeader(RemainID-1,0,0,SocketID); + if(RemainID == 1) GoOut = 1; + } + break; + case TIMESETREQ: + if(id < 0) err = NOID; + if(err >= 0) err = SetTime(DD_Var[id],DD_Time2Double(ReqTime)); + if(err == CTIMEISSHIFTED) err = SetTime(DD_Var[id],-1.0); + if(err >= 0) PutHeader(0,0,0,SocketID); + else PutHeader(err,0,0,SocketID); + break; + + case DATAINFOREQ: + if(id < 0) err = NOID; + else err = GetAttribute(id,ReqName); + if(err >= 0) err = SendConstantPacket(DD_Var[id],SocketID); + else PutHeader(err,0,0,SocketID); + break; + + case DATAGETREQ: + if(id < 0) err = NOID; + /*------ Call data until LastPacket Flag (OK) returns --------*/ + else do + { + err = GetMultiData(id,VarSize,VarNames,ReqTime,BackFlag); + if(err >= 0) + { + serr = SendDataPacket(DD_Var[id],SocketID,DD_Var[id]->LastPacketFlag); /* OK, MOREDATA, MOREDELAY */ + if(Verbose) fprintf(stderr, "Server:DATAGETRQ (ID=%d):GetMultiData->SentPackets\n", id); + } + } + while((err >= 0) && (DD_Var[id]->LastPacketFlag == MOREDATA)); + if(err < 0) PutHeader(err,0,0,SocketID); + break; + + case ADDVIREQ: + sprintf(Command,ADDDATASETCALL,getenv("DDBASEBIN"),RemBaseName,RemSetID,NewVIName); + if(Verbose) fprintf(stderr, "Serv:ADDVIREQ: Command = %s\n", Command); + err = system(Command); + switch(err) + { + case 0: PutHeader(OK,0,0,SocketID); break; + case NOPHP: PutHeader(NOEXEC,0,0,SocketID); break; + case NOSCRIPT: PutHeader(NOEXEC,0,0,SocketID); break; + default: PutHeader(NOEXEC,0,0,SocketID); + } + GoOut = 1; + break; + + case GETTICKETREQ: + errTick = CheckTicket(ReqLogin, ReqTicket); + Put2Log(uid,ReqHost,ReqLogin,errTick); /* Log file */ + if(errTick >= 0) TicketID = GetTicket(uid,ReqHost,errTick); + if(Verbose) printf("GETTICKETREQ: uid= %d ReqHost = %s ErrTick = %d\n",uid,ReqHost ,errTick); + PutHeader(TicketID,0,0,SocketID); + GoOut = 1; + break; + + case SHOWTICKETREQ: + if(Verbose) printf("SHOWTICKETREQ; ShowTicket; Host %s\n",STReqHost); + err = ShowTicket(STid,STReqHost,STReqLogin); + PutHeader(err,0,0,SocketID); + GoOut = 1; + break; + } /* swithch Reqtype */ + + } while(GoOut == 0);/* end while(GoOut) */ + if(Verbose) fprintf(stderr,"DD_SERVER:Exit child process, communication closed\n"); + + +endend: + if(Verbose) + fprintf(stderr, "Serv():EndEnd:Close session %d at %s by error %d\n",SocketID,Double2DD_Time((double)time(NULL)),err); + RemainID = CloseID(FileAccID); + if(Verbose) fprintf(stderr, "Serv():EndEnd:Last Open VI (Access) is closed\n"); + + if(RemainID < 0) err = NOID; + + free(ReqName); + free(ReqTime); + free(ReqBuf); + free(ReqHost); + free(ReqTicket); + free(ReqLogin); + free(STReqLogin); + free(STReqHost); + free(DD_Var); + + shutdown(SocketID,2); + close(SocketID); + exit(0); +} +/*---------------------end of SERV ------------------------*/ + +/*-----------------------MAIN ------------------------------*/ +int main(int argc, char **argv) +{ + int ListenerID; + int NewSocketID; + struct sockaddr NewSocketAddr; + socklen_t NewSocketLen; + int stat_loc; + + if(argc < 2) Verbose = 0; + else if(((argv[1])[1] == 'v') || ((argv[1])[1] == 'V')) Verbose = 1; + else Verbose = 0; + + if((ListenerID = SetListener()) < 0) + { + fprintf(stderr,"DD_server: I cant set Listener Socket\n"); + exit(1); + } + +/*------- Define the maximum number of open Virtual Instruments ----------------*/ + MaxIDNumber = (size_t)(sysconf(_SC_OPEN_MAX) / 3L - 5L); + +/*-------- Endless listen ----------------------------------------------*/ + while(1) + { + NewSocketLen = sizeof(NewSocketAddr); + if((NewSocketID = accept(ListenerID,&NewSocketAddr,&NewSocketLen)) < 0) + { + // printf(" %d %d %d \n", ListenerID, (int)NewSocketLen, NewSocketID); + if(Verbose) perror("DD_Server: Accept: "); + } + else + { + if(Verbose) fprintf(stderr, "There is connection from ...\n"); + if(fork() == 0) /* I am child */ + { + if(fork() == 0) + { + Serv(NewSocketID); /*Real working */ + } + else exit(0); + } + else wait(&stat_loc); /* wait of finishing of child */ + close(NewSocketID); + } + } + /* Unreachable point */ + + close(ListenerID); + return 0; +} diff --git a/src/SERVER/ExtDataRequest.c b/src/SERVER/ExtDataRequest.c new file mode 100644 index 0000000..3f6ab4c --- /dev/null +++ b/src/SERVER/ExtDataRequest.c @@ -0,0 +1,303 @@ +/** + * @file ExtDataRequest.c + * @version $Id: ExtDataRequest.c,v 1.6 2009/07/07 12:24:23 budnik Exp $ + *===================================================================== + * ExtDataRequest.c + * V.2.6 + * Functions set to call external script to get more data for + * current database. + * + * Versions: + * Aug 3, 2007, V.1.0, Fedorov + * Sep 20, 2007, V.2.0, Fedorov, New solution for IsTimesLocked() + * Sep 20, 2007, V.2.1, Fedorov, New solution for IsTimesLocked() + * Sep 25, 2007, V.2.2, Fedorov, Variable GAP + * May 21, 2008, V.2.3, Fedorov, skip no data file + * May 22, 2008, V.2.4, Fedorov, Measuring of elapsed time of Lock + * Apr 11, 2009, V.2.5, Fedorov, Do not call new file if the data out of general limits + * Jul 07, 2009, V.2.6, Budnik, Special external call if there is empty times.nc; + * if(DStop <= DD_Var->GlobalStart) + * if(DStart >= DD_Var->GlobalStop) + *=====================================================================*/ + +#include <unistd.h> +#include <string.h> +#include "DD.h" +#include "DD_comm.h" + +extern int Verbose; + +/*===================================================================== + * Double2ISOTime() + * Covert double time to ISO time + * return pointer to statis string inside function + *=====================================================================*/ +char *Double2ISOTime(double CTime) +{ + static char ISO[25]; + unsigned *UT; + + UT = Double2UT(CTime); + sprintf(ISO,ISOTIMEP,UT[0],UT[1],UT[2],UT[3],UT[4],UT[5],UT[6]); + return (char *)ISO; +} + +/*===================================================================== + * DoRequest + * Read request. + * return OK, or NOEXEC + *=====================================================================*/ + int DoRequest(DD_Var_t *DD_Var, double Start, double Stop) + { + static char Command[MAXCOMMANDL]; /*Memory for command in system() */ + static char StartISO[25],StopISO[25]; + int err; + struct timeval tv; + struct timezone tz; + + /*====================================================== + * Lock the VI + * Set 1 means that VI is locked by THIS DD_Var and external program did not set LockFile yet + *=====================================================*/ + DD_Var->VILocked = 1; + gettimeofday(&tv,&tz); + memcpy(&(DD_Var->LockStartTime),&(tv.tv_sec),sizeof(time_t)); + + strcpy(StartISO,Double2ISOTime(Start)); + strcpy(StopISO,Double2ISOTime(Stop)); + sprintf(Command,GETNEWDATACALL,getenv("DDBASEBIN"),DD_Var->BaseName,DD_Var->RemSetID,DD_Var->path,StartISO,StopISO); + if(Verbose) fprintf(stderr, "DoRequest(): Command = %s\n", Command); + err = system(Command); + + switch(err) + { + case 0: return OK; + case NOPHP: return NOEXEC; + case NOSCRIPT: return NOEXEC; + default: return NOEXEC; + } + + return NOEXEC; + } + +/*====================================================================== + * ExtDataRequest + * Return folowing values: + * OK - request is accepted SERVER has to wait when LOCK file is gone + * NOEXEC - error in external executable + * NODATAATTIME - time corresponds to the NODATA interval + * GAPISSMALL - Time is inside too small gap + *======================================================================*/ + int ExtDataRequest(DD_Var_t *DD_Var, double CTime) + { + size_t Rmin,Rmax; + static size_t start[2] = {0,0}; + static size_t TimeCount[2] = {1,TIMELENGTH}; + char StartTime[TIMELENGTH]; + char StopTime[TIMELENGTH]; + double DStart, DStop; + int SearchResult, More, status; + + if(Verbose) fprintf(stderr,"ExtDataRequest: Rmin,Rmax = %d %d, CTime = %f\n",DD_Var->CurrRmin,DD_Var->CurrRmax, CTime); + + /* + * Search if there is an emtpy space ... + */ + if(DD_Var->CurrRmin >= 0) Rmin = (size_t)DD_Var->CurrRmin; else Rmin = 0; + if(DD_Var->CurrRmax >= 0) Rmax = (size_t)DD_Var->CurrRmax; else Rmax = DD_Var->MaxTimeRecNum - 1; + + if(Verbose) fprintf(stderr,"ExtDataRequest: CTime = %s\n",Double2DD_Time(CTime)); + /* + * No yet Records in times.nc + */ + if (Rmax == -1) { + + DStart = CTime - REQTIMEINT; + DStop = CTime + REQTIMEINT; + if(DStart > DD_Var->GlobalStop) + { + if(Verbose) fprintf(stderr, "ExtDataRequest: Request exceeds the global stop\n"); + return OUTOFTIME; + } + if(DStop < DD_Var->GlobalStart) + { + if(Verbose) fprintf(stderr, "ExtDataRequest: Request is less than global start\n"); + return OUTOFTIME; + } + return DoRequest(DD_Var, DStart, DStop); + + } + + More = 1; + while(More) + { + start[0] = (Rmin + Rmax)/2; + + status = nc_get_vara_text(DD_Var->tmID, DD_Var->StartID,start,TimeCount,StartTime); + DStart = DD_Time2Double(StartTime); + + if(CTime > DStart) + { + status = nc_get_vara_text(DD_Var->tmID, DD_Var->StopID,start,TimeCount,StopTime); + DStop = DD_Time2Double(StopTime); + if(DStop >= CTime) /* This is really INSIDE NODATA */ + { + DD_Var->TimeRecNumber = start[0]; + More = 0; + return NODATAATTIME; + } + else /* Try interval at the right */ + { + if(start[0] >= DD_Var->MaxTimeRecNum - 1) /* It was the last record */ + { + More = 0; + DD_Var->TimeRecNumber = DD_Var->MaxTimeRecNum - 1; + SearchResult = DATAATLEFT; /* We are on the right of all records */ + + } + else + { + if(Verbose) fprintf(stderr,"ExtDataRequest: We have to move to %d record, CTime = %s\n", start[0]+1,Double2DD_Time(CTime)); + start[0]++; + status = nc_get_vara_text(DD_Var->tmID, DD_Var->StartID,start,TimeCount,StartTime); + DStart = DD_Time2Double(StartTime); + if(DStart >= CTime) /* No data interval is at the RIGHT */ + { + DD_Var->TimeRecNumber = start[0]; + More = 0; + SearchResult = DATAATRIGHT; + } + else + { + Rmin = start[0]; + if(Rmax <= Rmin) Rmax = Rmin; + More = 1; + } + } /* else start[0] >= maximal */ + } /* else of TestTime >= CTime */ + + } /*(CTime > DStart) */ + else /* StartTime(R) > CTime */ + { + if(start[0] <= 0) /* CTime is on the left from the first interval */ + { + More = 0; + DD_Var->TimeRecNumber = 0; + SearchResult = DATAATRIGHT; + } + else + { + start[0]--; /* Try interval at the left */ + status = nc_get_vara_text(DD_Var->tmID, DD_Var->StopID,start,TimeCount,StopTime); + DStop = DD_Time2Double(StopTime); + if(CTime > DStop) /* Correct interval is on the right */ + { + DD_Var->TimeRecNumber = start[0] + 1; + More = 0; + SearchResult = DATAATRIGHT; + } + else + { + Rmax = start[0]; + More =1; + } + } + } + } /* while(More) */ + + /* + * Probably we at the left or at the right of interval + */ + if(SearchResult == DATAATLEFT) // Data are on the left of requested data + { + start[0] = DD_Var->TimeRecNumber; + status = nc_get_vara_text(DD_Var->tmID, DD_Var->StopID,start,TimeCount,StopTime); + DStart = DD_Time2Double(StopTime); // Left boundary + if((CTime - DStart) > REQTIMEINT) DStart = CTime - REQTIMEINT; + DStop = CTime + REQTIMEINT; + if(DStart >= DD_Var->GlobalStop) + { + if(Verbose) fprintf(stderr, "ExtDataRequest: Request exceeds the global stop\n"); + return OUTOFTIME; + } + return DoRequest(DD_Var, DStart, DStop); + } + + if(DD_Var->TimeRecNumber == 0) // All data is on the right + { + start[0] = DD_Var->TimeRecNumber; + status = nc_get_vara_text(DD_Var->tmID, DD_Var->StartID,start,TimeCount,StartTime); + DStop = DD_Time2Double(StartTime); /* Right boundary */ + if((DStop - CTime) > REQTIMEINT) DStop = CTime + REQTIMEINT; + DStart = CTime - REQTIMEINT; + if(DStop <= DD_Var->GlobalStart) + { + if(Verbose) fprintf(stderr, "ExtDataRequest: Request is less than global start\n"); + return OUTOFTIME; + } + return DoRequest(DD_Var, DStart, DStop); + } + + /* + * Now we are between two records + * We have to check if the gap is big enough + */ + start[0] = DD_Var->TimeRecNumber; + status = nc_get_vara_text(DD_Var->tmID, DD_Var->StartID,start,TimeCount,StartTime); + DStop = DD_Time2Double(StartTime); /* GAP! */ + + start[0]--; + status = nc_get_vara_text(DD_Var->tmID, DD_Var->StopID,start,TimeCount,StopTime); + DStart = DD_Time2Double(StopTime); /* GAP! */ + + + if((DStop - DStart) < DD_Var->MinGap) return GAPISSMALL; + + + if((CTime - DStart) > REQTIMEINT) DStart = CTime - REQTIMEINT; + if((DStop - CTime) > REQTIMEINT) DStop = CTime + REQTIMEINT; + /* + if(Verbose) + { + fprintf(stderr,"DStart-GlobalStart = %f\n",DStart - DD_Var->GlobalStart); + fprintf(stderr,"DStop-GlobalStop = %f\n",DStop - DD_Var->GlobalStop); + } + if((DStop > DD_Var->GlobalStop) || (DStart < DD_Var->GlobalStart)) return OUTOFTIME; + */ + return DoRequest(DD_Var, DStart, DStop); + } + +/*====================================================================== + * IsTimesLocked + * Return 1 if there is LOCK in the VI directory or if the corresponding flag in DD_Var is UP + *======================================================================*/ + int IsTimesLocked(DD_Var_t *DD_VarL) + { + int status; + char FullPath[PATHLENGTH]; + struct timeval tv; + struct timezone tz; + + + strcpy(FullPath,DD_VarL->path); + strcat(FullPath,DIRLOCK); + status = access(FullPath, F_OK); /* negative if there is no file */ + switch(DD_VarL->VILocked) + { + case 0: if(status < 0) return NOLOCK; /* NO LOCK */ + else {DD_VarL->VILocked = 2; return LOCKED;} /* LOCK was made by another server */ + break; + case 1: if(status < 0) /* LOCK was made by THIS server, PHP is not ready yet OR already removed(!)*/ + { + gettimeofday(&tv,&tz); + if(difftime(tv.tv_sec,DD_VarL->LockStartTime) > 1.5) + {DD_VarL->VILocked = 0; return LOCKREMOVED;} /* PHP alreadyremoved LOCK */ + else return LOCKED; + } + else {DD_VarL->VILocked = 2; return LOCKED;} /* Now even PHP setup LOCK */ + break; + case 2: if(status < 0) {DD_VarL->VILocked = 0; return LOCKREMOVED;} /* PHP removed LOCK */ + else return LOCKED; /*Keep LOCK condition */ + } + } +/*=============================================================================================*/ diff --git a/src/SERVER/UpdateTimeInfo.c b/src/SERVER/UpdateTimeInfo.c new file mode 100644 index 0000000..7855b31 --- /dev/null +++ b/src/SERVER/UpdateTimeInfo.c @@ -0,0 +1,185 @@ +/*===================================================================== + * DD SYSTEM base package + * DD_Server library + * UpdateTimeInfo.c + * V.1.1 + * Functions to updete time constant in the DD_Var structure and + * auxial functions to search in the "times" file. + * + * Versions: + * Sep 20, 2007, V.1.0, Fedorov + * Sep 23, 2007, V.1.1, Fedorov, SHARE MODE + *=====================================================================*/ + +#include <netcdf.h> +#include "DD.h" +#include "DD_comm.h" + +extern int Verbose; +/*--------------------------------------------------------- + * SearchRight() + *---------------------------------------------------------*/ +int SearchRight(DD_Var_t *DD_VarL, size_t Rmin, size_t Rmax) +{ + static size_t start[2] = {0,0}; + static size_t TimeCount[2] = {1,TIMELENGTH}; + static size_t FileCount[2] = {1,MAXFILENAME}; + char TimeIntName[MAXSETLENGTH]; /* File name associated with the given time interval */ + int NoDataFlag; + int status; + + start[0] = DD_VarL->TimeRecNumber; + + NoDataFlag = 1; + while(NoDataFlag) + { + status = nc_get_vara_text(DD_VarL->tmID, DD_VarL->NameID,start,FileCount,TimeIntName); + if(strcmp(TimeIntName,NODATASTR) == 0) /* No data for this time interval */ + { + start[0]++; /* Go right */ + if(start[0] > Rmax) return REACHRIGHT; /* End of alowed interval is reached */ + } + else + { + DD_VarL->TimeRecNumber = start[0]; + NoDataFlag = 0; + } + } + return OKRIGHT; +} + +/*--------------------------------------------------------- + * SearchLeft() + *---------------------------------------------------------*/ +int SearchLeft(DD_Var_t *DD_VarL, size_t Rmin, size_t Rmax) +{ + static size_t start[2] = {0,0}; + static size_t TimeCount[2] = {1,TIMELENGTH}; + static size_t FileCount[2] = {1,MAXFILENAME}; + char TimeIntName[MAXSETLENGTH]; /* File name associated with the given time interval */ + int NoDataFlag; + int status; + + start[0] = DD_VarL->TimeRecNumber; + + NoDataFlag = 1; + while(NoDataFlag) + { + status = nc_get_vara_text(DD_VarL->tmID, DD_VarL->NameID,start,FileCount,TimeIntName); + if(strcmp(TimeIntName,NODATASTR) == 0) /* No data for this time interval */ + { + if(start[0] > 0) start[0]--; else return REACHLEFT; /* Go left */ + if(start[0] < Rmin) return REACHLEFT; /* End of alowed interval is reached */ + } + else + { + DD_VarL->TimeRecNumber = start[0]; + NoDataFlag = 0; + } + } + return OKLEFT; +} +/*-----------------------------------------------------------------*/ + +/*--------------------------------------------------------- + * UpdateTimeInfo() + *---------------------------------------------------------*/ +int UpdateTimeInfo(DD_Var_t *DD_VarL) +{ + static char StartName[] = "StartTime"; + static char StopName[] = "StopTime"; + static char FileName[] = "FileName"; /* Variable IDs */ + static char RecDimName[] = "record"; + static int RecDimID; + static size_t start[2] = {0,0}; + static size_t TimeCount[2] = {1,TIMELENGTH}; + char TimeS[TIMELENGTH]; + size_t Rmin,Rmax; + int SearchStatus; + int status; + /*---- Close file if it is open ---------------------------*/ + if(DD_VarL->tmID > -1) status = nc_close(DD_VarL->tmID); + + if(Verbose) fprintf(stderr,"UpdateTimeInfo(%s): Start\n",DD_VarL->TimesFileName); + + /*---- Reopen times file ----------------------------------*/ + status = nc_open(DD_VarL->TimesFileName, NC_NOWRITE|NC_SHARE,&(DD_VarL->tmID)); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"UpdateTimeInfo(%s): open file: message: %s\n",DD_VarL->TimesFileName,nc_strerror(status)); + return(NOTIMESFILE); + } + /* + * Init corresponding constants + */ + status = nc_inq_varid(DD_VarL->tmID,FileName, &(DD_VarL->NameID)); + status = nc_inq_varid(DD_VarL->tmID,StartName,&(DD_VarL->StartID)); + status = nc_inq_varid(DD_VarL->tmID,StopName, &(DD_VarL->StopID)); + if (status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"UpdateTimeInfo(%s): Get parameters times file %s\n",DD_VarL->TimesFileName,nc_strerror(status)); + return(NOTIMESFILE); + } + + /* Get MaxRecord Number */ + status = nc_inq_dimid(DD_VarL->tmID,RecDimName, &RecDimID); + if (status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"UpdateTimeInfo(%s): Get Max records in Times file %s\n",DD_VarL->TimesFileName,nc_strerror(status)); + return(NOTIMESFILE); + } + status = nc_inq_dimlen(DD_VarL->tmID,RecDimID, &(DD_VarL->MaxTimeRecNum)); + +/* ----------------------------------------------------------------- + * Search the extreme left and right valid intervals + * -----------------------------------------------------------------*/ + Rmin = 0; Rmax = DD_VarL->MaxTimeRecNum - 1; + DD_VarL->TimeRecNumber = 0; + switch(SearchRight(DD_VarL,Rmin,Rmax)) + { + case REACHRIGHT: SearchStatus = NOONEDATA; + DD_VarL->RValidMin = -1; + DD_VarL->RValidMax = -1; + DD_VarL->MinValidTime = -1.0; + break; + case OKRIGHT: DD_VarL->RValidMin = DD_VarL->TimeRecNumber;SearchStatus = IDLE; + } + + if(SearchStatus != NOONEDATA) /* Ther is something in the right */ + { + DD_VarL->TimeRecNumber = Rmax; + switch(SearchLeft(DD_VarL,Rmin,Rmax)) + { + case REACHLEFT: DD_VarL->RValidMin = -1; + DD_VarL->RValidMax = -1; + DD_VarL->MaxValidTime = -1.0; + break; /* Impossible */ + case OKLEFT: DD_VarL->RValidMax = (int)DD_VarL->TimeRecNumber; + } + } + + /*------ Define min and max valid times ------------------------*/ + if(DD_VarL->RValidMin >= 0) + { + start[0] = (size_t)DD_VarL->RValidMin; + status = nc_get_vara_text(DD_VarL->tmID, DD_VarL->StartID,start,TimeCount,TimeS); + DD_VarL->MinValidTime = DD_Time2Double(TimeS); + } + else DD_VarL->MinValidTime = -1.0; + if(DD_VarL->RValidMax >= 0) + { + start[0] = (size_t)DD_VarL->RValidMax; + status = nc_get_vara_text(DD_VarL->tmID, DD_VarL->StopID,start,TimeCount,TimeS); + DD_VarL->MaxValidTime = DD_Time2Double(TimeS); + } + else DD_VarL->MaxValidTime = -1.0; + + + /*------- Init other values ------------------------------------*/ + DD_VarL->CurrRmin = -1; + DD_VarL->CurrRmax = -1; + /*-----------------------------------------------------------------------*/ + if(Verbose) fprintf(stderr,"UpdateTimeInfo(%s): OK\n",DD_VarL->TimesFileName); + return OK; +} +/*====================================================================================*/ diff --git a/src/SERVER/ncfileop.c b/src/SERVER/ncfileop.c new file mode 100755 index 0000000..76a06cb --- /dev/null +++ b/src/SERVER/ncfileop.c @@ -0,0 +1,498 @@ +/*===================================================================== + * DD SYSTEM base package + * DD_Server library + * ncfileop.c + * V.6.7 + * Last revision: + * Oct 24, 2002 New calculation of the maximum record size V 4.1 + * work with NC files is now in file ncfileop.c + * Nov 19, 2004 Bug in the cach operation. + * Aug 16, 2005 Cach improved + * Mar 15, 2007 V.4.7 Some errors with cash + * Jul 10, 2007 V.5.0 According to Server protocol 4.5.1 Call external database if need. + * If "times" has "NODATA" string as name of the file, return "NOTIME" + * Sep 22, 2007 V.6.0 New approach. It tries to get new data between two files + * Sep 25, 2007 V.6.1 Variable Minimal Gap + * May 06, 2008 V.6.2 Fedorov, Max Records number processing + * May 12, 2008 V.6.3 Fedorov, In Max Records error in malloc sizeof(int *)!!! important for 64 + * May 15, 2008 V.6.4 Fedorov, NoData interval processing. Just go to the next correct data interval. + * Apr 08, 2009 V.6.5 Fedorov, Unziped files can be touched by groupe + * Apr 14, 2009 V.6.6 Fedorov, nc_sync + * Feb 02, 2010 V.6.7 Lena, wait to remove an old file in the cache + *======================================================================*/ +#include <netcdf.h> +#include "DD.h" +#include "DD_comm.h" + +/*------------------ GLOBAL VARIABLES --------------------------*/ +extern int Verbose; + +/*============================================================= + * CloseOldFile + *===========================================================*/ +int CloseOldFile(DD_Var_t *D) +{ + size_t CashStart[2] = {0L,0L}; + size_t CashCount[2] = {1L,MAXFILENAME}; + int status; + + if(D->Maxnc_rec > 0) + { + status = nc_close(D->ncID); + if(status < 0) + { + D->LastFileStatus = DATAFILEERR; + if(Verbose) fprintf(stderr,"CloseOldFile: file %s, error while closed\n",&(D->Cash.names[D->CurrCushN][0]),D->CurrCushN); + return DATAFILEERR; + } + if(Verbose) fprintf(stderr,"CloseOldFile: file %s, %d closed\n",&(D->Cash.names[D->CurrCushN][0]),D->CurrCushN); + D->CurrCushN = -1; + D->Maxnc_rec = 0; + } + else if(Verbose) fprintf(stderr,"CloseOldFile: Nothing To close\n"); + + return 1; +} + +/*##############################################################*/ +/*-----------------------SETNEWFILE-----------------------------*/ +/*##############################################################*/ + +int SetNewFile(DD_Var_t *D, int N) +/* + * Function tries to get new data for the gap beetween files, or just + * open a new data file according to offset N referring to current position in the times file. + * The current position changed if file is succesefully open. + * Return values: + * OK + * OUTOFTIME - next interval exceeeds GlobalStart/Stop + * TIMEINEMPTY - next interval marked as "NODATA" + * TRYAGAIN - the VI is blocked while new data is arriving + * WAITEXTCALL - new data is requested + * CACHTOOREC - now free space in the CACH + * CHACHERR - unrecovable error in CACH + * DATAFILEERR - unrecovable error in data file + *---------------------------------------------------------------- + * At the entry we are assuming that VI is not locked! + */ +{ + static char TimeDimName[] = "Time"; + static size_t CashStart[2] = {0L,0L}; + static size_t CashCount[2] = {1L,MAXFILENAME}; + static size_t TimeCount[2] = {1,TIMELENGTH}; + + char Name[MAXFILENAME]; /* Name of data nc file */ + char FullName[PATHLENGTH]; /* Full name of nc file */ + char StartTime[TIMELENGTH]; + char StopTime[TIMELENGTH]; + static int NameID,TimeDimID; /* NC variables ID for Times file */ + static size_t start[2] = {0,0}; /* NV start array */ + static size_t FileCount[2] = {1,MAXFILENAME}; /* NC count array for Times file */ + static size_t DimArray[NC_MAX_DIMS]; /* NC_MAX_DIMS is in netcdf.h */ + static int DimIDArray[NC_MAX_DIMS]; + size_t TestNumber; /* To test the new file number */ + int FileNumber, Find, OldestNumber, NewAttempt; + char command[300]; + int dltt; + int status; + time_t CurrentTime; + double FirstTime, LastTime; + int More; + +/*--------------- Calculate the next file to open ---------------*/ + TestNumber = D->TimeRecNumber + N; + if(Verbose) fprintf(stderr,"SetNewFile(): Record %d\n",TestNumber); + + D->TimeRecNumber = TestNumber; + start[0] = TestNumber; + +/*----------------------------------------------------------------* + * Some test and call external archive we have to make only if N > 0 + * Otherwise we just reopen existing file + *----------------------------------------------------------------*/ + if(N > 0) + { + if(TestNumber > D->RValidMax) /* Out of existing data files */ + { + if(Verbose) fprintf(stderr,"SetNewFile(): TestNumber %d exides D->RValidMax %d\n",TestNumber,D->RValidMax); + + if(D->ExtCallAllowed) + { + More = 1; + while(More) + { + switch(status = ExtDataRequest(D, D->CDTime+D->MinGap)) + { + case OK: return WAITEXTCALL; + case NODATAATTIME: /* The last files in the data base are only NODATA, let us try again with StopTime of TestNumber */ + start[0] = TestNumber; + status = nc_get_vara_text(D->tmID, D->StopID,start,TimeCount,StopTime); + D->CDTime = DD_Time2Double(StopTime) + 0.001; + if(Verbose) fprintf(stderr,"SetNewFile(): We found no data, Let us try another CDTime = %s\n",Double2DD_Time(D->CDTime)); + More = 1; + break; + case GAPISSMALL: return TIMEINEMPTY; break; + case OUTOFTIME: return OUTOFTIME; break; + default: return DATAFILEERR; + } + } + } else return OUTOFTIME; + } + } + + /*--------------- Get File Name and start Time ---------------------*/ + status = nc_get_vara_text(D->tmID,D->NameID,start,FileCount,Name); + status = nc_get_vara_text(D->tmID, D->StartID,start,TimeCount,StartTime); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"SetNewFile(): Get File Name and StartTime %s\n",nc_strerror(status)); + D->LastFileStatus = DATAFILEERR; + return DATAFILEERR; + } + FirstTime = DD_Time2Double(StartTime); + + if(N > 0) + { + if(strncmp(Name,"NODATA",6) == 0) /* Next record marked as NODATA */ + { + if(D->ExtCallAllowed && (FirstTime - D->CDTime > D->MinGap)) /* Try to fill the gap between the data + * and NODATA segment if there is enough gap + */ + { + if(Verbose) fprintf(stderr,"SetNewFile(): There is a gap %d\n",FirstTime - D->CDTime); + switch(status = ExtDataRequest(D, D->CDTime+D->MinGap)) + { + case OK: return WAITEXTCALL; + case NODATAATTIME: + case GAPISSMALL: return TIMEINEMPTY; break; + case OUTOFTIME: return OUTOFTIME; break; + default: return DATAFILEERR; + } + } + else /* Gap to NODATA interval is too small and we wiil try next time interval */ + { + if(Verbose) fprintf(stderr,"SetNewFile(): Next File is NODATA, try file %d\n",++TestNumber); + status = nc_get_vara_text(D->tmID, D->StopID,start,TimeCount,StopTime); + D->CDTime = DD_Time2Double(StopTime); + + switch( status = SetNewFile(D,1) ) + { + case OK: return OK; + case WAITEXTCALL: return WAITEXTCALL; + case TIMEINEMPTY: return TIMEINEMPTY; + case OUTOFTIME: return OUTOFTIME; + case CACHERR: return CACHERR; + default: return DATAFILEERR; + } + } + + } + else /* Next record is valid */ + { +// sleep(40); + if(D->ExtCallAllowed && ((FirstTime - D->CDTime) > D->MinGap)) + { + if(Verbose) fprintf(stderr,"SetNewFile(): File OK, but there is a gap %d %d\n",FirstTime - D->CDTime, D->MinGap); + switch(status = ExtDataRequest(D, D->CDTime+D->MinGap)) + { + case OK: return WAITEXTCALL; + case NODATAATTIME: + case GAPISSMALL: return TIMEINEMPTY; break; + case OUTOFTIME: return OUTOFTIME; break; + default: return DATAFILEERR; + } + } /* else just continue */ + } + } + +/*-------------- refresh the Cache table ---------------------------*/ + status = nc_sync(D->Cash.ID); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"SetNewFile(): Cache Synchro: %s\n",nc_strerror(status)); + return CACHERR; + } + for(CashStart[0] = 0; CashStart[0] < CASHLEN; CashStart[0]++) + { + status = nc_get_vara_text(D->Cash.ID, D->Cash.nameID,CashStart,CashCount,D->Cash.names[CashStart[0]]); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"SetNewFile(): Cache Names: %s\n",nc_strerror(status)); + D->LastFileStatus = CACHERR; + return CACHERR; + } + status = nc_get_vara_long(D->Cash.ID, D->Cash.timeID,CashStart,CashCount,&(D->Cash.times[CashStart[0]])); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"SetNewFile(): Cache Times %s\n",nc_strerror(status)); + D->LastFileStatus = CACHERR; + return CACHERR; + } + } + +/*----------- Close the old file ----------------------*/ + if((status = CloseOldFile(D)) < 0) return DATAFILEERR; + + strcpy(FullName,D->path); + strcpy(FullName+strlen(D->path), Name); +// if(Verbose) fprintf(stderr,"SetNewFile(): New file to open: %s\n",FullName); + + NewAttempt = 0; + + while (NewAttempt < 3) + { + /*----- Search the new requested file in the cache and the oldest file ----------*/ + FileNumber = 0; + CurrentTime = time(NULL); Find = 0; OldestNumber = -1; + + while((FileNumber < CASHLEN) && // Cache is finished + ((Find = strcmp(&(D->Cash.names[FileNumber][0]),Name)) != 0) && // File is already in the Cache + (D->Cash.names[FileNumber][0] != ' ')) // There is empty space + { + if((D->Cash.times[FileNumber] < (CurrentTime - FILEACCMARG) ) && (OldestNumber == -1)) OldestNumber = FileNumber; + dltt = (int)(D->Cash.times[OldestNumber] - D->Cash.times[FileNumber]); + if(dltt > 0) OldestNumber = FileNumber; + FileNumber++; + } + + /* ==================================================== + * Sometimes it is possible, that: + * 1) No corresponding file in the cache (Find != 0) + * 2) The oldest file is not found (OldestNumber == -1) + * 3) cach is full (FileNumber == CASHLEN) + * Then we need to repeat the search after one sec delay + *==================================================== */ + if((Find != 0) && (FileNumber == CASHLEN) && (OldestNumber == -1)) + { + NewAttempt++; + sleep((unsigned )(FILEACCMARG)); + + if (Verbose) + fprintf(stderr,"Waiting %d secs to get the Oldest File\n", FILEACCMARG); + + } else NewAttempt = 3; + } + +//---------- Parsing resultat of search ------------- +// if(Verbose) +// { +// if(OldestNumber > -1) fprintf(stderr,"SetNewFile(): Search: Is Oldest File %d %d %d\n", OldestNumber,D->Cash.times[OldestNumber],CurrentTime); +// else fprintf(stderr,"SetNewFile(): Search: No Oldest File %d %d\n", OldestNumber,CurrentTime); +// } + + if(Find != 0) +/*---------------- No request file in the CACHE ----------------------*/ + { + if(FileNumber < CASHLEN) + { + if(D->Cash.names[FileNumber][0] == ' ') /* There is empty space in the table */ + { + strcpy(command, "gunzip -c "); + strcat(command, FullName); + strcat(command, ".gz > "); + strcat(command, FullName); + system(command); /* File is unzipped */ + sprintf(command, "chmod g+w %s\0",FullName); + system(command); /* File is unzipped */ + + strcpy(&(D->Cash.names[FileNumber][0]),Name); + D->Cash.times[FileNumber] = CurrentTime; + CashStart[0] = FileNumber; + D->CurrCushN = FileNumber; + } + else + { + D->LastFileStatus = CACHERR; + return CACHERR; /* Unrecoverable error */ + } + } + else /* No empty space. It is necessury to remove one file */ + { + if (OldestNumber > -1) //------ Oldest file is found ------- + { + strcpy(command, "gunzip -c "); + strcat(command, FullName); + strcat(command, ".gz > "); + strcat(command, FullName); + system(command); /* File is unzipped */ + sprintf(command, "chmod g+w %s\0",FullName); + system(command); /* File is unzipped */ + + strcpy(command, "rm "); + strcat(command,D->path); + strcat(command,&(D->Cash.names[OldestNumber][0])); + strcat(command, " &"); + system(command); /* Old file removed */ + strcpy(&(D->Cash.names[OldestNumber][0]),Name); + D->Cash.times[OldestNumber] = CurrentTime; + CashStart[0] = OldestNumber; + D->CurrCushN = OldestNumber; + } + else { + if(Verbose) fprintf(stderr,"SetNewFile(): return CACHTOOREC\n"); + D->LastFileStatus = CACHTOOREC; + D->TimeRecNumber -= N; + return CACHTOOREC; //----- Say client that all files are too new + } + } + /*------------ The place for new cache is found --------------*/ + status = nc_put_vara_text(D->Cash.ID, D->Cash.nameID,CashStart,CashCount,&(D->Cash.names[CashStart[0]][0])); + status = nc_put_vara_long(D->Cash.ID, D->Cash.timeID,CashStart,CashCount,&(D->Cash.times[CashStart[0]])); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"SetNewFile(): Write Name and Time to cash: %s\n",nc_strerror(status)); + D->LastFileStatus = CACHERR; + return CACHERR; + } + status = nc_sync(D->Cash.ID); + } +//------------------ There is FILE already in the CACHE -------------- + else /*------- The requested file is already in the cache just refresh the time */ + { + CashStart[0] = FileNumber; + D->Cash.times[FileNumber] = CurrentTime; /* refresh the time */ + D->CurrCushN = FileNumber; + status = nc_put_vara_long(D->Cash.ID, D->Cash.timeID,CashStart,CashCount,&(D->Cash.times[CashStart[0]])); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"SetNewFile(): File In Cache: %s\n",nc_strerror(status)); + D->LastFileStatus = CACHERR; + return CACHERR; + } + status = nc_sync(D->Cash.ID); + } + +// if(Verbose) fprintf(stderr,"SetNewFile(): file %s, %d to be open\n",FullName,D->CurrCushN); + + +/*--------------- CACHE refreshed and requested file is unzipped ------------------------*/ +/*----------------- Open requested file -----------------------------------------------*/ + + status = nc_open(FullName,NC_NOWRITE,&(D->ncID)); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"SetNewFile(): Error while File Open: %s\n",nc_strerror(status)); + D->LastFileStatus =DATAFILEERR ; + return DATAFILEERR; + } + if(Verbose) fprintf(stderr,"SetNewFile(): %s is open\n",FullName); + +/* Recover time dimension */ + status = nc_inq_dimid(D->ncID,TimeDimName,&TimeDimID); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"SetNewFile(): Get Time Dim: %s\n",nc_strerror(status)); + D->LastFileStatus = DATAFILEERR; + return DATAFILEERR; + } + status = nc_inq_dimlen(D->ncID,TimeDimID,&(D->Maxnc_rec)); + if(status != NC_NOERR) + { + if(Verbose) fprintf(stderr,"SetNewFile: GetFile Length: %s\n",nc_strerror(status)); + D->LastFileStatus = DATAFILEERR; + return DATAFILEERR; + } + +/* Setup current position in the new open file */ + if(N > 0) D->nc_rec = 0; + if(N < 0) D->nc_rec = D->Maxnc_rec-1; + + D->LastFileStatus = OK; + return OK; +} +/*------------------------------------------------------------------------------------*/ + +/*----------------- VarSize -----------------------------------*/ +int VarSize(nc_type type) +{ + switch(type) + { + case NC_BYTE: return sizeof(char); + case NC_CHAR: return sizeof(char); + case NC_SHORT: return sizeof(short); + case NC_INT: return sizeof(int); + case NC_FLOAT: return sizeof(float); + case NC_DOUBLE: return sizeof(double); + default: return 1; + } +} + +/*##############################################################*/ +/*----------------------- MaxRecord -----------------------------*/ +/*##############################################################*/ + +size_t MaxRecord(int ncID) +/* ncID - ID of already open NC file */ +{ + int timedimid; /* ID for dimension "Time" */ + + int nvars; + int ndims; + int *ndims_arr; /* Array to keep number of dimensions of each variable */ + size_t *dimleng_arr; /* Array to keep all length of dimensions */ + nc_type *vartype_arr; /* Array to keep all types of variables */ + int **dimid_arr; /* array of pointers to arrays of variable dimensions */ + + int status; /* Error indicator */ + int iv, id; + int cvarsize; /* size of variable */ + int maxsize; /* maximal size */ + int recordsize; /* size by units */ + size_t RecordNumber; + + /*--- general information -------*/ + status = nc_inq_ndims(ncID,&ndims); + status = nc_inq_nvars(ncID,&nvars); + status = nc_inq_unlimdim(ncID, &timedimid); /* What is unlimited dimension ID */ + + /*---- memory allocation --------*/ + dimleng_arr = (size_t *)malloc(ndims * sizeof(size_t)); + vartype_arr = (nc_type *)malloc(nvars * sizeof(nc_type)); + dimid_arr = (int **)malloc(nvars * sizeof(int *)); + ndims_arr = (int *)malloc(nvars * sizeof(int)); + + /* Length of each dimension */ + for(id = 0; id < ndims; id++) + { + if(id == timedimid) dimleng_arr[id] = 1; + else status = nc_inq_dimlen(ncID, id, &(dimleng_arr[id])); + } + + /* type and dimension of each variable */ + for(iv = 0; iv < nvars; iv++) + { + status = nc_inq_vartype(ncID,iv,&(vartype_arr[iv])); + status = nc_inq_varndims(ncID,iv,&(ndims_arr[iv])); + dimid_arr[iv] = (int *)malloc(ndims_arr[iv]*sizeof(int)); /* memory for dim ID array */ + status = nc_inq_vardimid(ncID,iv,dimid_arr[iv]); + } + + /* calculation of size of variable and maximum size of variables */ + maxsize = 0; + for(iv = 0; iv < nvars; iv++) + { + recordsize = 1; + for(id = 0; id < ndims_arr[iv]; id++) + recordsize *= dimleng_arr[(dimid_arr[iv])[id]]; + cvarsize = recordsize * VarSize(vartype_arr[iv]); + if(cvarsize > maxsize) maxsize = cvarsize; + } + + /* calculation record number */ + RecordNumber = (size_t)(MAXPACKSIZE / maxsize); + if(RecordNumber == 0) + { + if(Verbose) fprintf(stderr,"MaxRecord(%d): Error in calculation of records number,MAXPACKSIZE = %d, maxsize = %d\n",ncID,MAXPACKSIZE,maxsize); + } + + /* Free all */ + for(iv = 0; iv < nvars; iv++) free(dimid_arr[iv]); + free(ndims_arr); + free(dimid_arr); + free(vartype_arr); + free(dimleng_arr); + + return RecordNumber; +} +/*----------------------------------------------------------------------*/ + -- libgit2 0.21.2