diff --git a/network.c b/network.c index 3639cae9..507dad33 100644 --- a/network.c +++ b/network.c @@ -668,6 +668,89 @@ int NETReadTillTerm(mkChannel *self, long timeout, return 1; } +/*---------------------------------------------------------------------------*/ +int NETReconnectWithFlags(mkChannel* self, int flags) +{ + int iRet; + int sock; + int oldopts; + + /* + * Get the flags and close the old socket + */ + oldopts = fcntl(self->sockid, F_GETFL, 0); + close(self->sockid); + /* Reopen and try to get it on the olf fd */ + sock = socket(AF_INET,SOCK_STREAM,0); + if (self->sockid != sock) { + iRet = fcntl(sock, F_DUPFD, self->sockid); + if (iRet != sock) + self->sockid = sock; + else + close(sock); + sock = self->sockid; + } + /* restore the old flags */ + fcntl(self->sockid, F_SETFL, oldopts); + /* set socket non-blocking */ + oldopts = fcntl(self->sockid, F_GETFL, 0); + if (/*(flags & 1) &&*/ !(oldopts & O_NONBLOCK)) + fcntl(self->sockid, F_SETFL, oldopts | O_NONBLOCK); + /* try to reconnect */ + iRet = connect(self->sockid, + (struct sockaddr *)&(self->adresse), + sizeof(struct sockaddr_in)); + if (iRet < 0) { + if (errno == EINPROGRESS) { + if ((flags & 1)) { + iRet = 0; /* in progress */ + } else { + fd_set rmask; + fd_set wmask; + struct timeval tmo = {1,0}; + + FD_ZERO(&rmask); + FD_ZERO(&wmask); + FD_SET(self->sockid, &rmask); + FD_SET(self->sockid, &wmask); + iRet = select(self->sockid+1, &rmask, &wmask, NULL, &tmo); + if (iRet < 0) /* error */ + iRet = -1; + else if (iRet == 0) /* timeout */ + iRet = 0; /* in progress */ + else { + char reply[1]; + if (FD_ISSET(self->sockid, &rmask)) { + iRet = recv(self->sockid, reply, 1, MSG_PEEK); + if (iRet <= 0) + iRet = -1; /* failure */ + } + if (FD_ISSET(self->sockid, &wmask)) { + iRet = send(self->sockid, NULL, 0, 0); + if (iRet < 0) + iRet = -1; /* failure */ + else + iRet = 1; /* success */ + } + } + } + } + else /* other error */ + iRet = -1; /* error */ + } + else + iRet = 1; /* success */ + + if (iRet != 0 && !(oldopts & O_NONBLOCK)) + fcntl(self->sockid, F_SETFL, oldopts); + return iRet; +} + +int NETReconnect(mkChannel* self) +{ + return NETReconnectWithFlags(self, 0); +} + /* ################### UDP -functions ######################################*/ mkChannel *UDPOpen(int iPort) { diff --git a/network.h b/network.h index 455d96f5..900d035a 100644 --- a/network.h +++ b/network.h @@ -76,10 +76,22 @@ of hostname are copied to pComposter */ + int NETReconnect(mkChannel* self); + /* If a connection has been lost, try to reconnect using the same + * socket id if possible. Blocks for up to one second. + * returns 0 if in progress, 1 on success, a negative value on error + */ + + int NETReconnectWithFlags(mkChannel* self, int flags); + /* If a connection has been lost, try to reconnect using the same + * socket id if possible. If (flags & 1) do not block, use + * NETConnectFinished to check success. + * returns 0 if in progress, 1 on success, a negative value on error + */ /* *********************** DATA TRANSFER ******************************** */ int NETWrite(mkChannel *self, char *buffer, long lLen); - /* writes data to socket self, returns True if succes, + /* writes data to socket self, returns True if success, false otherwise. */