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 "forward.h"
22 #include "TimerManager.h"
23 #include "UserConnectionListener.h"
24 #include "BufferedSocketListener.h"
25 #include "BufferedSocket.h"
26 #include "CriticalSection.h"
27 #include "File.h"
28 #include "User.h"
29 #include "AdcCommand.h"
30 #include "MerkleTree.h"
31 #include "DebugManager.h"
32 #ifdef LUA_SCRIPT
33 #include "ScriptManager.h"
34 #endif
35 
36 namespace dcpp {
37 #ifdef LUA_SCRIPT
38 class UserConnectionScriptInstance : public ScriptInstance {
39 protected:
40     bool onUserConnectionMessageIn(UserConnection* aConn, const string& aLine);
41     bool onUserConnectionMessageOut(UserConnection* aConn, const string& aLine);
42 };
43 #endif
44 
45 class UserConnection : public Speaker<UserConnectionListener>,
46     private BufferedSocketListener, public Flags, private CommandHandler<UserConnection>,
47     private boost::noncopyable
48 #ifdef LUA_SCRIPT
49 , public UserConnectionScriptInstance
50 #endif
51 {
52 public:
53     friend class ConnectionManager;
54 
55     static const string FEATURE_MINISLOTS;
56     static const string FEATURE_XML_BZLIST;
57     static const string FEATURE_ADCGET;
58     static const string FEATURE_ZLIB_GET;
59     static const string FEATURE_TTHL;
60     static const string FEATURE_TTHF;
61     static const string FEATURE_ADC_BAS0;
62     static const string FEATURE_ADC_BASE;
63     static const string FEATURE_ADC_BZIP;
64     static const string FEATURE_ADC_TIGR;
65 
66     static const string FILE_NOT_AVAILABLE;
67 
68     enum Modes {
69         MODE_COMMAND = BufferedSocket::MODE_LINE,
70         MODE_DATA = BufferedSocket::MODE_DATA
71     };
72 
73     enum Flags {
74         FLAG_NMDC = 0x01,
75         FLAG_OP = FLAG_NMDC << 1,
76         FLAG_UPLOAD = FLAG_OP << 1,
77         FLAG_DOWNLOAD = FLAG_UPLOAD << 1,
78         FLAG_INCOMING = FLAG_DOWNLOAD << 1,
79         FLAG_ASSOCIATED = FLAG_INCOMING << 1,
80         FLAG_HASSLOT = FLAG_ASSOCIATED << 1,
81         FLAG_HASEXTRASLOT = FLAG_HASSLOT << 1,
82         FLAG_INVALIDKEY = FLAG_HASEXTRASLOT << 1,
83         FLAG_SUPPORTS_MINISLOTS = FLAG_INVALIDKEY << 1,
84         FLAG_SUPPORTS_XML_BZLIST = FLAG_SUPPORTS_MINISLOTS << 1,
85         FLAG_SUPPORTS_ADCGET = FLAG_SUPPORTS_XML_BZLIST << 1,
86         FLAG_SUPPORTS_ZLIB_GET = FLAG_SUPPORTS_ADCGET << 1,
87         FLAG_SUPPORTS_TTHL = FLAG_SUPPORTS_ZLIB_GET << 1,
88         FLAG_SUPPORTS_TTHF = FLAG_SUPPORTS_TTHL << 1,
89         FLAG_SECURE = FLAG_SUPPORTS_TTHF << 1
90     };
91 
92     enum States {
93         // ConnectionManager
94         STATE_UNCONNECTED,
95         STATE_CONNECT,
96 
97         // Handshake
98         STATE_SUPNICK,      // ADC: SUP, Nmdc: $Nick
99         STATE_INF,
100         STATE_LOCK,
101         STATE_DIRECTION,
102         STATE_KEY,
103 
104         // UploadManager
105         STATE_GET,          // Waiting for GET
106         STATE_SEND,         // Waiting for $Send
107 
108         // DownloadManager
109         STATE_SND,  // Waiting for SND
110         STATE_IDLE, // No more downloads for the moment
111 
112         // Up & down
113         STATE_RUNNING       // Transmitting data
114 
115     };
116 
getNumber()117     short getNumber() { return (short)((((size_t)this)>>2) & 0x7fff); }
getSocket()118     BufferedSocket const* getSocket() { return socket; }
119 
120     // NMDC stuff
myNick(const string & aNick)121     void myNick(const string& aNick) { send("$MyNick " + Text::fromUtf8(aNick, encoding) + '|'); }
lock(const string & aLock,const string & aPk)122     void lock(const string& aLock, const string& aPk) { send ("$Lock " + aLock + " Pk=" + aPk + '|'); }
key(const string & aKey)123     void key(const string& aKey) { send("$Key " + aKey + '|'); }
direction(const string & aDirection,int aNumber)124     void direction(const string& aDirection, int aNumber) { send("$Direction " + aDirection + " " + Util::toString(aNumber) + '|'); }
fileLength(const string & aLength)125     void fileLength(const string& aLength) { send("$FileLength " + aLength + '|'); }
error(const string & aError)126     void error(const string& aError) { isSet(FLAG_NMDC) ? send("$Error " + aError + '|') :
127  send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_TRANSFER_GENERIC, aError)); }
listLen(const string & aLength)128     void listLen(const string& aLength) { send("$ListLen " + aLength + '|'); }
maxedOut()129     void maxedOut() { isSet(FLAG_NMDC) ? send("$MaxedOut|") : send(AdcCommand(AdcCommand::SEV_RECOVERABLE, AdcCommand::ERROR_SLOTS_FULL, "Slots full")); }
130     void fileNotAvail(const std::string& msg = FILE_NOT_AVAILABLE) { isSet(FLAG_NMDC) ? send("$Error " + msg + "|") : send(AdcCommand(AdcCommand::SEV_RECOVERABLE, AdcCommand::ERROR_FILE_NOT_AVAILABLE, msg)); }
131     void supports(const StringList& feat);
132 
133     // ADC Stuff
134     void sup(const StringList& features);
135     void inf(bool withToken);
get(const string & aType,const string & aName,const int64_t aStart,const int64_t aBytes)136     void get(const string& aType, const string& aName, const int64_t aStart, const int64_t aBytes) { send(AdcCommand(AdcCommand::CMD_GET).addParam(aType).addParam(aName).addParam(Util::toString(aStart)).addParam(Util::toString(aBytes))); }
snd(const string & aType,const string & aName,const int64_t aStart,const int64_t aBytes)137     void snd(const string& aType, const string& aName, const int64_t aStart, const int64_t aBytes) { send(AdcCommand(AdcCommand::CMD_SND).addParam(aType).addParam(aName).addParam(Util::toString(aStart)).addParam(Util::toString(aBytes))); }
send(const AdcCommand & c)138     void send(const AdcCommand& c) { send(c.toString(0, isSet(FLAG_NMDC))); }
139 
140     void setDataMode(int64_t aBytes = -1) { dcassert(socket); socket->setDataMode(aBytes); }
setLineMode(size_t rollback)141     void setLineMode(size_t rollback) { dcassert(socket); socket->setLineMode(rollback); }
142 
143     void connect(const string& aServer, uint16_t aPort, uint16_t localPort, const BufferedSocket::NatRoles natRole) throw(SocketException, ThreadException);
144     void accept(const Socket& aServer) throw(SocketException, ThreadException);
145 
updated()146     void updated() { if(socket) socket->updated(); }
147 
148     void disconnect(bool graceless = false) { if(socket) socket->disconnect(graceless); }
transmitFile(InputStream * f)149     void transmitFile(InputStream* f) { socket->transmitFile(f); }
150 
getDirectionString()151     const string& getDirectionString() {
152         dcassert(isSet(FLAG_UPLOAD) ^ isSet(FLAG_DOWNLOAD));
153         return isSet(FLAG_UPLOAD) ? UPLOAD : DOWNLOAD;
154     }
155 
getUser()156     const UserPtr& getUser() const { return user; }
getUser()157     UserPtr& getUser() { return user; }
getHintedUser()158     const HintedUser getHintedUser() const { return HintedUser(user, hubUrl); }
159 
isSecure()160     bool isSecure() const { return socket && socket->isSecure(); }
isTrusted()161     bool isTrusted() const { return socket && socket->isTrusted(); }
getCipherName()162     std::string getCipherName() const { return socket ? socket->getCipherName() : Util::emptyString; }
getKeyprint()163     vector<uint8_t> getKeyprint() const { return socket ? socket->getKeyprint() : vector<uint8_t>(); }
getRemoteIp()164     std::string getRemoteIp() const { return socket ? socket->getIp() : Util::emptyString; }
getDownload()165     Download* getDownload() { dcassert(isSet(FLAG_DOWNLOAD)); return download; }
166     //uint16_t getPort() const { if(socket) return socket->getPort(); else return 0; }
setDownload(Download * d)167     void setDownload(Download* d) { dcassert(isSet(FLAG_DOWNLOAD)); download = d; }
getUpload()168     Upload* getUpload() { dcassert(isSet(FLAG_UPLOAD)); return upload; }
setUpload(Upload * u)169     void setUpload(Upload* u) { dcassert(isSet(FLAG_UPLOAD)); upload = u; }
170 
handle(AdcCommand::SUP t,const AdcCommand & c)171     void handle(AdcCommand::SUP t, const AdcCommand& c) { fire(t, this, c); }
handle(AdcCommand::INF t,const AdcCommand & c)172     void handle(AdcCommand::INF t, const AdcCommand& c) { fire(t, this, c); }
handle(AdcCommand::GET t,const AdcCommand & c)173     void handle(AdcCommand::GET t, const AdcCommand& c) { fire(t, this, c); }
handle(AdcCommand::SND t,const AdcCommand & c)174     void handle(AdcCommand::SND t, const AdcCommand& c) { fire(t, this, c); }
175     void handle(AdcCommand::STA t, const AdcCommand& c);
handle(AdcCommand::RES t,const AdcCommand & c)176     void handle(AdcCommand::RES t, const AdcCommand& c) { fire(t, this, c); }
handle(AdcCommand::GFI t,const AdcCommand & c)177     void handle(AdcCommand::GFI t, const AdcCommand& c) { fire(t, this, c); }
178 
179     // Ignore any other ADC commands for now
handle(T,const AdcCommand &)180     template<typename T> void handle(T , const AdcCommand& ) { }
181 
getChunkSize()182     int64_t getChunkSize() const { return chunkSize; }
183     void updateChunkSize(int64_t leafSize, int64_t lastChunk, uint64_t ticks);
sendRaw(const string & raw)184     void sendRaw(const string& raw) { send(raw); }//aded
185     GETSET(string, hubUrl, HubUrl);
186     GETSET(string, token, Token);
187     GETSET(string, encoding, Encoding);
188     GETSET(uint16_t, port, Port);
189     GETSET(States, state, State);
190     GETSET(uint64_t, lastActivity, LastActivity);
191     GETSET(double, speed, Speed);
192 private:
193     int64_t chunkSize;
194     BufferedSocket* socket;
195     bool secure;
196     UserPtr user;
197 
198     static const string UPLOAD, DOWNLOAD;
199 
200     union {
201         Download* download;
202         Upload* upload;
203     };
204 
205     // We only want ConnectionManager to create this...
UserConnection(bool secure_)206     UserConnection(bool secure_) noexcept : encoding(Text::systemCharset), state(STATE_UNCONNECTED),
207         lastActivity(0), speed(0), chunkSize(0), socket(0), secure(secure_), download(NULL) {
208         if (secure_)
209             setFlag(FLAG_SECURE);
210     }
211 
~UserConnection()212     virtual ~UserConnection() noexcept {
213         BufferedSocket::putSocket(socket);
214     }
215 
216     friend struct DeleteFunction;
217 
setUser(const UserPtr & aUser)218     void setUser(const UserPtr& aUser) {
219         user = aUser;
220     }
221 
222     void onLine(const string& aLine) noexcept;
223 
send(const string & aString)224     void send(const string& aString) {
225         lastActivity = GET_TICK();
226         COMMAND_DEBUG(aString, DebugManager::CLIENT_OUT, getRemoteIp());
227 #ifdef LUA_SCRIPT
228         if(onUserConnectionMessageOut(this, aString)) {
229             disconnect(true);
230             return;
231         }
232 #endif
233         socket->write(aString);
234     }
235 
236     virtual void on(Connected) noexcept;
237     virtual void on(Line, const string&) noexcept;
238     virtual void on(Data, uint8_t* data, size_t len) noexcept;
239     virtual void on(BytesSent, size_t bytes, size_t actual) noexcept ;
240     virtual void on(ModeChange) noexcept;
241     virtual void on(TransmitDone) noexcept;
242     virtual void on(Failed, const string&) noexcept;
243     virtual void on(Updated) noexcept;
244 };
245 
246 } // namespace dcpp
247