OpenClonk
C4NetIOTCP Class Referenceabstract

#include <C4NetIO.h>

Inheritance diagram for C4NetIOTCP:
[legend]
Collaboration diagram for C4NetIOTCP:
[legend]

Classes

struct  ConnectWait
 
class  Peer
 
class  Socket
 

Public Types

typedef EndpointAddress addr_t
 

Public Member Functions

 C4NetIOTCP ()
 
 ~C4NetIOTCP () override
 
bool Init (uint16_t iPort=addr_t::IPPORT_NONE) override
 
virtual bool InitBroadcast (addr_t *pBroadcastAddr)
 
bool Close () override
 
virtual bool CloseBroadcast ()
 
bool Execute (int iMaxTime=TO_INF, pollfd *readyfds=nullptr) override
 
std::unique_ptr< SocketBind (const addr_t &addr)
 
bool Connect (const addr_t &addr, std::unique_ptr< Socket > socket)
 
bool Connect (const addr_t &addr) override
 
bool Close (const addr_t &addr) override
 
bool Send (const C4NetIOPacket &rPacket) override
 
bool Broadcast (const C4NetIOPacket &rPacket) override
 
bool SetBroadcast (const addr_t &addr, bool fSet=true) override
 
virtual void UnBlock ()
 
void GetFDs (std::vector< struct pollfd > &FDs) override
 
bool GetStatistic (int *pBroadcastRate) override
 
bool GetConnStatistic (const addr_t &addr, int *pIRate, int *pORate, int *pLoss) override
 
void ClearStatistic () override
 
void SetCallback (CBClass *pnCallback) override
 
bool IsNotify () override
 
virtual bool Send (const class C4NetIOPacket &rPacket)=0
 
virtual bool Broadcast (const class C4NetIOPacket &rPacket)=0
 
virtual const char * GetError () const
 
void ResetError ()
 
bool ExecuteUntil (int iTimeout=-1)
 
virtual C4TimeMilliseconds GetNextTick (C4TimeMilliseconds tNow)
 
bool IsSignaled ()
 
virtual bool IsLowPriority ()
 
virtual uint32_t TimerInterval ()
 

Static Public Member Functions

static std::vector< HostAddressGetLocalAddresses ()
 

Static Public Attributes

static const int TO_INF = -1
 

Protected Member Functions

virtual void PackPacket (const C4NetIOPacket &rPacket, StdBuf &rOutBuf)
 
virtual size_t UnpackPacket (const StdBuf &rInBuf, const C4NetIO::addr_t &Addr)
 
bool Listen (uint16_t inListenPort)
 
SOCKET CreateSocket (addr_t::AddressFamily family)
 
bool Connect (const addr_t &addr, SOCKET nsock)
 
PeerAccept (SOCKET nsock=INVALID_SOCKET, const addr_t &ConnectAddr=addr_t())
 
PeerGetPeer (const addr_t &addr)
 
void OnShareFree (CStdCSecEx *pCSec) override
 
void AddConnectWait (SOCKET sock, const addr_t &addr)
 
ConnectWaitGetConnectWait (const addr_t &addr)
 
void ClearConnectWaits ()
 
bool InitIPv6Socket (SOCKET socket)
 
void SetError (const char *strnError, bool fSockErr=false)
 
void Changed ()
 

Protected Attributes

PeerpPeerList {nullptr}
 
struct C4NetIOTCP::ConnectWait nullptr
 
CStdCSecEx PeerListCSec
 
CStdCSec PeerListAddCSec
 
bool fInit {false}
 
uint16_t iListenPort
 
SOCKET lsock
 
int Pipe [2]
 
StdCopyStrBuf Error
 

Friends

class Peer
 

Detailed Description

Definition at line 336 of file C4NetIO.h.


Class Documentation

◆ C4NetIOTCP::ConnectWait

struct C4NetIOTCP::ConnectWait

Definition at line 461 of file C4NetIO.h.

Collaboration diagram for C4NetIOTCP::ConnectWait:
[legend]
Class Members
addr_t addr
ConnectWait * Next
SOCKET sock

Member Typedef Documentation

◆ addr_t

typedef EndpointAddress C4NetIO::addr_t
inherited

Definition at line 213 of file C4NetIO.h.

Constructor & Destructor Documentation

◆ C4NetIOTCP()

C4NetIOTCP::C4NetIOTCP ( )

Definition at line 799 of file C4NetIO.cpp.

799  :
800  PeerListCSec(this),
802 {
803 
804 }
#define INVALID_SOCKET
Definition: C4NetIO.h:36
uint16_t iListenPort
Definition: C4NetIO.h:477
CStdCSecEx PeerListCSec
Definition: C4NetIO.h:470
SOCKET lsock
Definition: C4NetIO.h:478

◆ ~C4NetIOTCP()

C4NetIOTCP::~C4NetIOTCP ( )
override

Definition at line 806 of file C4NetIO.cpp.

807 {
808  Close();
809 }
bool Close() override
Definition: C4NetIO.cpp:857

References Close().

Here is the call graph for this function:

Member Function Documentation

◆ Accept()

C4NetIOTCP::Peer * C4NetIOTCP::Accept ( SOCKET  nsock = INVALID_SOCKET,
const addr_t ConnectAddr = addr_t() 
)
protected

Definition at line 1427 of file C4NetIO.cpp.

1428 {
1429 
1430  addr_t caddr = ConnectAddr;
1431 
1432  // accept incoming connection?
1433  C4NetIO::addr_t addr; socklen_t iAddrSize = addr.GetAddrLen();
1434  if (nsock == INVALID_SOCKET)
1435  {
1436  // accept from listener
1437 #ifdef __linux__
1438  if ((nsock = ::accept4(lsock, &addr, &iAddrSize, SOCK_CLOEXEC)) == INVALID_SOCKET)
1439 #else
1440  if ((nsock = ::accept(lsock, &addr, &iAddrSize)) == INVALID_SOCKET)
1441 #endif
1442  {
1443  // set error
1444  SetError("socket accept failed", true);
1445  return nullptr;
1446  }
1447  // connect address unknown, so zero it
1448  caddr.Clear();
1449  }
1450  else
1451  {
1452  // get peer address
1453  if (::getpeername(nsock, &addr, &iAddrSize) == SOCKET_ERROR)
1454  {
1455 #ifndef HAVE_WINSOCK
1456  // getpeername behaves strangely on exotic platforms. Just ignore it.
1457  if (errno != ENOTCONN)
1458  {
1459 #endif
1460  // set error
1461  SetError("could not get peer address for connected socket", true);
1462  return nullptr;
1463 #ifndef HAVE_WINSOCK
1464  }
1465 #endif
1466  }
1467  }
1468 
1469  // check address
1470  if (addr.GetFamily() == addr_t::UnknownFamily)
1471  {
1472  // set error
1473  SetError("socket accept failed: invalid address returned");
1474  closesocket(nsock);
1475  return nullptr;
1476  }
1477 
1478  // disable nagle (yep, we know what we are doing here - I think)
1479  int iNoDelay = 1;
1480  ::setsockopt(nsock, IPPROTO_TCP, TCP_NODELAY, reinterpret_cast<const char *>(&iNoDelay), sizeof(iNoDelay));
1481 
1482 #ifdef STDSCHEDULER_USE_EVENTS
1483  // set event
1484  if (::WSAEventSelect(nsock, Event, FD_READ | FD_WRITE | FD_CLOSE) == SOCKET_ERROR)
1485  {
1486  // set error
1487  SetError("connection accept failed: could not set event", true);
1488  closesocket(nsock);
1489  return nullptr;
1490  }
1491 #elif defined(HAVE_WINSOCK)
1492  // disable blocking
1493  unsigned long iBlock = 1;
1494  if (::ioctlsocket(nsock, FIONBIO, &iBlock) == SOCKET_ERROR)
1495  {
1496  // set error
1497  SetError("connect failed: could not disable blocking", true);
1498  close(nsock);
1499  return false;
1500  }
1501 #else
1502  // disable blocking
1503  if (::fcntl(nsock, F_SETFL, fcntl(nsock, F_GETFL) | O_NONBLOCK) == SOCKET_ERROR)
1504  {
1505  // set error
1506  SetError("connection accept failed: could not disable blocking", true);
1507  close(nsock);
1508  return nullptr;
1509  }
1510 #endif
1511 
1512 
1513  // create new peer
1514  Peer *pnPeer = new Peer(addr, nsock, this);
1515 
1516  // get required locks to add item to list
1517  CStdShareLock PeerListLock(&PeerListCSec);
1518  CStdLock PeerListAddLock(&PeerListAddCSec);
1519 
1520  // add to list
1521  pnPeer->Next = pPeerList;
1522  pPeerList = pnPeer;
1523 
1524  // clear add-lock
1525  PeerListAddLock.Clear();
1526 
1527  Changed();
1528 
1529  // ask callback if connection should be permitted
1530  if (pCB && !pCB->OnConn(addr, caddr, nullptr, this))
1531  // close socket immediately (will be deleted later)
1532  pnPeer->Close();
1533 
1534  // ok
1535  return pnPeer;
1536 }
#define SOCKET_ERROR
Definition: C4NetIO.cpp:47
#define ioctlsocket
Definition: C4NetIO.cpp:45
#define closesocket
Definition: C4NetIO.cpp:46
#define SOCK_CLOEXEC
Definition: C4NetIO.h:50
virtual bool OnConn(const addr_t &AddrPeer, const addr_t &AddrConnect, const addr_t *pOwnAddr, C4NetIO *pNetIO)
Definition: C4NetIO.h:221
void SetError(const char *strnError, bool fSockErr=false)
Definition: C4NetIO.cpp:750
EndpointAddress addr_t
Definition: C4NetIO.h:213
CStdCSec PeerListAddCSec
Definition: C4NetIO.h:471
Peer * pPeerList
Definition: C4NetIO.h:458
friend class Peer
Definition: C4NetIO.h:456
AddressFamily GetFamily() const
Definition: C4NetIO.cpp:520
size_t GetAddrLen() const
Definition: C4NetIO.cpp:526

References StdSchedulerProc::Changed(), C4NetIO::EndpointAddress::Clear(), CStdLock::Clear(), C4NetIOTCP::Peer::Close(), closesocket, C4NetIO::HostAddress::GetAddrLen(), C4NetIO::HostAddress::GetFamily(), INVALID_SOCKET, ioctlsocket, lsock, C4NetIOTCP::Peer::Next, C4NetIO::CBClass::OnConn(), Peer, PeerListAddCSec, PeerListCSec, pPeerList, C4NetIO::SetError(), SOCK_CLOEXEC, SOCKET_ERROR, and C4NetIO::HostAddress::UnknownFamily.

Referenced by Execute().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ AddConnectWait()

void C4NetIOTCP::AddConnectWait ( SOCKET  sock,
const addr_t addr 
)
protected

Definition at line 1651 of file C4NetIO.cpp.

1652 {
1653  CStdShareLock PeerListLock(&PeerListCSec);
1654  CStdLock PeerListAddLock(&PeerListAddCSec);
1655  // create new entry, add to list
1656  ConnectWait *pnWait = new ConnectWait;
1657  pnWait->sock = sock; pnWait->addr = addr;
1658  pnWait->Next = pConnectWaits;
1659  pConnectWaits = pnWait;
1660 #ifndef STDSCHEDULER_USE_EVENTS
1661  // unblock, so new FD can be realized
1662  UnBlock();
1663 #endif
1664  Changed();
1665 }
virtual void UnBlock()
Definition: C4NetIO.cpp:1343

References C4NetIOTCP::ConnectWait::addr, StdSchedulerProc::Changed(), C4NetIOTCP::ConnectWait::Next, PeerListAddCSec, PeerListCSec, C4NetIOTCP::ConnectWait::sock, and UnBlock().

Referenced by Connect().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Bind()

std::unique_ptr< C4NetIOTCP::Socket > C4NetIOTCP::Bind ( const addr_t addr)

Definition at line 1192 of file C4NetIO.cpp.

1193 {
1194  SOCKET nsock = CreateSocket(addr.GetFamily());
1195  if (nsock == INVALID_SOCKET) return nullptr;
1196 
1197  // bind the socket to the given address
1198  if (::bind(nsock, &addr, addr.GetAddrLen()) == SOCKET_ERROR)
1199  {
1200  SetError("binding the socket failed", true);
1201  closesocket(nsock);
1202  return nullptr;
1203  }
1204  return std::unique_ptr<Socket>(new Socket(nsock));
1205 }
#define SOCKET
Definition: C4NetIO.h:35
SOCKET CreateSocket(addr_t::AddressFamily family)
Definition: C4NetIO.cpp:1172

References closesocket, CreateSocket(), C4NetIO::HostAddress::GetAddrLen(), C4NetIO::HostAddress::GetFamily(), INVALID_SOCKET, C4NetIO::SetError(), SOCKET, and SOCKET_ERROR.

Here is the call graph for this function:

◆ Broadcast() [1/2]

bool C4NetIOTCP::Broadcast ( const C4NetIOPacket rPacket)
override

Definition at line 1332 of file C4NetIO.cpp.

1333 {
1334  CStdShareLock PeerListLock(&PeerListCSec);
1335  // just send to all clients
1336  bool fSuccess = true;
1337  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
1338  if (pPeer->Open() && pPeer->doBroadcast())
1339  fSuccess &= Send(C4NetIOPacket(rPacket.getRef(), pPeer->GetAddr()));
1340  return fSuccess;
1341 }
C4NetIOPacket getRef() const
Definition: C4NetIO.h:325
bool Send(const C4NetIOPacket &rPacket) override
Definition: C4NetIO.cpp:1310

References C4NetIOPacket::getRef(), C4NetIOTCP::Peer::Next, PeerListCSec, pPeerList, and Send().

Here is the call graph for this function:

◆ Broadcast() [2/2]

virtual bool C4NetIO::Broadcast ( const class C4NetIOPacket rPacket)
pure virtualinherited

◆ Changed()

void StdSchedulerProc::Changed ( )
protectedinherited

Definition at line 108 of file StdScheduler.cpp.

109 {
110  auto s = scheduler;
111  if (s)
112  s->Changed(this);
113 }
#define s

References s.

Referenced by Accept(), AddConnectWait(), C4NetIOUDP::AddPeer(), Listen(), and CStdTimerProc::SetDelay().

Here is the caller graph for this function:

◆ ClearConnectWaits()

void C4NetIOTCP::ClearConnectWaits ( )
protected

Definition at line 1677 of file C4NetIO.cpp.

1678 {
1679  CStdShareLock PeerListLock(&PeerListCSec);
1680  for (ConnectWait *pWait = pConnectWaits; pWait; pWait = pWait->Next)
1681  if (pWait->sock)
1682  {
1683  closesocket(pWait->sock);
1684  pWait->sock = 0;
1685  }
1686 }

References closesocket, C4NetIOTCP::ConnectWait::Next, and PeerListCSec.

Referenced by Close().

Here is the caller graph for this function:

◆ ClearStatistic()

void C4NetIOTCP::ClearStatistic ( )
overridevirtual

Implements C4NetIO.

Definition at line 1419 of file C4NetIO.cpp.

1420 {
1421  CStdShareLock PeerListLock(&PeerListCSec);
1422  // clear all peer statistics
1423  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
1424  pPeer->ClearStatistics();
1425 }

References C4NetIOTCP::Peer::Next, PeerListCSec, and pPeerList.

◆ Close() [1/2]

bool C4NetIOTCP::Close ( )
overridevirtual

Implements C4NetIO.

Reimplemented in C4Network2IRCClient, C4AulDebug, C4Network2IRCClient, and C4Network2IRCClient.

Definition at line 857 of file C4NetIO.cpp.

858 {
859  ResetError();
860 
861  // not init?
862  if (!fInit) return false;
863 
864  // terminate connections
865  CStdShareLock PeerListLock(&PeerListCSec);
866  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
867  if (pPeer->Open())
868  {
869  pPeer->Close();
870  if (pCB) pCB->OnDisconn(pPeer->GetAddr(), this, "owner class closed");
871  }
872 
874 
875  // close listen socket
876  if (lsock != INVALID_SOCKET)
877  {
880  }
881 
882 #ifdef STDSCHEDULER_USE_EVENTS
883  // close event
884  if (Event != nullptr)
885  {
886  WSACloseEvent(Event);
887  Event = nullptr;
888  }
889 #else
890  // close pipe
891  close(Pipe[0]);
892  close(Pipe[1]);
893 #endif
894 
895 #ifdef HAVE_WINSOCK
896  // release winsock
897  ReleaseWinSock();
898 #endif
899 
900  // ok
901  fInit = false;
902  return true;
903 }
virtual void OnDisconn(const addr_t &AddrPeer, C4NetIO *pNetIO, const char *szReason)
Definition: C4NetIO.h:222
void ResetError()
Definition: C4NetIO.h:287
int Pipe[2]
Definition: C4NetIO.h:485
bool fInit
Definition: C4NetIO.h:474
void ClearConnectWaits()
Definition: C4NetIO.cpp:1677

References ClearConnectWaits(), closesocket, fInit, INVALID_SOCKET, lsock, C4NetIOTCP::Peer::Next, C4NetIO::CBClass::OnDisconn(), PeerListCSec, Pipe, pPeerList, and C4NetIO::ResetError().

Referenced by C4Network2RefServer::Clear(), C4Network2IRCClient::Close(), C4AulDebug::Close(), Init(), ~C4NetIOTCP(), and C4NetIOTCP::Peer::~Peer().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Close() [2/2]

bool C4NetIOTCP::Close ( const addr_t addr)
overridevirtual

Implements C4NetIO.

Reimplemented in C4AulDebug.

Definition at line 1279 of file C4NetIO.cpp.

1280 {
1281  CStdShareLock PeerListLock(&PeerListCSec);
1282  // find connect wait
1283  ConnectWait *pWait = GetConnectWait(addr);
1284  if (pWait)
1285  {
1286  // close socket, do callback
1287  closesocket(pWait->sock); pWait->sock = 0;
1288  if (pCB) pCB->OnDisconn(pWait->addr, this, "closed");
1289  }
1290  else
1291  {
1292  // find peer
1293  Peer *pPeer = GetPeer(addr);
1294  if (pPeer)
1295  {
1296  C4NetIO::addr_t addr = pPeer->GetAddr();
1297  // close peer
1298  pPeer->Close();
1299  // do callback
1300  if (pCB) pCB->OnDisconn(addr, this, "closed");
1301  }
1302  // not found
1303  else
1304  return false;
1305  }
1306  // ok
1307  return true;
1308 }
Peer * GetPeer(const addr_t &addr)
Definition: C4NetIO.cpp:1593
ConnectWait * GetConnectWait(const addr_t &addr)
Definition: C4NetIO.cpp:1667

References C4NetIOTCP::ConnectWait::addr, C4NetIOTCP::Peer::Close(), closesocket, C4NetIOTCP::Peer::GetAddr(), GetConnectWait(), GetPeer(), C4NetIO::CBClass::OnDisconn(), PeerListCSec, and C4NetIOTCP::ConnectWait::sock.

Here is the call graph for this function:

◆ CloseBroadcast()

bool C4NetIOTCP::CloseBroadcast ( )
virtual

Definition at line 905 of file C4NetIO.cpp.

906 {
907  return true;
908 }

◆ Connect() [1/3]

bool C4NetIOTCP::Connect ( const addr_t addr)
overridevirtual

Implements C4NetIO.

Definition at line 1214 of file C4NetIO.cpp.

1215 {
1216  // create new socket
1217  SOCKET nsock = CreateSocket(addr.GetFamily());
1218  if (nsock == INVALID_SOCKET) return false;
1219 
1220  return Connect(addr, nsock);
1221 }
bool Connect(const addr_t &addr, std::unique_ptr< Socket > socket)
Definition: C4NetIO.cpp:1207

References Connect(), CreateSocket(), C4NetIO::HostAddress::GetFamily(), INVALID_SOCKET, and SOCKET.

Here is the call graph for this function:

◆ Connect() [2/3]

bool C4NetIOTCP::Connect ( const addr_t addr,
SOCKET  nsock 
)
protected

Definition at line 1223 of file C4NetIO.cpp.

1224 {
1225 #ifdef STDSCHEDULER_USE_EVENTS
1226  // set event
1227  if (::WSAEventSelect(nsock, Event, FD_CONNECT) == SOCKET_ERROR)
1228  {
1229  // set error
1230  SetError("connect failed: could not set event", true);
1231  closesocket(nsock);
1232  return false;
1233  }
1234 
1235  // add to list
1236  AddConnectWait(nsock, addr);
1237 
1238 #elif defined(HAVE_WINSOCK)
1239  // disable blocking
1240  unsigned long iBlock = 1;
1241  if (::ioctlsocket(nsock, FIONBIO, &iBlock) == SOCKET_ERROR)
1242  {
1243  // set error
1244  SetError("connect failed: could not disable blocking", true);
1245  close(nsock);
1246  return false;
1247  }
1248 #else
1249  // disable blocking
1250  if (::fcntl(nsock, F_SETFL, fcntl(nsock, F_GETFL) | O_NONBLOCK) == SOCKET_ERROR)
1251  {
1252  // set error
1253  SetError("connect failed: could not disable blocking", true);
1254  close(nsock);
1255  return false;
1256  }
1257 #endif
1258 
1259  // connect (async)
1260  if (::connect(nsock, &addr, addr.GetAddrLen()) == SOCKET_ERROR)
1261  {
1262  if (!HaveWouldBlockError()) // expected
1263  {
1264  SetError("socket connection failed", true);
1265  closesocket(nsock);
1266  return false;
1267  }
1268  }
1269 
1270 #ifndef STDSCHEDULER_USE_EVENTS
1271  // add to list
1272  AddConnectWait(nsock, addr);
1273 #endif
1274 
1275  // ok
1276  return true;
1277 }
bool HaveWouldBlockError()
Definition: C4NetIO.cpp:203
void AddConnectWait(SOCKET sock, const addr_t &addr)
Definition: C4NetIO.cpp:1651

References AddConnectWait(), closesocket, C4NetIO::HostAddress::GetAddrLen(), HaveWouldBlockError(), ioctlsocket, C4NetIO::SetError(), and SOCKET_ERROR.

Here is the call graph for this function:

◆ Connect() [3/3]

bool C4NetIOTCP::Connect ( const addr_t addr,
std::unique_ptr< Socket socket 
)

Definition at line 1207 of file C4NetIO.cpp.

1208 {
1209  SOCKET nsock = socket->sock;
1210  socket->sock = INVALID_SOCKET;
1211  return Connect(addr, nsock);
1212 }

References INVALID_SOCKET, and SOCKET.

Referenced by C4Network2IOConnection::Connect(), Connect(), and C4Network2IRCClient::Connect().

Here is the caller graph for this function:

◆ CreateSocket()

SOCKET C4NetIOTCP::CreateSocket ( addr_t::AddressFamily  family)
protected

Definition at line 1172 of file C4NetIO.cpp.

1173 {
1174  // create new socket
1175  SOCKET nsock = ::socket(family == HostAddress::IPv6 ? AF_INET6 : AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP);
1176  if (nsock == INVALID_SOCKET)
1177  {
1178  SetError("socket creation failed", true);
1179  return INVALID_SOCKET;
1180  }
1181 
1182  if (family == HostAddress::IPv6)
1183  if (!InitIPv6Socket(nsock))
1184  {
1185  closesocket(nsock);
1186  return INVALID_SOCKET;
1187  }
1188 
1189  return nsock;
1190 }
bool InitIPv6Socket(SOCKET socket)
Definition: C4NetIO.cpp:730

References closesocket, C4NetIO::InitIPv6Socket(), INVALID_SOCKET, C4NetIO::HostAddress::IPv6, C4NetIO::SetError(), SOCK_CLOEXEC, and SOCKET.

Referenced by Bind(), and Connect().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Execute()

bool C4NetIOTCP::Execute ( int  iMaxTime = TO_INF,
pollfd *  readyfds = nullptr 
)
overridevirtual

Implements C4NetIO.

Definition at line 919 of file C4NetIO.cpp.

920 {
921  // security
922  if (!fInit) return false;
923 
924 #ifdef STDSCHEDULER_USE_EVENTS
925  // wait for something to happen
926  if (WaitForSingleObject(Event, iMaxTime == C4NetIO::TO_INF ? INFINITE : iMaxTime) == WAIT_TIMEOUT)
927  // timeout -> nothing happened
928  return true;
929  WSAResetEvent(Event);
930 
931  WSANETWORKEVENTS wsaEvents;
932 #else
933 
934 #ifdef __APPLE__
935  iMaxTime = fix_poll_timeout(iMaxTime);
936 #endif
937 
938  std::vector<pollfd> fdvec;
939  std::map<SOCKET, const pollfd*> fdmap;
940  if (!fds)
941  {
942  // build socket sets
943  GetFDs(fdvec);
944  fds = &fdvec[0];
945  // wait for something to happen
946  int ret = poll(fds, fdvec.size(), iMaxTime);
947  // error
948  if (ret < 0)
949  {
950  SetError("poll failed");
951  return false;
952  }
953  // nothing happened
954  if (ret == 0)
955  return true;
956  }
957  else
958  {
959  // We need to know the size of fdvec, so construct the vector
960  GetFDs(fdvec);
961  // Now overwrite with the poll result
962  std::copy(fds, fds + fdvec.size(), fdvec.begin());
963  }
964 
965  // flush pipe
966  assert(fdvec[0].fd == Pipe[0]);
967  if (fdvec[0].events & fdvec[0].revents)
968  {
969  char c;
970  if (::read(Pipe[0], &c, 1) == -1)
971  SetError("read failed");
972  }
973 
974  for (std::vector<pollfd>::const_iterator i = fdvec.begin(); i != fdvec.end(); ++i)
975  fdmap[i->fd] = &*i;
976  std::map<SOCKET, const pollfd*>::const_iterator cur_fd;
977 #endif
978 
979  // check sockets for events
980 
981  // first: the listen socket
982  if (lsock != INVALID_SOCKET)
983  {
984 
985 #ifdef STDSCHEDULER_USE_EVENTS
986  // get event list
987  if (::WSAEnumNetworkEvents(lsock, nullptr, &wsaEvents) == SOCKET_ERROR)
988  return false;
989 
990  // a connection waiting for accept?
991  if (wsaEvents.lNetworkEvents & FD_ACCEPT)
992 #else
993  cur_fd = fdmap.find(lsock);
994  // a connection waiting for accept?
995  if (cur_fd != fdmap.end() && (cur_fd->second->events & cur_fd->second->revents))
996 #endif
997  if (!Accept())
998  return false;
999  // (note: what happens if there are more connections waiting?)
1000 
1001 #ifdef STDSCHEDULER_USE_EVENTS
1002  // closed?
1003  if (wsaEvents.lNetworkEvents & FD_CLOSE)
1004  // try to recreate the listen socket
1006 #endif
1007  }
1008 
1009  // second: waited-for connection
1010  CStdShareLock PeerListLock(&PeerListCSec);
1011  for (ConnectWait *pWait = pConnectWaits, *pNext; pWait; pWait = pNext)
1012  {
1013  pNext = pWait->Next;
1014 
1015  // not closed?
1016  if (pWait->sock)
1017  {
1018 #ifdef STDSCHEDULER_USE_EVENTS
1019  // get event list
1020  if (::WSAEnumNetworkEvents(pWait->sock, nullptr, &wsaEvents) == SOCKET_ERROR)
1021  return false;
1022 
1023  if (wsaEvents.lNetworkEvents & FD_CONNECT)
1024 #else
1025  // got connection?
1026  cur_fd = fdmap.find(pWait->sock);
1027  if (cur_fd != fdmap.end() && (cur_fd->second->events & cur_fd->second->revents))
1028 #endif
1029  {
1030  // remove from list
1031  SOCKET sock = pWait->sock; pWait->sock = 0;
1032 
1033 #ifdef STDSCHEDULER_USE_EVENTS
1034  // error?
1035  if (wsaEvents.iErrorCode[FD_CONNECT_BIT])
1036  {
1037  // disconnect-callback
1038  if (pCB) pCB->OnDisconn(pWait->addr, this, GetSocketErrorMsg(wsaEvents.iErrorCode[FD_CONNECT_BIT]));
1039  }
1040  else
1041 #else
1042  // get error code
1043  int iErrCode; socklen_t iErrCodeLen = sizeof(iErrCode);
1044  if (getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast<char *>(&iErrCode), &iErrCodeLen) != 0)
1045  {
1046  close(sock);
1047  if (pCB) pCB->OnDisconn(pWait->addr, this, GetSocketErrorMsg());
1048  }
1049  // error?
1050  else if (iErrCode)
1051  {
1052  close(sock);
1053  if (pCB) pCB->OnDisconn(pWait->addr, this, GetSocketErrorMsg(iErrCode));
1054  }
1055  else
1056 #endif
1057  // accept connection, do callback
1058  if (!Accept(sock, pWait->addr))
1059  return false;
1060  }
1061  }
1062 
1063  }
1064 
1065  // last: all connected sockets
1066  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
1067  if (pPeer->Open())
1068  {
1069  SOCKET sock = pPeer->GetSocket();
1070 
1071 #ifdef STDSCHEDULER_USE_EVENTS
1072  // get event list
1073  if (::WSAEnumNetworkEvents(sock, nullptr, &wsaEvents) == SOCKET_ERROR)
1074  return false;
1075 
1076  // something to read from socket?
1077  if (wsaEvents.lNetworkEvents & FD_READ)
1078 #else
1079  // something to read from socket?
1080  cur_fd = fdmap.find(sock);
1081  if (cur_fd != fdmap.end() && (POLLIN & cur_fd->second->revents))
1082 #endif
1083  for (;;)
1084  {
1085  // how much?
1086 #ifdef _WIN32
1087  DWORD iBytesToRead;
1088 #else
1089  int iBytesToRead;
1090 #endif
1091  if (::ioctlsocket(pPeer->GetSocket(), FIONREAD, &iBytesToRead) == SOCKET_ERROR)
1092  {
1093  pPeer->Close();
1094  if (pCB) pCB->OnDisconn(pPeer->GetAddr(), this, GetSocketErrorMsg());
1095  break;
1096  }
1097  // The following two lines of code will make sure that if the variable
1098  // "iBytesToRead" is zero, it will be increased by one.
1099  // In this case, it will hold the value 1 after the operation.
1100  // Note it doesn't do anything for negative values.
1101  // (This comment has been sponsored by Sven2)
1102  if (!iBytesToRead)
1103  ++iBytesToRead;
1104  // get buffer
1105  void *pBuf = pPeer->GetRecvBuf(iBytesToRead);
1106  // read a buffer full of data from socket
1107  int iBytesRead;
1108  if ((iBytesRead = ::recv(sock, reinterpret_cast<char *>(pBuf), iBytesToRead, 0)) == SOCKET_ERROR)
1109  {
1110  // Would block? Ok, let's try this again later
1111  if (HaveWouldBlockError()) { ResetSocketError(); break; }
1112  // So he's serious after all...
1113  pPeer->Close ();
1114  if (pCB) pCB->OnDisconn(pPeer->GetAddr(), this, GetSocketErrorMsg());
1115  break;
1116  }
1117  // nothing? this means the conection was closed, if you trust in linux manpages.
1118  if (!iBytesRead)
1119  {
1120  pPeer->Close();
1121  if (pCB) pCB->OnDisconn(pPeer->GetAddr(), this, "connection closed");
1122  break;
1123  }
1124  // pass to Peer::OnRecv
1125  pPeer->OnRecv(iBytesRead);
1126  }
1127 
1128  // socket has become writeable?
1129 #ifdef STDSCHEDULER_USE_EVENTS
1130  if (wsaEvents.lNetworkEvents & FD_WRITE)
1131 #else
1132  if (cur_fd != fdmap.end() && (POLLOUT & cur_fd->second->revents))
1133 #endif
1134  // send remaining data
1135  pPeer->Send();
1136 
1137 #ifdef STDSCHEDULER_USE_EVENTS
1138  // socket was closed?
1139  if (wsaEvents.lNetworkEvents & FD_CLOSE)
1140  {
1141  const char *szReason = wsaEvents.iErrorCode[FD_CLOSE_BIT] ? GetSocketErrorMsg(wsaEvents.iErrorCode[FD_CLOSE_BIT]) : "closed by peer";
1142  // close socket
1143  pPeer->Close();
1144  // do callback
1145  if (pCB) pCB->OnDisconn(pPeer->GetAddr(), this, szReason);
1146  }
1147 #endif
1148  }
1149 
1150  // done
1151  return true;
1152 }
void ResetSocketError()
Definition: C4NetIO.cpp:211
const char * GetSocketErrorMsg(int iError)
Definition: C4NetIO.cpp:190
uint32_t DWORD
#define INFINITE
Definition: StdSync.h:58
static const int TO_INF
Definition: C4NetIO.h:66
bool Listen(uint16_t inListenPort)
Definition: C4NetIO.cpp:1538
void GetFDs(std::vector< struct pollfd > &FDs) override
Definition: C4NetIO.cpp:1364
Peer * Accept(SOCKET nsock=INVALID_SOCKET, const addr_t &ConnectAddr=addr_t())
Definition: C4NetIO.cpp:1427

References Accept(), fInit, GetFDs(), GetSocketErrorMsg(), HaveWouldBlockError(), iListenPort, INFINITE, INVALID_SOCKET, ioctlsocket, Listen(), lsock, C4NetIOTCP::Peer::Next, C4NetIO::CBClass::OnDisconn(), PeerListCSec, Pipe, pPeerList, ResetSocketError(), C4NetIO::SetError(), SOCKET, SOCKET_ERROR, and C4NetIO::TO_INF.

Referenced by C4AulDebug::DebugStep().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ ExecuteUntil()

bool StdSchedulerProc::ExecuteUntil ( int  iTimeout = -1)
inherited

Definition at line 33 of file StdScheduler.cpp.

34 {
35  // Infinite?
36  if (iTimeout < 0)
37  for (;;)
38  if (!Execute())
39  return false;
40  // Calculate endpoint
41  C4TimeMilliseconds tStopTime = C4TimeMilliseconds::Now() + iTimeout;
42  for (;;)
43  {
44  // Call execute with given timeout
45  if (!Execute(std::max(iTimeout, 0)))
46  return false;
47  // Calculate timeout
49  if (tTime >= tStopTime)
50  break;
51  iTimeout = tStopTime - tTime;
52  }
53  // All ok.
54  return true;
55 }
static C4TimeMilliseconds Now()
virtual bool Execute(int iTimeout=-1, pollfd *readyfds=nullptr)=0

References StdSchedulerProc::Execute(), and C4TimeMilliseconds::Now().

Referenced by main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetConnectWait()

C4NetIOTCP::ConnectWait * C4NetIOTCP::GetConnectWait ( const addr_t addr)
protected

Definition at line 1667 of file C4NetIO.cpp.

1668 {
1669  CStdShareLock PeerListLock(&PeerListCSec);
1670  // search
1671  for (ConnectWait *pWait = pConnectWaits; pWait; pWait = pWait->Next)
1672  if (pWait->addr == addr)
1673  return pWait;
1674  return nullptr;
1675 }

References C4NetIOTCP::ConnectWait::Next, and PeerListCSec.

Referenced by Close().

Here is the caller graph for this function:

◆ GetConnStatistic()

bool C4NetIOTCP::GetConnStatistic ( const addr_t addr,
int *  pIRate,
int *  pORate,
int *  pLoss 
)
overridevirtual

Implements C4NetIO.

Definition at line 1406 of file C4NetIO.cpp.

1407 {
1408  CStdShareLock PeerListLock(&PeerListCSec);
1409  // find peer
1410  Peer *pPeer = GetPeer(addr);
1411  if (!pPeer || !pPeer->Open()) return false;
1412  // return statistics
1413  if (pIRate) *pIRate = pPeer->GetIRate();
1414  if (pORate) *pORate = pPeer->GetORate();
1415  if (pLoss) *pLoss = 0;
1416  return true;
1417 }

References C4NetIOTCP::Peer::GetIRate(), C4NetIOTCP::Peer::GetORate(), GetPeer(), C4NetIOTCP::Peer::Open(), and PeerListCSec.

Here is the call graph for this function:

◆ GetError()

virtual const char* C4NetIO::GetError ( ) const
inlinevirtualinherited

Definition at line 286 of file C4NetIO.h.

286 { return Error.getData(); }
StdCopyStrBuf Error
Definition: C4NetIO.h:283
const char * getData() const
Definition: StdBuf.h:442

References C4NetIO::Error, and StdStrBuf::getData().

Referenced by C4Network2IO::ConnectWithSocket(), C4NetIOUDP::DoLoopbackTest(), C4StartupNetDlg::DoRefresh(), C4Network2IO::Init(), C4NetIOUDP::InitBroadcast(), main(), MyCBClass::OnConn(), C4ChatControl::OnConnectBtn(), MyCBClass::OnPacket(), C4ChatControl::ProcessInput(), and C4Network2IOConnection::Send().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetFDs()

void C4NetIOTCP::GetFDs ( std::vector< struct pollfd > &  FDs)
overridevirtual

Reimplemented from StdSchedulerProc.

Definition at line 1364 of file C4NetIO.cpp.

1365 {
1366  pollfd pfd; pfd.revents = 0;
1367  // add pipe
1368  pfd.fd = Pipe[0]; pfd.events = POLLIN;
1369  fds.push_back(pfd);
1370  // add listener
1371  if (lsock != INVALID_SOCKET)
1372  {
1373  pfd.fd = lsock; pfd.events = POLLIN;
1374  fds.push_back(pfd);
1375  }
1376  // add connect waits (wait for them to become writeable)
1377  CStdShareLock PeerListLock(&PeerListCSec);
1378  for (ConnectWait *pWait = pConnectWaits; pWait; pWait = pWait->Next)
1379  {
1380  pfd.fd = pWait->sock; pfd.events = POLLOUT;
1381  fds.push_back(pfd);
1382  }
1383  // add sockets
1384  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
1385  if (pPeer->GetSocket())
1386  {
1387  // Wait for socket to become readable
1388  pfd.fd = pPeer->GetSocket(); pfd.events = POLLIN;
1389  // Wait for socket to become writeable, if there is data waiting
1390  if (pPeer->hasWaitingData())
1391  {
1392  pfd.events |= POLLOUT;
1393  }
1394  fds.push_back(pfd);
1395  }
1396 }

References INVALID_SOCKET, lsock, C4NetIOTCP::Peer::Next, C4NetIOTCP::ConnectWait::Next, PeerListCSec, Pipe, and pPeerList.

Referenced by Execute().

Here is the caller graph for this function:

◆ GetLocalAddresses()

std::vector< C4NetIO::HostAddress > C4NetIO::GetLocalAddresses ( )
staticinherited

Definition at line 631 of file C4NetIO.cpp.

632 {
633  std::vector<HostAddress> result;
634 
635 #ifdef HAVE_WINSOCK
636  HostAddress addr;
637  const size_t BUFFER_SIZE = 16000;
638  PIP_ADAPTER_ADDRESSES addresses = nullptr;
639  for (int i = 0; i < 3; ++i)
640  {
641  addresses = (PIP_ADAPTER_ADDRESSES) realloc(addresses, BUFFER_SIZE * (i+1));
642  if (!addresses)
643  // allocation failed
644  return result;
645  ULONG bufsz = BUFFER_SIZE * (i+1);
646  DWORD rv = GetAdaptersAddresses(AF_UNSPEC,
647  GAA_FLAG_SKIP_ANYCAST|GAA_FLAG_SKIP_MULTICAST|GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_SKIP_FRIENDLY_NAME,
648  nullptr, addresses, &bufsz);
649  if (rv == ERROR_BUFFER_OVERFLOW)
650  // too little space, try again
651  continue;
652  if (rv != NO_ERROR)
653  {
654  // Something else happened
655  free(addresses);
656  return result;
657  }
658  // All okay, add addresses
659  for (PIP_ADAPTER_ADDRESSES address = addresses; address; address = address->Next)
660  {
661  for (PIP_ADAPTER_UNICAST_ADDRESS unicast = address->FirstUnicastAddress; unicast; unicast = unicast->Next)
662  {
663  addr.SetHost(unicast->Address.lpSockaddr);
664  if (addr.IsLoopback())
665  continue;
666  result.push_back(addr);
667  }
668  }
669  }
670  free(addresses);
671 #else
672  bool have_ipv6 = false;
673 
674 #ifdef __linux__
675  // Get IPv6 addresses on Linux from procfs which allows filtering deprecated privacy addresses.
676  FILE *f = fopen("/proc/net/if_inet6", "r");
677  if (f)
678  {
679  sockaddr_in6 sa6 = sockaddr_in6();
680  sa6.sin6_family = AF_INET6;
681  auto a6 = sa6.sin6_addr.s6_addr;
682  uint8_t if_idx, plen, scope, flags;
683  char devname[20];
684  while (fscanf(f, "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx %02hhx %02hhx %02hhx %02hhx %20s\n",
685  &a6[0], &a6[1], &a6[2], &a6[3], &a6[4], &a6[5], &a6[6], &a6[7],
686  &a6[8], &a6[9], &a6[10], &a6[11], &a6[12], &a6[13], &a6[14], &a6[15],
687  &if_idx, &plen, &scope, &flags, devname) != EOF)
688  {
689  // Skip loopback and deprecated addresses.
690  if (scope == IPV6_ADDR_LOOPBACK || flags & IFA_F_DEPRECATED)
691  continue;
692  sa6.sin6_scope_id = scope == IPV6_ADDR_LINKLOCAL ? if_idx : 0;
693  result.emplace_back((sockaddr*) &sa6);
694  }
695  have_ipv6 = result.size() > 0;
696  fclose(f);
697  }
698 #endif
699 
700  struct ifaddrs* addrs;
701  if (getifaddrs(&addrs) < 0)
702  return result;
703  for (struct ifaddrs* ifaddr = addrs; ifaddr != nullptr; ifaddr = ifaddr->ifa_next)
704  {
705  struct sockaddr* ad = ifaddr->ifa_addr;
706  if (ad == nullptr) continue;
707 
708  if ((ad->sa_family == AF_INET || (!have_ipv6 && ad->sa_family == AF_INET6)) && (~ifaddr->ifa_flags & IFF_LOOPBACK)) // Choose only non-loopback IPv4/6 devices
709  {
710  result.emplace_back(ad);
711  }
712  }
713  freeifaddrs(addrs);
714 #endif
715 
716  return result;
717 }

References C4NetIO::HostAddress::IsLoopback(), and C4NetIO::HostAddress::SetHost().

Referenced by C4Network2Client::AddLocalAddrs(), and C4NetIOUDP::InitBroadcast().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ GetNextTick()

C4TimeMilliseconds StdSchedulerProc::GetNextTick ( C4TimeMilliseconds  tNow)
virtualinherited

Reimplemented in CStdTimerProc, C4Network2IO, C4NetIOUDP, and C4HTTPClient.

Definition at line 115 of file StdScheduler.cpp.

References C4TimeMilliseconds::PositiveInfinity.

◆ GetPeer()

C4NetIOTCP::Peer * C4NetIOTCP::GetPeer ( const addr_t addr)
protected

Definition at line 1593 of file C4NetIO.cpp.

1594 {
1595  CStdShareLock PeerListLock(&PeerListCSec);
1596  for (Peer *pPeer = pPeerList; pPeer; pPeer = pPeer->Next)
1597  if (pPeer->Open())
1598  if (pPeer->GetAddr() == addr)
1599  return pPeer;
1600  return nullptr;
1601 }

References C4NetIOTCP::Peer::Next, PeerListCSec, and pPeerList.

Referenced by Close(), GetConnStatistic(), Send(), and SetBroadcast().

Here is the caller graph for this function:

◆ GetStatistic()

bool C4NetIOTCP::GetStatistic ( int *  pBroadcastRate)
overridevirtual

Implements C4NetIO.

Definition at line 1399 of file C4NetIO.cpp.

1400 {
1401  // no broadcast
1402  if (pBroadcastRate) *pBroadcastRate = 0;
1403  return true;
1404 }

◆ Init()

bool C4NetIOTCP::Init ( uint16_t  iPort = addr_t::IPPORT_NONE)
overridevirtual

Implements C4NetIO.

Reimplemented in C4AulDebug.

Definition at line 811 of file C4NetIO.cpp.

812 {
813  // already init? close first
814  if (fInit) Close();
815 
816 #ifdef HAVE_WINSOCK
817  // init winsock
818  if (!AcquireWinSock())
819  {
820  SetError("could not start winsock");
821  return false;
822  }
823 #endif
824 
825 #ifdef STDSCHEDULER_USE_EVENTS
826  // create event
827  if ((Event = WSACreateEvent()) == WSA_INVALID_EVENT)
828  {
829  SetError("could not create socket event", true); // to do: more error information
830  return false;
831  }
832 #else
833  // create pipe
834  if (pipe(Pipe) != 0)
835  {
836  SetError("could not create pipe", true);
837  return false;
838  }
839 #endif
840 
841  // create listen socket (if necessary)
842  if (iPort != addr_t::IPPORT_NONE)
843  if (!Listen(iPort))
844  return false;
845 
846  // ok
847  fInit = true;
848  return true;
849 }
static const uint16_t IPPORT_NONE
Definition: C4NetIO.h:137

References Close(), fInit, C4NetIO::EndpointAddress::IPPORT_NONE, Listen(), Pipe, and C4NetIO::SetError().

Referenced by C4Network2IRCClient::Connect(), C4Network2IO::Init(), and C4AulDebug::Init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ InitBroadcast()

bool C4NetIOTCP::InitBroadcast ( addr_t pBroadcastAddr)
virtual

Definition at line 851 of file C4NetIO.cpp.

852 {
853  // ignore
854  return true;
855 }

◆ InitIPv6Socket()

bool C4NetIO::InitIPv6Socket ( SOCKET  socket)
protectedinherited

Definition at line 730 of file C4NetIO.cpp.

731 {
732  int opt = 0;
733  if (setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char*>(&opt), sizeof(opt)) == SOCKET_ERROR)
734  {
735  SetError("could not enable dual-stack socket", true);
736  return false;
737  }
738 
739 #ifdef IPV6_ADDR_PREFERENCES
740  // Prefer stable addresses. This should prevent issues with address
741  // deprecation while a match is running. No error handling - if the call
742  // fails, we just take any address.
743  opt = IPV6_PREFER_SRC_PUBLIC;
744  setsockopt(socket, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES, reinterpret_cast<char*>(&opt), sizeof(opt));
745 #endif
746 
747  return true;
748 }

References C4NetIO::SetError(), and SOCKET_ERROR.

Referenced by CreateSocket(), C4NetIOSimpleUDP::Init(), and Listen().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ IsLowPriority()

virtual bool StdSchedulerProc::IsLowPriority ( )
inlinevirtualinherited

Definition at line 82 of file StdScheduler.h.

82 { return false; }

◆ IsNotify()

bool C4NetIO::IsNotify ( )
inlineoverridevirtualinherited

Reimplemented from StdSchedulerProc.

Definition at line 260 of file C4NetIO.h.

260 { return true; }

◆ IsSignaled()

bool StdSchedulerProc::IsSignaled ( )
inherited

◆ Listen()

bool C4NetIOTCP::Listen ( uint16_t  inListenPort)
protected

Definition at line 1538 of file C4NetIO.cpp.

1539 {
1540  // already listening?
1541  if (lsock != INVALID_SOCKET)
1542  // close existing socket
1543  closesocket(lsock);
1545 
1546  // create socket
1547  if ((lsock = ::socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP)) == INVALID_SOCKET)
1548  {
1549  SetError("socket creation failed", true);
1550  return false;
1551  }
1552  if (!InitIPv6Socket(lsock))
1553  return false;
1554  // To be able to reuse the port after close
1555 #if !defined(_DEBUG) && !defined(_WIN32)
1556  int reuseaddr = 1;
1557  setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&reuseaddr), sizeof(reuseaddr));
1558 #endif
1559  // bind listen socket
1560  addr_t addr = addr_t::Any;
1561  addr.SetPort(inListenPort);
1562  if (::bind(lsock, &addr, addr.GetAddrLen()) == SOCKET_ERROR)
1563  {
1564  SetError("socket bind failed", true);
1566  return false;
1567  }
1568 
1569 #ifdef STDSCHEDULER_USE_EVENTS
1570  // set event callback
1571  if (::WSAEventSelect(lsock, Event, FD_ACCEPT | FD_CLOSE) == SOCKET_ERROR)
1572  {
1573  SetError("could not set event for listen socket", true);
1575  return false;
1576  }
1577 #endif
1578 
1579  // start listening
1580  if (::listen(lsock, SOMAXCONN) == SOCKET_ERROR)
1581  {
1582  SetError("socket listen failed", true);
1584  return false;
1585  }
1586 
1587  // ok
1588  iListenPort = inListenPort;
1589  Changed();
1590  return true;
1591 }

References C4NetIO::HostAddress::Any, StdSchedulerProc::Changed(), closesocket, C4NetIO::HostAddress::GetAddrLen(), iListenPort, C4NetIO::InitIPv6Socket(), INVALID_SOCKET, C4NetIO::EndpointAddress::IPPORT_NONE, lsock, C4NetIO::SetError(), C4NetIO::EndpointAddress::SetPort(), SOCK_CLOEXEC, and SOCKET_ERROR.

Referenced by Execute(), and Init().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ OnShareFree()

void C4NetIOTCP::OnShareFree ( CStdCSecEx pCSec)
overrideprotectedvirtual

Implements CStdCSecExCallback.

Definition at line 1603 of file C4NetIO.cpp.

1604 {
1605  if (pCSec == &PeerListCSec)
1606  {
1607  // clear up
1608  Peer *pPeer = pPeerList, *pLast = nullptr;
1609  while (pPeer)
1610  {
1611  // delete?
1612  if (!pPeer->Open())
1613  {
1614  // unlink
1615  Peer *pDelete = pPeer;
1616  pPeer = pPeer->Next;
1617  (pLast ? pLast->Next : pPeerList) = pPeer;
1618  // delete
1619  delete pDelete;
1620  }
1621  else
1622  {
1623  // next peer
1624  pLast = pPeer;
1625  pPeer = pPeer->Next;
1626  }
1627  }
1628  ConnectWait *pWait = pConnectWaits, *pWLast = nullptr;
1629  while (pWait)
1630  {
1631  // delete?
1632  if (!pWait->sock)
1633  {
1634  // unlink
1635  ConnectWait *pDelete = pWait;
1636  pWait = pWait->Next;
1637  (pWLast ? pWLast->Next : pConnectWaits) = pWait;
1638  // delete
1639  delete pDelete;
1640  }
1641  else
1642  {
1643  // next peer
1644  pWLast = pWait;
1645  pWait = pWait->Next;
1646  }
1647  }
1648  }
1649 }

References C4NetIOTCP::Peer::Next, C4NetIOTCP::ConnectWait::Next, C4NetIOTCP::Peer::Open(), PeerListCSec, pPeerList, and C4NetIOTCP::ConnectWait::sock.

Here is the call graph for this function:

◆ PackPacket()

void C4NetIOTCP::PackPacket ( const C4NetIOPacket rPacket,
StdBuf rOutBuf 
)
protectedvirtual

Reimplemented in C4Network2RefServer.

Definition at line 1688 of file C4NetIO.cpp.

1689 {
1690  // packet data
1691  uint8_t cFirstByte = 0xff;
1692  uint32_t iSize = rPacket.getSize();
1693  uint32_t iOASize = sizeof(cFirstByte) + sizeof(iSize) + iSize;
1694 
1695  // enlarge buffer
1696  int iPos = rOutBuf.getSize();
1697  rOutBuf.Grow(iOASize);
1698 
1699  // write packet at end of outgoing buffer
1700  *getMBufPtr<uint8_t>(rOutBuf, iPos) = cFirstByte; iPos += sizeof(uint8_t);
1701  *getMBufPtr<uint32_t>(rOutBuf, iPos) = iSize; iPos += sizeof(uint32_t);
1702  rOutBuf.Write(rPacket, iPos);
1703 }
int iSize
Definition: TstC4NetIO.cpp:32
size_t getSize() const
Definition: StdBuf.h:101
void Grow(size_t iGrow)
Definition: StdBuf.h:171
void Write(const void *pnData, size_t inSize, size_t iAt=0)
Definition: StdBuf.h:153

References StdBuf::getSize(), StdBuf::Grow(), iSize, and StdBuf::Write().

Here is the call graph for this function:

◆ ResetError()

void C4NetIO::ResetError ( )
inlineinherited

Definition at line 287 of file C4NetIO.h.

287 { Error.Clear(); }
void Clear()
Definition: StdBuf.h:466

References StdStrBuf::Clear(), and C4NetIO::Error.

Referenced by C4NetIO::C4NetIO(), Close(), C4NetIOSimpleUDP::Close(), C4NetIOUDP::CloseBroadcast(), C4Network2IO::ConnectWithSocket(), C4NetIOSimpleUDP::Execute(), C4NetIOUDP::Execute(), C4NetIOSimpleUDP::Init(), C4NetIOSimpleUDP::InitBroadcast(), C4NetIOUDP::InitBroadcast(), C4NetIOSimpleUDP::Send(), and C4Network2IOConnection::Send().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Send() [1/2]

bool C4NetIOTCP::Send ( const C4NetIOPacket rPacket)
override

Definition at line 1310 of file C4NetIO.cpp.

1311 {
1312  CStdShareLock PeerListLock(&PeerListCSec);
1313  // find peer
1314  Peer *pPeer = GetPeer(rPacket.getAddr());
1315  // not found?
1316  if (!pPeer) return false;
1317  // send
1318  return pPeer->Send(rPacket);
1319 }
const C4NetIO::addr_t & getAddr() const
Definition: C4NetIO.h:317

References C4NetIOPacket::getAddr(), GetPeer(), PeerListCSec, and C4NetIOTCP::Peer::Send().

Referenced by Broadcast(), C4NetIOTCP::Peer::Send(), and C4Network2IRCClient::Send().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Send() [2/2]

virtual bool C4NetIO::Send ( const class C4NetIOPacket rPacket)
pure virtualinherited

Referenced by main(), MyCBClass::OnConn(), MyCBClass::OnPacket(), C4Network2IOConnection::Send(), and C4Network2IO::SendPuncherPacket().

Here is the caller graph for this function:

◆ SetBroadcast()

bool C4NetIOTCP::SetBroadcast ( const addr_t addr,
bool  fSet = true 
)
overridevirtual

Implements C4NetIO.

Definition at line 1321 of file C4NetIO.cpp.

1322 {
1323  CStdShareLock PeerListLock(&PeerListCSec);
1324  // find peer
1325  Peer *pPeer = GetPeer(addr);
1326  if (!pPeer) return false;
1327  // set flag
1328  pPeer->SetBroadcast(fSet);
1329  return true;
1330 }

References GetPeer(), PeerListCSec, and C4NetIOTCP::Peer::SetBroadcast().

Here is the call graph for this function:

◆ SetCallback()

void C4NetIOTCP::SetCallback ( CBClass pnCallback)
inlineoverridevirtual

Implements C4NetIO.

Definition at line 505 of file C4NetIO.h.

505 { pCB = pnCallback; };

Referenced by C4Network2IRCClient::Connect(), and C4AulDebug::Init().

Here is the caller graph for this function:

◆ SetError()

void C4NetIO::SetError ( const char *  strnError,
bool  fSockErr = false 
)
protectedinherited

Definition at line 750 of file C4NetIO.cpp.

751 {
752  fSockErr &= HaveSocketError();
753  if (fSockErr)
754  Error.Format("%s (%s)", strnError, GetSocketErrorMsg());
755  else
756  Error.Copy(strnError);
757 }
bool HaveSocketError()
Definition: C4NetIO.cpp:199
void Copy()
Definition: StdBuf.h:467
void Format(const char *szFmt,...) GNUC_FORMAT_ATTRIBUTE_O
Definition: StdBuf.cpp:174

References StdStrBuf::Copy(), C4NetIO::Error, StdStrBuf::Format(), GetSocketErrorMsg(), and HaveSocketError().

Referenced by Accept(), Bind(), C4NetIOSimpleUDP::CloseBroadcast(), Connect(), C4Network2IRCClient::Connect(), CreateSocket(), C4NetIOUDP::DoLoopbackTest(), C4NetIOSimpleUDP::Execute(), C4NetIOUDP::Execute(), Execute(), Init(), C4NetIOSimpleUDP::Init(), C4NetIOSimpleUDP::InitBroadcast(), C4NetIOUDP::InitBroadcast(), C4NetIO::InitIPv6Socket(), C4Network2IRCClient::Join(), Listen(), C4NetIOSimpleUDP::Send(), C4Network2IRCClient::Send(), UnBlock(), and C4NetIOSimpleUDP::UnBlock().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ TimerInterval()

virtual uint32_t StdSchedulerProc::TimerInterval ( )
inlinevirtualinherited

Reimplemented in CStdTimerProc.

Definition at line 84 of file StdScheduler.h.

84 { return 0; }

◆ UnBlock()

void C4NetIOTCP::UnBlock ( )
virtual

Definition at line 1343 of file C4NetIO.cpp.

1344 {
1345 #ifdef STDSCHEDULER_USE_EVENTS
1346  // unblock WaitForSingleObject in C4NetIOTCP::Execute manually
1347  // by setting the Event
1348  WSASetEvent(Event);
1349 #else
1350  // write one character to the pipe, this will unblock everything that
1351  // waits for the FD set returned by GetFDs.
1352  char c = 1;
1353  if (write(Pipe[1], &c, 1) == -1)
1354  SetError("write failed");
1355 #endif
1356 }

References Pipe, and C4NetIO::SetError().

Referenced by AddConnectWait().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ UnpackPacket()

size_t C4NetIOTCP::UnpackPacket ( const StdBuf rInBuf,
const C4NetIO::addr_t Addr 
)
protectedvirtual

Reimplemented in C4Network2RefServer.

Definition at line 1705 of file C4NetIO.cpp.

1706 {
1707  size_t iPos = 0;
1708  // check first byte (should be 0xff)
1709  if (*getBufPtr<uint8_t>(IBuf, iPos) != (uint8_t) 0xff)
1710  // clear buffer
1711  return IBuf.getSize();
1712  iPos += sizeof(char);
1713  // read packet size
1714  uint32_t iPacketSize;
1715  if (iPos + sizeof(uint32_t) > IBuf.getSize())
1716  return 0;
1717  iPacketSize = *getBufPtr<uint32_t>(IBuf, iPos);
1718  iPos += sizeof(uint32_t);
1719  // packet incomplete?
1720  if (iPos + iPacketSize > IBuf.getSize())
1721  return 0;
1722  // ok, call back
1723  if (pCB) pCB->OnPacket(C4NetIOPacket(IBuf.getPart(iPos, iPacketSize), addr), this);
1724  // absorbed
1725  return iPos + iPacketSize;
1726 }
virtual void OnPacket(const class C4NetIOPacket &rPacket, C4NetIO *pNetIO)=0

References StdBuf::getPart(), StdBuf::getSize(), and C4NetIO::CBClass::OnPacket().

Here is the call graph for this function:

Friends And Related Function Documentation

◆ Peer

friend class Peer
friend

Definition at line 456 of file C4NetIO.h.

Referenced by Accept().

Member Data Documentation

◆ Error

StdCopyStrBuf C4NetIO::Error
protectedinherited

Definition at line 283 of file C4NetIO.h.

Referenced by C4NetIO::GetError(), C4NetIO::ResetError(), and C4NetIO::SetError().

◆ fInit

bool C4NetIOTCP::fInit {false}
protected

Definition at line 474 of file C4NetIO.h.

Referenced by Close(), Execute(), and Init().

◆ iListenPort

uint16_t C4NetIOTCP::iListenPort
protected

Definition at line 477 of file C4NetIO.h.

Referenced by Execute(), and Listen().

◆ lsock

SOCKET C4NetIOTCP::lsock
protected

Definition at line 478 of file C4NetIO.h.

Referenced by Accept(), Close(), Execute(), GetFDs(), and Listen().

◆ nullptr

struct C4NetIOTCP::ConnectWait C4NetIOTCP::nullptr
protected

◆ PeerListAddCSec

CStdCSec C4NetIOTCP::PeerListAddCSec
protected

Definition at line 471 of file C4NetIO.h.

Referenced by Accept(), and AddConnectWait().

◆ PeerListCSec

◆ Pipe

int C4NetIOTCP::Pipe[2]
protected

Definition at line 485 of file C4NetIO.h.

Referenced by Close(), Execute(), GetFDs(), Init(), and UnBlock().

◆ pPeerList

Peer* C4NetIOTCP::pPeerList {nullptr}
protected

Definition at line 458 of file C4NetIO.h.

Referenced by Accept(), Broadcast(), ClearStatistic(), Close(), Execute(), GetFDs(), GetPeer(), and OnShareFree().

◆ TO_INF

const int C4NetIO::TO_INF = -1
staticinherited

The documentation for this class was generated from the following files: