/*============================================================== * 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 #include #include #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 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\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; Cache_Init(); 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); Cache_Free(); return 0; }