1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 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.
10 //
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.
15 //
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
24 //
25 
26 #include "ListenSocket.h"	// Interface declarations
27 
28 #include <common/EventIDs.h>
29 
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 
37 //-----------------------------------------------------------------------------
38 // CListenSocket
39 //-----------------------------------------------------------------------------
40 //
41 // This is the socket that listens to incoming connections in aMule's TCP port
42 // As soon as a connection is detected, it creates a new socket of type
43 // CClientTCPSocket to handle (accept) the connection.
44 //
45 
CListenSocket(amuleIPV4Address & addr,const CProxyData * ProxyData)46 CListenSocket::CListenSocket(amuleIPV4Address &addr, const CProxyData *ProxyData)
47 :
48 // wxSOCKET_NOWAIT    - means non-blocking i/o
49 // wxSOCKET_REUSEADDR - means we can reuse the socket immediately (wx-2.5.3)
50 CSocketServerProxy(addr, MULE_SOCKET_NOWAIT|MULE_SOCKET_REUSEADDR, ProxyData)
51 {
52 	// 0.42e - vars not used by us
53 	m_pending = false;
54 	shutdown = false;
55 	m_OpenSocketsInterval = 0;
56 	totalconnectionchecks = 0;
57 	averageconnections = 0.0;
58 	memset(m_ConnectionStates, 0, 3 * sizeof(m_ConnectionStates[0]));
59 	// Set the listen socket event handler -- The handler is written in amule.cpp
60 	if (IsOk()) {
61 #ifndef ASIO_SOCKETS
62 		SetEventHandler(*theApp, ID_LISTENSOCKET_EVENT);
63 		SetNotify(wxSOCKET_CONNECTION_FLAG);
64 #endif
65 		Notify(true);
66 
67 		AddLogLineNS(_("ListenSocket: Ok."));
68 	} else {
69 		AddLogLineCS(_("ERROR: Could not listen to TCP port.") );
70 	}
71 }
72 
73 
~CListenSocket()74 CListenSocket::~CListenSocket()
75 {
76 	shutdown = true;
77 	Discard();
78 	Close();
79 
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)->IsDestroying());
84 	}
85 #endif
86 
87 	KillAllSockets();
88 }
89 
90 
OnAccept()91 void CListenSocket::OnAccept()
92 {
93 	m_pending = theApp->IsRunning();	// just do nothing if we are shutting down
94 	// If the client is still at maxconnections,
95 	// this will allow it to go above it ...
96 	// But if you don't, you will get a lowID on all servers.
97 	while (m_pending && (theApp->serverconnect->IsConnecting() || !TooManySockets())) {
98 		if (!SocketAvailable()) {
99 			m_pending = false;
100 		} else {
101 			// Create a new socket to deal with the connection
102 			CClientTCPSocket* newclient = new CClientTCPSocket();
103 			// Accept the connection and give it to the newly created socket
104 			if (!AcceptWith(*newclient, false)) {
105 				newclient->Safe_Delete();
106 				m_pending = false;
107 			} else {
108 				if (!newclient->InitNetworkData()) {
109 					// IP or port were not returned correctly
110 					// from the accepted address, or filtered.
111 					newclient->Safe_Delete();
112 				}
113 			}
114 		}
115 	}
116 	if (m_pending) {
117 		theStats::AddMaxConnectionLimitReached();
118 	}
119 }
120 
AddConnection()121 void CListenSocket::AddConnection()
122 {
123 	m_OpenSocketsInterval++;
124 }
125 
Process()126 void CListenSocket::Process()
127 {
128 	// 042e + Kry changes for Destroy
129 	m_OpenSocketsInterval = 0;
130 	SocketSet::iterator it = socket_list.begin();
131 	while ( it != socket_list.end() ) {
132 		CClientTCPSocket* cur_socket = *it++;
133 		if (!cur_socket->IsDestroying()) {
134 			cur_socket->CheckTimeOut();
135 		}
136 	}
137 
138 	if (m_pending) {
139 		OnAccept();
140 	}
141 }
142 
RecalculateStats()143 void CListenSocket::RecalculateStats()
144 {
145 	// 0.42e
146 	memset(m_ConnectionStates, 0, 3 * sizeof(m_ConnectionStates[0]));
147 	for (SocketSet::iterator it = socket_list.begin(); it != socket_list.end(); ) {
148 		CClientTCPSocket* cur_socket = *it++;
149 		switch (cur_socket->GetConState()) {
150 			case ES_DISCONNECTED:
151 				m_ConnectionStates[0]++;
152 				break;
153 			case ES_NOTCONNECTED:
154 				m_ConnectionStates[1]++;
155 				break;
156 			case ES_CONNECTED:
157 				m_ConnectionStates[2]++;
158 				break;
159 		}
160 	}
161 }
162 
AddSocket(CClientTCPSocket * toadd)163 void CListenSocket::AddSocket(CClientTCPSocket* toadd)
164 {
165 	wxASSERT(toadd);
166 	socket_list.insert(toadd);
167 	theStats::AddActiveConnection();
168 }
169 
RemoveSocket(CClientTCPSocket * todel)170 void CListenSocket::RemoveSocket(CClientTCPSocket* todel)
171 {
172 	wxASSERT(todel);
173 	socket_list.erase(todel);
174 	theStats::RemoveActiveConnection();
175 }
176 
KillAllSockets()177 void CListenSocket::KillAllSockets()
178 {
179 	// 0.42e reviewed - they use delete, but our safer is Destroy...
180 	// But I bet it would be better to call Safe_Delete on the socket.
181 	// Update: no... Safe_Delete MARKS for deletion. We need to delete it.
182 	for (SocketSet::iterator it = socket_list.begin(); it != socket_list.end(); ) {
183 		CClientTCPSocket* cur_socket = *it++;
184 		if (cur_socket->GetClient()) {
185 			cur_socket->Safe_Delete_Client();
186 		} else {
187 			cur_socket->Safe_Delete();
188 			cur_socket->Destroy();
189 		}
190 	}
191 }
192 
TooManySockets(bool bIgnoreInterval)193 bool CListenSocket::TooManySockets(bool bIgnoreInterval)
194 {
195 	if (GetOpenSockets() > thePrefs::GetMaxConnections()
196 		|| (!bIgnoreInterval && m_OpenSocketsInterval > (thePrefs::GetMaxConperFive() * GetMaxConperFiveModifier()))) {
197 		return true;
198 	} else {
199 		return false;
200 	}
201 }
202 
IsValidSocket(CClientTCPSocket * totest)203 bool CListenSocket::IsValidSocket(CClientTCPSocket* totest)
204 {
205 	// 0.42e
206 	return socket_list.find(totest) != socket_list.end();
207 }
208 
209 
UpdateConnectionsStatus()210 void CListenSocket::UpdateConnectionsStatus()
211 {
212 	// 0.42e xcept for the khaos stats
213 	if( theApp->IsConnected() ) {
214 		totalconnectionchecks++;
215 		float percent;
216 		percent = (float)(totalconnectionchecks-1)/(float)totalconnectionchecks;
217 		if( percent > .99f ) {
218 			percent = .99f;
219 		}
220 		averageconnections = (averageconnections*percent) + (float)GetOpenSockets()*(1.0f-percent);
221 	}
222 }
223 
224 
GetMaxConperFiveModifier()225 float CListenSocket::GetMaxConperFiveModifier()
226 {
227 	float SpikeSize = GetOpenSockets() - averageconnections;
228 	if ( SpikeSize < 1 ) {
229 		return 1;
230 	}
231 
232 	float SpikeTolerance = 2.5f * thePrefs::GetMaxConperFive();
233 	if ( SpikeSize > SpikeTolerance ) {
234 		return 0;
235 	}
236 
237 	return 1.0f - (SpikeSize/SpikeTolerance);
238 }
239 // File_checked_for_headers
240