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