View Javadoc

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