view C++/SocketListener.cpp @ 247:806dbb6011c7

Socket: * Make copyable so it's easier to use with SocketListener * Remove domain(), type() and protocol() functions because accept() can not determine them
author David Demelier <markand@malikania.fr>
date Tue, 30 Sep 2014 20:44:50 +0200
parents 3c12f0e8bbb9
children 4ad3c85ab73e
line wrap: on
line source

/*
 * SocketListener.cpp -- portable select() wrapper
 *
 * Copyright (c) 2013, David Demelier <markand@malikania.fr>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <algorithm>

#include "SocketListener.h"

const char *SocketTimeout::what() const noexcept
{
	return "Timeout occured";
}

SocketListener::SocketListener(int count)
{
	m_sockets.reserve(count);
}

void SocketListener::add(Socket s)
{
	m_sockets.push_back(std::move(s));
}

void SocketListener::remove(const Socket &s)
{
	m_sockets.erase(std::remove(m_sockets.begin(), m_sockets.end(), s), m_sockets.end());
}

void SocketListener::clear()
{
	m_sockets.clear();
}

unsigned SocketListener::size()
{
	return m_sockets.size();
}

Socket &SocketListener::select(int s, int us)
{
	fd_set fds;
	timeval maxwait, *towait;
	auto fdmax = m_sockets.front().handle();

	FD_ZERO(&fds);
	for (auto &c : m_sockets) {
		FD_SET(c.handle(), &fds);
		if ((int)c.handle() > fdmax)
			fdmax = c.handle();
	}

	maxwait.tv_sec = s;
	maxwait.tv_usec = us;

        // Set to NULL for infinite timeout.
	towait = (s == 0 && us == 0) ? nullptr : &maxwait;

	auto error = ::select(fdmax + 1, &fds, NULL, NULL, towait);
	if (error == SOCKET_ERROR)
		throw SocketError(Socket::syserror());
	if (error == 0)
		throw SocketTimeout();

	for (Socket &c : m_sockets)
		if (FD_ISSET(c.handle(), &fds))
			return c;

	throw SocketError("No socket found");
}