PSI sics-cvs-psi-2006
This commit is contained in:
289
network.c
289
network.c
@@ -1,6 +1,6 @@
|
||||
/*--------------------------------------------------------------------------
|
||||
|
||||
Some metworking functions. This version for TCP/IP.
|
||||
Some networking functions. This version for TCP/IP.
|
||||
|
||||
|
||||
|
||||
@@ -42,17 +42,23 @@
|
||||
#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.
|
||||
*/
|
||||
@@ -102,7 +108,6 @@ CreateSocketAdress(
|
||||
sockaddrPtr->sin_addr.s_addr = addr.s_addr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
mkChannel *NETOpenPort(int iPort)
|
||||
@@ -150,15 +155,16 @@ CreateSocketAdress(
|
||||
i = sizeof(struct linger);
|
||||
lili.l_onoff = 1;
|
||||
lili.l_linger = 1;
|
||||
/* setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i);
|
||||
*/
|
||||
/*
|
||||
setsockopt(pRes->sockid,SOL_SOCKET,SO_LINGER,&lili,i);
|
||||
*/
|
||||
pRes->iType = PORT;
|
||||
pRes->lMagic = NETMAGIC;
|
||||
return pRes;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
mkChannel *NETAccept(mkChannel *self, int timeout)
|
||||
mkChannel *NETAccept(mkChannel *self, long timeout)
|
||||
{
|
||||
mkChannel *pRes = NULL;
|
||||
int iRet;
|
||||
@@ -169,10 +175,11 @@ CreateSocketAdress(
|
||||
|
||||
assert(self != NULL);
|
||||
|
||||
if(timeout > 0)
|
||||
if(timeout >= 0)
|
||||
{
|
||||
/* select first */
|
||||
tmo.tv_usec = timeout;
|
||||
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 */
|
||||
@@ -200,25 +207,30 @@ CreateSocketAdress(
|
||||
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);
|
||||
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->iType = SOCKET;
|
||||
pRes->lMagic = NETMAGIC;
|
||||
return pRes;
|
||||
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
mkChannel *NETConnect(char *name, int port)
|
||||
mkChannel *NETConnectWithFlags(char *name, int port, int flags)
|
||||
{
|
||||
mkChannel *pRes = NULL;
|
||||
int iRet, i;
|
||||
int iRet, i, cnt;
|
||||
char pBueffel[80];
|
||||
struct hostent *pServer = NULL;
|
||||
struct linger lili;
|
||||
struct timeval now;
|
||||
long dif;
|
||||
int oldopts;
|
||||
|
||||
assert(port > 0);
|
||||
|
||||
@@ -247,24 +259,101 @@ CreateSocketAdress(
|
||||
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);
|
||||
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->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)
|
||||
{
|
||||
@@ -335,7 +424,8 @@ CreateSocketAdress(
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* setup for select first */
|
||||
#ifndef CYGNUS
|
||||
/* setup for select first */
|
||||
tmo.tv_usec = 100;
|
||||
FD_ZERO(&lMask);
|
||||
FD_SET(self->sockid,&lMask);
|
||||
@@ -344,7 +434,6 @@ CreateSocketAdress(
|
||||
{
|
||||
return -1; /* eof */
|
||||
}
|
||||
#ifndef CYGNUS
|
||||
iRet = select( (self->sockid + 1),NULL, &lMask, NULL,&tmo);
|
||||
if( iRet <= 0)
|
||||
{
|
||||
@@ -360,10 +449,13 @@ CreateSocketAdress(
|
||||
iRet = send(self->sockid,buffer,lLen,0);
|
||||
if(iRet != lLen)
|
||||
{
|
||||
printf("Incomplete send: %d to %d\n ",iRet,lLen);
|
||||
if(iRet < 0)
|
||||
{
|
||||
printf("System error: %s\n",strerror(errno));
|
||||
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;
|
||||
}
|
||||
@@ -374,7 +466,7 @@ CreateSocketAdress(
|
||||
|
||||
}
|
||||
/* -------------------------------------------------------------------------*/
|
||||
long NETRead(mkChannel *self, char *buffer, long lLen, int timeout)
|
||||
long NETRead(mkChannel *self, char *buffer, long lLen, long timeout)
|
||||
{
|
||||
fd_set lMask;
|
||||
struct timeval tmo ={0,1};
|
||||
@@ -385,10 +477,11 @@ CreateSocketAdress(
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(timeout > 0)
|
||||
if(timeout >= 0)
|
||||
{
|
||||
/* setup for select first */
|
||||
tmo.tv_usec = timeout;
|
||||
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 */
|
||||
@@ -422,8 +515,8 @@ CreateSocketAdress(
|
||||
}
|
||||
}
|
||||
/*---------------------------------------------------------------------*/
|
||||
int NETAvailable(mkChannel *self, int timeout)
|
||||
{
|
||||
int NETAvailable(mkChannel *self, long timeout)
|
||||
{
|
||||
fd_set lMask;
|
||||
struct timeval tmo ={0,1};
|
||||
int iRet;
|
||||
@@ -434,7 +527,8 @@ CreateSocketAdress(
|
||||
}
|
||||
|
||||
/* setup for select */
|
||||
tmo.tv_usec = timeout;
|
||||
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) )
|
||||
@@ -456,83 +550,80 @@ CreateSocketAdress(
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*--------------------------------------------------------------------------*/
|
||||
int NETReadTillTerm(mkChannel *self, int timeout,
|
||||
/*-------------------------------------------------------------------------*/
|
||||
int NETReadTillTerm(mkChannel *self, long timeout,
|
||||
char *pTerm, char *pBuffer, int iBufLen)
|
||||
{
|
||||
int iRet, termLen, i, j, nLoop;
|
||||
int read = 0;
|
||||
{
|
||||
struct timeval start, now;
|
||||
int bufPtr = 0, status, i, length;
|
||||
char c;
|
||||
long dif;
|
||||
|
||||
if(!VerifyChannel(self))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
gettimeofday(&start, NULL);
|
||||
|
||||
if(!VerifyChannel(self))
|
||||
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;
|
||||
}
|
||||
for(i = 0; i < length; i++)
|
||||
{
|
||||
if(c == pTerm[i])
|
||||
{
|
||||
return -1;
|
||||
return bufPtr+1;
|
||||
}
|
||||
|
||||
/*
|
||||
how may cycles to read in order to have a timeout
|
||||
*/
|
||||
nLoop = timeout/5;
|
||||
if(nLoop <= 0)
|
||||
{
|
||||
nLoop = 1;
|
||||
}
|
||||
|
||||
for(i = 0; i < nLoop; i++)
|
||||
{
|
||||
iRet = NETAvailable(self,5);
|
||||
if(iRet < 0)
|
||||
{
|
||||
return iRet;
|
||||
}
|
||||
else if(iRet == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
data is pending, read it
|
||||
*/
|
||||
iRet = recv(self->sockid,pBuffer+read,iBufLen - read,0);
|
||||
if(iRet < 0)
|
||||
{
|
||||
return iRet;
|
||||
}
|
||||
else
|
||||
{
|
||||
read += iRet;
|
||||
}
|
||||
if(read >= iBufLen)
|
||||
{
|
||||
pBuffer[iBufLen-1] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
pBuffer[read+1] = '\0';
|
||||
}
|
||||
/*
|
||||
have we found a terminator ?
|
||||
*/
|
||||
for(j = 0; j < strlen(pTerm); j++)
|
||||
{
|
||||
if(strrchr(pBuffer,pTerm[j]) != NULL)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(read >= iBufLen)
|
||||
{
|
||||
/*
|
||||
we have filled the buffer but not found a terminator
|
||||
*/
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0; /* timeout! */
|
||||
}
|
||||
|
||||
}
|
||||
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)
|
||||
{
|
||||
@@ -544,6 +635,7 @@ CreateSocketAdress(
|
||||
}
|
||||
|
||||
iRet = close(self->sockid);
|
||||
gettimeofday(&lastclose, NULL);
|
||||
self->iType = 0;
|
||||
self->sockid = 0;
|
||||
if(iRet < 0)
|
||||
@@ -664,10 +756,11 @@ CreateSocketAdress(
|
||||
}
|
||||
assert(self->iType == UDP);
|
||||
|
||||
if(timeout > 0)
|
||||
if(timeout >= 0)
|
||||
{
|
||||
/* setup for select first */
|
||||
tmo.tv_usec = timeout;
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user