JSerialComm not receiving/sending data in ttyAMA0 - java

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

Related

Netty client fail to read response from non-netty server

I have a Tcp client that connect to a old mainframe (52 years) that send and receive request and response from it.
Here is core connection part of the my client ,
public class SimpleConnector {
private String carrier;
private SocketChannel socketChannel;
public static final byte END_OF_MESSAGE_BYTE = (byte) 0x2b;
public SimpleConnector(String carrier, InetSocketAddress inetSocketAddress) throws IOException {
this.carrier = this.carrier;
socketChannel = SocketChannel.open();
socketChannel.socket().connect(inetSocketAddress, 30000);
}
public void shutDown() throws IOException {
this.socketChannel.close();
}
//Send Request
public String sendRequest(String request) throws Exception {
final CharsetEncoder charsetEncoder = Charset.forName("ISO-8859-1").newEncoder();
int requestLength = 12 + request.length() + 1;
ByteBuffer buffer = ByteBuffer.allocate(requestLength);
buffer.order(ByteOrder.BIG_ENDIAN);
buffer.putInt(requestLength);
buffer.put(charsetEncoder.encode(CharBuffer.wrap(carrier)));
buffer.put(charsetEncoder.encode(CharBuffer.wrap(request)));
buffer.put(END_OF_MESSAGE_BYTE);
buffer.flip();
socketChannel.write(buffer);
return readResponse();
}
//Read Response
protected String readResponse() throws Exception {
CharsetDecoder charsetDecoder = Charset.forName("ISO-8859-1").newDecoder();
int responseHeaderLength = 12;
ByteBuffer responseHeaderBuf = ByteBuffer.allocate(responseHeaderLength);
responseHeaderBuf.order(ByteOrder.BIG_ENDIAN);
int bytesRead = 0;
do {
bytesRead = socketChannel.read(responseHeaderBuf);
} while (bytesRead!=-1 && responseHeaderBuf.position()<responseHeaderLength);
if (bytesRead==-1) {
throw new IOException(carrier + " : Remote connection closed unexpectedly");
}
responseHeaderBuf.flip();
int lengthField = responseHeaderBuf.getInt();
int responseLength = lengthField - responseHeaderLength;
responseHeaderBuf.clear();
ByteBuffer responseBuf = ByteBuffer.allocate(responseLength);
bytesRead = socketChannel.read(responseBuf);
if (bytesRead>responseBuf.limit() || bytesRead ==-1) {
throw new IOException(carrier + " : Remote connection closed unexpectedly");
}
responseBuf.flip();
if (responseBuf.get(responseBuf.limit()-1)==END_OF_MESSAGE_BYTE) {
responseBuf.limit(responseBuf.limit()-1);
}
responseBuf.clear();
String response = charsetDecoder.decode(responseBuf).toString();
return response;
}
public static void main(String[] args) throws Exception{
SimpleConnector simpleConnector = new SimpleConnector("carrier",new InetSocketAddress("localhost",9999));
String response=simpleConnector.sendRequest("Request");
System.out.println(response);
}
}
I'm trying to rewrite the following piece using Netty. By using following tutorial as reference.
http://tutorials.jenkov.com/netty/netty-tcp-client.html
https://www.baeldung.com/netty
https://github.com/deepanprabhu/netty-twoway-tcp-client-server
The problem I'm facing is I was able to connect to server but couldn't read or write from it . I'm using a ChannelInboundHandlerAdapter to do the read and write operations.
Here is my Netty Client
public class NettyClient {
int port;
Channel channel;
EventLoopGroup workGroup = new NioEventLoopGroup();
public NettyClient(int port){
this.port = port;
}
public ChannelFuture connectLoop() throws Exception {
try{
Bootstrap b = new Bootstrap();
b.group(workGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.handler(new ChannelInitializer<SocketChannel>() {
protected void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new NettyClientHandler());
}
});
ChannelFuture channelFuture = b.connect("remote-ip", this.port).sync();
this.channel = channelFuture.channel();
return channelFuture;
}finally{
}
}
public void shutdown(){
workGroup.shutdownGracefully();
}
public static void main(String[] args) throws Exception{
try {
NettyClient nettyClient = new NettyClient(12000);
ChannelFuture channelFuture = nettyClient.connectLoop();
System.out.println("Sleep 2sec");
Thread.sleep(2000);
String command ="username";
final Charset charset = Charset.forName("ISO-8859-1");
int length = 13 + command.length();
if (channelFuture.isSuccess()) {
ByteBuf byteBuf = Unpooled.buffer(1024);
byteBuf.writeInt(length);
byteBuf.writeCharSequence("Some Info",charset);
byteBuf.writeCharSequence(command,charset);
channelFuture.channel().writeAndFlush(byteBuf).addListener(new ListenerImpl());
}
}
catch(Exception e){
System.out.println(e.getMessage());
System.out.println("Try Starting Server First !!");
}
finally {
}
}
private static final class ListenerImpl implements ChannelFutureListener{
public void operationComplete(ChannelFuture channelFuture) throws Exception {
if (channelFuture.isSuccess()){
System.out.println("Success"); //I can see success in Listener after write, but couldn't read response
}else {
System.out.println("Failed");
}
}
}
}
Handler
public class NettyClientHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
super.channelReadComplete(ctx);
}
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("NettyClientHandler : channelRead" );
ByteBuf byteBuf = (ByteBuf) msg;
String message = byteBuf.toString(Charset.defaultCharset());
System.out.println("Received Message : " + message);
}
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
System.out.println("NettyClientHandler : channelActive" );
}
}
I Initially thought netty will work only with netty servers.But this answer clear my doubt about that
Does a Netty client work with a netty server only?
Can some one guide me, what I'm doing wrong ???
I think the problem is with your ClientHandler. you should writeAndFlush() in channelActive method invoked when a connection has been established between the tcp server and client. Please use the below updated code and see whether it fixes the problem.
#Sharable
public class NettyClientHandler extends SimpleChannelInboundHandler<ByteBuf> {
#Override
public void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception {
String message = byteBuf.toString(Charset.defaultCharset());
System.out.println("Received Message : " + message);
}
#Override
public void channelActive(ChannelHandlerContext channelHandlerContext){
channelHandlerContext.writeAndFlush(Unpooled.copiedBuffer("Netty Rocks!", CharsetUtil.UTF_8));
}
}

Protocol Buffer Stream testing gRPC for a million messages

I am testing gRPC with a list of a million of items and sending this million of item by an stream.
I have this code on client:
on my test host: "Localhost", ipPort = 7777
ManagedChannel comunicationChanel = ManagedChannelBuilder.forAddress(host, ipPort)
.enableFullStreamDecompression().compressorRegistry(CompressorRegistry.getDefaultInstance())
.decompressorRegistry(DecompressorRegistry.getDefaultInstance()).usePlaintext(true)
.maxInboundMessageSize(200888896).build();
ListMessageSRVStub asyncStub = ListMessageSRVGrpc.newStub(comunicationChanel);
List<MessageValue> millionMessages = new ArrayList<MessageValue>();
for (long i = 0l; i < 1000000; i++) {
millionMessages.add(MessageValue.newBuilder().build());
}
long before = System.currentTimeMillis();
StreamObserver<MessageValue> requestObserver = asyncStub.recievetonm(responseObserverTonMessages);
long i = 0;
for (MessageValue messageValue : millionMessages) {
requestObserver.onNext(messageValue);
i++;
if (i % 50000 == 0) {
LOG.info("Sended: " + i);
}
}
requestObserver.onCompleted();
long total = System.currentTimeMillis() - before;
LOG.info("Time = " + total);
but I have this Exception:
Exception in thread "main" io.netty.util.internal.OutOfDirectMemoryError: failed to allocate 16777216 byte(s) of direct memory (used: 1879048487, max: 1894252544)
at io.netty.util.internal.PlatformDependent.incrementMemoryCounter(PlatformDependent.java:640)
at io.netty.util.internal.PlatformDependent.allocateDirectNoCleaner(PlatformDependent.java:594)
at io.netty.buffer.PoolArena$DirectArena.allocateDirect(PoolArena.java:764)
at io.netty.buffer.PoolArena$DirectArena.newChunk(PoolArena.java:740)
at io.netty.buffer.PoolArena.allocateNormal(PoolArena.java:244)
at io.netty.buffer.PoolArena.allocate(PoolArena.java:214)
at io.netty.buffer.PoolArena.allocate(PoolArena.java:146)
at io.netty.buffer.PooledByteBufAllocator.newDirectBuffer(PooledByteBufAllocator.java:324)
at io.netty.buffer.AbstractByteBufAllocator.directBuffer(AbstractByteBufAllocator.java:185)
at io.netty.buffer.AbstractByteBufAllocator.buffer(AbstractByteBufAllocator.java:121)
at io.grpc.netty.NettyWritableBufferAllocator.allocate(NettyWritableBufferAllocator.java:51)
at io.grpc.internal.MessageFramer.writeKnownLengthUncompressed(MessageFramer.java:226)
at io.grpc.internal.MessageFramer.writeUncompressed(MessageFramer.java:167)
at io.grpc.internal.MessageFramer.writePayload(MessageFramer.java:140)
at io.grpc.internal.AbstractStream.writeMessage(AbstractStream.java:52)
at io.grpc.internal.ClientCallImpl.sendMessage(ClientCallImpl.java:438)
at io.grpc.ForwardingClientCall.sendMessage(ForwardingClientCall.java:52)
at io.grpc.ForwardingClientCall.sendMessage(ForwardingClientCall.java:52)
at io.grpc.stub.ClientCalls$CallToStreamObserverAdapter.onNext(ClientCalls.java:320)
at com.oesia.grpgtest.server.TestClient.tonsofMSG(TestClient.java:130)
at com.oesia.grpgtest.server.TestClient.main(TestClient.java:146)
Any way to solve the problem sending that amounght of data?
Have you tried writing to with respect to slow receivers:
public class GracefulWriteHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelActive(ChannelHandlerContext ctx) {
writeIfPossible(ctx.channel());
}
#Override
public void channelWritabilityChanged(ChannelHandlerContext ctx) {
writeIfPossible(ctx.channel());
}
private void writeIfPossible(Channel channel) {
while(needsToWrite && channel.isWritable()) {
channel.writeAndFlush(createMessage());
}
}
}
I solve with this class, usin my own observer:
class OwnClientResponseObserver implements ClientResponseObserver<MessageValue, MessageValue> {
private ClientCallStreamObserver<MessageValue> requestStream;
private CountDownLatch countDownLatch;
Iterator<MessageValue> iterator;
public OwnClientResponseObserver(CountDownLatch countDownLatch, final Iterator<MessageValue> iterator) {
this.countDownLatch = countDownLatch;
this.iterator = iterator;
}
#Override
public void onNext(MessageValue value) {
LOG.info(value.toString());
}
#Override
public void onError(Throwable t) {
LOG.log(Level.SEVERE, "An savage error apears", t);
}
#Override
public void onCompleted() {
LOG.info("Finalized!!!");
}
#Override
public void beforeStart(ClientCallStreamObserver<MessageValue> requestStream) {
this.requestStream = requestStream;
this.requestStream.disableAutoInboundFlowControl();
this.requestStream.setOnReadyHandler(new Runnable() {
#Override
public void run() {
long i = 1L;
while (requestStream.isReady()) {
if (iterator.hasNext()) {
requestStream.onNext(iterator.next());
if (i % 1000 == 0) {
LOG.info("Checked in" + i);
}
i++;
} else {
requestStream.onCompleted();
countDownLatch.countDown();
}
}
}
});
}

JAVA RMI get pass ArrayList element

I have a server that contains an ArrayList in " ServerInfo " and when I try to take from ClientRMI an element of the ArrayList(in ServerInfo) for example adf.getSGM ( 0 ).incrementCount( ) ;
"count" does not increase it's as if every time I call it instantiates a new class SGM
in a few words I want to interact from ClientRMI with ArrayList that is on ServerInfo (SORRY FOR ENGLISH)
Hear are the classes :
SERVER
public class ServerRMI {
public static void main(String[] args) {
Registry registry = null;
String name = "ServerInfo";
try {
System.out.println("Init RMI");
ServerInfoInterface sir = ServerInfo.getInstance();
ServerInfoInterface stub = (ServerInfoInterface) UnicastRemoteObject.exportObject(sir, 0);
registry = LocateRegistry.createRegistry(9000);
registry.bind(name, stub);
System.out.println("RMI OK");
System.out.println("Init SGM...");
for(int i=0;i<3;i++){
ServerInfo.getInstance().addSGM(new SGM());
}
System.out.println("Init SGM OK");
} catch (Exception e) {
System.out.println("RMI Error"+e.toString());
registry = null;
}
}
}
public class ServerInfo implements ServerInfoInterface{
private ArrayList<SGM> sgmHandler = new ArrayList<SGM>();
// Singleton pattern
private static ServerInfo instance;
// Singleton pattern
public static ServerInfo getInstance() {
if (instance == null){
System.out.println("ServerInfo new instance");
instance = new ServerInfo();
}
return instance;
}
#Override
public synchronized void addSGM(SGM sgm) throws RemoteException {
sgmHandler.add(sgm);
}
#Override
public synchronized SGM getSGM(int i) throws RemoteException {
return sgmHandler.get(i);
}
}
public interface ServerInfoInterface extends Remote{
public void addSGM(SGM sgm) throws RemoteException;
public SGM getSGM(int i) throws RemoteException;
}
public class SGM implements Serializable{
/**
*
*/
private static final long serialVersionUID = -4756606091542270097L;
private int count=0;
public void incrementCount(){
count++;
}
public void decrementCount(){
count--;
}
public int getCount(){
return count;
}
}
CLIENT
public class ClientRMI {
private ServerInfoInterface sgmInterface;
public void startServer() {
String name = "ServerInfo";
Registry registry;
try {
registry = LocateRegistry.getRegistry(9000);
try {
sgmInterface = (ServerInfoInterface) registry.lookup(name);
sgmInterface.getSGM(0).incrementCount();
System.out.println(sgmInterface.getSGM(0).getCount()); // always 0
} catch (AccessException e) {
System.out.println("RIM AccessException"+ e.toString());
} catch (RemoteException e) {
System.out.println("RIM RemoteException"+ e.toString());
} catch (NotBoundException e) {
System.out.println("RIM NotBoundException"+ e.toString());
}
} catch (RemoteException e) {
System.out.println("RIM RemoteException registry"+ e.toString());
}
}
}
You're creating an SGM at the server, passing it via Serialization to the client, incrementing its count at the client, and then expecting that count to be magically increased at the server.
It can't work.
You will have to make SGM a remote object, with its own remote interface, or else provide a remote method in the original remote interface to increment the count of a GSM, specified by index.

get contents of processed JSP into spring controller without using HttpClient?

So normally in a Spring controller you'd just return a ModelAndView object and forward the request to the JSP.
What I need to do is actually get the contents of that processed JSP so I can then send it in a JSONP response (ex: callback("processed HTML from JSP");)
I know I could just use HttpClient to get the contents but was wondering if there's a way to avoid that extra step by calling something like:
String contents = processJSP(modelAndView);
Updated for geek to show my final solution:
First you need a fake HttpResponse to hold the response:
#Service
public class SpringUtils {
private static final Logger LOG = Logger.getLogger(SpringUtils.class);
#Autowired private ViewResolver viewResolver;
#Autowired private LocaleResolver localeResolver;
public String renderView(HttpServletRequest request, ModelAndView mav) {
try {
View view = viewResolver.resolveViewName(mav.getViewName(), localeResolver.resolveLocale(request));
HttpServletResponse localResponse = new MyHttpServletResponseWrapper(new DummyResponse());
view.render(mav.getModel(), request, localResponse);
return localResponse.toString();
} catch (Exception e) {
return "";
}
}
public boolean doesViewExist(HttpServletRequest request, String viewName) {
try {
if (viewResolver.resolveViewName(viewName, localeResolver.resolveLocale(request)) != null) {
return true;
}
} catch (Exception e) {
LOG.error(e.getMessage(), e);
}
return false;
}
static class MyHttpServletResponseWrapper extends HttpServletResponseWrapper {
private StringWriter sw = new StringWriter();
public MyHttpServletResponseWrapper(HttpServletResponse response) {
super(response);
}
public PrintWriter getWriter() throws IOException {
return new PrintWriter(sw);
}
public ServletOutputStream getOutputStream() throws IOException {
throw new UnsupportedOperationException();
}
public String toString() {
return sw.toString();
}
}
}
DummyResponse
public class DummyResponse implements HttpServletResponse {
public DummyResponse() {
}
public void setAppCommitted(boolean appCommitted) {}
public boolean isAppCommitted() { return false; }
public int getContentCount() { return -1; }
public boolean getIncluded() { return false; }
public void setIncluded(boolean included) {}
public String getInfo() { return null; }
public ServletResponse getResponse() { return null; }
public OutputStream getStream() { return null; }
public void setStream(OutputStream stream) {}
public void setSuspended(boolean suspended) {}
public boolean isSuspended() { return false; }
public void setError() {}
public boolean isError() { return false; }
public ServletOutputStream createOutputStream() throws IOException {
return null;
}
public void finishResponse() throws IOException {}
public int getContentLength() { return -1; }
public String getContentType() { return null; }
public PrintWriter getReporter() { return null; }
public void recycle() {}
public void write(int b) throws IOException {}
public void write(byte b[]) throws IOException {}
public void write(byte b[], int off, int len) throws IOException {}
public void flushBuffer() throws IOException {}
public int getBufferSize() { return -1; }
public String getCharacterEncoding() { return null; }
public void setCharacterEncoding(String charEncoding) {}
public ServletOutputStream getOutputStream() throws IOException {
return null;
}
public Locale getLocale() { return null; }
public PrintWriter getWriter() throws IOException { return null; }
public boolean isCommitted() { return false; }
public void reset() {}
public void resetBuffer() {}
public void setBufferSize(int size) {}
public void setContentLength(int length) {}
public void setContentType(String type) {}
public void setLocale(Locale locale) {}
public Cookie[] getCookies() { return null; }
public String getHeader(String name) { return null; }
public Collection<String> getHeaders(String arg0) { return null; }
public Collection<String> getHeaderNames() { return null; };
public String[] getHeaderValues(String name) { return null; }
public String getMessage() { return null; }
public int getStatus() { return -1; }
public void reset(int status, String message) {}
public void addCookie(Cookie cookie) {}
public void addDateHeader(String name, long value) {}
public void addHeader(String name, String value) {}
public void addIntHeader(String name, int value) {}
public boolean containsHeader(String name) { return false; }
public String encodeRedirectURL(String url) { return null; }
public String encodeRedirectUrl(String url) { return null; }
public String encodeURL(String url) { return null; }
public String encodeUrl(String url) { return null; }
public void sendAcknowledgement() throws IOException {}
public void sendError(int status) throws IOException {}
public void sendError(int status, String message) throws IOException {}
public void sendRedirect(String location) throws IOException {}
public void setDateHeader(String name, long value) {}
public void setHeader(String name, String value) {}
public void setIntHeader(String name, int value) {}
public void setStatus(int status) {}
public void setStatus(int status, String message) {}
}
Probably not possible easy way.
Maybe injecting view resolver into controller and calling render with special response will help, but not sure :
ViewResolver viewResoler = // injected
View view = viewReslover.resolveViewName(String viewName, Locale locale);
HttpServletResponse xresponse = // custom response, buffers data
view.render(Map model, HttpServletRequest request, HttpServletResponse xresponse);
String content = // extract conten from data from xresponse
'

Obfuscating the SSL client Hello v2 message in Java

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);
}
}

Categories