/******************************************************************************/ /** Copyright 2005 MBARI - Monterey Bay Aquarium Research Institute */ /******************************************************************************/ /******************************************************************************/ /** Filename : LOBOSERV.C */ /** Author : Luke Coletti */ /** Project : 600144 */ /** Version : 1.00 */ /** Created : 01/03/05 */ /** Compiler : gcc version 3.0.1 */ /** OS, Box : IRIX Release 6.5 IP27, lepas.mbari.org */ /** Archived : */ /** Summary : Manages the socket connections from the field Access Points, */ /** Cirronet SNAP2410, via inetd. */ /******************************************************************************/ /** Modification History: */ /** 11/04/05 - LJC - Added e-mail notification upon server timeout */ /** 04/15/06 - LJC - Added LOBOTALK function(s) */ /******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #define READ_TIMEOUT 5 //in seconds #define READ_MAIN_TIMEOUT 15 //in seconds #define MAX_RETRIES 5 #define MAX_SYNC_DELTA 2 //in seconds #define TRUE 1 #define FALSE 0 #define OK 0 #define ERROR (-1) #define TIMEOUT (-2) #define DISCONNECT (-3) #define LOBOTALK_SERVER_NOT_AVAILABLE 10 #define LOBOTALK_SERVER_CONNECT_DECLINED 20 #define LOBOTALK_SERVER_CONNECT_ACCEPTED 30 #define LOBOTALK_SERVER_SOCKET_ERROR (-10) #define LOBOTALK_SERVER_ADDRESS_ERROR (-20) #define LOBOTALK_SERVER_CONNECT_ERROR (-30) #define LOBOTALK_SERVER_READ_ERROR (-40) #define SENDMAIL "/usr/lib/sendmail -t" #define SENDER "coletti@mbari.org" #define RECIPIENT "coletti@mbari.org" long SyncClocks(int retries); int FstatFile(int retries); int SendPID(int retries); int TalkModeClientAck(int retries, char *msg, int val); int TalkModeServerAck(int retries); int TalkMode(int fds); int MoveInFileToOut(char *fname); int MatchPathToPort(unsigned short port); int MatchIDToPort(unsigned short port, char *ID); int MatchCommand(char *cmd); int DisplayBanner(void); void DisplayCommands(void); int SendMessage(char *msg); int WrData(int fds, char *tx_buf, int num); ssize_t RdData(int fds, char *rx_buf, size_t len, ushort tm_out); void RecordLastTransmission(char *filename, long filesize); void UpdateErrorLogFile(char *emsg); void UpdateZmodemLogFile(char *msg); void SendEmail(char *subject, char *message); enum LoboCommands{LoboDisplayBanner=0, LoboSyncToUtcTime, LoboReceiveZmodemFile, LoboFileStatus, LoboPingServer, LoboTransmitPID, LoboTalkMode, LoboServerCommands, LoboCloseServer, LoboCommandsEnd}; static char *commands[] = {"LOBOBANNER", "LOBOSYNCTIME", "LOBOZMODEM", "LOBOFSTAT", "LOBOPING", "LOBOPID", "LOBOTALK", "LOBOHELP", "LOBOQUIT"}; enum LoboTcpPorts{LoboPortsBeg=1999, BENCHTEST, L01, L02, L03, L04, L05, LoboPortsEnd}; static char *data_dirs[] = {"test", "L01", "L02", "L03", "L04", "L05"}; static char data_path_in[100] = "/u/coletti/lobo/incoming/"; static char data_path_out[100] = "/u/coletti/lobo/outgoing/"; static time_t timer; static struct tm *timeptr; static struct sockaddr_in addr_clnt; int main(int argc, char **argv, char **envp) { char rbuf[256]; //recv buf char cbuf[256]; //cmd buf char ebuf[256]; //emsg buf char sbuf[256]; //subject buf char mbuf[128]; //message buf char *ptr, *rptr; int command, gotConnect; int ret, zmod_ret, addr_len; long delta; time_t start_time, current_time; ssize_t read_ret; if( isatty(0) ){ fprintf(stderr,"This program was meant to run out of inetd\n"); exit(ERROR); } putenv("TZ=PST8PDT"); tzset(); time(&start_time); //find out who we're talking to addr_len = sizeof(addr_clnt); getpeername(STDIN_FILENO, (struct sockaddr *)&addr_clnt, &addr_len); MatchPathToPort( (unsigned)ntohs(addr_clnt.sin_port) ); //test if file system "Tepmest" is mounted! if( (ret = access("/u/coletti/lobo/", F_OK)) != OK ){ snprintf(sbuf, sizeof(sbuf)-1, "Tempest Mount Access Error"); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, main() - access() ret = %d - Tempest File System Unavailable", ret); SendEmail(sbuf, ebuf); return( OK ); } rptr = (char *)rbuf; memset(rbuf, '\0', sizeof(rbuf)); gotConnect = FALSE; while( 1 ){ time(¤t_time); if( difftime(current_time, start_time) >= 300.0){ // 5min server timeout snprintf(ebuf, sizeof(ebuf)-1, "ERROR, main() - 5min Server Timeout"); UpdateErrorLogFile(ebuf); snprintf(sbuf, sizeof(sbuf)-1, "LOBOSERV Timeout Error"); snprintf(ebuf, sizeof(ebuf)-1, "5min Server Timeout, SNAP [%s:%u] could be hung!", inet_ntoa(addr_clnt.sin_addr), (unsigned)ntohs(addr_clnt.sin_port)); SendEmail(sbuf, ebuf); return( OK ); } read_ret = RdData(STDIN_FILENO, rbuf, sizeof(rbuf), READ_MAIN_TIMEOUT); if( read_ret == ERROR ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, main() - RdData() = ERROR"); UpdateErrorLogFile(ebuf); return( OK ); } else if( read_ret == TIMEOUT ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, main() - RdData() = TIMEOUT"); UpdateErrorLogFile(ebuf); } else if( read_ret == DISCONNECT ){ // Got Disconnect if( gotConnect == FALSE ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, main() - RdData() = DISCONNECT"); UpdateErrorLogFile(ebuf); } return( OK ); } else{ //we got something, so, let's gather until we can't hold no mo while( read_ret > 0 ){ if( memchr(rbuf, '}', sizeof(rbuf)-2) != NULL ){ //found the message tail if( (ptr=memchr(rbuf, '{', sizeof(rbuf)-1)) != NULL ){ //is the message head still around if( (ptr=memccpy(mbuf, ptr, '}', sizeof(mbuf)-1)) != NULL){ //copy it into the msg buf *ptr = '\0'; //null terminate it if( (command = MatchCommand(mbuf)) != ERROR){ switch (command){ case LoboDisplayBanner: SendMessage("{ACK}"); DisplayBanner(); break; case LoboSyncToUtcTime: SendMessage("{ACK}"); delta = SyncClocks(MAX_RETRIES); break; case LoboReceiveZmodemFile: SendMessage("{ACK}"); memset(cbuf, '\0', sizeof(cbuf)); snprintf(cbuf, sizeof(cbuf), "(cd %s ; /u/coletti/bin/qrz)", data_path_in); zmod_ret = system(cbuf); time(&start_time); // don't let a long file tranmission result in a server timeout if( zmod_ret != OK ){ snprintf(mbuf, sizeof(mbuf)-1, "ERROR, Zmodem Ret = %d", zmod_ret); UpdateZmodemLogFile(mbuf); } break; case LoboFileStatus: SendMessage("{ACK}"); FstatFile(MAX_RETRIES); break; case LoboPingServer: SendMessage("{ACK}"); gotConnect = TRUE; //make it simple to "connect", need to screen out the riff-raff for zmodem start break; case LoboTransmitPID: SendMessage("{ACK}"); SendPID(MAX_RETRIES); break; case LoboTalkMode: SendMessage("{ACK}"); if( TalkModeClientAck(MAX_RETRIES, "TALK", (int)ntohs(addr_clnt.sin_port)) == TRUE ){ TalkModeServerAck(MAX_RETRIES); } break; case LoboServerCommands: SendMessage("{ACK}"); DisplayCommands(); break; case LoboCloseServer: SendMessage("{ACK}"); return( OK ); } // end switch // clear buf and start again break; } // end MatchCommand() if else{ // couldn't match the command, clear buf and start again // signal sender to try again SendMessage("{NAK}"); break; } } // end memccpy() if else{ // memccpy() failed, clear buf and start again // signal sender to try again SendMessage("{NAK}"); break; } } // end memchr({) if // found tail but no head, clear buf and start again else break; } // end memchr(}) if //must need mo! rptr += read_ret; if( (rptr >= ((char *)rbuf+sizeof(rbuf))) ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, main() - rptr grew too BIG"); UpdateErrorLogFile(ebuf); break; } else read_ret=RdData(STDIN_FILENO, rptr, (size_t)(((char *)rbuf+sizeof(rbuf))-rptr), READ_MAIN_TIMEOUT); } //end inner while //reset pointer into rbuf and purge rptr = (char *)rbuf; memset(rbuf, '\0', sizeof(rbuf)); }// end read_ret else }//end forever while return( OK ); } long SyncClocks(int retries) { char tbuf[256]; //xmit buf char rbuf[256]; //recv buf char ebuf[256]; //emsg buf char mbuf[256]; //message buf char *ptr, *rptr; int i, j, tzoffset, send_ret; int gotSomething, gotDataVals; int tz_rxd; time_t time_rxd; ssize_t read_ret; rptr = (char *)rbuf; memset(rbuf, '\0', sizeof(rbuf)); gotSomething = FALSE; for(i = 1; i <= retries; i++){ //transmit the SYNC MESSAGE memset(tbuf, '\0', sizeof(tbuf)); time(&timer); //epoch UTC secs timeptr = localtime(&timer); if(timeptr->tm_isdst) tzoffset = 7; else tzoffset = 8; snprintf(tbuf, sizeof(tbuf), "{SYNCTIME, %lu, %d}", timer, tzoffset); if( (send_ret=SendMessage(tbuf)) < 0 ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SyncClocks() - WrData() error - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); } if( (read_ret=RdData(STDIN_FILENO, rbuf, sizeof(rbuf), READ_TIMEOUT)) == ERROR ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SyncClocks() - RdData() error - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); return( ERROR ); } else if( read_ret == DISCONNECT ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SyncClocks() - Got Disconnect - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); return( DISCONNECT ); } else{ gotSomething = TRUE; //we got something, so, let's gather until we can't hold no mo while( read_ret > 0 ){ //are they still sending the original command, i.e., they didn't get the ACK if( strstr(rbuf, "{LOBOSYNCTIME}") != NULL ){ SendMessage("{ACK}"); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SyncClocks() - Received Repeated Entry Command"); UpdateErrorLogFile(ebuf); break; } //we got a NAK, resend SYNC MESSAGE! if( strstr(rbuf, "{NAK}") != NULL ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SyncClocks() - Received NAK"); UpdateErrorLogFile(ebuf); break; } //if we see the end let's go for it! else if( memchr(rbuf, '}', sizeof(rbuf)-2) != NULL ){ //found the message tail if( (ptr=strstr(rbuf, "{SYNC,")) != NULL ){ //is the message head still around if( (ptr=memccpy(mbuf, ptr, '}', sizeof(mbuf)-1)) != NULL){ //copy it into the msg buf *ptr = '\0'; j = gotDataVals = 0; time_rxd = 0; ptr = strtok(mbuf, ","); while( (ptr = strtok(NULL, ",")) != NULL ){ ++j; if(j == 1){ time_rxd = (time_t)atol(ptr); ++gotDataVals; } if(j == 2){ tz_rxd = atoi(ptr); ++gotDataVals; } } //end strtok while if( gotDataVals == 2 ){ //confirm that it got there and came back in a reasonable amount of time! time(&timer); if( difftime(timer, time_rxd) <= MAX_SYNC_DELTA ){ snprintf(tbuf, sizeof(tbuf), "{ACK, SYNCTIME}"); SendMessage(tbuf); return( (timer-time_rxd) ); } else{ //let's do it again! snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SyncClocks() - Time Delta Out of Range = %ld", (long)(timer - time_rxd) ); UpdateErrorLogFile(ebuf); break; } } //end gotDataVals if else{ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SuncClocks() - strtok could not parse string: %s", rbuf); UpdateErrorLogFile(ebuf); break; } } //end memccpy if } //end found head if } //end found tail if //must need mo! rptr += read_ret; if( (rptr >= ((char *)rbuf+sizeof(rbuf))) ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SyncClocks() - rptr grew too BIG"); UpdateErrorLogFile(ebuf); break; } else read_ret=RdData(STDIN_FILENO, rptr, (size_t)(((char *)rbuf+sizeof(rbuf))-rptr), READ_TIMEOUT); }//end while loop //we got some valid characters but it wasn't what we needed //re-attempt to implement the service, if there are retries left! //reset pointer into rbuf and purge rptr = (char *)rbuf; memset(rbuf, '\0', sizeof(rbuf)); //signal receiver we're going to try again snprintf(tbuf, sizeof(tbuf), "{NAK, SYNCTIME}"); SendMessage(tbuf); }// end read_ret else }//end i loop if(gotSomething == FALSE) return( TIMEOUT ); else return( ERROR ); } int FstatFile(int retries) { char tbuf[256]; //xmit buf char rbuf[256]; //recv buf char ebuf[256]; //emsg buf char mbuf[256]; //message buf char fname[64]; //storage for LOBO Controller file name char fpath[512]; char *ptr, *rptr; int i, j, ret; int gotSomething, gotDataVals; int statret; long fbytes; struct stat statbuf; ssize_t read_ret; FILE *in; rptr = (char *)rbuf; memset(rbuf, '\0', sizeof(rbuf)); gotSomething = FALSE; for(i = 1; i <= retries; i++){ if( (read_ret=RdData(STDIN_FILENO, rbuf, sizeof(rbuf), READ_TIMEOUT)) == ERROR){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, FstatFile() - RdData() error - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); return( ERROR ); } else if( read_ret == DISCONNECT ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, FstatFile() - Got Disconnect - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); return( DISCONNECT ); } else{ gotSomething = TRUE; //we got something, so, let's gather until we can't hold no mo while( read_ret > 0 ){ //are they still sending the original command, i.e., they didn't get the ACK if( strstr(rbuf, "{LOBOFSTAT}") != NULL ){ SendMessage("{ACK}"); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, FstatFile() - Received Repeated Entry Command"); UpdateErrorLogFile(ebuf); break; } //if we see the end let's go for it! else if( memchr(rbuf, '}', sizeof(rbuf)-2) != NULL ){ //found the message tail if( (ptr=strstr(rbuf, "{FNAMEFSIZE,")) != NULL ){ if( (ptr=memccpy(mbuf, ptr, '}', sizeof(mbuf)-1)) != NULL){ //copy it into the msg buf *ptr = '\0'; j = gotDataVals = 0; fbytes = 0L; ptr = strtok(mbuf, ","); while( (ptr = strtok(NULL, ",")) != NULL ){ ++j; if(j == 1){ while(strchr(ptr, ' ') != NULL) //skip white spaces ++ptr; strncpy(fname, ptr, sizeof(fname)-1); ++gotDataVals; } if(j == 2){ fbytes = atol(ptr); ++gotDataVals; } } //end strtok while if( gotDataVals == 2 ){ //process the file name info memset(fpath, '\0', sizeof(fpath)); strcpy(fpath, data_path_in); strcat(fpath, "/"); strcat(fpath, fname); //process the file size info //confirm that the file exits and is the same size if( (in = fopen(fpath, "r")) != NULL){ errno = 0; if( (statret = fstat(fileno(in), &statbuf)) != 0){ fclose(in); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, FstatFile() - file error = %d for: %s", errno, fpath); UpdateErrorLogFile(ebuf); break; } if(statbuf.st_size != fbytes){ fclose(in); // added 02/09/06 to remove file upon failed fstat() if(i == retries) remove(fpath); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, FstatFile() - file length = %ld did not match provided length = %ld for: %s", statbuf.st_size, fbytes, fpath); UpdateErrorLogFile(ebuf); break; } fclose(in); snprintf(tbuf, sizeof(tbuf), "{ACK, FSTAT}"); SendMessage(tbuf); if( (ret=MoveInFileToOut(fname)) != OK){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, FstatFile() - file move ret = %d for: %s", ret, fpath); UpdateErrorLogFile(ebuf); return( FALSE ); } else{ RecordLastTransmission(fname, fbytes); return( TRUE ); } } //end fopen if else{ //let's do it again! fclose(in); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, FstatFile() - could not open file given: [%s] with size: %lu", fpath, fbytes); UpdateErrorLogFile(ebuf); break; } } //end gotDataVals if else{ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, FstatFile() - strtok could not parse string: %s", rbuf); UpdateErrorLogFile(ebuf); break; } } //end memccpy if } //end found head if } //end found tail if //must need mo! rptr += read_ret; if( (rptr >= ((char *)rbuf+sizeof(rbuf))) ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, FstatFile() - rptr grew too BIG"); UpdateErrorLogFile(ebuf); break; } else read_ret=RdData(STDIN_FILENO, rptr, (size_t)(((char *)rbuf+sizeof(rbuf))-rptr), READ_TIMEOUT); }//end while loop //we got some valid characters but it wasn't what we needed //re-attempt to implement the service, if there are retries left! //reset pointer into rbuf and purge rptr = (char *)rbuf; memset(rbuf, '\0', sizeof(rbuf)); //signal receiver we're going to try again snprintf(tbuf, sizeof(tbuf), "{NAK, FSTAT}"); SendMessage(tbuf); }// end read_ret else }//end i loop if(gotSomething == FALSE) return( TIMEOUT ); else return( ERROR ); } int SendPID(int retries) { char tbuf[256]; //xmit buf char rbuf[8192]; //recv buf char ebuf[256]; //emsg buf char *rptr; int i, send_ret; int gotSomething; ssize_t read_ret; rptr = (char *)rbuf; memset(rbuf, '\0', sizeof(rbuf)); gotSomething = FALSE; for(i = 1; i <= retries; i++){ //transmit the PID MESSAGE memset(tbuf, '\0', sizeof(tbuf)); snprintf(tbuf, sizeof(tbuf), "{PID, %ld}", getpid() ); if( (send_ret=SendMessage(tbuf)) < 0 ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SendPID() - WrData() error - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); } if( (read_ret=RdData(STDIN_FILENO, rbuf, sizeof(rbuf), READ_TIMEOUT)) == ERROR){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SendPID() - RdData() error - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); return( ERROR ); } else if( read_ret == DISCONNECT ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SendPID() - Got Disconnect - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); return( DISCONNECT ); } else{ gotSomething = TRUE; //we got something, so, let's gather until we can't hold no mo while( read_ret > 0 ){ //are they still sending the original command, i.e., they didn't get the ACK if( strstr(rbuf, "{LOBOPID}") != NULL ){ SendMessage("{ACK}"); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SendPID() - Received Repeated Entry Command"); UpdateErrorLogFile(ebuf); break; } //we got a NAK, resend PID MESSAGE! if( strstr(rbuf, "{NAK}") != NULL ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SendPID() - Received NAK"); UpdateErrorLogFile(ebuf); break; } //we got the ACK, we're done! if( strstr(rbuf, "{ACK}") != NULL ){ return( TRUE ); } //must need mo! rptr += read_ret; if( (rptr >= ((char *)rbuf+sizeof(rbuf))) ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, SendPID() - rptr grew too BIG"); UpdateErrorLogFile(ebuf); break; } else read_ret=RdData(STDIN_FILENO, rptr, (size_t)(((char *)rbuf+sizeof(rbuf))-rptr), READ_TIMEOUT); }//end while loop //we got some valid characters but it wasn't what we needed //re-attempt to implement the service, if there are retries left! //reset pointer into rbuf and purge rptr = (char *)rbuf; memset(rbuf, '\0', sizeof(rbuf)); //signal receiver we're going to try again snprintf(tbuf, sizeof(tbuf), "{NAK, PID}"); SendMessage(tbuf); }// end read_ret else }//end i loop if(gotSomething == FALSE) return( TIMEOUT ); else return( ERROR ); } int TalkModeClientAck(int retries, char *msg, int val) { char tbuf[256]; //xmit buf char rbuf[8192]; //recv buf char ebuf[256]; //emsg buf char *rptr; int i, send_ret; int gotSomething; ssize_t read_ret; rptr = (char *)rbuf; memset(rbuf, '\0', sizeof(rbuf)); gotSomething = FALSE; for(i = 1; i <= retries; i++){ //transmit the RESPONSE MESSAGE memset(tbuf, '\0', sizeof(tbuf)); snprintf(tbuf, sizeof(tbuf), "{%s, %d}", msg, val); if( (send_ret=SendMessage(tbuf)) < 0 ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, TalkModeClientAck() - WrData() error - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); } if( (read_ret=RdData(STDIN_FILENO, rbuf, sizeof(rbuf), READ_TIMEOUT)) == ERROR){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, TalkModeClientAck() - RdData() error - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); return( ERROR ); } else if( read_ret == DISCONNECT ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, TalkModeClientAck() - Got Disconnect - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); return( DISCONNECT ); } else{ gotSomething = TRUE; //we got something, so, let's gather until we can't hold no mo while( read_ret > 0 ){ //are they still sending the original command, i.e., they didn't get the ACK if( strstr(rbuf, "{LOBOTALK}") != NULL ){ SendMessage("{ACK}"); snprintf(ebuf, sizeof(ebuf)-1, "ERROR, TalkModeClientAck() - Received Repeated Entry Command"); UpdateErrorLogFile(ebuf); break; } //we got a NAK, resend MESSAGE! if( strstr(rbuf, "{NAK}") != NULL ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, TalkModeClientAck() - Received NAK"); UpdateErrorLogFile(ebuf); break; } //we got the ACK from the client if( strstr(rbuf, "{ACK}") != NULL ){ return( TRUE ); } //must need mo! rptr += read_ret; if( (rptr >= ((char *)rbuf+sizeof(rbuf))) ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, TalkModeClientAck() - rptr grew too BIG"); UpdateErrorLogFile(ebuf); break; } else read_ret=RdData(STDIN_FILENO, rptr, (size_t)(((char *)rbuf+sizeof(rbuf))-rptr), READ_TIMEOUT); }//end while loop //we got some valid characters but it wasn't what we needed //re-attempt to implement the service, if there are retries left! //reset pointer into rbuf and purge rptr = (char *)rbuf; memset(rbuf, '\0', sizeof(rbuf)); //signal receiver we're going to try again snprintf(tbuf, sizeof(tbuf), "{NAK, CLIENTACK}"); SendMessage(tbuf); }// end read_ret else }//end i loop if(gotSomething == FALSE) return( TIMEOUT ); else return( ERROR ); } int TalkModeServerAck(int retries) { char tbuf[256]; //xmit buf char rbuf[8192]; //recv buf char ebuf[256]; //emsg buf char ID[64]; //string showing the ID of the caller, set in MatchIDToPort char *rptr; int i, n, tm_ret, send_ret; int gotSomething; ssize_t read_ret; struct sockaddr_in talk_addr; char *host_addr ="134.89.10.76"; /* IP address for MBARI computer (lepas) */ int talk_port = 52334; /* port number for lobotalk on lepas */ int talk_sock = 0; /* Create a TCP/IP socket to use */ talk_sock = socket(AF_INET, SOCK_STREAM, 0); if( talk_sock < 0 ){ close(talk_sock); n = sizeof(ebuf) - 1; snprintf(ebuf, n, "ERROR, TalkModeServerAck() - socket()"); n = n - strlen(ebuf); if( errno != 0 ) snprintf(ebuf+strlen(ebuf), n, " - %s : errno = %d", strerror(errno), errno); UpdateErrorLogFile(ebuf); TalkModeClientAck(MAX_RETRIES, "SERVER_MSG", LOBOTALK_SERVER_SOCKET_ERROR); return( LOBOTALK_SERVER_SOCKET_ERROR ); } /* set the server's socket address */ memset(&talk_addr, 0, sizeof(talk_addr)); talk_addr.sin_family = AF_INET; talk_addr.sin_port = htons(talk_port); talk_addr.sin_addr.s_addr = inet_addr(host_addr); if( talk_addr.sin_addr.s_addr == INADDR_NONE ){ close(talk_sock); n = sizeof(ebuf) - 1; snprintf(ebuf, n, "ERROR, TalkModeServerAck() - bad address"); n = n - strlen(ebuf); if( errno != 0 ) snprintf(ebuf+strlen(ebuf), n, " - %s : errno = %d", strerror(errno), errno); UpdateErrorLogFile(ebuf); TalkModeClientAck(MAX_RETRIES, "SERVER_MSG", LOBOTALK_SERVER_ADDRESS_ERROR); return( LOBOTALK_SERVER_ADDRESS_ERROR ); } if( connect(talk_sock, (struct sockaddr *)&talk_addr, sizeof(talk_addr)) < 0 ){ close(talk_sock); if( errno == ECONNREFUSED ){ //server is NOT running TalkModeClientAck(MAX_RETRIES, "SERVER_MSG", LOBOTALK_SERVER_NOT_AVAILABLE); return( LOBOTALK_SERVER_NOT_AVAILABLE ); } else { n = sizeof(ebuf) - 1; snprintf(ebuf, n, "ERROR, TalkModeServerAck() - connect()"); n = n - strlen(ebuf); if( errno != 0 ) snprintf(ebuf+strlen(ebuf), n, " - %s : errno = %d", strerror(errno), errno); UpdateErrorLogFile(ebuf); TalkModeClientAck(MAX_RETRIES, "SERVER_MSG", LOBOTALK_SERVER_CONNECT_ERROR); return( LOBOTALK_SERVER_CONNECT_ERROR ); } } MatchIDToPort( (unsigned)ntohs(addr_clnt.sin_port), ID ); rptr = (char *)rbuf; memset(rbuf, '\0', sizeof(rbuf)); gotSomething = FALSE; for(i = 1; i <= retries; i++){ //transmit the TALK REQUEST MESSAGE memset(tbuf, '\0', sizeof(tbuf)); snprintf(tbuf, sizeof(tbuf), "{TALK, %s}", ID ); if( ( send_ret=write(talk_sock, tbuf, (int)strlen(tbuf)) ) < 0 ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, TalkModeServerAck() - WrData() error - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); continue; } if( ( read_ret=RdData(talk_sock, rbuf, sizeof(rbuf), READ_TIMEOUT) ) == ERROR){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, TalkModeServerAck() - RdData() error - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); close(talk_sock); TalkModeClientAck(MAX_RETRIES, "SERVER_MSG", LOBOTALK_SERVER_READ_ERROR); return( LOBOTALK_SERVER_READ_ERROR ); } else if( read_ret == DISCONNECT ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, TalkModeServerAck() - Got Disconnect - at loop = %d - gotSomething = %d", i, gotSomething); UpdateErrorLogFile(ebuf); close(talk_sock); return( DISCONNECT ); } else{ gotSomething = TRUE; //we got something, so, let's gather until we can't hold no mo while( read_ret > 0 ){ //we got a NAK from the server, resend MESSAGE! if( strstr(rbuf, "{NAK}") != NULL ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, TalkModeServerAck() - Received NAK"); UpdateErrorLogFile(ebuf); break; } //server sez, get lost creep! if( strstr(rbuf, "{NO}") != NULL ){ close(talk_sock); TalkModeClientAck(MAX_RETRIES, "SERVER_MSG", LOBOTALK_SERVER_CONNECT_DECLINED); return( LOBOTALK_SERVER_CONNECT_DECLINED ); } //we got the go ahead from the server if( strstr(rbuf, "{YES}") != NULL ){ TalkModeClientAck(MAX_RETRIES, "SERVER_MSG", LOBOTALK_SERVER_CONNECT_ACCEPTED); tm_ret = TalkMode(talk_sock); close(talk_sock); return( tm_ret ); } //must need mo! rptr += read_ret; if( (rptr >= ((char *)rbuf+sizeof(rbuf))) ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, TalkModeServerAck() - rptr grew too BIG"); UpdateErrorLogFile(ebuf); break; } else read_ret=RdData(talk_sock, rptr, (size_t)(((char *)rbuf+sizeof(rbuf))-rptr), READ_TIMEOUT); }//end while loop //we got some valid characters but it wasn't what we needed //re-attempt to implement the service, if there are retries left! //reset pointer into rbuf and purge rptr = (char *)rbuf; memset(rbuf, '\0', sizeof(rbuf)); //signal receiver we're going to try again snprintf(tbuf, sizeof(tbuf), "{NAK, SERVERACK}"); SendMessage(tbuf); }// end read_ret else }//end i loop close(talk_sock); return( ERROR ); } int TalkMode(int fds) { return( OK ); } int MoveInFileToOut(char *fname) { char tbuf[512]; char fpath1[256]; char fpath2[256]; int ret; memset(fpath1, '\0', sizeof(fpath1)); strcpy(fpath1, data_path_in); strcat(fpath1, "/"); strcat(fpath1, fname); memset(fpath2, '\0', sizeof(fpath2)); strcpy(fpath2, data_path_out); strcat(fpath2, "/"); strcat(fpath2, fname); snprintf(tbuf, sizeof(tbuf), "(/u/coletti/bin/mv --backup --force %s %s)", fpath1, fpath2); ret = system(tbuf); return( ret ); } int MatchPathToPort(unsigned short port) { int choice, gotPort, i; gotPort = i = 0; choice = LoboPortsBeg+1; while(choice < LoboPortsEnd){ if(choice == port){ strcat(data_path_in, data_dirs[i]); strcat(data_path_out, data_dirs[i]); gotPort = TRUE; break; } ++i; ++choice; } if(gotPort == FALSE){ strcat(data_path_in, "lostandfound"); strcat(data_path_out, "lostandfound"); } return( gotPort ); } int MatchIDToPort(unsigned short port, char *ID) { int choice, gotID, i; gotID = i = 0; choice = LoboPortsBeg+1; while(choice < LoboPortsEnd){ if(choice == port){ strcpy(ID, data_dirs[i]); gotID = TRUE; break; } ++i; ++choice; } if(gotID == FALSE){ strcpy(ID, "NOMATCH"); } return( gotID ); } int MatchCommand(char *cmd) { int choice; for (choice=0; (choice < LoboCommandsEnd); choice++) { if( strstr(cmd, commands[choice]) != NULL ) return choice; } return(ERROR); } void DisplayCommands(void) { int choice; printf("Lobo Server Commands:\r\n"); for (choice=0; (choice < LoboCommandsEnd); choice++) { printf("%s\r\n", commands[choice]); } printf("\r\n"); fflush(stdout); } int DisplayBanner(void) { char tbuf[250]; //let the world know who they are talking to and who we think is calling! time(&timer); timeptr = gmtime(&timer); strftime(tbuf, sizeof(tbuf), "\r\n%a %d %b %Y %H:%M:%S, ", timeptr); snprintf(tbuf+strlen(tbuf), sizeof(tbuf), "Welcome %s:%u to loboserv, PID = %ld.\r\n", inet_ntoa(addr_clnt.sin_addr), (unsigned)ntohs(addr_clnt.sin_port), getpid() ); snprintf(tbuf+strlen(tbuf), sizeof(tbuf), "Resolved Data Path = %s\r\n", data_path_in); return( WrData(STDOUT_FILENO, tbuf, (int)strlen(tbuf)) ); } // We play ping pong with strings, therefore, // make sure the outgoing message is appended // with a CRLF pair. Makes it nice for gets() // or whatever, on the other side... int SendMessage(char *msg) { char tbuf[256]; snprintf(tbuf, sizeof(tbuf)-1, "%s\r\n", msg); if( WrData(STDOUT_FILENO, tbuf, (int)strlen(tbuf)) < 0 ) return( ERROR ); else return( OK ); } /************************************************************************/ /* Function : WrData */ /* Purpose : */ /* Input : None */ /* Outputs : None */ /* Comments : */ /************************************************************************/ int WrData(int fds, char *tx_buf, int num) { ssize_t send_ret; char ebuf[256]; if( fds == STDOUT_FILENO ){ fflush(stdin); //flush input stream buffer do { clearerr(stdout); send_ret = write(fds, tx_buf, num); } while ( ferror(stdout) && (errno == EINTR) ); if( fds == STDOUT_FILENO ) fflush(stdout); //flush output stream buffer } else send_ret = write(fds, tx_buf, num); if( send_ret < 0 ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, WrData() - write() ret = %d - errno = %s", (int)send_ret, strerror(errno)); UpdateErrorLogFile(ebuf); return( ERROR ); } else return( OK ); } /************************************************************************/ /* Function : RdData */ /* Purpose : */ /* Input : None */ /* Outputs : None */ /* Comments : */ /************************************************************************/ ssize_t RdData(int fds, char *rx_buf, size_t len, ushort tm_out) { char ebuf[256]; int sel_ret; fd_set rx_set; struct timeval tmout; ssize_t read_ret; FD_ZERO(&rx_set); FD_SET(fds, &rx_set); tmout.tv_sec = tm_out; tmout.tv_usec = 0; do { sel_ret = select(FD_SETSIZE, &rx_set, NULL, NULL, &tmout); } while ( (sel_ret == -1) && (errno == EINTR) ); if( sel_ret == 0 ) return( TIMEOUT ); else if( sel_ret < 0 ){ snprintf(ebuf, sizeof(ebuf)-1, "ERROR, RdDataD() - select() ret = %d - errno = %s", sel_ret, strerror(errno)); UpdateErrorLogFile(ebuf); return( ERROR ); } if( fds == STDIN_FILENO ){ do { clearerr(stdin); read_ret = read(fds, rx_buf, len); } while ( ferror(stdin) && (errno == EINTR) ); } else read_ret = read(fds, rx_buf, len); if( read_ret == 0 ) return( DISCONNECT ); else if( read_ret < 0 ) { snprintf(ebuf, sizeof(ebuf)-1, "ERROR, RdData() - read() ret = %d - errno = %s", (int)read_ret, strerror(errno)); UpdateErrorLogFile(ebuf); return( ERROR ); } else return( read_ret ); } /************************************************************************/ /* Function : RecordLastTransmission */ /* Purpose : keep a record of last successful file tranmission */ /* Input : None */ /* Outputs : None */ /* Comments : */ /************************************************************************/ void RecordLastTransmission(char *filename, long filesize) { FILE *logfile; char pbuf[256]; char timebuf[64]; time(&timer); timeptr = localtime(&timer); strftime(timebuf, sizeof(timebuf)-1, "%m/%d/%Y %H:%M:%S", timeptr); snprintf(pbuf, sizeof(pbuf), "%s/lastfile.log", data_path_out); logfile = fopen(pbuf, "w"); fprintf(logfile,"%lu,%s,%s,%ld\r\n", timer, timebuf, filename, filesize); fflush(logfile); fclose(logfile); } /************************************************************************/ /* Function : UpdateErrorLogFile */ /* Purpose : keep a usage log of all unsuccessful sessions */ /* Input : None */ /* Outputs : None */ /* Comments : */ /************************************************************************/ void UpdateErrorLogFile(char *emsg) { FILE *logfile; char timebuf[64]; char ID[64]; //string showing the ID of the caller, set in MatchIDToPort time(&timer); timeptr = localtime(&timer); MatchIDToPort( (unsigned)ntohs(addr_clnt.sin_port), ID ); strftime(timebuf, sizeof(timebuf)-1, "%a %d %b %Y %H:%M:%S", timeptr); logfile = fopen("/u/coletti/lobo/logs/loboserv.log", "a+"); fprintf(logfile,"%s, %s, %s, %ld, %s, %u\r\n", ID, emsg, timebuf, getpid(), inet_ntoa(addr_clnt.sin_addr), (unsigned)ntohs(addr_clnt.sin_port)); fflush(logfile); fclose(logfile); } /************************************************************************/ /* Function : UpdateZmodemLogFile */ /* Purpose : keep a usage log of all unsuccessful sessions */ /* Input : None */ /* Outputs : None */ /* Comments : */ /************************************************************************/ void UpdateZmodemLogFile(char *msg) { FILE *logfile; char timebuf[64]; char ID[64]; //string showing the ID of the caller, set in MatchIDToPort time(&timer); timeptr = localtime(&timer); MatchIDToPort( (unsigned)ntohs(addr_clnt.sin_port), ID ); strftime(timebuf, sizeof(timebuf)-1, "%a %d %b %Y %H:%M:%S ", timeptr); logfile = fopen("/u/coletti/lobo/logs/zmodem.log", "a+"); fprintf(logfile,"%s, %s, %s, %ld, %s, %u\r\n", ID, msg, timebuf, getpid(), inet_ntoa(addr_clnt.sin_addr), (unsigned)ntohs(addr_clnt.sin_port)); fflush(logfile); fclose(logfile); } void SendEmail(char *subject, char *message) { FILE *out; out = popen(SENDMAIL, "w"); fprintf(out, "From: %s <%s>\n", "LoboServ", SENDER); fprintf(out, "To: %s\n", RECIPIENT); fprintf(out, "Subject: %s\n", subject); fprintf(out, "\n \n"); fprintf(out, "%s", message); fprintf(out, "\n \n"); pclose(out); }