SSL Socket OutputStream Write Slow only on Windows - java

Server: Linux
Tested Clients: OS X, CentOS, Windows
Server/Client Programming Language: Java
Server-side
SSLServerSocketFactory sslserversocketfactory =
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
SSLServerSocket sslserversocket =
(SSLServerSocket) sslserversocketfactory.createServerSocket(9999);
SSLSocket sslsocket = (SSLSocket) sslserversocket.accept();
InputStream inputstream = sslsocket.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
String string = null;
while ((string = bufferedreader.readLine()) != null) {
System.out.println(string);
System.out.flush();
}
Server Program executed with this option
-Djavax.net.ssl.keyStore=mySrvKeystore -Djavax.net.ssl.keyStorePassword=123456
Certificate: Created with keytool on Linux
keytool -genkey -keystore mySrvKeystore -keyalg RSA
Client Side
....
SocketAddress sa = new InetSocketAddress(ip, port);
....
SSLContext sslContext = SSLContext.getInstance("SSL");
....
sslContext.init(.........., new SecureRandom());
SSLSocketFactory socketFactory = sslContext.getSocketFactory();
this.clientSock = socketFactory.createSocket();
this.clientSock.connect(sa, this.ConnectTimeout);
this.clientSock.setSoTimeout(this.RecvTimeout);
this.clientSock.setReuseAddress(true);
....
public boolean writeTo(String procname, BufferedOutputStream out, byte[] data)
{....
out.write(data, 0, data.length);
out.flush();
....}
Results: Everything works great but only client program from windows, it gets delayed when write to outputstream.
SSL Socket connection made
Set Output/Input stream
Write data into output stream
flush
... for 4-5 secs, it got stuck here with no reason at this point ...
close
The delay happens on the same java client simple program executing from Windows 7, Windows XP.
Tested from 3 different windows machine.
Everywhere else works great.
So I tried to build SSL simple clients with C and PHP, works great from Windows.
That means only Java clients method is not working.
Does anyone have any idea or similar experience before?
I'v seen some posts suspecting on WINS/DNS, but it seems like it's not the case here.
Also the funny thing is, it's always about 4-5 seconds of delay from every windows machine.
Thanks a lot for your comments in advance.

I've experienced a similar issue. Using tcpdump, I found that the TCP connection from client to server (SYN, SYN-ACK, ACK) happens almost instantaneously, then a mysterious pause, then the client actually sends the data.
The tcpdump output indicates that, immediately after connecting, the client (running on Windows) sends a NetBIOS name request (presumably to find out the name of the server, perhaps so it can choose an appropriate certificate or something) and the server immediately replies with an ICMP response saying the NetBIOS UDP (137) port is unreachable. It looks like the windows client ignores that response. After 1.5 seconds the windows client sends another NetBIOS name request, and the server sends the same ICMP response. After another 1.5 seconds the windows client sends a third and final NetBIOS name request, and the server sends back the same ICMP response. The socket data is finally transmitted 1.5 seconds after that.
So it looks like windows tries three times to determine the NetBIOS name of the server, and waits 1.5 seconds each time. Eventually (after 4.5 seconds) it gives up and sends the data. I think this explains the 4-5 second pause you reported.
One workaround to eliminate the pause is to add a 'hosts' file entry for the server. (It doesn't really matter what hostname you use within that file. The mere presence of an ip address avoids the need for the NetBIOS name resolution.) There are probably other alternatives too (e.g. add the server name to WINS or DNS or something, depending on what your windows machine is using for name resolution).

You're complaining about writing and you're only showing the reading code. What does the writing code look like? If you're not using a buffered stream or writer in the stack to the SSLSocket you can get data size explosions of up to 44 times, which would affect performance severely. I did some extensive testing over the Internet a few years ago and the conclusion was that with properly written code, SSL isn't any worse than 3 times as slow as plaintext.

Related

Got 200 FTP reply code but file not sent

Ive got a little problem which slowly makes me frustrated. I need to send file to FTP server over TLS, using org.apache.commons.net.ftp.FTPSClient and got a 200 reply code after calling storeFile() method but i don't see any result on a server.
FTP server is not running on my local host. When I do the same thing but using a Filezilla client then it's all done without any problems in both passive and active modes.
FTPSClient ftpsClient = new FTPSClient("TLS", false);
ftpsClient.connect(server, port);
boolean logged = ftpsClient.login(user, pass);
ftpsClient.enterRemotePassiveMode();
System.out.println(ftpsClient.getReplyCode());
ftpsClient.execPBSZ(0);
ftpsClient.execPROT("P");
ftpsClient.sendCommand("TYPE", "A");
System.out.println(ftpsClient.getReplyCode());
File file = new File("config.xml");
InputStream inputStream = new FileInputStream(file);
boolean done = ftpsClient.storeFile("config.xml", inputStream);
System.out.println(ftpsClient.getReplyCode());
inputStream.close();
result of this code execution is:
227
200
200
But maybe this STOR command hasn't overed in fact and this 200 code is related to command before?
If somebody is interested in solution of this problem, it was about resuming ssl session which was required by server and not handled by client. After unselecting this option on filezilla server it has started to work properly.

Indefinite stale of TCP packet reception

Deplyment environment:
I have created a TCP server using JAVA over windows 10 OS. My TCP client program is written in VC++ and runs on windows 7 OS (I don't have any control over this part of the code, it is a black box to me).
My TCP server code is like this:
Socket s = ss.accept();
s.setReceiveBufferSize(2000);
s.setSendBufferSize(2000);
s.setTcpNoDelay(true);
s.setKeepAlive(true);
new TcpConnectionHandler(s,this.packetHandler);
Following is the TCP connection handler snippet:
InputStream incomingPacketBuffer = this.clientSocket.getInputStream();
OutputStream outgoingPacketBuffer = this.clientSocket.getOutputStream();
int bufferLen=0;
byte inBuffer[] = new byte[this.clientSocket.getReceiveBufferSize()];
byte outBuffer[] = new byte[this.clientSocket.getSendBufferSize()];
while(this.clientSocket.isConnected())
{
bufferLen = incomingPacketBuffer.read(inBuffer);
if(bufferLen>0)
{
outBuffer = (byte[]) this.packetHandlerModule.invoke(this.packetHandler,Arrays.copyOf(inBuffer, bufferLen));
}
if(outBuffer != null)
{
if(this.clientSocket.isConnected())
{
outgoingPacketBuffer.write(outBuffer);
outgoingPacketBuffer.flush();
}
}
}
this.clientSocket.close();
The communication is packet based and the protocol/parsing is handled by packetHandler.
Two more variant I've tried:
I have tried to close the socket as and when a reply is sent back to the client. That is, after receiving one packet of data, I reply to the client and close the connection.
I used inputStream.available before using the read method.
The problem I face:
Most of the time the TCP server replies to incoming packets within a second. If the server receives a packet after some idle time, the server doesn't reply to the packet. Sometimes even when there is active communication is going on, the reply is not being transmitted. Secondly, the isConnected function returns true even when the client socket closed the connection.
Debugging attempts:
I used teraterm to send packets and checked it. The behavior is same. As long as I send packets one after another, I don't have an issue. If one packet doesn't get a reply, then every packet sent after that does not get reply from the server.
When I press Ctrl+C in server console, all the packets sent from teraterm is processed by TCP server and reply is sent back. After this the server works properly for some duration.
I checked the packet flow with wireshark. When the replies are sent back normally, it is sent along with the ACK of client request (SYN, SYN+ACK, ACK, PSH, PSH+ACK, FYN, FYN+ACK, ACK). When the reply gets staled (may not be the right term, it is stuck in inputStream.available or inputStream.read), only ACK packet is sent by server (SYN, SYN+ACK, ACK, PSH, ACK).
I checked many forums and other threads in stackexchange, learned about Nagle's algorithm, applicaion must take care of packetization in TCP, TCP may receive 10+10 packets as 8+12 or 15+5 or any such manner. The server code takes care of packetization, setKeepAlive is set to true (there is no problem when a packet is sent from server).
Problem in short: "At times, TCP read call is getting blocked for a long duration even when there is incoming packets. When Ctrl+C is pressed, they are getting processed."
PS: I just started posting queries on stackexchange, so kindly let me know if there is any issues in the way of formulating the query.
PPS: Sorry for such a long post.
UPDATE
The comment from EJB helped me to identify the peer disconnect.
I made another setup with Ubuntu 16.04 as operating system for server. It has been 3 days, windows system had the issue occasionally. Ubuntu 16.04 never staled.
Some things to consider;
the TCP buffer sizes are usually 8K at least and I don't think you can skink them to 2000 bytes, or if you can, I don't think it's a good idea.
the size of the byte[] doesn't really matter over about 2K, you may as well pick a value.
you can't need to be creating a buffer more than once.
So in short I would try.
Socket s = ss.accept();
s.setTcpNoDelay(true);
s.setKeepAlive(true);
new TcpConnectionHandler(s,this.packetHandler);
and
try {
InputStream in = this.clientSocket.getInputStream();
OutputStream out = this.clientSocket.getOutputStream();
int bufferLen = 0;
byte[] buffer = new byte[2048];
while ((bufferLen = in.read(buffer)) > 0) {
out.write(buffer, 0, bufferLen); // not buffered so no need to flush
}
} finally {
this.clientSocket.close();
}
At times, TCP read call is getting blocked for a long duration even when there is incoming packets.
Would write a test Java client to see that this is not due to behaviour in Java.

Sockets in Java...?

I need to build an application which can receive data from over a network and use this data to do some unrelevant things with.
Here's a piece of code to make clear what I'm doing.
On the server side:
static Socket client = null;
static ServerSocket ss = null;
if (ss != null) {
ss.close();
}
ss = new ServerSocket(5513);
isrunning = true;
System.out.println("Waiting for client...");
client = ss.accept();
System.out.println("Client accepted.");
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
And the client side:
Socket client = null;
PrintWriter out = null;
try {
client = new Socket("hostname", 5513);
out = new PrintWriter(client.getOutputStream(), true);
}
Please note that this is just a piece of the code. There are no errors in the code.
After running the server-sided piece of code, it correctly waits for the client to connect.
Now here comes the problem. As soon as I try to connect from the client side, I'm getting a "connection refused"-error.
HOWEVER, I found something on the internet whoch told me to try telnetting from the client side. For example, let the server-sided IP be 192.168.1.1. So, after using this command:
telnet 192.168.1.1 5513
I actually get a connection with the server. The command will launch an empty screen, and everything I manually type in the command line will be sent to the server-side after pressing enter (checked with debugging).
So, I can manually connect to the server-side and send some data, but my code refuses to connect.
Anyone who knows what I am doing wrong?
Is this the code you're actually using?
client = new Socket("hostname", 5513);
Try changing it to:
client = new Socket("192.168.1.1", 5513);
client = new Socket("hostname", 5513);
Hostname needs to represent the IP Address you're connecting to. If you're trying to connect to yourself, it would be "localhost"
Also, the server is not listening for the client AT ALL TIMES, there must be a while loop so the server listens and accepts connections.
while (true) {
client = ss.accept();
out = new PrintWriter(client.getOutputStream(), true);
//You should probably assign it to a seperate thread to handle stuff for this client
}
And I should explain on why you're getting that particular error. When something says that the connection is refused, it usually means that the IP Address you want to connect to knows your sending a connection and is blocking it because it was not listening for that connection. Basically, when the server closed, you stopped listening for the client, so anything that came in on that port would be blocked. Of course, the other case could be that Java was blocked on your firewall and an exception should be made for it. Although this is rarely the case if what you're trying to accomplish is over a LAN.
You're not actually using "hostname" in your Socket object in the client are you?
It should the 192.168.1.1.
Are you on Windows? and If so have you added java.exe and javaw.exe to Firewall with inbound and outbound enabled? and have you added a rule for 5513 to your Firewall?
If yes Windows but no Firewall settings, that's your answer, open up your Firewall.

Android communication to server very slow due to long DNS packets

I am working on a project that communicates to a server through a URLConnection.
Here is the code:
URL theSite;
theSite = new URL(TestURL);
URLConnection con = theSite.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
However this is taking my Motorola Atrix and Samsung Nexus S about 20 seconds or more to when talking with the server. (Information does get sent eventually it seams) Looking at the packets in wireshark, I've found that there are many groups of DNS packets sent which with about 3-5 seconds between each one. This is likely the cause of the slow communication.
Here is are two sample DNS packets. (I've changed the IP's, except for the destination of 8.8.8.8 which I believe is google)
Time Source Destination Protocol Info
20.308792 10.10.120.104 8.8.8.8 DNS Standard query PTR 3.120.10.10.in-addr.arpa
25.360726 10.10.120.104 8.8.8.8 DNS Standard query PTR 3.120.10.10.in-addr.arpa
Anyways, this happened today out of the blue. But it is very apparent that it is these DNS calls that are causing slow communication between the server and my device.
Another thing of note, is that I have also tried the EXACT same code on the Samsung Galaxy 10.1 tablet and it works fine. Looking at the packet trace there are no Extra DNS calls from the tablet.
I don't have control over the server, and had the packets sent to me. Does anyone have any suggestions? I'm guessing that it is a server related issue. If anyone has any ideas, it is much appreciated.
Thanks!
Are you using 4g or 3g? I had a very similar experience today, and noticed the delay was only present when using 4g. 3g seems to be fine.
AFAIK, 4g uses ipv6 addresses by default, while 3g uses ipv4 by default. That delay is ipv6 failing, getting to the failover, and finally being rerouted. For me, it took about an extra 20 seconds.
Currently, I am waiting on feedback from the server team to see if our DNS is set up to handle ipv6 properly.
But honestly, this is only as far as I got, sorry it is nothing definite.
We have figured this out. Turns out on the servers side, there were issues routing DNS packets and they kept timing out which they have fixed.
Something we added to help make sure that this issue doesn't happen again, is manually setting the DNS timeouts so that after failing once, the DNS packet timeout will be almost instant. Using InetSocketAddress is the key.
Here's some sample code to get this working.
int timeout = 0; //How ever long you want to set the timeout to.
somePageParameters = "Parameter String";
InetSocketAddress isock = new InetSocketAddress(ip, 1000);
Socket s = null;
s = new Socket();
s.connect(isock,timeout);
OutputStream os = s.getOutputStream();
String myString = "";
myString = "GET "+"/"+ somePageParameters+" HTTP/1.0\n\r\n\r";
System.err.println("Hitting with: "+myString);
byte outbuf[] = myString.getBytes();
os.write(outbuf);
os.flush();
Then use this socket as you normally would.
Hopefully this helps someone.

Create SSL-Socket on Android with self-signed certificate

I'm trying to connect an Android app to a SSL-enabled server, which uses a self-signed certificate. I've already read through dozens of tutorials and the app is now accepting the certificate & connecting to the server, but I never get any data back.
The original code i used to initialize the socket is this:
//passphrase for keystore
char[] keystorePass="password".toCharArray();
//load own keystore (MyApp just holds reference to application context)
KeyStore keyStore=KeyStore.getInstance("BKS");
keyStore.load(MyApp.getStaticApplicationContext().getResources().openRawResource(R.raw.keystore),keystorePass);
//create a factory
TrustManagerFactory trustManagerFactory=TrustManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
//get context
SSLContext sslContext=SSLContext.getInstance("TLS");
//init context
sslContext.init(
null,
trustManagerFactory.getTrustManagers(),
new SecureRandom()
);
//create the socket
Socket socket=sslContext.getSocketFactory().createSocket("hostname",443);
socket.setKeepAlive(true);
Afterwards, the run loop of the receiver thread uses socket.getInputStream() to access the input stream.
As long as I use an unencrypted connection, this works without a problem. But the secure connection does not retrieve any data from the socket. I've verified this by adding log messages to the receive loop and even used OpenSSL's s_server to check. I retrieved data from the client, but the client never received anything I sent to it.
As a last test, I tried to open a connection to www.google.com:443 like this:
javax.net.SocketFactory fact=SSLSocketFactory.getDefault();
Socket socket=fact.createSocket(_config.getUri().getHost(), _config.getUri().getPort());
Still the same result, connection works but using the InputStream I receive nothing from the server.
Anybody got any ideas?
EDIT:
I'm currently not allowed to answer my own question, but here's the answer:
Well, turns out the problem WAS the receive loop. I relied on InputStream.available() to get the number of bytes to read, but didn't realize it was rather unreliable (always returns 0 for SSL socket). So I switched the receive loop to use the blocking read() instead.
As mentioned above: Turns out the problem WAS the receive loop. I relied on InputStream.available() to get the number of bytes to read, but didn't realize it was rather unreliable (always returns 0 for SSL socket). So I switched the receive loop to use the blocking read() instead.

Categories