diff --git a/src/dbtools/BSlib.c b/src/dbtools/BSlib.c new file mode 100644 index 000000000..82938b937 --- /dev/null +++ b/src/dbtools/BSlib.c @@ -0,0 +1,987 @@ +#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 +#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 + 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 (&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; + + sin->sin_family=AF_INET; + +#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; + else + memcpy((char*)&(sin->sin_addr),(char*)&addr,sizeof(addr)); +#ifndef vxWorks + } + else + { + if((pHostent=gethostbyname(ip_addr))==NULL) return -1; + memcpy((char*)&addr,pHostent->h_addr,sizeof(addr)); + } +#endif + + 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; +} + diff --git a/src/dbtools/BSlib.h b/src/dbtools/BSlib.h new file mode 100644 index 000000000..7f5808b77 --- /dev/null +++ b/src/dbtools/BSlib.h @@ -0,0 +1,187 @@ +#ifndef ___BS_H +#define ___BS_H + +/* + * $Log$ + */ + +/* + Author: Jim Kowalkowski + Date: 9/1/95 +*/ + +#include +#include +#include +#include + +/* got from protocols(5) (cheated) or /etc/protocols */ +#define BS_UDP 17 +#define BS_TCP 6 + +/* server ports - in the user reserved area - above 50000 */ +#define BS_UDP_PORT 50296 +#define BS_TCP_PORT 50297 + +/* message types */ +#define BS_Ok 0 +#define BS_Error 1 +#define BS_Close 2 +#define BS_Ping 3 + +#define BS_LAST_VERB 3 +#define BS_RETRY_COUNT 3 + +/* protocol states */ +typedef enum { BSidle,BSunbound,BSsData,BSrData,BSbad,BSeof } BSstate; + +struct bs +{ + int soc; + int remaining_send; + int remaining_recv; + BSstate state; +}; +typedef struct bs BS; + +struct bs_udp_data +{ + struct sockaddr sin; + int len; +}; +typedef struct bs_udp_data BSDATA; + +struct BSmsgHead +{ + unsigned short verb; + unsigned long size; +}; +typedef struct BSmsgHead BSmsgHead; + +typedef unsigned long BS_ULONG; + +#define BSgetSocket(BS) (BS->soc) +#define BSgetResidualWrite(BS) (BS->remaining_send) +#define BSgetResidualRead(BS) (BS->remaining_recv) +#define BSgetProtoState(BS) (BS->state) + +/* ------------------------------------------------------------------------ + Server functions: + + BSopenListenerTCP: + Open a socket locally bound to the bulk data transfer TCP server port. + Set the socket up as a listener. Return the open socket. + + BSopenListenerUDP: + Open a socket locally bound to the bulk data transfer UDP server port. + Return the open socket. + + ------------------------------------------------------------------------ */ + +int BSopenListenerTCP(int Port); +int BSopenListenerUDP(int Port); +int BSopenTCP(BSDATA*); + +/* ------------------------------------------------------------------------ + Utilities functions: + + BSmakeServer: + Available under unix only. Put process in the background, disassociate + process from controlling terminal and parent process, and prepare + signals for reaping children spawned by the process. + + BSserverClearSignals: + Clear the signal handlers for a process, set them to default. + + BSmakeBS: + Allocate and initialize a BS from a socket. + + BSfreeBS: + Close the open socket and free the memory for the BS. + ------------------------------------------------------------------------ */ + +#ifndef vxWorks +int BSmakeServer(char** argv); +int BSserverClearSignals(); +#endif + +BS* BSmakeBS(int socket); /* make a BS from a socket */ +int BSfreeBS(BS* bdt); /* free a BS */ + +int BSgetBroadcastSocket(int port, struct sockaddr_in* sin); +int BSipBroadcastOpen(BSDATA* info, int default_dest_port); +int BSgetAddressPort(BSDATA* info,char* ip_addr, int* dest_port); +int BSsetAddressPort(BSDATA* info,char* ip_addr, int dest_port); +int BSsetAddress(BSDATA* info,char* ip_addr); +int BSsetPort(BSDATA* info,int dest_port); + +/* ------------------------------------------------------------------------ + UDP functions: + ------------------------------------------------------------------------ */ +int BStransUDP(int soc,BSDATA* info,void* obuf,int osize,void* ibuf,int isize); +int BSwriteUDP(int soc,BSDATA* info,void* obuf,int osize); +int BSwriteDataUDP(int soc,int dest_port, char* ip_addr,void* obuf,int osize); +int BSreadUDP(int soc,BSDATA* info,BS_ULONG tout,void* buf,int size); +int BSbroadcast(int soc,BSDATA* info,void* buf,int size); +int BSbroadcastTrans(int soc,int trys,BSDATA* o_info,BSDATA* i_info, + void* obuf,int osize,void* ibuf,int isize); + +/* ------------------------------------------------------------------------ + Client functions: + + BSipOpen: + Open a connection to an bulk data transfer given the IP address of the + machine where the server exists. The returned BS is returned unbound, + a connect must be issued before data transactions can take place. + + BSclose: + Completely close a connection to a server and free the BS. + + ------------------------------------------------------------------------ */ + +BS* BSipOpen(char* address, int port); +BS* BSipOpenData(BSDATA* info); +int BSclose(BS* bdt); + +/* ------------------------------------------------------------------------ + Client and Server shared functions: + + BSsendHeader: + Send a message header out to a connect BS with command and message body + size information. + + BSsendData: + Send a portion or all the message body out a connected BS. A header + must have previously been sent with length information. The interface + will only allow the amount of data specified in the header to be sent. + + BSwrite: + This call will block until all the data specified in the size parameter + are sent down the socket. + + BSread: + This call will block until all the data specified in the size parameter + is read from the socket. + + BSreceiveHeader: + Wait until a message header appears at the BS, return the action and + remaining message body size. + + BSreceiveData: + Wait for a chunk or the entire body of a message to appear at the BS. + Put the data into the buffer for a maximum size. Return the amount of + data actually received, or zero if there is no data remaining for the + current message. + + ------------------------------------------------------------------------ */ + +int BSsendHeader(BS* bdt, unsigned short verb, int size); +int BSsendData(BS* bdt, void* buffer, int size); +int BSreceiveHeader(BS* bdt, int* verb, int* size); +int BSreceiveData(BS* bdt, void* buffer, int size); +int BSread(int socket, void* buffer, int size); +int BSwrite(int socket, void* buffer, int size); +int BSflushOutput(BS* bdt); + +#endif + diff --git a/src/dbtools/PVS.h b/src/dbtools/PVS.h new file mode 100644 index 000000000..74c5bfc9b --- /dev/null +++ b/src/dbtools/PVS.h @@ -0,0 +1,18 @@ +#ifndef __PVS_H +#define __PVS_H + +#include "BSlib.h" + +#define PVS_RETRY_COUNT 4 +#define PVS_TRANSFER_SIZE 1024 +#define PVS_UDP 17 +#define PVS_TCP 6 +#define PVS_UDP_PORT 50298 +#define PVS_TCP_PORT 50299 +#define PVS_UDP_CPORT 50300 + +#define PVS_Request (BS_LAST_VERB+1) +#define PVS_Data (BS_LAST_VERB+2) +#define PVS_Alive (BS_LAST_VERB+3) + +#endif diff --git a/src/dbtools/PVSget.c b/src/dbtools/PVSget.c new file mode 100644 index 000000000..7cf709649 --- /dev/null +++ b/src/dbtools/PVSget.c @@ -0,0 +1,88 @@ + +/* only runable on work station now */ + +#include "PVS.h" + +#include +#include +#include +#include + +int main(int argc,char** argv) +{ + BS* bs; + int verb,size,done,len,i; + char* buffer; + BSDATA info; + + if(argc<2) + { + printf("Enter IOC name on command line\n"); + return -1; + } + + done=0; + buffer=(char*)malloc(PVS_TRANSFER_SIZE); + + if(BSsetAddressPort(&info,argv[1],PVS_TCP_PORT)<0) + { + printf("Failed to locate IOC host name\n"); + return -1; + } + + if((bs=BSipOpenData(&info))==NULL) + { + printf("open of socket to IOC failed\n"); + } + else + { + while(done==0) + { + printf("Begin----------\n"); + /* read messages until close received */ + if(BSreceiveHeader(bs,&verb,&size)<0) + { + printf("receive failed from socket\n"); + done=-1; + } + else + { + switch(verb) + { + case PVS_Data: /* read a block of names */ + printf("got PVS_Data msg, size=%d\n",size); + + if((len=BSreceiveData(bs,buffer,size))<0) + { + printf("receive data failed\n"); + } + else + { + for(i=0;i0) done=-1; + break; + } + } + } + printf("Closing connection\n"); + BSfreeBS(bs); + } + free(buffer); +} + diff --git a/src/dbtools/PVSserver.c b/src/dbtools/PVSserver.c new file mode 100644 index 000000000..09a0d1e0a --- /dev/null +++ b/src/dbtools/PVSserver.c @@ -0,0 +1,214 @@ + +/* only runable on work station now */ + +#include "PVS.h" + +#include +#include +#include +#include + +struct PVSnode +{ + BSDATA info; + int alive; + struct PVSnode* next; +}; +typedef struct PVSnode PVSNODE; + +static PVSNODE* ioc_list = (PVSNODE*)NULL; + +static int read_pvs(BSDATA* info); + +int main(int argc,char** argv) +{ + int soc,mlen; + unsigned short buf,in_buf,ping; + BSDATA info; + PVSNODE* node; + + if(BSmakeServer(argv)<0) + { + fprintf(stderr,"Cannot make into a server\n"); + return -1; + } + + if((soc=BSopenListenerUDP(PVS_UDP_PORT))<0) + { + fprintf(stderr,"Open of UDP listener socket failed\n"); + return -1; + } + + buf=htons(BS_Ok); /* always sends this out */ + ping=htons(BS_Ping); /* always sends this out */ + + while(1) + { + /* wait forever until a message comes in */ + + mlen=BSreadUDP(soc,&info,7,&in_buf,sizeof(in_buf)); + + /* check for errors */ + switch(mlen) + { + case 0: /* timeout */ + printf("Why did a timeout occur?\n"); + /* send out a ping to each of the IOCs in the ioc_list */ + for(node=ioc_list;node;node=node->next) + { + mlen=BStransUDP(soc,&(node->info),&ping,sizeof(ping), + &in_buf,sizeof(in_buf)); + + /* check for errors */ + switch(mlen) + { + case 0: /* timeout */ + printf("IOC dead\n"); + node->alive=0; + break; + case -1: /* error */ + printf("Communications failed\n"); + break; + default: /* ok */ + if(node->alive==0) + { + switch(fork()) + { + case -1: /* error */ + perror("fork failure"); + break; + case 0: /* child */ + close(soc); + BSserverClearSignals(); + sleep(1); + if(read_pvs(&(node->info))==0) + node->alive=1; + default: /* parent */ + break; + } + } + break; + } + } + break; + case -1: /* error */ + fprintf(stderr,"Communications failure\n"); + break; + default: /* ok */ + if(BSwriteUDP(soc,&info,&buf,sizeof(buf))<0) + fprintf(stderr,"respone send failed\n"); + else + { + node=(PVSNODE*)malloc(sizeof(PVSNODE)); + node->alive=1; + node->info=info; + BSsetPort(&(node->info),PVS_UDP_CPORT); + node->next=ioc_list; + ioc_list=node; + + switch(fork()) + { + case -1: /* error */ + perror("fork failure"); + break; + case 0: /* child */ + close(soc); + BSserverClearSignals(); + sleep(1); + return read_pvs(&info); + default: /* parent */ + break; + } + } + break; + } + } + close(soc); + return 0; +} + +static int read_pvs(BSDATA* info) +{ + BS* bs; + int verb,size,done,len,i,port; + char* buffer; + char ip_from[40]; + FILE* fd; + + BSgetAddressPort(info,ip_from,&port); + + printf("IOC %s starting\n",ip_from); + + /* verify ioc not already added */ + if(access(ip_from,F_OK)==0) + { + /* delete the existing file for this IOC */ + unlink(ip_from); + } + + buffer=(char*)malloc(PVS_TRANSFER_SIZE+2); + done=0; + BSsetPort(info,PVS_TCP_PORT); + + if((bs=BSipOpenData(info))==NULL) + { + fprintf(stderr,"Open of socket to IOC failed\n"); + } + else + { + if((fd=fopen(ip_from,"w"))==(FILE*)NULL) + { + fprintf(stderr,"Open of name file failed\n"); + } + else + { + while(done==0) + { + /* read messages until close received */ + if(BSreceiveHeader(bs,&verb,&size)<0) + { + fprintf(stderr,"Receive header failed\n"); + done=-1; + } + else + { + switch(verb) + { + case PVS_Data: /* read a block of names */ + if((len=BSreceiveData(bs,buffer,size))<0) + { + fprintf(stderr,"Receive data failed\n"); + } + else + { + for(i=0;i0) done=-1; + break; + } + } + } + fclose(fd); + } + BSfreeBS(bs); + } + free(buffer); + return 0; +} + diff --git a/src/dbtools/PVSvx.c b/src/dbtools/PVSvx.c new file mode 100644 index 000000000..833d6d716 --- /dev/null +++ b/src/dbtools/PVSvx.c @@ -0,0 +1,232 @@ + +#include "PVS.h" + +#include +#include + +#ifdef vxWorks +#include +#include +#include +#include + +extern struct dbBase *pdbBase; + +#else +#include +#include +#include +#endif + +static void PVSserver(int want_annouce,char* name); +static int PVSannouce(int want_annouce,char* name); + +#ifdef vxWorks +int PVSstart(int want_annouce, char* name) +#else +int main(int argc,char** argv) +#endif +{ +#ifndef vxWorks + char* name; + int want_annouce; +#endif + +#ifndef vxWorks + if(argc<3) + { + fprintf(stderr,"bad args\n"); + fprintf(stderr," usage: %s a_flag host_name\n", + argv[0]); + fprintf(stderr," where\n"); + fprintf(stderr," a_flag=0(want),1(don't want) to annouce boot\n"); + fprintf(stderr," host_name=PV master host (if one exists)\n"); + return -1; + } + name=argv[2]; + if(sscanf(argv[1],"%d",&want_annouce)<1) + { + fprintf(stderr,"bad a_flag\n"); + return -1; + } +#endif + +#ifdef vxWorks + taskSpawn("PVS",150,VX_FP_TASK|VX_STDIO,5000, + (FUNCPTR)PVSserver,want_annouce,(int)name,0,0,0,0,0,0,0,0); +#else + PVSserver(want_annouce,name); +#endif + + return 0; +} + +static int PVSannouce(int want_annouce,char* name) +{ + int soc,mlen; + unsigned short buf,in_buf; + BSDATA info,in_info; + + if(want_annouce==0 && name) + { + if((soc=BSopenListenerUDP(0))<0) + { + printf("Open of UDP socket failed\n"); + return -1; + } + + if(BSsetAddressPort(&info,name,PVS_UDP_PORT)<0) + { + printf("Set send port failed\n"); + return -1; + } + + buf=htons(PVS_Alive); + mlen=BStransUDP(soc,&info,&buf,sizeof(buf),&in_buf,sizeof(in_buf)); + + /* check for errors */ + switch(mlen) + { + case 0: /* timeout */ + printf("No server running on host\n"); + break; + case -1: /* error */ + printf("Communications failed\n"); + break; + default: /* ok */ + break; + } + + close(soc); + } + return 0; +} + +static void PVSserver(int want_annouce,char* name) +{ + fd_set fds,rfds; + int tsoc,usoc,nsoc,len,s; + unsigned short buf; + unsigned long names_len,nl; + struct sockaddr stemp; + int stemp_len; + char* names; + char* n; + BSDATA info; + BS* bs; + long rc; +#ifdef vxWorks + DBENTRY db; +#endif + + bs=(BS*)NULL; + names=(char*)malloc(PVS_TRANSFER_SIZE); + + if((tsoc=BSopenListenerTCP(PVS_TCP_PORT))<0) + { + printf("PVSserver: Open of TCP listener socket failed\n"); + return; + } + + if((usoc=BSopenListenerUDP(PVS_UDP_CPORT))<0) + { + printf("PVSserver: Open of UDP listener socket failed\n"); + return; + } + + FD_ZERO(&fds); + FD_SET(tsoc,&fds); + FD_SET(usoc,&fds); + + PVSannouce(want_annouce,name); + + while(1) + { + rfds=fds; + if(select(FD_SETSIZE,&rfds,(fd_set*)NULL,(fd_set*)NULL, + (struct timeval*)NULL)<0) + { + printf("PVSserver: Select failure\n"); + } + else + { + if(FD_ISSET(tsoc,&rfds)) + { + /* only requests for PVs will come in here for now */ + /* handle the request here - single threaded server */ + + stemp_len=sizeof(stemp); + if((nsoc=accept(tsoc,&stemp,&stemp_len))<0) + printf("PVSserver: Bad accept\n"); + else + { + bs=BSmakeBS(nsoc); +#ifdef vxWorks + dbInitEntry(pdbBase,&db); + names_len=0; + for(rc=dbFirstRecdes(&db);rc==0;rc=dbNextRecdes(&db)) + { + for(rc=dbFirstRecord(&db);rc==0;rc=dbNextRecord(&db)) + { + /* collect the names util we excede the max */ + n=dbGetRecordName(&db); + s=strlen(n); + if((names_len+s)>PVS_TRANSFER_SIZE) + { + names[names_len++]='\0'; + if(BSsendHeader(bs,PVS_Data,names_len)<0) + printf("PVSserver: data cmd failed\n"); + else + { + if(BSsendData(bs,names,names_len)<0) + printf("PVSserver: data send failed\n"); + } + names_len=0; + } + memcpy(&names[names_len],n,s); + names_len+=s; + names[names_len++]=' '; + } + } + if(names_len>0) + { + names[names_len++]='\0'; + if(BSsendHeader(bs,PVS_Data,names_len)<0) + printf("PVSserver: data cmd failed\n"); + else + { + if(BSsendData(bs,names,names_len)<0) + printf("PVSserver: data send failed\n"); + } + } +#else + strcpy(names,"jim Kowalkowski"); + names_len=strlen("jim kowalkowski")+1; + if(BSsendHeader(bs,PVS_Data,names_len)<0) + printf("BSsendHeader failed\n"); + else + { + if(BSsendData(bs,names,names_len)<0) + printf("BSsendData failed\n"); + } +#endif + BSclose(bs); + } + } + if(FD_ISSET(usoc,&rfds)) + { + /* only pings will come in here for now */ + len=BSreadUDP(usoc,&info,0,&buf,sizeof(buf)); + if(len<=0) + printf("PVSserver: UDP listener read failure\n"); + else + { + if(BSwriteUDP(usoc,&info,&buf,sizeof(buf))<0) + printf("PVSserver: UDP listener ping write failure\n"); + } + } + } + } +} + +