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