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