summaryrefslogtreecommitdiff
path: root/net/ServerSocket.hpp
blob: 557f7004e6efef1bb82b51101172f4cc4833c437 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#pragma once

#include "memory"

#include "Socket.hpp"
#include "Log.hpp"

#include <Poco/Net/SocketAddress.h>

class SocketFactory
{
public:
    virtual std::shared_ptr<Socket> create(const int fd) = 0;
};

/// A non-blocking, streaming socket.
class ServerSocket : public Socket
{
public:
    ServerSocket(Socket::Type type, SocketPoll& clientPoller, std::shared_ptr<SocketFactory> sockFactory) :
        Socket(type),
#if !MOBILEAPP
        _type(type),
#endif
        _clientPoller(clientPoller),
        _sockFactory(std::move(sockFactory))
    {
    }

    /// Control access to a bound TCP socket
    enum Type { Local, Public };

    /// Binds to a local address (Servers only).
    /// Does not retry on error.
    /// Returns true only on success.
    virtual bool bind(Type type, int port);

    /// Listen to incoming connections (Servers only).
    /// Does not retry on error.
    /// Returns true on success only.
    bool listen(const int backlog = 64)
    {
#if !MOBILEAPP
        const int rc = ::listen(getFD(), backlog);
#else
        const int rc = fakeSocketListen(getFD());
#endif
        if (rc)
            LOG_SYS("Failed to listen");
        return rc == 0;
    }

    /// Accepts an incoming connection (Servers only).
    /// Does not retry on error.
    /// Returns a valid Socket shared_ptr on success only.
    virtual std::shared_ptr<Socket> accept();

    int getPollEvents(std::chrono::steady_clock::time_point /* now */,
                      int64_t & /* timeoutMaxMicroS */) override
    {
        return POLLIN;
    }

    void dumpState(std::ostream& os) override;

    void handlePoll(SocketDisposition &,
                    std::chrono::steady_clock::time_point /* now */,
                    int events) override
    {
        if (events & POLLIN)
        {
            std::shared_ptr<Socket> clientSocket = accept();
            if (!clientSocket)
            {
                const std::string msg = "Failed to accept. (errno: ";
                throw std::runtime_error(msg + std::strerror(errno) + ')');
            }

            LOG_DBG("Accepted client #" << clientSocket->getFD());
            _clientPoller.insertNewSocket(clientSocket);
        }
    }

private:
#if !MOBILEAPP
    Socket::Type _type;
#endif
    SocketPoll& _clientPoller;
protected:
    std::shared_ptr<SocketFactory> _sockFactory;
};

#if !MOBILEAPP

/// A non-blocking, streaming Unix Domain Socket for local use
class LocalServerSocket : public ServerSocket
{
public:
    LocalServerSocket(SocketPoll& clientPoller, std::shared_ptr<SocketFactory> sockFactory) :
        ServerSocket(Socket::Type::Unix, clientPoller, std::move(sockFactory))
    {
    }
    virtual bool bind(Type, int) override { assert(false); return false; }
    virtual std::shared_ptr<Socket> accept() override;
    std::string bind();

private:
    std::string _name;
};

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */