
io.jsync.net.impl.ConnectionBase Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsync.io Show documentation
Show all versions of jsync.io Show documentation
jsync.io is a non-blocking, event-driven networking framework for Java
/*
* Copyright (c) 2011-2013 The original author or authors
* ------------------------------------------------------
* 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 io.jsync.net.impl;
import io.jsync.AsyncResult;
import io.jsync.Handler;
import io.jsync.impl.AsyncInternal;
import io.jsync.impl.DefaultContext;
import io.jsync.impl.DefaultFutureResult;
import io.netty.channel.*;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.stream.ChunkedFile;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.security.cert.X509Certificate;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.InetSocketAddress;
/**
* Abstract base class for TCP connections.
*
* @author Tim Fox
*/
public abstract class ConnectionBase {
protected final AsyncInternal async;
protected final Channel channel;
protected final DefaultContext context;
protected Handler exceptionHandler;
protected Handler closeHandler;
private volatile boolean writable = true;
private boolean read;
private boolean needsFlush;
protected ConnectionBase(AsyncInternal async, Channel channel, DefaultContext context) {
this.async = async;
this.channel = channel;
this.context = context;
}
public final void startRead() {
read = true;
}
public final void endReadAndFlush() {
read = false;
if (needsFlush) {
needsFlush = false;
// flush now
channel.flush();
}
}
public ChannelFuture queueForWrite(final Object obj) {
needsFlush = true;
return channel.write(obj);
}
public ChannelFuture write(Object obj) {
if (read) {
return queueForWrite(obj);
}
if (channel.isOpen()) {
return channel.writeAndFlush(obj);
} else {
return null;
}
}
/**
* Close the connection
*/
public void close() {
// make sure everything is flushed out on close
endReadAndFlush();
channel.close();
}
public void doPause() {
channel.config().setAutoRead(false);
}
public void doResume() {
channel.config().setAutoRead(true);
}
public void doSetWriteQueueMaxSize(int size) {
channel.config().setWriteBufferLowWaterMark(size / 2);
channel.config().setWriteBufferHighWaterMark(size);
}
public boolean doWriteQueueFull() {
return !writable;
}
protected void setWritable(boolean writable) {
this.writable = writable;
}
protected DefaultContext getContext() {
return context;
}
protected void handleException(Throwable t) {
if (exceptionHandler != null) {
setContext();
try {
exceptionHandler.handle(t);
} catch (Throwable t2) {
handleHandlerException(t2);
}
}
}
protected void handleClosed() {
if (closeHandler != null) {
setContext();
try {
closeHandler.handle(null);
} catch (Throwable t) {
handleHandlerException(t);
}
}
}
protected void addFuture(final Handler> doneHandler, final ChannelFuture future) {
if (future != null) {
future.addListener(new ChannelFutureListener() {
public void operationComplete(final ChannelFuture channelFuture) throws Exception {
if (doneHandler != null) {
context.execute(new Runnable() {
public void run() {
if (channelFuture.isSuccess()) {
doneHandler.handle(new DefaultFutureResult<>((Void) null));
} else {
doneHandler.handle(new DefaultFutureResult(channelFuture.cause()));
}
}
});
} else if (!channelFuture.isSuccess()) {
handleException(channelFuture.cause());
}
}
});
}
}
protected void setContext() {
async.setContext(context);
}
protected void handleHandlerException(Throwable t) {
async.reportException(t);
}
protected boolean supportsFileRegion() {
return !isSSL();
}
private boolean isSSL() {
return channel.pipeline().get(SslHandler.class) != null;
}
protected ChannelFuture sendFile(File file) {
final RandomAccessFile raf;
try {
raf = new RandomAccessFile(file, "r");
long fileLength = file.length();
// Write the content.
ChannelFuture writeFuture;
if (!supportsFileRegion()) {
// Cannot use zero-copy
writeFuture = write(new ChunkedFile(raf, 0, fileLength, 8192));
} else {
// No encryption - use zero-copy.
final FileRegion region =
new DefaultFileRegion(raf.getChannel(), 0, fileLength);
writeFuture = write(region);
}
writeFuture.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
raf.close();
}
});
return writeFuture;
} catch (IOException e) {
handleException(e);
return null;
}
}
public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
if (isSSL()) {
final ChannelHandlerContext sslHandlerContext = channel.pipeline().context("ssl");
assert sslHandlerContext != null;
final SslHandler sslHandler = (SslHandler) sslHandlerContext.handler();
return sslHandler.engine().getSession().getPeerCertificateChain();
} else {
return null;
}
}
public InetSocketAddress remoteAddress() {
return (InetSocketAddress) channel.remoteAddress();
}
public InetSocketAddress localAddress() {
return (InetSocketAddress) channel.localAddress();
}
protected abstract void handleInterestedOpsChanged();
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy