Branch data Line data Source code
1 : : /* 2 : : ** Copyright (C) 2023 Sylvain Fargier 3 : : ** 4 : : ** This software is provided 'as-is', without any express or implied 5 : : ** warranty. In no event will the authors be held liable for any damages 6 : : ** arising from the use of this software. 7 : : ** 8 : : ** Permission is granted to anyone to use this software for any purpose, 9 : : ** including commercial applications, and to alter it and redistribute it 10 : : ** freely, subject to the following restrictions: 11 : : ** 12 : : ** 1. The origin of this software must not be misrepresented; you must not 13 : : ** claim that you wrote the original software. If you use this software 14 : : ** in a product, an acknowledgment in the product documentation would be 15 : : ** appreciated but is not required. 16 : : ** 2. Altered source versions must be plainly marked as such, and must not be 17 : : ** misrepresented as being the original software. 18 : : ** 3. This notice may not be removed or altered from any source distribution. 19 : : ** 20 : : ** Created on: 2023-12-16T12:06:12 21 : : ** Author: Sylvain Fargier <fargier.sylvain@gmail.com> 22 : : */ 23 : : 24 : : #ifndef IPSOCKET_HXX__ 25 : : #define IPSOCKET_HXX__ 26 : : 27 : : #include <logger/Logger.hpp> 28 : : #include <poll.h> 29 : : #include <unistd.h> 30 : : 31 : : #include "../Buffer.hpp" 32 : : #include "../Exception.hpp" 33 : : #include "Socket.hpp" 34 : : 35 : : namespace ccut { 36 : : namespace net { 37 : : 38 : : template<typename M> 39 : 15 : Socket<M>::Socket(const std::string &name) : BaseSocket(name) 40 : 15 : {} 41 : : 42 : : template<typename M> 43 : 15 : Socket<M>::~Socket() 44 : : { 45 : 15 : stop(); 46 : 15 : if (m_socket > 0) 47 : 8 : ::close(m_socket); 48 : 30 : } 49 : : 50 : : template<typename M> 51 : 6 : void Socket<M>::send(const Message &msg) 52 : : { 53 : 6 : if (m_socket < 0) 54 : : { 55 : 2 : if (msg.to.isValid() && msg.to.addr()->sa_family == AF_INET6) 56 : 1 : bind6(); 57 : : else 58 : 1 : bind(); 59 : : } 60 : : 61 : 6 : ssize_t sz = sendto(m_socket, msg.data.data(), msg.data.size(), 0, 62 : 6 : msg.to.addr(), msg.to.size()); 63 : 6 : if (sz < 0) 64 : : { 65 : 0 : ccut::Exception err = ccut::make_errno_exception(); 66 : 0 : logger::error("ccut:net:socket") << "failed to send: " << err.what(); 67 : 0 : throw err; 68 : 0 : } 69 : 6 : } 70 : : 71 : : template<typename M> 72 : 8 : void Socket<M>::thread_func() 73 : : { 74 : 8 : if (m_socket < 0) 75 : : { 76 : 1 : logger::notice("ccut:net:socket") << "Socket started but socket closed"; 77 : 2 : return; 78 : : } 79 : : 80 : 7 : address_t from{m_addr}; 81 : 7 : cow_ptr<buffer_t> buffer{make_cow<buffer_t>()}; 82 : : 83 : 24 : while (m_started.load() && m_socket > 0) 84 : : { 85 : 36 : struct pollfd pfds[2] = {{m_socket, POLLIN | POLLERR, 0}, 86 : 18 : {m_wakePipe.in(), POLLIN | POLLERR, 0}}; 87 : 18 : if (::poll(pfds, 2, -1) < 0) 88 : 0 : continue; 89 : : 90 : 18 : if (pfds[1].revents & POLLIN) 91 : 13 : m_wakePipe.flush(); 92 : : 93 : 18 : if (pfds[0].revents & (POLLNVAL | POLLERR) || 94 : 17 : pfds[1].revents & (POLLNVAL | POLLERR)) 95 : : { 96 : 1 : logger::error("ccut:net:socket") << "socket error, closing"; 97 : 1 : ::close(m_socket); 98 : 1 : m_socket = -1; /* will come back on next bind/open */ 99 : 1 : return; 100 : : } 101 : : 102 : 17 : if (pfds[0].revents & POLLIN) 103 : : { 104 : 6 : buffer->resize(m_bufferSize); 105 : 6 : from.detach(); 106 : : 107 : 6 : socklen_t slen = from.size(); 108 : 6 : ssize_t sz = recvfrom(m_socket, buffer->data(), buffer->size(), 0, 109 : 6 : const_cast<struct sockaddr *>(from.addr()), 110 : : &slen); 111 : 6 : if (sz < 0) 112 : : { 113 : 0 : ccut::Exception ex{ccut::make_errno_exception()}; 114 : : logger::error("ccut:net:socket") 115 : 0 : << "failed to receive message: " << ex.what(); 116 : 0 : } 117 : : else 118 : : { 119 : 6 : buffer->resize(sz); 120 : 6 : Message m{processMessage(from, m_addr, buffer)}; 121 : 6 : if (m.isValid()) 122 : 6 : message(m); 123 : 6 : } 124 : : } 125 : : } 126 : 8 : } 127 : : 128 : : template<typename M> 129 : 5 : typename Socket<M>::Message Socket<M>::processMessage( 130 : : const address_t &from, 131 : : const address_t &to, 132 : : const cow_ptr<buffer_t> &buffer) 133 : : { 134 : 5 : Message msg(from, to, buffer); 135 : 10 : logger::debug("ccut:net") << "message received " << from << " -> " << to 136 : 5 : << " size:" << (buffer ? buffer->size() : -1); 137 : 5 : return msg; 138 : 0 : } 139 : : 140 : : } // namespace net 141 : : } // namespace ccut 142 : : 143 : : #endif