"Fossies" - the Fresh Open Source Software Archive

Member "netxms-3.8.166/src/libnetxms/cch.cpp" (23 Feb 2021, 4556 Bytes) of package /linux/misc/netxms-3.8.166.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "cch.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.8.120_vs_3.8.166.

    1 /*
    2 ** NetXMS - Network Management System
    3 ** NetXMS Foundation Library
    4 ** Copyright (C) 2003-2021 Victor Kirhenshtein
    5 **
    6 ** This program is free software; you can redistribute it and/or modify
    7 ** it under the terms of the GNU Lesser General Public License as published
    8 ** by the Free Software Foundation; either version 3 of the License, or
    9 ** (at your option) any later version.
   10 **
   11 ** This program is distributed in the hope that it will be useful,
   12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14 ** GNU General Public License for more details.
   15 **
   16 ** You should have received a copy of the GNU Lesser General Public License
   17 ** along with this program; if not, write to the Free Software
   18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   19 **
   20 ** File: cch.cpp
   21 **
   22 **/
   23 
   24 #include "libnetxms.h"
   25 
   26 /**
   27  * Abstract communication channel constructor
   28  */
   29 AbstractCommChannel::AbstractCommChannel()
   30 {
   31 }
   32 
   33 /**
   34  * Abstract communication channel destructor
   35  */
   36 AbstractCommChannel::~AbstractCommChannel()
   37 {
   38 }
   39 
   40 /**
   41  * Socket communication channel constructor
   42  */
   43 SocketCommChannel::SocketCommChannel(SOCKET socket, BackgroundSocketPollerHandle *socketPoller, Ownership owner) : AbstractCommChannel()
   44 {
   45    m_socket = socket;
   46    m_owner = (owner == Ownership::True);
   47 #ifndef _WIN32
   48    if (pipe(m_controlPipe) != 0)
   49    {
   50       m_controlPipe[0] = -1;
   51       m_controlPipe[1] = -1;
   52    }
   53 #endif
   54    m_socketPoller = socketPoller;
   55 }
   56 
   57 /**
   58  * Socket communication channel destructor
   59  */
   60 SocketCommChannel::~SocketCommChannel()
   61 {
   62    if (m_owner && (m_socket != INVALID_SOCKET))
   63       closesocket(m_socket);
   64 #ifndef _WIN32
   65    if (m_controlPipe[0] != -1)
   66       _close(m_controlPipe[0]);
   67    if (m_controlPipe[1] != -1)
   68       _close(m_controlPipe[1]);
   69 #endif
   70    if (m_socketPoller != nullptr)
   71       InterlockedDecrement(&m_socketPoller->usageCount);
   72 }
   73 
   74 /**
   75  * Send data
   76  */
   77 ssize_t SocketCommChannel::send(const void *data, size_t size, MUTEX mutex)
   78 {
   79    return SendEx(m_socket, data, size, 0, mutex);
   80 }
   81 
   82 /**
   83  * Receive data
   84  */
   85 ssize_t SocketCommChannel::recv(void *buffer, size_t size, UINT32 timeout)
   86 {
   87    if (timeout == 0)
   88    {
   89 #ifdef _WIN32
   90       int rc = ::recv(m_socket, reinterpret_cast<char*>(buffer), static_cast<int>(size), 0);
   91 #else
   92       int rc = ::recv(m_socket, reinterpret_cast<char*>(buffer), size, 0);
   93 #endif
   94       if (rc >= 0)
   95          return rc;
   96       return ((WSAGetLastError() == WSAEWOULDBLOCK) || (WSAGetLastError() == WSAEINPROGRESS)) ? -4 : -1;
   97    }
   98 #ifdef _WIN32
   99    return RecvEx(m_socket, buffer, size, 0, timeout);
  100 #else
  101    return RecvEx(m_socket, buffer, size, 0, timeout, m_controlPipe[0]);
  102 #endif
  103 }
  104 
  105 /**
  106  * Poll channel
  107  */
  108 int SocketCommChannel::poll(UINT32 timeout, bool write)
  109 {
  110    if (m_socket == INVALID_SOCKET)
  111       return -1;
  112 
  113    SocketPoller sp(write);
  114    sp.add(m_socket);
  115    return sp.poll(timeout);
  116 }
  117 
  118 /**
  119  * Shutdown channel
  120  */
  121 int SocketCommChannel::shutdown()
  122 {
  123 #ifndef _WIN32
  124    // Cause select/poll to wake up
  125    if (m_controlPipe[1] != -1)
  126       _write(m_controlPipe[1], "X", 1);
  127 #endif
  128    return (m_socket != INVALID_SOCKET) ? ::shutdown(m_socket, SHUT_RDWR) : -1;
  129 }
  130 
  131 /**
  132  * Close channel
  133  */
  134 void SocketCommChannel::close()
  135 {
  136    if (m_socket != INVALID_SOCKET)
  137    {
  138       if (m_socketPoller != nullptr)
  139          m_socketPoller->poller.cancel(m_socket);
  140       closesocket(m_socket);
  141       m_socket = INVALID_SOCKET;
  142    }
  143 }
  144 
  145 /**
  146  * Wrapper context for background socket poll
  147  */
  148 struct BackgroundPollContext
  149 {
  150    SocketCommChannel *channel;
  151    void (*callback)(BackgroundSocketPollResult, AbstractCommChannel*, void*);
  152    void *context;
  153 };
  154 
  155 /**
  156  * Wrapper callback for background socket poll
  157  */
  158 static void BackgroundPollWrapper(BackgroundSocketPollResult pollResult, SOCKET hSocket, BackgroundPollContext *context)
  159 {
  160    context->callback(pollResult, context->channel, context->context);
  161    MemFree(context);
  162 }
  163 
  164 /**
  165  * Start background poll
  166  */
  167 void SocketCommChannel::backgroundPoll(uint32_t timeout, void (*callback)(BackgroundSocketPollResult, AbstractCommChannel*, void*), void *context)
  168 {
  169    if ((m_socketPoller != nullptr) && (m_socket != INVALID_SOCKET))
  170    {
  171       auto wrapperContext = MemAllocStruct<BackgroundPollContext>();
  172       wrapperContext->channel = this;
  173       wrapperContext->callback = callback;
  174       wrapperContext->context = context;
  175       m_socketPoller->poller.poll(m_socket, timeout, BackgroundPollWrapper, wrapperContext);
  176    }
  177    else
  178    {
  179       callback(BackgroundSocketPollResult::FAILURE, this, context);
  180    }
  181 }