Fix CA server bind issue from Freddie Akeroyd

This commit is contained in:
Andrew Johnson
2017-01-19 12:33:54 -06:00
parent b9ae6c3308
commit 3e58c59377
12 changed files with 188 additions and 174 deletions

View File

@@ -13,6 +13,17 @@
<!-- Insert new items immediately below here ... -->
<h3>Server bind issue on Windows</h3>
<p>When a National Instruments network variables CA server is already running on
a Windows system and an IOC or PCAS server is started, the IOC's attempt to
bind a TCP socket to the CA server port number fails, but Windows returns a
different error status value than the IOC is expecting in that circumstance
(because the National Instruments code requests exclusive use of that port,
unlike the EPICS code) so the IOC fails to start properly. The relevent EPICS
bind() checks have now been updated so the IOC will request that a dynamic port
number be allocated for this TCP socket instead when this happens.</p>
<h3>Checking Periodic Scan Rates</h3>
<p>Code has been added to the IOC startup to better protect it against bad
@@ -786,7 +797,7 @@ access monitor on the DLYA field; this happens twice during record processing if
the ODLY field is larger than 0.</p>
<p>Timestamps from all seq record monitor events have been wrong since 1995 or
earlier, the time being provided was from the last time the record processed.
earlier, the time being provided was from the last time the record processed.
Now the record timestamp will be updated between reading each DOL1..DOLA link
and posting the monitor on the associated DO1..DOA field. The VAL field is
never given a value by the record processing code, but is used for posting
@@ -1018,7 +1029,7 @@ fixed in this release:</p>
<li>717252
<a href="https://launchpad.net/bugs/771252">
local caput causes ioc crash on win32</a></li>
<li>750549
<li>750549
<a href="https://launchpad.net/bugs/750549 ">
epicsTime has non-portable c++ static initialization</a></li>
<li>753137
@@ -1372,7 +1383,7 @@ more extensive modifications.</p>
<h4>RTEMS 4.10 support</h4>
<p>Added support for the latest release of RTEMS. There is no longer a
<p>Added support for the latest release of RTEMS. There is no longer a
distinction between executive and malloc memory pools. The new mount() API
is used.</p>
@@ -1465,7 +1476,7 @@ doing a put</p>
<p> These changes impact the Gateway (Proxy server) and other servers but not
the IOC.</h4>
<p>Mantis 360 fix - server is unresponsive for one of its clients, when
<p>Mantis 360 fix - server is unresponsive for one of its clients, when
async io postponed and in flow control mode</p>
<p>Mantis 358 fix - PCAS service snap-in has no way to determine if its a put,
@@ -1478,7 +1489,7 @@ controling motor through gw.</p>
<p>Mantis 340 fix - leak when performing a read and conversion fails.</p>
<p>Mantis 348 fix - A call to 'assert (item.pList == this)'
<p>Mantis 348 fix - A call to 'assert (item.pList == this)'
failed in ../../../../src/cas/generic/st/ioBlocked.cc line 112</p>
<p>Mantis 345 fix - Compilation warning: complaint about missing
@@ -1494,7 +1505,7 @@ R3.13 client</p>
<p>Mantis 329 fix - GW hang, pthread_mutex_lock failed: error Invalid
argument message</p>
<p>Mantis 352 fix - gateway hangs temporarily under heavy load on 8-core
<p>Mantis 352 fix - gateway hangs temporarily under heavy load on 8-core
64bit RHEL5</p>
<ul>
@@ -2015,7 +2026,7 @@ tools to allow specifying the CA priority.</p>
<h4>GCC_EXEC_PREFIX references removed from configuration files</h4>
<p>Definition of GCC_EXEC_PREFIX removed from CONFIG.CrossCommon and
<p>Definition of GCC_EXEC_PREFIX removed from CONFIG.CrossCommon and
unexport of GCC_EXEC_PREFIX removed from vxWorks and RTEMS builds.</p>
<h4>RTEMS Release</h4>
@@ -3232,7 +3243,7 @@ was returned as -1.17549435E-38. This is now fixed.</p>
in a &lt;name&gt;_DBD macro definition. An include line will be placed in the
&lt;name&gt;Include.dbd for each file specified in the &lt;name&gt;_DBD
definition. If a Makefile contains</p>
<pre> DBD=xxx.dbd
<pre> DBD=xxx.dbd
xxx_DBD = f1.dbd f2.dbd f3.dbd </pre>
<p>an xxxInclude.dbd file will be created containing the lines</p>

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
//
@@ -32,7 +32,7 @@ const unsigned caServerConnectPendQueueSize = 5u;
//
// casIntfIO::casIntfIO()
//
casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
sock ( INVALID_SOCKET ),
addr ( addrIn.getSockIP() )
{
@@ -40,80 +40,79 @@ casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
osiSocklen_t addrSize;
bool portChange;
if ( ! osiSockAttach () ) {
throw S_cas_internal;
}
if ( ! osiSockAttach () ) {
throw S_cas_internal;
}
/*
* Setup the server socket
*/
this->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if (this->sock==INVALID_SOCKET) {
/*
* Setup the server socket
*/
this->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
if (this->sock == INVALID_SOCKET) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
printf ( "No socket error was %s\n", sockErrBuf );
throw S_cas_noFD;
}
printf ( "No socket error was %s\n", sockErrBuf );
throw S_cas_noFD;
}
epicsSocketEnableAddressReuseDuringTimeWaitState ( this->sock );
status = bind ( this->sock,
reinterpret_cast <sockaddr *> (&this->addr),
sizeof(this->addr) );
if (status<0) {
if (SOCKERRNO == SOCK_EADDRINUSE) {
//
// enable assignment of a default port
// (so the getsockname() call below will
// work correctly)
//
this->addr.sin_port = ntohs (0);
status = bind(
status = bind ( this->sock,
reinterpret_cast <sockaddr *> (&this->addr),
sizeof(this->addr) );
if (status < 0) {
if (SOCKERRNO == SOCK_EADDRINUSE ||
SOCKERRNO == SOCK_EACCES) {
//
// enable assignment of a default port
// (so the getsockname() call below will
// work correctly)
//
this->addr.sin_port = ntohs (0);
status = bind(
this->sock,
reinterpret_cast <sockaddr *> (&this->addr),
sizeof(this->addr) );
}
if (status<0) {
}
if (status < 0) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
char buf[64];
ipAddrToA (&this->addr, buf, sizeof(buf));
errPrintf ( S_cas_bindFail,
__FILE__, __LINE__,
"- bind TCP IP addr=%s failed because %s",
buf, sockErrBuf );
char buf[64];
ipAddrToA (&this->addr, buf, sizeof(buf));
errlogPrintf ( "CAS: Socket bind TCP to %s failed with %s",
buf, sockErrBuf );
epicsSocketDestroy (this->sock);
throw S_cas_bindFail;
}
throw S_cas_bindFail;
}
portChange = true;
}
}
else {
portChange = false;
}
addrSize = ( osiSocklen_t ) sizeof (this->addr);
status = getsockname (
this->sock,
reinterpret_cast <sockaddr *> ( &this->addr ),
addrSize = ( osiSocklen_t ) sizeof (this->addr);
status = getsockname (
this->sock,
reinterpret_cast <sockaddr *> ( &this->addr ),
&addrSize );
if (status) {
if (status) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf ( "CAS: getsockname() error %s\n",
sockErrBuf );
errlogPrintf ( "CAS: getsockname() error %s\n",
sockErrBuf );
epicsSocketDestroy (this->sock);
throw S_cas_internal;
}
throw S_cas_internal;
}
//
// be sure of this now so that we can fetch the IP
// address and port number later
//
//
// be sure of this now so that we can fetch the IP
// address and port number later
//
assert (this->addr.sin_family == AF_INET);
if ( portChange ) {
errlogPrintf ( "cas warning: Configured TCP port was unavailable.\n");
errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n",
errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n",
ntohs (this->addr.sin_port) );
errlogPrintf ( "cas warning: but now two or more servers share the same UDP port.\n");
errlogPrintf ( "cas warning: Depending on your IP kernel this server may not be\n" );
@@ -121,12 +120,12 @@ casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
}
status = listen(this->sock, caServerConnectPendQueueSize);
if(status < 0) {
if (status < 0) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf ( "CAS: listen() error %s\n", sockErrBuf );
errlogPrintf ( "CAS: listen() error %s\n", sockErrBuf );
epicsSocketDestroy (this->sock);
throw S_cas_internal;
throw S_cas_internal;
}
}
@@ -135,17 +134,17 @@ casIntfIO::casIntfIO ( const caNetAddr & addrIn ) :
//
casIntfIO::~casIntfIO()
{
if (this->sock != INVALID_SOCKET) {
epicsSocketDestroy (this->sock);
}
if (this->sock != INVALID_SOCKET) {
epicsSocketDestroy (this->sock);
}
osiSockRelease ();
osiSockRelease ();
}
//
// newStreamIO::newStreamClient()
//
casStreamOS *casIntfIO::newStreamClient ( caServerI & cas,
casStreamOS *casIntfIO::newStreamClient ( caServerI & cas,
clientBufMemoryManager & bufMgr ) const
{
static bool oneMsgFlag = false;
@@ -175,14 +174,14 @@ casStreamOS *casIntfIO::newStreamClient ( caServerI & cas,
args.sock = newSock;
casStreamOS * pOS = new casStreamOS ( cas, bufMgr, args );
if ( ! pOS ) {
errMessage ( S_cas_noMemory,
errMessage ( S_cas_noMemory,
"unable to create data structures for a new client" );
epicsSocketDestroy ( newSock );
}
else {
if ( cas.getDebugLevel() > 0u ) {
char pName[64u];
pOS->hostName ( pName, sizeof ( pName ) );
errlogPrintf ( "CAS: allocated client object for \"%s\"\n", pName );
}
@@ -197,7 +196,7 @@ void casIntfIO::setNonBlocking()
{
int status;
osiSockIoctl_t yes = true;
status = socket_ioctl(this->sock, FIONBIO, &yes); // X aCC 392
if ( status < 0 ) {
char sockErrBuf[64];

View File

@@ -1,7 +1,7 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* Author: Eric Norum
@@ -38,6 +38,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
@@ -13,12 +13,12 @@
* Under Linux if we dont define _POSIX_C_SOURCE or _XOPEN_SOURCE
* then none of the POSIX stuff (such as signals) can be used
* with cc -v. However if one of _POSIX_C_SOURCE or _XOPEN_SOURCE
* are defined then we cant use the socket library. Therefore I
* have been adding the following in order to use POSIX signals
* are defined then we cant use the socket library. Therefore I
* have been adding the following in order to use POSIX signals
* and also sockets on Linux with cc -v. What a pain....
*
* #ifdef linux
* #define __EXTENSIONS__
* #define __EXTENSIONS__
* #endif
*/
@@ -53,6 +53,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED
@@ -82,4 +83,3 @@ typedef socklen_t osiSocklen_t;
#define ifreq_size(pifreq) (sizeof(pifreq->ifr_name))
#endif /*osdSockH*/

View File

@@ -1,7 +1,7 @@
/*************************************************************************\
* Copyright (c) 2002 The University of Saskatchewan
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* RTEMS osdSock.h
@@ -35,7 +35,7 @@ int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, str
#ifdef __cplusplus
}
#endif
typedef int SOCKET;
#define INVALID_SOCKET (-1)
#define SOCKERRNO errno
@@ -49,6 +49,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED
@@ -74,7 +75,7 @@ typedef socklen_t osiSocklen_t;
#ifndef INADDR_NONE
# define INADDR_NONE (0xffffffff)
#endif
#endif
/*
* For shutdown()

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef osdSockH
@@ -14,7 +14,7 @@
#include <errno.h>
/*
* winsock2.h changes the structure alignment to 4 if
* winsock2.h changes the structure alignment to 4 if
* WIN32 isnt set which can be a source of confusion
*/
#ifndef WIN32
@@ -48,6 +48,7 @@ typedef int osiSocklen_t;
#define SOCK_ENOBUFS WSAENOBUFS
#define SOCK_ECONNRESET WSAECONNRESET
#define SOCK_ETIMEDOUT WSAETIMEDOUT
#define SOCK_EACCES WSAEACCES
#define SOCK_EADDRINUSE WSAEADDRINUSE
#define SOCK_ECONNREFUSED WSAECONNREFUSED
#define SOCK_ECONNABORTED WSAECONNABORTED

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* cygwin32 specific include
@@ -49,6 +49,7 @@ typedef int osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED
@@ -66,4 +67,3 @@ typedef int osiSocklen_t;
#define ifreq_size(pifreq) (sizeof(pifreq->ifr_name))
#endif /*osdSockH*/

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#ifndef osdSockH
@@ -29,7 +29,7 @@
#define IPPORT_USERRESERVED 5000
#endif
typedef int SOCKET;
#define INVALID_SOCKET (-1)
#define SOCKERRNO errno
@@ -43,6 +43,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED
@@ -76,4 +77,3 @@ typedef socklen_t osiSocklen_t;
#endif
#endif /*osdSockH*/

View File

@@ -39,6 +39,7 @@ typedef socklen_t osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
@@ -39,7 +39,7 @@ typedef int osiSockIoctl_t;
#if SOLARIS > 6 || defined ( _SOCKLEN_T )
typedef uint32_t osiSocklen_t;
#else
#else
typedef int osiSocklen_t;
#endif
@@ -51,6 +51,7 @@ typedef int osiSockIoctl_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED
@@ -79,9 +80,8 @@ typedef int osiSockIoctl_t;
#ifndef INADDR_NONE
# define INADDR_NONE (0xffffffff)
#endif
#endif
#define ifreq_size(pifreq) (sizeof(pifreq->ifr_name))
#endif /*osdSockH*/

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
* vxWorks specific socket include
@@ -44,7 +44,7 @@ int sysClkRateGet(void);
#ifdef __cplusplus
}
#endif
typedef int SOCKET;
#define INVALID_SOCKET (-1)
#define SOCKERRNO errno
@@ -72,6 +72,7 @@ typedef int osiSocklen_t;
#define SOCK_ENOBUFS ENOBUFS
#define SOCK_ECONNRESET ECONNRESET
#define SOCK_ETIMEDOUT ETIMEDOUT
#define SOCK_EACCES EACCES
#define SOCK_EADDRINUSE EADDRINUSE
#define SOCK_ECONNREFUSED ECONNREFUSED
#define SOCK_ECONNABORTED ECONNABORTED
@@ -92,7 +93,7 @@ typedef int osiSocklen_t;
#ifndef INADDR_NONE
# define INADDR_NONE (0xffffffff)
#endif
#endif
#if defined(_SIZEOF_ADDR_IFREQ)
# define ifreq_size(pifreq) _SIZEOF_ADDR_IFREQ(*pifreq)
@@ -103,5 +104,3 @@ typedef int osiSocklen_t;
#endif
#endif /*osdSockH*/

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/*
@@ -70,22 +70,22 @@ static void req_server (void *pParm)
epicsSignalInstallSigPipeIgnore ();
taskwdInsert ( epicsThreadGetIdSelf (), NULL, NULL );
rsrvCurrentClient = epicsThreadPrivateCreate ();
if ( envGetConfigParamPtr ( &EPICS_CAS_SERVER_PORT ) ) {
ca_server_port = envGetInetPortConfigParam ( &EPICS_CAS_SERVER_PORT,
ca_server_port = envGetInetPortConfigParam ( &EPICS_CAS_SERVER_PORT,
(unsigned short) CA_SERVER_PORT );
}
else {
ca_server_port = envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT,
ca_server_port = envGetInetPortConfigParam ( &EPICS_CA_SERVER_PORT,
(unsigned short) CA_SERVER_PORT );
}
if (IOC_sock != 0 && IOC_sock != INVALID_SOCKET) {
epicsSocketDestroy ( IOC_sock );
}
/*
* Open the socket. Use ARPA Internet address format and stream
* sockets. Format described in <sys/socket.h>.
@@ -100,53 +100,54 @@ static void req_server (void *pParm)
/* Zero the sock_addr structure */
memset ( (void *) &serverAddr, 0, sizeof ( serverAddr ) );
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = htonl (INADDR_ANY);
serverAddr.sin_addr.s_addr = htonl (INADDR_ANY);
serverAddr.sin_port = htons ( ca_server_port );
/* get server's Internet address */
status = bind ( IOC_sock, (struct sockaddr *) &serverAddr, sizeof ( serverAddr ) );
if ( status < 0 ) {
if ( SOCKERRNO == SOCK_EADDRINUSE ) {
/*
* enable assignment of a default port
* (so the getsockname() call below will
* work correctly)
*/
serverAddr.sin_port = ntohs (0);
status = bind ( IOC_sock,
if ( status < 0 ) {
if ( SOCKERRNO == SOCK_EADDRINUSE ||
SOCKERRNO == SOCK_EACCES ) {
/*
* enable assignment of a default port
* (so the getsockname() call below will
* work correctly)
*/
serverAddr.sin_port = ntohs (0);
status = bind ( IOC_sock,
(struct sockaddr *) &serverAddr, sizeof ( serverAddr ) );
}
if ( status < 0 ) {
}
if ( status < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf ( "CAS: Socket bind error was \"%s\"\n",
errlogPrintf ( "CAS: Socket bind failed with %s\n",
sockErrBuf );
epicsThreadSuspendSelf ();
}
}
portChange = 1;
}
}
else {
portChange = 0;
}
addrSize = ( osiSocklen_t ) sizeof ( serverAddr );
status = getsockname ( IOC_sock,
(struct sockaddr *)&serverAddr, &addrSize);
if ( status ) {
addrSize = ( osiSocklen_t ) sizeof ( serverAddr );
status = getsockname ( IOC_sock,
(struct sockaddr *)&serverAddr, &addrSize);
if ( status ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf ( "CAS: getsockname() error %s\n",
sockErrBuf );
errlogPrintf ( "CAS: getsockname() error %s\n",
sockErrBuf );
epicsThreadSuspendSelf ();
}
}
ca_server_port = ntohs (serverAddr.sin_port);
if ( portChange ) {
errlogPrintf ( "cas warning: Configured TCP port was unavailable.\n");
errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n",
errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n",
ca_server_port );
errlogPrintf ( "cas warning: but now two or more servers share the same UDP port.\n");
errlogPrintf ( "cas warning: Depending on your IP kernel this server may not be\n" );
@@ -189,13 +190,13 @@ static void req_server (void *pParm)
clientSock = epicsSocketAccept ( IOC_sock, &sockAddr, &addLen );
if ( clientSock == INVALID_SOCKET ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf("CAS: Client accept error was \"%s\"\n",
sockErrBuf );
epicsThreadSleep(15.0);
continue;
}
}
else {
epicsThreadId id;
struct client *pClient;
@@ -279,14 +280,14 @@ int rsrv_init (void)
castcp_ctl = ctlPause;
/*
* go down two levels so that we are below
* go down two levels so that we are below
* the TCP and event threads started on behalf
* of individual clients
*/
tbs = epicsThreadHighestPriorityLevelBelow (
tbs = epicsThreadHighestPriorityLevelBelow (
epicsThreadPriorityCAServerLow, &priorityOfConnectDaemon );
if ( tbs == epicsThreadBooleanStatusSuccess ) {
tbs = epicsThreadHighestPriorityLevelBelow (
tbs = epicsThreadHighestPriorityLevelBelow (
priorityOfConnectDaemon, &priorityOfConnectDaemon );
if ( tbs != epicsThreadBooleanStatusSuccess ) {
priorityOfConnectDaemon = epicsThreadPriorityCAServerLow;
@@ -327,7 +328,7 @@ int rsrv_pause (void)
return RSRV_OK;
}
static unsigned countChanListBytes (
static unsigned countChanListBytes (
struct client *client, ELLLIST * pList )
{
struct channel_in_use * pciu;
@@ -346,7 +347,7 @@ static unsigned countChanListBytes (
return bytes_reserved;
}
static void showChanList (
static void showChanList (
struct client * client, ELLLIST * pList )
{
unsigned i = 0u;
@@ -354,7 +355,7 @@ static void showChanList (
epicsMutexMustLock ( client->chanListLock );
pciu = (struct channel_in_use *) pList->node.next;
while ( pciu ){
printf( "\t%s(%d%c%c)",
printf( "\t%s(%d%c%c)",
pciu->addr.precord->name,
ellCount ( &pciu->eventq ),
asCheckGet ( pciu->asClientPVT ) ? 'r': '-',
@@ -395,28 +396,28 @@ static void log_one_client (struct client *client, unsigned level)
send_delay = epicsTimeDiffInSeconds(&current,&client->time_at_last_send);
recv_delay = epicsTimeDiffInSeconds(&current,&client->time_at_last_recv);
printf ( "%s %s(%s): User=\"%s\", V%u.%u, %d Channels, Priority=%u\n",
printf ( "%s %s(%s): User=\"%s\", V%u.%u, %d Channels, Priority=%u\n",
pproto,
clientHostName,
client->pHostName ? client->pHostName : "",
client->pUserName ? client->pUserName : "",
CA_MAJOR_PROTOCOL_REVISION,
client->minor_version_number,
ellCount(&client->chanList) +
ellCount(&client->chanList) +
ellCount(&client->chanPendingUpdateARList),
client->priority );
if ( level >= 1 ) {
printf ("\tTask Id=%p, Socket FD=%d\n",
(void *) client->tid, client->sock);
printf(
"\tSecs since last send %6.2f, Secs since last receive %6.2f\n",
printf ("\tTask Id=%p, Socket FD=%d\n",
(void *) client->tid, client->sock);
printf(
"\tSecs since last send %6.2f, Secs since last receive %6.2f\n",
send_delay, recv_delay);
printf(
"\tUnprocessed request bytes=%u, Undelivered response bytes=%u\n",
printf(
"\tUnprocessed request bytes=%u, Undelivered response bytes=%u\n",
client->recv.cnt - client->recv.stk,
client->send.stk );
printf(
"\tState=%s%s%s\n",
client->send.stk );
printf(
"\tState=%s%s%s\n",
state[client->disconnect?1:0],
client->send.type == mbtLargeTCP ? " jumbo-send-buf" : "",
client->recv.type == mbtLargeTCP ? " jumbo-recv-buf" : "");
@@ -425,9 +426,9 @@ static void log_one_client (struct client *client, unsigned level)
if ( level >= 2u ) {
unsigned bytes_reserved = 0;
bytes_reserved += sizeof(struct client);
bytes_reserved += countChanListBytes (
bytes_reserved += countChanListBytes (
client, & client->chanList );
bytes_reserved += countChanListBytes (
bytes_reserved += countChanListBytes (
client, & client->chanPendingUpdateARList );
printf( "\t%d bytes allocated\n", bytes_reserved);
showChanList ( client, & client->chanList );
@@ -482,20 +483,20 @@ void epicsShareAPI casr (unsigned level)
printf( "UDP Server:\n" );
log_one_client(prsrv_cast_client, level);
}
if (level>=2u) {
bytes_reserved = 0u;
bytes_reserved += sizeof (struct client) *
bytes_reserved += sizeof (struct client) *
freeListItemsAvail (rsrvClientFreeList);
bytes_reserved += sizeof (struct channel_in_use) *
freeListItemsAvail (rsrvChanFreeList);
bytes_reserved += sizeof(struct event_ext) *
freeListItemsAvail (rsrvEventFreeList);
bytes_reserved += MAX_TCP *
bytes_reserved += MAX_TCP *
freeListItemsAvail ( rsrvSmallBufFreeListTCP );
bytes_reserved += rsrvSizeofLargeBufTCP *
bytes_reserved += rsrvSizeofLargeBufTCP *
freeListItemsAvail ( rsrvLargeBufFreeListTCP );
bytes_reserved += rsrvSizeOfPutNotify ( 0 ) *
bytes_reserved += rsrvSizeOfPutNotify ( 0 ) *
freeListItemsAvail ( rsrvPutNotifyFreeList );
printf( "There are currently %u bytes on the server's free list\n",
(unsigned int) bytes_reserved);
@@ -522,7 +523,7 @@ void epicsShareAPI casr (unsigned level)
}
}
/*
/*
* destroy_client ()
*/
void destroy_client ( struct client *client )
@@ -530,7 +531,7 @@ void destroy_client ( struct client *client )
if ( ! client ) {
return;
}
if ( client->tid != 0 ) {
taskwdRemove ( client->tid );
}
@@ -600,12 +601,12 @@ void destroy_client ( struct client *client )
if ( client->pHostName ) {
free ( client->pHostName );
}
}
freeListFree ( rsrvClientFreeList, client );
}
static void destroyAllChannels (
static void destroyAllChannels (
struct client * client, ELLLIST * pList )
{
if ( !client->chanListLock || !client->eventqLock ) {
@@ -649,7 +650,7 @@ static void destroyAllChannels (
rsrvChannelCount--;
UNLOCK_CLIENTQ;
if ( status != S_bucket_success ) {
errPrintf ( status, __FILE__, __LINE__,
errPrintf ( status, __FILE__, __LINE__,
"Bad id=%d at close", pciu->sid);
}
status = asRemoveClient(&pciu->asClientPVT);
@@ -689,7 +690,7 @@ void destroy_tcp_client ( struct client *client )
if ( client->evuser ) {
db_close_events (client->evuser);
}
destroy_client ( client );
}
@@ -708,7 +709,7 @@ struct client * create_client ( SOCKET sock, int proto )
spaceAvailOnFreeList = freeListItemsAvail ( rsrvClientFreeList ) > 0
&& freeListItemsAvail ( rsrvSmallBufFreeListTCP ) > 0;
spaceNeeded = sizeof (struct client) + MAX_TCP;
if ( ! ( osiSufficentSpaceInPool(spaceNeeded) || spaceAvailOnFreeList ) ) {
if ( ! ( osiSufficentSpaceInPool(spaceNeeded) || spaceAvailOnFreeList ) ) {
epicsSocketDestroy ( sock );
epicsPrintf ("CAS: no space in pool for a new client (below max block thresh)\n");
return NULL;
@@ -719,7 +720,7 @@ struct client * create_client ( SOCKET sock, int proto )
epicsSocketDestroy ( sock );
epicsPrintf ("CAS: no space in pool for a new client (alloc failed)\n");
return NULL;
}
}
client->sock = sock;
client->proto = proto;
@@ -735,8 +736,8 @@ struct client * create_client ( SOCKET sock, int proto )
return NULL;
}
client->pUserName = NULL;
client->pHostName = NULL;
client->pUserName = NULL;
client->pHostName = NULL;
ellInit ( & client->chanList );
ellInit ( & client->chanPendingUpdateARList );
ellInit ( & client->putNotifyQue );
@@ -774,7 +775,7 @@ struct client * create_client ( SOCKET sock, int proto )
epicsTimeGetCurrent ( &client->time_at_last_recv );
client->minor_version_number = CA_UKN_MINOR_VERSION;
client->recvBytesToDrain = 0u;
return client;
}
@@ -789,10 +790,10 @@ void casAttachThreadToClient ( struct client *pClient )
void casExpandSendBuffer ( struct client *pClient, ca_uint32_t size )
{
if ( pClient->send.type == mbtSmallTCP && rsrvSizeofLargeBufTCP > MAX_TCP
if ( pClient->send.type == mbtSmallTCP && rsrvSizeofLargeBufTCP > MAX_TCP
&& size <= rsrvSizeofLargeBufTCP ) {
int spaceAvailOnFreeList = freeListItemsAvail ( rsrvLargeBufFreeListTCP ) > 0;
if ( osiSufficentSpaceInPool(rsrvSizeofLargeBufTCP) || spaceAvailOnFreeList ) {
if ( osiSufficentSpaceInPool(rsrvSizeofLargeBufTCP) || spaceAvailOnFreeList ) {
char *pNewBuf = ( char * ) freeListCalloc ( rsrvLargeBufFreeListTCP );
if ( pNewBuf ) {
memcpy ( pNewBuf, pClient->send.buf, pClient->send.stk );
@@ -810,7 +811,7 @@ void casExpandRecvBuffer ( struct client *pClient, ca_uint32_t size )
if ( pClient->recv.type == mbtSmallTCP && rsrvSizeofLargeBufTCP > MAX_TCP
&& size <= rsrvSizeofLargeBufTCP) {
int spaceAvailOnFreeList = freeListItemsAvail ( rsrvLargeBufFreeListTCP ) > 0;
if ( osiSufficentSpaceInPool(rsrvSizeofLargeBufTCP) || spaceAvailOnFreeList ) {
if ( osiSufficentSpaceInPool(rsrvSizeofLargeBufTCP) || spaceAvailOnFreeList ) {
char *pNewBuf = ( char * ) freeListCalloc ( rsrvLargeBufFreeListTCP );
if ( pNewBuf ) {
assert ( pClient->recv.cnt >= pClient->recv.stk );
@@ -847,26 +848,26 @@ struct client *create_tcp_client ( SOCKET sock )
* see TCP(4P) this seems to make unsolicited single events much
* faster. I take care of queue up as load increases.
*/
status = setsockopt ( sock, IPPROTO_TCP, TCP_NODELAY,
status = setsockopt ( sock, IPPROTO_TCP, TCP_NODELAY,
(char *) &intTrue, sizeof (intTrue) );
if (status < 0) {
errlogPrintf ( "CAS: TCP_NODELAY option set failed\n" );
destroy_client ( client );
return NULL;
}
/*
/*
* turn on KEEPALIVE so if the client crashes
* this task will find out and exit
*/
status = setsockopt ( sock, SOL_SOCKET, SO_KEEPALIVE,
status = setsockopt ( sock, SOL_SOCKET, SO_KEEPALIVE,
(char *) &intTrue, sizeof (intTrue) );
if ( status < 0 ) {
errlogPrintf ( "CAS: SO_KEEPALIVE option set failed\n" );
destroy_client ( client );
return NULL;
}
/*
* some concern that vxWorks will run out of mBuf's
* if this change is made
@@ -874,8 +875,8 @@ struct client *create_tcp_client ( SOCKET sock )
* joh 11-10-98
*/
#if 0
/*
* set TCP buffer sizes to be synergistic
/*
* set TCP buffer sizes to be synergistic
* with CA internal buffering
*/
i = MAX_MSG_SIZE;
@@ -893,7 +894,7 @@ struct client *create_tcp_client ( SOCKET sock )
return NULL;
}
#endif
addrSize = sizeof ( client->addr );
status = getpeername ( sock, (struct sockaddr *)&client->addr,
&addrSize );
@@ -926,8 +927,8 @@ struct client *create_tcp_client ( SOCKET sock )
}
}
status = db_start_events ( client->evuser, "CAS-event",
NULL, NULL, priorityOfEvents );
status = db_start_events ( client->evuser, "CAS-event",
NULL, NULL, priorityOfEvents );
if ( status != DB_EVENT_OK ) {
errlogPrintf ( "CAS: unable to start the event facility\n" );
destroy_tcp_client ( client );