Link to home
Start Free TrialLog in
Avatar of rkneal
rkneal

asked on

Can a socket expert on Unix review this code. In current state it is acting a little flakey! Errors out.

can i pay someone with more smarts than me to review this socket code in unix c.

I want to make it more robust, it seems to error out a lot.  Any pointers, hints, suggestions would be great.  It only has one client connected to it at any time, it receives and sends information.  

Thanks

<email id removed by sunnycoder, Page Editor>











#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "/wdpf/rel/ssw/shc/inc/SHC_err.h"
#include "/wdpf/rel/ssw/shc/inc/spd.h"
#include "pointServer.h"
#include <signal.h>
#include <unistd.h>


#define TRUE 1
#define FALSE 0
#define anaDB  .01
#define MAXPOINTS 8000
#define RECBUFFSIZE  400000
#define SENDBUFFSIZE 400000
#define MAXRECORDSENDS 100

/* signal stuff */
void update_timer(int);
void cleanup();

#define SCANTIME  1


char debug_msg = FALSE;
int PORT;

void processRead(void);

typedef struct datarec {
       char pn[9];
    int rt;
    unsigned short digital_val;
    unsigned short old_digital_val;
      unsigned short digital_stat;
      unsigned short old_digital_stat;
      unsigned short gp_val;
      unsigned short old_gp_val;
      unsigned short gp_stat;
      unsigned short old_gp_stat;
      unsigned short gp_force_stat;
      unsigned short old_gp_force_stat;
      float av;
    float old_av;      
    unsigned short as;
      unsigned short old_as;
    long sid; } DATAREC;



/* struct datarec *indatap; */
struct datarec indatap[MAXPOINTS];


int numpoints;

FILE *data_lun;
int access_type = RUNTIME;
static char *wdpf_pdir;
long gp_sid = 0;
char gp_bit_num = 0;
char ina_flag;
char ext_flag;
char outbuff[SENDBUFFSIZE];   /* need to dynamically do this! later*/
char inbuff[RECBUFFSIZE];
int file_desc;
int status;
/* char ch[1]; */
int pcalcins, pcalcouts;
int msgsock;
struct tm *local;
Point_entry point_info;
char network_name[8];
unsigned short digital_val;
unsigned short digital_stat;
unsigned short gp_val;
unsigned short gp_stat;
unsigned short gp_force_stat;
char field_name[2];
unsigned char byte_val;
int optlen;
long sockstat;
int ch;

main(int argc, char *argv[])
{

int sock,clientLen,serverLen;
struct sockaddr_in serverAddr, clientAddr;
int i;
char on=1;
int tcpsendbuff, tcprecbuff;
struct linger stLinger;

if(debug_msg)
printf("\nprogram started...");


/** get program command flags **/
/** first argument is port number **/
if(argc < 2) {
  printf("\nincorrect calling parameters;  rt portID <d>  <d> = debug mode");
  exit(0); }

/** see if want to go into debug mode **/
while(--argc >0)
 if(strchr(argv[argc],'d')) {
   debug_msg = TRUE;
   printf("\nentering debug message mode\n"); }

/** get port number from command line **/
PORT = strtol(argv[1],NULL,10);

/** set up WDPF stuff **/
wdpf_pdir = (char *) getenv("WDPF_PDIR");
if(wdpf_pdir == NULL) {
  printf("\nunable to get WDPF_PDIR environment variable");
  exit(1); }

status = SHC_open_memory();
if(status != SHC_OK) {
  printf("\nSHC_open_memory error -- status = %d",status);
  exit(1); }

file_desc = SPD_open_file(wdpf_pdir,&access_type);
if(file_desc < 0) {
  printf("\nSPD_open_file error -- %s status = %d",wdpf_pdir,file_desc);
  exit(1); }



/******************** set up socket interface with NT  ***********************/


/** setup stream socket **/
if((sock = socket(AF_INET,SOCK_STREAM,0)) < 0) {
    printf("\ncannot open stream socket");
    exit(1); }

if(debug_msg)
  printf("\ncreated sock, sock = %d..",sock);

/** set socket options **/
if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on)) < 0) {
    printf("\ncannot set SO_REUSEADDR socket option");
   /* exit(1);*/ }
   

tcpsendbuff = 64384;
tcprecbuff = 64384;


if(setsockopt(sock,SOL_SOCKET,SO_SNDBUF, (char *) &tcpsendbuff, sizeof(tcpsendbuff)) < 0) {
    printf("\ncannot set SO_SNDBUF socket option");
    exit(1); }
 
if(setsockopt(sock,SOL_SOCKET,SO_RCVBUF, (char *) &tcprecbuff, sizeof(tcprecbuff)) < 0) {
    printf("\ncannot set SO_RCVBUF socket option");
    exit(1); }

optlen =sizeof(tcpsendbuff);
if(getsockopt(sock,SOL_SOCKET,SO_SNDBUF, (char *) &tcpsendbuff, &optlen) < 0) {
    printf("\ncannot set SO_SNDBUF socket option");
    exit(1); }
if(debug_msg)
 printf("\nnew SO_SNDBUF len = %d",tcpsendbuff);


optlen =sizeof(tcprecbuff);
if(getsockopt(sock,SOL_SOCKET,SO_RCVBUF, (char *) &tcprecbuff, &optlen) < 0) {
    printf("\ncannot set SO_RCVBUF socket option");
    exit(1); }
if(debug_msg)
 printf("\nnew SO_RCVBUF len = %d",tcprecbuff);


serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddr.sin_port=htons(PORT);

if(bind(sock,(struct sockaddr *) &serverAddr,sizeof(serverAddr)) < 0) {
   printf("\ncannot bind stream socket error, port = %d",PORT);
   exit(1); }

if(debug_msg)
  printf("\nbind socket ok...");

serverLen = sizeof(serverAddr);

if(getsockname(sock,(struct sockaddr *) &serverAddr,&serverLen) <0) {
   printf("getting socket name");
   exit(1); }

if(debug_msg)
  printf("\ngetsocketname ok...");

listen(sock,1);

if(debug_msg)
  printf("\nlistening for requests on socket %d...",PORT);

/* turn off alarming up front  */
signal(SIGINT, cleanup);
signal(SIGPIPE, SIG_IGN);



for(;;) {

do {
  clientLen= sizeof(clientAddr);
  msgsock = accept(sock, (struct sockaddr *) &clientAddr, &clientLen);
if(debug_msg);  
printf("\nmsgsock=%d errno = %d errstr = %s",msgsock,errno,strerror(errno));
}while (msgsock <0 && (errno == EINTR || errno == 32));


if(msgsock < 0)
 if(debug_msg) {
    printf("\nsock accept error");
    exit (-1); }
 

if(debug_msg)
  printf("\naccepted socket...");
inbuff[0]='\0';
i=readn(msgsock,inbuff, sizeof(inbuff));

if(debug_msg) {
 printf("\nreceived %d bytes",i);
 printf("\nstring = %s",inbuff); }



 read_request();
 /* checkforchanges();  */

}/* end for loop */

if(debug_msg)
printf("\nexiting do loop errno = %s",strerror(errno));
sockstat = close(msgsock);
exit(0);



}

/*************************** end main **********************************/



/************************************************************************/
/** this function  used to read "n" bytes from socket **/
int
readn(fd,ptr,nbytes)
register int fd;
register char *ptr;
register int nbytes;
{
int nleft,nread;
char tmpbuff[RECBUFFSIZE];


nleft = nbytes;
ptr = tmpbuff;

do {

nread = read(fd,ptr,nleft);
 
if(nread < 0)
   return(nread);
else if (nread == 0)
   break;

nleft -= nread;
ptr   += nread;
*ptr ='\0';

if(strstr(tmpbuff,"^^"))
{
  break;
}


} while(1);

tmpbuff[strlen(tmpbuff)]='\0';
strcpy(inbuff,tmpbuff);
return(strlen(tmpbuff));

}


/*************************************************************************/
/* used to write "n" bytes */
int
writen(fd,ptr,nbytes)
register int fd;
register char *ptr;
register int nbytes;
{

int nleft, nwritten;

nleft = nbytes;

while(nleft >0) {
 
nwritten = write(fd,ptr,nleft);
 
if(nwritten <=0)
    return(nwritten);
  nleft -= nwritten;
 ptr   += nwritten;
}

return(nbytes - nleft);
}
/*****************************************************************/




/********** read inputs points ******/
read_request(void)
{

int i,j;
char cmdType[3];
int cmdNum;
int status;
int count;
char strcount[5];
char field_name[2];
char in;

cmdType[0]='\0';
cmdNum=99;

strncpy(cmdType,inbuff+0,2);
cmdNum = atoi(cmdType);
cmdType[2]='\0';



/* whole point records */
if(cmdNum==0) {


update_timer(0);
 
strncpy(strcount,inbuff+2,4);
strcount[4]='\0';
count = atoi(strcount);
numpoints = count;


if(debug_msg)
 printf("\nrequested to retreive %d points",count);

/* allocate memory based on number of points found */
/*indatap = malloc(count * sizeof(datarec)); */
if(debug_msg)
  printf("\nallocated %d memory structures for points",count);


j=6;
for (i = 1;i <=count; i++)
 {
strncpy(indatap[i].pn, inbuff+j,8);
j=j+8;
indatap[i].pn[8]='\0';

/* need to add error checking here later*/
status = SPD_get_sid(&file_desc,indatap[i].pn,&indatap[i].sid,&gp_sid,&gp_bit_num,&ext_flag,&ina_flag);


status = SPD_get_point_info(&file_desc,&indatap[i].sid,&point_info,network_name);
indatap[i].rt = point_info.rec_type;

if(debug_msg)
  printf("\nrt = %d",indatap[i].rt);

if(debug_msg)
  printf("\npopulated dynamic structure for %s (index = %d) stat = %d",indatap[i].pn,i,status);
}

/* go and get whole point records if cmd type = 00*/

/* free( (void *)indatap); */
update_timer(1);

} /* end whole point record */


if(cmdNum== 2) {

update_timer(0);

strcpy(field_name,"CM");
byte_val = 14;

printf("\nnum points = %d",numpoints);
for(i=1;i<=numpoints;i++)  {
status = SHC_change_byte_attribute(&indatap[i].sid,&field_name, &byte_val);
if(debug_msg)
  printf("\nwrote ack bit for pn = %s, stat = %d", indatap[i].pn,status);
 }

update_timer(1);
} /* end write ack bit */



}


int getpointrecord()
{

int i;
int k;
unsigned char point_record[300];
char hh[2];
char hdrStr[6];
int status;
int bytesSent;
long retMsgCount;
char tempbuff[300];
int sendCounter;

/* build ret msg string in format of [cmd][index]data^^  */  
outbuff[0]='\0';
hdrStr[0]='\0';
sendCounter = 0;

/* cmdtype = 00 for whole point record ret */
sprintf(hdrStr,"%2s","00");  
hdrStr[2]='\0';
strcpy(outbuff,hdrStr);

if(debug_msg)
printf("\nnumpoints = %d",numpoints);

for (i = 1;i <= numpoints; i++)

 {

   strcat(outbuff,"(");
   sprintf(hdrStr,"%04d",i);  
   hdrStr[4]='\0';
   strcat(outbuff,hdrStr);

   tempbuff[0]='\0';
   status = SHC_get_point_record(&indatap[i].sid, &point_record);
   if(debug_msg)
    printf("\nretrieved record for %s (index = %d)",indatap[i].pn,i);

    for(k=0;k<128;k++) {
     sprintf(hh,"%02x",point_record[k]);
     strcat(tempbuff,hh);}
   
   strcat(outbuff,tempbuff);
   strcat(outbuff,")");

   if(sendCounter >= MAXRECORDSENDS) {
       outbuff[strlen(outbuff)] ='\0';
       bytesSent=writen(msgsock,(char *)outbuff,strlen(outbuff));
      if(debug_msg  )
         printf("\ngoing to send back %d bytes",strlen(outbuff));
          /*  printf("\nstring = \n%s",outbuff);  */
           outbuff[0]='\0';
         sendCounter = 0; }
   else
         sendCounter = sendCounter +1;
   
}  

/* tag ending message info */
    strcat(outbuff,"^^");
    retMsgCount = strlen(outbuff);
    outbuff[retMsgCount]='\0';

   /* send back the localbuff up to retMsgCount of len */
   if(debug_msg  ) {
     printf("\ngoing to send back %d bytes",retMsgCount);
     /* printf("\nstring = \n%s",outbuff); */ }

   bytesSent=writen(msgsock,(char *)outbuff,retMsgCount);
   if(debug_msg)
     printf("\nwriten errno = %d, sent %d bytes over network",errno,bytesSent);

/** ok once here, then start sending exceptions **/

init_struct();


}


checkforchanges()
{
int i;
char *modestr;
int status;
float absval;
int bytesSent;
char tmpstr[20];
char ch;


/* exceptions sent as CMD(PN_TOKEN=VALUE), ... */
/* clear out buffer */


/* don't let another timer hit if already in here */

/* while(1) {    */


outbuff[0]='\0';
strcpy(outbuff,"01");

for (i=1;i<=numpoints;i++)
  {

modestr="";

  switch(indatap[i].rt) {

  case RECORD_TYPE_AI:
  case RECORD_TYPE_AL:
  case RECORD_TYPE_AC:
  case RECORD_TYPE_AM:
  modestr="Analog";
  status = SHC_get_analog_val_stat(&indatap[i].sid,&indatap[i].av,&indatap[i].as);



if(indatap[i].old_as != indatap[i].as) {
      strcat(outbuff,"(");
      strcat(outbuff,indatap[i].pn);
      strcat(outbuff,"_AS=");
        sprintf(tmpstr,"%d",indatap[i].as);
        strcat(outbuff,tmpstr);
      strcat(outbuff,")");

indatap[i].old_as = indatap[i].as;
 }

if(debug_msg &&  indatap[i].old_as != indatap[i].as)  
     printf("\nold as of %s = %d, new as val = %d",indatap[i].pn, indatap[i].old_as,indatap[i].as);


  break;

  case RECORD_TYPE_DI:
  case RECORD_TYPE_DL:
  case RECORD_TYPE_DC:
  case RECORD_TYPE_DM:
  modestr="Digital";
  status = SHC_get_digital_val_stat(&indatap[i].sid,&gp_sid,&gp_bit_num,&indatap[i].digital_val,&indatap[i].digital_stat);

if(indatap[i].digital_stat != indatap[i].old_digital_stat && status == SHC_OK) {
      strcat(outbuff,"(");
       strcat(outbuff,indatap[i].pn);
      strcat(outbuff,"_DS=");
        sprintf(tmpstr,"%d",indatap[i].digital_stat & 0x01);
        strcat(outbuff,tmpstr);
      strcat(outbuff,")");

indatap[i].old_digital_stat = indatap[i].digital_stat;
}


if(debug_msg && indatap[i].digital_stat != indatap[i].old_digital_stat)
          printf("\nold ds of %s = %d, new ds = %d",indatap[i].pn, indatap[i].old_digital_stat,indatap[i].digital_stat);

/* indatap[i].old_digital_stat = indatap[i].digital_stat;
*/
        
break;


  break; }  /* end switch */


 }   /* next point, end for*/

 strcat(outbuff,"^^");
 outbuff[strlen(outbuff)]='\0';

/* only send if string is greater than the default 00^^ */
if(strlen(outbuff) > 4) {
 bytesSent=writen(msgsock,(char *)outbuff,strlen(outbuff));
   if(debug_msg)
     printf("\nwriten errno = %d, sent %d bytes over network",errno,bytesSent);
   }

if(errno == 32) {
if(debug_msg)  
  printf("\nreceived EPIPE signal, closing socket, waiting...");
 close(msgsock);
 errno=0;
 return; }

/*  sleep(SCANTIME); */

/*     }     while true */

}


 
void update_timer(int signum)
{

if(debug_msg)
  printf("\nchecking for exceptions");
checkforchanges();
signal(SIGALRM,update_timer);
alarm(SCANTIME);  
return;
}  

init_struct()
{

int i;

for(i=1;i<=numpoints;i++) {

        indatap[i].digital_val=0;
        indatap[i].old_digital_val=9;
      indatap[i].digital_stat=0;
      indatap[i].old_digital_stat=9;
      indatap[i].gp_val=0;
      indatap[i].old_gp_val=9;
      indatap[i].gp_stat=0;
      indatap[i].old_gp_stat=9;
      indatap[i].gp_force_stat=0;
      indatap[i].old_gp_force_stat=9;
      indatap[i].av=0.00;
        indatap[i].old_av=99999.00;      

}
}



void cleanup(int sig_num)
{
 signal(SIGINT,cleanup);
 printf("\nexit gracefully\n\n\n...");
 fflush(stdout);
 sockstat = close(msgsock);  
exit(0);
}
Avatar of webtrans
webtrans

Dear
your best shot would be at <site name edited by sunnycoder- Page Editor>
quick programming and very low prices there

Hope this is a answer to ur question
Avatar of sunnycoder
>I want to make it more robust, it seems to error out a lot.

What kind of errors? Can you post some exact error messages and instances ... From what I see, you have built reasonable amount of error checking ... so if it logically correct, it shouold serve your purpose
sunnycoder
i have been directed by other Administrator b4 that it is not advisable to do work for money in here
just rather answer questions only
so i was guiding the guy to where he can find a solution
anyway i will stop from posting links like this in the future anyway
and thanks for ur note
Avatar of rkneal

ASKER

Boy, i seemed to cause a big problem here, was all excited to see the posts, but only one of them was related to my question.   I will narrow it down instead of asking for someone to code review it and point to specific problems.  Just thought someone with heavy socket experience could point to some obvious issues.

Sorry

Bob
Hi Bob,

It was not troublesome :) ... It does take a while to settle in a community and its perfectly all right. Welcome to the forum :)

I do know some socket programming but it is hard to read the code when you do not know what you are looking for ... If you can elaborate a bit on the problems you faced or at the very least the inputs/setup in which you face difficulties, I would atleast know what the objective is.

I can scan the code and post opinions but they may or may not help you much.

sunnycoder
I think your problem is not really the socket stuff.  Specifically, I see issue with some of your memory allocation.  Let's look at readn() as an example.

In readn() you pass in a pointer to space (inbuff) and a size RECBUFFSIZE (sizeof(inbuff).  Now in readn() you are using your own tmpbuff (RECBUFFSIZE) variable and trying to add an additional character (totalling RECBUFSIZE+1) with tmpbuff[strlen(tmpbuff)]='\0';  Also do you _know_ that your incoming data contains no '\0' -like an integer = 0?

Why do you not use the passed in ptr instead -as is- instead of pointing it to tmpbuff and copying to ptr (or inbuff)?

The best way to progress from here is to ...
1) Run this program under a debugger (gdb) until it SEGs and track it down that way?  or
2) Provide more information in terms of logs, or
3) Provide the client dataset or application.


Good luck



Avatar of rkneal

ASKER

njk123,

when you say add an additional character with tmpbuff[strlen(tempbuff)]='\0';   all i am trying to do is put a null at then end of the string.  I was always taught in c to make sure to terminate a character buffer with a '\0'.  Maybe i am missing something.

Let me look at your suggestion, thanks
No what I am saying is that you erroneously add an additonal character beyond the amount you have allocated.  In the case were you read RECBUFSIZE (from your read() call) you are then doing a *ptr='\0' or analogously inbuff[RECBUFSIZE] = '\0'.  Which is 1 beyond the size of the array which is
inbuff[0..RECBUFSIZE-1].

Moreover, this line
tmpbuff[strlen(tmpbuff)]='\0';
will never do anything in readn() if you actually read data -because of your *ptr='\0.  However that line
tmpbuff[strlen(tmpbuff)]='\0';
is unpredicable in the case were read() returns <=0 and could segfault.

Why are you using strXXX functions, is memxxx more appropriate?  Is this data coming across as ascii strings, does the client write out the nulls?  What are the clients sending?
ASKER CERTIFIED SOLUTION
Avatar of njk123
njk123

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of rkneal

ASKER

i am going to work on this this weekend, i will look at your excellent comments.

Here is the basic program overview.

We need to retrieve real-time information from a control system.   What i do on the client (windows) is build a list of points/tags that i need info from.  The cmd "00" is telling the socket to retreive ALL the information one time from the socket, so the windows client builds the needed point list, sends it off to client, and waits for the "wholepointrecord" routine to send back the info.   This is 256 bytes of info on each point, it is binary, i'm not sure why i sent as a string to tell you truth, thought way back when i had problems sending as binary or just did not know how.   After the wholepointrecord is sent, it is supposed to go in a mode of sending the dynamic information that can change on each point. That is where the interupt and timer comes into play. It checks every second for any updates to the AS, DS record which is the dynamic portion of the points (the other information in the record is pretty static so don't need to send it).

While this is going on (sending updates), i also am trying to write requests to the socket to do "acknowledges" (cmd "02"). When it recieves a "02" command, it sends a request to the control system to acknowledge the points.  

I am pretty new to sockets, not a professional programmer.  I have had simliar code running at a site for about 2 years, it hangs on occasions, that is why wanted to really have someone that knows what they are doing look at it for points. I appreciate your comments.  I would be more than willing to send you the windows side of it (vb 6.0) if you are interested, just don't want to take up too much of your time on it.  

I was asked by our firewall people why the data going back and forth appeared to be ascii strings, so i would like to make it send binary data instead.  You can see on the checkforchanges routing, i am building "strings" like 1BDIY01S_AS = 0020, etc, and if anyone knows about this control system they would be able to tell the data being send which is not good.   I have the index number of the points once i build the list, so it would be best to just come up with a protocol that puts the ID of the point, and the value of it along side it.

Thanks so much,

Bob


















Ill probably have a few more questions about the particulars of the control system.  Mostly because I am interested as I write control systems for a living (particularily for the automotive assembly industry).  So Ill look at it some more this weekend.  However, quickly I notcied that perhaps the socket (msgsock) is not always closed?  Should you not close msgsock right at the end of the for(;;) loop in main().  Right after the call to read_request().

How is the program dying?  Is it hanging?  Segmentation Fault?  Ill try to go over the code in greater depth later.
Avatar of rkneal

ASKER

what type of control systems do you write. I'm a controls engineer for last 15 years, do DCS systems like Westinghouse WDPF/Ovation, Honeywell, Bailey Infi-90, then most of the PLC programs like AB Control Logix, Devicenet, SLC, Modicon, GE, etc, etc.

How can i send you the vb code for the client?
Sorry, I am probably using too lose terminology.  I am a programmer by trade and have been working contracts in the auto industry for the past few years.  So all my work hasnt been on the control system side but more the interface too control systems.  Specifically talking to PLC and controlling assembly lines.  So I write the software that interfaces the outside world (orders, schedules, inventory, ...) into (an out of) the PLC.  Sorry for the confusion.  I can be found at manse.ca-at-gmail-dot-com.


Avatar of rkneal

ASKER

Can someone look at the below code.

As soon a i return back from the line "read_request", i can no longer write data back to client.
I get a errno=4, interupted system call, then everytime i write data i get a "bad file number"

I am able to write data back to the client, but it looks like as soon as first timer gets fired off or when i return from read_request, i get errno=4, then can't write any longer.

If i eliminate the timer/alarm/signal, and jump into the checkforchanges in an infinite loop, i can write all day long back to the client.  

Any help would be appreciated.

thanks
bob








main()
....

for(;;) {

do {
  clientLen= sizeof(clientAddr);
  msgsock = accept(sock, (struct sockaddr *) &clientAddr, &clientLen);
if(debug_msg)  
printf("\nmsgsock=%d errno = %d errstr = %s",msgsock,errno,strerror(errno));
}while (msgsock <0 && (errno == EINTR || errno == 32) );

if(msgsock < 0)
 if(debug_msg) {
    printf("\nsock accept error");
    exit (-1); }
 

if(debug_msg)
  printf("\naccepted socket...");
i=readn(msgsock,inbuff, sizeof(inbuff));

read_request();
close(msgsock);


}/* end for loop */

if(debug_msg)
printf("\nexiting do loop errno = %s",strerror(errno));
sockstat = close(msgsock);
exit(0);



}


read_request()
{
....getdata
....sendback to client
....turn on timer to check for updates every second
....update_timer(1);

}

checkforchanges()
{
update_timer(0); /* turn off timer while updating so doesn't fire off again */

...write exceptions back to client...

update_timer(1); /* turn back on */



}


if(debug_msg)
  printf("\nchecking for exceptions");
checkforchanges();
signal(SIGALRM,update_timer);
alarm(SCANTIME);  
}  


My bad.  I was only looking at the socket stuff and not the structure of what you have setup.  The close(msgsock) is hindering the asynchronous write back.  I suspect that read_request is completing and then main() is calling close(msgsock) and later in a signal handle (checkforchange) your are writing to the msgsock descriptor.  There is an oddness to the structure by allowing multiple connections

for(;;){
    msgsock = accept
    read_request
}

and outside of this loop you asynchronosly write to the open msgsock on a timer.
Avatar of rkneal

ASKER

njk123,

i tried taking the close out and then i get errno=9, bad file number when try to send anything in checkforchanges.

What do you mean by your comment "there is an oddness....".   I only have one client connecting to this for data exchange, but it does need to handshake and be able to receive/send requests all the time.  

Thanks!
How do you stop multiple firings of your sigalarm?  Especially with an ALARM  The parameter to update_timer() doesnt appear to do anything.  If there is indeed only one client at a time then I would recommend a structure (without getting into multiple threads) like

for(;;){
    msgsock = accept
    read_request()

    while(!bDone){
        reset_alarm_if_appropriate()  /* This may be checkforchange() */
        sleep();
        checkforchange(); /* Somewhere in here
    }

    close(msgsock)
}

ie.  dont embed large amounts of logic and system calls into signal handler.  They are suppose to fire as quickly as possible.  Have the signal handlers do simple things like:  bump you out of a hanging system call (like SIGALARM does with sleep), check and set a variable, ...
This also answer some questions that you posed
https://www.experts-exchange.com/questions/21127927/getting-errno-4-interupted-system-call-also-get-a-EPIPE-signal-after-runs-for-a-few-hours.html

1) The "bad file number" is always because your program has closed the socket.  
2) EPIPE is often caused by the remote side closing the connection.  You dont have any readers (remote end) for your pipe -or socket in this case.
3) Best practices say that you always trap the returns of system calls.  
? What is the exact protocol?
Once you have read the request and start waiting to write the answer do you need to read anymore from the client?  It doesnt look like it, at least from the code, but I want to make sure that is your expectation as well
Avatar of rkneal

ASKER

njk123,

thanks again. I think i am really confusing myself on all of this because so new to sockets.
I will implement you changes and let you know.

One thing want to tell you about program, is that although there is one client attached to it, it needs to send commands to the socket while it is updating it also.

Let me explain better.  here is the exact sequence

1. client starts up, gets a list of all points needs updates on
2. the client sends a "01" command to server
3. the server gets the "01" command, and does a getpointrecord (gets ALL info)
4. the client receives all this info and posts it into its real-time database
5. the server then enters the checkforchanges loop, sending any changes to the dynamic fields of the records (AS, DS)

6. when an operator presses a switch, the client will send the server a  "02" command.
7. when the server recieves the "02" command, it will acknowledge all the points

8. if the client does not receive any data for x amount of seconds, it re-initializes communications and starts all over.

6-7 are where i am having trouble. Because although it has only one client, it needs to handshake back and forth like this.  What i have been trying to do is when i receive a "02" command, i want to temporarily suspend the checkforchanges, have it write the values, then enter back into the checkforchanges loop.

I think this is where i am getting into trouble because i am getting multiple connections to the socket.  What i have been doing to make it work which i know is not correct, is disconnecting the client, then reconnecting every time i want to send the "02" command.  It EPIPE's, waits, then receives the "02" command, but seems really slow.

I hope this helps you on what trying to do.  I'm starting to look at the fork call to think i need to use it.

Thanks
Bob









Avatar of rkneal

ASKER

njk123,

this might help on handshaking, output from all debug messages



entering debug message mode
created sock, sock = 6..
new SO_SNDBUF len = 64384
new SO_RCVBUF len = 64384
bind socket ok...
getsocketname ok...
listening for requests on socket 5461...
msgsock=7 errno = 0 errstr = Error 0


/************* client sends 01 command with a list of all points ***/
accepted socket...
terminator = ^^
received 1110 bytes
string = 0001381BRDI0011FPSMOOT1BRLT0031BRLT0041AIRFLLO1FWDI0021FWDI0071FWDI0111CNDI0021CNDI0081CNDI0111AHABTR 1AHBBTR 1BDDI0021BDDI0051BDDI0081BDDI0111PFDI0221PFDI0261PFDI0301PFDI0341PFDI0381EXAIR  1HITEMP 1BDDI0381RAPFAIL1SOALM  1IAPALRM1PFDI0021PFDI0061PFDI0101PFDI0141PFDI0181BLGATEC1GNSE0131TCDI0091GNSE0331TODI0091TODI0031TODI0011HDPASTF1HDPBSTF1TGDI0051CCPMPTR1TGDI0011TMDET011TMDET031RHDI0041MSDI0031RHDI0031TGDI0031TMTC1211FWDI0391FWDI0401HDDI0011HDDI0061HDDI0041HDDI0051TGDI0021CNLT0011TODI0071TODI0021MPDI0061GNDI0451TODI0051TBOFFTG1TURVIBA1TURWIN 1GNSE0301GNSE0141GNSE0411GNSE0161GNSE0521GNSE0111GNSE0121GNSE0101MPSE0031GNSE0511GNSE0081GNSE0071GNSE0091GNSE0061APSE0201APDI0091APDI0121GNSE0251GNDI0421GNDI0461GNDI0051GNDI0401GNDI0321MPDI0021MPDI0011APDI0141APDI0131GNDI0231BUSAPAR1BUSBPAR1GHDI0011ANGNSTA1GNFTSL 1EXTEMHI1FS677061FS677121FS677041FS677131FS677031FS677111FS677101FS666141FS677141TCDI0131FS677051CWDI0021CWDI0081CWDI0161CWDI0221CWPT01ADUMMY   1SWDI0021SWDI0051CWDI0271DWP1STF1DWP2STF1SBDI0011BRPH0012BDDI0471EGDI0021EGDI0011APDI0211APDI0231APDI0241APDI0221DCDI0011DCDI0031MWDI0012DCSTOG DUMMY4^^
requested to retreive 138 points
allocated 138 memory structures for points
rt = 140
populated dynamic structure for 1BRDI001 (index = 1) stat = 0
rt = 80
populated dynamic structure for 1FPSMOOT (index = 2) stat = 0
rt = 90
populated dynamic structure for 1BRLT003 (index = 3) stat = 0
rt = 90
populated dynamic structure for 1BRLT004 (index = 4) stat = 0
rt = 130
populated dynamic structure for 1AIRFLLO (index = 5) stat = 0
rt = 140
populated dynamic structure for 1FWDI002 (index = 6) stat = 0
rt = 140
populated dynamic structure for 1FWDI007 (index = 7) stat = 0
rt = 140
populated dynamic structure for 1FWDI011 (index = 8) stat = 0
rt = 140
populated dynamic structure for 1CNDI002 (index = 9) stat = 0
rt = 140
populated dynamic structure for 1CNDI008 (index = 10) stat = 0
rt = 140
numpoints = 10
retrieved record for 1BRDI001 (index = 1)
retrieved record for 1FPSMOOT (index = 2)
retrieved record for 1BRLT003 (index = 3)
retrieved record for 1BRLT004 (index = 4)
retrieved record for 1AIRFLLO (index = 5)
retrieved record for 1FWDI002 (index = 6)
retrieved record for 1FWDI007 (index = 7)
retrieved record for 1FWDI011 (index = 8)
retrieved record for 1CNDI002 (index = 9)
retrieved record for 1CNDI008 (index = 10)
going to send back 36160 bytes

/*** server sends back all the data for each point **/
writen errno = 0, Error 0 sent 36160 bytes over network



/********** server enters checkforchanges and sends back all changes to client ***/
writen str = 01(000011BRDI001_DS=1)(000051AIRFLLO_DS=0)(000061FWDI002_DS=0)(000071FWDI007_DS=0)(000081FWDI011_DS=0)(000091CNDI002_DS=0)(000101CNDI008_DS=0)(000111CNDI011_DS=0)(000121AHABTR _DS=0)(000131AHBBTR _DS=0)(000141BDDI002_DS=0)(000151BDDI005_DS=0)(000161BDDI008_DS=0)(000171BDDI011_DS=0)(000181PFDI022_DS=0)(000191PFDI026_DS=0)(000201PFDI030_DS=0)(000211PFDI034_DS=0)(000221PFDI038_DS=0)(000241HITEMP _DS=0)(000251BDDI038_DS=0)(000261RAPFAIL_DS=0)(000271SOALM  _DS=0)(000281IAPALRM_DS=0)(000291PFDI002_DS=2)(000301PFDI006_DS=2)(000311PFDI010_DS=2)(000321PFDI014_DS=2)(000331PFDI018_DS=2)(000341BLGATEC_DS=0)(000351GNSE013_DS=0)(000361TCDI009_DS=0)(000371GNSE033_DS=0)(000381TODI009_DS=0)(000391TODI003_DS=0)(000401TODI001_DS=0)(000411HDPASTF_DS=0)(000421HDPBSTF_DS=0)(000431TGDI005_DS=0)(000441CCPMPTR_DS=0)(000451TGDI001_DS=0)(1TMDET01_AS=8192)(1TMDET03_AS=8192)(000481RHDI004_DS=0)(000491MSDI003_DS=0)(000501RHDI003_DS=0)(000511TGDI003_DS=0)(000531FWDI039_DS=0)(000541FWDI040_DS=0)(000551HDDI001_DS=0)(000561HDDI006_DS=0)(000571HDDI004_DS=0)(000581HDDI005_DS=0)(000591TGDI002_DS=0)(000611TODI007_DS=0)(000621TODI002_DS=0)(000631MPDI006_DS=0)(000641GNDI045_DS=0)(000651TODI005_DS=0)(000661TBOFFTG_DS=0)(000671TURVIBA_DS=0)(000681TURWIN _DS=0)(000691GNSE030_DS=0)(000701GNSE014_DS=0)(000711GNSE041_DS=0)(000721GNSE016_DS=0)(000731GNSE052_DS=0)(000741GNSE011_DS=0)(000751GNSE012_DS=0)(000761GNSE010_DS=0)(000771MPSE003_DS=0)(000781GNSE051_DS=0)(000791GNSE008_DS=0)(000801GNSE007_DS=0)(000811GNSE009_DS=0)(000821GNSE006_DS=0)(000831APSE020_DS=0)(000841APDI009_DS=0)(000851APDI012_DS=0)(000861GNSE025_DS=0)(000871GNDI042_DS=0)(000881GNDI046_DS=0)(000891GNDI005_DS=0)(000901GNDI040_DS=0)(000911GNDI032_DS=0)(000921MPDI002_DS=0)(000931MPDI001_DS=129)(000941APDI014_DS=0)(000951APDI013_DS=0)(000961GNDI023_DS=0)(000971BUSAPAR_DS=0)(000981BUSBPAR_DS=0)(000991GHDI001_DS=0)(001001ANGNSTA_DS=0)(001011GNFTSL _DS=0)(001021EXTEMHI_DS=0)(001031FS67706_DS=3)(001041FS67712_DS=3)(001051FS67704_DS=3)(001061FS67713_DS=3)(001071FS67703_DS=3)(001081FS67711_DS=3)(001091FS67710_DS=3)(001101FS66614_DS=1)(001111FS67714_DS=3)(001121TCDI013_DS=0)(001131FS67705_DS=3)(001141CWDI002_DS=0)(001151CWDI008_DS=0)(001161CWDI016_DS=0)(001171CWDI022_DS=0)(001201SWDI002_DS=0)(001211SWDI005_DS=0)(001221CWDI027_DS=0)(001231DWP1STF_DS=0)(001241DWP2STF_DS=0)(001251SBDI001_DS=0)(001272BDDI047_DS=0)(001281EGDI002_DS=0)(001291EGDI001_DS=0)(001301APDI021_DS=0)(001311APDI023_DS=0)(001321APDI024_DS=0)(001331APDI022_DS=0)(001341DCDI001_DS=0)(001351DCDI003_DS=1)(001361MWDI001_DS=0)(001372DCSTOG _DS=1)(00138DUMMY4^^_DS=0)^^
 errno = 0, Error 0, sent 2582 bytes over network


/** server is now sending just the changes ever secound (i have this point rigged to send data every scan) */
writen str = 01(000011BRDI001_DS=27)^^
 errno = 4, Interrupted system call, sent 25 bytes over network
writen str = 01(000011BRDI001_DS=53)^^
 errno = 4, Interrupted system call, sent 25 bytes over network
writen str = 01(000011BRDI001_DS=79)^^
 errno = 4, Interrupted system call, sent 25 bytes over network
writen str = 01(000011BRDI001_DS=10)^^
 errno = 4, Interrupted system call, sent 25 bytes over network
writen str = 01(000011BRDI001_DS=36)^^
 errno = 4, Interrupted system call, sent 25 bytes over network
writen str = 01(000011BRDI001_DS=62)(001372DCSTOG _DS=0)^^
 errno = 4, Interrupted system call, sent 45 bytes over network

/** here is where the client presses a button to send an acknowledge to the server "02" command **/
/** i think it gives broken pipe because i destroy socket, and reconnect from client to server **/

 errno = 32, Broken pipe, sent -1 bytes over network
received EPIPE signal, closing socket, waiting...
msgsock=7 errno = 0 errstr = Error 0
accepted socket...
terminator = ^^
received 4 bytes

/*** recieved a "02" command **/
string = 02^^

/** goes into read_request again, determines it's a "02" command, and writes out acknowledges **/
num points = 138
wrote ack bit for pn = 1BRDI001, stat = 0
wrote ack bit for pn = 1FPSMOOT, stat = 0
wrote ack bit for pn = 1BRLT003, stat = 0
wrote ack bit for pn = 1BRLT004, stat = 0
wrote ack bit for pn = 1AIRFLLO, stat = 0
wrote ack bit for pn = 1FWDI002, stat = 0
wrote ack bit for pn = 1FWDI007, stat = 0
wrote ack bit for pn = 1FWDI011, stat = 0
wrote ack bit for pn = 1CNDI002, stat = 0


/** jumps back into the checkforchanges **/
writen str = 01(000011BRDI001_DS=9)^^
 errno = 0, Error 0, sent 24 bytes over network
writen str = 01(000011BRDI001_DS=35)^^
 errno = 4, Interrupted system call, sent 25 bytes over network
writen str = 01(000011BRDI001_DS=61)^^
 errno = 4, Interrupted system call, sent 25 bytes over network
writen str = 01(000011BRDI001_DS=87)^^
 errno = 4, Interrupted system call, sent 25 bytes over network

/* another "02" command send from client */
received EPIPE signal, closing socket, waiting...
msgsock=7 errno = 0 errstr = Error 0
accepted socket...
terminator = ^^
received 4 bytes
string = 02^^
num points = 138
wrote ack bit for pn = 1BRDI001, stat = 0
wrote ack bit for pn = 1FPSMOOT, stat = 0
wrote ack bit for pn = 1BRLT003, stat = 0
wrote ack bit for pn = 1BRLT004, stat = 0
wrote ack bit for pn = 1AIRFLLO, stat = 0
wrote ack bit for pn = 1FWDI002, stat = 0
exit gracefully