view src/org/eclipse/jetty/io/nio/ChannelEndPoint.java @ 1070:a44fc6b53757

fix use of HttpGenerator._buffer
author Franklin Schmidt <fschmidt@gmail.com>
date Thu, 10 Nov 2016 01:23:37 -0700
parents 4a50422596b6
children ebb0f1343ef6
line wrap: on
line source

//
//  ========================================================================
//  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.io.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
import java.nio.channels.GatheringByteChannel;
import java.nio.channels.SocketChannel;

import org.eclipse.jetty.io.JBuffer;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Channel End Point.
 * <p>Holds the channel and socket for an NIO endpoint.
 *
 */
public class ChannelEndPoint implements EndPoint
{
	private static final Logger LOG = LoggerFactory.getLogger(ChannelEndPoint.class);

	private final SocketChannel _channel;
	protected final Socket _socket;
	private final InetSocketAddress _local;
	private final InetSocketAddress _remote;
	protected volatile int _maxIdleTime;
	private volatile boolean _ishut = false;
	private volatile boolean _oshut = false;

	protected ChannelEndPoint(SocketChannel channel, int maxIdleTime) throws IOException
	{
		this._channel = channel;
		_maxIdleTime = maxIdleTime;
		_socket = channel.socket();
		_local = (InetSocketAddress)_socket.getLocalSocketAddress();
		_remote = (InetSocketAddress)_socket.getRemoteSocketAddress();
		_socket.setSoTimeout(_maxIdleTime);
	}

	@Override
	public final boolean isBlocking()
	{
		return _channel.isBlocking();
	}

	@Override
	public boolean blockReadable(long millisecs) throws IOException
	{
		return true;
	}

	@Override
	public boolean blockWritable(long millisecs) throws IOException
	{
		return true;
	}

	@Override
	public final boolean isOpen()
	{
		return _channel.isOpen();
	}

	@Override
	public final void shutdownInput() throws IOException
	{
		LOG.debug("ishut {}", this);
		_ishut = true;
		if (_channel.isOpen())
		{
			try
			{
				if (!_socket.isInputShutdown())
				{
					_socket.shutdownInput();
				}
			}
			catch (SocketException e)
			{
				LOG.debug(e.toString());
				LOG.trace("",e);
			}
			finally
			{
				if (_oshut)
				{
					close();
				}
			}
		}
	}

	@Override
	public final void shutdownOutput() throws IOException
	{
		LOG.debug("oshut {}",this);
		_oshut = true;
		if (_channel.isOpen())
		{
			try
			{
				if (!_socket.isOutputShutdown())
				{
					_socket.shutdownOutput();
				}
			}
			catch (SocketException e)
			{
				LOG.debug(e.toString());
				LOG.trace("",e);
			}
			finally
			{
				if (_ishut)
				{
					close();
				}
			}
		}
	}

	@Override
	public final boolean isOutputShutdown()
	{
		return _oshut || !_channel.isOpen() || _socket.isOutputShutdown();
	}

	@Override
	public final boolean isInputShutdown()
	{
		return _ishut || !_channel.isOpen() || _socket.isInputShutdown();
	}

	@Override
	public void close() throws IOException
	{
//Thread.dumpStack();
		LOG.debug("close {}",this);
		_channel.close();
	}

	@Override
	public int fill(JBuffer buffer) throws IOException
	{
		if (_ishut)
			return -1;
		int len = 0;
		final ByteBuffer bbuf = buffer.getByteBuffer().duplicate();

		//noinspection SynchronizationOnLocalVariableOrMethodParameter
		try
		{
			bbuf.limit(bbuf.capacity());
			bbuf.position(buffer.limit());
			len = _channel.read(bbuf);
			buffer.limit(bbuf.position());

			if (len<0 && isOpen())
			{
				if (!isInputShutdown())
					shutdownInput();
				if (isOutputShutdown())
					_channel.close();
			}
		}
		catch (IOException x)
		{
			LOG.debug("Exception while filling", x);
			try
			{
				if (_channel.isOpen())
					_channel.close();
			}
			catch (Exception xx)
			{
				LOG.trace("",xx);
			}

			if (len>0)
				throw x;
			len = -1;
		}

		return len;
	}

	@Override
	public int flush(JBuffer buffer) throws IOException
	{
		final ByteBuffer bbuf = buffer.getByteBuffer();
		return _channel.write(bbuf);
	}

	@Override
	public int flush(JBuffer header, JBuffer buffer, JBuffer trailer) throws IOException
	{
		int length=0;

		if (_channel instanceof GatheringByteChannel &&
			header!=null && header.remaining()!=0 &&
			buffer!=null && buffer.remaining()!=0)
		{
			length = gatheringFlush(header,buffer);
		}
		else
		{
			// flush header
			if (header!=null && header.remaining()>0)
				length=flush(header);

			// flush buffer
			if ((header==null || header.remaining()==0) &&
				 buffer!=null && buffer.remaining()>0)
				length+=flush(buffer);

			// flush trailer
			if ((header==null || header.remaining()==0) &&
				(buffer==null || buffer.remaining()==0) &&
				 trailer!=null && trailer.remaining()>0)
				length+=flush(trailer);
		}

		return length;
	}

	private synchronized int gatheringFlush(JBuffer header, JBuffer buffer) throws IOException
	{
		ByteBuffer bbuf0 = header.getByteBuffer();
		ByteBuffer bbuf1 = buffer.getByteBuffer();
		return (int)_channel.write(new ByteBuffer[]{bbuf0,bbuf1});
	}

	public final SocketChannel getChannel()
	{
		return _channel;
	}

	@Override
	public final String getLocalAddr()
	{
	   if (_local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
		   return StringUtil.ALL_INTERFACES;
		return _local.getAddress().getHostAddress();
	}

	@Override
	public final String getLocalHost()
	{
	   if (_local.getAddress()==null || _local.getAddress().isAnyLocalAddress())
		   return StringUtil.ALL_INTERFACES;
		return _local.getAddress().getCanonicalHostName();
	}

	@Override
	public final int getLocalPort()
	{
		return _local.getPort();
	}

	@Override
	public final String getRemoteAddr()
	{
		return _remote.getAddress().getHostAddress();
	}

	@Override
	public final String getRemoteHost()
	{
		return _remote.getAddress().getCanonicalHostName();
	}

	@Override
	public final int getRemotePort()
	{
		return _remote.getPort();
	}

	@Override
	public void flush()
		throws IOException
	{
	}

	@Override
	public final int getMaxIdleTime()
	{
		return _maxIdleTime;
	}

	@Override
	public void setMaxIdleTime(int timeMs) throws IOException
	{
		if (timeMs!=_maxIdleTime)
			_socket.setSoTimeout(timeMs>0?timeMs:0);
		_maxIdleTime=timeMs;
	}
}