Skip to content
Snippets Groups Projects
listener.cpp 2.64 KiB
Newer Older
#include <glog/logging.h>

#include <ftl/uri.hpp>
#include <ftl/net/listener.hpp>
#include <ftl/net/socket.hpp>
#include <ftl/net/protocol.hpp>
#include <iostream>

#ifndef WIN32
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#endif

#ifdef WIN32
#include <windows.h>
#include <winsock.h>
typedef int socklen_t;
#define MSG_WAITALL 0
#endif

using namespace ftl;
using ftl::net::Listener;
using std::shared_ptr;

int tcpListen(URI &uri) {
	int ssock;
	//std::cerr << "TCP Listen: " << uri.getHost() << " : " << uri.getPort() << std::endl;
	#ifdef WIN32
	WSAData wsaData;
	//If Win32 then load winsock
	if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
		return INVALID_SOCKET;
	}
	#endif

	ssock = socket(AF_INET, SOCK_STREAM, 0);
	if (ssock == INVALID_SOCKET) {
		return INVALID_SOCKET;
	}
	
	int enable = 1;
	if (setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0)
		LOG(ERROR) << "setsockopt(SO_REUSEADDR) failed";

	//Specify listen port and address
	sockaddr_in slocalAddr;
	slocalAddr.sin_family = AF_INET;
	slocalAddr.sin_addr.s_addr = htonl(INADDR_ANY); // TODO, use that given in URI
	slocalAddr.sin_port = htons(uri.getPort());
	
	int rc = ::bind(ssock, (struct sockaddr*)&slocalAddr, sizeof(slocalAddr));
	
	if (rc == SOCKET_ERROR) {
		#ifndef WIN32
		close(ssock);
		#else
		closesocket(ssock);
		#endif
		ssock = INVALID_SOCKET;
		
		LOG(ERROR) << "Could not bind to " << uri.getBaseURI();
		return INVALID_SOCKET;
	}

	//Attempt to start listening for connection requests.
	rc = ::listen(ssock, 1);

	if (rc == SOCKET_ERROR) {
		#ifndef WIN32
		close(ssock);
		#else
		closesocket(ssock);
		#endif
		ssock = INVALID_SOCKET;
		
		LOG(ERROR) << "Could not listen on " << uri.getBaseURI();
		return INVALID_SOCKET;
	}
	
	return ssock;
}

int wsListen(URI &uri) {
	return INVALID_SOCKET;
}

Listener::Listener(const char *pUri) {
	URI uri(pUri);
	
	descriptor_ = INVALID_SOCKET;

	if (uri.getProtocol() == URI::SCHEME_TCP) {
		descriptor_ = tcpListen(uri);
		std::cout << "Listening: " << pUri << " - " << descriptor_ << std::endl;
	} else if (uri.getProtocol() == URI::SCHEME_WS) {
		descriptor_ = wsListen(uri);
	} else {
		
	}
}

Listener::~Listener() {
	// Close the socket.
	close();
}

void Listener::connection(shared_ptr<Socket> &s) {
	if (default_proto_) {
		s->setProtocol(default_proto_);
	}
	for (auto h : handler_connect_) h(s);
}

void Listener::close() {
	if (isListening()) {
		#ifndef WIN32
		::close(descriptor_);
		#else
		closesocket(descriptor_);
		#endif
		descriptor_ = INVALID_SOCKET;

		// Attempt auto reconnect?