acceptor.cpp 1.66 KB
#include <cstring>
#include "socket-cpp/acceptor.h"

using namespace std;
using namespace osdev::components::socket-cpp;

acceptor acceptor::create(int domain)
{
	acceptor acc(create_handle(domain));
	if (!acc)
		acc.clear(get_last_error());
	return acc;
}

// --------------------------------------------------------------------------

// This attempts to open the acceptor, bind to the requested address, and
// start listening. On any error it will be sure to leave the underlying
// socket in an unopened/invalid state.
// If the acceptor appears to already be opened, this will quietly succeed
// without doing anything.

bool acceptor::open(const sock_address& addr,
					int queSize /*=DFLT_QUE_SIZE*/,
					bool reuseSock /*=true*/)
{
	// TODO: What to do if we are open but bound to a different address?
	if (is_open())
		return true;

	sa_family_t domain = addr.family();
	socket_t h = create_handle(domain);

	if (!check_socket_bool(h))
		return false;

	reset(h);

	#if defined(_WIN32)
		const int REUSE = SO_REUSEADDR;
	#else
		const int REUSE = SO_REUSEPORT;
	#endif
	
	if (reuseSock && (domain == AF_INET || domain == AF_INET6)) {
		int reuse = 1;
		if (!set_option(SOL_SOCKET, REUSE, reuse))
			return close_on_err();
	}

	if (!bind(addr) || !listen(queSize))
		return close_on_err();

	return true;
}

// --------------------------------------------------------------------------

stream_socket acceptor::accept(sock_address* clientAddr /*=nullptr*/)
{
	sockaddr* p = clientAddr ? clientAddr->sockaddr_ptr() : nullptr;
	socklen_t len = clientAddr ? clientAddr->size() : 0;

	socket_t s = check_socket(::accept(handle(), p, clientAddr ? &len : nullptr));
	return stream_socket(s);
}