upnp_context.h 4.24 KB
Newer Older
Stepan Salenikovich's avatar
Stepan Salenikovich committed
1
/*
Sébastien Blin's avatar
Sébastien Blin committed
2
 *  Copyright (C) 2004-2019 Savoir-faire Linux Inc.
Guillaume Roguez's avatar
Guillaume Roguez committed
3
 *
Stepan Salenikovich's avatar
Stepan Salenikovich committed
4
 *  Author: Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>
5
 *  Author: Eden Abitbol <eden.abitbol@savoirfairelinux.com>
Stepan Salenikovich's avatar
Stepan Salenikovich committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA.
 */

Adrien Béraud's avatar
Adrien Béraud committed
22
#pragma once
Stepan Salenikovich's avatar
Stepan Salenikovich committed
23 24 25 26 27

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

28
#include "protocol/upnp_protocol.h"
Adrien Béraud's avatar
Adrien Béraud committed
29
#if HAVE_LIBNATPMP
30
#include "protocol/natpmp/nat_pmp.h"
Adrien Béraud's avatar
Adrien Béraud committed
31
#endif
32 33 34 35 36
#if HAVE_LIBUPNP
#include "protocol/pupnp/pupnp.h"
#endif
#include "protocol/igd.h"
#include "protocol/global_mapping.h"
Adrien Béraud's avatar
Adrien Béraud committed
37

38 39
#include "logger.h"
#include "ip_utils.h"
Stepan Salenikovich's avatar
Stepan Salenikovich committed
40
#include "noncopyable.h"
41 42

#include <opendht/rng.h>
Stepan Salenikovich's avatar
Stepan Salenikovich committed
43

Adrien Béraud's avatar
Adrien Béraud committed
44 45
#include <set>
#include <map>
46
#include <list>
Adrien Béraud's avatar
Adrien Béraud committed
47 48
#include <mutex>
#include <memory>
49
#include <string>
Adrien Béraud's avatar
Adrien Béraud committed
50
#include <chrono>
51
#include <random>
Adrien Béraud's avatar
Adrien Béraud committed
52 53
#include <atomic>
#include <thread>
54 55 56 57 58 59 60
#include <vector>
#include <condition_variable>
#include <cstdlib>

using random_device = dht::crypto::random_device;

using IgdFoundCallback = std::function<void()>;
Adrien Béraud's avatar
Adrien Béraud committed
61

Adrien Béraud's avatar
Adrien Béraud committed
62
namespace jami {
Stepan Salenikovich's avatar
Stepan Salenikovich committed
63 64 65
class IpAddr;
}

Adrien Béraud's avatar
Adrien Béraud committed
66
namespace jami { namespace upnp {
Stepan Salenikovich's avatar
Stepan Salenikovich committed
67

68 69
class UPnPContext
{
Stepan Salenikovich's avatar
Stepan Salenikovich committed
70 71 72 73
public:
    UPnPContext();
    ~UPnPContext();

74 75
    // Check if there is a valid IGD in the IGD list.
    bool hasValidIGD();
Stepan Salenikovich's avatar
Stepan Salenikovich committed
76

77 78 79 80
    // Add IGD listener.
    size_t addIGDListener(IgdFoundCallback&& cb);

    // Remove IGD listener.
81 82
    void removeIGDListener(size_t token);

83 84 85 86
    // Tries to add a valid mapping. Will return it if successful.
    Mapping addMapping(uint16_t port_desired, uint16_t port_local, PortType type, bool unique);

    // Removes a mapping.
Stepan Salenikovich's avatar
Stepan Salenikovich committed
87 88
    void removeMapping(const Mapping& mapping);

89
    // Get external Ip of a chosen IGD.
Éloi Bail's avatar
Éloi Bail committed
90 91
    IpAddr getExternalIP() const;

92
    // Get our local Ip.
Éloi Bail's avatar
Éloi Bail committed
93
    IpAddr getLocalIP() const;
Stepan Salenikovich's avatar
Stepan Salenikovich committed
94

95
    // Inform the UPnP context that the network status has changed. This clears the list of known
96 97
    void connectivityChanged();

98 99 100 101 102 103 104 105 106 107
private:
    // Checks if the IGD is in the list by checking the IGD's public Ip.
    bool isIgdInList(const IpAddr& publicIpAddr);

    // Returns the protocol of the IGD.
    UPnPProtocol::Type getIgdProtocol(IGD* igd);

    // Returns a random port that is not yet used by the daemon for UPnP.
    uint16_t chooseRandomPort(const IGD& igd, PortType type);

108 109
    // Tries to add or remove IGD to the list via callback.
    bool igdListChanged(UPnPProtocol* protocol, IGD* igd, const IpAddr publicIpAddr, bool added);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
110

111 112
    // Tries to add IGD to the list by getting it's public Ip address internally.
    bool addIgdToList(UPnPProtocol* protocol, IGD* igd);
113

114 115
    // Removes IGD from list by specifiying the IGD itself.
    bool removeIgdFromList(IGD* igd);
116

117 118
    // Removes IGD from list by specifiying the IGD's public Ip address.
    bool removeIgdFromList(IpAddr publicIpAddr);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
119

120 121
    // Tries to add mapping. Assumes mutex is already locked.
    Mapping addMapping(IGD* igd, uint16_t port_external, uint16_t port_internal, PortType type, UPnPProtocol::UpnpError& upnp_error);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
122

123 124
public:
    constexpr static unsigned MAX_RETRIES = 20;
Stepan Salenikovich's avatar
Stepan Salenikovich committed
125

126 127
private:
    NON_COPYABLE(UPnPContext);
Stepan Salenikovich's avatar
Stepan Salenikovich committed
128

129 130
    std::map<size_t, IgdFoundCallback> igdListeners_;           // Map of valid IGD listeners with their tokens.
    size_t listenerToken_{ 0 };                                 // Last provided token for valid IGD listeners (0 is the invalid token).
Stepan Salenikovich's avatar
Stepan Salenikovich committed
131

132 133 134
    std::vector<std::unique_ptr<UPnPProtocol>> protocolList_;	// Vector of available protocols.
    std::list<std::pair<UPnPProtocol*, IGD*>> igdList_;			// List of IGDs with their corresponding public IPs.
    mutable std::mutex igdListMutex_;							// Mutex used to access these lists and IGDs in a thread-safe manner.
Stepan Salenikovich's avatar
Stepan Salenikovich committed
135 136 137 138 139

};

std::shared_ptr<UPnPContext> getUPnPContext();

Adrien Béraud's avatar
Adrien Béraud committed
140
}} // namespace jami::upnp