I am currently working on a client/server TLS tool that requires us to connect through firewalls.
For reasons that are outside our control, we are only granted an outgoing TCP connection.
The problem is that our client's firewall blocks the client Hello v2 message (and possibly the whole SSL handshake).
Is there a way to obfuscate the stream in some manner?
I was thinking about trying to use compression to make the stream unreadable to the firewall.
(Maybe using JDK7's GzipOutputStream which now allows for syncFlush flushing)
I am no SSL expert but it seems to me it should be possible to translate the whole stream which should make it impossible for the firewall to pick up the connection and block it.
As far as I can see, there are a few (two?) ways to go about this :
Override the default implementation
Implement SSLServerSocketFactory
The first option didn't work out for me as I am unable to find the source code of com.sun.net.ssl.internal.ssl.SSLServerSocketFactoryImpl, which is the default implementation.
I did browse the openJDK source code for it, but even there, the sources appear to be missing.
Implementing a SSLServerSocketFactory is beyond my capabilities. As I said I am no SSL expert.
Please note that the application does work fine through other, less agressive firewalls / firewall rules.
Compressing an encrypted stream is not useful, where you actually only want some masking to avoid your firewall.
On the client side, you can use the SSLSocketFactory's method createSocket(socket, host, port, autoclose) to create a SSL socket based on another socket - and this another socket can get your special SocketImpl implementation, doing a simple XOR-masking on the first some bytes.
On the server side, it is more complicated, since the SSLServerSocketFactory has no such method.
In a answer to Java RMI + SSL + Compression = IMPOSSIBLE!, I described how to build a delegating Socket factory. There it was done for a Rmi(Client|Server)SocketFactory, but it would work in an analogous way for a ServerSocketFactory or SocketFactory.
But of course it could be that your firewall is not actually blocking SSL traffic, but blocking anything that is not whitelisted (like HTTP). Before building your wrapping socket implementation, try if a simple socket+serversocket which sends some random data and receives them back even works.
It is possible to tunnel TCP through HTTP without additional development. There are various tools. Look at GNU httptunnel. httptunnel creates a bidirectional virtual data connection tunnelled in HTTP requests. The HTTP requests can be sent via an HTTP proxy if so desired.Httpc is quite interresting too.
Perhaps slightly off-topic, but if the problem is specifically about SSLv2, and if SSLv3 or TLS 1.x handshakes work fine, you could disable the V2 ClientHello, by using SSLSocket.setEnabledProtocols(new String[] { "SSLv3", "TLSv1", "TLSv1.1" }).
See the JSSE Reference guide (section on SSLContext).
EDIT: For those who don't read comments, here is a link to #EJP's answer with more details on this topic: Why does Java's SSLSocket send a version 2 client hello?
It appears the solution is to combine Bruno's suggestion and Paulo's solution.
Paulo's solution allows us to customize the behavior of our SSLSocket or SSLServerSocket using delegates.
Bruno's suggestion allows us to tell the default SSL implementation to use our modified SSLSocket or SSLServerSocket.
Here is what I did :
Create a delegate ServerSocket class ( MyServerSocket )
Create a delegate ServerSocketFactory class (MyServerSocketFactory)
Create a delegate SocketFactory class (MySocketFactory)
Create a delegate Socket class (MySocket)
Create XorInputStream (find it here)
Create XorOutputStream (find it here)
On the server side :
// Initialisation as usual
...
sslSocketFactory = sslContext.getSocketFactory();
serverSocketFactory = ServerSocketFactory.getDefault();
serverSocketFactory = new MyServerSocketFactory(serverSocketFactory);
serverSocket = serverSocketFactory.createServerSocket(port);
...
Socket s = (Socket) serverSocket.accept();
sslSocket = (SSLSocket) sslSocketFactory.createSocket(s, null, s.getPort(), false);
sslSocket.setUseClientMode(false);
sslSocket.setEnabledCipherSuites(new String[]{"SSL_RSA_WITH_RC4_128_MD5"});
sslSocket.setNeedClientAuth(true);
...
On the client side:
Socket s = new MySocketFactory(SocketFactory.getDefault()).createSocket(host, port);
SSLSocket socket = (SSLSocket) factory.createSocket(s, host, port, false);
Sources
public class MyServerSocket extends ServerSocket {
private ServerSocket baseSocket;
public MyServerSocket(ServerSocket baseSocket) throws IOException {
this.baseSocket = baseSocket;
}
#Override
public Socket accept() throws IOException {
return new MySocket(baseSocket.accept());
}
#Override
public void bind(SocketAddress endpoint) throws IOException {
baseSocket.bind(endpoint);
}
#Override
public void bind(SocketAddress endpoint, int backlog) throws IOException {
baseSocket.bind(endpoint, backlog);
}
#Override
public void close() throws IOException {
baseSocket.close();
}
#Override
public ServerSocketChannel getChannel() {
return baseSocket.getChannel();
}
#Override
public InetAddress getInetAddress() {
return baseSocket.getInetAddress();
}
#Override
public int getLocalPort() {
return baseSocket.getLocalPort();
}
#Override
public SocketAddress getLocalSocketAddress() {
return baseSocket.getLocalSocketAddress();
}
#Override
public synchronized int getReceiveBufferSize() throws SocketException {
return baseSocket.getReceiveBufferSize();
}
#Override
public boolean getReuseAddress() throws SocketException {
return baseSocket.getReuseAddress();
}
#Override
public synchronized int getSoTimeout() throws IOException {
return baseSocket.getSoTimeout();
}
#Override
public boolean isBound() {
return baseSocket.isBound();
}
#Override
public boolean isClosed() {
return baseSocket.isClosed();
}
#Override
public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
baseSocket.setPerformancePreferences(connectionTime, latency, bandwidth);
}
#Override
public synchronized void setReceiveBufferSize(int size) throws SocketException {
baseSocket.setReceiveBufferSize(size);
}
#Override
public void setReuseAddress(boolean on) throws SocketException {
baseSocket.setReuseAddress(on);
}
#Override
public synchronized void setSoTimeout(int timeout) throws SocketException {
baseSocket.setSoTimeout(timeout);
}
#Override
public String toString() {
return baseSocket.toString();
}
}
public class MyServerSocketFactory extends ServerSocketFactory {
private ServerSocketFactory baseFactory;
public MyServerSocketFactory(ServerSocketFactory baseFactory) {
this.baseFactory = baseFactory;
}
#Override
public ServerSocket createServerSocket(int i) throws IOException {
return new MyServerSocket(baseFactory.createServerSocket(i));
}
#Override
public ServerSocket createServerSocket(int i, int i1) throws IOException {
return new MyServerSocket(baseFactory.createServerSocket(i, i1));
}
#Override
public ServerSocket createServerSocket(int i, int i1, InetAddress ia) throws IOException {
return new MyServerSocket(baseFactory.createServerSocket(i, i1, ia));
}
}
public class MySocket extends Socket {
private Socket baseSocket;
public MySocket(Socket baseSocket) {
this.baseSocket = baseSocket;
}
private XorInputStream xorInputStream = null;
private XorOutputStream xorOutputStream = null;
private final byte pattern = (byte)0xAC;
#Override
public InputStream getInputStream() throws IOException {
if (xorInputStream == null)
{
xorInputStream = new XorInputStream(baseSocket.getInputStream(), pattern);
}
return xorInputStream;
}
#Override
public OutputStream getOutputStream() throws IOException {
if (xorOutputStream == null)
{
xorOutputStream = new XorOutputStream(baseSocket.getOutputStream(), pattern);
}
return xorOutputStream;
}
#Override
public void bind(SocketAddress bindpoint) throws IOException {
baseSocket.bind(bindpoint);
}
#Override
public synchronized void close() throws IOException {
baseSocket.close();
}
#Override
public void connect(SocketAddress endpoint) throws IOException {
baseSocket.connect(endpoint);
}
#Override
public void connect(SocketAddress endpoint, int timeout) throws IOException {
baseSocket.connect(endpoint, timeout);
}
#Override
public SocketChannel getChannel() {
return baseSocket.getChannel();
}
#Override
public InetAddress getInetAddress() {
return baseSocket.getInetAddress();
}
#Override
public boolean getKeepAlive() throws SocketException {
return baseSocket.getKeepAlive();
}
#Override
public InetAddress getLocalAddress() {
return baseSocket.getLocalAddress();
}
#Override
public int getLocalPort() {
return baseSocket.getLocalPort();
}
#Override
public SocketAddress getLocalSocketAddress() {
return baseSocket.getLocalSocketAddress();
}
#Override
public boolean getOOBInline() throws SocketException {
return baseSocket.getOOBInline();
}
#Override
public int getPort() {
return baseSocket.getPort();
}
#Override
public synchronized int getReceiveBufferSize() throws SocketException {
return baseSocket.getReceiveBufferSize();
}
#Override
public SocketAddress getRemoteSocketAddress() {
return baseSocket.getRemoteSocketAddress();
}
#Override
public boolean getReuseAddress() throws SocketException {
return baseSocket.getReuseAddress();
}
#Override
public synchronized int getSendBufferSize() throws SocketException {
return baseSocket.getSendBufferSize();
}
#Override
public int getSoLinger() throws SocketException {
return baseSocket.getSoLinger();
}
#Override
public synchronized int getSoTimeout() throws SocketException {
return baseSocket.getSoTimeout();
}
#Override
public boolean getTcpNoDelay() throws SocketException {
return baseSocket.getTcpNoDelay();
}
#Override
public int getTrafficClass() throws SocketException {
return baseSocket.getTrafficClass();
}
#Override
public boolean isBound() {
return baseSocket.isBound();
}
#Override
public boolean isClosed() {
return baseSocket.isClosed();
}
#Override
public boolean isConnected() {
return baseSocket.isConnected();
}
#Override
public boolean isInputShutdown() {
return baseSocket.isInputShutdown();
}
#Override
public boolean isOutputShutdown() {
return baseSocket.isOutputShutdown();
}
#Override
public void sendUrgentData(int data) throws IOException {
baseSocket.sendUrgentData(data);
}
#Override
public void setKeepAlive(boolean on) throws SocketException {
baseSocket.setKeepAlive(on);
}
#Override
public void setOOBInline(boolean on) throws SocketException {
baseSocket.setOOBInline(on);
}
#Override
public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
baseSocket.setPerformancePreferences(connectionTime, latency, bandwidth);
}
#Override
public synchronized void setReceiveBufferSize(int size) throws SocketException {
baseSocket.setReceiveBufferSize(size);
}
#Override
public void setReuseAddress(boolean on) throws SocketException {
baseSocket.setReuseAddress(on);
}
#Override
public synchronized void setSendBufferSize(int size) throws SocketException {
baseSocket.setSendBufferSize(size);
}
#Override
public void setSoLinger(boolean on, int linger) throws SocketException {
baseSocket.setSoLinger(on, linger);
}
#Override
public synchronized void setSoTimeout(int timeout) throws SocketException {
baseSocket.setSoTimeout(timeout);
}
#Override
public void setTcpNoDelay(boolean on) throws SocketException {
baseSocket.setTcpNoDelay(on);
}
#Override
public void setTrafficClass(int tc) throws SocketException {
baseSocket.setTrafficClass(tc);
}
#Override
public void shutdownInput() throws IOException {
baseSocket.shutdownInput();
}
#Override
public void shutdownOutput() throws IOException {
baseSocket.shutdownOutput();
}
#Override
public String toString() {
return baseSocket.toString();
}
}
public class MySocketFactory extends SocketFactory {
private SocketFactory baseFactory;
public MySocketFactory(SocketFactory baseFactory) {
this.baseFactory = baseFactory;
}
#Override
public Socket createSocket() throws IOException {
return baseFactory.createSocket();
}
#Override
public boolean equals(Object obj) {
return baseFactory.equals(obj);
}
#Override
public int hashCode() {
return baseFactory.hashCode();
}
#Override
public String toString() {
return baseFactory.toString();
}
#Override
public Socket createSocket(String string, int i) throws IOException, UnknownHostException {
return new MySocket(baseFactory.createSocket(string, i));
}
#Override
public Socket createSocket(String string, int i, InetAddress ia, int i1) throws IOException, UnknownHostException {
return baseFactory.createSocket(string, i, ia, i1);
}
#Override
public Socket createSocket(InetAddress ia, int i) throws IOException {
return baseFactory.createSocket(ia, i);
}
#Override
public Socket createSocket(InetAddress ia, int i, InetAddress ia1, int i1) throws IOException {
return baseFactory.createSocket(ia, i, ia1, i1);
}
}
Related
I implemented a code that maintains Serial communications to different ports.
However, the same code is working perfectly with USB port /dev/ttyUSB0, but not working on port /dev/ttyAMA0 (This port is operating if I use PI4J library)
Baud rates :
/dev/ttyAMA0 - 115200
/dev/ttyUSB0 - 9600
I'm running on a raspberry pi 3B with Java 9
What I am missing here?
This is my code:
public class JSerialComm extends BaseSerial
{
private SerialPort serial = null;
private Object recLock = new Object();
public JSerialComm()
{
super();
}
#Override
protected boolean checkIsClosed()
{
return this.serial == null || !this.serial.isOpen();
}
#Override
protected void registerToSerialEventListener()
{
this.serial.addDataListener(new SerialPortPacketListener()
{
#Override
public void serialEvent(SerialPortEvent event)
{
try
{
synchronized (recLock)
{
if(event.getSerialPort().bytesAvailable()>=getPacketSize())
{
final byte[] newData = new byte[getPacketSize()];
event.getSerialPort().readBytes(newData, getPacketSize());
notifyHandlers(newData);
}
}
}
catch(Exception e)
{
}
}
#Override
public int getListeningEvents()
{
return SerialPort.LISTENING_EVENT_DATA_AVAILABLE;
}
#Override
public int getPacketSize()
{
return MindoLifeJSerialComm.this.getPacketSize();
}
});
}
#Override
protected int sendByteToSerial(byte[] input) throws Exception
{
return sendByteToSerial(input,input.length);
}
#Override
protected void openPort(String portName, int baudRate) throws Exception
{
for (SerialPort port : SerialPort.getCommPorts())
{
if (portName.toLowerCase().endsWith(port.getSystemPortName().toLowerCase()))
{
serial = port;
}
}
if(serial == null)
{
throw new Exception("Couldn't find port " + portName );
}
serial.setBaudRate(baudRate);
serial.setComPortTimeouts(SerialPort.TIMEOUT_NONBLOCKING, 0, 0);
serial.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);
serial.setParity(SerialPort.NO_PARITY);
serial.setNumStopBits(SerialPort.ONE_STOP_BIT);
if (!serial.openPort())
{
throw new Exception("Couldn't open port " + portName + " opened with baud " + baudRate);
}
}
#Override
protected int sendByteToSerial(byte[] input, int length) throws Exception {
int res = serial.writeBytes(input, length);
// TODO:flush
return res;
}
#Override
protected void closePort() {
this.serial.closePort();
}
}
Base class:
public abstract class BaseSerial
{
HasSerialMessageHandler handler;
private Object recLock = new Object();
private int packetSize = 1;
private String portName;
protected final void notifyHandlers(byte[] newData)
{
if (handler != null)
{
handler.incoming(newData);
}
}
private Object writeLock = new Object();
public int write(byte[] input) throws Exception
{
return write(input, -1);
}
public int write(byte[] input, int length) throws Exception
{
int res = sendByteToSerial(input,length);
return res;
}
public void addListener(final HasSerialMessageHandler handler) throws TooManyListenersException
{
this.handler = handler;
registerToSerialEventListener();
}
public boolean isClosed()
{
return checkIsClosed();
}
public void open(String portName, int baudRate) throws Exception
{
this.portName = portName;
openPort(portName, baudRate);
Thread.sleep(1000);
}
public int getPacketSize()
{
return packetSize;
}
public void setPacketSize(int packetSize)
{
this.packetSize = packetSize;
}
public void close()
{
closePort();
}
public String getPortName()
{
return portName;
}
protected abstract boolean checkIsClosed();
protected abstract void registerToSerialEventListener();
protected abstract void openPort(String portName, int baudRate) throws Exception;
protected abstract int sendByteToSerial(byte[] input) throws Exception;
protected abstract int sendByteToSerial(byte[] input, int length) throws Exception;
protected abstract void closePort();
}
Init and Usage (For both ports):
public class Main
{
public static void main(String[] args)
{
BaseSerial serial = new JSerialComm ();
serial.setPacketSize(14);
serial.addListener(new HasSerialMessageHandler() {
#Override
public void incoming(final byte[] message)
{
if (message.length > 0)
{
sysout(message);
}
}
serial.open("/dev/ttyAMA0", 115200);
});
}
}
My /etc/inittab is set as the following:
1:2345:respawn:/sbin/getty --noclear 38400 tty1
2:23:respawn:/sbin/getty 38400 tty2
3:23:respawn:/sbin/getty 38400 tty3
4:23:respawn:/sbin/getty 38400 tty4
5:23:respawn:/sbin/getty 38400 tty5
6:23:respawn:/sbin/getty 38400 tty6
# Example how to put a getty on a serial line (for a terminal)
#
#T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100
#T1:23:respawn:/sbin/getty -L ttyS1 9600 vt100
# Example how to put a getty on a modem line.
#
#T3:23:respawn:/sbin/mgetty -x0 -s 57600 ttyS3
#Spawn a getty on Raspberry Pi serial line
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100
This question already has answers here:
Official reasons for "Software caused connection abort: socket write error"
(14 answers)
Closed 5 years ago.
I'm trying to go through the SSL example and EchoServer example in Netty and for some reason, when I add my sslContext on the client side, I keep getting, an established connection was aborted by the software in your host machine.
EchoServerBootstrap
public class EchoServerBootstrap {
private final int port;
public EchoServerBootstrap(int port) {
this.port = port;
}
public static void main(String[] args) throws Exception {
new EchoServerBootstrap(3000).start();
}
public void start() throws Exception {
SelfSignedCertificate ssc = new SelfSignedCertificate();
final SslContext sslContext = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(sslContext.newHandler(ch.alloc()));
ch.pipeline().addLast(new EchoServerHandler());
}
});
ChannelFuture f = b.bind().sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
}
EchoServerHandler
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf in = (ByteBuf) msg;
System.out.println("Received: " + in.toString(CharsetUtil.UTF_8));
ctx.write(in);
}
#Override
public void channelReadComplete(ChannelHandlerContext ctx) {
System.out.println("channel read complete");
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
EchoClientHandler
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
#Override
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks", CharsetUtil.UTF_8));
}
#Override
public void channelRead0(ChannelHandlerContext ctx, ByteBuf in) {
System.out.println("Client receive: " + in.toString(CharsetUtil.UTF_8));
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
EchoClientBootstrap
public class EchoClientBootstrap {
private final String host;
private final int port;
public EchoClientBootstrap(String host, int port) {
this.port = port;
this.host = host;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
final SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(sslContext.newHandler(ch.alloc(), host, port)); // WHEN I ADD THIS LINE IT FAILS WITH I/O EXCEPTION 'an established connection was aborted...'
ch.pipeline().addLast(new EchoClientHandler());
}
});
ChannelFuture f = b.connect(host, port).sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
public static void main(String[] args) throws Exception {
new EchoClientBootstrap("localhost", 3000).start();
}
}
Is there something obvious I'm missing? I tried following this example and altering it a bit (http://netty.io/4.1/xref/io/netty/example/securechat/package-summary.html), but I keep getting that exception when I add the sslContext to the client channel. Any thoughts?
I added some logging to figure out what was going on, and without encryption, EchoClient sends over the "Netty rocks" message and the server reads the message and closes the channel. But for some reason if SSL is enabled, the EchoServerHandler calls channelReadComplete before the EchoClient can send "Netty rocks" which is essentially this method
#Override
public void channelReadComplete(ChannelHandlerContext ctx) {
System.out.println("channel read complete");
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
which was closing my channel. I am not sure why there is that discrepancy when using SSL.
I have application which uses both TCP and UDP protocols. Main assumption is that the client connects to server via TCP protocol and when connection is established, UDP datagrams are being send.
I have to support two scenarios of connecting to server:
- client connects when server is running
- client connects when server is down and retries connection until server starts again
For the first scenario everything works pretty fine: I got working both connections.
The problem is with second scenario. When client tries few times to connect via TCP and finally connects, the UDP connection function throws an exception:
java.net.SocketException: No buffer space available (maximum connections reached?): bind
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Net.java:344)
at sun.nio.ch.DatagramChannelImpl.bind(DatagramChannelImpl.java:684)
at sun.nio.ch.DatagramSocketAdaptor.bind(DatagramSocketAdaptor.java:91)
at io.netty.channel.socket.nio.NioDatagramChannel.doBind(NioDatagramChannel.java:192)
at io.netty.channel.AbstractChannel$AbstractUnsafe.bind(AbstractChannel.java:484)
at io.netty.channel.DefaultChannelPipeline$HeadContext.bind(DefaultChannelPipeline.java:1080)
at io.netty.channel.AbstractChannelHandlerContext.invokeBind(AbstractChannelHandlerContext.java:430)
at io.netty.channel.AbstractChannelHandlerContext.bind(AbstractChannelHandlerContext.java:415)
at io.netty.channel.DefaultChannelPipeline.bind(DefaultChannelPipeline.java:903)
at io.netty.channel.AbstractChannel.bind(AbstractChannel.java:197)
at io.netty.bootstrap.AbstractBootstrap$2.run(AbstractBootstrap.java:350)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:380)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
at java.lang.Thread.run(Thread.java:722)
When I restart client application without doing anything with server, client will connect with any problems.
What can cause a problem?
In below I attach source code of classes. All source code comes from examples placed in official Netty project page. The only thing which I have midified is that I replaced static variables and functions with non-static ones. It was caused that in future I will need many TCP-UDP connections to multiple servers.
public final class UptimeClient {
static final String HOST = System.getProperty("host", "192.168.2.193");
static final int PORT = Integer.parseInt(System.getProperty("port", "2011"));
static final int RECONNECT_DELAY = Integer.parseInt(System.getProperty("reconnectDelay", "5"));
static final int READ_TIMEOUT = Integer.parseInt(System.getProperty("readTimeout", "10"));
private static UptimeClientHandler handler;
public void runClient() throws Exception {
configureBootstrap(new Bootstrap()).connect();
}
private Bootstrap configureBootstrap(Bootstrap b) {
return configureBootstrap(b, new NioEventLoopGroup());
}
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); //To change body of generated methods, choose Tools | Templates.
}
Bootstrap configureBootstrap(Bootstrap b, EventLoopGroup g) {
if(handler == null){
handler = new UptimeClientHandler(this);
}
b.group(g)
.channel(NioSocketChannel.class)
.remoteAddress(HOST, PORT)
.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new IdleStateHandler(READ_TIMEOUT, 0, 0), handler);
}
});
return b;
}
void connect(Bootstrap b) {
b.connect().addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.cause() != null) {
handler.startTime = -1;
handler.println("Failed to connect: " + future.cause());
}
}
});
}
}
#Sharable
public class UptimeClientHandler extends SimpleChannelInboundHandler<Object> {
UptimeClient client;
public UptimeClientHandler(UptimeClient client){
this.client = client;
}
long startTime = -1;
#Override
public void channelActive(ChannelHandlerContext ctx) {
try {
if (startTime < 0) {
startTime = System.currentTimeMillis();
}
println("Connected to: " + ctx.channel().remoteAddress());
new QuoteOfTheMomentClient(null).run();
} catch (Exception ex) {
Logger.getLogger(UptimeClientHandler.class.getName()).log(Level.SEVERE, null, ex);
}
}
#Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
}
#Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
if (!(evt instanceof IdleStateEvent)) {
return;
}
IdleStateEvent e = (IdleStateEvent) evt;
if (e.state() == IdleState.READER_IDLE) {
// The connection was OK but there was no traffic for last period.
println("Disconnecting due to no inbound traffic");
ctx.close();
}
}
#Override
public void channelInactive(final ChannelHandlerContext ctx) {
println("Disconnected from: " + ctx.channel().remoteAddress());
}
#Override
public void channelUnregistered(final ChannelHandlerContext ctx) throws Exception {
println("Sleeping for: " + UptimeClient.RECONNECT_DELAY + 's');
final EventLoop loop = ctx.channel().eventLoop();
loop.schedule(new Runnable() {
#Override
public void run() {
println("Reconnecting to: " + UptimeClient.HOST + ':' + UptimeClient.PORT);
client.connect(client.configureBootstrap(new Bootstrap(), loop));
}
}, UptimeClient.RECONNECT_DELAY, TimeUnit.SECONDS);
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
void println(String msg) {
if (startTime < 0) {
System.err.format("[SERVER IS DOWN] %s%n", msg);
} else {
System.err.format("[UPTIME: %5ds] %s%n", (System.currentTimeMillis() - startTime) / 1000, msg);
}
}
}
public final class QuoteOfTheMomentClient {
private ServerData config;
public QuoteOfTheMomentClient(ServerData config){
this.config = config;
}
public void run() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioDatagramChannel.class)
.option(ChannelOption.SO_BROADCAST, true)
.handler(new QuoteOfTheMomentClientHandler());
Channel ch = b.bind(0).sync().channel();
ch.writeAndFlush(new DatagramPacket(
Unpooled.copiedBuffer("QOTM?", CharsetUtil.UTF_8),
new InetSocketAddress("192.168.2.193", 8193))).sync();
if (!ch.closeFuture().await(5000)) {
System.err.println("QOTM request timed out.");
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
finally {
group.shutdownGracefully();
}
}
}
public class QuoteOfTheMomentClientHandler extends SimpleChannelInboundHandler<DatagramPacket> {
#Override
public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
String response = msg.content().toString(CharsetUtil.UTF_8);
if (response.startsWith("QOTM: ")) {
System.out.println("Quote of the Moment: " + response.substring(6));
ctx.close();
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
If your server is Windows Server 2008 (R2 or R2 SP1), this problem is likely described and solved by this stackoverflow answer which refers to Microsoft KB article #2577795
This issue occurs because of a race condition in the Ancillary Function Driver
for WinSock (Afd.sys) that causes sockets to be leaked. With time, the issue
that is described in the "Symptoms" section occurs if all available socket
resources are exhausted.
If your server is Windows Server 2003, this problem is likely described and solved by this stackoverflow answer which refers to Microsoft KB article #196271
The default maximum number of ephemeral TCP ports is 5000 in the products that
are included in the "Applies to" section. A new parameter has been added in
these products. To increase the maximum number of ephemeral ports, follow these
steps...
...which basically means that you have run out of ephemeral ports.
We wrote client application in android which connects with https servers using HttpsUrlConnection apis. Due to Poodle vulnerability, we need to disable SSLv3 from the list of enabled protocols while invoking any request.
We followed the guidelines captured by oracle
and added following line before invoking url connection
java.lang.System.setProperty("https.protocols", "TLSv1");
This solution works fine with normal java program.
We got SSLHandShakeException when tried to connect with a server which only works on SSLv3 protocol.
But concern is : same fix does not work for android. Am I missing something or should I try another approach for android? Please suggest.
I found the solution for it by analyzing the data packets using wireshark. What I found is that while making a secure connection, android was falling back to SSLv3 from TLSv1 . It is a bug in android versions < 4.4 , and it can be solved by removing the SSLv3 protocol from Enabled Protocols list. I made a custom socketFactory class called NoSSLv3SocketFactory.java. Use this to make a socketfactory.
/*Copyright 2015 Bhavit Singh Sengar
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.*/
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.net.ssl.HandshakeCompletedListener;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
public class NoSSLv3SocketFactory extends SSLSocketFactory{
private final SSLSocketFactory delegate;
public NoSSLv3SocketFactory() {
this.delegate = HttpsURLConnection.getDefaultSSLSocketFactory();
}
public NoSSLv3SocketFactory(SSLSocketFactory delegate) {
this.delegate = delegate;
}
#Override
public String[] getDefaultCipherSuites() {
return delegate.getDefaultCipherSuites();
}
#Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}
private Socket makeSocketSafe(Socket socket) {
if (socket instanceof SSLSocket) {
socket = new NoSSLv3SSLSocket((SSLSocket) socket);
}
return socket;
}
#Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
return makeSocketSafe(delegate.createSocket(s, host, port, autoClose));
}
#Override
public Socket createSocket(String host, int port) throws IOException {
return makeSocketSafe(delegate.createSocket(host, port));
}
#Override
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException {
return makeSocketSafe(delegate.createSocket(host, port, localHost, localPort));
}
#Override
public Socket createSocket(InetAddress host, int port) throws IOException {
return makeSocketSafe(delegate.createSocket(host, port));
}
#Override
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
return makeSocketSafe(delegate.createSocket(address, port, localAddress, localPort));
}
private class NoSSLv3SSLSocket extends DelegateSSLSocket {
private NoSSLv3SSLSocket(SSLSocket delegate) {
super(delegate);
}
#Override
public void setEnabledProtocols(String[] protocols) {
if (protocols != null && protocols.length == 1 && "SSLv3".equals(protocols[0])) {
List<String> enabledProtocols = new ArrayList<String>(Arrays.asList(delegate.getEnabledProtocols()));
if (enabledProtocols.size() > 1) {
enabledProtocols.remove("SSLv3");
System.out.println("Removed SSLv3 from enabled protocols");
} else {
System.out.println("SSL stuck with protocol available for " + String.valueOf(enabledProtocols));
}
protocols = enabledProtocols.toArray(new String[enabledProtocols.size()]);
}
super.setEnabledProtocols(protocols);
}
}
public class DelegateSSLSocket extends SSLSocket {
protected final SSLSocket delegate;
DelegateSSLSocket(SSLSocket delegate) {
this.delegate = delegate;
}
#Override
public String[] getSupportedCipherSuites() {
return delegate.getSupportedCipherSuites();
}
#Override
public String[] getEnabledCipherSuites() {
return delegate.getEnabledCipherSuites();
}
#Override
public void setEnabledCipherSuites(String[] suites) {
delegate.setEnabledCipherSuites(suites);
}
#Override
public String[] getSupportedProtocols() {
return delegate.getSupportedProtocols();
}
#Override
public String[] getEnabledProtocols() {
return delegate.getEnabledProtocols();
}
#Override
public void setEnabledProtocols(String[] protocols) {
delegate.setEnabledProtocols(protocols);
}
#Override
public SSLSession getSession() {
return delegate.getSession();
}
#Override
public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
delegate.addHandshakeCompletedListener(listener);
}
#Override
public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
delegate.removeHandshakeCompletedListener(listener);
}
#Override
public void startHandshake() throws IOException {
delegate.startHandshake();
}
#Override
public void setUseClientMode(boolean mode) {
delegate.setUseClientMode(mode);
}
#Override
public boolean getUseClientMode() {
return delegate.getUseClientMode();
}
#Override
public void setNeedClientAuth(boolean need) {
delegate.setNeedClientAuth(need);
}
#Override
public void setWantClientAuth(boolean want) {
delegate.setWantClientAuth(want);
}
#Override
public boolean getNeedClientAuth() {
return delegate.getNeedClientAuth();
}
#Override
public boolean getWantClientAuth() {
return delegate.getWantClientAuth();
}
#Override
public void setEnableSessionCreation(boolean flag) {
delegate.setEnableSessionCreation(flag);
}
#Override
public boolean getEnableSessionCreation() {
return delegate.getEnableSessionCreation();
}
#Override
public void bind(SocketAddress localAddr) throws IOException {
delegate.bind(localAddr);
}
#Override
public synchronized void close() throws IOException {
delegate.close();
}
#Override
public void connect(SocketAddress remoteAddr) throws IOException {
delegate.connect(remoteAddr);
}
#Override
public void connect(SocketAddress remoteAddr, int timeout) throws IOException {
delegate.connect(remoteAddr, timeout);
}
#Override
public SocketChannel getChannel() {
return delegate.getChannel();
}
#Override
public InetAddress getInetAddress() {
return delegate.getInetAddress();
}
#Override
public InputStream getInputStream() throws IOException {
return delegate.getInputStream();
}
#Override
public boolean getKeepAlive() throws SocketException {
return delegate.getKeepAlive();
}
#Override
public InetAddress getLocalAddress() {
return delegate.getLocalAddress();
}
#Override
public int getLocalPort() {
return delegate.getLocalPort();
}
#Override
public SocketAddress getLocalSocketAddress() {
return delegate.getLocalSocketAddress();
}
#Override
public boolean getOOBInline() throws SocketException {
return delegate.getOOBInline();
}
#Override
public OutputStream getOutputStream() throws IOException {
return delegate.getOutputStream();
}
#Override
public int getPort() {
return delegate.getPort();
}
#Override
public synchronized int getReceiveBufferSize() throws SocketException {
return delegate.getReceiveBufferSize();
}
#Override
public SocketAddress getRemoteSocketAddress() {
return delegate.getRemoteSocketAddress();
}
#Override
public boolean getReuseAddress() throws SocketException {
return delegate.getReuseAddress();
}
#Override
public synchronized int getSendBufferSize() throws SocketException {
return delegate.getSendBufferSize();
}
#Override
public int getSoLinger() throws SocketException {
return delegate.getSoLinger();
}
#Override
public synchronized int getSoTimeout() throws SocketException {
return delegate.getSoTimeout();
}
#Override
public boolean getTcpNoDelay() throws SocketException {
return delegate.getTcpNoDelay();
}
#Override
public int getTrafficClass() throws SocketException {
return delegate.getTrafficClass();
}
#Override
public boolean isBound() {
return delegate.isBound();
}
#Override
public boolean isClosed() {
return delegate.isClosed();
}
#Override
public boolean isConnected() {
return delegate.isConnected();
}
#Override
public boolean isInputShutdown() {
return delegate.isInputShutdown();
}
#Override
public boolean isOutputShutdown() {
return delegate.isOutputShutdown();
}
#Override
public void sendUrgentData(int value) throws IOException {
delegate.sendUrgentData(value);
}
#Override
public void setKeepAlive(boolean keepAlive) throws SocketException {
delegate.setKeepAlive(keepAlive);
}
#Override
public void setOOBInline(boolean oobinline) throws SocketException {
delegate.setOOBInline(oobinline);
}
#Override
public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) {
delegate.setPerformancePreferences(connectionTime, latency, bandwidth);
}
#Override
public synchronized void setReceiveBufferSize(int size) throws SocketException {
delegate.setReceiveBufferSize(size);
}
#Override
public void setReuseAddress(boolean reuse) throws SocketException {
delegate.setReuseAddress(reuse);
}
#Override
public synchronized void setSendBufferSize(int size) throws SocketException {
delegate.setSendBufferSize(size);
}
#Override
public void setSoLinger(boolean on, int timeout) throws SocketException {
delegate.setSoLinger(on, timeout);
}
#Override
public synchronized void setSoTimeout(int timeout) throws SocketException {
delegate.setSoTimeout(timeout);
}
#Override
public void setTcpNoDelay(boolean on) throws SocketException {
delegate.setTcpNoDelay(on);
}
#Override
public void setTrafficClass(int value) throws SocketException {
delegate.setTrafficClass(value);
}
#Override
public void shutdownInput() throws IOException {
delegate.shutdownInput();
}
#Override
public void shutdownOutput() throws IOException {
delegate.shutdownOutput();
}
#Override
public String toString() {
return delegate.toString();
}
#Override
public boolean equals(Object o) {
return delegate.equals(o);
}
}
}
Use this class like this while connecting :
SSLContext sslcontext = SSLContext.getInstance("TLSv1");
sslcontext.init(null,
null,
null);
SSLSocketFactory NoSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory());
HttpsURLConnection.setDefaultSSLSocketFactory(NoSSLv3Factory);
l_connection = (HttpsURLConnection) l_url.openConnection();
l_connection.connect();
UPDATE :
Now, correct solution would be to install a newer security provider using Google Play Services:
ProviderInstaller.installIfNeeded(getApplicationContext());
This effectively gives your app access to a newer version of OpenSSL and Java Security Provider, which includes support for TLSv1.2 in SSLEngine. Once the new provider is installed, you can create an SSLEngine which supports SSLv3, TLSv1, TLSv1.1 and TLSv1.2 the usual way:
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(null, null, null);
SSLEngine engine = sslContext.createSSLEngine();
Or you can restrict the enabled protocols using engine.setEnabledProtocols.
Don't forget to add the following dependency (latest version found here):
compile 'com.google.android.gms:play-services-auth:11.8.0'
For more info, checkout this link.
Inspired by Bhavit S. Sengar's answer, it bundled that technique into a dead simple method call. You can use the NetCipher library to get a modern TLS config when using Android's HttpsURLConnection. NetCipher configures the HttpsURLConnection instance to use the best supported TLS version, removes SSLv3 support, and configures the best suite of ciphers for that TLS version. First, add it to your build.gradle:
compile 'info.guardianproject.netcipher:netcipher:1.2'
Or you can download the netcipher-1.2.jar and include it directly in your app. Then instead of calling:
HttpURLConnection connection = (HttpURLConnection) sourceUrl.openConnection();
Call this:
HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl);
At first I tried Bhavit S. Sengar's answer and it worked for most cases. But sometimes there where issues even when SSLv3 protocol was removed from Enabled Protocols on an Android 4.4.4 device. So the NetCipher library by Hans-Christoph Steiner is perfect to solve that problem as far as I could test it.
We use jsoup to make a bunch of web scraping on different servers, so we cannot set HttpsURLConnection connection = NetCipher.getHttpsURLConnection(sourceUrl);. I assume that's the same problem if you use OkHttp.
The best solution we've come to is to set the info.guardianproject.netcipher.client.TlsOnlySocketFactory from NetCipher as DefaultSSLSocketFactory in a static block. So it's set for the whole runtime of our app:
SSLContext sslcontext = SSLContext.getInstance("TLSv1");
sslcontext.init(null, null, null);
SSLSocketFactory noSSLv3Factory = new TlsOnlySocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultSSLSocketFactory(noSSLv3Factory);
If you like to inspect the full details (with trustAllCertificates) you can do it here.
use this code snippet, if server is SSLv3 enable then it will fail handshaking.
SocketFactory sf = SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) sf.createSocket("host-name", 443);
socket.setEnabledProtocols(new String[] { "TLSv1"});
socket.startHandshake();
SSLContext sslContext = SSLContext.getInstance("TLSv1");
sslContext.init(null, null, null);
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
httpURLConnection.setSSLSocketFactory(socketFactory);
HttpsURLConnection using TSL create a security failed, the Android implementation will fall back to SSLV3 to connection.
Please refer this http://code.google.com/p/android/issues/detail?id=78431
Using PlayService publisher client libraries running on Android I experienced the same problem when running the sample.
Fixed it with #bhavit-s-sengar's awnser above. Had to also change AndroidPublisherHelper.newTrustedTransport() to this:
SSLContext sslcontext = SSLContext.getInstance("TLSv1");
sslcontext.init(null, null, null);
// NoSSLv3SocketFactory is #bhavit-s-sengar's http://stackoverflow.com/a/29946540/8524
SSLSocketFactory noSSLv3Factory = new NoSSLv3SocketFactory(sslcontext.getSocketFactory());
NetHttpTransport.Builder netTransportBuilder = new NetHttpTransport.Builder();
netTransportBuilder.setSslSocketFactory(noSSLv3Factory);
HTTP_TRANSPORT = netTransportBuilder.build();
Connects with https server we need certificate in handshaking from client side. 1 year back I solved a similar issue using self sign certificate in the following way-
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
public class HttpsTrustManager implements X509TrustManager {
private static TrustManager[] trustManagers;
private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{};
#Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] x509Certificates, String s)
throws java.security.cert.CertificateException {
}
#Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] x509Certificates, String s)
throws java.security.cert.CertificateException {
}
public boolean isClientTrusted(X509Certificate[] chain) {
return true;
}
public boolean isServerTrusted(X509Certificate[] chain) {
return true;
}
#Override
public X509Certificate[] getAcceptedIssuers() {
return _AcceptedIssuers;
}
public static void allowAllSSL() {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
SSLContext context = null;
if (trustManagers == null) {
trustManagers = new TrustManager[]{new HttpsTrustManager()};
}
try {
context = SSLContext.getInstance("TLS");
context.init(null, trustManagers, new SecureRandom());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
HttpsURLConnection.setDefaultSSLSocketFactory(context
.getSocketFactory());
}
}
Usage in client side before HttpsUrlConnection
HttpsTrustManager.allowAllSSL();
hopefully it will work :)
Actually we don't need to disable the SSLV3 or TLSV1.0, What we just need to enable TLSV1.1 or TLSv1.2 in android < 5 devices.
The problem is TLSv1.1 and TLSv1.2 not enabled on Android <5 by default and to connect using these latest secure protocol we must have to enable in Android <5 devices.
This solution fixed my problem : https://stackoverflow.com/a/45853669/3448003
I'm trying to write a simple echo server with Netty. I'm reading Netty in Action MEAP v8 to get down some theory and learn the core basics of Netty. The client connects successfully, but no messages get through from the client. I am able to telnet a message to the server and receive the response, so I guess the issue is on the client, I just have no idea what is wrong, due to me being new to Netty.
Here is the client:
public class Client {
private final String host;
private final int port;
public Client(String host, int port) {
this.host = host;
this.port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new EchoClientHandler());
}
});
ChannelFuture f = b.connect().sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
public static void main (String [] args) throws Exception {
new Client("127.0.0.1", 11235).start();
}
}
And the Client handler: (I did try appending '\r\n' to the sent message, but that did not make a difference, which I found here: Netty Client to Server message)
#Sharable
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("Connected");
ctx.write(Unpooled.copiedBuffer("Netty MAY rock!", CharsetUtil.UTF_8));
}
protected void channelRead0(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
System.out.println(
"Client received: " + in.toString(CharsetUtil.UTF_8));
}
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
The server:
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(group)
.channel(NioServerSocketChannel.class)
.localAddress(new InetSocketAddress(port))
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
System.out.println("New client connected: " + ch.localAddress());
ch.pipeline().addLast(new EchoServerHandler());
}
});
ChannelFuture f = b.bind().sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
public static void main (String [] args) throws Exception {
new EchoServer(11235).start();
}
}
The server handler:
#Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf in = (ByteBuf) msg;
System.out.println(
"Server received: " + in.toString(CharsetUtil.UTF_8));
ctx.write(in);
}
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
.addListener(ChannelFutureListener.CLOSE);
}
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
It must be something small I'm missing, so any help will preserve my fleeting sanity and will be much appreciated!
Instead of write use writeAndFlush in your ClientHandler:
public void channelActive(ChannelHandlerContext ctx) {
System.out.println("Connected");
ctx.writeAndFlush(Unpooled.copiedBuffer("Netty MAY rock!", CharsetUtil.UTF_8));
}