1 /*
2  * File    : TRTrackerServerFactoryImpl.java
3  * Created : 13-Dec-2003
4  * By      : parg
5  *
6  * Azureus - a Java Bittorrent client
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details ( see the LICENSE file ).
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22 
23 package org.gudy.azureus2.core3.tracker.server.impl;
24 
25 /**
26  * @author parg
27  *
28  */
29 
30 import java.io.ByteArrayOutputStream;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.net.InetAddress;
34 import java.net.InetSocketAddress;
35 import java.nio.channels.SocketChannel;
36 import java.util.*;
37 
38 import org.gudy.azureus2.core3.config.COConfigurationManager;
39 import org.gudy.azureus2.core3.tracker.server.*;
40 import org.gudy.azureus2.core3.tracker.server.impl.dht.TRTrackerServerDHT;
41 import org.gudy.azureus2.core3.tracker.server.impl.tcp.TRTrackerServerTCP;
42 import org.gudy.azureus2.core3.tracker.server.impl.tcp.blocking.TRBlockingServer;
43 import org.gudy.azureus2.core3.tracker.server.impl.tcp.nonblocking.TRNonBlockingServer;
44 import org.gudy.azureus2.core3.tracker.server.impl.tcp.nonblocking.TRNonBlockingServerProcessor;
45 import org.gudy.azureus2.core3.tracker.server.impl.tcp.nonblocking.TRNonBlockingServerProcessorFactory;
46 import org.gudy.azureus2.core3.tracker.server.impl.udp.*;
47 import org.gudy.azureus2.core3.util.AEMonitor;
48 import org.gudy.azureus2.core3.util.AsyncController;
49 import org.gudy.azureus2.plugins.tracker.Tracker;
50 
51 import com.aelitis.azureus.core.stats.AzureusCoreStats;
52 import com.aelitis.azureus.core.stats.AzureusCoreStatsProvider;
53 import com.aelitis.azureus.core.util.CopyOnWriteList;
54 
55 public class
56 TRTrackerServerFactoryImpl
57 {
58 	protected static CopyOnWriteList		servers		= new CopyOnWriteList();
59 
60 	protected static List		listeners 	= new ArrayList();
61 	protected static AEMonitor 	class_mon 	= new AEMonitor( "TRTrackerServerFactory" );
62 
63 	static{
64 		Set	types = new HashSet();
65 
66 		types.add( AzureusCoreStats.ST_TRACKER_READ_BYTES );
67 		types.add( AzureusCoreStats.ST_TRACKER_WRITE_BYTES );
68 		types.add( AzureusCoreStats.ST_TRACKER_ANNOUNCE_COUNT );
69 		types.add( AzureusCoreStats.ST_TRACKER_ANNOUNCE_TIME );
70 		types.add( AzureusCoreStats.ST_TRACKER_SCRAPE_COUNT );
71 		types.add( AzureusCoreStats.ST_TRACKER_SCRAPE_TIME );
72 
AzureusCoreStats.registerProvider( types, new AzureusCoreStatsProvider() { public void updateStats( Set types, Map values ) { long read_bytes = 0; long write_bytes = 0; long announce_count = 0; long announce_time = 0; long scrape_count = 0; long scrape_time = 0; Iterator it = servers.iterator(); while( it.hasNext()){ TRTrackerServerStats stats = ((TRTrackerServer)it.next()).getStats(); read_bytes += stats.getBytesIn(); write_bytes += stats.getBytesOut(); announce_count += stats.getAnnounceCount(); announce_time += stats.getAnnounceTime(); scrape_count += stats.getScrapeCount(); scrape_time += stats.getScrapeTime(); } if ( types.contains( AzureusCoreStats.ST_TRACKER_READ_BYTES )){ values.put( AzureusCoreStats.ST_TRACKER_READ_BYTES, new Long( read_bytes )); } if ( types.contains( AzureusCoreStats.ST_TRACKER_WRITE_BYTES )){ values.put( AzureusCoreStats.ST_TRACKER_WRITE_BYTES, new Long( write_bytes )); } if ( types.contains( AzureusCoreStats.ST_TRACKER_ANNOUNCE_COUNT )){ values.put( AzureusCoreStats.ST_TRACKER_ANNOUNCE_COUNT, new Long( announce_count )); } if ( types.contains( AzureusCoreStats.ST_TRACKER_ANNOUNCE_TIME )){ values.put( AzureusCoreStats.ST_TRACKER_ANNOUNCE_TIME, new Long( announce_time )); } if ( types.contains( AzureusCoreStats.ST_TRACKER_SCRAPE_COUNT )){ values.put( AzureusCoreStats.ST_TRACKER_SCRAPE_COUNT, new Long( scrape_count )); } if ( types.contains( AzureusCoreStats.ST_TRACKER_SCRAPE_TIME )){ values.put( AzureusCoreStats.ST_TRACKER_SCRAPE_TIME, new Long( scrape_time )); } } })73 		AzureusCoreStats.registerProvider(
74 			types,
75 			new AzureusCoreStatsProvider()
76 			{
77 				public void
78 				updateStats(
79 					Set		types,
80 					Map		values )
81 				{
82 					long	read_bytes		= 0;
83 					long	write_bytes		= 0;
84 					long	announce_count	= 0;
85 					long	announce_time	= 0;
86 					long	scrape_count	= 0;
87 					long	scrape_time		= 0;
88 
89 					Iterator it = servers.iterator();
90 
91 					while( it.hasNext()){
92 
93 						TRTrackerServerStats stats = ((TRTrackerServer)it.next()).getStats();
94 
95 						read_bytes		+= stats.getBytesIn();
96 						write_bytes		+= stats.getBytesOut();
97 						announce_count 	+= stats.getAnnounceCount();
98 						announce_time	+= stats.getAnnounceTime();
99 						scrape_count 	+= stats.getScrapeCount();
100 						scrape_time		+= stats.getScrapeTime();
101 					}
102 
103 					if ( types.contains( AzureusCoreStats.ST_TRACKER_READ_BYTES )){
104 
105 						values.put( AzureusCoreStats.ST_TRACKER_READ_BYTES, new Long( read_bytes ));
106 					}
107 					if ( types.contains( AzureusCoreStats.ST_TRACKER_WRITE_BYTES )){
108 
109 						values.put( AzureusCoreStats.ST_TRACKER_WRITE_BYTES, new Long( write_bytes ));
110 					}
111 					if ( types.contains( AzureusCoreStats.ST_TRACKER_ANNOUNCE_COUNT )){
112 
113 						values.put( AzureusCoreStats.ST_TRACKER_ANNOUNCE_COUNT, new Long( announce_count ));
114 					}
115 					if ( types.contains( AzureusCoreStats.ST_TRACKER_ANNOUNCE_TIME )){
116 
117 						values.put( AzureusCoreStats.ST_TRACKER_ANNOUNCE_TIME, new Long( announce_time ));
118 					}
119 					if ( types.contains( AzureusCoreStats.ST_TRACKER_SCRAPE_COUNT )){
120 
121 						values.put( AzureusCoreStats.ST_TRACKER_SCRAPE_COUNT, new Long( scrape_count ));
122 					}
123 					if ( types.contains( AzureusCoreStats.ST_TRACKER_SCRAPE_TIME )){
124 
125 						values.put( AzureusCoreStats.ST_TRACKER_SCRAPE_TIME, new Long( scrape_time ));
126 					}
127 				}
128 			});
129 	}
130 
131 	public static TRTrackerServer
create( String name, int protocol, int port, InetAddress bind_ip, boolean ssl, boolean apply_ip_filter, boolean main_tracker, boolean start_up_ready, Map<String,Object> properties )132 	create(
133 		String					name,
134 		int						protocol,
135 		int						port,
136 		InetAddress				bind_ip,
137 		boolean					ssl,
138 		boolean					apply_ip_filter,
139 		boolean					main_tracker,
140 		boolean					start_up_ready,
141 		Map<String,Object>		properties )
142 
143 		throws TRTrackerServerException
144 	{
145 		if ( properties == null ){
146 
147 			properties = new HashMap<String, Object>();
148 		}
149 
150 		Boolean	pr_non_blocking = (Boolean)properties.get(Tracker.PR_NON_BLOCKING );
151 
152 		try{
153 			class_mon.enter();
154 
155 			TRTrackerServerImpl	server;
156 
157 			if ( protocol == TRTrackerServerFactory.PR_TCP ){
158 
159 				boolean explicit_non_blocking = pr_non_blocking != null && pr_non_blocking;
160 
161 				boolean non_blocking =
162 						( COConfigurationManager.getBooleanParameter( "Tracker TCP NonBlocking" ) && main_tracker ) ||
163 						( explicit_non_blocking );
164 
165 				if ( non_blocking && !ssl ){
166 
167 					TRNonBlockingServer nb_server =
168 						new TRNonBlockingServer(
169 							name,
170 							port,
171 							bind_ip,
172 							apply_ip_filter,
173 							start_up_ready,
174 							new TRNonBlockingServerProcessorFactory()
175 							{
176 								public TRNonBlockingServerProcessor
177 								create(
178 									TRTrackerServerTCP		_server,
179 									SocketChannel			_socket )
180 								{
181 									return( new NonBlockingProcessor( _server, _socket ));
182 
183 								}
184 							});
185 
186 					server = nb_server;
187 
188 					if ( explicit_non_blocking ){
189 
190 						nb_server.setRestrictNonBlocking( false );
191 					}
192 				}else{
193 
194 					server = new TRBlockingServer( name, port, bind_ip, ssl, apply_ip_filter, start_up_ready );
195 				}
196 
197 			}else if ( protocol == TRTrackerServerFactory.PR_UDP ){
198 
199 				if ( ssl ){
200 
201 					throw( new TRTrackerServerException( "TRTrackerServerFactory: UDP doesn't support SSL"));
202 				}
203 
204 				server = new TRTrackerServerUDP( name, port, start_up_ready );
205 
206 			}else{
207 
208 				server = new TRTrackerServerDHT( name, start_up_ready );
209 			}
210 
211 			servers.add( server );
212 
213 			for (int i=0;i<listeners.size();i++){
214 
215 				((TRTrackerServerFactoryListener)listeners.get(i)).serverCreated( server );
216 			}
217 
218 			return( server );
219 
220 		}finally{
221 
222 			class_mon.exit();
223 		}
224 	}
225 
226 	protected static void
close( TRTrackerServerImpl server )227 	close(
228 		TRTrackerServerImpl	server )
229 	{
230 		try{
231 			class_mon.enter();
232 
233 			server.closeSupport();
234 
235 			if ( servers.remove( server )){
236 
237 				for (int i=0;i<listeners.size();i++){
238 
239 					((TRTrackerServerFactoryListener)listeners.get(i)).serverDestroyed( server );
240 				}
241 			}
242 		}finally{
243 
244 			class_mon.exit();
245 		}
246 	}
247 
248 	public static void
addListener( TRTrackerServerFactoryListener l )249 	addListener(
250 		TRTrackerServerFactoryListener	l )
251 	{
252 		try{
253 			class_mon.enter();
254 
255 			listeners.add( l );
256 
257 			Iterator it = servers.iterator();
258 
259 			while( it.hasNext()){
260 
261 				l.serverCreated((TRTrackerServer)it.next());
262 			}
263 		}finally{
264 
265 			class_mon.exit();
266 		}
267 	}
268 
269 	public static void
removeListener( TRTrackerServerFactoryListener l )270 	removeListener(
271 		TRTrackerServerFactoryListener	l )
272 	{
273 		try{
274 			class_mon.enter();
275 
276 			listeners.remove( l );
277 
278 		}finally{
279 
280 			class_mon.exit();
281 		}
282 	}
283 
284 	protected static class
285 	NonBlockingProcessor
286 		extends TRNonBlockingServerProcessor
287 	{
288 		protected
NonBlockingProcessor( TRTrackerServerTCP _server, SocketChannel _socket )289 		NonBlockingProcessor(
290 			TRTrackerServerTCP		_server,
291 			SocketChannel			_socket )
292 		{
293 			super( _server, _socket );
294 		}
295 
296 		protected ByteArrayOutputStream
process( String input_header, String lowercase_input_header, String url_path, InetSocketAddress remote_address, boolean announce_and_scrape_only, InputStream is, AsyncController async )297 		process(
298 			String 				input_header,
299 			String 				lowercase_input_header,
300 			String 				url_path,
301 			InetSocketAddress 	remote_address,
302 			boolean 			announce_and_scrape_only,
303 			InputStream 		is,
304 			AsyncController		async )
305 
306 			throws IOException
307 		{
308 			ByteArrayOutputStream	os = new ByteArrayOutputStream( 1024 );
309 
310 			InetSocketAddress	local_address = null;	// TODO
311 
312 			processRequest(input_header, lowercase_input_header, url_path, local_address, remote_address, announce_and_scrape_only, false, is, os, async );
313 
314 			return( os );
315 		}
316 	}
317 }
318