PageRenderTime 47ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/azureus-4.7.0.2/com/aelitis/azureus/core/networkmanager/impl/tcp/TCPTransportHelper.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 660 lines | 434 code | 154 blank | 72 comment | 60 complexity | ccf8d97849c6a5cbf29e8a1093e5a95d MD5 | raw file
  1. /*
  2. * Created on Nov 1, 2005
  3. * Created by Alon Rohter
  4. * Copyright (C) 2005, 2006 Aelitis, All Rights Reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. *
  18. * AELITIS, SAS au capital de 46,603.30 euros
  19. * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
  20. *
  21. */
  22. package com.aelitis.azureus.core.networkmanager.impl.tcp;
  23. import java.io.IOException;
  24. import java.net.InetSocketAddress;
  25. import java.net.SocketException;
  26. import java.nio.ByteBuffer;
  27. import java.nio.channels.SocketChannel;
  28. import java.util.*;
  29. import org.gudy.azureus2.core3.logging.*;
  30. import org.gudy.azureus2.core3.util.*;
  31. import com.aelitis.azureus.core.networkmanager.VirtualChannelSelector;
  32. import com.aelitis.azureus.core.networkmanager.VirtualChannelSelector.VirtualSelectorListener;
  33. import com.aelitis.azureus.core.networkmanager.impl.TransportHelper;
  34. /**
  35. *
  36. */
  37. public class
  38. TCPTransportHelper
  39. implements TransportHelper
  40. {
  41. public static final int READ_TIMEOUT = 10*1000;
  42. public static final int CONNECT_TIMEOUT = 20*1000;
  43. public static final int MAX_PARTIAL_WRITE_RETAIN = 64; // aim here is to catch headers
  44. private long remainingBytesToScatter = 0;
  45. private static boolean enable_efficient_io = !Constants.JAVA_VERSION.startsWith("1.4");
  46. private final SocketChannel channel;
  47. private ByteBuffer delayed_write;
  48. private Map user_data;
  49. private boolean trace;
  50. private volatile boolean closed;
  51. public TCPTransportHelper( SocketChannel _channel ) {
  52. channel = _channel;
  53. }
  54. public InetSocketAddress
  55. getAddress()
  56. {
  57. return( new InetSocketAddress( channel.socket().getInetAddress(), channel.socket().getPort()));
  58. }
  59. public String
  60. getName(boolean verbose)
  61. {
  62. // default is TCP so don't clutter up views with this info
  63. if ( verbose ){
  64. return( "TCP" );
  65. }else{
  66. return( "" );
  67. }
  68. }
  69. public boolean
  70. minimiseOverheads()
  71. {
  72. return( false );
  73. }
  74. public int
  75. getConnectTimeout()
  76. {
  77. return( CONNECT_TIMEOUT );
  78. }
  79. public int
  80. getReadTimeout()
  81. {
  82. return( READ_TIMEOUT );
  83. }
  84. public boolean
  85. delayWrite(
  86. ByteBuffer buffer)
  87. {
  88. if ( delayed_write != null ){
  89. Debug.out( "secondary delayed write" );
  90. return( false );
  91. }
  92. delayed_write = buffer;
  93. return( true );
  94. }
  95. public boolean
  96. hasDelayedWrite()
  97. {
  98. return( delayed_write != null );
  99. }
  100. public int
  101. write(
  102. ByteBuffer buffer,
  103. boolean partial_write )
  104. throws IOException
  105. {
  106. if ( channel == null ){
  107. Debug.out( "channel == null" );
  108. return 0;
  109. }
  110. // partial-write means we are guaranteed to get hit with another write straight away
  111. if ( partial_write && delayed_write == null ){
  112. if ( buffer.remaining() < MAX_PARTIAL_WRITE_RETAIN ){
  113. ByteBuffer copy = ByteBuffer.allocate( buffer.remaining());
  114. copy.put( buffer );
  115. copy.position( 0 );
  116. delayed_write = copy;
  117. return( copy.remaining());
  118. }
  119. }
  120. long written = 0;
  121. if ( delayed_write != null ){
  122. // System.out.println( "delayed write: single" );
  123. ByteBuffer[] buffers = new ByteBuffer[]{ delayed_write, buffer };
  124. int delay_remaining = delayed_write.remaining();
  125. delayed_write = null;
  126. written = write( buffers, 0, 2 );
  127. // note that we can't report delayed bytes actually written as these have already been accounted for and confuse
  128. // the layers above if we report them now
  129. if ( buffers[0].hasRemaining()){
  130. delayed_write = buffers[0];
  131. written = 0;
  132. // System.out.println( "delayed write: single incomp" );
  133. }else{
  134. written -= delay_remaining;
  135. }
  136. }else{
  137. // log( buffer );
  138. written = channelWrite(buffer);
  139. }
  140. if ( trace ){
  141. TimeFormatter.milliTrace( "tcp: write " + written );
  142. }
  143. return((int)written );
  144. }
  145. public long
  146. write(
  147. ByteBuffer[] buffers,
  148. int array_offset,
  149. int length )
  150. throws IOException
  151. {
  152. if( channel == null ){
  153. Debug.out( "channel == null" );
  154. return 0;
  155. }
  156. long written_sofar = 0;
  157. if ( delayed_write != null ){
  158. ByteBuffer[] buffers2 = new ByteBuffer[length+1];
  159. buffers2[0] = delayed_write;
  160. int pos = 1;
  161. for (int i=array_offset;i<array_offset+length;i++){
  162. buffers2[pos++] = buffers[i];
  163. }
  164. // System.out.println( "delayed write: mult (" + buffers2.length + ")" );
  165. int delay_remaining = delayed_write.remaining();
  166. delayed_write = null;
  167. written_sofar = write( buffers2, 0, buffers2.length );
  168. if ( buffers2[0].hasRemaining()){
  169. delayed_write = buffers2[0];
  170. written_sofar = 0;
  171. // System.out.println( "delayed write: mult incomp" );
  172. }else{
  173. written_sofar -= delay_remaining;
  174. }
  175. }else{
  176. // log( buffers, array_offset, length );
  177. if ( enable_efficient_io && remainingBytesToScatter < 1 ){
  178. try{
  179. written_sofar = channel.write( buffers, array_offset, length );
  180. }catch( IOException ioe ) {
  181. //a bug only fixed in Tiger (1.5 series):
  182. //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4854354
  183. String msg = ioe.getMessage();
  184. if( msg != null && msg.equals( "A non-blocking socket operation could not be completed immediately" ) ) {
  185. enable_efficient_io = false;
  186. Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_WARNING,
  187. "WARNING: Multi-buffer socket write failed; "
  188. + "switching to single-buffer mode.\n"
  189. + "Upgrade to JRE 1.5 (5.0) series to fix this problem!"));
  190. }
  191. throw ioe;
  192. }
  193. }else{
  194. //single-buffer mode
  195. for( int i=array_offset; i < (array_offset + length); i++ ) {
  196. int data_length = buffers[ i ].remaining();
  197. int written = channelWrite(buffers[i]);
  198. written_sofar += written;
  199. if( written < data_length ) {
  200. break;
  201. }
  202. }
  203. }
  204. }
  205. if ( trace ){
  206. TimeFormatter.milliTrace( "tcp: write " + written_sofar );
  207. }
  208. return written_sofar;
  209. }
  210. private static final Random rnd = new Random();
  211. private int channelWrite(ByteBuffer buf) throws IOException
  212. {
  213. int written = 0;
  214. while(remainingBytesToScatter > 0 && buf.remaining() > 0)
  215. {
  216. int currentWritten = channel.write((ByteBuffer)(buf.slice().limit(Math.min(50+rnd.nextInt(100),buf.remaining()))));
  217. if(currentWritten == 0)
  218. break;
  219. buf.position(buf.position()+currentWritten);
  220. remainingBytesToScatter -= currentWritten;
  221. if(remainingBytesToScatter <= 0)
  222. {
  223. remainingBytesToScatter = 0;
  224. try
  225. {
  226. channel.socket().setTcpNoDelay(false);
  227. } catch (SocketException e)
  228. {
  229. Debug.printStackTrace(e);
  230. }
  231. }
  232. written += currentWritten;
  233. }
  234. if(buf.remaining() > 0)
  235. written += channel.write(buf);
  236. return written;
  237. }
  238. public int
  239. read(
  240. ByteBuffer buffer )
  241. throws IOException
  242. {
  243. if( channel == null ) {
  244. Debug.out( "channel == null" );
  245. return 0;
  246. }
  247. int res = channel.read( buffer );
  248. if ( trace ){
  249. TimeFormatter.milliTrace( "tcp: read " + res );
  250. }
  251. return( res );
  252. }
  253. public long
  254. read(
  255. ByteBuffer[] buffers,
  256. int array_offset,
  257. int length )
  258. throws IOException
  259. {
  260. if( channel == null ) {
  261. Debug.out( "channel == null" );
  262. return 0;
  263. }
  264. if( buffers == null ) {
  265. Debug.out( "read: buffers == null" );
  266. return 0;
  267. }
  268. long bytes_read = 0;
  269. if( enable_efficient_io ) {
  270. try{
  271. bytes_read = channel.read( buffers, array_offset, length );
  272. }
  273. catch( IOException ioe ) {
  274. //a bug only fixed in Tiger (1.5 series):
  275. //http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4854354
  276. String msg = ioe.getMessage();
  277. if( msg != null && msg.equals( "A non-blocking socket operation could not be completed immediately" ) ) {
  278. enable_efficient_io = false;
  279. Logger.log(new LogAlert(LogAlert.UNREPEATABLE, LogAlert.AT_WARNING,
  280. "WARNING: Multi-buffer socket read failed; switching to single-buffer mode.\n"
  281. + "Upgrade to JRE 1.5 (5.0) series to fix this problem!"));
  282. }
  283. throw ioe;
  284. }
  285. }else{
  286. //single-buffer mode
  287. for( int i=array_offset; i < (array_offset + length); i++ ) {
  288. int data_length = buffers[ i ].remaining();
  289. int read = channel.read( buffers[ i ] );
  290. bytes_read += read;
  291. if( read < data_length ) {
  292. break;
  293. }
  294. }
  295. }
  296. if ( bytes_read < 0 ){
  297. throw new IOException( "end of stream on socket read" );
  298. }
  299. if ( trace ){
  300. TimeFormatter.milliTrace( "tcp: read " + bytes_read );
  301. }
  302. return bytes_read;
  303. }
  304. public void
  305. registerForReadSelects(
  306. final selectListener listener,
  307. Object attachment )
  308. {
  309. TCPNetworkManager.getSingleton().getReadSelector().register(
  310. channel,
  311. new VirtualSelectorListener()
  312. {
  313. public boolean
  314. selectSuccess(
  315. VirtualChannelSelector selector,
  316. SocketChannel sc,
  317. Object attachment )
  318. {
  319. return( listener.selectSuccess( TCPTransportHelper.this, attachment ));
  320. }
  321. public void
  322. selectFailure(
  323. VirtualChannelSelector selector,
  324. SocketChannel sc,
  325. Object attachment,
  326. Throwable msg)
  327. {
  328. listener.selectFailure( TCPTransportHelper.this, attachment, msg );
  329. }
  330. },
  331. attachment );
  332. }
  333. public void
  334. registerForWriteSelects(
  335. final selectListener listener,
  336. Object attachment )
  337. {
  338. TCPNetworkManager.getSingleton().getWriteSelector().register(
  339. channel,
  340. new VirtualSelectorListener()
  341. {
  342. public boolean
  343. selectSuccess(
  344. VirtualChannelSelector selector,
  345. SocketChannel sc,
  346. Object attachment )
  347. {
  348. if ( trace ){
  349. TimeFormatter.milliTrace( "tcp: write select" );
  350. }
  351. return( listener.selectSuccess( TCPTransportHelper.this, attachment ));
  352. }
  353. public void
  354. selectFailure(
  355. VirtualChannelSelector selector,
  356. SocketChannel sc,
  357. Object attachment,
  358. Throwable msg)
  359. {
  360. listener.selectFailure( TCPTransportHelper.this, attachment, msg );
  361. }
  362. },
  363. attachment );
  364. }
  365. public void
  366. cancelReadSelects()
  367. {
  368. TCPNetworkManager.getSingleton().getReadSelector().cancel( channel );
  369. }
  370. public void
  371. cancelWriteSelects()
  372. {
  373. if ( trace ){
  374. TimeFormatter.milliTrace( "tcp: cancel write selects" );
  375. }
  376. TCPNetworkManager.getSingleton().getWriteSelector().cancel( channel );
  377. }
  378. public void
  379. resumeReadSelects()
  380. {
  381. TCPNetworkManager.getSingleton().getReadSelector().resumeSelects( channel );
  382. }
  383. public void
  384. resumeWriteSelects()
  385. {
  386. if ( trace ){
  387. TimeFormatter.milliTrace( "tcp: resume write selects" );
  388. }
  389. TCPNetworkManager.getSingleton().getWriteSelector().resumeSelects( channel );
  390. }
  391. public void
  392. pauseReadSelects()
  393. {
  394. TCPNetworkManager.getSingleton().getReadSelector().pauseSelects( channel );
  395. }
  396. public void
  397. pauseWriteSelects()
  398. {
  399. if ( trace ){
  400. TimeFormatter.milliTrace( "tcp: pause write selects" );
  401. }
  402. TCPNetworkManager.getSingleton().getWriteSelector().pauseSelects( channel );
  403. }
  404. public boolean
  405. isClosed()
  406. {
  407. return( closed );
  408. }
  409. public void
  410. close( String reason )
  411. {
  412. closed = true;
  413. TCPNetworkManager.getSingleton().getReadSelector().cancel( channel );
  414. TCPNetworkManager.getSingleton().getWriteSelector().cancel( channel );
  415. TCPNetworkManager.getSingleton().getConnectDisconnectManager().closeConnection( channel );
  416. }
  417. public void
  418. failed(
  419. Throwable reason )
  420. {
  421. close( Debug.getNestedExceptionMessage( reason ));
  422. }
  423. public SocketChannel getSocketChannel(){ return channel; }
  424. public synchronized void
  425. setUserData(
  426. Object key,
  427. Object data )
  428. {
  429. if ( user_data == null ){
  430. user_data = new HashMap();
  431. }
  432. user_data.put( key, data );
  433. }
  434. public synchronized Object
  435. getUserData(
  436. Object key )
  437. {
  438. if ( user_data == null ){
  439. return(null);
  440. }
  441. return( user_data.get( key ));
  442. }
  443. /*
  444. protected void
  445. log(
  446. ByteBuffer[] buffers,
  447. int array_offset,
  448. int length )
  449. {
  450. System.out.println( "Writing group of " + length );
  451. for( int i=array_offset; i < (array_offset + length); i++ ) {
  452. log( buffers[i]);
  453. }
  454. }
  455. protected void
  456. log(
  457. ByteBuffer buffer )
  458. {
  459. int position = buffer.position();
  460. int rem = buffer.remaining();
  461. byte[] temp = new byte[rem>64?64:rem];
  462. buffer.get( temp );
  463. buffer.position( position );
  464. System.out.println( " writing " + rem + ": " + new String(temp));
  465. }
  466. */
  467. public void
  468. setTrace(
  469. boolean on )
  470. {
  471. trace = on;
  472. }
  473. public void setScatteringMode(long forBytes) {
  474. if(forBytes > 0)
  475. {
  476. if(remainingBytesToScatter == 0)
  477. try
  478. {
  479. channel.socket().setTcpNoDelay(true);
  480. } catch (SocketException e)
  481. {
  482. Debug.printStackTrace(e);
  483. }
  484. remainingBytesToScatter = forBytes;
  485. } else
  486. {
  487. if(remainingBytesToScatter > 0)
  488. try
  489. {
  490. channel.socket().setTcpNoDelay(false);
  491. } catch (SocketException e)
  492. {
  493. Debug.printStackTrace(e);
  494. }
  495. remainingBytesToScatter = 0;
  496. }
  497. }
  498. }