447 lines
13 KiB
C
447 lines
13 KiB
C
/* salCommon.c - socket application common library */
|
|
|
|
/*
|
|
* Copyright (c) 2003-2008, 2010, 2012 Wind River Systems, Inc.
|
|
*
|
|
* The right to copy, distribute, modify or otherwise make use
|
|
* of this software may be licensed only pursuant to the terms
|
|
* of an applicable Wind River license agreement.
|
|
*/
|
|
|
|
/*
|
|
modification history
|
|
--------------------
|
|
01n,12jul12,shi clean up warnings (WIND00357529)
|
|
01m,14jan10,pad System Viewer's instrumentation is available in the kernel
|
|
only.
|
|
01l,12may08,jpb Modifications for source build. Renamed
|
|
WV_INSTRUMENTATION to _WRS_CONFIG_SV_INSTRUMENTATION.
|
|
01k,18apr05,ebh connectionless sockets are considered always connected
|
|
01j,16feb05,ebh rename sockopt struct to salSockopt (it conflicts with
|
|
target/h/wrn/coreip/net/socketvar.h)
|
|
01i,01sep04,ymz renamed from salClientBase.c to salCommon.c (SPR 98185).
|
|
01h,25may04,ymz merged salClientSns.c
|
|
01g,20may04,ymz coding convention changes.
|
|
01f,19may04,p_r documentation update
|
|
01e,26apr04,ymz windview instrumentation.
|
|
01d,08apr04,ymz iteration 5 code review changes
|
|
01c,20feb04,ymz code review changes, added salCall timeout support
|
|
01b,03dec03,als clean up (comments, errnos, etc.)
|
|
01a,26nov03,als created
|
|
*/
|
|
|
|
/*
|
|
DESCRIPTION
|
|
This module contains the fundamental routines used by a SAL application,
|
|
and utility routines used by the SAL client and server libraries.
|
|
|
|
The routines assist a SAL client to look up the Socket Name Service (SNS),
|
|
and assist a SAL server to register register service with SNS.
|
|
|
|
These routines have been separated from the main SAL client and server library
|
|
so that both the client and the server components can use this common code,
|
|
without having to include each other's component.
|
|
|
|
INCLUDE FILES: salClient.h
|
|
|
|
NOMANUAL
|
|
*/
|
|
|
|
/* includes */
|
|
|
|
#include "vxWorks.h"
|
|
#include "errnoLib.h"
|
|
#include "ioLib.h"
|
|
#include "semLib.h"
|
|
#include "sockLib.h"
|
|
#include "string.h"
|
|
#include "sys/socket.h"
|
|
#include "sys/un.h"
|
|
#include "unistd.h"
|
|
#include "dsi/private/salClientP.h"
|
|
#include "dsi/private/snsLibP.h"
|
|
#include "stdio.h" /* if using DPRINT */
|
|
|
|
#ifdef _WRS_KERNEL
|
|
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
|
#include "private/eventP.h"
|
|
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
|
#endif /* _WRS_KERNEL */
|
|
|
|
/* defines */
|
|
|
|
#define DPRINT /* swap order of these two lines to enable/disable */
|
|
#undef DPRINT /* swap order of these two lines to enable/disable */
|
|
#ifdef DPRINT /* local file debug statements when DPRINT defined */
|
|
# define dprintf printf
|
|
#else
|
|
# define dprintf if (0) printf
|
|
#endif /* DPRINT */
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* salAttach - establish communication with a socket-based server
|
|
*
|
|
* This routine establishes a connection with the server application
|
|
* using the sockets specified by <pSockInfoList>.
|
|
* It tries to connect to each of the server's sockets in turn,
|
|
* until it is successful or all sockets have been tried.
|
|
*
|
|
* User should close the attached socket using close().
|
|
*
|
|
* The <options> parameter points to an array of <numOptions> socket option
|
|
* values that are applied to the client socket before a connection is attempted.
|
|
* If no options are required, <numOptions> should be set to zero.
|
|
*
|
|
* If the socket is of a connectionless type, then this routine always
|
|
* returns success. This allows the socket to be set up and be considered
|
|
* "connected".
|
|
*
|
|
* RETURNS: >=0 opened socket file descriptor, -1 otherwise
|
|
*
|
|
* ERRNO:
|
|
* \is
|
|
* \i S_salLib_INVALID_ARGUMENT
|
|
* An invalid argument was passed to this routine.
|
|
* \i S_salLib_CLIENT_SOCKET_ERROR
|
|
* Unable to connect to server using any of the specified socket addresses.
|
|
* \ie
|
|
*
|
|
* SEE ALSO: close().
|
|
*
|
|
* NOMANUAL
|
|
*/
|
|
|
|
int salAttach
|
|
(
|
|
struct addrinfo * pSockInfoList, /* list of server sockets */
|
|
struct salSockopt * pSockOptions, /* array of socket options */
|
|
int numOptions /* number of socket options */
|
|
)
|
|
{
|
|
int newSockfd; /* new client socket */
|
|
int currOpt; /* socket option counter */
|
|
|
|
|
|
SAL_DEBUG (SAL_DEBUG_CONTROL, "entered, salAttach numOptions=%d.", numOptions);
|
|
|
|
/* validate parameters */
|
|
|
|
if ( (pSockInfoList == NULL) || (numOptions < 0) ||
|
|
((numOptions > 0) && (pSockOptions == NULL)))
|
|
{
|
|
SAL_DEBUG (SAL_DEBUG_SEVERE, "invalid parameters, numOptions 0x%x",
|
|
numOptions);
|
|
errnoSet (S_salLib_INVALID_ARGUMENT);
|
|
return -1;
|
|
}
|
|
|
|
/* create connection to one of the specified server sockets */
|
|
|
|
newSockfd = -1;
|
|
for (; pSockInfoList != NULL; pSockInfoList = pSockInfoList->ai_next)
|
|
{
|
|
/* create a client socket of the same type as the server uses */
|
|
dprintf("salAttach: attempt sockfamily=%d.\n",pSockInfoList->ai_family);
|
|
dprintf(" socktype=%d.\n",pSockInfoList->ai_socktype);
|
|
dprintf(" protocol=%d.\n",pSockInfoList->ai_protocol);
|
|
|
|
newSockfd = socket (pSockInfoList->ai_family,
|
|
pSockInfoList->ai_socktype,
|
|
pSockInfoList->ai_protocol);
|
|
SAL_DEBUG (SAL_DEBUG_ALL, "socket(...) returned fd=%d\n", newSockfd);
|
|
|
|
if (newSockfd == ERROR)
|
|
{
|
|
|
|
/* try next server socket */
|
|
|
|
continue;
|
|
}
|
|
|
|
/* set the socket options (if any) */
|
|
|
|
for (currOpt = 0; currOpt < numOptions; currOpt++)
|
|
{
|
|
if (setsockopt (newSockfd, pSockOptions[currOpt].so_level,
|
|
pSockOptions[currOpt].so_name,
|
|
pSockOptions[currOpt].so_value,
|
|
pSockOptions[currOpt].so_length) != OK)
|
|
break;
|
|
}
|
|
|
|
if (currOpt != numOptions)
|
|
{
|
|
SAL_DEBUG (SAL_DEBUG_ALL,
|
|
"setsockopt(...) failed on option %d", currOpt);
|
|
|
|
/* get rid of the newly created client socket */
|
|
|
|
close (newSockfd);
|
|
newSockfd = -1;
|
|
|
|
/* try next server socket */
|
|
|
|
continue;
|
|
}
|
|
|
|
/* connect to the server socket - if connection oriented */
|
|
|
|
if ((pSockInfoList->ai_socktype == SOCK_SEQPACKET) ||
|
|
(pSockInfoList->ai_socktype == SOCK_STREAM))
|
|
{
|
|
|
|
if (connect (newSockfd, pSockInfoList->ai_addr,
|
|
pSockInfoList->ai_addr->sa_len) < 0)
|
|
{
|
|
SAL_DEBUG (SAL_DEBUG_ALL,
|
|
"connect(...) failed, socket 0x%x", newSockfd);
|
|
|
|
/* get rid of the newly created client socket */
|
|
|
|
close (newSockfd);
|
|
newSockfd = -1;
|
|
|
|
/* try next server socket */
|
|
|
|
continue;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
dprintf("salAttach: connection-less socket.\n");
|
|
}
|
|
|
|
/* have successfully created a client socket, so exit loop */
|
|
|
|
break;
|
|
}
|
|
|
|
/* creation fails if unable to create a client socket */
|
|
|
|
if (newSockfd < 0)
|
|
{
|
|
SAL_DEBUG (SAL_DEBUG_ERROR, "unable to create a client socket", 0);
|
|
errnoSet (S_salLib_CLIENT_SOCKET_ERROR);
|
|
return -1;
|
|
}
|
|
|
|
SAL_DEBUG (SAL_DEBUG_SUCCESS, "salAttach returned, sockfd 0x%0x",
|
|
newSockfd);
|
|
|
|
return newSockfd;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* salCall - invoke a socket-based server
|
|
*
|
|
* This routine sends a message to the server associated with the socket
|
|
* descriptor <sockfd> and waits for a reply. The message consists of the
|
|
* <sendLen> bytes pointed at by <pSendBuf>. The reply is placed in the
|
|
* <recvLen> bytes pointed at by <pRecvBuf>. If fewer than <recvLen> bytes
|
|
* are received the unused portion of <pRecvBuf> is not altered; if more
|
|
* than <recvLen> bytes are received the unused portion of the reply may be
|
|
* kept or discarded depending on the socket protocol being used.
|
|
*
|
|
* If the socket descriptor is used by multiple clients, mutual exclusion
|
|
* needs to be provided before this routines is called. This is to avoid the
|
|
* case when a reply is intercepted by a higher priority task sharing the
|
|
* same <sockfd>.
|
|
*
|
|
* RETURNS:
|
|
* # of bytes placed in reply buffer, for connection based transport,
|
|
* 0 bytes may returned when the called end closes the connection;
|
|
* ERROR otherwise.
|
|
*
|
|
* ERRNO:
|
|
* \is
|
|
* \i S_salLib_INVALID_ARGUMENT
|
|
* An invalid argument was passed to this routine.
|
|
* \ie
|
|
*/
|
|
|
|
int salCall
|
|
(
|
|
int sockfd, /* client socket fd */
|
|
void * pSendBuf, /* message buffer */
|
|
int sendLen, /* size of message buffer */
|
|
void * pRecvBuf, /* reply buffer */
|
|
int recvLen /* size of reply buffer */
|
|
)
|
|
{
|
|
int replySize; /* actual size of reply */
|
|
|
|
SAL_DEBUG (SAL_DEBUG_CONTROL, "entered with sockfd 0x%x", sockfd);
|
|
|
|
/* validate parameters */
|
|
|
|
if ( (sockfd < 0) || (pSendBuf == NULL) || (pRecvBuf == NULL) )
|
|
{
|
|
SAL_DEBUG (SAL_DEBUG_SEVERE,
|
|
"invalid parameters, socket 0x%0x", sockfd);
|
|
errnoSet (S_salLib_INVALID_ARGUMENT);
|
|
return ERROR;
|
|
}
|
|
|
|
#if defined(_WRS_CONFIG_SV_INSTRUMENTATION) && defined(_WRS_KERNEL)
|
|
EVT_OBJ_SAL_3 (EVENT_SALCALL_SENDREQ, sendLen, pSendBuf, sockfd);
|
|
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
|
|
|
/* send message to server */
|
|
|
|
SAL_DEBUG (SAL_DEBUG_ALL, "sending %d bytes", sendLen);
|
|
if (send (sockfd, pSendBuf, sendLen, 0) == ERROR)
|
|
{
|
|
SAL_DEBUG (SAL_DEBUG_ERROR, "send to fd=%d failed", sockfd);
|
|
return ERROR;
|
|
}
|
|
|
|
/* get reply from server */
|
|
|
|
replySize = (int)recv (sockfd, pRecvBuf, recvLen, 0);
|
|
SAL_DEBUG (SAL_DEBUG_ALL, "received %d bytes", replySize);
|
|
|
|
#if defined(_WRS_CONFIG_SV_INSTRUMENTATION) && defined(_WRS_KERNEL)
|
|
EVT_OBJ_SAL_3 (EVENT_SALCALL_REPLY, replySize, pRecvBuf, sockfd);
|
|
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
|
|
|
|
|
if (replySize == ERROR)
|
|
{
|
|
SAL_DEBUG (SAL_DEBUG_ERROR, "recv from fd=%d failed", sockfd);
|
|
return ERROR;
|
|
}
|
|
|
|
|
|
/* indicate success */
|
|
|
|
SAL_DEBUG (SAL_DEBUG_CONTROL, "returned, replySize=%d", replySize);
|
|
return replySize;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* salSnsClientCreate - create an SNS client
|
|
*
|
|
* This routine establishes communication to the SNS server.
|
|
*
|
|
* RETURNS: socket fd if >=0; -1 if error.
|
|
*
|
|
* ERRNO:
|
|
* \is
|
|
* \i S_salLib_SNS_UNAVAILABLE
|
|
* Unable to establish communications with the SNS server task.
|
|
* \ie
|
|
*
|
|
* NOMANUAL
|
|
*/
|
|
|
|
int salSnsClientCreate (void)
|
|
{
|
|
static struct addrinfo snsServerInfo; /* socket info for SNS server */
|
|
static struct sockaddr_un snsServerAddr; /* socket address of SNS server */
|
|
static BOOL addrCreated = FALSE; /* is server address created? */
|
|
int sockfd; /* returned socket fd */
|
|
|
|
/* create info about the well-known socket for the SNS server */
|
|
|
|
if (!addrCreated)
|
|
{
|
|
snsServerAddr.sun_len = sizeof (snsServerAddr);
|
|
snsServerAddr.sun_family = AF_LOCAL;
|
|
strcpy (snsServerAddr.sun_path, SNS_SERVER_PATH);
|
|
|
|
snsServerInfo.ai_flags = 0;
|
|
snsServerInfo.ai_family = AF_LOCAL;
|
|
snsServerInfo.ai_socktype = SOCK_SEQPACKET;
|
|
snsServerInfo.ai_protocol = 0;
|
|
snsServerInfo.ai_addrlen = snsServerAddr.sun_len;
|
|
snsServerInfo.ai_canonname = NULL;
|
|
snsServerInfo.ai_addr = (struct sockaddr *)&snsServerAddr;
|
|
snsServerInfo.ai_next = NULL;
|
|
|
|
addrCreated = TRUE;
|
|
}
|
|
|
|
/* try to create a client that connects to the SNS server */
|
|
|
|
sockfd = salAttach (&snsServerInfo, NULL, 0);
|
|
|
|
/* indicate results to caller */
|
|
|
|
if (sockfd < 0)
|
|
{
|
|
errnoSet (S_salLib_SNS_UNAVAILABLE);
|
|
}
|
|
return sockfd;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* salSnsClientDelete - delete an SNS client
|
|
*
|
|
* This routine terminates communication with the SNS server.
|
|
*
|
|
* RETURNS: OK or ERROR.
|
|
*
|
|
* ERRNO:
|
|
* \is
|
|
* \i S_salLib_INVALID_ARGUMENT
|
|
* An invalid argument was passed to this routine.
|
|
* \ie
|
|
*
|
|
* NOMANUAL
|
|
*/
|
|
|
|
STATUS salSnsClientDelete
|
|
(
|
|
int sockfd /* SNS client socket fd */
|
|
)
|
|
{
|
|
return close (sockfd);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* salSnsClientReplyCheck - validate the size of a reply from the SNS server
|
|
*
|
|
* This routine validates the size of a reply received from the SNS server
|
|
* by comparing it to the expected reply size.
|
|
*
|
|
* RETURNS: S_salLib_SNS_DID_NOT_REPLY if size is negative;
|
|
* S_salLib_SNS_PROTOCOL_ERROR if size does not match expected size;
|
|
* 0 if size is correct.
|
|
*
|
|
* NOMANUAL
|
|
*/
|
|
|
|
int salSnsClientReplyCheck
|
|
(
|
|
int actualSize, /* message actual size */
|
|
int expectedSize /* message expected size */
|
|
)
|
|
{
|
|
int checkErrno; /* error code to return */
|
|
|
|
/* validate size of reply */
|
|
|
|
if (actualSize < 0)
|
|
{
|
|
checkErrno = S_salLib_SNS_DID_NOT_REPLY;
|
|
}
|
|
else if (actualSize != expectedSize)
|
|
{
|
|
checkErrno = S_salLib_SNS_PROTOCOL_ERROR;
|
|
}
|
|
else
|
|
{
|
|
checkErrno = 0;
|
|
}
|
|
|
|
/* indicate results of check */
|
|
|
|
return checkErrno;
|
|
}
|