This is Unofficial EPICS BASE Doxygen Site
cast_server.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 /*
10  * Author: Jeffrey O. Hill
11  * hill@luke.lanl.gov
12  * (505) 665 1831
13  * Date: 5-88
14  *
15  * Improvements
16  * ------------
17  * .01
18  * Dont send channel found message unless there is memory, a task slot,
19  * and a TCP socket available. Send a diagnostic instead.
20  * Or ... make the timeout shorter? This is only a problem if
21  * they persist in trying to make a connection after getting no
22  * response.
23  *
24  * Notes:
25  * ------
26  * .01
27  * Replies to broadcasts are not returned over
28  * an existing TCP connection to avoid a TCP
29  * pend which could lock up the cast server.
30  */
31 
32 
33 #include <stddef.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <errno.h>
38 
39 #include "dbDefs.h"
40 #include "envDefs.h"
41 #include "epicsMutex.h"
42 #include "epicsTime.h"
43 #include "errlog.h"
44 #include "freeList.h"
45 #include "osiSock.h"
46 #include "taskwd.h"
47 
48 #define epicsExportSharedSymbols
49 #include "rsrv.h"
50 #include "server.h"
51 
52 #define TIMEOUT 60.0 /* sec */
53 
54 /*
55  * clean_addrq
56  */
57 static void clean_addrq(struct client *client)
58 {
59  struct channel_in_use * pciu;
60  struct channel_in_use * pnextciu;
61  epicsTimeStamp current;
62  double delay;
63  double maxdelay = 0;
64  unsigned ndelete=0;
65  double timeout = TIMEOUT;
66  int s;
67 
68  epicsTimeGetCurrent ( &current );
69 
70  epicsMutexMustLock ( client->chanListLock );
71  pnextciu = (struct channel_in_use *)
72  client->chanList.node.next;
73 
74  while( (pciu = pnextciu) ) {
75  pnextciu = (struct channel_in_use *)pciu->node.next;
76 
77  delay = epicsTimeDiffInSeconds(&current,&pciu->time_at_creation);
78  if (delay > timeout) {
79 
80  ellDelete(&client->chanList, &pciu->node);
83  pCaBucket,
84  &pciu->sid);
85  if(s){
86  errMessage (s, "Bad id at close");
87  }
88  else {
90  }
92  if ( ! s ) {
94  ndelete++;
95  }
96  if(delay>maxdelay) maxdelay = delay;
97  }
98  }
99  epicsMutexUnlock ( client->chanListLock );
100 
101 # ifdef DEBUG
102  if(ndelete){
103  epicsPrintf ("CAS: %d CA channels have expired after %f sec\n",
104  ndelete, maxdelay);
105  }
106 # endif
107 
108 }
109 
110 /*
111  * CAST_SERVER
112  *
113  * service UDP messages
114  *
115  */
116 void cast_server(void *pParm)
117 {
118  rsrv_iface_config *conf = pParm;
119  int status;
120  int count=0;
121  int mysocket=0;
122  struct sockaddr_in new_recv_addr;
123  osiSocklen_t recv_addr_size;
124  osiSockIoctl_t nchars;
125  SOCKET recv_sock, reply_sock;
126  struct client *client;
127 
128  recv_addr_size = sizeof(new_recv_addr);
129 
130  reply_sock = conf->udp;
131 
132  /*
133  * setup new client structure but reuse old structure if
134  * possible
135  *
136  */
137  while ( TRUE ) {
138  client = create_client ( reply_sock, IPPROTO_UDP );
139  if ( client ) {
140  break;
141  }
142  epicsThreadSleep(300.0);
143  }
144  if (conf->startbcast) {
145  recv_sock = conf->udpbcast;
146  conf->bclient = client;
147  }
148  else {
149  recv_sock = conf->udp;
150  conf->client = client;
151  }
152  client->udpRecv = recv_sock;
153 
154  casAttachThreadToClient ( client );
155 
156  /*
157  * add placeholder for the first version message should it be needed
158  */
159  rsrv_version_reply ( client );
160 
161  /* these pointers become invalid after signaling casudp_startStopEvent */
162  conf = NULL;
163 
165 
166  while (TRUE) {
167  status = recvfrom (
168  recv_sock,
169  client->recv.buf,
170  client->recv.maxstk,
171  0,
172  (struct sockaddr *)&new_recv_addr,
173  &recv_addr_size);
174  if (status < 0) {
175  if (SOCKERRNO != SOCK_EINTR) {
176  char sockErrBuf[64];
178  sockErrBuf, sizeof ( sockErrBuf ) );
179  epicsPrintf ("CAS: UDP recv error: %s\n",
180  sockErrBuf);
181  epicsThreadSleep(1.0);
182  }
183 
184  } else {
185  size_t idx;
186  for(idx=0; casIgnoreAddrs[idx]; idx++)
187  {
188  if(new_recv_addr.sin_addr.s_addr==casIgnoreAddrs[idx]) {
189  status = -1; /* ignore */
190  break;
191  }
192  }
193  }
194 
195  if (status >= 0 && casudp_ctl == ctlRun) {
196  client->recv.cnt = (unsigned) status;
197  client->recv.stk = 0ul;
199 
201  client->seqNoOfReq = 0;
202 
203  /*
204  * If we are talking to a new client flush to the old one
205  * in case we are holding UDP messages waiting to
206  * see if the next message is for this same client.
207  */
208  if (client->send.stk>sizeof(caHdr)) {
209  status = memcmp(&client->addr,
210  &new_recv_addr, recv_addr_size);
211  if(status){
212  /*
213  * if the address is different
214  */
215  cas_send_dg_msg(client);
216  client->addr = new_recv_addr;
217  }
218  }
219  else {
220  client->addr = new_recv_addr;
221  }
222 
223  if (CASDEBUG>1) {
224  char buf[40];
225 
226  ipAddrToDottedIP (&client->addr, buf, sizeof(buf));
227  errlogPrintf ("CAS: cast server msg of %d bytes from addr %s\n",
228  client->recv.cnt, buf);
229  }
230 
231  if (CASDEBUG>2)
232  count = ellCount (&client->chanList);
233 
234  status = camessage ( client );
235  if(status == RSRV_OK){
236  if(client->recv.cnt !=
237  client->recv.stk){
238  char buf[40];
239 
240  ipAddrToDottedIP (&client->addr, buf, sizeof(buf));
241 
242  epicsPrintf ("CAS: partial (damaged?) UDP msg of %d bytes from %s ?\n",
243  client->recv.cnt - client->recv.stk, buf);
244 
245  epicsTimeToStrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
246  &client->time_at_last_recv);
247  epicsPrintf ("CAS: message received at %s\n", buf);
248  }
249  }
250  else if (CASDEBUG>0){
251  char buf[40];
252 
253  ipAddrToDottedIP (&client->addr, buf, sizeof(buf));
254 
255  epicsPrintf ("CAS: invalid (damaged?) UDP request from %s ?\n", buf);
256 
257  epicsTimeToStrftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S",
258  &client->time_at_last_recv);
259  epicsPrintf ("CAS: message received at %s\n", buf);
260  }
261 
262  if (CASDEBUG>2) {
263  if ( ellCount (&client->chanList) ) {
264  errlogPrintf ("CAS: Fnd %d name matches (%d tot)\n",
265  ellCount(&client->chanList)-count,
266  ellCount(&client->chanList));
267  }
268  }
269  }
270 
271  /*
272  * allow messages to batch up if more are comming
273  */
274  nchars = 0; /* supress purify warning */
275  status = socket_ioctl(recv_sock, FIONREAD, &nchars);
276  if (status<0) {
277  errlogPrintf ("CA cast server: Unable to fetch N characters pending\n");
278  cas_send_dg_msg (client);
279  clean_addrq (client);
280  }
281  else if (nchars == 0) {
282  cas_send_dg_msg (client);
283  clean_addrq (client);
284  }
285  }
286 
287  /* ATM never reached, just a placeholder */
288 
289  if(!mysocket)
290  client->sock = INVALID_SOCKET; /* only one cast_server should destroy the reply socket */
291  destroy_client(client);
292  epicsSocketDestroy(recv_sock);
293 }
double timeout
Definition: pvutils.cpp:25
LIBCOM_API void epicsStdCall epicsSocketDestroy(SOCKET s)
Definition: osdSock.c:117
epicsTimeStamp time_at_creation
Definition: server.h:138
GLBLTYPE int CASDEBUG
Definition: server.h:190
void casAttachThreadToClient(struct client *pClient)
SOCKET udpbcast
Definition: server.h:163
struct message_buffer recv
Definition: server.h:81
#define INVALID_SOCKET
Definition: osdSock.h:32
int rsrv_version_reply(struct client *client)
Definition: camessage.c:2141
#define ellCount(PLIST)
Report the number of nodes in a list.
Definition: ellLib.h:84
unsigned cnt
Definition: server.h:70
struct client client
pvd::Status status
const unsigned sid
Definition: server.h:137
unsigned maxstk
Definition: server.h:68
int osiSocklen_t
Definition: osdSock.h:36
unsigned int startbcast
Definition: server.h:166
Routines to get and set EPICS environment parameters.
#define TIMEOUT
Definition: cast_server.c:52
void cast_server(void *pParm)
Definition: cast_server.c:116
#define CA_UKN_MINOR_VERSION
Definition: caProto.h:29
#define NULL
Definition: catime.c:38
#define errMessage(S, PM)
Definition: errlog.h:48
struct client * client
Definition: server.h:164
#define LOCK_CLIENTQ
Definition: server.h:223
SOCKET sock
Definition: server.h:96
unsigned stk
Definition: server.h:67
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
Miscellaneous macro definitions.
struct sockaddr_in addr
Definition: server.h:89
void epicsSocketConvertErrnoToString(char *pBuf, unsigned bufSize)
void destroy_client(struct client *client)
#define socket_ioctl(A, B, C)
Definition: osdSock.h:34
LIBCOM_API size_t epicsStdCall epicsTimeToStrftime(char *pBuff, size_t bufLength, const char *pFormat, const epicsTimeStamp *pTS)
Convert epicsTimeStamp to string. See epicsTime::strftime()
Definition: epicsTime.cpp:1120
epicsMutexId chanListLock
Definition: server.h:84
#define epicsEventSignal(ID)
A synonym for epicsEventTrigger().
Definition: epicsEvent.h:172
int osiSockIoctl_t
Definition: osdSock.h:35
Definition: server.h:169
Definition: server.h:76
struct message_buffer send
Definition: server.h:79
epicsTimeStamp time_at_last_recv
Definition: server.h:91
APIs for the epicsMutex mutual exclusion semaphore.
LIBCOM_API void epicsStdCall freeListFree(void *pvt, void *pmem)
Definition: freeListLib.c:131
int epicsStdCall epicsTimeGetCurrent(epicsTimeStamp *pDest)
Get current time into *pDest.
#define RSRV_OK
Definition: rsrv.h:23
#define epicsPrintf
Definition: errlog.h:51
char * buf
Definition: server.h:65
LIBCOM_API int epicsStdCall bucketRemoveItemUnsignedId(BUCKET *prb, const unsigned *pId)
Remove an item identified by a string from the table.
Definition: bucketLib.c:415
int camessage(struct client *client)
Definition: camessage.c:2391
int SOCKET
Definition: osdSock.h:31
GLBLTYPE BUCKET * pCaBucket
Definition: server.h:199
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
struct client * create_client(SOCKET sock, int proto)
GLBLTYPE epicsEventId casudp_startStopEvent
Definition: server.h:209
GLBLTYPE void * rsrvChanFreeList
Definition: server.h:201
#define SOCKERRNO
Definition: osdSock.h:33
struct ELLNODE * next
Pointer to next node in list.
Definition: ellLib.h:46
ELLNODE node
Definition: server.h:132
GLBLTYPE epicsUInt32 * casIgnoreAddrs
Definition: server.h:197
EPICS time stamp, for use from C code.
Definition: epicsTime.h:33
#define SOCK_EINTR
Definition: osdSock.h:64
#define TRUE
Definition: dbDefs.h:27
LIBCOM_API void epicsStdCall epicsThreadSleep(double seconds)
Block the calling thread for at least the specified time.
Definition: osdThread.c:790
void cas_send_dg_msg(struct client *pclient)
Definition: caserverio.c:173
LIBCOM_API double epicsStdCall epicsTimeDiffInSeconds(const epicsTimeStamp *pLeft, const epicsTimeStamp *pRight)
Time difference between left and right in seconds.
Definition: epicsTime.cpp:1048
unsigned minor_version_number
Definition: server.h:99
#define UNLOCK_CLIENTQ
Definition: server.h:224
EPICS time-stamps (epicsTimeStamp), epicsTime C++ class and C functions for handling wall-clock times...
ELLLIST chanList
Definition: server.h:86
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
Definition: ellLib.c:75
ELLNODE node
Pointers to the first and last nodes on list.
Definition: ellLib.h:57
GLBLTYPE unsigned rsrvChannelCount
Definition: server.h:207
ca_uint32_t seqNoOfReq
Definition: server.h:100
SOCKET udpRecv
Definition: server.h:96
GLBLTYPE enum ctl casudp_ctl
Definition: server.h:212
unsigned epicsStdCall ipAddrToDottedIP(const struct sockaddr_in *paddr, char *pBuf, unsigned bufSize)
Definition: osiSock.c:144
struct client * bclient
Definition: server.h:164