diff --git a/src/ca/lookup_addr_test.c b/src/ca/lookup_addr_test.c new file mode 100644 index 000000000..ca35f5fc0 --- /dev/null +++ b/src/ca/lookup_addr_test.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +main(argc, argv) +int argc; +char **argv; +{ + struct in_addr net_addr; + struct hostent *ent; + struct hostent *gethostbyaddr(); + + unsigned long net; + unsigned long addr; + + if(argc != 2){ + printf("test \n"); + exit(); + } +printf("%s\n",argv[1]); + net = inet_network(argv[1]); + addr = inet_addr(argv[1]); +printf("%x %x\n", addr, net); + net_addr = inet_makeaddr(net, addr); +printf("%x\n", net_addr.s_addr); + + + + /* the above seems to be broken ? */ + ent = gethostbyaddr(&net, sizeof(net_addr), AF_INET); + if(ent) + printf("%s\n", ent->h_name); + + +} diff --git a/src/ca/os_depen.h b/src/ca/os_depen.h new file mode 100644 index 000000000..438d0e756 --- /dev/null +++ b/src/ca/os_depen.h @@ -0,0 +1,152 @@ +/* + * O S _ D E P E N . H + * + * + * OS dependent stuff for channel access + * Author Jeffrey O. Hill + * + * History + * .01 joh 110190 Moved to this file + * + */ + +#ifndef INCos_depenh +#define INCos_depenh + +#ifdef vxWorks +# ifndef INCfast_lockh +# include +# endif +#endif + +/************************************************************************/ +/* Provided to enforce one thread at a time code sections */ +/* independent of a particular operating system */ +/************************************************************************/ +#ifdef VMS + /* provides for data structure mutal exclusive lock out */ + /* in the VMS AST environment. */ + /* note: the following must allways be used together */ +# define LOCK\ + {register long astenblwas;\ + astenblwas = sys$setast(FALSE); +# define UNLOCK\ + if(astenblwas == SS$_WASSET)sys$setast(TRUE);} +#endif + +#ifdef vxWorks +# define LOCK FASTLOCK(&client_lock); +# define UNLOCK FASTUNLOCK(&client_lock); +#endif + +#ifdef UNIX +# define LOCK +# define UNLOCK +#endif + +#ifdef vxWorks +#define VXTHISTASKID taskIdCurrent +extern int taskIdCurrent; +#define abort() taskSuspend(VXTHISTASKID); +#endif + +#ifdef vxWorks +# define memcpy(D,S,N) bcopy(S,D,N) +# define memset(D,V,N) bfill(D,N,V) +# define printf logMsg +#endif + +#ifdef VMS +#ifdef WINTCP /* Wallangong */ +/* (the VAXC runtime lib has its own close */ +# define socket_close(S) netclose(S) +# define socket_ioctl(A,B,C) ioctl(A,B,C) +#else +#endif +#endif + +#ifdef UNIX +# define socket_close(S) close(S) +# define socket_ioctl(A,B,C) ioctl(A,B,C) +#endif + +#ifdef vxWorks +# define socket_close(S) close(S) +# define socket_ioctl(A,B,C) ioctl(A,B,C) +#endif + +#ifdef VMS +#ifdef WINTCP + extern int uerrno; /* Wallongong errno is uerrno */ +# define MYERRNO uerrno +#else + extern volatile int noshare socket_errno; +# define MYERRNO socket_errno +#endif +#endif + +#ifdef vxWorks +# define MYERRNO (errnoGet()&0xffff) +#endif + +#ifdef UNIX + extern int errno; +# define MYERRNO errno +#endif + +#ifdef VMS +struct iosb{ +short status; +unsigned short count; +void *device; +}; +#endif + +struct timeval{ + unsigned long tv_sec; + unsigned long tv_usec; +}; + +#ifdef vxWorks +# define POST_IO_EV vrtxPost(&io_done_flag, TRUE) +#endif +#ifdef VMS +# define POST_IO_EV sys$setef(io_done_flag) +#endif +#ifdef UNIX +# define POST_IO_EV +#endif + +/* 50 mS delay for TCP to finish transmitting */ +/* select wakes you if message is only partly here */ +/* so this wait free's up the processor until it completely arrives */ +/* NOTE: DELAYVAL must be less than 1.0 */ +#define DELAYVAL 0.250 /* 250 mS */ + +#ifdef VMS +# define SYSFREQ 10000000 /* 10 MHz */ +# define TCPDELAY\ +{float delay = DELAYVAL; static int ef=NULL;\ + int status; int systim[2]={-SYSFREQ*DELAYVAL,~0};\ + if(!ef)ef= lib$get_ef(&ef);\ + status = sys$setimr(ef,systim,NULL,MYTIMERID,NULL);\ + if(~status&STS$M_SUCCESS)lib$signal(status);\ + status = sys$waitfr(ef);\ + if(~status&STS$M_SUCCESS)lib$signal(status);\ +}; +#endif + +#ifdef vxWorks +# define SYSFREQ sysClkRateGet() /* 60 Hz */ +# define TCPDELAY taskDelay((unsigned int)DELAYVAL*SYSFREQ); +# define time(A) (tickGet()/sysfreq) +#endif + +#ifdef UNIX +# define SYSFREQ 1000000 /* 1 MHz */ +# define TCPDELAY {if(select(0,NULL,NULL,NULL,&tcpdelayval)<0)abort();} +static struct timeval tcpdelayval = {0,(unsigned int)DELAYVAL*SYSFREQ}; +#endif + + +#endif diff --git a/src/ca/repeater.c b/src/ca/repeater.c new file mode 100644 index 000000000..1af02908c --- /dev/null +++ b/src/ca/repeater.c @@ -0,0 +1,265 @@ +/* + * REPEATER.C + * + * CA broadcast repeater + * + * Author: Jeff Hill + * Date: 3-27-90 + * + * Control System Software for the GTA Project + * + * Copyright 1988, 1989, the Regents of the University of California. + * + * This software was produced under a U.S. Government contract + * (W-7405-ENG-36) at the Los Alamos National Laboratory, which is + * operated by the University of California for the U.S. Department + * of Energy. + * + * Developed by the Controls and Automation Group (AT-8) + * Accelerator Technology Division + * Los Alamos National Laboratory + * + * Direct inqueries to: + * Andy Kozubal, AT-8, Mail Stop H820 + * Los Alamos National Laboratory + * Los Alamos, New Mexico 87545 + * Phone: (505) 667-6508 + * E-mail: kozubal@k2.lanl.gov + * + * PURPOSE: + * Broadcasts fan out over the LAN, but UDP does not allow + * two processes on the same machine to get the same broadcast. + * This code takes extends the broadcast model from the net to within + * the OS. + * + * NOTES: + * + * This server does not gaurantee the reliability of + * fanned out broadcasts in keeping with the nature of + * broadcasts. Therefore, CA provides a backup. + * + * UDP datagrams delivered between two processes on the same + * machine dont travel over the LAN. + * + * + * Modification Log: + * ----------------- + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +struct sockaddr_in *local_addr(); + +/* + these can be external since there is only one instance + per machine so we dont care about reentrancy +*/ +struct one_client{ + NODE node; + struct sockaddr_in from; +}; + +static +LIST client_list; + +static +char buf[MAX_UDP]; /* bigger than max TCP */ + + +/* + * + * Fan out broadcasts to several processor local tasks + * + * + */ +#ifdef VMS +main() +#else +ca_repeater_task() +#endif +{ + int status; + int size; + int sock; + struct sockaddr_in from; + struct sockaddr_in bd; + struct sockaddr_in local; + int from_size = sizeof from; + struct one_client *pclient; + struct one_client *pnxtclient; + unsigned *pcount = (unsigned *)buf; + + + lstInit(&client_list); + + /* allocate a socket */ + sock = socket( AF_INET, /* domain */ + SOCK_DGRAM, /* type */ + 0); /* deflt proto */ + if(sock == ERROR) + abort(); + + memset(&bd,0,sizeof bd); + bd.sin_family = AF_INET; + bd.sin_addr.s_addr = htonl(INADDR_ANY); + bd.sin_port = htons(CA_CLIENT_PORT); + status = bind(sock, &bd, sizeof bd); + if(status<0) + if(MYERRNO == EADDRINUSE){ + printf("Only one CA repeater thread per host\n"); + exit(); + } + else + abort(); + + local = *local_addr(sock); + + while(TRUE){ + + size = recvfrom( + sock, + buf, + sizeof buf, + 0, + &from, + &from_size); + + if(size > 0){ + if(size != ntohl(*pcount)) + printf("ca repeater: corrupt msg ignored\n"); + else if(from.sin_addr.s_addr != local.sin_addr.s_addr) + for( pclient = (struct one_client *) + client_list.node.next; + pclient; + pclient = (struct one_client *) + pclient->node.next){ + + status = sendto( + sock, + buf, + size, + 0, + &pclient->from, + sizeof pclient->from); + if(status < 0) + abort(); +#ifdef DEBUG + printf("Sent\n"); +#endif + } + } + else if(size == 0){ + struct { + unsigned length; + struct extmsg extmsg; + }confirm; + + /* + * If this is a processor local message then add to + * the list of clients to repeat to if not there + * allready + */ + for( pclient = (struct one_client *) + client_list.node.next; + pclient; + pclient = (struct one_client *) + pclient->node.next) + if(from.sin_port == pclient->from.sin_port) + break; + + if(!pclient){ + pclient = (struct one_client *) + malloc(sizeof *pclient); + if(pclient){ + pclient->from = from; + lstAdd(&client_list, pclient); +#ifdef DEBUG + printf("Added %x %d\n", from.sin_port, size); +#endif + } + } + + memset(&confirm, NULL, sizeof confirm); + confirm.length = htonl(sizeof confirm); + confirm.extmsg.m_cmmd = htons(REPEATER_CONFIRM); + confirm.extmsg.m_available = local.sin_addr.s_addr; + status = sendto( + sock, + &confirm, + sizeof confirm, + 0, + &from, /* reflect back to sender */ + sizeof from); + if(status != sizeof confirm) + abort(); + }else + abort(); + + /* remove any dead wood prior to pending */ + for( pclient = (struct one_client *) + client_list.node.next; + pclient; + pclient = pnxtclient){ + /* do it now in case item deleted */ + pnxtclient = (struct one_client *) + pclient->node.next; + clean_client(pclient); + } + } +} + + +/* + * + * check to see if this client is still around + * + */ +clean_client(pclient) +struct one_client *pclient; +{ + int port = pclient->from.sin_port; + int sock; + struct sockaddr_in bd; + int status; + int present = FALSE; + + /* allocate a socket */ + sock = socket( AF_INET, /* domain */ + SOCK_DGRAM, /* type */ + 0); /* deflt proto */ + if(sock == ERROR) + abort(); + + memset(&bd,0,sizeof bd); + bd.sin_family = AF_INET; + bd.sin_addr.s_addr = htonl(INADDR_ANY); + bd.sin_port = port; + status = bind(sock, &bd, sizeof bd); + if(status<0){ + if(MYERRNO == EADDRINUSE) + present = TRUE; + else + abort(); + } + close(sock); + + if(!present){ + lstDelete(&client_list, pclient); + if(free(pclient)<0) + abort(); +#ifdef DEBUG + printf("Deleted\n"); +#endif + } + + return OK; +}