#include #include #include #include #include #include "BSlib.h" #ifdef linux #include #include #endif #ifdef vxWorks #include #include #include #include #include #include #include #include #else #include #include #include #include #endif #ifdef SOLARIS #define BSD_COMP #include #endif #include #include #include #include static long BSgetBroadcastAddr(int soc, struct sockaddr* sin); /* ---------------------------------------------------------------------- */ /* server mode functions */ #ifndef vxWorks /* server mode functions */ static char* filename=(char*)NULL; /* ----------------------------- */ /* signal catcher for the server */ /* ----------------------------- */ static void catch_sig(int sig) { fprintf(stderr,"\nbdt server exiting\n"); unlink(filename); exit(0); } /* -------------------------------- */ /* child reaper for the server mode */ /* -------------------------------- */ static void get_child(int sig) { #ifdef SOLARIS while(waitpid(-1,(int*)NULL,WNOHANG)>0); #else while(wait3((int *)NULL,WNOHANG,(struct rusage *)NULL)>0); #endif #if defined linux || defined SOLARIS signal(SIGCHLD,get_child); /* for reaping children */ #endif } /* ------------------------------- */ /* Clear the signals for a process */ /* ------------------------------- */ int BSserverClearSignals() { signal(SIGCHLD,SIG_DFL); signal(SIGHUP,SIG_DFL); signal(SIGINT,SIG_DFL); signal(SIGTERM,SIG_DFL); signal(SIGQUIT,SIG_DFL); return 0; } /* ----------------------------------------------------- */ /* Make a unix process into a generic background process */ /* ----------------------------------------------------- */ int BSmakeServer(char** argv) { FILE* fd; if(filename) return -1; /* set up signal handling for the server */ signal(SIGCHLD,get_child); /* for reaping children */ signal(SIGHUP,catch_sig); signal(SIGINT,catch_sig); signal(SIGTERM,catch_sig); signal(SIGQUIT,catch_sig); /* disconnect from parent */ switch(fork()) { case -1: /* error */ perror("Cannot fork"); return -1; case 0: /* child */ #if defined linux || defined SOLARIS || defined SGI setpgrp(); #else setpgrp(0,0); #endif setsid(); break; default: /* parent goes away */ exit(0); } /* save process ID */ filename=(char*)malloc(strlen(argv[0])+10); sprintf(filename,"%s.%d",argv[0],getpid()); fd=fopen(filename,"w"); fprintf(fd,"%d",getpid()); fprintf(stderr,"\npv server pid: %d\n",getpid()); fclose(fd); return 0; } #endif /* server mode functions */ /* --------------------------------------------------------------- */ /* open a bulk data socket to a server given the server IP address */ /* --------------------------------------------------------------- */ BS* BSipOpen(char* address, int Port) { struct hostent* pHostent; unsigned long addr; BSDATA info; struct sockaddr_in* tsin; tsin=(struct sockaddr_in*)&(info.sin); #ifndef vxWorks /* Deal with the name -vs- IP number issue. */ if (isdigit(address[0])) { #endif addr=inet_addr(address); #ifndef vxWorks } else { if((pHostent=gethostbyname(address))==NULL) return NULL; memcpy((char*)&addr,pHostent->h_addr,sizeof(addr)); } #endif tsin->sin_port=htons(Port); tsin->sin_family=AF_INET; memcpy((char*)&(tsin->sin_addr),(char*)&addr,sizeof(addr)); return BSipOpenData(&info); } BS* BSipOpenData(BSDATA* info) { struct sockaddr_in tsin; int osoc; BS* bdt; tsin.sin_port=0; tsin.sin_family=AF_INET; tsin.sin_addr.s_addr=htonl(INADDR_ANY); if((osoc=socket(AF_INET,SOCK_STREAM,BS_TCP))<0) { perror("BSipOpen: create socket failed"); return (BS*)NULL; } if((bind(osoc,(struct sockaddr*)&tsin,sizeof(tsin)))<0) { perror("BSipOpen: local address bind failed"); return (BS*)NULL; } if(connect(osoc,(struct sockaddr*)&(info->sin),sizeof(info->sin))<0) { perror("BSipOpen: connect failed"); close(osoc); return (BS*)NULL; } bdt=(BS*)malloc(sizeof(BS)); bdt->soc=osoc; bdt->remaining_send=0; bdt->remaining_recv=0; bdt->state=BSidle; #ifndef vxWorks { int j; j = fcntl(bdt->soc, F_GETFL, 0); fcntl(bdt->soc, F_SETFL, j|O_NDELAY); } #endif /* now connected to the bulk data socket on the IOC */ return bdt; } /* -------------------------------------- */ /* write size bytes from buffer to socket */ /* -------------------------------------- */ int BSwrite(int soc,void* buffer,int size) { int rc; int total; unsigned char* data; fd_set fds; struct timeval to; data=(unsigned char*)buffer; total=size; to.tv_sec = 5; to.tv_usec = 0; do { FD_ZERO(&fds); FD_SET(soc, &fds); if(select(FD_SETSIZE,NULL,&fds,NULL,&to) != 1) { printf("BSwrite: timeout waiting to write data\n"); return -1; } /* send block of data */ if((rc=send(soc,(char*)&data[size-total],total,0))<0) { if(errno == EINTR) rc = 0; else perror("BSwrite: Send to remote failed"); } else total-=rc; } while(rc>0 && total>0); return (rc<=0)?-1:0; } /* --------------------------------------- */ /* send a message header down a BS socket */ /* --------------------------------------- */ int BSsendHeader(BS* bdt,unsigned short verb,int size) { BSmsgHead buf; if(bdt->state!=BSidle) { fprintf(stderr,"BSsendHeader: Interface not idle\n"); bdt->state=BSbad; return -1; } buf.verb=htons(verb); buf.size=htonl((unsigned long)size); if(BSwrite(bdt->soc,&buf.verb, sizeof(buf.verb))<0) { fprintf(stderr,"BSsendHeader: write to remote failed"); return -1; } if(BSwrite(bdt->soc,&buf.size, sizeof(buf.size))<0) { fprintf(stderr,"BSsendHeader: write to remote failed"); return -1; } /* don't wait for response if data must go out */ if(size) { bdt->remaining_send=size; bdt->state=BSsData; } return 0; } /* ------------------------------------------- */ /* send a message data chunk down a BS socket */ /* ------------------------------------------- */ int BSsendData(BS* bdt,void* buffer,int size) { int len; int remaining; int rc; if(bdt->state!=BSsData) { fprintf(stderr,"BSsendData: Interface not in send data mode\n"); bdt->state=BSbad; return -1; } remaining=bdt->remaining_send-size; if(remaining<0) { fprintf(stderr,"WARNING -- BSsendData: To much data to send\n"); len=bdt->remaining_send; } else len=size; if (BSwrite(bdt->soc, buffer, len) < 0) return -1; bdt->remaining_send-=len; if(bdt->remaining_send<0) { fprintf(stderr,"BSsendData: To much data Sent\n"); bdt->remaining_send=0; } if(bdt->remaining_send==0) bdt->state=BSidle; return len; } int BSflushOutput(BS* bdt) { #ifdef vxWorks ioctl(bdt->soc, FIOWFLUSH, 0); #endif return 0; } /* ------------------------------------- */ /* Read exactly size bytes from remote */ /* ------------------------------------- */ int BSread(int soc,void* buffer,int size) { int rc,total; unsigned char* data; fd_set fds; struct timeval to; to.tv_sec = 5; to.tv_usec = 0; data=(unsigned char*)buffer; total=size; do { #if 1 /* wait for data chunk */ FD_ZERO(&fds); FD_SET(soc, &fds); if (select(soc+1, &fds, NULL, NULL, &to) != 1) { printf("BSread: timeout waiting for data\n"); return(-1); } #endif if((rc=recv(soc,(char*)&data[size-total],total,0))<0) { if(errno==EINTR) { printf("BSread: EINTR"); rc=0; } else { perror("BSread: Receive data chunk failed"); } } else total-=rc; } while(rc>0 && total>0); return (rc<=0)?-1:0; } /* ------------------------------------- */ /* wait for a message header from remote */ /* ------------------------------------- */ int BSreceiveHeader(BS* bdt,int* verb,int* size) { BSmsgHead buf; /* can only receive header when in the idle state */ if (bdt->state == BSeof) return -1; if(bdt->state != BSidle) { fprintf(stderr,"BSreceiveHeader: Interface not idle\n"); bdt->state=BSbad; return -1; } if(BSread(bdt->soc,&buf.verb,sizeof(buf.verb))<0) { fprintf(stderr,"BSreceiveHeader: Read failed\n"); return -1; } if(BSread(bdt->soc,&buf.size,sizeof(buf.size))<0) { fprintf(stderr,"BSreceiveHeader: Read failed\n"); return -1; } /* copy message data to user */ *verb=ntohs(buf.verb); *size=ntohl(buf.size); if(*size) bdt->state=BSrData; bdt->remaining_recv=*size; return 0; } /* ------------------------------------------------------------------------ Wait for a chunk of data from remote. User can continually call this with a maximum size until it return 0. ------------------------------------------------------------------------ */ int BSreceiveData(BS* bdt,void* buffer,int size) { int rc; /* can only receive data when in the receive data state */ switch(bdt->state) { case BSrData: break; case BSidle: return 0; default: fprintf(stderr,"BSreceiveData: bad receive state\n"); bdt->state=BSbad; break; } if (bdt->remaining_recv < size) size = bdt->remaining_recv; if(BSread(bdt->soc,buffer,size)<0) { fprintf(stderr,"BSreceiveData: Read failed\n"); bdt->state = BSeof; return -1; } bdt->remaining_recv-=size; if(bdt->remaining_recv<0) { fprintf(stderr,"BSreceiveData: To much data received\n"); bdt->remaining_recv=0; } if(bdt->remaining_recv==0) bdt->state=BSidle; return size; } /* -------------------- */ /* close the connection */ /* -------------------- */ int BSclose(BS* bdt) { int verb,size,done; /* send a close message out */ if(BSsendHeader(bdt,BS_Close,0)<0) { fprintf(stderr,"BSclose: Cannot send close message\n"); return -1; } done=0; do { /* check response */ if(BSreceiveHeader(bdt,&verb,&size)<0) { fprintf(stderr,"BSclose: Close message response error\n"); return -1; } switch(verb) { case BS_Ok: done=1; break; case BS_Error: fprintf(stderr,"BSclose: Close rejected\n"); return -1; default: break; } } while(done==0); BSfreeBS(bdt); return 0; } /* --------------------------------------- */ /* make a listener socket for UDP - simple */ /* --------------------------------------- */ int BSopenListenerUDP(int Port) { int nsoc; struct sockaddr_in tsin; tsin.sin_port=htons(Port); tsin.sin_family=AF_INET; tsin.sin_addr.s_addr=htonl(INADDR_ANY); if((nsoc=socket(AF_INET,SOCK_DGRAM,BS_UDP))<0) { perror("BSopenListenerUDP: open socket failed"); return -1; } if((bind(nsoc,(struct sockaddr*)&tsin,sizeof(tsin)))<0) { perror("BSopenListenerUDP: local bind failed"); close(nsoc); return -1; } return nsoc; } /* --------------------------------------- */ /* make a listener socket for TCP - simple */ /* --------------------------------------- */ int BSopenListenerTCP(int Port) { int nsoc; struct sockaddr_in tsin; memset ((void *)&tsin, 0, sizeof(struct sockaddr_in)); tsin.sin_port=htons(Port); tsin.sin_family=htons(AF_INET); tsin.sin_addr.s_addr=htonl(INADDR_ANY); if((nsoc=socket(AF_INET,SOCK_STREAM,BS_TCP))<0) { perror("BSopenListenerTCP: open socket failed"); return -1; } if((bind(nsoc,(struct sockaddr*)&tsin,sizeof(tsin)))<0) { perror("BSopenListenerTCP: local bind failed"); close(nsoc); return -1; } listen(nsoc,5); return nsoc; } /* ------------------------------- */ /* make BS from a socket - simple */ /* ------------------------------- */ BS* BSmakeBS(int soc) { BS* bdt; bdt=(BS*)malloc(sizeof(BS)); bdt->soc=soc; bdt->remaining_send=0; bdt->remaining_recv=0; bdt->state=BSidle; return bdt; } /* --------------------------- */ /* free a BS and close socket */ /* --------------------------- */ int BSfreeBS(BS* bdt) { close(bdt->soc); free(bdt); return 0; } /*-----------------------------------------------------------------------*/ /* Next three function adjust the fields of the BSDATA structure. */ /*-----------------------------------------------------------------------*/ int BSgetAddressPort(BSDATA* info, char* ip_addr, int* dest_port) { char* name; struct sockaddr_in* sin = (struct sockaddr_in*)&(info->sin); *dest_port=sin->sin_port; name=inet_ntoa(sin->sin_addr); strcpy(ip_addr,name); return 0; } int BSsetAddressPort(BSDATA* info, char* ip_addr, int dest_port) { BSsetPort(info, dest_port); return BSsetAddress(info, ip_addr); } int BSsetPort(BSDATA* info, int dest_port) { struct sockaddr_in* sin = (struct sockaddr_in*)&(info->sin); sin->sin_family=AF_INET; sin->sin_port=htons(dest_port); return 0; } int BSsetAddress(BSDATA* info, char* ip_addr) { struct hostent *pHostent; struct sockaddr_in* sin = (struct sockaddr_in*)&(info->sin); unsigned long addr; #ifndef vxWorks /* Deal with the name -vs- IP number issue. */ if (isdigit(ip_addr[0])) { #endif if((addr=inet_addr(ip_addr))==-1) return -1; #ifndef vxWorks } else { if((pHostent=gethostbyname(ip_addr))==NULL) return -1; memcpy((char*)&addr,pHostent->h_addr,sizeof(addr)); } #endif sin->sin_family=AF_INET; memcpy((char*)&(sin->sin_addr),(char*)&addr,sizeof(addr)); return 0; } /* ----------------------------------------------------------------- */ /* All this function does is send a broadcast message and return the addressing info to the caller of a responder to the broadcast. arguments: soc - broadcast socket to use for sending data trys - number of times to send if no response o_info - outgoing BSDATA, address/port info i_info - incoming BSDATA, address/port where response came from omsg/osize - outgoing message and size imsg/isize - incoming message and buffer size Returns the number of bytes read. */ /* ----------------------------------------------------------------- */ int BSbroadcastTrans(int soc,int trys,BSDATA* o_info,BSDATA* i_info, void* omsg,int osize,void* imsg,int isize) { int i; int rc=0; for(i=0;rc==0 && i0) { error=0; do { info->len=sizeof(info->sin); mlen=recvfrom(soc,(char*)buf,size,0, &info->sin,&info->len); if(mlen<0) { switch(errno) { case EINTR: break; default: error=-1; break; } } } while(mlen<0 && error==0); if(mlen<0) rc=-1; else rc=mlen; } return rc; } /*-----------------------------------------------------------------------*/ /* Write a chuck of data to a UDP socket at an internet address */ /*-----------------------------------------------------------------------*/ int BSwriteDataUDP(int soc,int dest_port,char* ip_addr,void* buf,int size) { BSDATA data; BSsetAddress(&data,ip_addr); BSsetPort(&data,dest_port); return BSwriteUDP(soc,&data,buf,size); } /*-----------------------------------------------------------------------*/ /* Write a chunk of data to a UDP socket using BSDATA. Arguments: */ /*-----------------------------------------------------------------------*/ int BSwriteUDP(int soc,BSDATA* info,void* obuf,int osize) { int mlen; mlen=sendto(soc,(char*)obuf,osize,0,&info->sin,sizeof(info->sin)); return mlen; } /*-----------------------------------------------------------------------*/ /* Write/Read a chuck of data to a UDP socket using BSDATA. Arguments: soc - socket to send message down and read from info - address/port to send message to obuf/osize - outgoing message and size of it. ibuf/isize - incoming message and size of the buffer. Returns the number of bytes read, -1 for error. */ /*-----------------------------------------------------------------------*/ int BStransUDP(int soc,BSDATA* info,void* obuf,int osize,void* ibuf,int isize) { int done,i,mlen,flen; struct sockaddr fromsin; fd_set fds; struct timeval tout; done=0; mlen=0; for(i=0;isin),sizeof(info->sin)); if(mlen<0) { printf("send failed\n"); return -1; } tout.tv_sec=0; tout.tv_usec=200000; FD_ZERO(&fds); FD_SET(soc,&fds); switch(select(FD_SETSIZE,&fds,(fd_set*)0,(fd_set*)0,&tout)) { case 0: /* timeout */ break; case -1: /* error */ printf("select failed\n"); return -1; default: /* data ready */ flen=sizeof(fromsin); mlen=recvfrom(soc,(char*)ibuf,isize,0,&fromsin,&flen); if(mlen<0) return -1; done=1; break; } } if(i>=BS_RETRY_COUNT) return 0; return mlen; } /*-----------------------------------------------------------------------*/ /* Open a broadcast socket and set port to a default. */ /*-----------------------------------------------------------------------*/ int BSipBroadcastOpen(BSDATA* info, int default_dest_port) { struct sockaddr_in* sin; int soc; sin=(struct sockaddr_in*)&(info->sin); if( (soc=BSgetBroadcastSocket(0,sin)) <0) return -1; sin->sin_port=htons(default_dest_port); return soc; } /*-----------------------------------------------------------------------*/ /* BSgetBroadcastSocket() - return a broadcast socket for a port, return a sockaddr also. */ /*-----------------------------------------------------------------------*/ int BSgetBroadcastSocket(int port, struct sockaddr_in* sin) { int on=1; int soc; BS bs; sin->sin_port=htons(port); sin->sin_family=AF_INET; sin->sin_addr.s_addr=htonl(INADDR_ANY); if( (soc=socket(AF_INET,SOCK_DGRAM,BS_UDP)) < 0 ) { perror("socket create failed"); return -1; } setsockopt(soc,SOL_SOCKET,SO_BROADCAST,(char*)&on,sizeof(on)); if( bind(soc,(struct sockaddr*)sin,sizeof(struct sockaddr_in)) < 0 ) { perror("socket bind failed"); close(soc); return -1; } if( BSgetBroadcastAddr(soc,(struct sockaddr*)sin) < 0 ) return -1; return soc; } /*-----------------------------------------------------------------------*/ /* BSgetBroadcastAddr() - Determine the broadcast address, this is directly from the Sun Network Programmer's guide. */ /*-----------------------------------------------------------------------*/ static long BSgetBroadcastAddr(int soc, struct sockaddr* sin) { struct ifconf ifc; struct ifreq* ifr; struct ifreq* save; char buf[BUFSIZ]; int tot,i; ifc.ifc_len = sizeof(buf); ifc.ifc_buf = buf; if(ioctl(soc,SIOCGIFCONF,(int)&ifc) < 0) { perror("ioctl SIOCGIFCONF failed"); return -1; } ifr = ifc.ifc_req; tot = ifc.ifc_len/sizeof(struct ifreq); save=(struct ifreq*)NULL; i=0; do { if(ifr[i].ifr_addr.sa_family==AF_INET) { if(ioctl(soc,SIOCGIFFLAGS,(int)&ifr[i])<0) { perror("ioctl SIOCGIFFLAGS failed"); return -1; } if( (ifr[i].ifr_flags&IFF_UP) && !(ifr[i].ifr_flags&IFF_LOOPBACK) && (ifr[i].ifr_flags&IFF_BROADCAST)) { save=&ifr[i]; } } } while( !save && ++iifr_broadaddr, sizeof(save->ifr_broadaddr)); } else return -1; return 0; }