- allow empty terminator in NETReadTillTermNew

- introduced NETReadFinished and NETConnectWithFlags
This commit is contained in:
zolliker
2005-09-05 08:18:22 +00:00
parent 476ad8d672
commit 15a307eef8
2 changed files with 113 additions and 23 deletions

117
network.c
View File

@ -49,6 +49,7 @@
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#define PORT 1
#define SOCKET 2
@ -206,19 +207,21 @@ 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, cnt;
@ -227,6 +230,7 @@ CreateSocketAdress(
struct linger lili;
struct timeval now;
long dif;
int oldopts;
assert(port > 0);
@ -255,22 +259,38 @@ CreateSocketAdress(
free(pRes);
return NULL;
}
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 (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 (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);
@ -284,6 +304,51 @@ CreateSocketAdress(
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 bmode */
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) {
if (FD_ISSET(self->sockid, &wmask)) {
if (FD_ISSET(self->sockid, &rmask)) {
iret = recv(self->sockid, NULL, 0, 0);
if (iret >= 0) {
iret = 1;
}
} else {
iret = send(self->sockid, NULL, 0, 0);
if (iret >= 0) {
iret = 1;
}
}
}
}
/* reset to blocking mode */
fcntl(self->sockid, F_SETFL, oldopts | ~ O_NONBLOCK);
return iret;
}
/*------------------------------------------------------------------------*/
int VerifyChannel(mkChannel *self)
{
@ -379,10 +444,13 @@ CreateSocketAdress(
iRet = send(self->sockid,buffer,lLen,0);
if(iRet != lLen)
{
printf("Incomplete send: %d to %ld\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;
}
@ -493,6 +561,8 @@ int NETReadTillTermNew(mkChannel *self, long timeout,
gettimeofday(&start, NULL);
if (pTerm == NULL) pTerm="";
length = strlen(pTerm);
memset(pBuffer,0,iBufLen);
@ -512,20 +582,24 @@ int NETReadTillTermNew(mkChannel *self, long timeout,
{
if(c == pTerm[i])
{
return 1;
return bufPtr+1;
}
}
if(c != 0) /* skip null characters */
if (c == 0 && *pTerm != 0)
{
if(bufPtr >= iBufLen-1)
{
/* 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;
bufPtr++;
} else {
return -1;
return bufPtr+1;
}
pBuffer[bufPtr] = c;
bufPtr++;
/*
wait for more data
*/
@ -542,7 +616,8 @@ int NETReadTillTermNew(mkChannel *self, long timeout,
status = NETAvailable(self,timeout-dif);
};
};
return status;
assert(bufPtr > 0);
return bufPtr;
}
/*--------------------------------------------------------------------------
This old version may be removed in some stage. It has two problems:

View File

@ -58,6 +58,18 @@
and port. Returns NULL on failure, a struct else
*/
mkChannel *NETConnectWithFlags(char *name, int port, int flags);
/* the same as NETConnect, but with flags:
if (flags & 1): do not block on connect (use NETConnectFinished
to check success)
if (flags & 2): wait 1000 ms after last close (workaround for
a bug in Lantronix terminal server
*/
int NETConnectFinished(mkChannel *self);
/* returns 0 if in progress, 1 on success, a negative value on error
*/
int NETInfo(mkChannel *self, char *pComposter, int iBufLen);
/* Once a socket is connected it is possible to figure out
which host the connection came from. Maximum iBufLen characters
@ -90,12 +102,15 @@
been found. The data is copied into the buffer pBuffer. A
maximum length of iBufLen characters is observed. The timeout
parameter defines a maximum time to wait for a terminator to
appear. NETReadTillTerm returns 1 on success, 0 on a timeout,
appear. NETReadTillTerm returns the number of characters read
(including terminator) on success, 0 on a timeout,
and a negative value if a network error occurred. Beware that
this may not work correctly if the wrong terminator is given.
The last one is really needed.
In the new version, timeout is in MILLIseconds (10 -3 sec).
However, the accuracy is machine dependent (for Linux 10 ms, for Tru64 1 ms)
However, the accuracy is machine dependent (for Linux 10 ms, for Tru64 1 ms)
If no terminator is given, the routine waits for iBufLen characters
or timeout.
*/
/* ********************* KILLING FIELD ******************************** */
int NETClosePort(mkChannel *self);