View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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  
19  package org.eclipse.jetty.io.nio;
20  
21  import java.io.IOException;
22  import java.net.InetSocketAddress;
23  import java.net.Socket;
24  import java.net.SocketException;
25  import java.nio.ByteBuffer;
26  import java.nio.channels.ByteChannel;
27  import java.nio.channels.GatheringByteChannel;
28  import java.nio.channels.SelectableChannel;
29  import java.nio.channels.SocketChannel;
30  
31  import org.eclipse.jetty.io.Buffer;
32  import org.eclipse.jetty.io.EndPoint;
33  import org.eclipse.jetty.util.StringUtil;
34  import org.eclipse.jetty.util.log.Log;
35  import 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   */
42  public 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 }