I'am really sorry if this is a duplicate question but I tried many answers in other threads and none of them worked for me.
I'am trying to send an ISO8583 message to a remote server through an SSLSocket using the TLSv1.2 protocol, I configured the certificate with the Keystore and attempted to send a sample ISO8583 message : 08002220010000800000900000011312115000000180105000003
0800: MTI
2220010000800000: Binary Hex Encoded Bitmap (Only fields 3, 7, 11, 24, 41 are present)
900000: Process code
0113121150: Transmission Date&Time
000001: STAN
801: Function code
05000003: Terminal ID
I then converted the message to an array of bytes and sent it with the socket OutputStream but no response came from the server and it is freezing when attempting to read the InputStream.
For the purpose of this question, I chose to test a manually-set sample message and not use any packaging method.
I'm very new to the ISO8583 so I don't exactly know what I'm doing wrong.
Here is the code I tried so far and thank you so much to who ever that will try to help me.
Thread thread = new Thread(() -> {
try {
X509TrustManager[] tmm;
KeyStore ks = KeyStore.getInstance("BKS");
InputStream is = getResources().openRawResource(R.raw.tunrootca2);
ks.load(is, KEY_PASSWORD.toCharArray());
tmm=tm(ks);
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
ctx.init(null, tmm, null);
SSLSocketFactory SocketFactory = ctx.getSocketFactory();
SSLSocket socket = (SSLSocket) SocketFactory
.createSocket(REMOTE_ENDPOINT, REMOTE_ENDPOINT_PORT);
String sampleMessage = "080022200100008000009000000113120000000180105000003";
byte[] bytesMessage = sampleMessage.getBytes(StandardCharsets.UTF_16LE);
byte[] bytes = packData(bytesMessage);
OutputStream out = socket.getOutputStream();
out.write(bytes);
byte[] buffer = new byte[256];
InputStream in = socket.getInputStream();
int read;
while((read = in.read(buffer)) != -1) {
String output = new String(buffer, 0, read);
Log.v("SOCKET_OUTPUT", output);
}
} catch (Exception e) {
e.printStackTrace();
}
});
thread.start();
});
PackData Function
static byte[] packData(byte[] data) {
int len = data.length;
byte buf[] = new byte[len + 2];
buf[0] = (byte) (len >> 8 & 255);
buf[1] = (byte) (len & 255);
System.arraycopy(data, 0, buf, 2, len);
return buf;
}
Settuing up socket communication can be tricky. If possible, I'd advise using WebSockets for communication, as they're already set up with how the communications protocols connect.
But if you are going to stick with plain sockets:
After your write call, call flush();
out.write(bytes);
out.flush();
If 1 didn't work, things get trickier. Since you don't control the server side part of this, it's hard to know what you need to send them in order to get them to send you something back. You might try sending a newline character. But otherwise, there's a mismatch between what you are sending and what the server on the other end is expecting
--- Edit ---
I looked up ISO 8583 and have a better idea of what you are trying to do. You can ignore my previous suggestion on using WebServer sockets.
You are missing the basics. You can't build ISO messages using string concatenation. You have to set correct bitmaps for those enable fields. Maybe try to follow the below sample. It will guide you with the basics.
https://kodejava.org/how-do-i-pack-an-iso-8583-message/
Your code looks ok. What sort of backend are you connecting to? 8583 is a bit like xml, it's a format description, but every processor uses it to build their own specific protocol from it, so you really need to ask the vendor you are connecting to for protocol documentation.
Some things that may be the matter:
flush the OutputStream when you are done writing, the message may still be hanging in your OS buffer
check the vendor documentation whether you need some sort of framing you may need to append a checksum to the message or ...
you may need to prepend a length header to the message. 8583 was originally built on top of relay protocols where the transport handled message length. A lot of parsers haven't caught up yet with the transition to TCP/IP :)
Related
InputStream in = socket.getInputStream();
byte[] content = new byte[2048];
int received = in.read(content, 0, content.length);
System.out.println(received);
Using this code, I would like to know how I retrieve only the number of bytes that the server sends me.
I was told to use a loop using a Buffer, but as I am new to this area, I didn't quite understand what it means, could someone give me a hand?
You are storing the number of bytes that the server sends you in the received variable. If you want to convert the data that the server sent into a string for debugging purposes, this is how you can do it:
int received = in.read(content, 0, content.length);
String messageFromServer = new String(content, 0, received);
Note that in general you need to call read multiple times in order to receive all the data from the server, just like with any InputStream. You can find tutorials on using Input and OutputStreams here:
https://docs.oracle.com/javase/tutorial/essential/io/bytestreams.html - specific example for reading and writing files, but sockets are no different.
http://tutorials.jenkov.com/java-io/inputstream.html - more general and thorough tutorial
I am testing a java code to issue AT Commands to the Modem at the designated port. I was able to successfully make Socket connection to the Modem's default gateway IP and AT Command port and write AT commands to that socket. (something like below)
Socket socket = new Socket(address, port);
socket.setKeepAlive(true);
...
String command = "AT\r\n";
...
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
byte[] commandBytes = command.getBytes(StandardCharsets.US_ASCII);
out.write(commandBytes, 0, commandBytes.length);
out.flush();
And try to read the response from the socket as below
BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
byte[] byteArray = new byte[1024];
int count = in.read(byteArray, 0, byteArray.length);
System.out.println("Response Received: " + new String(byteArray, StandardCharsets.US_ASCII));
The problem is, I am getting bad characters (like ??) as the response. I am expecting the output as "OK". When I issue the same command from the command prompt of the same PC where I am running this code, I am getting the response in proper English. I am assuming (mostly true) that the modem might be using a different language like C, C++ and their byte rage is different from the byte range of Java. But if this is the case, I am not sure how to fix it. Need help.
Things that I have already tried:
Printed the bytes as retrieved and found that these are of negative byte values (like -1, -3, -5 etc)
Verified the default of charset of the modem and if found to be ISO-8859-1 and tried using the same in my code (both write and read) still getting similar bad characters only
Tried reading as characters using BufferredReader* classed, but nothing is getting received at the response
My question in short, how to read the binary(byte array) data received as response from Modem for the given AT commands issued from Java Socket Connection?
Any help in this regard is highly appreciated.
The program consist that I have to send a byte from by Android app to a Wifi Access Point, then this byte is interpreted by a hardware device.
I can send byte to client and it receives the byte correctly (and more bytes, don't know why, maybe because protocol). Hardware filter protocol bytes and catch only the correct one.
There's is how i send it (byte es created previously in another method, but it's correct):
public static void sendByte (Byte data) throws IOException {
DataOutputStream output;
Socket client;
client = new Socket("1.2.3.4", 2000);
output = new DataOutputStream(client.getOutputStream());
output.write(data);
output.close();
client.close();
Log.w("INFO","Data sended");
}
When I send the byte, hardware part change the color of a light, and it happens successfully.
I putted this 3 lines too:
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Until here there's no problem.
Then I want to receive from that hardware bytes too. Imagine that someone change the color of that light, I want to know it. So I created a receiving method:
public static String readByte() throws IOException{
InputStream input;
DataInputStream iData;
String data = null;
try {
byte[] bytes = {0, 0, 0, 0, 0, 0, 0, 0};
Socket server = new Socket(2000);
Socket client = server.accept();
input = client.getInputStream();
iData = new DataInputStream(input);
Scanner scanner = new Scanner(iData);
iData.skip(0);
iData.read(bytes, 0, 8);
data = bytesToHex(bytes); //A simple method that change bytes to hex, this method it's correct
Log.w("READ", "" + data);
input.close();
client.close();
server.close();
}catch(IOException e){
Log.w("EROR","No es pot conectar");
}
return data;
}
Here I create a server that connects to client to get data (I don't know if it's necessary to create a server). The problem is that I always receive 7 bytes, and they are always the same, I used skip(7) to skip the protocol bytes, but then I don't receive anymore bytes.
I know that the hardware send bytes through the wifi where I'm connected, but I can't catch them.
_________TO SUM UP_________
I think the problem is that I can't catch the bytes because the hardware part simply send me, and my Android app can't store it. I would like to read the byte just when hardware sends me it, or something like this. I searched methods everywhere and object attributes and I can't find a solution to this :(
Thanks for your attention.
Wanted to know to if ServerSocket is strictly necessary or not.
When java program sends data to hardware, at that time, java program is the client and hardware is the server.
When the hardware sends data to java program, the hardware is the client and your java program is the server.
So, in your java program, you need to have two threads, one client thread (with a Socket to send bytes) and a server thread (with a ServerSocket, lets say for example, on port 8999) to receive bytes.
For the hardware to send you the bytes, it needs the following details.
1. IP Address or host name of the device on which your java program runs.
2. The port in which the ServerSocket is listening (8999 in our case).
If your hardware manual says it can send data to you, then, I am sure you can configure these details somewhere. (I am not sure what your hardware is. So, look at your hardware manual about how to configure these details).
Sometimes, the device can send response on the same Socket you opened. (Again, I am at a loss how it is done in your hardware. Refer your hardware manual). In such case, keep your socket open and read from it in a separate thread.
I am trying to read strings from a Bluetooth SPP server into my Android client. The server works fine, and sends the strings to the client as is evidenced in the Logcat.The LogCat indicates that bytes are read in from the btSocket. However, my attempt to read from the socket and display to the strings to the TextView has been futile. Here is the Android client and here is the logcat to evidence that the server works fine. Some Android & java guru to kindly assist. Thanks.
Try something like this :
byte[] buffer = new byte[1024];
int bytes;
inFromServer = nmeaServerSocket.getInputStream();
bytes = inFromServer.read(buffer);
String readMessage = new String(buffer, 0, bytes);
Log.d(TAG, "Message :: "+readMessage);
Hope it helps you.
Thanks.
My question is: is there a way to perform a socket OutputStream shutdown or it is not right/fully implemented as it should be by nokia? (J2ME nokia implementation, tested at nokia c6-00 and not closing stream, tested on emulator and works fine)
The main problem is that J2SE server application does not get the end of stream info, the condition read(buffer) == -1 is never true, tries to read from an empty stream and hangs until client is force-killed. This works with a very, very, very ugly workaround on the server side application
Thread.sleep(10);//wait some time for data else you would get stuck........
while ((count = dataInputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, count);
if (count != BUFFER_SIZE_1024 || dataInputStream.available() == 0) { //the worlds worst condition ever written... but works
break;
}
Thread.sleep(10);//wait for data input to get some data for dataInputStream.available() to return != 0 if client still sends data else you would not read all data......
}
but this solution is absolutely not acceptable (i dont know something about nokia java coding, i'm missing something, or is it maybe similar to a some sort of nokia-J2ME coding standard and i should get used to it or change platform)
I can't close the client socket after sending data because server sends a response to the client after receiving and processing data.
It looks like this: J2ME client -> J2SE server (hangs on read because client does not perform a outputstream shutdown) -> J2ME
I've tried to:
close the dataOutputStream on the J2ME client - no effect
setSocketOptions (KEEPALIVE, SNDBUF and others) - no effect or errors
nothing seems to work on the target device
sorry but i'm a bit furious right now after this nonsense fight with little java.
I'have searched for the solution but non seems to work
Client code:
SocketConnection socketConnection = (SocketConnection) Connector.open("socket://" + ip + ":" + port);
int count;
byte[] buffer = new byte[BUFFER_SIZE_1024];
// client -> server
DataOutputStream dataOutputStream = new DataOutputStream(socketConnection.openDataOutputStream());
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
while ((count = byteArrayInputStream.read(buffer)) != -1) {
dataOutputStream.write(buffer, 0, count);
dataOutputStream.flush();
}
dataOutputStream.close();
byteArrayInputStream.close();
With J2SE, my advice would be to initialize Socket from the java.nio.channels.SocketChannel and just interrupt the blocked thread after reasonable timeout has expired.
I'm not sure which side you are trying to fix, but looks like with J2ME your only option would be to set socket timeout.
EDIT
Actually, now that you've posted client code, I see the problem. If the exception is thrown from the while loop for whatever reason, the output stream is not closed.
Here is my proposed fix for that:
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
try
{
DataOutputStream dataOutputStream = new DataOutputStream(
socketConnection.openDataOutputStream()
);
try
{
while ((count = byteArrayInputStream.read(buffer)) != -1) {
dataOutputStream.write(buffer, 0, count);
dataOutputStream.flush();
}
}
finally
{
dataOutputStream.close();
}
}
finally
{
byteArrayInputStream.close();
}
Note, that it is not strictly necessary to close ByteArrayInputStream, but the code has a habit to mutate, and some day that input stream may become something that needs explicit close.
I've tried the code with the same effect - on the emulator works like a charm, on the device hangs but i solved my problem as follows:
On the J2ME client before sending the 1024 byte packet I'm sending its length and its state (IsNext or IsLast) after this on the J2SE server side in a while(true) loop. I'm reading first the length with a readShort, then state with a readByte (I know it's better to combine it on a one short but I didn't knew if it will work and if the effort was worth it and now when it works I'm not touching this, besides it is easy to add a new state if necessarily and it works quite fast).
After this server goes in to a second nested loop [ while (dataInputStream.available() < length) {} - I'll have to put here a timeout but I'll worry about that later. Also note that on J2ME dataInputStream.available() always returns a 0 (!) so in the J2ME client read in this place is a for (int i = 0; i < length... loop reading a single byte]
When the while(dataInputStream.available() ... loop breaks I'm reading a block of data which length I have, and if the state is IsLast I break the while(true) loop. Works perfectly and stable.
Thanks for the advice and hope this info will help someone