File indexing completed on 2024-04-28 16:59:42

0001 /*
0002    Copyright (C) 2017 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 "server.h"
0025 
0026 #include "connectaddress.h"
0027 #include "connection.h"
0028 #include "eventdispatcher_p.h"
0029 #include "icompletionlistener.h"
0030 #include "iioeventforwarder.h"
0031 #include "inewconnectionlistener.h"
0032 #include "iserver.h"
0033 #include "itransport.h"
0034 
0035 #include <cassert>
0036 
0037 class ServerPrivate : public IIoEventForwarder, public ICompletionListener
0038 {
0039 public:
0040     ServerPrivate(EventDispatcher *dispatcher);
0041 
0042     // IIOEventForwarder
0043     IO::Status handleIoReady(IO::RW rw) override;
0044 
0045     // ICompletionListener
0046     void handleCompletion(void *transportServer) override;
0047 
0048     ConnectAddress listenAddress;
0049     ConnectAddress concreteAddress;
0050     EventDispatcher *eventDispatcher;
0051     Server *server;
0052     INewConnectionListener *newConnectionListener;
0053     IServer *transportServer;
0054 };
0055 
0056 ServerPrivate::ServerPrivate(EventDispatcher *dispatcher)
0057    : IIoEventForwarder(EventDispatcherPrivate::get(dispatcher)),
0058      eventDispatcher(dispatcher)
0059 {
0060 }
0061 
0062 IO::Status ServerPrivate::handleIoReady(IO::RW rw)
0063 {
0064     const IO::Status ret = transportServer->handleIoReady(rw);
0065     // ### error handling? But there is no possible permanent error with an already listening socket.
0066     return ret;
0067 }
0068 
0069 void ServerPrivate::handleCompletion(void *task)
0070 {
0071     assert(task == transportServer);
0072     (void) task;
0073     if (newConnectionListener) {
0074         newConnectionListener->handleNewConnection(server);
0075     }
0076 }
0077 
0078 Server::Server(EventDispatcher *dispatcher, const ConnectAddress &listenAddress)
0079    : d(new ServerPrivate(dispatcher))
0080 {
0081 #if 0
0082     if (ca.bus() == ConnectAddress::Bus::None || ca.socketType() == ConnectAddress::AddressType::None ||
0083         ca.role() == ConnectAddress::Role::None ||
0084         (ca.role() != ConnectAddress::Role::Server && ca.isServerOnly())) {
0085         cerr << "\nConnection: connection constructor Exit A\n\n";
0086         return;
0087     }
0088 #endif
0089     d->listenAddress = listenAddress;
0090     d->server = this;
0091     d->newConnectionListener = nullptr;
0092     d->transportServer = IServer::create(listenAddress, &d->concreteAddress);
0093     if (d->transportServer && d->transportServer->isListening()) {
0094         d->addIoListener(d->transportServer);
0095         d->transportServer->setNewConnectionListener(d);
0096     } else {
0097         delete d->transportServer;
0098         d->transportServer = nullptr;
0099     }
0100 
0101 }
0102 
0103 Server::~Server()
0104 {
0105     delete d->transportServer;
0106 
0107     delete d;
0108     d = nullptr;
0109 }
0110 
0111 void Server::setNewConnectionListener(INewConnectionListener *listener)
0112 {
0113     d->newConnectionListener = listener;
0114 }
0115 
0116 INewConnectionListener *Server::newConnectionListener() const
0117 {
0118     return d->newConnectionListener;
0119 }
0120 
0121 Connection *Server::takeNextClient()
0122 {
0123     // TODO proper error handling / propagation
0124     if (!d->transportServer) {
0125         return nullptr;
0126     }
0127     ITransport *newTransport = d->transportServer->takeNextClient();
0128     if (!newTransport) {
0129         return nullptr;
0130     }
0131 
0132     return new Connection(newTransport, d->eventDispatcher, d->concreteAddress);
0133 }
0134 
0135 bool Server::isListening() const
0136 {
0137     return d->transportServer ? d->transportServer->isListening() : false;
0138 }
0139 
0140 ConnectAddress Server::listenAddress() const
0141 {
0142     return d->listenAddress;
0143 }
0144 
0145 ConnectAddress Server::concreteAddress() const
0146 {
0147     return d->concreteAddress;
0148 }