- Mapped fileeval to exe manager - Updates for TRICS file formats SKIPPED: psi/libpsi.a psi/sinqhmdriv.c psi/sinqhttp.c psi/tabledrive.c psi/tasscan.c psi/hardsup/asynsrv_utility.c psi/hardsup/sinqhm.c
935 lines
24 KiB
C
935 lines
24 KiB
C
/*--------------------------------------------------------------------------
|
|
|
|
Some networking functions. This version for TCP/IP.
|
|
|
|
|
|
|
|
|
|
Mark Koennecke, October 1996
|
|
|
|
Copyright:
|
|
|
|
Labor fuer Neutronenstreuung
|
|
Paul Scherrer Institut
|
|
CH-5423 Villigen-PSI
|
|
|
|
|
|
The authors hereby grant permission to use, copy, modify, distribute,
|
|
and license this software and its documentation for any purpose, provided
|
|
that existing copyright notices are retained in all copies and that this
|
|
notice is included verbatim in any distributions. No written agreement,
|
|
license, or royalty fee is required for any of the authorized uses.
|
|
Modifications to this software may be copyrighted by their authors
|
|
and need not follow the licensing terms described here, provided that
|
|
the new terms are clearly indicated on the first page of each file where
|
|
they apply.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
|
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
|
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
|
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
|
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
|
|
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
|
|
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
|
|
MODIFICATIONS.
|
|
----------------------------------------------------------------------------*/
|
|
#include "fortify.h"
|
|
#include "network.h"
|
|
#include <sys/time.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <ctype.h>
|
|
#include <unistd.h>
|
|
#include <netdb.h>
|
|
#include <arpa/inet.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
|
|
#define PORT 1
|
|
#define SOCKET 2
|
|
#define UDP 3
|
|
|
|
/* wait time [ms] between a close and the next open */
|
|
#define WAIT_CLOSE_OPEN 500
|
|
|
|
struct timeval lastclose={-1,0};
|
|
/*-----------------------------------------------------------------------
|
|
Redefine this function if another means of error reporting is necessary.
|
|
*/
|
|
#include "Scommon.h"
|
|
extern void SICSLogWrite(char *pText, OutCode eCode); /* servlog.c */
|
|
|
|
static void NetError(char *pText)
|
|
{
|
|
SICSLogWrite(pText,eError);
|
|
}
|
|
|
|
/* ---------------------------- Local ------------------------------------
|
|
CreateSocketAdress stolen from Tcl. Thanks to John Ousterhout
|
|
*/
|
|
|
|
static int
|
|
CreateSocketAdress(
|
|
struct sockaddr_in *sockaddrPtr, /* Socket address */
|
|
char *host, /* Host. NULL implies INADDR_ANY */
|
|
int port) /* Port number */
|
|
{
|
|
struct hostent *hostent; /* Host database entry */
|
|
struct in_addr addr; /* For 64/32 bit madness */
|
|
|
|
(void) memset((char *) sockaddrPtr, '\0', sizeof(struct sockaddr_in));
|
|
sockaddrPtr->sin_family = AF_INET;
|
|
sockaddrPtr->sin_port = htons((unsigned short) (port & 0xFFFF));
|
|
if (host == NULL) {
|
|
addr.s_addr = INADDR_ANY;
|
|
} else {
|
|
hostent = gethostbyname(host);
|
|
if (hostent != NULL) {
|
|
memcpy((char *) &addr,
|
|
(char *) hostent->h_addr_list[0], (size_t) hostent->h_length);
|
|
} else {
|
|
addr.s_addr = inet_addr(host);
|
|
if (addr.s_addr == (unsigned long)-1) {
|
|
return 0; /* error */
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* There is a rumor that this assignment may require care on
|
|
* some 64 bit machines.
|
|
*/
|
|
|
|
sockaddrPtr->sin_addr.s_addr = addr.s_addr;
|
|
return 1;
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
mkChannel *NETOpenPort(int iPort)
|
|
{
|
|
mkChannel *pRes = NULL;
|
|
int iRet,i;
|
|
struct linger lili;
|
|
|
|
pRes = (mkChannel *)malloc(sizeof(mkChannel));
|
|
if(!pRes)
|
|
return NULL;
|
|
|
|
/* open a socket */
|
|
pRes->sockid = socket(AF_INET,SOCK_STREAM,0);
|
|
if(pRes->sockid < 0)
|
|
{
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
|
|
/* REUSEADDR, for restarts */
|
|
i = 1;
|
|
setsockopt(pRes->sockid,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int));
|
|
|
|
/* bind */
|
|
memset(&(pRes->adresse),0,sizeof(struct sockaddr_in));
|
|
pRes->adresse.sin_family = AF_INET;
|
|
pRes->adresse.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
pRes->adresse.sin_port = htons(iPort);
|
|
iRet = bind(pRes->sockid,(struct sockaddr *)&(pRes->adresse),
|
|
sizeof(struct sockaddr_in));
|
|
if(iRet < 0)
|
|
{
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
|
|
/* listen */
|
|
iRet = listen(pRes->sockid,8);
|
|
if(iRet < 0)
|
|
{
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
i = sizeof(struct linger);
|
|
lili.l_onoff = 1;
|
|
lili.l_linger = 1;
|
|
/*
|
|
setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i);
|
|
*/
|
|
pRes->iType = PORT;
|
|
pRes->lMagic = NETMAGIC;
|
|
return pRes;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
mkChannel *NETAccept(mkChannel *self, long timeout)
|
|
{
|
|
mkChannel *pRes = NULL;
|
|
int iRet;
|
|
fd_set lMask;
|
|
struct timeval tmo = {1,0};
|
|
int iLen, i;
|
|
struct linger lili;
|
|
|
|
assert(self != NULL);
|
|
|
|
if(timeout >= 0)
|
|
{
|
|
/* select first */
|
|
tmo.tv_usec = (timeout % 1000) * 1000;
|
|
tmo.tv_sec = timeout / 1000;
|
|
FD_ZERO(&lMask);
|
|
FD_SET(self->sockid,&lMask);
|
|
if((self->sockid >= FD_SETSIZE) || (self->sockid < 0) ) /* invalid descriptor */
|
|
{
|
|
return NULL; /* eof */
|
|
}
|
|
iRet = select( (self->sockid + 1),(fd_set *)&lMask, NULL, NULL,&tmo);
|
|
if( iRet <= 0)
|
|
{
|
|
/* failure, or no request */
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/* positive: accept */
|
|
iLen = sizeof(struct sockaddr);
|
|
pRes = (mkChannel *)malloc(sizeof(mkChannel));
|
|
if(!pRes) return NULL;
|
|
|
|
pRes->sockid = accept(self->sockid,
|
|
(struct sockaddr *)&(pRes->adresse),
|
|
&iLen);
|
|
if(pRes->sockid < 0)
|
|
{
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
/*
|
|
i = sizeof(struct linger);
|
|
lili.l_onoff = 1;
|
|
lili.l_linger = 1;
|
|
setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i);
|
|
i = 1;
|
|
setsockopt(pRes->sockid,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int));
|
|
*/
|
|
pRes->iType = SOCKET;
|
|
pRes->lMagic = NETMAGIC;
|
|
return pRes;
|
|
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
mkChannel *NETConnectWithFlags(char *name, int port, int flags)
|
|
{
|
|
mkChannel *pRes = NULL;
|
|
int iRet, i, cnt;
|
|
char pBueffel[80];
|
|
struct hostent *pServer = NULL;
|
|
struct linger lili;
|
|
struct timeval now;
|
|
long dif;
|
|
int oldopts;
|
|
|
|
assert(port > 0);
|
|
|
|
/* default name to localhost */
|
|
if(name == NULL)
|
|
{
|
|
strcpy(pBueffel,"localhost");
|
|
name = pBueffel;
|
|
}
|
|
|
|
/* new channel */
|
|
pRes = (mkChannel *)malloc(sizeof(mkChannel));
|
|
if(!pRes)
|
|
return NULL;
|
|
|
|
/* connect */
|
|
iRet = CreateSocketAdress(&(pRes->adresse),name,port);
|
|
if(!iRet)
|
|
{
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
pRes->sockid = socket(AF_INET,SOCK_STREAM,0);
|
|
if(pRes->sockid < 0)
|
|
{
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
|
|
if (flags & 2) { /* wait if closed recently */
|
|
/* workaround for a bug in Lantronix terminal server:
|
|
if a channel is closed and reopened within short time
|
|
the connect will be succesful, but a message will be
|
|
sent on the channel! */
|
|
|
|
if (lastclose.tv_sec >= 0) {
|
|
gettimeofday(&now, NULL);
|
|
dif = (now.tv_sec-lastclose.tv_sec)*1000+(now.tv_usec-lastclose.tv_usec)/1000;
|
|
if (dif < 0) dif += 24*3600*1000;
|
|
} else {
|
|
dif = 0;
|
|
}
|
|
if (dif < WAIT_CLOSE_OPEN) {
|
|
usleep((WAIT_CLOSE_OPEN-dif)*1000);
|
|
}
|
|
}
|
|
|
|
if (flags & 1) { /* open in non blocking mode */
|
|
oldopts = fcntl(pRes->sockid, F_GETFL, 0);
|
|
fcntl(pRes->sockid, F_SETFL, oldopts | O_NONBLOCK);
|
|
}
|
|
|
|
iRet = connect(pRes->sockid,(struct sockaddr *)&(pRes->adresse),
|
|
sizeof(struct sockaddr_in));
|
|
if(iRet < 0)
|
|
{
|
|
if (errno != EINPROGRESS) {
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
}
|
|
/*
|
|
i = sizeof(struct linger);
|
|
lili.l_onoff = 1;
|
|
lili.l_linger = 1;
|
|
setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i);
|
|
i = 1;
|
|
setsockopt(pRes->sockid,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int));
|
|
*/
|
|
pRes->iType = SOCKET;
|
|
pRes->lMagic = NETMAGIC;
|
|
return pRes;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
mkChannel *NETConnect(char *name, int port) {
|
|
return NETConnectWithFlags(name, port, 0);
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int NETConnectFinished(mkChannel *self) {
|
|
fd_set wmask, rmask;
|
|
struct timeval tmo = {0,0};
|
|
int iret;
|
|
int oldopts;
|
|
|
|
if (self->sockid == 0) {
|
|
errno = ENOTCONN;
|
|
return -1;
|
|
}
|
|
oldopts = fcntl(self->sockid, F_GETFL, 0);
|
|
if (! (oldopts | O_NONBLOCK)) {
|
|
/* assume success when in blocking mode */
|
|
return 1;
|
|
}
|
|
FD_ZERO(&wmask);
|
|
FD_ZERO(&rmask);
|
|
FD_SET(self->sockid, &wmask);
|
|
FD_SET(self->sockid, &rmask);
|
|
iret = select(self->sockid+1, &rmask, &wmask, NULL, &tmo);
|
|
if (iret == 0) return 0; /* in progress */
|
|
if (iret > 0) {
|
|
/* the connection has either succeded or failed
|
|
- the write flag indicates success
|
|
- the read flag indicates, if there is already data pending
|
|
the read flag should not appear without the write flag
|
|
*/
|
|
if (FD_ISSET(self->sockid, &wmask)) { /* should always be true */
|
|
if (FD_ISSET(self->sockid, &rmask)) { /* there may already be data for read */
|
|
iret = recv(self->sockid, NULL, 0, 0); /* zero length, check only return value */
|
|
if (iret >= 0) {
|
|
iret = 1; /* success */
|
|
} /* else failure */
|
|
} else {
|
|
iret = send(self->sockid, NULL, 0, 0); /* zero length, check only return value */
|
|
if (iret >= 0) {
|
|
iret = 1; /* success */
|
|
} /* else failure */
|
|
}
|
|
}
|
|
}
|
|
/* reset to blocking mode */
|
|
fcntl(self->sockid, F_SETFL, oldopts | ~ O_NONBLOCK);
|
|
return iret;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
int VerifyChannel(mkChannel *self)
|
|
{
|
|
if(!self)
|
|
{
|
|
return 0;
|
|
}
|
|
if(self->lMagic != NETMAGIC)
|
|
{
|
|
NetError("CORRUPTED MAGIC: network channel data corrupted");
|
|
return 0;
|
|
}
|
|
if( (self->sockid < 0) || (self->sockid > 65000) )
|
|
{
|
|
NetError("MAGIC DEAD: Invalid socket number, data corrupted");
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
/*------------------------------------------------------------------------*/
|
|
int NETInfo(mkChannel *self, char *pCompost, int iBufLen)
|
|
{
|
|
|
|
int t;
|
|
int len;
|
|
struct sockaddr_in sin;
|
|
struct hostent *host;
|
|
|
|
if(!VerifyChannel(self))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
len = sizeof sin;
|
|
if (getpeername(self->sockid, (struct sockaddr *) &sin, &len) < 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if ((host = gethostbyaddr((char *) &sin.sin_addr,
|
|
sizeof sin.sin_addr,
|
|
AF_INET)) == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
strncpy(pCompost,host->h_name,iBufLen);
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int NETWrite(mkChannel *self, char *buffer, long lLen)
|
|
{
|
|
int iRet;
|
|
fd_set lMask;
|
|
struct timeval tmo ={0,1};
|
|
|
|
|
|
if(!VerifyChannel(self))
|
|
{
|
|
return 0;
|
|
}
|
|
if(!(self->iType == SOCKET))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#ifndef CYGNUS
|
|
/* setup for select first */
|
|
tmo.tv_usec = 100;
|
|
FD_ZERO(&lMask);
|
|
FD_SET(self->sockid,&lMask);
|
|
if((self->sockid >= FD_SETSIZE) || (self->sockid < 0) )
|
|
/* invalid descriptor */
|
|
{
|
|
return -1; /* eof */
|
|
}
|
|
iRet = select( (self->sockid + 1),NULL, &lMask, NULL,&tmo);
|
|
if( iRet <= 0)
|
|
{
|
|
/* failure, or no data */
|
|
return -1;
|
|
}
|
|
/* blocking on write */
|
|
if(!FD_ISSET(self->sockid,&lMask))
|
|
{
|
|
return -2;
|
|
}
|
|
#endif
|
|
iRet = send(self->sockid,buffer,lLen,0);
|
|
if(iRet != lLen)
|
|
{
|
|
if(iRet < 0)
|
|
{
|
|
if (errno != EPIPE) { /* do not write "broken pipe" error */
|
|
printf("System error: %s\n",strerror(errno));
|
|
}
|
|
} else {
|
|
printf("Incomplete send: %d to %ld\n",iRet,lLen);
|
|
}
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
}
|
|
/* -------------------------------------------------------------------------*/
|
|
long NETRead(mkChannel *self, char *buffer, long lLen, long timeout)
|
|
{
|
|
fd_set lMask;
|
|
struct timeval tmo ={0,1};
|
|
long iRet;
|
|
|
|
if(!VerifyChannel(self))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if(timeout >= 0)
|
|
{
|
|
/* setup for select first */
|
|
tmo.tv_usec = (timeout % 1000) *1000;
|
|
tmo.tv_sec = timeout / 1000;
|
|
FD_ZERO(&lMask);
|
|
FD_SET(self->sockid,&lMask);
|
|
if((self->sockid >= FD_SETSIZE) || (self->sockid < 0) ) /* invalid descriptor */
|
|
{
|
|
return -1; /* eof */
|
|
}
|
|
iRet = select( (self->sockid + 1),&lMask, NULL, NULL,&tmo);
|
|
if( iRet <= 0)
|
|
{
|
|
/* failure, or no data
|
|
printf(" %d %d\n", iRet, errno);
|
|
*/
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* data or block for read, read */
|
|
memset(buffer,0,lLen);
|
|
iRet = recv(self->sockid,buffer,lLen,0);
|
|
if(iRet == 0)
|
|
{/* eof */
|
|
return -1;
|
|
}
|
|
if(iRet < 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return iRet;
|
|
}
|
|
}
|
|
/*---------------------------------------------------------------------*/
|
|
int NETAvailable(mkChannel *self, long timeout)
|
|
{
|
|
fd_set lMask;
|
|
struct timeval tmo ={0,1};
|
|
int iRet;
|
|
|
|
if(!VerifyChannel(self))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/* setup for select */
|
|
tmo.tv_usec = (timeout % 1000) * 1000;
|
|
tmo.tv_sec = timeout / 1000;
|
|
FD_ZERO(&lMask);
|
|
FD_SET(self->sockid,&lMask);
|
|
if((self->sockid >= FD_SETSIZE) || (self->sockid < 0) )
|
|
/* invalid descriptor */
|
|
{
|
|
return -1; /* eof */
|
|
}
|
|
iRet = select( (self->sockid + 1),&lMask, NULL, NULL,&tmo);
|
|
if( iRet < 0)
|
|
{
|
|
return -1;
|
|
}
|
|
if(FD_ISSET(self->sockid,&lMask))
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
/*-------------------------------------------------------------------------*/
|
|
int NETReadTillTerm(mkChannel *self, long timeout,
|
|
char *pTerm, char *pBuffer, int iBufLen)
|
|
{
|
|
struct timeval start, now;
|
|
int bufPtr = 0, status, i, length, matchIndex=1;
|
|
char c;
|
|
long dif;
|
|
|
|
if(!VerifyChannel(self))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
gettimeofday(&start, NULL);
|
|
|
|
if (pTerm == NULL) pTerm="";
|
|
|
|
length = strlen(pTerm);
|
|
memset(pBuffer,0,iBufLen);
|
|
|
|
status = NETAvailable(self,timeout); /* first time: full timeout */
|
|
if(status <= 0) /* return on error or on timeout */
|
|
{
|
|
return status;
|
|
}
|
|
while (status > 0)
|
|
{
|
|
status = recv(self->sockid,&c,1,0);
|
|
if(status <= 0)
|
|
{
|
|
return status;
|
|
}
|
|
if ('&' != pTerm[0]) {
|
|
for(i = 0; i < length; i++)
|
|
{
|
|
if(c == pTerm[i])
|
|
{
|
|
return bufPtr+1;
|
|
}
|
|
}
|
|
} else {
|
|
if (matchIndex == 1 && c == pTerm[1]) {
|
|
matchIndex++;
|
|
} else {
|
|
if (c== pTerm[matchIndex] && matchIndex < length -1) {
|
|
matchIndex++;
|
|
} else {
|
|
if (c == pTerm[matchIndex] && matchIndex == length - 1) {
|
|
bufPtr = bufPtr - matchIndex + 1;
|
|
pBuffer[bufPtr] = '\0';
|
|
return bufPtr;
|
|
} else {
|
|
matchIndex == 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (c == 0 && *pTerm != 0)
|
|
{
|
|
/* a null character is an error, except when no terminator is defined (binary data) */
|
|
return -1;
|
|
}
|
|
if(bufPtr >= iBufLen-1)
|
|
{
|
|
if (*pTerm != 0) { /* terminator expected */
|
|
return -1; /* overflow */
|
|
}
|
|
pBuffer[bufPtr] = c;
|
|
return bufPtr+1;
|
|
}
|
|
pBuffer[bufPtr] = c;
|
|
bufPtr++;
|
|
/*
|
|
wait for more data
|
|
*/
|
|
status = NETAvailable(self,0); /* timeout 0 (just poll) */
|
|
if (status == 0 && timeout > 0)
|
|
{
|
|
gettimeofday(&now, NULL);
|
|
dif = (now.tv_sec-start.tv_sec)*1000+(now.tv_usec-start.tv_usec)/1000;
|
|
if (dif < 0) dif += 24*3600*1000; /* treat midnight correctly */
|
|
if(dif > timeout)
|
|
{
|
|
return 0; /* timeout */
|
|
}
|
|
status = NETAvailable(self,timeout-dif);
|
|
};
|
|
};
|
|
assert(bufPtr > 0);
|
|
return bufPtr;
|
|
}
|
|
/*---------------------------------------------------------------------------*/
|
|
int NETClosePort(mkChannel *self)
|
|
{
|
|
int iRet;
|
|
|
|
if(!VerifyChannel(self))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
iRet = close(self->sockid);
|
|
gettimeofday(&lastclose, NULL);
|
|
self->iType = 0;
|
|
self->sockid = 0;
|
|
if(iRet < 0)
|
|
return 0;
|
|
else
|
|
return 1;
|
|
|
|
}
|
|
/* ################### UDP -functions ######################################*/
|
|
mkChannel *UDPOpen(int iPort)
|
|
{
|
|
mkChannel *pRes = NULL;
|
|
int iRet, i;
|
|
|
|
pRes = (mkChannel *)malloc(sizeof(mkChannel));
|
|
if(!pRes)
|
|
return NULL;
|
|
|
|
/* open a socket */
|
|
pRes->sockid = socket(AF_INET,SOCK_DGRAM,0);
|
|
if(pRes->sockid < 0)
|
|
{
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
|
|
/* REUSEADDR for restarting ability */
|
|
i = 1;
|
|
setsockopt(pRes->sockid,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int));
|
|
|
|
assert(pRes->sockid < (sizeof(long)*8));
|
|
/* if this fails the masks for select will be to
|
|
short.
|
|
*/
|
|
|
|
|
|
/* bind */
|
|
memset(&(pRes->adresse),0,sizeof(struct sockaddr_in));
|
|
pRes->adresse.sin_family = AF_INET;
|
|
pRes->adresse.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
pRes->adresse.sin_port = htons(iPort);
|
|
iRet = bind(pRes->sockid,(struct sockaddr *)&(pRes->adresse),
|
|
sizeof(struct sockaddr_in));
|
|
if(iRet < 0)
|
|
{
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
|
|
pRes->iType = UDP;
|
|
pRes->lMagic = NETMAGIC;
|
|
return pRes;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
mkChannel *UDPConnect(char *name, int port)
|
|
{
|
|
mkChannel *pRes = NULL;
|
|
int iRet, i;
|
|
char pBueffel[80];
|
|
struct hostent *pServer = NULL;
|
|
|
|
assert(port > 0);
|
|
|
|
/* default name to localhost */
|
|
if(name == NULL)
|
|
{
|
|
strcpy(pBueffel,"localhost");
|
|
name = pBueffel;
|
|
}
|
|
|
|
/* new channel */
|
|
pRes = (mkChannel *)malloc(sizeof(mkChannel));
|
|
if(!pRes)
|
|
return NULL;
|
|
|
|
/* connect */
|
|
iRet = CreateSocketAdress(&(pRes->adresse),name,port);
|
|
if(!iRet)
|
|
{
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
pRes->sockid = socket(AF_INET,SOCK_DGRAM,0);
|
|
if(pRes->sockid < 0)
|
|
{
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
/*
|
|
iRet = connect(pRes->sockid,(struct sockaddr *)&(pRes->adresse),
|
|
sizeof(struct sockaddr_in));
|
|
*/
|
|
iRet = 1;
|
|
if(iRet < 0)
|
|
{
|
|
free(pRes);
|
|
return NULL;
|
|
}
|
|
|
|
/* i = 1;
|
|
setsockopt(pRes->sockid,SOL_SOCKET,SO_REUSEADDR,&i,sizeof(int));
|
|
*/
|
|
pRes->iType = UDP;
|
|
pRes->lMagic = NETMAGIC;
|
|
return pRes;
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
long UDPRead(mkChannel *self, char *buffer, long lLen, int timeout)
|
|
{
|
|
long lMask = 0L;
|
|
struct timeval tmo ={0,1};
|
|
long iRet;
|
|
int iLang;
|
|
|
|
if(!VerifyChannel(self))
|
|
{
|
|
return 0;
|
|
}
|
|
assert(self->iType == UDP);
|
|
|
|
if(timeout >= 0)
|
|
{
|
|
/* setup for select first */
|
|
tmo.tv_usec = (timeout % 1000) *1000;
|
|
tmo.tv_sec = timeout / 1000;
|
|
lMask = (1 << self->sockid);
|
|
iRet = select( (self->sockid + 1),(fd_set *)&lMask, NULL, NULL,&tmo);
|
|
if( iRet <= 0)
|
|
{
|
|
/* failure, or no data */
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/* data, read */
|
|
buffer[0] = '\0';
|
|
iLang = sizeof(struct sockaddr_in);
|
|
iRet = recvfrom(self->sockid,buffer,lLen,0,
|
|
(struct sockaddr *)&(self->adresse),
|
|
&iLang);
|
|
if(iRet == 0)
|
|
{/* eof */
|
|
return -1;
|
|
}
|
|
if(iRet < 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
buffer[iRet] = '\0';
|
|
return iRet;
|
|
}
|
|
}
|
|
/*--------------------------------------------------------------------------*/
|
|
int UDPWrite(mkChannel *self, char *buffer, long lLen)
|
|
{
|
|
int iRet;
|
|
|
|
if(!VerifyChannel(self))
|
|
{
|
|
return 0;
|
|
}
|
|
assert(self->iType == UDP);
|
|
|
|
iRet = sendto(self->sockid,buffer,lLen,0,
|
|
(struct sockaddr *)&(self->adresse),sizeof(struct sockaddr_in));
|
|
fsync(self->sockid);
|
|
if(iRet < 0)
|
|
{
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* ==========================================================================
|
|
|
|
TestCode. Compile with DBCLIENT defined to get a test client,
|
|
with DBSERVER defined to get a test server.
|
|
*/
|
|
|
|
#ifdef DBCLIENT
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
char pBueffel[80];
|
|
mkChannel *pChan = NULL;
|
|
int iRet;
|
|
|
|
pChan = NETConnect("localhost",4711);
|
|
if(!pChan)
|
|
{
|
|
puts("No connection to server");
|
|
exit(2);
|
|
}
|
|
|
|
for( ; ; )
|
|
{
|
|
printf("Client> ");
|
|
gets(pBueffel);
|
|
if(strcmp(pBueffel,"exit") == 0)
|
|
break;
|
|
iRet = NETWrite(pChan,pBueffel,strlen(pBueffel));
|
|
if(!iRet)
|
|
puts("Write error");
|
|
|
|
iRet = NETRead(pChan,pBueffel,79,2000);
|
|
if(iRet < -1)
|
|
{
|
|
puts("Read error");
|
|
}
|
|
else if(iRet > 0)
|
|
{
|
|
pBueffel[iRet] = '\0';
|
|
puts(pBueffel);
|
|
}
|
|
}
|
|
NETClosePort(pChan);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#ifdef DBSERVER
|
|
int main(int argc, char *argv[])
|
|
{
|
|
mkChannel *pPort = NULL;
|
|
mkChannel *pCon[20];
|
|
int i,iRet, iPtr = 0;
|
|
char pBueffel[132];
|
|
|
|
pPort = NETOpenPort(4711);
|
|
if(!pPort)
|
|
{
|
|
puts("Cannot start server");
|
|
exit(1);
|
|
}
|
|
|
|
while(1)
|
|
{
|
|
/* accept new connections */
|
|
pCon[iPtr] = NETAccept(pPort,200);
|
|
if(pCon[iPtr])
|
|
{
|
|
printf("Connection accepted on socket %d\n",pCon[iPtr]->sockid);
|
|
iPtr++;
|
|
}
|
|
|
|
/* look for messages */
|
|
for(i = 0; i < iPtr; i++)
|
|
{
|
|
if(pCon[i])
|
|
{
|
|
iRet = NETRead(pCon[i],pBueffel,131,200);
|
|
if(iRet < 0)
|
|
{
|
|
printf("closing socket %d\n",pCon[i]->sockid);
|
|
NETClosePort(pCon[i]);
|
|
free(pCon[i]);
|
|
pCon[i] = NULL;
|
|
}
|
|
else if(iRet > 0)
|
|
{
|
|
pBueffel[iRet] = '\0';
|
|
printf("Received - %s - from %d\n",pBueffel,pCon[i]->sockid);
|
|
NETWrite(pCon[i],"Acknowledge",strlen("Acknowledge"));
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
#endif
|