com.caucho.vfs.SocketChannelStream Maven / Gradle / Ivy
Show all versions of resin-kernel Show documentation
/*
* Copyright (c) 1998-2012 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
* Free SoftwareFoundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.vfs;
import java.io.InterruptedIOException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.logging.*;
import com.caucho.inject.Module;
/**
* Specialized stream to handle sockets.
*
* Unlike VfsStream, when the read() throws and IOException or
* a SocketException, SocketStream will throw a ClientDisconnectException.
*/
@Module
public class SocketChannelStream extends StreamImpl {
private static final Logger log
= Logger.getLogger(SocketChannelStream.class.getName());
private static byte []UNIX_NEWLINE = new byte[] { (byte) '\n' };
private SocketChannel _channel;
private ByteBuffer _readBuffer;
private ByteBuffer _writeBuffer;
private boolean _needsFlush;
private byte []_newline = UNIX_NEWLINE;
private boolean _throwReadInterrupts = false;
private long _totalReadBytes;
private long _totalWriteBytes;
public SocketChannelStream()
{
_readBuffer = ByteBuffer.allocateDirect(TempBuffer.SIZE);
_writeBuffer = ByteBuffer.allocateDirect(TempBuffer.SIZE);
}
public SocketChannelStream(SocketChannel channel)
{
this();
init(channel);
}
/**
* Initialize the SocketStream with a new Socket.
*
* @param s the new socket.
*/
public void init(SocketChannel channel)
{
_channel = channel;
_readBuffer.clear();
_readBuffer.flip();
_needsFlush = false;
}
/**
* If true, throws read interrupts instead of returning an end of
* fail. Defaults to false.
*/
public void setThrowReadInterrupts(boolean allowThrow)
{
_throwReadInterrupts = allowThrow;
}
/**
* If true, throws read interrupts instead of returning an end of
* fail. Defaults to false.
*/
public boolean getThrowReadInterrupts()
{
return _throwReadInterrupts;
}
public void setNewline(byte []newline)
{
_newline = newline;
}
@Override
public byte []getNewline()
{
return _newline;
}
/**
* Returns true if stream is readable and bytes can be skipped.
*/
@Override
public boolean hasSkip()
{
return canRead();
}
/**
* Skips bytes in the file.
*
* @param n the number of bytes to skip
*
* @return the actual bytes skipped.
@Override
public long skip(long n)
throws IOException
{
if (_is == null) {
if (_s == null)
return -1;
_is = _s.getInputStream();
}
return _is.skip(n);
}
*/
/**
* Returns true since the socket stream can be read.
*/
@Override
public boolean canRead()
{
return _channel != null;
}
/**
* Reads bytes from the socket.
*
* @param buf byte buffer receiving the bytes
* @param offset offset into the buffer
* @param length number of bytes to read
* @return number of bytes read or -1
* @exception throws ClientDisconnectException if the connection is dropped
*/
@Override
public int read(byte []buf, int offset, int length) throws IOException
{
try {
if (_channel == null) {
return -1;
}
int remaining = _readBuffer.remaining();
if (remaining > 0) {
_readBuffer.get(buf, offset, remaining);
return remaining;
}
_readBuffer.clear();
int channelRead = _channel.read(_readBuffer);
_readBuffer.flip();
if (channelRead < 0)
return -1;
_readBuffer.get(buf, offset, channelRead);
return channelRead;
} catch (InterruptedIOException e) {
if (_throwReadInterrupts)
throw e;
log.log(Level.FINEST, e.toString(), e);
} catch (IOException e) {
if (_throwReadInterrupts)
throw e;
log.log(Level.FINER, e.toString(), e);
// server/0611
/*
try {
close();
} catch (IOException e1) {
}
*/
}
return -1;
}
/**
* Reads bytes from the socket.
*
* @param buf byte buffer receiving the bytes
* @param offset offset into the buffer
* @param length number of bytes to read
* @return number of bytes read or -1
* @exception throws ClientDisconnectException if the connection is dropped
@Override
public int readTimeout(byte []buf, int offset, int length, long timeout)
throws IOException
{
Socket s = _s;
if (s == null)
return -1;
int oldTimeout = s.getSoTimeout();
try {
s.setSoTimeout((int) timeout);
int readLength = read(buf, offset, length);
return readLength;
} finally {
s.setSoTimeout(oldTimeout);
}
}
*/
/**
* Returns the number of bytes available to be read from the input stream.
*/
@Override
public int getAvailable() throws IOException
{
if (_channel == null) {
return -1;
}
// return _channel.available();
return 1;
}
/*
@Override
public boolean canWrite()
{
return _os != null || _s != null;
}
*/
/**
* Writes bytes to the socket.
*
* @param buf byte buffer containing the bytes
* @param offset offset into the buffer
* @param length number of bytes to read
* @param isEnd if the write is at a close.
*
* @exception throws ClientDisconnectException if the connection is dropped
*/
/*
@Override
public void write(byte []buf, int offset, int length, boolean isEnd)
throws IOException
{
if (_os == null) {
if (_s == null)
return;
_os = _s.getOutputStream();
}
try {
_needsFlush = true;
_os.write(buf, offset, length);
_totalWriteBytes += length;
} catch (IOException e) {
try {
close();
} catch (IOException e1) {
}
throw ClientDisconnectException.create(e);
}
}
*/
/**
* Flushes the socket.
*/
/*
@Override
public void flush() throws IOException
{
if (_os == null || ! _needsFlush)
return;
_needsFlush = false;
try {
_os.flush();
} catch (IOException e) {
try {
close();
} catch (IOException e1) {
}
throw ClientDisconnectException.create(e);
}
}
public void resetTotalBytes()
{
_totalReadBytes = 0;
_totalWriteBytes = 0;
}
public long getTotalReadBytes()
{
return _totalReadBytes;
}
public long getTotalWriteBytes()
{
return _totalWriteBytes;
}
*/
/**
* Closes the write half of the stream.
*/
/*
@Override
public void closeWrite() throws IOException
{
OutputStream os = _os;
_os = null;
// since the output stream is opened lazily, we might
// need to open it
if (_s != null) {
try {
_s.shutdownOutput();
} catch (Exception e) {
log.log(Level.FINER, e.toString(), e);
}
}
// SSLSocket doesn't support shutdownOutput()
if (os != null)
os.close();
}
*/
/**
* Closes the underlying sockets and socket streams.
*/
@Override
public void close() throws IOException
{
SocketChannel channel = _channel;
_channel = null;
if (channel != null)
channel.close();
}
@Override
public String toString()
{
return getClass().getSimpleName() + "[" + _channel + "]";
}
}