2 // This file is part of the aMule Project.
4 // Copyright (c) 2005-2008 aMule Team ( admin@amule.org / http://www.amule.org )
6 // Any parts of this program derived from the xMule, lMule or eMule project,
7 // or contributed by third-party developers are copyrighted by their
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "MuleUDPSocket.h" // Interface declarations
30 #include <protocol/ed2k/Constants.h>
32 #include "Logger.h" // Needed for AddDebugLogLineM
33 #include "amule.h" // Needed for theApp
34 #include "GetTickCount.h" // Needed for GetTickCount()
35 #include "Packet.h" // Needed for CPacket
36 #include <common/StringFunctions.h> // Needed for unicode2char
37 #include "Proxy.h" // Needed for CDatagramSocketProxy
38 #include "Logger.h" // Needed for AddDebugLogLineM
39 #include "UploadBandwidthThrottler.h"
40 #include "EncryptedDatagramSocket.h"
41 #include "OtherFunctions.h"
42 #include "kademlia/kademlia/Prefs.h"
43 #include "ClientList.h"
46 CMuleUDPSocket::CMuleUDPSocket(const wxString
& name
, int id
, const amuleIPV4Address
& address
, const CProxyData
* ProxyData
)
58 CMuleUDPSocket::~CMuleUDPSocket()
60 theApp
->uploadBandwidthThrottler
->RemoveFromAllQueues(this);
62 wxMutexLocker
lock(m_mutex
);
67 void CMuleUDPSocket::CreateSocket()
69 wxCHECK_RET(!m_socket
, wxT("Socket already opened."));
71 m_socket
= new CEncryptedDatagramSocket(m_addr
, wxSOCKET_NOWAIT
, m_proxy
);
72 m_socket
->SetClientData(this);
73 m_socket
->SetEventHandler(*theApp
, m_id
);
74 m_socket
->SetNotify(wxSOCKET_INPUT_FLAG
| wxSOCKET_OUTPUT_FLAG
| wxSOCKET_LOST_FLAG
);
75 m_socket
->Notify(true);
77 if (!m_socket
->Ok()) {
78 AddDebugLogLineM(true, logMuleUDP
, wxT("Failed to create valid ") + m_name
);
81 AddLogLineM(false, wxString(wxT("Created ")) << m_name
<< wxT(" at port ") << m_addr
.Service());
86 void CMuleUDPSocket::DestroySocket()
89 AddDebugLogLineM(false, logMuleUDP
, wxT("Shutting down ") + m_name
);
90 m_socket
->SetNotify(0);
91 m_socket
->Notify(false);
99 void CMuleUDPSocket::Open()
101 wxMutexLocker
lock(m_mutex
);
107 void CMuleUDPSocket::Close()
109 wxMutexLocker
lock(m_mutex
);
115 void CMuleUDPSocket::OnSend(int errorCode
)
122 wxMutexLocker
lock(m_mutex
);
124 if (m_queue
.empty()) {
129 theApp
->uploadBandwidthThrottler
->QueueForSendingControlPacket(this);
133 const unsigned UDP_BUFFER_SIZE
= 16384;
136 void CMuleUDPSocket::OnReceive(int errorCode
)
138 AddDebugLogLineM(false, logMuleUDP
, wxString::Format(
139 wxT("Got UDP callback for read: Error %i Socket state %i"),
140 errorCode
, Ok() ? 1 : 0));
142 char buffer
[UDP_BUFFER_SIZE
];
149 wxMutexLocker
lock(m_mutex
);
151 if (errorCode
|| (m_socket
== NULL
) || !m_socket
->Ok()) {
159 length
= m_socket
->RecvFrom(addr
, buffer
, UDP_BUFFER_SIZE
).LastCount();
160 error
= m_socket
->Error();
161 lastError
= m_socket
->LastError();
164 const uint32 ip
= StringIPtoUint32(addr
.IPAddress());
165 const uint16 port
= addr
.Service();
167 OnReceiveError(lastError
, ip
, port
);
168 } else if (length
< 2) {
169 // 2 bytes (protocol and opcode) is the smallets possible packet.
170 AddDebugLogLineM(false, logMuleUDP
, m_name
+ wxT(": Invalid Packet received"));
173 AddLogLineNS(wxT("Unknown ip receiving an UDP packet! Ignoring: '") + addr
.IPAddress() + wxT("'"));
176 AddLogLineNS(wxT("Unknown port receiving an UDP packet! Ignoring"));
177 } else if (theApp
->clientlist
->IsBannedClient(ip
)) {
178 AddDebugLogLineM(false, logMuleUDP
, m_name
+ wxT(": Dropped packet from banned IP ") + addr
.IPAddress());
180 AddDebugLogLineM(false, logMuleUDP
, (m_name
+ wxT(": Packet received ("))
181 << addr
.IPAddress() << wxT(":") << port
<< wxT("): ")
182 << length
<< wxT("b"));
183 OnPacketReceived(ip
, port
, (byte
*)buffer
, length
);
188 void CMuleUDPSocket::OnReceiveError(int errorCode
, uint32
WXUNUSED(ip
), uint16
WXUNUSED(port
))
190 AddDebugLogLineM(false, logMuleUDP
, (m_name
+ wxT(": Error while reading: ")) << errorCode
);
194 void CMuleUDPSocket::OnDisconnected(int WXUNUSED(errorCode
))
196 /* Due to bugs in wxWidgets, UDP sockets will sometimes
197 * be closed. This is caused by the fact that wx treats
198 * zero-length datagrams as EOF, which is only the case
199 * when dealing with streaming sockets.
201 * This has been reported as patch #1885472:
202 * http://sourceforge.net/tracker/index.php?func=detail&aid=1885472&group_id=9863&atid=309863
204 AddDebugLogLineM(true, logMuleUDP
, m_name
+ wxT("Socket died, recreating."));
210 void CMuleUDPSocket::SendPacket(CPacket
* packet
, uint32 IP
, uint16 port
, bool bEncrypt
, const uint8
* pachTargetClientHashORKadID
, bool bKad
, uint32 nReceiverVerifyKey
)
212 wxCHECK_RET(packet
, wxT("Invalid packet."));
213 /*wxCHECK_RET(port, wxT("Invalid port."));
214 wxCHECK_RET(IP, wxT("Invalid IP."));
222 AddDebugLogLineM(false, logMuleUDP
, (m_name
+ wxT(": Packet discarded, socket not Ok ("))
223 << Uint32_16toStringIP_Port(IP
, port
) << wxT("): ") << packet
->GetPacketSize() << wxT("b"));
229 AddDebugLogLineM(false, logMuleUDP
, (m_name
+ wxT(": Packet queued ("))
230 << Uint32_16toStringIP_Port(IP
, port
) << wxT("): ") << packet
->GetPacketSize() << wxT("b"));
234 newpending
.port
= port
;
235 newpending
.packet
= packet
;
236 newpending
.time
= GetTickCount();
237 newpending
.bEncrypt
= bEncrypt
&& (pachTargetClientHashORKadID
!= NULL
|| (bKad
&& nReceiverVerifyKey
!= 0));
238 newpending
.bKad
= bKad
;
239 newpending
.nReceiverVerifyKey
= nReceiverVerifyKey
;
240 if (newpending
.bEncrypt
&& pachTargetClientHashORKadID
!= NULL
) {
241 md4cpy(newpending
.pachTargetClientHashORKadID
, pachTargetClientHashORKadID
);
243 md4clr(newpending
.pachTargetClientHashORKadID
);
247 wxMutexLocker
lock(m_mutex
);
248 m_queue
.push_back(newpending
);
251 theApp
->uploadBandwidthThrottler
->QueueForSendingControlPacket(this);
255 bool CMuleUDPSocket::Ok()
257 wxMutexLocker
lock(m_mutex
);
259 return m_socket
&& m_socket
->Ok();
263 SocketSentBytes
CMuleUDPSocket::SendControlData(uint32 maxNumberOfBytesToSend
, uint32
WXUNUSED(minFragSize
))
265 wxMutexLocker
lock(m_mutex
);
266 uint32 sentBytes
= 0;
267 while (!m_queue
.empty() && !m_busy
&& (sentBytes
< maxNumberOfBytesToSend
)) {
268 UDPPack item
= m_queue
.front();
269 CPacket
* packet
= item
.packet
;
270 if (GetTickCount() - item
.time
< UDPMAXQUEUETIME
) {
271 uint32_t len
= packet
->GetPacketSize() + 2;
272 uint8_t *sendbuffer
= new uint8_t [len
];
273 memcpy(sendbuffer
, packet
->GetUDPHeader(), 2);
274 memcpy(sendbuffer
+ 2, packet
->GetDataBuffer(), packet
->GetPacketSize());
276 if (item
.bEncrypt
&& (theApp
->GetPublicIP() > 0 || item
.bKad
)) {
277 len
= CEncryptedDatagramSocket::EncryptSendClient(&sendbuffer
, len
, item
.pachTargetClientHashORKadID
, item
.bKad
, item
.nReceiverVerifyKey
, (item
.bKad
? Kademlia::CPrefs::GetUDPVerifyKey(item
.IP
) : 0));
280 if (SendTo(sendbuffer
, len
, item
.IP
, item
.port
)) {
284 delete [] sendbuffer
;
286 // TODO: Needs better error handling, see SentTo
287 delete [] sendbuffer
;
295 if (!m_busy
&& !m_queue
.empty()) {
296 theApp
->uploadBandwidthThrottler
->QueueForSendingControlPacket(this);
298 SocketSentBytes returnVal
= { true, 0, sentBytes
};
304 bool CMuleUDPSocket::SendTo(uint8_t *buffer
, uint32_t length
, uint32_t ip
, uint16_t port
)
306 // Just pretend that we sent the packet in order to avoid infinite loops.
307 if (!(m_socket
&& m_socket
->Ok())) {
311 amuleIPV4Address addr
;
315 // We better clear this flag here, status might have been changed
316 // between the U.B.T. addition and the real sending happening later
319 m_socket
->SendTo(addr
, buffer
, length
);
320 if (m_socket
->Error()) {
321 wxSocketError error
= m_socket
->LastError();
323 if (error
== wxSOCKET_WOULDBLOCK
) {
324 // Socket is busy and can't send this data right now,
325 // so we just return not sent and set the wouldblock
326 // flag so it gets resent when socket is ready.
329 // An error which we can't handle happended, so we drop
330 // the packet rather than risk entering an infinite loop.
331 AddLogLineNS((wxT("WARNING! ") + m_name
+ wxT(": Packet to "))
332 << Uint32_16toStringIP_Port(ip
, port
)
333 << wxT(" discarded due to error (") << error
<< wxT(") while sending."));
337 AddDebugLogLineM(false, logMuleUDP
, (m_name
+ wxT(": Packet sent ("))
338 << Uint32_16toStringIP_Port(ip
, port
) << wxT("): ")
339 << length
<< wxT("b"));
346 // File_checked_for_headers