Apache Mina + SSL + Android not working - java

I'm developing an Android app using Apache Mina for network IO. Non-SSL connections (reading, writing) work fine, but as soon as I add an SSL filter things stop working.
I also tried pure SSL sockets and they work fine.
This is my Mina connection code (in a separate networking thread):
IoConnector connector = new NioSocketConnector();
connector.getSessionConfig().setReadBufferSize(2048);
SocketSessionConfig cfg = (SocketSessionConfig)connector.getSessionConfig();
cfg.setTcpNoDelay(true);
SslContextFactory f = new SslContextFactory();
f.setTrustManagerFactory(new BogusTrustManagerFactory());
f.setProtocol("SSL");
try {
filter = new SslFilter(f.newInstance(), true);
} catch (Exception e) {
Log.d(TAG, "Exception: ", e);
return;
}
filter.setUseClientMode(true);
connector.getFilterChain().addLast("sslFilter", filter);
connector.getFilterChain().addLast("logger", new LoggingFilter());
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("ASCII"))));
connector.setHandler(new MinaClientHandler());
ConnectFuture future = connector.connect(new InetSocketAddress("10.0.1.9", 7072));
future.awaitUninterruptibly();
if (!future.isConnected())
{
Log.d(TAG, "not connected, return");
return;
}
IoSession session = future.getSession();
session.getConfig().setUseReadOperation(true);
session.getCloseFuture().awaitUninterruptibly();
//System.out.println(session.read().getMessage());
Log.d(TAG, "after writting");
connector.dispose();
In my IoHandlerAdapter I have the following override:
#Override
public void sessionOpened(IoSession session)
{
session.write(IoBuffer.wrap(data)); // byte array
}
Not my actual code, but it reproduces the problem.
On the server side I see that the connection is accepted an the handshake succeeds. But on the client side nothing is sent over the socket. I have tried the same code in a desktop Java application and it also works.
Also if I move the write call just after IoSession session = future.getSession(); the same thing happens.
Has anyone had similar issues? Are there known issues with Mina on Android? Am I missing some session config options?
Since normal SSL sockets work, that is a workaround, but I would rather not rewrite all my networking code.

Related

After successfully establishing a socket connection, how does the server actively send string messages to the client?

I am building a server. I hope that after the Java server and the C# client are connected, I can send information from the HTML to the Java server, and then the Java server sends this information to the client.But I can't get the socket after the successful establishment in the service layer, so my Java server can only send fixed information to the client.
I tried using Class object = new Class(); object.setObject(socket); to save the socket, but when I call this object in the service layer, I get null;
I tried to save the socket using (Map) socket.put("socket", socket), but when I call this method in the service layer, I get null.
This is the code to make the socket. from SocketThread.java
public void run() {
ServerSocket serverSocket = null;
try{
serverSocket = new ServerSocket(5656);
LOGGER.info("socket server start, monitor 5656 port ! ");
Socket socket = serverSocket.accept();
new SocketClientRequest(socket).start();
LOGGER.info("send success ! ");
}catch (Exception ex){
LOGGER.error("send fail ! ");
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
LOGGER.error("服务器延时重启失败 ! ");
}
}
This is a method of reading the information sent by the client using the socket and sending the information to the client. from SocketClientRequest.java
public void run() {
try {
//获取socket中的数据
bufferedInputStream = new
BufferedInputStream(socket.getInputStream());
byte[] clientCharStream = new byte[messageLengthBytes];
bufferedInputStream.read(clientCharStream);
System.out.println(new String(clientCharStream, "utf-8"));
OutputStream out = socket.getOutputStream();
out.write(new String("welcome_send_server!").getBytes());
} catch (IOException e) {
LOGGER.error("read massage error [{}]", e);
}
}
Create a connection when the project starts
#EnableScheduling
#SpringBootApplication
public class GzserverApplication {
public static void main(String[] args) {
SpringApplication.run(GzserverApplication.class, args);
SocketServer socketServer = new SocketServer();
socketServer.start();
}
}
Until this step, everything is fine, but the key problem is coming.
I need to send information to the client through my controller.
this is controller
#ResponseBody
#RequestMapping(value = "firstSend)
public SResult<String> firstSend(String uName, String pNum, String time){
try{
return httpService.firstSend(uName, pNum, time);
}catch (Exception ex){
LOGGER.error(ex.getMessage(), ex);
}
return SResult.failure("fail of connect");
}
this is service
public SResult<String> firstSend(String uName, String pNum, String time) throws Exception {
String token = TokenUtil.sign(uName);
System.out.println("token code : "+token);
SocketObject socketObject = new SocketObject();
Map<String, Socket> socketMap = socketObject.socket();
Socket socket1 = socketMap.get("Socket"); // is null
Socket socket2 = socketObject.getSocket(); // is null
return SResult.success(token);
}
I hope that after the connection is successfully created, the socket can be used in the service layer, and the information is sent to the client through the socket, but no matter what I do, the socket is null in the service layer.please give me a help, thank you very much
You should not be dealing with Sockets if using Spring. Spring is a very extensive abstraction layer, that lets you avoid having to deal with the nasty details that Sockets introduce.
In your controller, you call: SocketObject socketObject = new SocketObject(); This creates a new object, presumably with a null-initialized Socket object. Nowhere in this code do you pass a socket object from the main() scope to any other scope (for example using a method named setSocket(Socket socket).
However, and I cannot stress this enough, you should not use Sockets in Spring. Think about what problem you are trying to solve, and ask yourself (why do I need to send information to the client). It is likely that Spring has a module that will do this for you in a much more scalable and manageable way.
For example, perhaps you need to establish 2-way communication between the server and the client, and need to post information to the client periodically. In this case, the WebSocket protocol (and associated Spring Websocket library) might be for you.
This is likely an XY problem. If you edit your question to illustrate the functionality you are trying to implement, it may be easier to help

Client-Server connects while being on the same computer but not while being run on different ones

I'm trying to build a basic client-server application.
When I run both the server and the client on the same computer both manage to connect without a hitch but if I try to do so from different computers (desktop and laptop) the connection doesn't get though. The server isn't even aware that someone tried to connect to it while the client timeouts after a while. At first I assumed that it's a firewall problem but disabling the firewall completely on the server PC did not help. Tried changing ports and checked on multiple computers. Any ideas what could cause this?
I control both the server and the client and can change the code of both if necessary. The server always runs on the same PC and I'm connecting to it directly using hardcoded IP address.
This is the code of the client sending random int to the server.
public static void main(String[] args) {
Socket s = new Socket();
try {
s.connect(new InetSocketAddress("123.45.67.891", 8084), 5000);
s.getOutputStream().write(42);
s.close();
} catch (IOException e) {
e.printStackTrace();
return;
}
}
The server is slightly more complicated but considering the fact that they manage to connect while being run from the same PC I assume that the problem isn't with it.
edit: Server code (Thread per client. There shouldn't be too many of those)
public void run() {
try {
serverSocket = new ServerSocket(listenPort); //integer
} catch (IOException e) { ... }
while (shouldRun) {
try {
Socket clientSocket = serverSocket.accept(); // Blocked here while trying to connect from remote computer
//Never gets here
ConnectionHandler newConnection = connectionHandlerCreator.create(clientSocket);
connectionHandlers.add(newConnection);
newConnection.initialize();
new Thread(newConnection).start();
} catch (IOException e) { ... }
}
}
Initialize consists of the following (which latter used for I/O).
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
out = new PrintWriter(clientSocket.getOutputStream(), true);
The problem is probably on your server side though: you have to make it respond to all ip's not just local one, by using the constructor:
ServerSocket(int port)
it will default accepting connections on any addresses which is not the case if you specified an IP

Java detect disconnect from Server in Client

I made an java-application which has a client- and a server-side. Both sides communicate via sockets. This works well until my server application is killed by something and can't close or shutdown the serversocket.
The client does not seem to notice the broken connection and just hangs itself while trying to read the next object.
I also tried sending a test object from the client every 5 seconds to detect that the server is offline, but that also does not work.
I might have to mention this only occurs when running the server app on Windows and the client on Linux (Ubuntu in VirtualBox). Windows-Windows works fine. Netstat even gives me an ESTABLISHED on Linux, although I already killed the server.
Client code:
requestSocket = new Socket("192.168.1.3", 1234);
out = new ObjectOutputStream(new CipherOutputStream(requestSocket.getOutputStream(), ec));
in = new ObjectInputStream(new CipherInputStream(requestSocket.getInputStream(), dc));
new Thread() {
public void run() {
while(true) {
try {
out.writeObject(obj);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("sent");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {}
}
}
}.start();
Server code:
serverSocket = new ServerSocket(1234);
socket = serverSocket.accept();
out = new ObjectOutputStream(new CipherOutputStream(clientSocket.getOutputStream(), ec));
in = new ObjectInputStream(new CipherInputStream(clientSocket.getInputStream(), dc));
//do-while-reading on the socket[...]
I read multiple threads which told me how to detect a lost connection on the server side, but found none for the client side or the answers did not work for me.
Set a read timeout on the socket, of suitable duration, enough to include all normal transfers, and catch SocketTimeoutException.
The problem seemed to be the VM. When testing it on my Laptop with Manjaro Linux, everything worked as it should have in the beginning!
Thank you for your contributions anyway. :)

Configure an App to use the proxy from settings

In my android application I need to connect to the internet to check for the time. This snippet works very nicely in mobile networks and in WiFi-Networks with no proxy enabled:
public class MyTimeGetterTask {
#Override
protected Long doInBackground(Void... params) {
WebTimeSntpClient client = new WebTimeSntpClient();
if (client.requestTime("time-d.nist.gov", 3000)) {
long now = client.getNtpTime() + SystemClock.elapsedRealtime()
- client.getNtpTimeReference();
return now;
}
else {
return null;
}
}
}
The core elements of the WebTimeSntpClient are as follows:
public class WebTimeSntpClient {
public boolean requestTime(String host, int timeout) {
DatagramSocket socket = null;
try {
socket = new DatagramSocket();
socket.setSoTimeout(timeout);
InetAddress address = InetAddress.getByName(host);
byte[] buffer = new byte[NTP_PACKET_SIZE];
DatagramPacket request = new DatagramPacket(buffer, buffer.length, address, NTP_PORT);
...
socket.send(request);
DatagramPacket response = new DatagramPacket(buffer, buffer.length);
socket.receive(response);
...
} catch (IOException ex) {
return false;
} finally {
if (socket != null) {
socket.close();
}
}
return true;
}
}
However when I'm in the office and the WiFi requires me to configure a proxy (which I did in the settings by long-pressing on the network and then clicking "modify network" - as of Android API level 17) the connection fails.
Now I have looked up quite a lot of very good posts about proxies on the internet and especially here on SO, but absolutely none of them seem to answer this (to me) very simple question:
How do I force my application to use the proxy that is already configured in the settings?
Instead, they focus on more advanced issues like:
How to GET a proxy from the system
How to SET ip information to the system yourself
and much much more about how to make existing applications from the play store use a proxy
Again: I want to stress that this is not my intention, I simply want my app to connect to the internet, no matter what. Is there some System.useWifiProxyIfAvailable(true) method? I'm sure I must have missed a post somewhere here...
You are trying to use SNTP trough a proxy that only allows HTTP/HTTPS.
Your alternative is to use some HTTP service providing the current time, which will be more than enough for most user level applications.
Give http://www.timeapi.org/utc/now a try, however if you are publishing an application using this service you should check the terms and conditions.

My server stops working when reading .accept(), using Sockets

please excuse my writing errors...
I'm using NetBeans to run a homemade server and a client, and it all works fine. As I said before, I'm using "Socket" on my client, and "ServerSocket" on my sv. I'm also using JDBC Mysql in the server.
The problem starts when I generate both java files in their distributable folders and use them. The client sends information to the server (it starts with .getOutputStream() and .getInputStream(), then .flush() ), but the server doesn't receive any message. I tried seeing where it stops and it's in
clients[i] = new Client (server.accept(), i);
The crazy thing happens when I try executing my server from NetBeans and the client from my desktop... It works! So the server must be the problem. I'm also using an opened UDP port, and i'm looking for the IP of the server on 192.168.0.10 (which is my computer, in LAN).
I hope someone can help me, thanks in advance!
Here I paste my code, i'm sorry some variables are in spanish:
public ServidorMultiCliente() {
super("Servidor MultiCliente");
initComponents();
try{
servidor = new ServerSocket( 500, maxNumberClients);
}catch(IOException excepcion){
excepcion.printStackTrace();
System.exit(1);
}
serverWriteBox.append("Server iniciated, waiting for connections..."); }
I run these, from the Server:
public void ejecutar(){
clientsAcceptor.start();
messagesListener.start(); }
Where clientsAcceptor is:
private class aceptadorClientes extends Thread{
public void run(){
for( int i = 1; i < maxNumberClients; i++ ){
try{
clientes[i] = new Cliente (servidor.accept(), i); // **Here it stops**
// It never reaches here... (without using NetBeans)
clientes[i].start();
clientes[i].aceptado = true;
}catch(IOException excepcion){
excepcion.printStackTrace();
}
}
That's how I accept clients in different threads. I make the same thing with messageListener, which is a new thread for every new client. It's in a loop, always listening. And here I paste my executable Client, which is different from the Cliente class I was using in ServidorMultiCliente:
public Cliente(){
}
public Cliente(String host){
this.host = host;
this.executeConnection();
}
public void executeConnection(){
int connect = 0;
try {
cliente = new Socket(InetAddress.getByName(host), 500);
conectar = 1;
} catch (IOException ex) {
conectar = 0;
this.ejecutarConexion();
}
if(conectar == 1){
obtainFlows();
}
}
private void obtainFlows(){
try{
output= new ObjectOutputStream( cliente.getOutputStream());
output.flush(); // Here I should be "connected"
input = new ObjectInputStream(cliente.getInputStream());
} catch(IOException ex){
this.initiateDisconnection();
}
sendFlows("I'm connected!");
new messageListener().start(); // This is a thread
}
ServerSocket#accept is a blocking call. It listens to a port and returns a Socket when a client connects. You don't show very much of your server logic but it seems you put clients in an array so you obviously want to support more than one client. You don't show if your Client class starts a thread and returns immediatly.
You should have a server loop that just listens to a server socket and creates clients after it retrieved a client socket. Even if you do this in your Client constructor (I can't tell without the code) it is not a very good place for this and seriously hinders debugging.
If you don't start threads for your clients this would explain a server that "stops" (if "stops" means "blocks" and not "crashes"). See "Writing the Server Side of a Socket" in the Java Tutorial for a detailed explanation.
I can't think of why it behaves different when started via Netbeans. A little bit more of code context is needed.

Categories