diff --git a/lib/src/main/java/io/github/lonamiwebs/overgram/Overgram.java b/lib/src/main/java/io/github/lonamiwebs/overgram/Overgram.java index 95ecb20..bd99e6b 100644 --- a/lib/src/main/java/io/github/lonamiwebs/overgram/Overgram.java +++ b/lib/src/main/java/io/github/lonamiwebs/overgram/Overgram.java @@ -14,7 +14,7 @@ public class Overgram { final MTProtoSender sender = new MTProtoSender(new MTProtoState(), new TcpFull()); try { sender.connect("149.154.167.91", 443); - final Future result = sender.send(new Functions.help.GetConfig()); + final Future result = sender.send(new Functions.Ping()); System.out.println(result.get()); } finally { sender.disconnect(); diff --git a/lib/src/main/java/io/github/lonamiwebs/overgram/network/MTProtoSender.java b/lib/src/main/java/io/github/lonamiwebs/overgram/network/MTProtoSender.java index 2cdbf35..98d6876 100644 --- a/lib/src/main/java/io/github/lonamiwebs/overgram/network/MTProtoSender.java +++ b/lib/src/main/java/io/github/lonamiwebs/overgram/network/MTProtoSender.java @@ -169,6 +169,7 @@ public class MTProtoSender { doDisconnect(); return; } + pendingAck.clear(); } final TLMessage message; @@ -186,7 +187,9 @@ public class MTProtoSender { while (!message.future.isCancelled()) { try { connection.send(body); + break; } catch (IOException ignored) { + // TODO e.g. on timeout retry (loop; not done yet) try { Thread.sleep(1000); doReconnect(); @@ -228,7 +231,7 @@ public class MTProtoSender { private void processMessage(final TLMessage message) throws InterruptedException { pendingAck.add(message.id); - if (message.object instanceof RpcResult) { + if (message.object instanceof RPCResult) { handleRpcResult(message); } else if (message.object instanceof MessageContainer) { handleContainer(message); @@ -262,11 +265,15 @@ public class MTProtoSender { } private void handleRpcResult(final TLMessage message) { - final RpcResult result = (RpcResult) message.object; - final TLMessage replyMessage = pendingMessages.remove(result.reqMsgId()); + final RPCResult result = (RPCResult) message.object; + final TLMessage replyMessage = pendingMessages.remove(result.reqMsgId); - // TODO RPC error - final BinaryReader reader = new BinaryReader(ByteBuffer.wrap(result.result())); + if (result.error != null) { + replyMessage.future.completeExceptionally(new RPCError(result.error)); + return; + } + + final BinaryReader reader = new BinaryReader(ByteBuffer.wrap(result.result)); try { replyMessage.future.complete(((TLRequest) replyMessage.object).readResult(reader)); } catch (ClassNotFoundException e) { @@ -276,7 +283,7 @@ public class MTProtoSender { public void handleContainer(final TLMessage message) throws InterruptedException { final MessageContainer result = (MessageContainer) message.object; - for (final TLMessage innerMessage : result.messages()) { + for (final TLMessage innerMessage : result.messages) { processMessage(innerMessage); } } diff --git a/lib/src/main/java/io/github/lonamiwebs/overgram/network/MTProtoState.java b/lib/src/main/java/io/github/lonamiwebs/overgram/network/MTProtoState.java index 7efc6ba..f6988f6 100644 --- a/lib/src/main/java/io/github/lonamiwebs/overgram/network/MTProtoState.java +++ b/lib/src/main/java/io/github/lonamiwebs/overgram/network/MTProtoState.java @@ -101,7 +101,9 @@ public class MTProtoState { final Pair keyIv = calcKey(msgKey, false); final byte[] plainText = AES.decryptIge(reader.read(), keyIv.getKey(), keyIv.getValue()); - final byte[] ourKey = Utils.sha256digest(ByteBuffer.wrap(authKey.key, 96, 32).array(), body); + final byte[] ourKey = Arrays.copyOfRange(Utils.sha256digest( + Arrays.copyOfRange(authKey.key, 96, 128), plainText), 8, 24); + if (!Arrays.equals(msgKey, ourKey)) { throw new SecurityException("Received message key doesn't match with expected one"); } @@ -112,11 +114,11 @@ public class MTProtoState { throw new SecurityException("Server replied with a wrong session ID"); } - final long remoteMsgId = reader.readLong(); - final int remoteSeq = reader.readInt(); - reader.readInt(); // inner message length + final long remoteMsgId = tlReader.readLong(); + final int remoteSeq = tlReader.readInt(); + tlReader.readInt(); // inner message length - final TLObject object = reader.readTl(); + final TLObject object = tlReader.readTl(); return new TLMessage(remoteMsgId, remoteSeq, object); } diff --git a/lib/src/main/java/io/github/lonamiwebs/overgram/tl/GzipPacked.java b/lib/src/main/java/io/github/lonamiwebs/overgram/tl/GzipPacked.java index bb087a9..c4b15b6 100644 --- a/lib/src/main/java/io/github/lonamiwebs/overgram/tl/GzipPacked.java +++ b/lib/src/main/java/io/github/lonamiwebs/overgram/tl/GzipPacked.java @@ -7,16 +7,20 @@ public class GzipPacked extends TLObject { public static final int CONSTRUCTOR_ID = 812830625; @Override - public void serialize(BinaryWriter writer) { + public void serialize(final BinaryWriter writer) { throw new UnsupportedOperationException(); } @Override - public void deserialize(BinaryReader reader) throws ClassNotFoundException { + public void deserialize(final BinaryReader reader) throws ClassNotFoundException { throw new UnsupportedOperationException(); } public TLObject packedObject() { throw new UnsupportedOperationException(); } + + public static byte[] unzip(final BinaryReader reader) { + throw new UnsupportedOperationException(); + } } diff --git a/lib/src/main/java/io/github/lonamiwebs/overgram/tl/MessageContainer.java b/lib/src/main/java/io/github/lonamiwebs/overgram/tl/MessageContainer.java index 8507cc9..8da82aa 100644 --- a/lib/src/main/java/io/github/lonamiwebs/overgram/tl/MessageContainer.java +++ b/lib/src/main/java/io/github/lonamiwebs/overgram/tl/MessageContainer.java @@ -3,22 +3,31 @@ package io.github.lonamiwebs.overgram.tl; import io.github.lonamiwebs.overgram.utils.BinaryReader; import io.github.lonamiwebs.overgram.utils.BinaryWriter; +import java.util.ArrayList; import java.util.List; public class MessageContainer extends TLObject { public static final int CONSTRUCTOR_ID = 1945237724; + final public List messages = new ArrayList<>(); + @Override - public void serialize(BinaryWriter writer) { + public void serialize(final BinaryWriter writer) { throw new UnsupportedOperationException(); } @Override - public void deserialize(BinaryReader reader) throws ClassNotFoundException { - throw new UnsupportedOperationException(); - } - - public List messages() { - throw new UnsupportedOperationException(); + public void deserialize(final BinaryReader reader) throws ClassNotFoundException { + messages.clear(); + final int count = reader.readInt(); + for (int i = 0; i < count; ++i) { + final long msgId = reader.readLong(); + final int seqNo = reader.readInt(); + final int length = reader.readInt(); + final int before = reader.tell(); + final TLObject object = reader.readTl(); + reader.set(before + length); + messages.add(new TLMessage(msgId, seqNo, object)); + } } } diff --git a/lib/src/main/java/io/github/lonamiwebs/overgram/tl/RPCError.java b/lib/src/main/java/io/github/lonamiwebs/overgram/tl/RPCError.java new file mode 100644 index 0000000..4302416 --- /dev/null +++ b/lib/src/main/java/io/github/lonamiwebs/overgram/tl/RPCError.java @@ -0,0 +1,14 @@ +package io.github.lonamiwebs.overgram.tl; + +import java.rmi.RemoteException; + +public class RPCError extends RemoteException { + public final int code; + public final String value; + + public RPCError(final Types.RpcError from) { + super(String.format("RPC error %d: %s", from.errorCode(), from.errorMessage())); + code = from.errorCode(); + value = from.errorMessage(); + } +} diff --git a/lib/src/main/java/io/github/lonamiwebs/overgram/tl/RPCResult.java b/lib/src/main/java/io/github/lonamiwebs/overgram/tl/RPCResult.java new file mode 100644 index 0000000..2068eab --- /dev/null +++ b/lib/src/main/java/io/github/lonamiwebs/overgram/tl/RPCResult.java @@ -0,0 +1,33 @@ +package io.github.lonamiwebs.overgram.tl; + +import io.github.lonamiwebs.overgram.utils.BinaryReader; +import io.github.lonamiwebs.overgram.utils.BinaryWriter; + +import java.util.Arrays; + +public class RPCResult extends TLObject { + public static final int CONSTRUCTOR_ID = -212046591; + + public long reqMsgId; + public Types.RpcError error; + public byte[] result; + + @Override + public void serialize(final BinaryWriter writer) { + throw new UnsupportedOperationException(); + } + + @Override + public void deserialize(final BinaryReader reader) throws ClassNotFoundException { + reqMsgId = reader.readLong(); + final int code = reader.readInt(); + if (code == Types.RpcError.CONSTRUCTOR_ID) { + error = new Types.RpcError(); + error.deserialize(reader); + } else if (code == GzipPacked.CONSTRUCTOR_ID) { + result = GzipPacked.unzip(reader); + } else { + result = reader.read(); + } + } +} diff --git a/lib/src/main/java/io/github/lonamiwebs/overgram/tl/RpcResult.java b/lib/src/main/java/io/github/lonamiwebs/overgram/tl/RpcResult.java deleted file mode 100644 index 1793a24..0000000 --- a/lib/src/main/java/io/github/lonamiwebs/overgram/tl/RpcResult.java +++ /dev/null @@ -1,26 +0,0 @@ -package io.github.lonamiwebs.overgram.tl; - -import io.github.lonamiwebs.overgram.utils.BinaryReader; -import io.github.lonamiwebs.overgram.utils.BinaryWriter; - -public class RpcResult extends TLObject { - public static final int CONSTRUCTOR_ID = -212046591; - - @Override - public void serialize(BinaryWriter writer) { - throw new UnsupportedOperationException(); - } - - @Override - public void deserialize(BinaryReader reader) throws ClassNotFoundException { - throw new UnsupportedOperationException(); - } - - public long reqMsgId() { - throw new UnsupportedOperationException(); - } - - public byte[] result() { - throw new UnsupportedOperationException(); - } -} diff --git a/lib/src/main/java/io/github/lonamiwebs/overgram/utils/BinaryReader.java b/lib/src/main/java/io/github/lonamiwebs/overgram/utils/BinaryReader.java index 08b06f4..14977ae 100644 --- a/lib/src/main/java/io/github/lonamiwebs/overgram/utils/BinaryReader.java +++ b/lib/src/main/java/io/github/lonamiwebs/overgram/utils/BinaryReader.java @@ -1,7 +1,6 @@ package io.github.lonamiwebs.overgram.utils; -import io.github.lonamiwebs.overgram.tl.TLObject; -import io.github.lonamiwebs.overgram.tl.Types; +import io.github.lonamiwebs.overgram.tl.*; import java.math.BigInteger; import java.nio.ByteBuffer; @@ -111,7 +110,22 @@ public class BinaryReader { } public TLObject readTl() throws ClassNotFoundException { - final TLObject object = Types.getFromId(readInt()); + final int id = readInt(); + final TLObject object; + switch (id) { + case RPCResult.CONSTRUCTOR_ID: + object = new RPCResult(); + break; + case GzipPacked.CONSTRUCTOR_ID: + object = new GzipPacked(); + break; + case MessageContainer.CONSTRUCTOR_ID: + object = new MessageContainer(); + break; + default: + object = Types.getFromId(id); + break; + } object.deserialize(this); return object; } @@ -126,10 +140,18 @@ public class BinaryReader { return result; } + public int tell() { + return buffer.position(); + } + public void seek(final int delta) { buffer.position(buffer.position() + delta); } + public void set(final int position) { + buffer.position(position); + } + public byte[] read(final int size) { final byte[] result = new byte[size]; buffer.get(result);