LCOV - code coverage report
Current view: top level - src/net - Socket.hxx (source / functions) Hit Total Coverage
Test: lcov.info Lines: 52 61 85.2 %
Date: 2025-04-27 01:14:20 Functions: 18 30 60.0 %
Branches: 0 0 -

           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

Generated by: LCOV version 1.14