diff options
author | Matthias P. Braendli <matthias.braendli@mpb.li> | 2017-09-27 14:24:49 +0200 |
---|---|---|
committer | Matthias P. Braendli <matthias.braendli@mpb.li> | 2017-09-28 13:43:03 +0200 |
commit | 7593596f6b21483d5af0a55715065fa2b44c1019 (patch) | |
tree | f68b99f909761390249db10a41e940183838564a /src/Socket.h | |
parent | 0cfca99b6f0a9b03f148e30c7c44e1f32b82baa1 (diff) | |
download | dabmod-7593596f6b21483d5af0a55715065fa2b44c1019.tar.gz dabmod-7593596f6b21483d5af0a55715065fa2b44c1019.tar.bz2 dabmod-7593596f6b21483d5af0a55715065fa2b44c1019.zip |
Add TCP Socket listener abstraction and use for UHD Feedback
Diffstat (limited to 'src/Socket.h')
-rw-r--r-- | src/Socket.h | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/Socket.h b/src/Socket.h new file mode 100644 index 0000000..1d9c252 --- /dev/null +++ b/src/Socket.h @@ -0,0 +1,164 @@ +/* + Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Her Majesty the + Queen in Right of Canada (Communications Research Center Canada) + + Copyright (C) 2017 + Matthias P. Braendli, matthias.braendli@mpb.li + + http://opendigitalradio.org + +DESCRIPTION: + Abstraction for sockets. +*/ + +/* + This file is part of ODR-DabMod. + + ODR-DabMod is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + ODR-DabMod is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with ODR-DabMod. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <unistd.h> +#include <cstdint> +#include <stdexcept> +#include <sys/socket.h> +#include <netinet/ip.h> +#include <errno.h> +#include <poll.h> + +class TCPSocket { + public: + TCPSocket() { + if ((m_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) { + throw std::runtime_error("Can't create TCP socket"); + } + } + + ~TCPSocket() { + if (m_sock != -1) { + ::close(m_sock); + } + } + + TCPSocket(const TCPSocket& other) = delete; + TCPSocket& operator=(const TCPSocket& other) = delete; + TCPSocket(TCPSocket&& other) { + m_sock = other.m_sock; + + if (other.m_sock != -1) { + other.m_sock = -1; + } + } + + TCPSocket& operator=(TCPSocket&& other) + { + m_sock = other.m_sock; + + if (other.m_sock != -1) { + other.m_sock = -1; + } + + return *this; + } + + bool valid(void) const { + return m_sock != -1; + } + + void listen(int port) { + struct sockaddr_in addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = htonl(INADDR_ANY); + + const int reuse = 1; + if (setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) { + throw std::runtime_error("Can't reuse address for TCP socket"); + } + + if (bind(m_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { + close(); + throw std::runtime_error("Can't bind TCP socket"); + } + + if (::listen(m_sock, 1) < 0) { + close(); + m_sock = -1; + throw std::runtime_error("Can't listen TCP socket"); + } + + } + + void close(void) { + ::close(m_sock); + m_sock = -1; + } + + TCPSocket accept_with_timeout(int timeout_ms, struct sockaddr_in *client) + { + struct pollfd fds[1]; + fds[0].fd = m_sock; + fds[0].events = POLLIN | POLLOUT; + + int retval = poll(fds, 1, timeout_ms); + + if (retval == -1) { + throw std::runtime_error("TCP Socket accept error: " + std::to_string(errno)); + } + else if (retval) { + socklen_t client_len = sizeof(struct sockaddr_in); + int sockfd = accept(m_sock, (struct sockaddr*)&client, &client_len); + TCPSocket s(sockfd); + return s; + } + else { + TCPSocket s(-1); + return s; + } + } + + ssize_t sendall(const void *buffer, size_t buflen) + { + uint8_t *buf = (uint8_t*)buffer; + while (buflen > 0) { + ssize_t sent = send(m_sock, buf, buflen, 0); + if (sent < 0) { + return -1; + } + else { + buf += sent; + buflen -= sent; + } + } + return buflen; + } + + ssize_t recv(void *buffer, size_t length, int flags) + { + return ::recv(m_sock, buffer, length, flags); + } + + private: + explicit TCPSocket(int sockfd) { + m_sock = sockfd; + } + + int m_sock = -1; +}; + |