Newer
Older
/*
* tcp_server_socket.cpp
*
* Created on: 02.01.2021
* Author: doralitze
*/
#include "net/tcp_server_socket.hpp"
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
namespace rmrf::net {
tcp_server_socket::tcp_server_socket(uint16_t port, incoming_client_listener_type client_listener_) :
ss{nullptr}, client_listener(client_listener_), number_of_connected_clients(0) {
auto raw_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if(raw_socket_fd < 0) {
// TODO implement propper error handling
throw netio_exception("Failed to create socket fd.");
}
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY; // TODO FIXME
if (bind(raw_socket_fd, (struct sockaddr *) &addr, sizeof(addr)) != 0) {
std::string msg = "Failed to bind to all addresses (FIXME)";
if (port < 1024) {
msg += "\tYou tried to bind to a port smaller than 1024. Are you root?";
}
throw netio_exception(msg);
// Append the non blocking flag to the file state of the socket fd.
// This might be linux only. We should check that
fcntl(raw_socket_fd, F_SETFL, fcntl(raw_socket_fd, F_GETFL, 0) | O_NONBLOCK);
if (listen(raw_socket_fd, 5) == -1) {
throw netio_exception("Failed to enable listening mode for raw socket");
}
this->ss = std::make_shared<async_server_socket>(auto_fd(raw_socket_fd));
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
using namespace std::placeholders;
this->ss->set_accept_handler(std::bind(&tcp_server_socket::await_raw_socket_incomming, this, _1, _2));
}
// As we're not depending on the actual async server object we need to suppress the warning that we're not using it.
#ifdef __GNUC__
#define UNUSED __attribute__ ((unused))
#else
#define UNUSED
#endif
void tcp_server_socket::await_raw_socket_incomming(async_server_socket::self_ptr_type ass UNUSED, const auto_fd& socket) {
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
int client_fd_raw = accept(socket.get(), (struct sockaddr *)&client_addr, &client_len);
if(client_fd_raw < 0) {
throw netio_exception("Unable to bind incoming client");
}
fcntl(client_fd_raw, F_SETFL, fcntl(client_fd_raw, F_GETFL, 0) | O_NONBLOCK);
const std::string address = inet_ntoa(client_addr.sin_addr);
const uint16_t port = ntohs(client_addr.sin_port);
// Generate client object from fd and announce it
this->number_of_connected_clients++;
using namespace std::placeholders;
this->client_listener(tcp_client(std::bind(&tcp_server_socket::client_destructed_cb, this, _1), auto_fd(client_fd_raw), address, port));
}
int tcp_server_socket::get_number_of_connected_clients() {
return this->number_of_connected_clients;
}
void tcp_server_socket::client_destructed_cb(tcp_client::exit_status exit_status UNUSED) {
this->number_of_connected_clients--;