Upstream tarball 20080304
[amule.git] / src / libs / ec / cpp / RemoteConnect.cpp
blob7b4aa36e32611efb2ed156bc7b812ee7af4eba42
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2004-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2004-2008 Angel Vidal Veiga ( kry@users.sourceforge.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "RemoteConnect.h"
28 #include <wx/intl.h>
30 using std::auto_ptr;
32 DEFINE_LOCAL_EVENT_TYPE(wxEVT_EC_CONNECTION)
34 CECLoginPacket::CECLoginPacket(const wxString &pass,
35 const wxString& client, const wxString& version) : CECPacket(EC_OP_AUTH_REQ)
37 AddTag(CECTag(EC_TAG_CLIENT_NAME, client));
38 AddTag(CECTag(EC_TAG_CLIENT_VERSION, version));
39 AddTag(CECTag(EC_TAG_PROTOCOL_VERSION, (uint64)EC_CURRENT_PROTOCOL_VERSION));
41 CMD4Hash passhash;
42 wxCHECK2(passhash.Decode(pass), /* Do nothing. */);
43 AddTag(CECTag(EC_TAG_PASSWD_HASH, passhash));
46 #ifdef EC_VERSION_ID
47 CMD4Hash versionhash;
48 wxCHECK2(versionhash.Decode(wxT(EC_VERSION_ID)), /* Do nothing. */);
49 AddTag(CECTag(EC_TAG_VERSION_ID, versionhash));
50 #endif
54 /*!
55 * Connection to remote core
59 CRemoteConnect::CRemoteConnect(wxEvtHandler* evt_handler)
61 CECMuleSocket(evt_handler != 0),
62 m_ec_state(EC_INIT),
63 m_req_fifo(),
64 // Give application some indication about how fast requests are served
65 // When request fifo contain more that certain number of entries, it may
66 // indicate that either core or network is slowing us down
67 m_req_count(0),
68 // This is not mean to be absolute limit, because we can't drop requests
69 // out of calling context; it is just signal to application to slow down
70 m_req_fifo_thr(20),
71 m_notifier(evt_handler)
75 bool CRemoteConnect::ConnectToCore(const wxString &host, int port,
76 const wxString &WXUNUSED(login), const wxString &pass,
77 const wxString& client, const wxString& version)
79 m_connectionPassword = pass;
81 m_client = client;
82 m_version = version;
84 // don't even try to connect without a valid password
85 if (m_connectionPassword.IsEmpty() || m_connectionPassword == wxT("d41d8cd98f00b204e9800998ecf8427e")) {
86 m_server_reply = _("You must specify a non-empty password.");
87 return false;
88 } else {
89 CMD4Hash hash;
90 if (!hash.Decode(m_connectionPassword)) {
91 m_server_reply = _("Invalid password, not a MD5 hash!");
92 return false;
93 } else if (hash.IsEmpty()) {
94 m_server_reply = _("You must specify a non-empty password.");
95 return false;
99 wxIPV4address addr;
101 addr.Hostname(host);
102 addr.Service(port);
104 if ( !ConnectSocket(addr) ) {
105 return false;
108 // if we're using blocking calls - enter login sequence now. Else,
109 // we will wait untill OnConnect gets called
110 if ( !m_notifier ) {
111 CECLoginPacket login_req(m_connectionPassword, m_client, m_version);
112 std::auto_ptr<const CECPacket> reply(SendRecvPacket(&login_req));
113 return ConnectionEstablished(reply.get());
114 } else {
115 m_ec_state = EC_CONNECT_SENT;
118 return true;
121 void CRemoteConnect::OnConnect() {
122 if (m_notifier) {
123 wxASSERT(m_ec_state == EC_CONNECT_SENT);
124 CECLoginPacket login_req(m_connectionPassword, m_client, m_version);
125 CECSocket::SendPacket(&login_req);
127 m_ec_state = EC_REQ_SENT;
128 } else {
129 // do nothing, calling code will take from here
133 void CRemoteConnect::OnClose() {
134 if (m_notifier) {
135 // Notify app of failure
136 wxECSocketEvent event(wxEVT_EC_CONNECTION,false,_("Connection failure"));
137 m_notifier->AddPendingEvent(event);
139 // FIXME: wtf is that ?
140 //CECSocket::OnClose();
143 const CECPacket *CRemoteConnect::OnPacketReceived(const CECPacket *packet)
145 CECPacket *next_packet = 0;
146 m_req_count--;
147 switch(m_ec_state) {
148 case EC_REQ_SENT:
149 if ( ConnectionEstablished(packet) ) {
150 m_ec_state = EC_OK;
151 } else {
152 m_ec_state = EC_FAIL;
154 break;
155 case EC_OK:
156 if ( !m_req_fifo.empty() ) {
157 CECPacketHandlerBase *handler = m_req_fifo.front();
158 m_req_fifo.pop_front();
159 if ( handler ) {
160 handler->HandlePacket(packet);
162 } else {
163 printf("EC error - packet received, but request fifo is empty\n");
165 break;
166 default:
167 break;
170 // no reply by default
171 return next_packet;
175 * Our requests are served by core in FCFS order. And core always replies. So, even
176 * if we're not interested in reply, we preserve place in request fifo.
178 void CRemoteConnect::SendRequest(CECPacketHandlerBase *handler, CECPacket *request)
180 m_req_count++;
181 m_req_fifo.push_back(handler);
182 CECSocket::SendPacket(request);
185 void CRemoteConnect::SendPacket(CECPacket *request)
187 SendRequest(0, request);
190 bool CRemoteConnect::ConnectionEstablished(const CECPacket *reply) {
191 bool result = false;
193 if (!reply) {
194 m_server_reply = _("EC Connection Failed. Empty reply.");
195 CloseSocket();
196 } else {
197 if (reply->GetOpCode() == EC_OP_AUTH_FAIL) {
198 const CECTag *reason = reply->GetTagByName(EC_TAG_STRING);
199 if (reason != NULL) {
200 m_server_reply = wxString(_("ExternalConn: Access denied because: ")) +
201 wxGetTranslation(reason->GetStringData());
202 } else {
203 m_server_reply = _("ExternalConn: Access denied");
205 CloseSocket();
206 } else if (reply->GetOpCode() != EC_OP_AUTH_OK) {
207 m_server_reply = _("ExternalConn: Bad reply from server. Connection closed.");
208 CloseSocket();
209 } else {
210 if (reply->GetTagByName(EC_TAG_SERVER_VERSION)) {
211 m_server_reply = _("Succeeded! Connection established to aMule ") +
212 reply->GetTagByName(EC_TAG_SERVER_VERSION)->GetStringData();
213 } else {
214 m_server_reply = _("Succeeded! Connection established.");
216 result = true;
219 if ( m_notifier ) {
220 wxECSocketEvent event(wxEVT_EC_CONNECTION, result, m_server_reply);
221 m_notifier->AddPendingEvent(event);
223 return result;
226 /******************** EC API ***********************/
228 void CRemoteConnect::StartKad() {
229 CECPacket req(EC_OP_KAD_START);
230 SendPacket(&req);
233 void CRemoteConnect::StopKad() {
234 CECPacket req(EC_OP_KAD_STOP);
235 SendPacket(&req);
238 void CRemoteConnect::ConnectED2K(uint32 ip, uint16 port) {
239 CECPacket req(EC_OP_SERVER_CONNECT);
240 if (ip && port) {
241 req.AddTag(CECTag(EC_TAG_SERVER, EC_IPv4_t(ip, port)));
243 SendPacket(&req);
246 void CRemoteConnect::DisconnectED2K() {
247 CECPacket req(EC_OP_SERVER_DISCONNECT);
248 SendPacket(&req);
251 void CRemoteConnect::RemoveServer(uint32 ip, uint16 port) {
252 CECPacket req(EC_OP_SERVER_REMOVE);
253 if (ip && port) {
254 req.AddTag(CECTag(EC_TAG_SERVER, EC_IPv4_t(ip, port)));
256 SendPacket(&req);
258 // File_checked_for_headers