File indexing completed on 2024-05-05 17:50:10

0001 /*
0002    Copyright (C) 2013 Andreas Hartmetz <ahartmetz@gmail.com>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LGPL.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017    Boston, MA 02110-1301, USA.
0018 
0019    Alternatively, this file is available under the Mozilla Public License
0020    Version 1.1.  You may obtain a copy of the License at
0021    http://www.mozilla.org/MPL/
0022 */
0023 
0024 #include "itransport.h"
0025 
0026 #include "eventdispatcher.h"
0027 #include "eventdispatcher_p.h"
0028 #include "itransportlistener.h"
0029 #include "ipsocket.h"
0030 #include "connectaddress.h"
0031 
0032 #ifdef __unix__
0033 #include "localsocket.h"
0034 #endif
0035 
0036 #include <algorithm>
0037 #include <cassert>
0038 
0039 ITransport::ITransport()
0040 {
0041 }
0042 
0043 ITransport::~ITransport()
0044 {
0045     setReadListener(nullptr);
0046     setWriteListener(nullptr);
0047 }
0048 
0049 IO::Result ITransport::readWithFileDescriptors(byte *buffer, uint32 maxSize, std::vector<int> *)
0050 {
0051     // This may be OK - if the other side tried to send file descriptors we will later notice
0052     // the difference between the message header declaring a nonzero FD count and the actual
0053     // received FD count which will always be zero if we get here. IF the other side didn't try
0054     // to send FDs, there is no problem.
0055     return read(buffer, maxSize);
0056 }
0057 
0058 IO::Result ITransport::writeWithFileDescriptors(chunk, const std::vector<int> &)
0059 {
0060     // Just don't call this on a transport that doesn't support passing file descriptors
0061     IO::Result res;
0062     res.status = IO::Status::LocalClosed;
0063     return res;
0064 }
0065 
0066 void ITransport::setReadListener(ITransportListener *listener)
0067 {
0068     if (m_readListener != listener) {
0069         if (m_readListener) {
0070             m_readListener->m_readTransport = nullptr;
0071         }
0072         if (listener) {
0073             if (listener->m_readTransport) {
0074                 listener->m_readTransport->setReadListener(nullptr);
0075             }
0076             assert(!listener->m_readTransport);
0077             listener->m_readTransport = this;
0078         }
0079         m_readListener = listener;
0080     }
0081     updateTransportIoInterest();
0082 }
0083 
0084 void ITransport::setWriteListener(ITransportListener *listener)
0085 {
0086     if (m_writeListener != listener) {
0087         if (m_writeListener) {
0088             m_writeListener->m_writeTransport = nullptr;
0089         }
0090         if (listener) {
0091             if (listener->m_writeTransport) {
0092                 listener->m_writeTransport->setWriteListener(nullptr);
0093             }
0094             assert(!listener->m_writeTransport);
0095             listener->m_writeTransport = this;
0096         }
0097         m_writeListener = listener;
0098     }
0099     updateTransportIoInterest();
0100 }
0101 
0102 void ITransport::updateTransportIoInterest()
0103 {
0104     setIoInterest((m_readListener ? uint32(IO::RW::Read) : 0) |
0105                   (m_writeListener ? uint32(IO::RW::Write) : 0));
0106 }
0107 
0108 void ITransport::close()
0109 {
0110     if (!isOpen()) {
0111         return;
0112     }
0113     if (ioEventSource()) {
0114         ioEventSource()->removeIoListener(this);
0115     }
0116     platformClose();
0117 }
0118 
0119 IO::Status ITransport::handleIoReady(IO::RW rw)
0120 {
0121     IO::Status ret = IO::Status::OK;
0122     assert(uint32(rw) & ioInterest()); // only get notified about events we requested
0123     if (rw == IO::RW::Read && m_readListener) {
0124         ret = m_readListener->handleTransportCanRead();
0125     } else if (rw == IO::RW::Write && m_writeListener) {
0126         ret = m_writeListener->handleTransportCanWrite();
0127     } else {
0128         assert(false);
0129     }
0130     if (ret != IO::Status::OK) {
0131         // TODO call some common close, cleanup & report error method
0132     }
0133     return ret;
0134 }
0135 
0136 //static
0137 ITransport *ITransport::create(const ConnectAddress &ci)
0138 {
0139     switch (ci.type()) {
0140 #ifdef __unix__
0141         case ConnectAddress::Type::UnixPath:
0142         return new LocalSocket(ci.path());
0143     case ConnectAddress::Type::AbstractUnixPath: // TODO this is Linux only, reflect it in code
0144         return new LocalSocket(std::string(1, '\0') + ci.path());
0145 #endif
0146     case ConnectAddress::Type::Tcp:
0147     case ConnectAddress::Type::Tcp4:
0148     case ConnectAddress::Type::Tcp6:
0149         return new IpSocket(ci);
0150     default:
0151         assert(false);
0152         return nullptr;
0153     }
0154 }