1// 2// ======================================================================== 3// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 4// ------------------------------------------------------------------------ 5// All rights reserved. This program and the accompanying materials 6// are made available under the terms of the Eclipse Public License v1.0 7// and Apache License v2.0 which accompanies this distribution. 8// 9// The Eclipse Public License is available at 10// http://www.eclipse.org/legal/epl-v10.html 11// 12// The Apache License v2.0 is available at 13// http://www.opensource.org/licenses/apache2.0.php 14// 15// You may elect to redistribute this code under either of these licenses. 16// ======================================================================== 17// 18 19package org.eclipse.jetty.io.nio; 20 21import java.io.IOException; 22import java.net.InetSocketAddress; 23import java.net.Socket; 24import java.net.SocketException; 25import java.nio.ByteBuffer; 26import java.nio.channels.ByteChannel; 27import java.nio.channels.GatheringByteChannel; 28import java.nio.channels.SelectableChannel; 29import java.nio.channels.SocketChannel; 30 31import org.eclipse.jetty.io.Buffer; 32import org.eclipse.jetty.io.EndPoint; 33import org.eclipse.jetty.util.StringUtil; 34import org.eclipse.jetty.util.log.Log; 35import org.eclipse.jetty.util.log.Logger; 36 37/** 38 * Channel End Point. 39 * <p>Holds the channel and socket for an NIO endpoint. 40 * 41 */ 42public class ChannelEndPoint implements EndPoint 43{ 44 private static final Logger LOG = Log.getLogger(ChannelEndPoint.class); 45 46 protected final ByteChannel _channel; 47 protected final ByteBuffer[] _gather2=new ByteBuffer[2]; 48 protected final Socket _socket; 49 protected final InetSocketAddress _local; 50 protected final InetSocketAddress _remote; 51 protected volatile int _maxIdleTime; 52 private volatile boolean _ishut; 53 private volatile boolean _oshut; 54 55 public ChannelEndPoint(ByteChannel channel) throws IOException 56 { 57 super(); 58 this._channel = channel; 59 _socket=(channel instanceof SocketChannel)?((SocketChannel)channel).socket():null; 60 if (_socket!=null) 61 { 62 _local=(InetSocketAddress)_socket.getLocalSocketAddress(); 63 _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); 64 _maxIdleTime=_socket.getSoTimeout(); 65 } 66 else 67 { 68 _local=_remote=null; 69 } 70 } 71 72 protected ChannelEndPoint(ByteChannel channel, int maxIdleTime) throws IOException 73 { 74 this._channel = channel; 75 _maxIdleTime=maxIdleTime; 76 _socket=(channel instanceof SocketChannel)?((SocketChannel)channel).socket():null; 77 if (_socket!=null) 78 { 79 _local=(InetSocketAddress)_socket.getLocalSocketAddress(); 80 _remote=(InetSocketAddress)_socket.getRemoteSocketAddress(); 81 _socket.setSoTimeout(_maxIdleTime); 82 } 83 else 84 { 85 _local=_remote=null; 86 } 87 } 88 89 public boolean isBlocking() 90 { 91 return !(_channel instanceof SelectableChannel) || ((SelectableChannel)_channel).isBlocking(); 92 } 93 94 public boolean blockReadable(long millisecs) throws IOException 95 { 96 return true; 97 } 98 99 public boolean blockWritable(long millisecs) throws IOException 100 { 101 return true; 102 } 103 104 /* 105 * @see org.eclipse.io.EndPoint#isOpen() 106 */ 107 public boolean isOpen() 108 { 109 return _channel.isOpen(); 110 } 111 112 /** Shutdown the channel Input. 113 * Cannot be overridden. To override, see {@link #shutdownInput()} 114 * @throws IOException 115 */ 116 protected final void shutdownChannelInput() throws IOException 117 { 118 LOG.debug("ishut {}", this); 119 _ishut = true; 120 if (_channel.isOpen()) 121 { 122 if (_socket != null) 123 { 124 try 125 { 126 if (!_socket.isInputShutdown()) 127 { 128 _socket.shutdownInput(); 129 } 130 } 131 catch (SocketException e) 132 { 133 LOG.debug(e.toString()); 134 LOG.ignore(e); 135 } 136 finally 137 { 138 if (_oshut) 139 { 140 close(); 141 } 142 } 143 } 144 } 145 } 146 147 /* (non-Javadoc) 148 * @see org.eclipse.io.EndPoint#close() 149 */ 150 public void shutdownInput() throws IOException 151 { 152 shutdownChannelInput(); 153 } 154 155 protected final void shutdownChannelOutput() throws IOException 156 { 157 LOG.debug("oshut {}",this); 158 _oshut = true; 159 if (_channel.isOpen()) 160 { 161 if (_socket != null) 162 { 163 try 164 { 165 if (!_socket.isOutputShutdown()) 166 { 167 _socket.shutdownOutput(); 168 } 169 } 170 catch (SocketException e) 171 { 172 LOG.debug(e.toString()); 173 LOG.ignore(e); 174 } 175 finally 176 { 177 if (_ishut) 178 { 179 close(); 180 } 181 } 182 } 183 } 184 } 185 186 /* (non-Javadoc) 187 * @see org.eclipse.io.EndPoint#close() 188 */ 189 public void shutdownOutput() throws IOException 190 { 191 shutdownChannelOutput(); 192 } 193 194 public boolean isOutputShutdown() 195 { 196 return _oshut || !_channel.isOpen() || _socket != null && _socket.isOutputShutdown(); 197 } 198 199 public boolean isInputShutdown() 200 { 201 return _ishut || !_channel.isOpen() || _socket != null && _socket.isInputShutdown(); 202 } 203 204 /* (non-Javadoc) 205 * @see org.eclipse.io.EndPoint#close() 206 */ 207 public void close() throws IOException 208 { 209 LOG.debug("close {}",this); 210 _channel.close(); 211 } 212 213 /* (non-Javadoc) 214 * @see org.eclipse.io.EndPoint#fill(org.eclipse.io.Buffer) 215 */ 216 public int fill(Buffer buffer) throws IOException 217 { 218 if (_ishut) 219 return -1; 220 Buffer buf = buffer.buffer(); 221 int len=0; 222 if (buf instanceof NIOBuffer) 223 { 224 final NIOBuffer nbuf = (NIOBuffer)buf; 225 final ByteBuffer bbuf=nbuf.getByteBuffer(); 226 227 //noinspection SynchronizationOnLocalVariableOrMethodParameter 228 try 229 { 230 synchronized(bbuf) 231 { 232 try 233 { 234 bbuf.position(buffer.putIndex()); 235 len=_channel.read(bbuf); 236 } 237 finally 238 { 239 buffer.setPutIndex(bbuf.position()); 240 bbuf.position(0); 241 } 242 } 243 244 if (len<0 && isOpen()) 245 { 246 if (!isInputShutdown()) 247 shutdownInput(); 248 if (isOutputShutdown()) 249 _channel.close(); 250 } 251 } 252 catch (IOException x) 253 { 254 LOG.debug("Exception while filling", x); 255 try 256 { 257 if (_channel.isOpen()) 258 _channel.close(); 259 } 260 catch (Exception xx) 261 { 262 LOG.ignore(xx); 263 } 264 265 if (len>0) 266 throw x; 267 len=-1; 268 } 269 } 270 else 271 { 272 throw new IOException("Not Implemented"); 273 } 274 275 return len; 276 } 277 278 /* (non-Javadoc) 279 * @see org.eclipse.io.EndPoint#flush(org.eclipse.io.Buffer) 280 */ 281 public int flush(Buffer buffer) throws IOException 282 { 283 Buffer buf = buffer.buffer(); 284 int len=0; 285 if (buf instanceof NIOBuffer) 286 { 287 final NIOBuffer nbuf = (NIOBuffer)buf; 288 final ByteBuffer bbuf=nbuf.getByteBuffer().asReadOnlyBuffer(); 289 try 290 { 291 bbuf.position(buffer.getIndex()); 292 bbuf.limit(buffer.putIndex()); 293 len=_channel.write(bbuf); 294 } 295 finally 296 { 297 if (len>0) 298 buffer.skip(len); 299 } 300 } 301 else if (buf instanceof RandomAccessFileBuffer) 302 { 303 len = ((RandomAccessFileBuffer)buf).writeTo(_channel,buffer.getIndex(),buffer.length()); 304 if (len>0) 305 buffer.skip(len); 306 } 307 else if (buffer.array()!=null) 308 { 309 ByteBuffer b = ByteBuffer.wrap(buffer.array(), buffer.getIndex(), buffer.length()); 310 len=_channel.write(b); 311 if (len>0) 312 buffer.skip(len); 313 } 314 else 315 { 316 throw new IOException("Not Implemented"); 317 } 318 return len; 319 } 320 321 /* (non-Javadoc) 322 * @see org.eclipse.io.EndPoint#flush(org.eclipse.io.Buffer, org.eclipse.io.Buffer, org.eclipse.io.Buffer) 323 */ 324 public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException 325 { 326 int length=0; 327 328 Buffer buf0 = header==null?null:header.buffer(); 329 Buffer buf1 = buffer==null?null:buffer.buffer(); 330 331 if (_channel instanceof GatheringByteChannel && 332 header!=null && header.length()!=0 && buf0 instanceof NIOBuffer && 333 buffer!=null && buffer.length()!=0 && buf1 instanceof NIOBuffer) 334 { 335 length = gatheringFlush(header,((NIOBuffer)buf0).getByteBuffer(),buffer,((NIOBuffer)buf1).getByteBuffer()); 336 } 337 else 338 { 339 // flush header 340 if (header!=null && header.length()>0) 341 length=flush(header); 342 343 // flush buffer 344 if ((header==null || header.length()==0) && 345 buffer!=null && buffer.length()>0) 346 length+=flush(buffer); 347 348 // flush trailer 349 if ((header==null || header.length()==0) && 350 (buffer==null || buffer.length()==0) && 351 trailer!=null && trailer.length()>0) 352 length+=flush(trailer); 353 } 354 355 return length; 356 } 357 358 protected int gatheringFlush(Buffer header, ByteBuffer bbuf0, Buffer buffer, ByteBuffer bbuf1) throws IOException 359 { 360 int length; 361 362 synchronized(this) 363 { 364 // Adjust position indexs of buf0 and buf1 365 bbuf0=bbuf0.asReadOnlyBuffer(); 366 bbuf0.position(header.getIndex()); 367 bbuf0.limit(header.putIndex()); 368 bbuf1=bbuf1.asReadOnlyBuffer(); 369 bbuf1.position(buffer.getIndex()); 370 bbuf1.limit(buffer.putIndex()); 371 372 _gather2[0]=bbuf0; 373 _gather2[1]=bbuf1; 374 375 // do the gathering write. 376 length=(int)((GatheringByteChannel)_channel).write(_gather2); 377 378 int hl=header.length(); 379 if (length>hl) 380 { 381 header.clear(); 382 buffer.skip(length-hl); 383 } 384 else if (length>0) 385 { 386 header.skip(length); 387 } 388 } 389 return length; 390 } 391 392 /* ------------------------------------------------------------ */ 393 /** 394 * @return Returns the channel. 395 */ 396 public ByteChannel getChannel() 397 { 398 return _channel; 399 } 400 401 402 /* ------------------------------------------------------------ */ 403 /* 404 * @see org.eclipse.io.EndPoint#getLocalAddr() 405 */ 406 public String getLocalAddr() 407 { 408 if (_socket==null) 409 return null; 410 if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress()) 411 return StringUtil.ALL_INTERFACES; 412 return _local.getAddress().getHostAddress(); 413 } 414 415 /* ------------------------------------------------------------ */ 416 /* 417 * @see org.eclipse.io.EndPoint#getLocalHost() 418 */ 419 public String getLocalHost() 420 { 421 if (_socket==null) 422 return null; 423 if (_local==null || _local.getAddress()==null || _local.getAddress().isAnyLocalAddress()) 424 return StringUtil.ALL_INTERFACES; 425 return _local.getAddress().getCanonicalHostName(); 426 } 427 428 /* ------------------------------------------------------------ */ 429 /* 430 * @see org.eclipse.io.EndPoint#getLocalPort() 431 */ 432 public int getLocalPort() 433 { 434 if (_socket==null) 435 return 0; 436 if (_local==null) 437 return -1; 438 return _local.getPort(); 439 } 440 441 /* ------------------------------------------------------------ */ 442 /* 443 * @see org.eclipse.io.EndPoint#getRemoteAddr() 444 */ 445 public String getRemoteAddr() 446 { 447 if (_socket==null) 448 return null; 449 if (_remote==null) 450 return null; 451 return _remote.getAddress().getHostAddress(); 452 } 453 454 /* ------------------------------------------------------------ */ 455 /* 456 * @see org.eclipse.io.EndPoint#getRemoteHost() 457 */ 458 public String getRemoteHost() 459 { 460 if (_socket==null) 461 return null; 462 if (_remote==null) 463 return null; 464 return _remote.getAddress().getCanonicalHostName(); 465 } 466 467 /* ------------------------------------------------------------ */ 468 /* 469 * @see org.eclipse.io.EndPoint#getRemotePort() 470 */ 471 public int getRemotePort() 472 { 473 if (_socket==null) 474 return 0; 475 return _remote==null?-1:_remote.getPort(); 476 } 477 478 /* ------------------------------------------------------------ */ 479 /* 480 * @see org.eclipse.io.EndPoint#getConnection() 481 */ 482 public Object getTransport() 483 { 484 return _channel; 485 } 486 487 /* ------------------------------------------------------------ */ 488 public void flush() 489 throws IOException 490 { 491 } 492 493 /* ------------------------------------------------------------ */ 494 public int getMaxIdleTime() 495 { 496 return _maxIdleTime; 497 } 498 499 /* ------------------------------------------------------------ */ 500 /** 501 * @see org.eclipse.jetty.io.bio.StreamEndPoint#setMaxIdleTime(int) 502 */ 503 public void setMaxIdleTime(int timeMs) throws IOException 504 { 505 if (_socket!=null && timeMs!=_maxIdleTime) 506 _socket.setSoTimeout(timeMs>0?timeMs:0); 507 _maxIdleTime=timeMs; 508 } 509} 510