2013-10-25 15:19:00 +00:00
|
|
|
/*
|
2013-12-20 19:25:49 +00:00
|
|
|
* This is the source code of Telegram for Android v. 1.3.2.
|
2013-10-25 15:19:00 +00:00
|
|
|
* It is licensed under GNU GPL v. 2 or later.
|
|
|
|
* You should have received a copy of the license in this archive (see LICENSE).
|
|
|
|
*
|
|
|
|
* Copyright Nikolai Kudashov, 2013.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package org.telegram.messenger;
|
|
|
|
|
2013-12-20 19:25:49 +00:00
|
|
|
import android.content.Context;
|
|
|
|
import android.content.SharedPreferences;
|
2013-10-25 15:19:00 +00:00
|
|
|
|
|
|
|
import org.telegram.TL.TLRPC;
|
2013-12-20 19:25:49 +00:00
|
|
|
import org.telegram.ui.ApplicationLoader;
|
2013-10-25 15:19:00 +00:00
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.Comparator;
|
2013-12-20 19:25:49 +00:00
|
|
|
import java.util.HashMap;
|
2013-10-25 15:19:00 +00:00
|
|
|
|
|
|
|
public class Datacenter {
|
2013-12-26 11:43:37 +00:00
|
|
|
private final int DATA_VERSION = 3;
|
2013-12-20 19:25:49 +00:00
|
|
|
|
2013-10-25 15:19:00 +00:00
|
|
|
public int datacenterId;
|
2013-12-20 19:25:49 +00:00
|
|
|
public ArrayList<String> addresses = new ArrayList<String>();
|
|
|
|
public HashMap<String, Integer> ports = new HashMap<String, Integer>();
|
2013-12-26 11:43:37 +00:00
|
|
|
public int[] defaultPorts = new int[] {-1, 80, -1, 443, -1, 443, -1, 80, -1, 443, -1};
|
2013-10-25 15:19:00 +00:00
|
|
|
public boolean authorized;
|
|
|
|
public long authSessionId;
|
|
|
|
public long authDownloadSessionId;
|
|
|
|
public long authUploadSessionId;
|
|
|
|
public byte[] authKey;
|
|
|
|
public byte[] authKeyId;
|
2013-12-26 11:43:37 +00:00
|
|
|
public int lastInitVersion = 0;
|
2013-12-20 19:25:49 +00:00
|
|
|
private volatile int currentPortNum = 0;
|
|
|
|
private volatile int currentAddressNum = 0;
|
2013-10-25 15:19:00 +00:00
|
|
|
|
|
|
|
public TcpConnection connection;
|
|
|
|
public TcpConnection downloadConnection;
|
|
|
|
public TcpConnection uploadConnection;
|
|
|
|
|
|
|
|
private ArrayList<ServerSalt> authServerSaltSet = new ArrayList<ServerSalt>();
|
|
|
|
|
|
|
|
public Datacenter() {
|
|
|
|
authServerSaltSet = new ArrayList<ServerSalt>();
|
|
|
|
}
|
|
|
|
|
2013-12-20 19:25:49 +00:00
|
|
|
public Datacenter(SerializedData data, int version) {
|
|
|
|
if (version == 0) {
|
|
|
|
datacenterId = data.readInt32();
|
|
|
|
String address = data.readString();
|
|
|
|
addresses.add(address);
|
|
|
|
int port = data.readInt32();
|
|
|
|
ports.put(address, port);
|
|
|
|
int len = data.readInt32();
|
|
|
|
if (len != 0) {
|
|
|
|
authKey = data.readData(len);
|
|
|
|
}
|
|
|
|
len = data.readInt32();
|
|
|
|
if (len != 0) {
|
|
|
|
authKeyId = data.readData(len);
|
|
|
|
}
|
|
|
|
authorized = data.readInt32() != 0;
|
|
|
|
len = data.readInt32();
|
|
|
|
for (int a = 0; a < len; a++) {
|
|
|
|
ServerSalt salt = new ServerSalt();
|
|
|
|
salt.validSince = data.readInt32();
|
|
|
|
salt.validUntil = data.readInt32();
|
|
|
|
salt.value = data.readInt64();
|
|
|
|
if (authServerSaltSet == null) {
|
|
|
|
authServerSaltSet = new ArrayList<ServerSalt>();
|
|
|
|
}
|
|
|
|
authServerSaltSet.add(salt);
|
|
|
|
}
|
|
|
|
} else if (version == 1) {
|
|
|
|
int currentVersion = data.readInt32();
|
2013-12-26 11:43:37 +00:00
|
|
|
if (currentVersion == 2 || currentVersion == 3) {
|
2013-12-20 19:25:49 +00:00
|
|
|
datacenterId = data.readInt32();
|
2013-12-26 11:43:37 +00:00
|
|
|
if (currentVersion == 3) {
|
|
|
|
lastInitVersion = data.readInt32();
|
|
|
|
}
|
2013-12-20 19:25:49 +00:00
|
|
|
int len = data.readInt32();
|
|
|
|
for (int a = 0; a < len; a++) {
|
|
|
|
String address = data.readString();
|
|
|
|
addresses.add(address);
|
|
|
|
ports.put(address, data.readInt32());
|
|
|
|
}
|
|
|
|
|
|
|
|
len = data.readInt32();
|
|
|
|
if (len != 0) {
|
|
|
|
authKey = data.readData(len);
|
|
|
|
}
|
|
|
|
len = data.readInt32();
|
|
|
|
if (len != 0) {
|
|
|
|
authKeyId = data.readData(len);
|
|
|
|
}
|
|
|
|
authorized = data.readInt32() != 0;
|
|
|
|
len = data.readInt32();
|
|
|
|
for (int a = 0; a < len; a++) {
|
|
|
|
ServerSalt salt = new ServerSalt();
|
|
|
|
salt.validSince = data.readInt32();
|
|
|
|
salt.validUntil = data.readInt32();
|
|
|
|
salt.value = data.readInt64();
|
|
|
|
if (authServerSaltSet == null) {
|
|
|
|
authServerSaltSet = new ArrayList<ServerSalt>();
|
|
|
|
}
|
|
|
|
authServerSaltSet.add(salt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
readCurrentAddressAndPortNum();
|
|
|
|
}
|
|
|
|
|
|
|
|
public String getCurrentAddress() {
|
|
|
|
if (addresses.isEmpty()) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
if (currentAddressNum >= addresses.size()) {
|
|
|
|
currentAddressNum = 0;
|
|
|
|
}
|
|
|
|
return addresses.get(currentAddressNum);
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getCurrentPort() {
|
|
|
|
if (ports.isEmpty()) {
|
|
|
|
return 443;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (currentPortNum >= defaultPorts.length) {
|
|
|
|
currentPortNum = 0;
|
|
|
|
}
|
|
|
|
int port = defaultPorts[currentPortNum];
|
|
|
|
if (port == -1) {
|
|
|
|
String address = getCurrentAddress();
|
|
|
|
return ports.get(address);
|
|
|
|
}
|
|
|
|
return port;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addAddressAndPort(String address, int port) {
|
|
|
|
if (addresses.contains(address)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
addresses.add(address);
|
|
|
|
ports.put(address, port);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void nextAddressOrPort() {
|
|
|
|
if (currentPortNum + 1 < defaultPorts.length) {
|
|
|
|
currentPortNum++;
|
|
|
|
} else {
|
|
|
|
if (currentAddressNum + 1 < addresses.size()) {
|
|
|
|
currentAddressNum++;
|
|
|
|
} else {
|
|
|
|
currentAddressNum = 0;
|
2013-10-25 15:19:00 +00:00
|
|
|
}
|
2013-12-20 19:25:49 +00:00
|
|
|
currentPortNum = 0;
|
2013-10-25 15:19:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-20 19:25:49 +00:00
|
|
|
public void storeCurrentAddressAndPortNum() {
|
|
|
|
Utilities.stageQueue.postRunnable(new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("dataconfig", Context.MODE_PRIVATE);
|
|
|
|
SharedPreferences.Editor editor = preferences.edit();
|
|
|
|
editor.putInt("dc" + datacenterId + "port", currentPortNum);
|
|
|
|
editor.putInt("dc" + datacenterId + "address", currentAddressNum);
|
|
|
|
editor.commit();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
private void readCurrentAddressAndPortNum() {
|
|
|
|
SharedPreferences preferences = ApplicationLoader.applicationContext.getSharedPreferences("dataconfig", Context.MODE_PRIVATE);
|
|
|
|
currentPortNum = preferences.getInt("dc" + datacenterId + "port", 0);
|
|
|
|
currentAddressNum = preferences.getInt("dc" + datacenterId + "address", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void replaceAddressesAndPorts(ArrayList<String> newAddresses, HashMap<String, Integer> newPorts) {
|
|
|
|
addresses = newAddresses;
|
|
|
|
ports = newPorts;
|
|
|
|
}
|
|
|
|
|
2013-10-25 15:19:00 +00:00
|
|
|
public void SerializeToStream(SerializedData stream) {
|
2013-12-20 19:25:49 +00:00
|
|
|
stream.writeInt32(DATA_VERSION);
|
2013-10-25 15:19:00 +00:00
|
|
|
stream.writeInt32(datacenterId);
|
2013-12-26 11:43:37 +00:00
|
|
|
stream.writeInt32(lastInitVersion);
|
2013-12-20 19:25:49 +00:00
|
|
|
stream.writeInt32(addresses.size());
|
|
|
|
for (String address : addresses) {
|
|
|
|
stream.writeString(address);
|
|
|
|
stream.writeInt32(ports.get(address));
|
|
|
|
}
|
2013-10-25 15:19:00 +00:00
|
|
|
if (authKey != null) {
|
|
|
|
stream.writeInt32(authKey.length);
|
|
|
|
stream.writeRaw(authKey);
|
|
|
|
} else {
|
|
|
|
stream.writeInt32(0);
|
|
|
|
}
|
|
|
|
if (authKeyId != null) {
|
|
|
|
stream.writeInt32(authKeyId.length);
|
|
|
|
stream.writeRaw(authKeyId);
|
|
|
|
} else {
|
|
|
|
stream.writeInt32(0);
|
|
|
|
}
|
|
|
|
stream.writeInt32(authorized ? 1 : 0);
|
|
|
|
stream.writeInt32(authServerSaltSet.size());
|
|
|
|
for (ServerSalt salt : authServerSaltSet) {
|
|
|
|
stream.writeInt32(salt.validSince);
|
|
|
|
stream.writeInt32(salt.validUntil);
|
|
|
|
stream.writeInt64(salt.value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void clear() {
|
|
|
|
authKey = null;
|
|
|
|
authKeyId = null;
|
|
|
|
authorized = false;
|
|
|
|
authServerSaltSet.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void clearServerSalts() {
|
|
|
|
authServerSaltSet.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
public long selectServerSalt(int date) {
|
|
|
|
boolean cleanupNeeded = false;
|
|
|
|
|
|
|
|
long result = 0;
|
|
|
|
int maxRemainingInterval = 0;
|
|
|
|
|
|
|
|
for (ServerSalt salt : authServerSaltSet) {
|
|
|
|
if (salt.validUntil < date || (salt.validSince == 0 && salt.validUntil == Integer.MAX_VALUE)) {
|
|
|
|
cleanupNeeded = true;
|
|
|
|
} else if (salt.validSince <= date && salt.validUntil > date) {
|
|
|
|
if (maxRemainingInterval == 0 || Math.abs(salt.validUntil - date) > maxRemainingInterval) {
|
|
|
|
maxRemainingInterval = Math.abs(salt.validUntil - date);
|
|
|
|
result = salt.value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cleanupNeeded) {
|
|
|
|
for (int i = 0; i < authServerSaltSet.size(); i++) {
|
|
|
|
ServerSalt salt = authServerSaltSet.get(i);
|
|
|
|
if (salt.validUntil < date) {
|
|
|
|
authServerSaltSet.remove(i);
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-20 19:25:49 +00:00
|
|
|
if (result == 0) {
|
|
|
|
FileLog.e("tmessages", "Valid salt not found");
|
2013-10-25 15:19:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
private class SaltComparator implements Comparator<ServerSalt> {
|
|
|
|
@Override
|
|
|
|
public int compare(ServerSalt o1, ServerSalt o2) {
|
|
|
|
if (o1.validSince < o2.validSince) {
|
|
|
|
return -1;
|
|
|
|
} else if (o1.validSince > o2.validSince) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void mergeServerSalts(int date, ArrayList<TLRPC.TL_futureSalt> salts) {
|
|
|
|
if (salts == null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ArrayList<Long> existingSalts = new ArrayList<Long>(authServerSaltSet.size());
|
|
|
|
|
|
|
|
for (ServerSalt salt : authServerSaltSet) {
|
|
|
|
existingSalts.add(salt.value);
|
|
|
|
}
|
|
|
|
for (TLRPC.TL_futureSalt saltDesc : salts) {
|
|
|
|
long salt = saltDesc.salt;
|
|
|
|
if (!existingSalts.contains(salt) && saltDesc.valid_until > date) {
|
|
|
|
ServerSalt serverSalt = new ServerSalt();
|
|
|
|
serverSalt.validSince = saltDesc.valid_since;
|
|
|
|
serverSalt.validUntil = saltDesc.valid_until;
|
|
|
|
serverSalt.value = salt;
|
|
|
|
authServerSaltSet.add(serverSalt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Collections.sort(authServerSaltSet, new SaltComparator());
|
|
|
|
}
|
|
|
|
|
|
|
|
public void addServerSalt(ServerSalt serverSalt) {
|
|
|
|
for (ServerSalt salt : authServerSaltSet) {
|
|
|
|
if (salt.value == serverSalt.value) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
authServerSaltSet.add(serverSalt);
|
|
|
|
Collections.sort(authServerSaltSet, new SaltComparator());
|
|
|
|
}
|
|
|
|
|
|
|
|
boolean containsServerSalt(long value) {
|
|
|
|
for (ServerSalt salt : authServerSaltSet) {
|
|
|
|
if (salt.value == value) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|