|
|
|
@ -22,331 +22,478 @@
|
|
|
|
|
#include "srslte/common/network_utils.h"
|
|
|
|
|
|
|
|
|
|
#include <netinet/sctp.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
|
|
#define rxSockError(fmt, ...) log_h->error("%s: " fmt, name.c_str(), ##__VA_ARGS__)
|
|
|
|
|
#define rxSockWarn(fmt, ...) log_h->warning("%s: " fmt, name.c_str(), ##__VA_ARGS__)
|
|
|
|
|
#define rxSockInfo(fmt, ...) log_h->info("%s: " fmt, name.c_str(), ##__VA_ARGS__)
|
|
|
|
|
#define rxSockDebug(fmt, ...) log_h->debug("%s: " fmt, name.c_str(), ##__VA_ARGS__)
|
|
|
|
|
|
|
|
|
|
namespace srslte {
|
|
|
|
|
|
|
|
|
|
std::string net_addr_t::ip() const
|
|
|
|
|
namespace net_utils {
|
|
|
|
|
bool set_sockaddr(sockaddr_in* addr, const char* ip_str, int port)
|
|
|
|
|
{
|
|
|
|
|
char ip_str[128];
|
|
|
|
|
// TODO: check whether IP4 or IP6 based on provided input
|
|
|
|
|
addr->sin_family = AF_INET;
|
|
|
|
|
if (inet_pton(AF_INET, ip_str, &addr->sin_addr) != 1) {
|
|
|
|
|
perror("inet_pton");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
addr->sin_port = (port != 0) ? htons(port) : 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string get_ip(const sockaddr_in& addr)
|
|
|
|
|
{
|
|
|
|
|
char ip_str[128]; // TODO: check max size
|
|
|
|
|
inet_ntop(addr.sin_family, &addr.sin_addr, ip_str, sizeof(ip_str));
|
|
|
|
|
return std::string{ip_str};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool net_addr_t::set_ip(const char* ip_str)
|
|
|
|
|
int get_port(const sockaddr_in& addr)
|
|
|
|
|
{
|
|
|
|
|
addr.sin_family = AF_INET; // ip4 only for now
|
|
|
|
|
if (inet_pton(AF_INET, ip_str, &addr.sin_addr) != 1) {
|
|
|
|
|
perror("inet_pton");
|
|
|
|
|
return false;
|
|
|
|
|
return ntohs(addr.sin_port);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
net_utils::socket_type get_addr_family(int fd)
|
|
|
|
|
{
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
return net_utils::socket_type::none;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
int type;
|
|
|
|
|
socklen_t length = sizeof(int);
|
|
|
|
|
getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &length);
|
|
|
|
|
return (net_utils::socket_type)type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* protocol_to_string(protocol_type p)
|
|
|
|
|
{
|
|
|
|
|
switch (p) {
|
|
|
|
|
case protocol_type::TCP:
|
|
|
|
|
return "TCP";
|
|
|
|
|
case protocol_type::UDP:
|
|
|
|
|
return "UDP";
|
|
|
|
|
case protocol_type::SCTP:
|
|
|
|
|
return "SCTP";
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace net_utils
|
|
|
|
|
|
|
|
|
|
/********************************************
|
|
|
|
|
* Socket Classes
|
|
|
|
|
*******************************************/
|
|
|
|
|
|
|
|
|
|
base_socket_t::base_socket_t(base_socket_t&& other) noexcept
|
|
|
|
|
socket_handler_t::socket_handler_t(socket_handler_t&& other) noexcept
|
|
|
|
|
{
|
|
|
|
|
sockfd = other.sockfd;
|
|
|
|
|
memcpy(&addr_in, &other.addr_in, sizeof(addr_in));
|
|
|
|
|
sockfd = other.sockfd;
|
|
|
|
|
addr = other.addr;
|
|
|
|
|
other.sockfd = 0;
|
|
|
|
|
bzero(&other.addr_in, sizeof(other.addr_in));
|
|
|
|
|
other.addr = {};
|
|
|
|
|
}
|
|
|
|
|
base_socket_t::~base_socket_t()
|
|
|
|
|
socket_handler_t::~socket_handler_t()
|
|
|
|
|
{
|
|
|
|
|
if (sockfd >= 0) {
|
|
|
|
|
close(sockfd);
|
|
|
|
|
}
|
|
|
|
|
reset();
|
|
|
|
|
}
|
|
|
|
|
base_socket_t& base_socket_t::operator=(base_socket_t&& other) noexcept
|
|
|
|
|
socket_handler_t& socket_handler_t::operator=(socket_handler_t&& other) noexcept
|
|
|
|
|
{
|
|
|
|
|
if (this == &other) {
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
memcpy(&addr_in, &other.addr_in, sizeof(addr_in));
|
|
|
|
|
sockfd = other.sockfd;
|
|
|
|
|
bzero(&other.addr_in, sizeof(other.addr_in));
|
|
|
|
|
addr = other.addr;
|
|
|
|
|
sockfd = other.sockfd;
|
|
|
|
|
other.addr = {};
|
|
|
|
|
other.sockfd = 0;
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void base_socket_t::reset_()
|
|
|
|
|
void socket_handler_t::close()
|
|
|
|
|
{
|
|
|
|
|
if (sockfd >= 0) {
|
|
|
|
|
close(sockfd);
|
|
|
|
|
::close(sockfd);
|
|
|
|
|
sockfd = -1;
|
|
|
|
|
}
|
|
|
|
|
addr_in = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int base_socket_t::bind_addr(const char* bind_addr_str, int port)
|
|
|
|
|
void socket_handler_t::reset()
|
|
|
|
|
{
|
|
|
|
|
this->close();
|
|
|
|
|
addr = {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool socket_handler_t::bind_addr(const char* bind_addr_str, int port, srslte::log* log_)
|
|
|
|
|
{
|
|
|
|
|
if (sockfd < 0) {
|
|
|
|
|
if (create_socket() != 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->error("Trying to bind to a closed socket\n");
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
addr_in.sin_family = AF_INET;
|
|
|
|
|
addr_in.sin_port = (port != 0) ? htons(port) : 0;
|
|
|
|
|
if (inet_pton(AF_INET, bind_addr_str, &(addr_in.sin_addr)) != 1) {
|
|
|
|
|
perror("inet_pton");
|
|
|
|
|
return -1;
|
|
|
|
|
if (not net_utils::set_sockaddr(&addr, bind_addr_str, port)) {
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->error("Failed to convert IP address (%s) to sockaddr_in struct\n", bind_addr_str);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bind(sockfd, (struct sockaddr*)&addr_in, sizeof(addr_in)) != 0) {
|
|
|
|
|
perror("bind()");
|
|
|
|
|
return -1;
|
|
|
|
|
if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) != 0) {
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->error("Failed to bind on address %s: %s errno %d\n", bind_addr_str, strerror(errno), errno);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int base_socket_t::connect_to(struct sockaddr_in* dest_addr, const char* dest_addr_str, int dest_port)
|
|
|
|
|
bool socket_handler_t::connect_to(const char* dest_addr_str,
|
|
|
|
|
int dest_port,
|
|
|
|
|
sockaddr_in* dest_sockaddr,
|
|
|
|
|
srslte::log* log_)
|
|
|
|
|
{
|
|
|
|
|
dest_addr->sin_family = AF_INET;
|
|
|
|
|
dest_addr->sin_port = htons(dest_port);
|
|
|
|
|
if (inet_pton(AF_INET, dest_addr_str, &(dest_addr->sin_addr)) != 1) {
|
|
|
|
|
perror("inet_pton()");
|
|
|
|
|
return -1;
|
|
|
|
|
if (sockfd < 0) {
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->error("tried to connect to remote address with a closed socket.\n");
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (connect(sockfd, (struct sockaddr*)dest_addr, sizeof(*dest_addr)) == -1) {
|
|
|
|
|
perror("connect()");
|
|
|
|
|
return -1;
|
|
|
|
|
sockaddr_in sockaddr_tmp{};
|
|
|
|
|
sockaddr_in* sockaddr_ptr = (dest_sockaddr == nullptr) ? &sockaddr_tmp : dest_sockaddr;
|
|
|
|
|
*sockaddr_ptr = {};
|
|
|
|
|
if (not net_utils::set_sockaddr(sockaddr_ptr, dest_addr_str, dest_port)) {
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->error("Error converting IP address (%s) to sockaddr_in structure\n", dest_addr_str);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
if (connect(sockfd, (const struct sockaddr*)sockaddr_ptr, sizeof(*sockaddr_ptr)) == -1) {
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->error("Failed to establish socket connection to %s\n", dest_addr_str);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool socket_handler_t::open_socket(net_utils::addr_family ip_type,
|
|
|
|
|
net_utils::socket_type socket_type,
|
|
|
|
|
net_utils::protocol_type protocol,
|
|
|
|
|
srslte::log* log_)
|
|
|
|
|
{
|
|
|
|
|
if (sockfd >= 0) {
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->error("Socket is already open.\n");
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
sockfd = socket((int)ip_type, (int)socket_type, (int)protocol);
|
|
|
|
|
if (sockfd == -1) {
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->error("Failed to open %s socket.\n", net_utils::protocol_to_string(protocol));
|
|
|
|
|
}
|
|
|
|
|
perror("Could not create socket\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
* SCTP socket
|
|
|
|
|
**********************************************************************/
|
|
|
|
|
|
|
|
|
|
void sctp_socket_t::reset()
|
|
|
|
|
{
|
|
|
|
|
reset_();
|
|
|
|
|
dest_addr = {};
|
|
|
|
|
}
|
|
|
|
|
namespace net_utils {
|
|
|
|
|
|
|
|
|
|
int sctp_socket_t::listen_addr(const char* bind_addr_str, int port)
|
|
|
|
|
bool sctp_init_socket(socket_handler_t* socket,
|
|
|
|
|
net_utils::socket_type socktype,
|
|
|
|
|
const char* bind_addr_str,
|
|
|
|
|
int port,
|
|
|
|
|
srslte::log* log_)
|
|
|
|
|
{
|
|
|
|
|
if (sockfd < 0 and create_socket() != 0) {
|
|
|
|
|
reset();
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
if (not socket->open_socket(net_utils::addr_family::ipv4, socktype, net_utils::protocol_type::SCTP, log_)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sets the data_io_event to be able to use sendrecv_info
|
|
|
|
|
// Subscribes to the SCTP_SHUTDOWN event, to handle graceful shutdown
|
|
|
|
|
struct sctp_event_subscribe evnts = {};
|
|
|
|
|
evnts.sctp_data_io_event = 1;
|
|
|
|
|
evnts.sctp_shutdown_event = 1;
|
|
|
|
|
if (setsockopt(sockfd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts)) != 0) {
|
|
|
|
|
if (setsockopt(socket->fd(), IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts)) != 0) {
|
|
|
|
|
perror("setsockopt");
|
|
|
|
|
reset();
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// bind addr
|
|
|
|
|
if (bind_addr(bind_addr_str, port) != 0) {
|
|
|
|
|
reset();
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Listen for connections
|
|
|
|
|
if (listen(sockfd, SOMAXCONN) != 0) {
|
|
|
|
|
perror("listen");
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sctp_socket_t::connect_addr(const char* bind_addr_str, const char* dest_addr_str, int dest_port)
|
|
|
|
|
{
|
|
|
|
|
if (sockfd < 0 and bind_addr(bind_addr_str, 0) != 0) {
|
|
|
|
|
reset();
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
socket->reset();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (connect_to(&dest_addr, dest_addr_str, dest_port) != 0) {
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
if (not socket->bind_addr(bind_addr_str, port, log_)) {
|
|
|
|
|
socket->reset();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sctp_socket_t::read(void* buf, size_t nbytes, net_addr_t* addr) const
|
|
|
|
|
bool sctp_init_client(socket_handler_t* socket,
|
|
|
|
|
net_utils::socket_type socktype,
|
|
|
|
|
const char* bind_addr_str,
|
|
|
|
|
srslte::log* log_)
|
|
|
|
|
{
|
|
|
|
|
if (addr != nullptr) {
|
|
|
|
|
sockaddr_in* from = &addr->get_sockaddr_in();
|
|
|
|
|
socklen_t fromlen = sizeof(*from);
|
|
|
|
|
return read(buf, nbytes, from, &fromlen);
|
|
|
|
|
}
|
|
|
|
|
return read(buf, nbytes);
|
|
|
|
|
return sctp_init_socket(socket, socktype, bind_addr_str, 0, log_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sctp_socket_t::read(void* buf,
|
|
|
|
|
size_t nbytes,
|
|
|
|
|
struct sockaddr_in* from,
|
|
|
|
|
socklen_t* fromlen,
|
|
|
|
|
struct sctp_sndrcvinfo* sinfo,
|
|
|
|
|
int msg_flags) const
|
|
|
|
|
bool sctp_init_server(socket_handler_t* socket,
|
|
|
|
|
net_utils::socket_type socktype,
|
|
|
|
|
const char* bind_addr_str,
|
|
|
|
|
int port,
|
|
|
|
|
srslte::log* log_)
|
|
|
|
|
{
|
|
|
|
|
if (from != nullptr) {
|
|
|
|
|
*fromlen = sizeof(*from);
|
|
|
|
|
return sctp_recvmsg(sockfd, buf, nbytes, (struct sockaddr*)from, fromlen, sinfo, &msg_flags);
|
|
|
|
|
if (not sctp_init_socket(socket, socktype, bind_addr_str, port, log_)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return sctp_recvmsg(sockfd, buf, nbytes, nullptr, nullptr, sinfo, &msg_flags);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int sctp_socket_t::send(void* buf, size_t nbytes, uint32_t ppid, uint32_t stream_id) const
|
|
|
|
|
{
|
|
|
|
|
return sctp_sendmsg(
|
|
|
|
|
sockfd, buf, nbytes, (struct sockaddr*)&dest_addr, sizeof(dest_addr), htonl(ppid), 0, stream_id, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Private Methods
|
|
|
|
|
|
|
|
|
|
int sctp_socket_t::create_socket()
|
|
|
|
|
{
|
|
|
|
|
sockfd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
|
|
|
|
|
if (sockfd == -1) {
|
|
|
|
|
perror("Could not create SCTP socket\n");
|
|
|
|
|
return -1;
|
|
|
|
|
// Listen for connections
|
|
|
|
|
if (listen(socket->fd(), SOMAXCONN) != 0) {
|
|
|
|
|
log_->error("Failed to listen to incoming SCTP connections\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
|
* TCP Socket
|
|
|
|
|
**************************************************************/
|
|
|
|
|
|
|
|
|
|
void tcp_socket_t::reset()
|
|
|
|
|
bool tcp_make_server(socket_handler_t* socket,
|
|
|
|
|
const char* bind_addr_str,
|
|
|
|
|
int port,
|
|
|
|
|
int nof_connections,
|
|
|
|
|
srslte::log* log_)
|
|
|
|
|
{
|
|
|
|
|
reset_();
|
|
|
|
|
dest_addr = {};
|
|
|
|
|
if (connfd >= 0) {
|
|
|
|
|
connfd = -1;
|
|
|
|
|
if (not socket->open_socket(addr_family::ipv4, socket_type::stream, protocol_type::TCP, log_)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int tcp_socket_t::listen_addr(const char* bind_addr_str, int port)
|
|
|
|
|
{
|
|
|
|
|
if (sockfd < 0 and bind_addr(bind_addr_str, port) != 0) {
|
|
|
|
|
reset();
|
|
|
|
|
return -1;
|
|
|
|
|
if (not socket->bind_addr(bind_addr_str, port, log_)) {
|
|
|
|
|
socket->reset();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Listen for connections
|
|
|
|
|
if (listen(sockfd, 1) != 0) {
|
|
|
|
|
perror("listen");
|
|
|
|
|
return -1;
|
|
|
|
|
if (listen(socket->fd(), nof_connections) != 0) {
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->error("Failed to listen to incoming TCP connections\n");
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int tcp_socket_t::accept_connection()
|
|
|
|
|
int tcp_accept(socket_handler_t* socket, sockaddr_in* destaddr, srslte::log* log_)
|
|
|
|
|
{
|
|
|
|
|
socklen_t clilen = sizeof(dest_addr);
|
|
|
|
|
connfd = accept(sockfd, (struct sockaddr*)&dest_addr, &clilen);
|
|
|
|
|
socklen_t clilen = sizeof(destaddr);
|
|
|
|
|
int connfd = accept(socket->fd(), (struct sockaddr*)&destaddr, &clilen);
|
|
|
|
|
if (connfd < 0) {
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->error("Failed to accept connection\n");
|
|
|
|
|
}
|
|
|
|
|
perror("accept");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int tcp_socket_t::connect_addr(const char* bind_addr_str, const char* dest_addr_str, int dest_port)
|
|
|
|
|
{
|
|
|
|
|
if (sockfd < 0 and bind_addr(bind_addr_str, 0) != 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return connect_to(&dest_addr, dest_addr_str, dest_port);
|
|
|
|
|
return connfd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int tcp_socket_t::create_socket()
|
|
|
|
|
int tcp_read(int remotefd, void* buf, size_t nbytes, srslte::log* log_)
|
|
|
|
|
{
|
|
|
|
|
sockfd = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
|
if (sockfd == -1) {
|
|
|
|
|
perror("Could not create TCP socket\n");
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
}
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int tcp_socket_t::read(void* buf, size_t nbytes) const
|
|
|
|
|
{
|
|
|
|
|
int n = ::read(connfd, buf, nbytes);
|
|
|
|
|
int n = ::read(remotefd, buf, nbytes);
|
|
|
|
|
if (n == 0) {
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->info("TCP connection closed\n");
|
|
|
|
|
close(remotefd);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if (n == -1) {
|
|
|
|
|
perror("read");
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->error("Failed to read from TCP socket.");
|
|
|
|
|
} else {
|
|
|
|
|
perror("TCP read");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return n;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int tcp_socket_t::send(const void* buf, size_t nbytes) const
|
|
|
|
|
int tcp_send(int remotefd, const void* buf, size_t nbytes, srslte::log* log_)
|
|
|
|
|
{
|
|
|
|
|
// Loop until all bytes are sent
|
|
|
|
|
char* ptr = (char*)buf;
|
|
|
|
|
while (nbytes > 0) {
|
|
|
|
|
ssize_t i = ::send(connfd, ptr, nbytes, 0);
|
|
|
|
|
char* ptr = (char*)buf;
|
|
|
|
|
ssize_t nbytes_remaining = nbytes;
|
|
|
|
|
while (nbytes_remaining > 0) {
|
|
|
|
|
ssize_t i = ::send(remotefd, ptr, nbytes_remaining, 0);
|
|
|
|
|
if (i < 1) {
|
|
|
|
|
perror("Error calling send()\n");
|
|
|
|
|
return SRSLTE_ERROR;
|
|
|
|
|
if (log_ != nullptr) {
|
|
|
|
|
log_->error("Failed to send data to TCP socket\n");
|
|
|
|
|
} else {
|
|
|
|
|
perror("Error calling send()\n");
|
|
|
|
|
}
|
|
|
|
|
return i;
|
|
|
|
|
}
|
|
|
|
|
ptr += i;
|
|
|
|
|
nbytes -= i;
|
|
|
|
|
nbytes_remaining -= i;
|
|
|
|
|
}
|
|
|
|
|
return SRSLTE_SUCCESS;
|
|
|
|
|
return nbytes - nbytes_remaining;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace net_utils
|
|
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
|
* Rx Multisocket Task Types
|
|
|
|
|
**************************************************************/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Description: Specialization of recv_task for the case the received data is
|
|
|
|
|
* in the form of unique_byte_buffer, and a recv(...) call is used
|
|
|
|
|
*/
|
|
|
|
|
class recv_pdu_task final : public rx_multisocket_handler::recv_task
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
using callback_t = std::function<void(srslte::unique_byte_buffer_t pdu)>;
|
|
|
|
|
explicit recv_pdu_task(srslte::byte_buffer_pool* pool_, callback_t func_) : pool(pool_), func(std::move(func_)) {}
|
|
|
|
|
|
|
|
|
|
bool operator()(int fd) override
|
|
|
|
|
{
|
|
|
|
|
srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*pool, "Rxsocket", true);
|
|
|
|
|
// inside rx_sockets thread. Read socket
|
|
|
|
|
ssize_t n_recv = recv(fd, pdu->msg, pdu->get_tailroom(), 0);
|
|
|
|
|
if (n_recv > 0) {
|
|
|
|
|
pdu->N_bytes = static_cast<uint32_t>(n_recv);
|
|
|
|
|
}
|
|
|
|
|
func(std::move(pdu));
|
|
|
|
|
return n_recv != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
srslte::byte_buffer_pool* pool = nullptr;
|
|
|
|
|
callback_t func;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class sctp_recvmsg_pdu_task final : public rx_multisocket_handler::recv_task
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
using callback_t = std::function<
|
|
|
|
|
void(srslte::unique_byte_buffer_t pdu, const sockaddr_in& from, const sctp_sndrcvinfo& sri, int flags)>;
|
|
|
|
|
explicit sctp_recvmsg_pdu_task(srslte::byte_buffer_pool* pool_, srslte::log* log_, callback_t func_) :
|
|
|
|
|
pool(pool_),
|
|
|
|
|
log_h(log_),
|
|
|
|
|
func(std::move(func_))
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool operator()(int fd) override
|
|
|
|
|
{
|
|
|
|
|
// inside rx_sockets thread. Read socket
|
|
|
|
|
srslte::unique_byte_buffer_t pdu = srslte::allocate_unique_buffer(*pool, "Rxsocket", true);
|
|
|
|
|
sockaddr_in from = {};
|
|
|
|
|
socklen_t fromlen = sizeof(from);
|
|
|
|
|
sctp_sndrcvinfo sri = {};
|
|
|
|
|
int flags = 0;
|
|
|
|
|
ssize_t n_recv = sctp_recvmsg(fd, pdu->msg, pdu->get_tailroom(), (struct sockaddr*)&from, &fromlen, &sri, &flags);
|
|
|
|
|
if (n_recv == -1 and errno != EAGAIN) {
|
|
|
|
|
log_h->error("Error reading from SCTP socket: %s\n", strerror(errno));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (n_recv == -1 and errno == EAGAIN) {
|
|
|
|
|
log_h->debug("Socket timeout reached\n");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ret = true;
|
|
|
|
|
pdu->N_bytes = static_cast<uint32_t>(n_recv);
|
|
|
|
|
if (flags & MSG_NOTIFICATION) {
|
|
|
|
|
// Received notification
|
|
|
|
|
union sctp_notification* notification = (union sctp_notification*)pdu->msg;
|
|
|
|
|
if (notification->sn_header.sn_type == SCTP_SHUTDOWN_EVENT) {
|
|
|
|
|
// Socket Shutdown
|
|
|
|
|
ret = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
func(std::move(pdu), from, sri, flags);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
srslte::byte_buffer_pool* pool = nullptr;
|
|
|
|
|
srslte::log* log_h = nullptr;
|
|
|
|
|
callback_t func;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/***************************************************************
|
|
|
|
|
* Rx Multisocket Handler
|
|
|
|
|
**************************************************************/
|
|
|
|
|
|
|
|
|
|
rx_multisocket_handler::rx_multisocket_handler(std::string name_, srslte::log* log_) :
|
|
|
|
|
rx_multisocket_handler::rx_multisocket_handler(std::string name_, srslte::log* log_, int thread_prio) :
|
|
|
|
|
thread(name_),
|
|
|
|
|
name(std::move(name_)),
|
|
|
|
|
log_h(log_)
|
|
|
|
|
{
|
|
|
|
|
pool = srslte::byte_buffer_pool::get_instance();
|
|
|
|
|
// register control pipe fd
|
|
|
|
|
if (pipe(pipefd) == -1) {
|
|
|
|
|
rxSockInfo("Failed to open control pipe\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
start(THREAD_PRIO);
|
|
|
|
|
start(thread_prio);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rx_multisocket_handler::~rx_multisocket_handler()
|
|
|
|
|
{
|
|
|
|
|
stop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rx_multisocket_handler::stop()
|
|
|
|
|
{
|
|
|
|
|
if (running) {
|
|
|
|
|
std::lock_guard<std::mutex> lock(socket_mutex);
|
|
|
|
|
ctrl_cmd_t msg{};
|
|
|
|
|
msg.cmd = ctrl_cmd_t::cmd_id_t::EXIT;
|
|
|
|
|
rxSockDebug("Closing socket handler\n");
|
|
|
|
|
if (write(pipefd[1], &msg, sizeof(msg)) != sizeof(msg)) {
|
|
|
|
|
rxSockError("while writing to control pipe\n");
|
|
|
|
|
// close thread
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(socket_mutex);
|
|
|
|
|
ctrl_cmd_t msg{};
|
|
|
|
|
msg.cmd = ctrl_cmd_t::cmd_id_t::EXIT;
|
|
|
|
|
if (write(pipefd[1], &msg, sizeof(msg)) != sizeof(msg)) {
|
|
|
|
|
rxSockError("while writing to control pipe\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
rxSockDebug("Closing rx socket handler thread\n");
|
|
|
|
|
wait_thread_finish();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// close thread
|
|
|
|
|
wait_thread_finish();
|
|
|
|
|
if (pipefd[0] >= 0) {
|
|
|
|
|
close(pipefd[0]);
|
|
|
|
|
close(pipefd[1]);
|
|
|
|
|
pipefd[0] = -1;
|
|
|
|
|
pipefd[1] = -1;
|
|
|
|
|
rxSockDebug("closed.\n");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
close(pipefd[0]);
|
|
|
|
|
close(pipefd[1]);
|
|
|
|
|
/**
|
|
|
|
|
* Convenience method for read PDUs from socket
|
|
|
|
|
*/
|
|
|
|
|
bool rx_multisocket_handler::add_socket_pdu_handler(int fd, recv_callback_t pdu_task)
|
|
|
|
|
{
|
|
|
|
|
std::unique_ptr<srslte::rx_multisocket_handler::recv_task> task;
|
|
|
|
|
task.reset(new srslte::recv_pdu_task(pool, std::move(pdu_task)));
|
|
|
|
|
return add_socket_handler(fd, std::move(task));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rxSockDebug("closed.\n");
|
|
|
|
|
/**
|
|
|
|
|
* Convenience method for reading PDUs from SCTP socket
|
|
|
|
|
*/
|
|
|
|
|
bool rx_multisocket_handler::add_socket_sctp_handler(int fd, sctp_recv_callback_t pdu_task)
|
|
|
|
|
{
|
|
|
|
|
srslte::rx_multisocket_handler::task_callback_t task;
|
|
|
|
|
task.reset(new srslte::sctp_recvmsg_pdu_task(pool, log_h, std::move(pdu_task)));
|
|
|
|
|
return add_socket_handler(fd, std::move(task));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool rx_multisocket_handler::register_socket_(std::pair<const int, std::function<void()> >&& elem)
|
|
|
|
|
bool rx_multisocket_handler::add_socket_handler(int fd, task_callback_t handler)
|
|
|
|
|
{
|
|
|
|
|
int fd = elem.first;
|
|
|
|
|
std::lock_guard<std::mutex> lock(socket_mutex);
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
rxSockError("Provided SCTP socket must be already open\n");
|
|
|
|
@ -357,7 +504,7 @@ bool rx_multisocket_handler::register_socket_(std::pair<const int, std::function
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
active_sockets.insert(std::move(elem));
|
|
|
|
|
active_sockets.insert(std::pair<const int, task_callback_t>(fd, std::move(handler)));
|
|
|
|
|
|
|
|
|
|
// this unlocks the reading thread to add new connections
|
|
|
|
|
ctrl_cmd_t msg;
|
|
|
|
@ -365,12 +512,46 @@ bool rx_multisocket_handler::register_socket_(std::pair<const int, std::function
|
|
|
|
|
msg.new_fd = fd;
|
|
|
|
|
if (write(pipefd[1], &msg, sizeof(msg)) != sizeof(msg)) {
|
|
|
|
|
rxSockError("while writing to control pipe\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rxSockDebug("socket fd=%d has been registered.\n", fd);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool rx_multisocket_handler::remove_socket(int fd)
|
|
|
|
|
{
|
|
|
|
|
std::lock_guard<std::mutex> lock(socket_mutex);
|
|
|
|
|
auto it = active_sockets.find(fd);
|
|
|
|
|
if (it == active_sockets.end()) {
|
|
|
|
|
rxSockError("The socket fd=%d to be removed does not exist\n", fd);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctrl_cmd_t msg;
|
|
|
|
|
msg.cmd = ctrl_cmd_t::cmd_id_t::RM_FD;
|
|
|
|
|
msg.new_fd = fd;
|
|
|
|
|
if (write(pipefd[1], &msg, sizeof(msg)) != sizeof(msg)) {
|
|
|
|
|
rxSockError("while writing to control pipe\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool rx_multisocket_handler::remove_socket_unprotected(int fd, fd_set* total_fd_set, int* max_fd)
|
|
|
|
|
{
|
|
|
|
|
if (fd < 0) {
|
|
|
|
|
rxSockError("fd to be removed is not valid\n");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
active_sockets.erase(fd);
|
|
|
|
|
FD_CLR(fd, total_fd_set);
|
|
|
|
|
// assumes ordering
|
|
|
|
|
*max_fd = (active_sockets.empty()) ? pipefd[0] : std::max(pipefd[0], active_sockets.rbegin()->first);
|
|
|
|
|
rxSockDebug("Socket fd=%d has been successfully removed\n", fd);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rx_multisocket_handler::run_thread()
|
|
|
|
|
{
|
|
|
|
|
running = true;
|
|
|
|
@ -387,7 +568,7 @@ void rx_multisocket_handler::run_thread()
|
|
|
|
|
|
|
|
|
|
// handle select return
|
|
|
|
|
if (n == -1) {
|
|
|
|
|
rxSockError("Error from select()");
|
|
|
|
|
rxSockError("Error from select(%d,...). Number of rx sockets: %d", max_fd + 1, (int)active_sockets.size() + 1);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (n == 0) {
|
|
|
|
@ -395,6 +576,7 @@ void rx_multisocket_handler::run_thread()
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Shared state area
|
|
|
|
|
std::lock_guard<std::mutex> lock(socket_mutex);
|
|
|
|
|
|
|
|
|
|
// call read callback for all SCTP/TCP/UDP connections
|
|
|
|
@ -402,7 +584,11 @@ void rx_multisocket_handler::run_thread()
|
|
|
|
|
if (not FD_ISSET(handler_pair.first, &read_fd_set)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
handler_pair.second();
|
|
|
|
|
bool socket_valid = (*handler_pair.second)(handler_pair.first);
|
|
|
|
|
if (not socket_valid) {
|
|
|
|
|
rxSockWarn("The socket fd=%d has been closed by peer\n", handler_pair.first);
|
|
|
|
|
remove_socket_unprotected(handler_pair.first, &total_fd_set, &max_fd);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// handle ctrl messages
|
|
|
|
@ -425,6 +611,10 @@ void rx_multisocket_handler::run_thread()
|
|
|
|
|
rxSockError("added fd is not valid\n");
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case ctrl_cmd_t::cmd_id_t::RM_FD:
|
|
|
|
|
remove_socket_unprotected(msg.new_fd, &total_fd_set, &max_fd);
|
|
|
|
|
rxSockDebug("Socket fd=%d has been successfully removed\n", msg.new_fd);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
rxSockError("ctrl message command %d is not valid\n", (int)msg.cmd);
|
|
|
|
|
}
|
|
|
|
|