0

I need to sent a packet to a server using socket from my android application. I only know a packet layout:

Packet ID 4 bytes | Packet length 4 bytes(minus len + ID) | payload (protobuf message)

The whole stuff about TLSv1.2 connection and self-signed certificate works well. For example, I need to send authentication packet - LoginRequest and server will response with LoginResponse if the packet was sent successfully. What I am trying do to is connect to a server inside AsyncTask class, write data and receive response, but obviously I am doing it wrong because I got no response. The code for writing and reading a message:

LoginRequest protobuf message:

Protos.LoginRequest loginRequest = Protos.LoginRequest.newBuilder()
                    .setUsername(mailAddress)
                    .setPassword(pass).build();

And the code(inside doInBackground() method):

//TLSSocketFactory is custom SSLSocketFactory class for forcing TLSv1.2 on devices > 16 & < 20
socket = tlsSocketFactory.createSocket("airwave1.exurion.com", 2559);

byte[] payload = loginRequest.toByteArray();

DataOutputStream out = new DataOutputStream(socket.getOutputStream());
InputStream inStream = socket.getInputStream();

out.writeInt(10); //ID of the packet
out.writeInt(payload.length);
out.write(payload);

out.flush();

byte[] data = new byte[100];
int count = inStream.read(data);

out.close();
inStream.close();
socket.close();

As I said I got no response, Sometimes I also get an SSLException while reading the message:

javax.net.ssl.SSLException: Read error: ssl=0xb3a28580: I/O error during system call, Connection timed out

Has anyone an idea how to solve this?

//UPDATED I figured out that the byte order needs to be in LITTLE_ENDIAN, so I tried to use ByteBuffer:

//based on previous packet layout (4 bytes for ID, 4 bytes for payload length, and payload) - is it ByteBuffer.allocate() fine?
    ByteBuffer buffer = ByteBuffer.allocate(8 + payload.length);
    buffer.order(ByteOrder.LITTLE_ENDIAN);

    buffer.putInt(LoginPacketType.LOGIN_REQUEST.getId());
    buffer.putInt(payload.length);
    buffer.put(payload);

    buffer.rewind();
    byte[] result = new byte[buffer.capacity()]; // Could also use result = buffer.array();
    buffer.get(result);

    out.write(result);

But now I am getting OOM exception:

Failed to allocate a 184549388 byte allocation with 16777216 free bytes and 155MB until OOM

Details about that: After writing to an DataOutputStream, I make:

buffer.clear()
out.flush();

//code for reading from InputStream

And now, in my log appears this message several times: Starting a blocking GC Alloc

and than throws OOM exception.

2 Answers 2

1

The problem was with LITTLE_ENDIAN and BIG_ENDIAN order. Servers sends response in LITTLE_ENDIAN order so I rewrite your answer a bit:

int type = inStream.readInt();
type = Integer.reverseBytes(type);
int length = inStream.readInt();
length = Integer.reverseBytes(length);

if (length > 0) {
    byte[] data = new byte[length];
    inStream.readFully(data);
    Protos.LoginResponse response = Protos.LoginResponse.parseFrom(data);
}

Thanks for the hint.

Sign up to request clarification or add additional context in comments.

Comments

0

You're writing a packet type and length and payload, but you're only reading a payload. You're also assuming that read() fills the buffer.

int type = din.readInt();
int length = din.readInt();
byte[] data = new byte[length];
din.readyFully(data);

3 Comments

Thanks for the hint but still is not working, it stuck on reading. Probably the problem is when sending packet but I can't figure it out.
If this code is stuck in reading, the other end isn't sending this protocol.
What is din here supposed to be?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.