/*
NetLink Sockets: Networking C++ library
Copyright 2012 Pedro Francisco Pareja Ruiz (PedroPareja@Gmail.com)
This file is part of NetLink Sockets.
NetLink Sockets is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
NetLink Sockets is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with NetLink Sockets. If not, see .
*/
#include "socket_group.h"
NL_NAMESPACE_USE
; // <-- this is for doxygen not to get confused by NL_NAMESPACE_USE
/**
* SocketGroup constructor
*/
SocketGroup::SocketGroup(): _cmdOnAccept(NULL), _cmdOnRead(NULL), _cmdOnDisconnect(NULL) {}
/**
* Removes a socket of the group
*
* @param socket The socket we want to be removed
* @warning This removes only one reference to the socket: if the socket was added to the group more
* than once (you shouldn't) there will be references left
*/
void SocketGroup::remove(Socket* socket) {
vector::iterator it = _vSocket.begin();
while(it != _vSocket.end())
if(*it == socket) {
_vSocket.erase(it);
return;
}
else
++it;
}
/**
* Listens for incoming data/connections
*
* Listens during milisecs time for incoming data/connections in any socket of the group calling
* the appropriate callback (Accept, Read or Disconnect) if assigned.
*
* @note UDP sockets only uses Read callback as they don not establish connections (can not accept) nor
* they register disconnections
*
* @param milisec minimum time spent listening. By defaul 0
* @param reference A pointer which can be passed to the callback functions so they have a context.
* By default NULL
* @return false if there were no incoming data, true otherwise
* @throw Exception ERROR_SELECT
*/
bool SocketGroup::listen(unsigned milisec, void* reference) {
unsigned long long finTime = getTime() + milisec;
bool executedOnce = false;
bool result = false;
while(getTime() < finTime || !executedOnce) {
executedOnce = true;
fd_set setSockets;
int maxHandle = 0;
FD_ZERO(&setSockets);
for(unsigned i=0; i < _vSocket.size(); i++) {
FD_SET(_vSocket[i]->socketHandler(), &setSockets);
maxHandle = iMax(maxHandle, _vSocket[i]->socketHandler());
}
unsigned long long milisecLeft = finTime - getTime();
struct timeval timeout;
timeout.tv_sec = milisecLeft / 1000;
timeout.tv_usec = (milisecLeft % 1000) * 1000;
int status = select(maxHandle + 1, &setSockets, NULL, NULL, &timeout);
if (status == -1)
throw Exception(Exception::ERROR_SELECT, "SocketGroup::listen: could not perform socket select");
unsigned i=0;
int launchSockets = 0;
while(launchSockets < status && i < _vSocket.size()) {
if(FD_ISSET(_vSocket[i]->socketHandler(), &setSockets)) {
launchSockets++;
if(_vSocket[i]->type() == SERVER && _vSocket[i]->protocol() == TCP) {
if(_cmdOnAccept)
_cmdOnAccept->exec(_vSocket[i], this, reference);
} //if
else {
if(_vSocket[i]->protocol() == TCP && !_vSocket[i]->nextReadSize()) {
if(_cmdOnDisconnect)
_cmdOnDisconnect->exec(_vSocket[i], this, reference);
}
else if(_cmdOnRead)
_cmdOnRead->exec(_vSocket[i], this, reference);
}
}
++i;
} //while
if(launchSockets)
result = true;
} //while
return result;
}