1 /*
2  * Copyright (C) 2001-2012 Jacek Sieka, arnetheduck on gmail point com
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #pragma once
20 
21 #include "TimerManager.h"
22 #include "UserConnection.h"
23 #include "User.h"
24 #include "CriticalSection.h"
25 #include "Singleton.h"
26 #include "Util.h"
27 #include "ConnectionManagerListener.h"
28 
29 namespace dcpp {
30 
31 class SocketException;
32 
33 class ConnectionQueueItem : boost::noncopyable {
34 public:
35     typedef ConnectionQueueItem* Ptr;
36     typedef vector<Ptr> List;
37     typedef List::iterator Iter;
38 
39     enum State {
40         CONNECTING,                 // Recently sent request to connect
41         WAITING,                    // Waiting to send request to connect
42         NO_DOWNLOAD_SLOTS,          // Not needed right now
43         ACTIVE                      // In one up/downmanager
44     };
45 
ConnectionQueueItem(const HintedUser & aUser,bool aDownload)46     ConnectionQueueItem(const HintedUser& aUser, bool aDownload) : token(Util::toString(Util::rand())),
47                 lastAttempt(0), errors(0), state(WAITING), download(aDownload), user(aUser) { }
48 
49     GETSET(string, token, Token);
50     GETSET(uint64_t, lastAttempt, LastAttempt);
51     GETSET(int, errors, Errors); // Number of connection errors, or -1 after a protocol error
52     GETSET(State, state, State);
53     GETSET(bool, download, Download);
54 
getUser()55     const HintedUser& getUser() const { return user; }
56 
57 private:
58     HintedUser user;
59 };
60 
61 class ExpectedMap {
62 public:
add(const string & aNick,const string & aMyNick,const string & aHubUrl)63     void add(const string& aNick, const string& aMyNick, const string& aHubUrl) {
64         Lock l(cs);
65         expectedConnections.insert(make_pair(aNick, make_pair(aMyNick, aHubUrl)));
66     }
67 
remove(const string & aNick)68     StringPair remove(const string& aNick) {
69         Lock l(cs);
70         auto i = expectedConnections.find(aNick);
71 
72         if(i == expectedConnections.end())
73             return make_pair(Util::emptyString, Util::emptyString);
74 
75         StringPair tmp = i->second;
76         expectedConnections.erase(i);
77 
78         return tmp;
79     }
80 
81 private:
82     /** Nick -> myNick, hubUrl for expected NMDC incoming connections */
83     typedef map<string, StringPair> ExpectMap;
84     ExpectMap expectedConnections;
85 
86     CriticalSection cs;
87 };
88 
89 // Comparing with a user...
90 inline bool operator==(ConnectionQueueItem::Ptr ptr, const UserPtr& aUser) { return ptr->getUser() == aUser; }
91 
92 class ConnectionManager : public Speaker<ConnectionManagerListener>,
93     public UserConnectionListener, TimerManagerListener,
94     public Singleton<ConnectionManager>
95 {
96 public:
nmdcExpect(const string & aNick,const string & aMyNick,const string & aHubUrl)97     void nmdcExpect(const string& aNick, const string& aMyNick, const string& aHubUrl) {
98         expectedConnections.add(aNick, aMyNick, aHubUrl);
99     }
100 
101     void nmdcConnect(const string& aServer, uint16_t aPort, const string& aMyNick, const string& hubUrl, const string& encoding, bool secure);
102     void nmdcConnect(const string& aServer, uint16_t aPort, uint16_t localPort, BufferedSocket::NatRoles natRole, const string& aNick, const string& hubUrl, const string& encoding, bool secure);
103     void adcConnect(const OnlineUser& aUser, uint16_t aPort, const string& aToken, bool secure);
104     void adcConnect(const OnlineUser& aUser, uint16_t aPort, uint16_t localPort, BufferedSocket::NatRoles natRole, const string& aToken, bool secure);
105 
106     void getDownloadConnection(const HintedUser& aUser);
107     void force(const UserPtr& aUser);
108 
109     void disconnect(const UserPtr& aUser); // disconnect downloads and uploads
110     void disconnect(const UserPtr& aUser, int isDownload);
111 
112     void shutdown();
113 
114     /** Find a suitable port to listen on, and start doing it */
115     void listen();
116     void disconnect() noexcept;
117 
getPort()118     uint16_t getPort() { return server ? static_cast<uint16_t>(server->getPort()) : 0; }
getSecurePort()119     uint16_t getSecurePort() { return secureServer ? static_cast<uint16_t>(secureServer->getPort()) : 0; }
120 
121     void addCTM2HUB(const string &server, const string &port);
122 
123 private:
124 
125     unordered_set<string> ddosctm2hub;
126 
127     class Server : public Thread {
128     public:
129         Server(bool secure_, uint16_t port, const string& ip = "0.0.0.0");
getPort()130         uint16_t getPort() { return port; }
~Server()131         virtual ~Server() { die = true; join(); }
132     private:
133         virtual int run() noexcept;
134 
135         Socket sock;
136         uint16_t port;
137         string ip;
138         bool secure;
139         bool die;
140     };
141 
142     friend class Server;
143 
144     CriticalSection cs;
145 
146     /** All ConnectionQueueItems */
147     ConnectionQueueItem::List downloads;
148     ConnectionQueueItem::List uploads;
149 
150     /** All active connections */
151     UserConnectionList userConnections;
152 
153     StringList features;
154     StringList adcFeatures;
155 
156     ExpectedMap expectedConnections;
157 
158     uint32_t floodCounter;
159 
160     Server* server;
161     Server* secureServer;
162 
163     bool shuttingDown;
164 
165     friend class Singleton<ConnectionManager>;
166     ConnectionManager();
167 
~ConnectionManager()168     virtual ~ConnectionManager() { shutdown(); }
169 
170     UserConnection* getConnection(bool aNmdc, bool secure) noexcept;
171     void putConnection(UserConnection* aConn);
172 
173     void addUploadConnection(UserConnection* uc);
174     void addDownloadConnection(UserConnection* uc);
175 
176     ConnectionQueueItem* getCQI(const HintedUser& aUser, bool download);
177     void putCQI(ConnectionQueueItem* cqi);
178 
179     bool checkKeyprint(UserConnection *aSource);
180 
181     void accept(const Socket& sock, bool secure) noexcept;
182 
183     void failed(UserConnection* aSource, const string& aError, bool protocolError);
184 
185     // UserConnectionListener
186     virtual void on(Connected, UserConnection*) noexcept;
187     virtual void on(Failed, UserConnection*, const string&) noexcept;
188     virtual void on(ProtocolError, UserConnection*, const string&) noexcept;
189     virtual void on(CLock, UserConnection*, const string&, const string&) noexcept;
190     virtual void on(Key, UserConnection*, const string&) noexcept;
191     virtual void on(Direction, UserConnection*, const string&, const string&) noexcept;
192     virtual void on(MyNick, UserConnection*, const string&) noexcept;
193     virtual void on(Supports, UserConnection*, const StringList&) noexcept;
194 
195     virtual void on(AdcCommand::SUP, UserConnection*, const AdcCommand&) noexcept;
196     virtual void on(AdcCommand::INF, UserConnection*, const AdcCommand&) noexcept;
197     virtual void on(AdcCommand::STA, UserConnection*, const AdcCommand&) noexcept;
198 
199     // TimerManagerListener
200     virtual void on(TimerManagerListener::Second, uint64_t aTick) noexcept;
201     virtual void on(TimerManagerListener::Minute, uint64_t aTick) noexcept;
202 
203 };
204 
205 } // namespace dcpp
206