Upstream tarball 20080418
[amule.git] / src / ListenSocket.cpp
blobb4d5f9f47eb7849407063cb689396acf1760f3da
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.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 "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 //-----------------------------------------------------------------------------
39 // CListenSocket
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.
45 //
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
54 bListening = false;
55 shutdown = false;
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
61 if (Ok()) {
62 SetEventHandler(*theApp, ID_LISTENSOCKET_EVENT);
63 SetNotify(wxSOCKET_CONNECTION_FLAG);
64 Notify(true);
66 printf("ListenSocket: Ok.\n");
67 } else {
68 AddLogLineM( true, _("Error: Could not listen to TCP port.") );
69 printf("ListenSocket: Could not listen to TCP port.");
74 CListenSocket::~CListenSocket()
76 shutdown = true;
77 Discard();
78 Close();
80 #ifdef __DEBUG__
81 // No new sockets should have been opened by now
82 for (SocketSet::iterator it = socket_list.begin(); it != socket_list.end(); it++) {
83 wxASSERT((*it)->OnDestroy());
85 #endif
87 KillAllSockets();
91 bool CListenSocket::StartListening()
93 // 0.42e
94 bListening = true;
96 return true;
99 void CListenSocket::ReStartListening()
101 // 0.42e
102 bListening = true;
103 if (m_nPeningConnections) {
104 m_nPeningConnections--;
105 OnAccept(0);
109 void CListenSocket::StopListening()
111 // 0.42e
112 bListening = false;
113 theStats::AddMaxConnectionLimitReached();
116 void CListenSocket::OnAccept(int nErrorCode)
118 // 0.42e
119 if (!nErrorCode) {
120 m_nPeningConnections++;
121 if (m_nPeningConnections < 1) {
122 wxASSERT(FALSE);
123 m_nPeningConnections = 1;
125 if (TooManySockets(true) && !theApp->serverconnect->IsConnecting()) {
126 StopListening();
127 return;
128 } else if (bListening == false) {
129 // If the client is still at maxconnections,
130 // this will allow it to go above it ...
131 // But if you don't, you will get a lowID on all servers.
132 ReStartListening();
134 // Deal with the pending connections, there might be more than one, due to
135 // the StopListening() call above.
136 while (m_nPeningConnections) {
137 m_nPeningConnections--;
138 // Create a new socket to deal with the connection
139 CClientTCPSocket* newclient = new CClientTCPSocket();
140 // Accept the connection and give it to the newly created socket
141 if (!AcceptWith(*newclient, false)) {
142 newclient->Safe_Delete();
143 } else {
144 wxASSERT(theApp->IsRunning());
145 if (!newclient->InitNetworkData()) {
146 // IP or port were not returned correctly
147 // from the accepted address, or filtered.
148 newclient->Safe_Delete();
155 void CListenSocket::AddConnection()
157 m_OpenSocketsInterval++;
160 void CListenSocket::Process()
162 // 042e + Kry changes for Destroy
163 m_OpenSocketsInterval = 0;
164 SocketSet::iterator it = socket_list.begin();
165 while ( it != socket_list.end() ) {
166 CClientTCPSocket* cur_socket = *it++;
167 if (!cur_socket->OnDestroy()) {
168 if (cur_socket->ForDeletion()) {
169 cur_socket->Destroy();
170 } else {
171 cur_socket->CheckTimeOut();
176 if ((GetOpenSockets()+5 < thePrefs::GetMaxConnections() || theApp->serverconnect->IsConnecting()) && !bListening) {
177 ReStartListening();
181 void CListenSocket::RecalculateStats()
183 // 0.42e
184 memset(m_ConnectionStates,0,6);
185 for (SocketSet::iterator it = socket_list.begin(); it != socket_list.end(); ) {
186 CClientTCPSocket* cur_socket = *it++;
187 switch (cur_socket->GetConState()) {
188 case ES_DISCONNECTED:
189 m_ConnectionStates[0]++;
190 break;
191 case ES_NOTCONNECTED:
192 m_ConnectionStates[1]++;
193 break;
194 case ES_CONNECTED:
195 m_ConnectionStates[2]++;
196 break;
201 void CListenSocket::AddSocket(CClientTCPSocket* toadd)
203 wxASSERT(toadd);
204 socket_list.insert(toadd);
205 theStats::AddActiveConnection();
208 void CListenSocket::RemoveSocket(CClientTCPSocket* todel)
210 wxASSERT(todel);
211 socket_list.erase(todel);
212 theStats::RemoveActiveConnection();
215 void CListenSocket::KillAllSockets()
217 // 0.42e reviewed - they use delete, but our safer is Destroy...
218 // But I bet it would be better to call Safe_Delete on the socket.
219 // Update: no... Safe_Delete MARKS for deletion. We need to delete it.
220 for (SocketSet::iterator it = socket_list.begin(); it != socket_list.end(); ) {
221 CClientTCPSocket* cur_socket = *it++;
222 if (cur_socket->GetClient()) {
223 cur_socket->GetClient()->Safe_Delete();
224 } else {
225 cur_socket->Safe_Delete();
226 cur_socket->Destroy();
231 bool CListenSocket::TooManySockets(bool bIgnoreInterval)
233 if (GetOpenSockets() > thePrefs::GetMaxConnections() || (m_OpenSocketsInterval > (thePrefs::GetMaxConperFive()*GetMaxConperFiveModifier()) && !bIgnoreInterval)) {
234 return true;
235 } else {
236 return false;
240 bool CListenSocket::IsValidSocket(CClientTCPSocket* totest)
242 // 0.42e
243 return socket_list.find(totest) != socket_list.end();
247 void CListenSocket::UpdateConnectionsStatus()
249 // 0.42e xcept for the khaos stats
250 if( theApp->IsConnected() ) {
251 totalconnectionchecks++;
252 float percent;
253 percent = (float)(totalconnectionchecks-1)/(float)totalconnectionchecks;
254 if( percent > .99f ) {
255 percent = .99f;
257 averageconnections = (averageconnections*percent) + (float)GetOpenSockets()*(1.0f-percent);
262 float CListenSocket::GetMaxConperFiveModifier()
264 float SpikeSize = GetOpenSockets() - averageconnections;
265 if ( SpikeSize < 1 ) {
266 return 1;
269 float SpikeTolerance = 2.5f*thePrefs::GetMaxConperFive();
270 if ( SpikeSize > SpikeTolerance ) {
271 return 0;
274 return 1.0f - (SpikeSize/SpikeTolerance);
276 // File_checked_for_headers