first release
This commit is contained in:
18
src/bdt/Makefile
Normal file
18
src/bdt/Makefile
Normal file
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
# Base Lowest Level Directroy Makefile
|
||||
# by Janet Anderson
|
||||
#
|
||||
# $Log$
|
||||
# Revision 1.1 1994/09/07 19:26:22 jba
|
||||
# New file
|
||||
#
|
||||
#
|
||||
|
||||
EPICS=../../..
|
||||
|
||||
include $(EPICS)/config/CONFIG_BASE
|
||||
|
||||
include $(EPICS)/config/RULES_ARCHS
|
||||
|
||||
10
src/bdt/Makefile.Unix
Normal file
10
src/bdt/Makefile.Unix
Normal file
@@ -0,0 +1,10 @@
|
||||
EPICS = ../../../..
|
||||
include Target.include
|
||||
include $(EPICS)/config/CONFIG_BASE
|
||||
|
||||
|
||||
LIBOBJS += bdt.o
|
||||
|
||||
LIBNAME = libBdt.a
|
||||
|
||||
include $(EPICS)/config/RULES.Unix
|
||||
21
src/bdt/Makefile.Vx
Normal file
21
src/bdt/Makefile.Vx
Normal file
@@ -0,0 +1,21 @@
|
||||
EPICS = ../../../..
|
||||
include Target.include
|
||||
include $(EPICS)/config/CONFIG_BASE
|
||||
|
||||
SRCS.c += ../bdt.c
|
||||
SRCS.c += ../bdtServ.c
|
||||
SRCS.c += ../bdtServName.c
|
||||
SRCS.c += ../bdtServPv.c
|
||||
|
||||
OBJS += bdt.o
|
||||
OBJS += bdtServ.o
|
||||
OBJS += bdtServName.o
|
||||
OBJS += bdtServPv.o
|
||||
|
||||
PROD = bdt
|
||||
|
||||
include $(EPICS)/config/RULES.Vx
|
||||
|
||||
$(PROD): $(OBJS)
|
||||
$(RM) $@
|
||||
$(LINK.c) $@ $(OBJS) $(LDLIBS)
|
||||
701
src/bdt/bdt.c
Normal file
701
src/bdt/bdt.c
Normal file
@@ -0,0 +1,701 @@
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/wait.h>
|
||||
#ifdef linux
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#ifdef vxWorks
|
||||
#include <vxWorks.h>
|
||||
#include <in.h>
|
||||
#include <inetLib.h>
|
||||
#include <taskLib.h>
|
||||
#include <ioLib.h>
|
||||
#include <selectLib.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "bdt.h"
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
/* 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)
|
||||
{
|
||||
while(wait3((int *)NULL,WNOHANG,(struct rusage *)NULL)>0);
|
||||
#ifdef linux
|
||||
signal(SIGCHLD,get_child); /* for reaping children */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ------------------------------- */
|
||||
/* Clear the signals for a process */
|
||||
/* ------------------------------- */
|
||||
int BdtServerClearSignals()
|
||||
{
|
||||
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 BdtMakeServer(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 */
|
||||
#ifdef linux
|
||||
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 */
|
||||
|
||||
/* ------------------------------------------ */
|
||||
/* unimplemented channel access open function */
|
||||
/* ------------------------------------------ */
|
||||
BDT* BdtPvOpen(char *IocName, char* PvName)
|
||||
{
|
||||
BDT *bdt;
|
||||
|
||||
if((bdt = BdtIpOpen(IocName, BDT_TCP_PORT)) == NULL)
|
||||
{
|
||||
fprintf(stderr,"open of address %s failed\n", IocName);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if(BdtServiceConnect(bdt, BDT_SERVICE_PV, PvName) < 0)
|
||||
{
|
||||
fprintf(stderr,"connect to PV %s failed\n", PvName);
|
||||
BdtClose(bdt);
|
||||
return(NULL);
|
||||
}
|
||||
return(bdt);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/* open a bulk data socket to a server given the server IP address */
|
||||
/* --------------------------------------------------------------- */
|
||||
BDT* BdtIpOpen(char* address, int Port)
|
||||
{
|
||||
struct hostent *pHostent;
|
||||
struct sockaddr_in tsin;
|
||||
unsigned long addr;
|
||||
int osoc;
|
||||
BDT *bdt;
|
||||
|
||||
#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);
|
||||
bcopy (pHostent->h_addr, (char *) &addr, sizeof(addr));
|
||||
printf("Converting name >%s< to IP number %08.8X\n", address, addr);
|
||||
}
|
||||
#endif
|
||||
|
||||
tsin.sin_port=0;
|
||||
tsin.sin_family=AF_INET;
|
||||
tsin.sin_addr.s_addr=htonl(INADDR_ANY);
|
||||
|
||||
if((osoc=socket(AF_INET,SOCK_STREAM,BDT_TCP))<0)
|
||||
{
|
||||
perror("BdtIpOpen: create socket failed");
|
||||
return (BDT*)NULL;
|
||||
}
|
||||
|
||||
if((bind(osoc,(struct sockaddr*)&tsin,sizeof(tsin)))<0)
|
||||
{
|
||||
perror("BdtIpOpen: local address bind failed");
|
||||
return (BDT*)NULL;
|
||||
}
|
||||
|
||||
tsin.sin_port=htons(Port);
|
||||
memcpy((char*)&tsin.sin_addr,(char*)&addr,sizeof(addr));
|
||||
|
||||
if(connect(osoc,(struct sockaddr*)&tsin,sizeof(tsin))<0)
|
||||
{
|
||||
perror("BdtIpOpen: connect failed");
|
||||
close(osoc);
|
||||
return (BDT*)NULL;
|
||||
}
|
||||
|
||||
bdt=(BDT*)malloc(sizeof(BDT));
|
||||
bdt->soc=osoc;
|
||||
bdt->remaining_send=0;
|
||||
bdt->remaining_recv=0;
|
||||
bdt->state=BdtUnbound;
|
||||
|
||||
#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 BdtWrite(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(soc+1, NULL, &fds, NULL, &to) != 1)
|
||||
{
|
||||
printf("BdtWrite: timeout waiting to write data\n");
|
||||
return(-1);
|
||||
}
|
||||
/* send block of data */
|
||||
if((rc=send(soc,&data[size-total],total,0))<0)
|
||||
{
|
||||
if(errno == EINTR)
|
||||
rc = 0;
|
||||
else
|
||||
perror("BdtWrite: Send to remote failed");
|
||||
}
|
||||
else
|
||||
total-=rc;
|
||||
}
|
||||
while(rc>0 && total>0);
|
||||
|
||||
return (rc<=0)?-1:0;
|
||||
}
|
||||
|
||||
/* --------------------------------------- */
|
||||
/* send a message header down a BDT socket */
|
||||
/* --------------------------------------- */
|
||||
int BdtSendHeader(BDT* bdt,unsigned short verb,int size)
|
||||
{
|
||||
BdtMsgHead buf;
|
||||
|
||||
if(bdt->state!=BdtIdle)
|
||||
{
|
||||
fprintf(stderr,"BdtSendHeader: Interface not idle\n");
|
||||
bdt->state=BdtBad;
|
||||
return -1;
|
||||
}
|
||||
|
||||
buf.verb=htons(verb);
|
||||
buf.size=htonl((unsigned long)size);
|
||||
|
||||
if(BdtWrite(bdt->soc,&buf.verb, sizeof(buf.verb))<0)
|
||||
{
|
||||
fprintf(stderr,"BdtSendHeader: write to remote failed");
|
||||
return -1;
|
||||
}
|
||||
if(BdtWrite(bdt->soc,&buf.size, sizeof(buf.size))<0)
|
||||
{
|
||||
fprintf(stderr,"BdtSendHeader: write to remote failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* don't wait for response if data must go out */
|
||||
if(size)
|
||||
{
|
||||
bdt->remaining_send=size;
|
||||
bdt->state=BdtSData;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------- */
|
||||
/* send a message data chunk down a BDT socket */
|
||||
/* ------------------------------------------- */
|
||||
int BdtSendData(BDT* bdt,void* buffer,int size)
|
||||
{
|
||||
int len;
|
||||
int remaining;
|
||||
int rc;
|
||||
|
||||
if(bdt->state!=BdtSData)
|
||||
{
|
||||
fprintf(stderr,"BdtSendData: Interface not in send data mode\n");
|
||||
bdt->state=BdtBad;
|
||||
return -1;
|
||||
}
|
||||
|
||||
remaining=bdt->remaining_send-size;
|
||||
|
||||
if(remaining<0)
|
||||
{
|
||||
fprintf(stderr,"WARNING -- BdtSendData: To much data to send\n");
|
||||
len=bdt->remaining_send;
|
||||
}
|
||||
else
|
||||
len=size;
|
||||
|
||||
if (BdtWrite(bdt->soc, buffer, len) < 0)
|
||||
return -1;
|
||||
|
||||
bdt->remaining_send-=len;
|
||||
|
||||
if(bdt->remaining_send<0)
|
||||
{
|
||||
fprintf(stderr,"BdtSendData: To much data Sent\n");
|
||||
bdt->remaining_send=0;
|
||||
}
|
||||
|
||||
if(bdt->remaining_send==0)
|
||||
bdt->state=BdtIdle;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
int BdtFlushOutput(BDT* bdt)
|
||||
{
|
||||
#ifdef vxWorks
|
||||
ioctl(bdt->soc, FIOWFLUSH, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* ------------------------------------- */
|
||||
/* Read exactly size bytes from remote */
|
||||
/* ------------------------------------- */
|
||||
int BdtRead(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("BdtRead: timeout waiting for data\n");
|
||||
return(-1);
|
||||
}
|
||||
#endif
|
||||
if((rc=recv(soc,&data[size-total],total,0))<0)
|
||||
{
|
||||
if(errno==EINTR)
|
||||
{
|
||||
printf("BdtRead: EINTR");
|
||||
rc=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
perror("BdtRead: 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 BdtReceiveHeader(BDT* bdt,int* verb,int* size)
|
||||
{
|
||||
BdtMsgHead buf;
|
||||
|
||||
/* can only receive header when in the idle state */
|
||||
if (bdt->state == BdtEof)
|
||||
return -1;
|
||||
|
||||
if(bdt->state != BdtIdle)
|
||||
{
|
||||
fprintf(stderr,"BdtReceiveHeader: Interface not idle\n");
|
||||
bdt->state=BdtBad;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(BdtRead(bdt->soc,&buf.verb,sizeof(buf.verb))<0)
|
||||
{
|
||||
fprintf(stderr,"BdtReceiveHeader: Read failed\n");
|
||||
return -1;
|
||||
}
|
||||
if(BdtRead(bdt->soc,&buf.size,sizeof(buf.size))<0)
|
||||
{
|
||||
fprintf(stderr,"BdtReceiveHeader: Read failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* copy message data to user */
|
||||
*verb=ntohs(buf.verb);
|
||||
*size=ntohl(buf.size);
|
||||
|
||||
if(*size)
|
||||
bdt->state=BdtRData;
|
||||
|
||||
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 BdtReceiveData(BDT* bdt,void* buffer,int size)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* can only receive data when in the receive data state */
|
||||
switch(bdt->state)
|
||||
{
|
||||
case BdtRData: break;
|
||||
case BdtIdle: return 0;
|
||||
default:
|
||||
fprintf(stderr,"BdtReceiveData: bad receive state\n");
|
||||
bdt->state=BdtBad;
|
||||
break;
|
||||
}
|
||||
|
||||
if (bdt->remaining_recv < size)
|
||||
size = bdt->remaining_recv;
|
||||
|
||||
if(BdtRead(bdt->soc,buffer,size)<0)
|
||||
{
|
||||
fprintf(stderr,"BdtReceiveData: Read failed\n");
|
||||
bdt->state = BdtEof;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bdt->remaining_recv-=size;
|
||||
|
||||
if(bdt->remaining_recv<0)
|
||||
{
|
||||
fprintf(stderr,"BdtReceiveData: To much data received\n");
|
||||
bdt->remaining_recv=0;
|
||||
}
|
||||
|
||||
if(bdt->remaining_recv==0)
|
||||
bdt->state=BdtIdle;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------ */
|
||||
/* connect to a process variable, useful if raw open used */
|
||||
/* ------------------------------------------------------ */
|
||||
int BdtServiceConnect(BDT* bdt, char* Name, char *Args)
|
||||
{
|
||||
int len;
|
||||
int rc;
|
||||
int size;
|
||||
int verb;
|
||||
unsigned char NameLen;
|
||||
unsigned char ArgLen;
|
||||
|
||||
if(bdt->state!=BdtUnbound)
|
||||
{
|
||||
fprintf(stderr,"BdtServiceConnect: can only bind to one service\n");
|
||||
return -1;
|
||||
}
|
||||
bdt->state=BdtIdle;
|
||||
NameLen = strlen(Name)+1;
|
||||
if (Args != NULL)
|
||||
ArgLen = strlen(Args)+1;
|
||||
else
|
||||
ArgLen = 0;
|
||||
|
||||
/* send out connect message */
|
||||
if(BdtSendHeader(bdt, BDT_Connect, NameLen+ArgLen) < 0)
|
||||
{
|
||||
fprintf(stderr,"BdtServiceConnect: send of connect header failed\n");
|
||||
bdt->state=BdtUnbound;
|
||||
return -1;
|
||||
}
|
||||
|
||||
NameLen--;
|
||||
ArgLen--;
|
||||
/* send out the process variable to connect to */
|
||||
if((BdtSendData(bdt, &NameLen, 1) < 0) || (BdtSendData(bdt, Name, NameLen) < 0))
|
||||
|
||||
{
|
||||
fprintf(stderr,"BdtServiceConnect: send of connect body failed\n");
|
||||
bdt->state=BdtUnbound;
|
||||
return -1;
|
||||
}
|
||||
if (ArgLen > 0)
|
||||
{
|
||||
if ((BdtSendData(bdt, &ArgLen, 1) < 0) || (BdtSendData(bdt, Args, ArgLen) < 0))
|
||||
{
|
||||
fprintf(stderr,"BdtServiceConnect: send of connect body failed\n");
|
||||
bdt->state=BdtUnbound;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
rc=0;
|
||||
|
||||
/* wait for response from connect to process variable */
|
||||
if(BdtReceiveHeader(bdt,&verb,&size)<0)
|
||||
{
|
||||
fprintf(stderr,"BdtServiceConnect: receive reponse failed\n");
|
||||
bdt->state=BdtUnbound;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* check response */
|
||||
switch(verb)
|
||||
{
|
||||
case BDT_Ok:
|
||||
rc=0;
|
||||
break;
|
||||
case BDT_Error:
|
||||
fprintf(stderr,"BdtServiceConnect: connection rejected\n");
|
||||
bdt->state=BdtUnbound;
|
||||
rc=-1;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"BdtServiceConnect: unknown response from remote\n");
|
||||
bdt->state=BdtUnbound;
|
||||
rc=-1;
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* -------------------- */
|
||||
/* close the connection */
|
||||
/* -------------------- */
|
||||
int BdtClose(BDT* bdt)
|
||||
{
|
||||
int verb,size,done;
|
||||
|
||||
/* send a close message out */
|
||||
if(BdtSendHeader(bdt,BDT_Close,0)<0)
|
||||
{
|
||||
fprintf(stderr,"BdtClose: Cannot send close message\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
done=0;
|
||||
|
||||
do
|
||||
{
|
||||
/* check response */
|
||||
if(BdtReceiveHeader(bdt,&verb,&size)<0)
|
||||
{
|
||||
fprintf(stderr,"BdtClose: Close message response error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch(verb)
|
||||
{
|
||||
case BDT_Ok:
|
||||
done=1;
|
||||
break;
|
||||
case BDT_Error:
|
||||
fprintf(stderr,"BdtClose: Close rejected\n");
|
||||
return -1;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
while(done==0);
|
||||
|
||||
bdt->state=BdtUnbound;
|
||||
free(bdt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------- */
|
||||
/* make a listener socket for UDP - simple */
|
||||
/* --------------------------------------- */
|
||||
int BdtOpenListenerUDP(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,BDT_UDP))<0)
|
||||
{
|
||||
perror("BdtOpenListenerUDP: open socket failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((bind(nsoc,(struct sockaddr*)&tsin,sizeof(tsin)))<0)
|
||||
{
|
||||
perror("BdtOpenListenerUDP: local bind failed");
|
||||
close(nsoc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nsoc;
|
||||
}
|
||||
|
||||
/* --------------------------------------- */
|
||||
/* make a listener socket for TCP - simple */
|
||||
/* --------------------------------------- */
|
||||
int BdtOpenListenerTCP(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,BDT_TCP))<0)
|
||||
{
|
||||
perror("BdtOpenListenerTCP: open socket failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((bind(nsoc,(struct sockaddr*)&tsin,sizeof(tsin)))<0)
|
||||
{
|
||||
perror("BdtOpenListenerTCP: local bind failed");
|
||||
close(nsoc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
listen(nsoc,5);
|
||||
return nsoc;
|
||||
}
|
||||
|
||||
/* ------------------------------- */
|
||||
/* make BDT from a socket - simple */
|
||||
/* ------------------------------- */
|
||||
BDT* BdtMakeBDT(int soc)
|
||||
{
|
||||
BDT* bdt;
|
||||
bdt=(BDT*)malloc(sizeof(BDT));
|
||||
bdt->soc=soc;
|
||||
bdt->remaining_send=0;
|
||||
bdt->remaining_recv=0;
|
||||
bdt->state=BdtIdle;
|
||||
return bdt;
|
||||
}
|
||||
|
||||
/* --------------------------- */
|
||||
/* free a BDT and close socket */
|
||||
/* --------------------------- */
|
||||
int BdtFreeBDT(BDT* bdt)
|
||||
{
|
||||
close(bdt->soc);
|
||||
free(bdt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int BdtPvPutArray(BDT *bdt, short DbrType, void *Buf, unsigned long NumElements,
|
||||
unsigned long ElementSize)
|
||||
{
|
||||
int Verb;
|
||||
int Size;
|
||||
unsigned long BufSize;
|
||||
|
||||
BufSize = NumElements * ElementSize;
|
||||
if (BdtSendHeader(bdt, BDT_Put, 6 + BufSize) != 0)
|
||||
return(-1);
|
||||
if (BdtSendData(bdt, &DbrType, 2) < 0)
|
||||
return(-1);
|
||||
if (BdtSendData(bdt, &NumElements, 4) < 0)
|
||||
return(-1);
|
||||
if (BdtSendData(bdt, Buf, BufSize) < 0)
|
||||
return(-1);
|
||||
if (BdtReceiveHeader(bdt, &Verb, &Size) != 0)
|
||||
return(-1);
|
||||
if (Verb != BDT_Ok)
|
||||
return(-1);
|
||||
|
||||
return(0);
|
||||
}
|
||||
392
src/bdt/bdtServ.c
Normal file
392
src/bdt/bdtServ.c
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
*
|
||||
* Author: John Winans
|
||||
* Date: 95-05-22
|
||||
*
|
||||
* $Log$
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* IOC listener task blocks on accept calls waiting for binders.
|
||||
* If a bind arrives, a receiver task is spawned.
|
||||
*
|
||||
* IOC receiver task blocks on read calls waiting for transactions.
|
||||
* When a transaction arrives it is serviced.
|
||||
* At the end of a transaction service, a response is sent back.
|
||||
* After the response is sent, a chack is made to see if a delta transmission
|
||||
* was blocked by the transaction's use of the socket... if so, it is sent.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <selectLib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <vxWorks.h>
|
||||
#include <sys/socket.h>
|
||||
#include <in.h>
|
||||
#include <inetLib.h>
|
||||
#include <taskLib.h>
|
||||
#include <sysSymTbl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bdt.h"
|
||||
|
||||
#define BDT_TASK_PRIO 200
|
||||
#define BDT_TASK_OPTIONS VX_FP_TASK
|
||||
#define BDT_TASK_STACK 5000
|
||||
#define STATIC static
|
||||
|
||||
/* used for debugging */
|
||||
STATIC char *BdtNames[] = {
|
||||
"BDT_Ok",
|
||||
"BDT_Connect",
|
||||
"BDT_Error",
|
||||
"BDT_Get",
|
||||
"BDT_Put",
|
||||
"BDT_Close",
|
||||
"BDT_Monitor",
|
||||
"BDT_Value",
|
||||
"BDT_Delta",
|
||||
"BDT_Add",
|
||||
"BDT_Delete",
|
||||
"BDT_Ping"
|
||||
};
|
||||
|
||||
STATIC int HexDump(char *ReadBuffer, int rbytes);
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* A debugging routine that hex-dumps a message to the console.
|
||||
*
|
||||
*****************************************************************************/
|
||||
void BDT_DumpMessage(BDT *Bdt)
|
||||
{
|
||||
char Buf[16*4];
|
||||
int RecvLen;
|
||||
|
||||
while(Bdt->remaining_recv)
|
||||
{
|
||||
RecvLen = (Bdt->remaining_recv > sizeof(Buf)) ? sizeof(Buf): Bdt->remaining_recv;
|
||||
if (BdtReceiveData(Bdt, Buf, RecvLen) != RecvLen)
|
||||
return; /* Got EOF, (EOM handled by the while() */
|
||||
|
||||
HexDump(Buf, RecvLen);
|
||||
}
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Throw away a message.
|
||||
*
|
||||
****************************************************************************/
|
||||
void BDT_DiscardMessage(BDT *Bdt)
|
||||
{
|
||||
char Buf[16*4];
|
||||
int RecvLen;
|
||||
|
||||
while(Bdt->remaining_recv)
|
||||
{
|
||||
RecvLen = (Bdt->remaining_recv > sizeof(Buf)) ? sizeof(Buf): Bdt->remaining_recv;
|
||||
if (BdtReceiveData(Bdt, Buf, RecvLen) != RecvLen)
|
||||
return; /* Got EOF, (EOM handled by the while() */
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Process a single Connect message. And return a response.
|
||||
*
|
||||
******************************************************************************/
|
||||
STATIC int BDT_ProcessConnect(BDT *Bdt)
|
||||
{
|
||||
SYM_TYPE Type;
|
||||
unsigned char length;
|
||||
char Buf[50];
|
||||
char HandlerName[70];
|
||||
|
||||
if (Bdt->remaining_recv > sizeof(Buf))
|
||||
{
|
||||
printf("BDT_ProcessConnect Connect Message too long %d\n", Bdt->remaining_recv);
|
||||
BDT_DiscardMessage(Bdt);
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
if (Bdt->remaining_recv < 2)
|
||||
{
|
||||
printf("BDT_ProcessConnect Connect Message w/missing service name\n");
|
||||
BDT_DiscardMessage(Bdt);
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
BdtReceiveData(Bdt, &length, 1);
|
||||
if (length > sizeof(Buf))
|
||||
{
|
||||
printf("BDT_ProcessConnect Connect Message service name too long %d\n", length);
|
||||
BDT_DiscardMessage(Bdt);
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
BdtReceiveData(Bdt, Buf, length);
|
||||
Buf[length] = '\0';
|
||||
|
||||
sprintf(HandlerName, "_BDT_ServiceHandler_%s", Buf);
|
||||
printf("BDT_ProcessConnect NAME service (%s)\n", HandlerName);
|
||||
|
||||
/*Bdt->pHandlers = (BdthandlerFunc *)(&BDT_NameServicehandlers);*/
|
||||
if (symFindByName(sysSymTbl, HandlerName, (char **)&(Bdt->pHandlers), &Type) != OK)
|
||||
{
|
||||
printf("BDT_ProcessConnect Connect to unknown service (%s)\n", Buf);
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
Bdt->Name = (char *)malloc(strlen(Buf)+1);
|
||||
strcpy(Bdt->Name, Buf);
|
||||
if (Bdt->pHandlers[BDT_Connect] != NULL)
|
||||
return((*(Bdt->pHandlers[BDT_Connect]))(Bdt));
|
||||
else
|
||||
{
|
||||
BDT_DiscardMessage(Bdt);
|
||||
BdtSendHeader(Bdt, BDT_Ok, 0);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Process a single message. And return a response.
|
||||
*
|
||||
******************************************************************************/
|
||||
STATIC int BDT_ProcMessage(BDT *Bdt, unsigned short Command)
|
||||
{
|
||||
int RecvLen;
|
||||
|
||||
if (Command > BDT_LAST_VERB)
|
||||
{
|
||||
printf("BDT: %s Invalid command %d, length = %d\n", Bdt->Name, Command, Bdt->remaining_recv);
|
||||
BDT_DumpMessage(Bdt);
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (Bdt->pHandlers == NULL)
|
||||
{
|
||||
if (Command == BDT_Connect)
|
||||
BDT_ProcessConnect(Bdt);
|
||||
else
|
||||
{
|
||||
printf("BDT_ProcMessage: %s got %s before connect\n", Bdt->Name, BdtNames[Command]);
|
||||
BDT_DiscardMessage(Bdt);
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
if (Bdt->pHandlers[Command] == NULL)
|
||||
{
|
||||
printf("BDT_ProcMessage: service %s got %s... invalid\n", Bdt->Name, BdtNames[Command]);
|
||||
}
|
||||
return((*(Bdt->pHandlers[Command]))(Bdt));
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Wait on a socket read for a message. When one arrives, read the header,
|
||||
* decode it, and call the message handler routine to process and respond to it.
|
||||
*
|
||||
******************************************************************************/
|
||||
STATIC void BDT_ReceiverTask(int Sock)
|
||||
{
|
||||
int Verb;
|
||||
int Size;
|
||||
BDT Bdt;
|
||||
int MonitorLockTimeout = (BDT_PING_INTERVAL*sysClkRateGet())/2;
|
||||
static char *NoBdtName = "(No Name)";
|
||||
fd_set FdSet;
|
||||
struct timeval TimeVal;
|
||||
int PollStatus;
|
||||
int SocketState;
|
||||
|
||||
Bdt.soc = Sock;
|
||||
Bdt.pMonitor = NULL;
|
||||
Bdt.WriteLock = semBCreate(SEM_Q_PRIORITY, SEM_FULL);
|
||||
Bdt.MonitorLock = semBCreate(SEM_Q_PRIORITY, SEM_FULL);
|
||||
Bdt.state = BdtIdle;
|
||||
Bdt.pHandlers = NULL;
|
||||
Bdt.Name = NoBdtName;
|
||||
|
||||
printf("BDT_ReceiverTask(%d) started\n", Sock);
|
||||
|
||||
TimeVal.tv_sec = BDT_CONENCTION_TIMEOUT;
|
||||
TimeVal.tv_usec = 0;
|
||||
FD_ZERO(&FdSet);
|
||||
FD_SET(Bdt.soc, &FdSet);
|
||||
|
||||
SocketState = 0;
|
||||
while (((PollStatus = select(FD_SETSIZE, &FdSet, NULL, NULL, &TimeVal)) > 0) && (BdtReceiveHeader(&Bdt, &Verb, &Size) == 0))
|
||||
{
|
||||
semTake(Bdt.WriteLock, WAIT_FOREVER);
|
||||
|
||||
SocketState = BDT_ProcMessage(&Bdt, Verb);
|
||||
|
||||
if (SocketState != 0)
|
||||
break;
|
||||
|
||||
#if 0
|
||||
if (semTake(Bdt.MonitorLock, MonitorLockTimeout) == OK)
|
||||
{
|
||||
/* Check for delta flag and send if so */
|
||||
|
||||
/* Change this to run thru a delta-message linked list */
|
||||
if (Bdt.pMonitor != NULL)
|
||||
{
|
||||
/* Send delta notifier */
|
||||
}
|
||||
semGive(Bdt.WriteLock); /* Order important for BDT_SendDelta */
|
||||
semGive(Bdt.MonitorLock);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("BDT_ReceiverTask timeout on monitor semaphore. Monitors are stuck!\n");
|
||||
semGive(Bdt.WriteLock);
|
||||
}
|
||||
#else
|
||||
semGive(Bdt.WriteLock);
|
||||
#endif
|
||||
BdtFlushOutput(&Bdt);
|
||||
|
||||
FD_ZERO(&FdSet);
|
||||
FD_SET(Bdt.soc, &FdSet);
|
||||
}
|
||||
if (SocketState == 0)
|
||||
{
|
||||
if (PollStatus == 0)
|
||||
printf("BDT_ReceiverTask(%d) exiting on client timeout\n", Sock);
|
||||
else
|
||||
printf("BDT_ReceiverTask(%d) exiting on I/O error talking to Client\n", Sock);
|
||||
}
|
||||
else
|
||||
printf("BDT_ReceiverTask(%d) received close from client\n", Sock);
|
||||
|
||||
/* Free up resources */
|
||||
if (Bdt.Name != NoBdtName)
|
||||
free(Bdt.Name);
|
||||
|
||||
close(Sock);
|
||||
semDelete(Bdt.WriteLock);
|
||||
semDelete(Bdt.MonitorLock);
|
||||
return;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
******************************************************************************/
|
||||
#if 0
|
||||
int BDT_SendDelta(int Socket, char *Message)
|
||||
{
|
||||
semTake (DeltaFlagLock, WAIT_FOREVER);
|
||||
if (if (semTake(SocketWriteLock, no wait) == failed)
|
||||
{
|
||||
/* Reader task is busy... Post message for future transmission */
|
||||
Bdt.pending_delta = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
write(Message); /* This COULD block */
|
||||
semGive(SocketWriteLock);
|
||||
}
|
||||
semGive(DeltaFlagLock);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* This task listens on a port for new connections. When one is made, it
|
||||
* spawns a task to manage it.
|
||||
*
|
||||
******************************************************************************/
|
||||
void BDT_ListenerTask(int Port)
|
||||
{
|
||||
/* Open a socket to listen on */
|
||||
struct sockaddr_in ListenerAddr;
|
||||
struct sockaddr_in ClientAddr;
|
||||
int ListenerSock;
|
||||
int ClientSock;
|
||||
int ClientAddrLen;
|
||||
int SockAddrSize = sizeof(struct sockaddr_in);
|
||||
|
||||
if (Port == 0)
|
||||
Port = BDT_TCP_PORT;
|
||||
|
||||
printf("BDT_Listener(%d) started\n", Port);
|
||||
|
||||
if ((ListenerSock = BdtOpenListenerTCP(Port)) < 0)
|
||||
{
|
||||
printf("BDT_ListenerTask(%d) can't start listener\n", Port);
|
||||
return;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
ClientAddrLen = sizeof(ClientAddr);
|
||||
if((ClientSock = accept(ListenerSock, (struct sockaddr*)&ClientAddr, &ClientAddrLen)) < 0)
|
||||
{
|
||||
if(errno!=EINTR)
|
||||
{
|
||||
printf("BDT_ListenerTask(%d) accept() failed\n", Port);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Spawn a task to handle the new connection */
|
||||
printf("Accepted a connection\n");
|
||||
taskSpawn("BDT", BDT_TASK_PRIO, BDT_TASK_OPTIONS, BDT_TASK_STACK, (FUNCPTR)BDT_ReceiverTask, ClientSock, 2,3,4,5,6,7,8,9,0);
|
||||
}
|
||||
}
|
||||
/* Never reached */
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* A handy routine to assist in debugging.
|
||||
*
|
||||
******************************************************************************/
|
||||
STATIC int HexDump(char *ReadBuffer, int rbytes)
|
||||
{
|
||||
int c = 0;
|
||||
int i = 0;
|
||||
int firsttime;
|
||||
char ascii[20]; /* To hold printable portion of string */
|
||||
|
||||
if (!rbytes)
|
||||
return(0);
|
||||
|
||||
firsttime = 1;
|
||||
while(c < rbytes)
|
||||
{
|
||||
if ((c % 16) == 0)
|
||||
{
|
||||
if (!firsttime)
|
||||
{
|
||||
ascii[i] = '\0';
|
||||
printf(" *%s*\n", ascii);
|
||||
}
|
||||
firsttime=0;
|
||||
i = 0;
|
||||
}
|
||||
printf(" %02.2X", ReadBuffer[c] & 0xff);
|
||||
ascii[i] = ReadBuffer[c];
|
||||
if (!isprint(ascii[i]))
|
||||
ascii[i] = '.';
|
||||
++i;
|
||||
++c;
|
||||
}
|
||||
while (c%16)
|
||||
{
|
||||
fputs(" ", stdout);
|
||||
++c;
|
||||
}
|
||||
ascii[i] = '\0';
|
||||
printf(" *%s*\n", ascii);
|
||||
return(0);
|
||||
}
|
||||
129
src/bdt/bdtServName.c
Normal file
129
src/bdt/bdtServName.c
Normal file
@@ -0,0 +1,129 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Author: John Winans
|
||||
* Date: 95-06-05
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $Log$
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <selectLib.h>
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* IOC listener task blocks on accept calls waiting for binders.
|
||||
* If a bind arrives, a receiver task is spawned.
|
||||
*
|
||||
* IOC receiver task blocks on read calls waiting for transactions.
|
||||
* When a transaction arrives it is serviced.
|
||||
* At the end of a transaction service, a response is sent back.
|
||||
* After the response is sent, a chack is made to see if a delta transmission
|
||||
* was blocked by the transaction's use of the socket... if so, it is sent.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <sys/socket.h>
|
||||
#include <in.h>
|
||||
#include <inetLib.h>
|
||||
#include <taskLib.h>
|
||||
|
||||
#include "bdt.h"
|
||||
|
||||
#define STATIC static
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_NameServiceOk(BDT *Bdt)
|
||||
{
|
||||
printf("BDT_NameServiceOk \n");
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_NameServiceConnect(BDT *Bdt)
|
||||
{
|
||||
printf("BDT_NameServiceConnect \n");
|
||||
BdtSendHeader(Bdt, BDT_Ok, 0);
|
||||
return(0);
|
||||
}
|
||||
STATIC int BDT_NameServiceError(BDT *Bdt)
|
||||
{
|
||||
printf("BDT_NameServiceError \n");
|
||||
return(0);
|
||||
}
|
||||
STATIC int BDT_NameServiceGet(BDT *Bdt)
|
||||
{
|
||||
printf("BDT_NameServiceGet \n");
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
STATIC int BDT_NameServicePut(BDT *Bdt)
|
||||
{
|
||||
printf("BDT_NameServicePut \n");
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
STATIC int BDT_NameServiceClose(BDT *Bdt)
|
||||
{
|
||||
printf("BDT_NameServiceClose \n");
|
||||
BdtSendHeader(Bdt, BDT_Ok, 0);
|
||||
return(0);
|
||||
}
|
||||
STATIC int BDT_NameServiceMonitor(BDT *Bdt)
|
||||
{
|
||||
printf("BDT_NameServiceMonitor \n");
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
STATIC int BDT_NameServiceValue(BDT *Bdt)
|
||||
{
|
||||
printf("BDT_NameServiceValue \n");
|
||||
return(0);
|
||||
}
|
||||
STATIC int BDT_NameServiceDelta(BDT *Bdt)
|
||||
{
|
||||
printf("BDT_NameServiceDelta \n");
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
STATIC int BDT_NameServiceAdd(BDT *Bdt)
|
||||
{
|
||||
printf("BDT_NameServiceAdd \n");
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
STATIC int BDT_NameServiceDelete(BDT *Bdt)
|
||||
{
|
||||
printf("BDT_NameServiceDelete \n");
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
STATIC int BDT_NameServicePing(BDT *Bdt)
|
||||
{
|
||||
printf("BDT_NameServicePing \n");
|
||||
BdtSendHeader(Bdt, BDT_Ok, 0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
BdtHandlers BDT_ServiceHandler_name =
|
||||
{
|
||||
BDT_NameServiceOk,
|
||||
BDT_NameServiceConnect,
|
||||
BDT_NameServiceError,
|
||||
BDT_NameServiceGet,
|
||||
BDT_NameServicePut,
|
||||
BDT_NameServiceClose,
|
||||
BDT_NameServiceMonitor,
|
||||
BDT_NameServiceValue,
|
||||
BDT_NameServiceDelta,
|
||||
BDT_NameServiceAdd,
|
||||
BDT_NameServiceDelete,
|
||||
BDT_NameServicePing
|
||||
};
|
||||
377
src/bdt/bdtServPv.c
Normal file
377
src/bdt/bdtServPv.c
Normal file
@@ -0,0 +1,377 @@
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Author: John Winans
|
||||
* Date: 95-06-05
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $Log$
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <semLib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <dbCommon.h>
|
||||
#include <dbAccess.h>
|
||||
|
||||
#include "bdt.h"
|
||||
|
||||
#define STATIC static
|
||||
#define MESSAGE_PREFIX "BDT PV server:"
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* These conversion finctions take care of one of the most insane parts
|
||||
* of dealing with database access... having two different interfaces that
|
||||
* have the same named enumerators in two seperate header files... that
|
||||
* therefore can not be both included in the same file.
|
||||
*
|
||||
* This is so bad, I wanted to vomit when typing it in.
|
||||
*
|
||||
******************************************************************************/
|
||||
STATIC int DbrOld2New(int Old)
|
||||
{
|
||||
switch (Old)
|
||||
{
|
||||
case 0: return(DBR_STRING);
|
||||
case 1: return(DBR_SHORT);
|
||||
case 2: return(DBR_FLOAT);
|
||||
case 3: return(DBR_ENUM);
|
||||
case 4: return(DBR_CHAR);
|
||||
case 5: return(DBR_LONG);
|
||||
case 6: return(DBR_DOUBLE);
|
||||
default:
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC int DbrNew2Old(int New)
|
||||
{
|
||||
switch (New)
|
||||
{
|
||||
case DBR_STRING: return(0);
|
||||
case DBR_CHAR: return(4);
|
||||
case DBR_UCHAR: return(4);
|
||||
case DBR_SHORT: return(1);
|
||||
case DBR_USHORT: return(1);
|
||||
case DBR_LONG: return(5);
|
||||
case DBR_ULONG: return(5);
|
||||
case DBR_FLOAT: return(2);
|
||||
case DBR_DOUBLE: return(6);
|
||||
case DBR_ENUM: return(3);
|
||||
default:
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Handle the receipt of an OK message.
|
||||
*
|
||||
* The OK message is received as a confirmation of the last operation. It is
|
||||
* not normally responded to.
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_ServiceOk(BDT *Bdt)
|
||||
{
|
||||
printf("%s got a Ok message\n", MESSAGE_PREFIX);
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Handle the receipt of a Connect message.
|
||||
*
|
||||
* The Connect is received when a new connection is first made.
|
||||
* Any arguments left in the message body have not yet been read.
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_ServiceConnect(BDT *Bdt)
|
||||
{
|
||||
unsigned char Length;
|
||||
char Buf[100];
|
||||
struct dbAddr *pDbAddr;
|
||||
|
||||
Buf[0] = '\0';
|
||||
if (Bdt->remaining_recv > 0)
|
||||
{
|
||||
BdtReceiveData(Bdt, &Length, 1);
|
||||
if (Length <= sizeof(Buf))
|
||||
{
|
||||
BdtReceiveData(Bdt, Buf, Length);
|
||||
Buf[Length] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s Connect message argument list too long\n", MESSAGE_PREFIX);
|
||||
BDT_DiscardMessage(Bdt);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
}
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf("%s got Connect >%s<\n", MESSAGE_PREFIX, Buf);
|
||||
#endif
|
||||
/* Find the PV in the database */
|
||||
Bdt->pService = malloc(sizeof(struct dbAddr));
|
||||
pDbAddr = (struct dbAddr *)(Bdt->pService);
|
||||
if (dbNameToAddr(Buf, pDbAddr))
|
||||
{
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
free(Bdt->pService);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pDbAddr->dbr_field_type != pDbAddr->field_type)
|
||||
{
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
free(Bdt->pService);
|
||||
}
|
||||
else
|
||||
BdtSendHeader(Bdt, BDT_Ok, 0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Handle the receipt of an Error message.
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_ServiceError(BDT *Bdt)
|
||||
{
|
||||
printf("%s got a Error message\n", MESSAGE_PREFIX);
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Handle the receipt of a Get message.
|
||||
*
|
||||
* The response to a Get message is either an Error or a Value:
|
||||
*
|
||||
* Value message body format:
|
||||
* SHORT EPICS data type enumerator (in old format)
|
||||
* LONG Number of elements
|
||||
* CHAR[] Value image
|
||||
*
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_ServiceGet(BDT *Bdt)
|
||||
{
|
||||
void *Buf;
|
||||
struct dbAddr *pDbAddr = (struct dbAddr *)(Bdt->pService);
|
||||
long NumElements;
|
||||
long Size;
|
||||
long l;
|
||||
short OldType;
|
||||
int stat;
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf("%s got a Get message\n", MESSAGE_PREFIX);
|
||||
|
||||
printf("field type=%d, field size=%d, elements=%d\n", pDbAddr->field_type, pDbAddr->field_size, pDbAddr->no_elements);
|
||||
#endif
|
||||
|
||||
OldType = DbrNew2Old(pDbAddr->field_type);
|
||||
if (OldType < 0)
|
||||
{
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
/* Allocate a buffer to hold the response message data */
|
||||
Buf = malloc(pDbAddr->field_size * pDbAddr->no_elements);
|
||||
if (Buf == NULL)
|
||||
{
|
||||
printf("Can't allocate %d-byte buffer for get request to %s\n",
|
||||
pDbAddr->field_size * pDbAddr->no_elements,
|
||||
pDbAddr->precord->name);
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
/* Get the response message data */
|
||||
NumElements = pDbAddr->no_elements;
|
||||
if (stat=dbGetField(pDbAddr, pDbAddr->field_type, Buf, 0, &NumElements, NULL))
|
||||
{
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
#if 0
|
||||
/* Test hack to transfer HUGE buffers */
|
||||
NumElements = pDbAddr->no_elements;
|
||||
#endif
|
||||
/* Send the response message */
|
||||
Size = NumElements * pDbAddr->field_size;
|
||||
BdtSendHeader(Bdt, BDT_Value, Size + sizeof(long) + sizeof(short));
|
||||
BdtSendData(Bdt, &OldType, sizeof(short));
|
||||
BdtSendData(Bdt, &NumElements, sizeof(long));
|
||||
if (Size)
|
||||
BdtSendData(Bdt, Buf, Size);
|
||||
free(Buf);
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Handle the receipt of a Put message.
|
||||
*
|
||||
* Put message body format:
|
||||
* SHORT EPICS data type enumerator
|
||||
* LONG Number of elements
|
||||
* CHAR[] Value image
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_ServicePut(BDT *Bdt)
|
||||
{
|
||||
long Size;
|
||||
void *Buf;
|
||||
short DbrType;
|
||||
long NumElements;
|
||||
struct dbAddr *pDbAddr = (struct dbAddr *)(Bdt->pService);
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf("%s got a Put message\n", MESSAGE_PREFIX);
|
||||
#endif
|
||||
if (BdtGetResidualRead(Bdt) < 6)
|
||||
{
|
||||
BDT_DiscardMessage(Bdt);
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
if (BdtGetResidualRead(Bdt) == 6)
|
||||
{ /* Do data contents, just toss it */
|
||||
BDT_DiscardMessage(Bdt);
|
||||
BdtSendHeader(Bdt, BDT_Ok, 0);
|
||||
return(0);
|
||||
}
|
||||
Buf = malloc(BdtGetResidualRead(Bdt) - 6);
|
||||
if (Buf == NULL)
|
||||
{
|
||||
printf("Can't allocate %d-byte buffer for put request to %s\n",
|
||||
BdtGetResidualRead(Bdt), pDbAddr->precord->name);
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
BdtReceiveData(Bdt, &DbrType, 2);
|
||||
BdtReceiveData(Bdt, &NumElements, 4);
|
||||
|
||||
#ifdef DEBUG_VERBOSE
|
||||
printf("record field type=%d, field size=%d, elements=%d\n", pDbAddr->field_type, pDbAddr->field_size, pDbAddr->no_elements);
|
||||
printf("message field type=%d, field size=%d, elements=%d total %d\n", DbrType, pDbAddr->field_type ,NumElements, BdtGetResidualRead(Bdt));
|
||||
#endif
|
||||
|
||||
BdtReceiveData(Bdt, Buf, BdtGetResidualRead(Bdt));
|
||||
DbrType = DbrOld2New(DbrType);
|
||||
|
||||
if (DbrType < 0)
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
else if (dbPutField(pDbAddr, DbrType, Buf, NumElements))
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
else
|
||||
BdtSendHeader(Bdt, BDT_Ok, 0);
|
||||
|
||||
free(Buf);
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Handle the receipt of a Close message.
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_ServiceClose(BDT *Bdt)
|
||||
{
|
||||
printf("%s got a Close message\n", MESSAGE_PREFIX);
|
||||
free(Bdt->pService);
|
||||
BdtSendHeader(Bdt, BDT_Ok, 0);
|
||||
return(1);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Handle the receipt of a Monitor message.
|
||||
*
|
||||
* Not Supported.
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_ServiceMonitor(BDT *Bdt)
|
||||
{
|
||||
printf("%s got a Monitor message\n", MESSAGE_PREFIX);
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Handle the receipt of a Value message.
|
||||
*
|
||||
* Not Supported.
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_ServiceValue(BDT *Bdt)
|
||||
{
|
||||
printf("%s got a Value message\n", MESSAGE_PREFIX);
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Handle the receipt of a Delta message.
|
||||
*
|
||||
* Not Supported.
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_ServiceDelta(BDT *Bdt)
|
||||
{
|
||||
printf("%s got a Delta message\n", MESSAGE_PREFIX);
|
||||
BdtSendHeader(Bdt, BDT_Ok, 0);
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Handle the receipt of an Add message.
|
||||
*
|
||||
* Not Supported.
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_ServiceAdd(BDT *Bdt)
|
||||
{
|
||||
printf("%s got a Add message\n", MESSAGE_PREFIX);
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Handle the receipt of a Delete message.
|
||||
*
|
||||
* Not Supported.
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_ServiceDelete(BDT *Bdt)
|
||||
{
|
||||
printf("%s got a Delete message\n", MESSAGE_PREFIX);
|
||||
BdtSendHeader(Bdt, BDT_Error, 0);
|
||||
return(0);
|
||||
}
|
||||
/*****************************************************************************
|
||||
*
|
||||
* Handle the receipt of a Ping message.
|
||||
*
|
||||
*****************************************************************************/
|
||||
STATIC int BDT_ServicePing(BDT *Bdt)
|
||||
{
|
||||
printf("%s got a Ping message\n", MESSAGE_PREFIX);
|
||||
BdtSendHeader(Bdt, BDT_Ok, 0);
|
||||
return(0);
|
||||
}
|
||||
|
||||
BdtHandlers BDT_ServiceHandler_pv =
|
||||
{
|
||||
BDT_ServiceOk,
|
||||
BDT_ServiceConnect,
|
||||
BDT_ServiceError,
|
||||
BDT_ServiceGet,
|
||||
BDT_ServicePut,
|
||||
BDT_ServiceClose,
|
||||
BDT_ServiceMonitor,
|
||||
BDT_ServiceValue,
|
||||
BDT_ServiceDelta,
|
||||
BDT_ServiceAdd,
|
||||
BDT_ServiceDelete,
|
||||
BDT_ServicePing
|
||||
};
|
||||
Reference in New Issue
Block a user