2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2008 Merkur ( devs@emule-project.net / http://www.emule-project.net )
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
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.
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 "ListenSocket.h" // Interface declarations
28 #include <common/EventIDs.h>
30 #include "ClientTCPSocket.h" // Needed for CClientRequestSocket
31 #include "Logger.h" // Needed for AddLogLineM
32 #include "Statistics.h" // Needed for theStats
33 #include "Preferences.h" // Needed for CPreferences
34 #include "amule.h" // Needed for theApp
35 #include "ServerConnect.h" // Needed for CServerConnect
36 #include "updownclient.h" // Needed for CUpDownClient
38 //-----------------------------------------------------------------------------
40 //-----------------------------------------------------------------------------
42 // This is the socket that listens to incomming connections in aMule's TCP port
43 // As soon as a connection is detected, it creates a new socket of type
44 // CClientTCPSocket to handle (accept) the connection.
47 CListenSocket::CListenSocket(wxIPaddress
&addr
, const CProxyData
*ProxyData
)
49 // wxSOCKET_NOWAIT - means non-blocking i/o
50 // wxSOCKET_REUSEADDR - means we can reuse the socket imediately (wx-2.5.3)
51 CSocketServerProxy(addr
, wxSOCKET_NOWAIT
|wxSOCKET_REUSEADDR
, ProxyData
)
53 // 0.42e - vars not used by us
56 m_OpenSocketsInterval
= 0;
57 m_nPeningConnections
= 0;
58 totalconnectionchecks
= 0;
59 averageconnections
= 0.0;
60 // Set the listen socket event handler -- The handler is written in amule.cpp
62 SetEventHandler(*theApp
, ID_LISTENSOCKET_EVENT
);
63 SetNotify(wxSOCKET_CONNECTION_FLAG
);
66 AddLogLineNS(_("ListenSocket: Ok."));
68 AddLogLineCS(_("ERROR: Could not listen to TCP port.") );
73 CListenSocket::~CListenSocket()
80 // No new sockets should have been opened by now
81 for (SocketSet::iterator it
= socket_list
.begin(); it
!= socket_list
.end(); it
++) {
82 wxASSERT((*it
)->OnDestroy());
90 bool CListenSocket::StartListening()
98 void CListenSocket::ReStartListening()
102 if (m_nPeningConnections
) {
103 m_nPeningConnections
--;
108 void CListenSocket::StopListening()
112 theStats::AddMaxConnectionLimitReached();
115 void CListenSocket::OnAccept(int nErrorCode
)
119 m_nPeningConnections
++;
120 if (m_nPeningConnections
< 1) {
122 m_nPeningConnections
= 1;
124 if (TooManySockets(true) && !theApp
->serverconnect
->IsConnecting()) {
127 } else if (bListening
== false) {
128 // If the client is still at maxconnections,
129 // this will allow it to go above it ...
130 // But if you don't, you will get a lowID on all servers.
133 // Deal with the pending connections, there might be more than one, due to
134 // the StopListening() call above.
135 while (m_nPeningConnections
) {
136 m_nPeningConnections
--;
137 // Create a new socket to deal with the connection
138 CClientTCPSocket
* newclient
= new CClientTCPSocket();
139 // Accept the connection and give it to the newly created socket
140 if (!AcceptWith(*newclient
, false)) {
141 newclient
->Safe_Delete();
143 wxASSERT(theApp
->IsRunning());
144 if (!newclient
->InitNetworkData()) {
145 // IP or port were not returned correctly
146 // from the accepted address, or filtered.
147 newclient
->Safe_Delete();
154 void CListenSocket::AddConnection()
156 m_OpenSocketsInterval
++;
159 void CListenSocket::Process()
161 // 042e + Kry changes for Destroy
162 m_OpenSocketsInterval
= 0;
163 SocketSet::iterator it
= socket_list
.begin();
164 while ( it
!= socket_list
.end() ) {
165 CClientTCPSocket
* cur_socket
= *it
++;
166 if (!cur_socket
->OnDestroy()) {
167 if (cur_socket
->ForDeletion()) {
168 cur_socket
->Destroy();
170 cur_socket
->CheckTimeOut();
175 if ((GetOpenSockets()+5 < thePrefs::GetMaxConnections() || theApp
->serverconnect
->IsConnecting()) && !bListening
) {
180 void CListenSocket::RecalculateStats()
183 memset(m_ConnectionStates
,0,6);
184 for (SocketSet::iterator it
= socket_list
.begin(); it
!= socket_list
.end(); ) {
185 CClientTCPSocket
* cur_socket
= *it
++;
186 switch (cur_socket
->GetConState()) {
187 case ES_DISCONNECTED
:
188 m_ConnectionStates
[0]++;
190 case ES_NOTCONNECTED
:
191 m_ConnectionStates
[1]++;
194 m_ConnectionStates
[2]++;
200 void CListenSocket::AddSocket(CClientTCPSocket
* toadd
)
203 socket_list
.insert(toadd
);
204 theStats::AddActiveConnection();
207 void CListenSocket::RemoveSocket(CClientTCPSocket
* todel
)
210 socket_list
.erase(todel
);
211 theStats::RemoveActiveConnection();
214 void CListenSocket::KillAllSockets()
216 // 0.42e reviewed - they use delete, but our safer is Destroy...
217 // But I bet it would be better to call Safe_Delete on the socket.
218 // Update: no... Safe_Delete MARKS for deletion. We need to delete it.
219 for (SocketSet::iterator it
= socket_list
.begin(); it
!= socket_list
.end(); ) {
220 CClientTCPSocket
* cur_socket
= *it
++;
221 if (cur_socket
->GetClient()) {
222 cur_socket
->GetClient()->Safe_Delete();
224 cur_socket
->Safe_Delete();
225 cur_socket
->Destroy();
230 bool CListenSocket::TooManySockets(bool bIgnoreInterval
)
232 if (GetOpenSockets() > thePrefs::GetMaxConnections() || (m_OpenSocketsInterval
> (thePrefs::GetMaxConperFive()*GetMaxConperFiveModifier()) && !bIgnoreInterval
)) {
239 bool CListenSocket::IsValidSocket(CClientTCPSocket
* totest
)
242 return socket_list
.find(totest
) != socket_list
.end();
246 void CListenSocket::UpdateConnectionsStatus()
248 // 0.42e xcept for the khaos stats
249 if( theApp
->IsConnected() ) {
250 totalconnectionchecks
++;
252 percent
= (float)(totalconnectionchecks
-1)/(float)totalconnectionchecks
;
253 if( percent
> .99f
) {
256 averageconnections
= (averageconnections
*percent
) + (float)GetOpenSockets()*(1.0f
-percent
);
261 float CListenSocket::GetMaxConperFiveModifier()
263 float SpikeSize
= GetOpenSockets() - averageconnections
;
264 if ( SpikeSize
< 1 ) {
268 float SpikeTolerance
= 2.5f
*thePrefs::GetMaxConperFive();
269 if ( SpikeSize
> SpikeTolerance
) {
273 return 1.0f
- (SpikeSize
/SpikeTolerance
);
275 // File_checked_for_headers