/**
*
* @File : Complément de nsNet.cxx
*
* @Version : V1.0
* @Authors : D. Mathieu, M. Laporte, C. Pain-Barre
*
* @Last modified : 21/12/2001
*
**/
#include <algorithm> // max()
#include <cerrno> // EINPROGRESS
#include <fcntl.h> // F_SETFL, F_GETFL, O_NONBLOCK
#include <netinet/in.h> // sockaddr_in, in_addr
#include <sys/select.h> // FD_ZERO, FD_ISSET
#include <sys/socket.h> // connect(), SOL_SOCKET, SOL_ERROR
#include "nsSysteme.h" // Fcntl(), Select(), Close()
#include "nsNet.h" //
#include "CException.h"
#include "CExcFctSyst.h"
#include "CstCodErr.h"
#include "CstCodErrNet.h"
#include "TimeBase.h"
using namespace nsUtil;
using namespace nsSysteme;
namespace nsNet
{
void ClientConnectSockIn (int sd, const ::in_addr & Adresse,
unsigned short int Port,
unsigned TimeOut = 0)
throw (nsUtil::CException)
{
CTimevalBase Time (TimeOut);
int OldFlags = Fcntl (sd, F_GETFL);
Fcntl (sd, F_SETFL, OldFlags | O_NONBLOCK);
::sockaddr_in Addr;
Init_AddrIn (Addr, Port, Adresse);
if (::connect (sd, reinterpret_cast < ::sockaddr *> (& Addr),
sizeof (Addr)))
{
if (EINPROGRESS != errno)
throw CExcFctSystFile ("connect()", sd);
::fd_set MaskWrite;
FD_ZERO (&MaskWrite);
FD_SET (sd, & MaskWrite);
if (!Select (sd + 1, 0, &MaskWrite, 0, & Time))
{
Close (sd);
throw CException ("TimeOut de connexion", CstTimeOut);
}
int Error;
::socklen_t len = sizeof (Error);
if (::getsockopt (sd, SOL_SOCKET, SO_ERROR, &Error, &len))
throw CExcFctSystFile ("getsockopt()", sd);
if ((errno = Error))
{
Close (sd);
throw CExcFctSystFile ("connect()", sd);
}
}
Fcntl (sd, F_SETFL, OldFlags);
} // ClientConnectSockIn()
void ClientMultiConnectSockIn (int NbConnect,
int sd [],
::in_addr Adresse [],
unsigned short int Port [],
int CodErr [],
unsigned TimeOut = 0)
throw (nsUtil::CException)
{
int OldFlags [NbConnect];
CTimevalBase Time (TimeOut);
::fd_set MaskSuspended;
FD_ZERO (&MaskSuspended);
int NbInProgress = 0;
int MaxSd = 0;
for (int i = NbConnect; i--; )
{
OldFlags [i] = Fcntl (sd [i], F_GETFL);
Fcntl (sd [i], F_SETFL, OldFlags [i] | O_NONBLOCK);
::sockaddr_in Addr;
Init_AddrIn (Addr, Port [i], Adresse [i]);
if (::connect (sd [i],
reinterpret_cast < ::sockaddr *> (& Addr),
sizeof (Addr)))
if (EINPROGRESS != errno)
CodErr [i] = errno;
else
{
FD_SET (sd [i], & MaskSuspended);
MaxSd = max (MaxSd, sd [i]);
++NbInProgress;
}
else
CodErr [i] = CstNoError;
}
int NbEvent;
int Error;
socklen_t len = sizeof (Error);
// Tant qu'il y a des connexions en suspens et que des
// événements arrivent (pas de timeout)
for (; NbInProgress &&
(NbEvent = Select (MaxSd + 1, 0,
&MaskWrite, 0, & Time)); )
{
::fd_set MaskWrite = MaskSuspended;
for (int i = NbConnect; i--; )
if (FD_ISSET (sd [i], &MaskWrite))
{
FD_CLR (sd [i], &MaskSuspended);
if (::getsockopt (sd [i], SOL_SOCKET, SO_ERROR,
&Error, &len))
CodErr [i] = errno;
else
CodErr [i] = (Error) ? Error : CstNoError;
}
NbInProgress -= NbEvent;
}
for (int i = NbConnect; i--; )
{
// Tous les sd qui restent positionnés dans le masque
// correspondent à des TimeOut
if (FD_ISSET (sd [i], &MaskSuspended)
CodErr [i] = CstTimeOut;
Fcntl (sd [i], F_SETFL, OldFlags [i]);
}
} // ClientMultiConnectSockIn()
} // namespace nsNet