/* $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>

#include <netinet/in.h>
#include <arpa/inet.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 =================================*/

int getInfoFromHostName(const char *hostName, struct sockaddr_in *addr)
{
	struct addrinfo hints;
	memset(&hints, 0, sizeof(struct addrinfo));
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_PASSIVE;
	hints.ai_protocol = 0;
	hints.ai_canonname = NULL;
	hints.ai_addr = NULL;
	hints.ai_next = NULL;

	struct addrinfo *result;
	int s;

	s = getaddrinfo(hostName, NULL, &hints, &result);

	if (s != 0)
	{
		return NOHOST;
	}

	struct sockaddr_in *h;
	h = (struct sockaddr_in *) result->ai_addr;

	memcpy(addr,h,sizeof(struct sockaddr_in));

	freeaddrinfo(result);

	return 0;
}

/*----------------------- 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 */

     struct sockaddr_in addr;

     if (getInfoFromHostName(HostName,&addr) != 0)
    	 return NOHOST;

     unsigned int b1, b2, b3, b4;
     sscanf(inet_ntoa( addr.sin_addr), "%3u.%3u.%3u.%3u", &b1, &b2, &b3, &b4);
     snprintf(UserHost, MAXHOSTLENGTH, "%03u.%03u.%03u.%03u", 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 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));

   if (getInfoFromHostName(RemSerName,&IntAFAddr) != 0)
	   return NOHOST;

   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((SocketID = socket(AF_INET,SOCK_STREAM,PROTOCOL)) < 0)
   {
      perror("Socket:"); return(-1);
   }

   /* 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]);

    //BRE - When the corresponding time is the last one of a file, MOREDATA is returned by DDServer.
    // => force recall of DD_GetData to open the next file and finish correctly the request
    if (err == MOREDATA)
    {
    	if ((err = DD_GetData(VarID, (char *)"Time", TimeInt, &data)) < 0)
        {
    		while ((err == WAITEXTCALL) || (err == TRYAGAIN))
        	{
    			sleep(2);
        	    err = DD_GetData(VarID, (char *)"Time", TimeInt, &data);
        	}
        }
    }

   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 -------------------------------*/