1
0
mirror of https://github.com/danog/libtgvoip.git synced 2024-12-03 10:07:45 +01:00
libtgvoip/VoIPController.cpp

3206 lines
96 KiB
C++
Raw Normal View History

//
// libtgvoip is free and unencumbered public domain software.
// For more information, see http://unlicense.org or the UNLICENSE file
// you should have received with this source code distribution.
//
#ifndef _WIN32
#include <unistd.h>
#include <sys/time.h>
#endif
2017-02-02 17:24:40 +01:00
#include <errno.h>
#include <string.h>
#include <wchar.h>
#include "VoIPController.h"
#include "logging.h"
#include "threading.h"
2018-06-04 21:37:43 +02:00
#include "Buffers.h"
2017-02-02 17:24:40 +01:00
#include "OpusEncoder.h"
#include "OpusDecoder.h"
2017-03-30 16:06:59 +02:00
#include "VoIPServerConfig.h"
2018-06-04 21:37:43 +02:00
#include "PrivateDefines.h"
2017-02-02 17:24:40 +01:00
#include <assert.h>
#include <time.h>
#include <math.h>
#include <exception>
#include <stdexcept>
#include <algorithm>
2017-08-21 18:02:37 +02:00
inline int pad4(int x){
int r=PAD4(x);
if(r==4)
return 0;
return r;
}
using namespace tgvoip;
2018-06-04 21:37:43 +02:00
using namespace std;
2017-02-02 17:24:40 +01:00
#ifdef __APPLE__
2017-03-30 16:06:59 +02:00
#include "os/darwin/AudioUnitIO.h"
2017-02-02 17:24:40 +01:00
#include <mach/mach_time.h>
double VoIPController::machTimebase=0;
uint64_t VoIPController::machTimestart=0;
#endif
#ifdef _WIN32
int64_t VoIPController::win32TimeScale = 0;
bool VoIPController::didInitWin32TimeScale = false;
2017-02-02 17:24:40 +01:00
#endif
2017-03-30 16:06:59 +02:00
#ifndef TGVOIP_USE_CUSTOM_CRYPTO
extern "C" {
2017-02-02 17:24:40 +01:00
#include <openssl/sha.h>
#include <openssl/aes.h>
#include <openssl/modes.h>
2017-02-02 17:24:40 +01:00
#include <openssl/rand.h>
}
2017-02-02 17:24:40 +01:00
void tgvoip_openssl_aes_ige_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
AES_KEY akey;
AES_set_encrypt_key(key, 32*8, &akey);
AES_ige_encrypt(in, out, length, &akey, iv, AES_ENCRYPT);
}
void tgvoip_openssl_aes_ige_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
AES_KEY akey;
AES_set_decrypt_key(key, 32*8, &akey);
AES_ige_encrypt(in, out, length, &akey, iv, AES_DECRYPT);
}
void tgvoip_openssl_rand_bytes(uint8_t* buffer, size_t len){
RAND_bytes(buffer, len);
}
void tgvoip_openssl_sha1(uint8_t* msg, size_t len, uint8_t* output){
SHA1(msg, len, output);
}
void tgvoip_openssl_sha256(uint8_t* msg, size_t len, uint8_t* output){
SHA256(msg, len, output);
}
void tgvoip_openssl_aes_ctr_encrypt(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num){
AES_KEY akey;
AES_set_encrypt_key(key, 32*8, &akey);
CRYPTO_ctr128_encrypt(inout, inout, length, &akey, iv, ecount, num, (block128_f) AES_encrypt);
}
2018-05-15 20:23:46 +02:00
void tgvoip_openssl_aes_cbc_encrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
AES_KEY akey;
AES_set_encrypt_key(key, 256, &akey);
AES_cbc_encrypt(in, out, length, &akey, iv, AES_ENCRYPT);
}
void tgvoip_openssl_aes_cbc_decrypt(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv){
AES_KEY akey;
AES_set_decrypt_key(key, 256, &akey);
AES_cbc_encrypt(in, out, length, &akey, iv, AES_DECRYPT);
}
2018-06-04 21:37:43 +02:00
CryptoFunctions VoIPController::crypto={
2017-02-02 17:24:40 +01:00
tgvoip_openssl_rand_bytes,
tgvoip_openssl_sha1,
tgvoip_openssl_sha256,
tgvoip_openssl_aes_ige_encrypt,
tgvoip_openssl_aes_ige_decrypt,
2018-05-15 20:23:46 +02:00
tgvoip_openssl_aes_ctr_encrypt,
tgvoip_openssl_aes_cbc_encrypt,
tgvoip_openssl_aes_cbc_decrypt
2017-02-02 17:24:40 +01:00
};
#else
2018-06-04 21:37:43 +02:00
CryptoFunctions VoIPController::crypto; // set it yourself upon initialization
#endif
2017-02-02 17:24:40 +01:00
2017-03-30 16:06:59 +02:00
extern FILE* tgvoipLogFile;
VoIPController::VoIPController() : activeNetItfName(""),
currentAudioInput("default"),
currentAudioOutput("default"),
2018-05-15 20:23:46 +02:00
outgoingPacketsBufferPool(1024, 20),
proxyAddress(""),
proxyUsername(""),
2018-05-15 20:23:46 +02:00
proxyPassword("") {
2017-02-02 17:24:40 +01:00
seq=1;
lastRemoteSeq=0;
state=STATE_WAIT_INIT;
audioInput=NULL;
audioOutput=NULL;
encoder=NULL;
audioOutStarted=false;
audioTimestampIn=0;
audioTimestampOut=0;
stopping=false;
sendQueue=new BlockingQueue<PendingOutgoingPacket>(21);
2017-02-02 17:24:40 +01:00
memset(recvPacketTimes, 0, sizeof(double)*32);
memset(rttHistory, 0, sizeof(double)*32);
memset(sendLossCountHistory, 0, sizeof(uint32_t)*32);
2018-06-04 21:37:43 +02:00
memset(&stats, 0, sizeof(TrafficStats));
2017-02-02 17:24:40 +01:00
lastRemoteAckSeq=0;
lastSentSeq=0;
recvLossCount=0;
2018-06-04 21:37:43 +02:00
packetsReceived=0;
2017-02-02 17:24:40 +01:00
waitingForAcks=false;
networkType=NET_TYPE_UNKNOWN;
echoCanceller=NULL;
dontSendPackets=0;
micMuted=false;
currentEndpoint=NULL;
waitingForRelayPeerInfo=false;
allowP2p=true;
dataSavingMode=false;
publicEndpointsReqTime=0;
connectionInitTime=0;
lastRecvPacketTime=0;
dataSavingRequestedByPeer=false;
peerVersion=0;
conctl=new CongestionControl();
2017-02-02 17:24:40 +01:00
prevSendLossCount=0;
2017-03-30 16:06:59 +02:00
receivedInit=false;
receivedInitAck=false;
peerPreferredRelay=NULL;
statsDump=NULL;
useTCP=false;
useUDP=true;
didAddTcpRelays=false;
setEstablishedAt=0;
udpPingCount=0;
lastUdpPingTime=0;
openingTcpSocket=NULL;
proxyProtocol=PROXY_NONE;
proxyPort=0;
resolvedProxyAddress=NULL;
2017-08-21 18:02:37 +02:00
signalBarCount=0;
selectCanceller=SocketSelectCanceller::Create();
udpSocket=NetworkSocket::Create(PROTO_UDP);
realUdpSocket=udpSocket;
udpConnectivityState=UDP_UNKNOWN;
2017-12-27 18:25:47 +01:00
echoCancellationStrength=1;
outputAGC=NULL;
outputAGCEnabled=false;
2018-05-15 20:23:46 +02:00
peerCapabilities=0;
callbacks={0};
didReceiveGroupCallKey=false;
didReceiveGroupCallKeyAck=false;
didSendGroupCallKey=false;
didSendUpgradeRequest=false;
2018-06-04 21:37:43 +02:00
didInvokeUpgradeCallback=false;
2018-05-15 20:23:46 +02:00
connectionMaxLayer=0;
useMTProto2=false;
setCurrentEndpointToTCP=false;
2018-06-04 21:37:43 +02:00
useIPv6=false;
peerIPv6Available=false;
shittyInternetMode=false;
didAddIPv6Relays=false;
didSendIPv6Endpoint=false;
2018-05-15 20:23:46 +02:00
sendThread=NULL;
recvThread=NULL;
tickThread=NULL;
maxAudioBitrate=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate", 20000);
maxAudioBitrateGPRS=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate_gprs", 8000);
maxAudioBitrateEDGE=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate_edge", 16000);
maxAudioBitrateSaving=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_max_bitrate_saving", 8000);
initAudioBitrate=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate", 16000);
initAudioBitrateGPRS=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate_gprs", 8000);
initAudioBitrateEDGE=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate_edge", 8000);
initAudioBitrateSaving=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_init_bitrate_saving", 8000);
audioBitrateStepIncr=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_bitrate_step_incr", 1000);
audioBitrateStepDecr=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_bitrate_step_decr", 1000);
minAudioBitrate=(uint32_t) ServerConfig::GetSharedInstance()->GetInt("audio_min_bitrate", 8000);
relaySwitchThreshold=ServerConfig::GetSharedInstance()->GetDouble("relay_switch_threshold", 0.8);
p2pToRelaySwitchThreshold=ServerConfig::GetSharedInstance()->GetDouble("p2p_to_relay_switch_threshold", 0.6);
relayToP2pSwitchThreshold=ServerConfig::GetSharedInstance()->GetDouble("relay_to_p2p_switch_threshold", 0.8);
reconnectingTimeout=ServerConfig::GetSharedInstance()->GetDouble("reconnecting_state_timeout", 2.0);
2017-03-30 16:06:59 +02:00
2017-02-02 17:24:40 +01:00
#ifdef __APPLE__
2018-05-15 20:23:46 +02:00
machTimestart=0;
#if TARGET_OS_OSX
if(kCFCoreFoundationVersionNumber>=kCFCoreFoundationVersionNumber10_7){
#endif
appleAudioIO=new audio::AudioUnitIO();
#if TARGET_OS_OSX
}else{
2018-06-04 21:37:43 +02:00
appleAudioIO=NULL;
2018-05-15 20:23:46 +02:00
}
2017-03-30 16:06:59 +02:00
#endif
2017-02-02 17:24:40 +01:00
#endif
2018-06-04 21:37:43 +02:00
shared_ptr<Stream> stm=make_shared<Stream>();
stm->id=1;
stm->type=STREAM_TYPE_AUDIO;
stm->codec=CODEC_OPUS;
stm->enabled=1;
stm->frameDuration=60;
2017-02-02 17:24:40 +01:00
outgoingStreams.push_back(stm);
2018-05-15 20:23:46 +02:00
2018-06-04 21:37:43 +02:00
/*Stream vstm={0};
vstm.id=2;
vstm.type=STREAM_TYPE_VIDEO;
vstm.codec=CODEC_AVC;
vstm.enabled=1;
outgoingStreams.push_back(vstm);*/
2018-05-15 20:23:46 +02:00
2018-06-04 21:37:43 +02:00
memset(signalBarsHistory, 0, sizeof(signalBarsHistory));
2018-05-15 20:23:46 +02:00
}
VoIPController::~VoIPController(){
LOGD("Entered VoIPController::~VoIPController");
2018-05-15 20:23:46 +02:00
if(!stopping){
LOGE("!!!!!!!!!!!!!!!!!!!! CALL controller->Stop() BEFORE DELETING THE CONTROLLER OBJECT !!!!!!!!!!!!!!!!!!!!!!!1");
abort();
}
2017-02-02 17:24:40 +01:00
LOGD("before close socket");
if(udpSocket)
delete udpSocket;
if(udpSocket!=realUdpSocket)
delete realUdpSocket;
2018-06-04 21:37:43 +02:00
for(vector<shared_ptr<Stream>>::iterator _stm=incomingStreams.begin();_stm!=incomingStreams.end();++_stm){
//LOGD("before delete jitter buffer");
shared_ptr<Stream> stm=*_stm;
/*if(stm->jitterBuffer){
2018-05-15 20:23:46 +02:00
delete stm->jitterBuffer;
2018-06-04 21:37:43 +02:00
}*/
2018-05-15 20:23:46 +02:00
LOGD("before stop decoder");
if(stm->decoder){
stm->decoder->Stop();
}
2017-02-02 17:24:40 +01:00
}
LOGD("before delete audio input");
if(audioInput){
delete audioInput;
}
LOGD("before delete encoder");
if(encoder){
encoder->Stop();
delete encoder;
}
2018-06-04 21:37:43 +02:00
//LOGD("before delete audio output");
//if(audioOutput){
// delete audioOutput;
//}
2018-05-15 20:23:46 +02:00
#ifdef __APPLE__
LOGD("before delete AudioUnitIO");
if(appleAudioIO){
delete appleAudioIO;
}
#endif
2018-06-04 21:37:43 +02:00
/*for(vector<shared_ptr<Stream>>::iterator stm=incomingStreams.begin();stm!=incomingStreams.end();++stm){
2018-05-15 20:23:46 +02:00
LOGD("before delete decoder");
2018-06-04 21:37:43 +02:00
if((*stm)->decoder){
delete (*stm)->decoder;
2018-05-15 20:23:46 +02:00
}
2018-06-04 21:37:43 +02:00
}*/
2017-02-02 17:24:40 +01:00
LOGD("before delete echo canceller");
if(echoCanceller){
echoCanceller->Stop();
delete echoCanceller;
}
delete sendQueue;
2018-06-04 21:37:43 +02:00
/*for(i=0;i<queuedPackets.size();i++){
2017-02-02 17:24:40 +01:00
if(queuedPackets[i]->data)
free(queuedPackets[i]->data);
free(queuedPackets[i]);
2018-06-04 21:37:43 +02:00
}*/
2017-02-02 17:24:40 +01:00
delete conctl;
2018-06-04 21:37:43 +02:00
/*for(vector<Endpoint*>::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){
if((*itr)->socket){
(*itr)->socket->Close();
delete (*itr)->socket;
}
delete *itr;
2018-06-04 21:37:43 +02:00
}*/
2017-03-30 16:06:59 +02:00
if(tgvoipLogFile){
FILE* log=tgvoipLogFile;
tgvoipLogFile=NULL;
fclose(log);
}
if(statsDump)
fclose(statsDump);
if(resolvedProxyAddress)
delete resolvedProxyAddress;
delete selectCanceller;
if(outputAGC)
delete outputAGC;
LOGD("Left VoIPController::~VoIPController");
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
void VoIPController::Stop(){
LOGD("Entered VoIPController::Stop");
stopping=true;
runReceiver=false;
LOGD("before shutdown socket");
if(udpSocket)
udpSocket->Close();
if(realUdpSocket!=udpSocket)
realUdpSocket->Close();
selectCanceller->CancelSelect();
sendQueue->Put(PendingOutgoingPacket{0});
if(openingTcpSocket)
openingTcpSocket->Close();
LOGD("before join sendThread");
if(sendThread){
sendThread->Join();
delete sendThread;
}
LOGD("before join recvThread");
if(recvThread){
recvThread->Join();
delete recvThread;
}
LOGD("before join tickThread");
if(tickThread){
tickThread->Join();
delete tickThread;
}
{
LOGD("Before stop audio I/O");
MutexGuard m(audioIOMutex);
if(audioInput)
audioInput->Stop();
if(audioOutput)
audioOutput->Stop();
}
2018-05-15 20:23:46 +02:00
LOGD("Left VoIPController::Stop");
}
2018-06-04 21:37:43 +02:00
void VoIPController::SetRemoteEndpoints(vector<Endpoint> endpoints, bool allowP2p, int32_t connectionMaxLayer){
2018-05-15 20:23:46 +02:00
LOGW("Set remote endpoints, allowP2P=%d, connectionMaxLayer=%u", allowP2p ? 1 : 0, connectionMaxLayer);
2017-02-02 17:24:40 +01:00
preferredRelay=NULL;
2018-05-15 20:23:46 +02:00
{
MutexGuard m(endpointsMutex);
this->endpoints.clear();
didAddTcpRelays=false;
useTCP=true;
2018-06-04 21:37:43 +02:00
for(vector<Endpoint>::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){
this->endpoints.push_back(make_shared<Endpoint>(*itrtr));
2018-05-15 20:23:46 +02:00
if(itrtr->type==Endpoint::TYPE_TCP_RELAY)
didAddTcpRelays=true;
if(itrtr->type==Endpoint::TYPE_UDP_RELAY)
useTCP=false;
LOGV("Adding endpoint: %s:%d, %s", itrtr->address.ToString().c_str(), itrtr->port, itrtr->type==Endpoint::TYPE_UDP_RELAY ? "UDP" : "TCP");
}
2017-02-02 17:24:40 +01:00
}
currentEndpoint=this->endpoints[0];
preferredRelay=currentEndpoint;
2017-02-02 17:24:40 +01:00
this->allowP2p=allowP2p;
2018-05-15 20:23:46 +02:00
this->connectionMaxLayer=connectionMaxLayer;
if(connectionMaxLayer>=74){
useMTProto2=true;
}
2018-06-04 21:37:43 +02:00
AddIPv6Relays();
2017-02-02 17:24:40 +01:00
}
void VoIPController::Start(){
2017-02-02 17:24:40 +01:00
LOGW("Starting voip controller");
udpSocket->Open();
if(udpSocket->IsFailed()){
SetState(STATE_FAILED);
return;
}
2017-03-31 07:33:30 +02:00
//SendPacket(NULL, 0, currentEndpoint);
2017-02-02 17:24:40 +01:00
runReceiver=true;
2018-05-15 20:23:46 +02:00
recvThread=new Thread(new MethodPointer<VoIPController>(&VoIPController::RunRecvThread, this), NULL);
recvThread->SetName("VoipRecv");
recvThread->Start();
sendThread=new Thread(new MethodPointer<VoIPController>(&VoIPController::RunSendThread, this), NULL);
sendThread->SetName("VoipSend");
sendThread->Start();
tickThread=new Thread(new MethodPointer<VoIPController>(&VoIPController::RunTickThread, this), NULL);
tickThread->SetName("VoipTick");
tickThread->Start();
2017-02-02 17:24:40 +01:00
}
2018-06-04 21:37:43 +02:00
void VoIPController::AudioInputCallback(unsigned char* data, size_t length, unsigned char* secondaryData, size_t secondaryLength, void* param){
((VoIPController*)param)->HandleAudioInput(data, length, secondaryData, secondaryLength);
2017-02-02 17:24:40 +01:00
}
2018-06-04 21:37:43 +02:00
void VoIPController::HandleAudioInput(unsigned char *data, size_t len, unsigned char* secondaryData, size_t secondaryLen){
2017-02-02 17:24:40 +01:00
if(stopping)
return;
if(waitingForAcks || dontSendPackets>0){
LOGV("waiting for RLC, dropping outgoing audio packet");
return;
}
2018-06-04 21:37:43 +02:00
//LOGV("Audio packet size %u", (unsigned int)len);
unsigned char* buf=outgoingPacketsBufferPool.Get();
if(buf){
BufferOutputStream pkt(buf, outgoingPacketsBufferPool.GetSingleBufferSize());
unsigned char flags=(unsigned char) (len>255 ? STREAM_DATA_FLAG_LEN16 : 0);
pkt.WriteByte((unsigned char) (1 | flags)); // streamID + flags
if(len>255)
pkt.WriteInt16((int16_t) len);
else
pkt.WriteByte((unsigned char) len);
pkt.WriteInt32(audioTimestampOut);
pkt.WriteBytes(data, len);
PendingOutgoingPacket p{
/*.seq=*/GenerateOutSeq(),
/*.type=*/PKT_STREAM_DATA,
/*.len=*/pkt.GetLength(),
/*.data=*/buf,
2018-06-04 21:37:43 +02:00
/*.endpoint=*/0,
};
sendQueue->Put(p);
2017-02-02 17:24:40 +01:00
}
2018-06-04 21:37:43 +02:00
if(secondaryData && secondaryLen && shittyInternetMode){
Buffer ecBuf(secondaryLen);
ecBuf.CopyFrom(secondaryData, 0, secondaryLen);
ecAudioPackets.push_back(move(ecBuf));
while(ecAudioPackets.size()>4)
ecAudioPackets.erase(ecAudioPackets.begin());
buf=outgoingPacketsBufferPool.Get();
if(buf){
BufferOutputStream pkt(buf, outgoingPacketsBufferPool.GetSingleBufferSize());
pkt.WriteByte(outgoingStreams[0]->id);
pkt.WriteInt32(audioTimestampOut);
pkt.WriteByte((unsigned char)ecAudioPackets.size());
for(Buffer& ecData:ecAudioPackets){
pkt.WriteByte((unsigned char)ecData.Length());
pkt.WriteBytes(ecData);
}
PendingOutgoingPacket p{
GenerateOutSeq(),
PKT_STREAM_EC,
pkt.GetLength(),
buf,
0
};
sendQueue->Put(p);
}
}
audioTimestampOut+=outgoingStreams[0]->frameDuration;
}
void VoIPController::HandleVideoInput(EncodedVideoFrame& frame){
if(stopping)
return;
if(waitingForAcks || dontSendPackets>0 || networkType==NET_TYPE_EDGE || networkType==NET_TYPE_GPRS){
LOGV("dropping outgoing video packet");
return;
}
2017-02-02 17:24:40 +01:00
}
void VoIPController::Connect(){
2017-02-02 17:24:40 +01:00
assert(state!=STATE_WAIT_INIT_ACK);
if(proxyProtocol==PROXY_SOCKS5){
resolvedProxyAddress=NetworkSocket::ResolveDomainName(proxyAddress);
if(!resolvedProxyAddress){
LOGW("Error resolving proxy address %s", proxyAddress.c_str());
SetState(STATE_FAILED);
return;
}
InitUDPProxy();
}
2017-02-02 17:24:40 +01:00
connectionInitTime=GetCurrentTime();
SendInit();
}
void VoIPController::SetEncryptionKey(char *key, bool isOutgoing){
2017-02-02 17:24:40 +01:00
memcpy(encryptionKey, key, 256);
uint8_t sha1[SHA1_LENGTH];
crypto.sha1((uint8_t*) encryptionKey, 256, sha1);
memcpy(keyFingerprint, sha1+(SHA1_LENGTH-8), 8);
uint8_t sha256[SHA256_LENGTH];
crypto.sha256((uint8_t*) encryptionKey, 256, sha256);
memcpy(callID, sha256+(SHA256_LENGTH-16), 16);
2017-03-30 16:06:59 +02:00
this->isOutgoing=isOutgoing;
2017-02-02 17:24:40 +01:00
}
uint32_t VoIPController::GenerateOutSeq(){
return seq++;
}
void VoIPController::WritePacketHeader(uint32_t pseq, BufferOutputStream *s, unsigned char type, uint32_t length){
2017-02-02 17:24:40 +01:00
uint32_t acks=0;
int i;
for(i=0;i<32;i++){
if(recvPacketTimes[i]>0)
acks|=1;
if(i<31)
acks<<=1;
}
if(state==STATE_WAIT_INIT || state==STATE_WAIT_INIT_ACK){
s->WriteInt32(TLID_DECRYPTED_AUDIO_BLOCK);
int64_t randomID;
crypto.rand_bytes((uint8_t *) &randomID, 8);
s->WriteInt64(randomID);
unsigned char randBytes[7];
crypto.rand_bytes(randBytes, 7);
s->WriteByte(7);
2017-03-30 16:06:59 +02:00
s->WriteBytes(randBytes, 7);
2017-02-02 17:24:40 +01:00
uint32_t pflags=PFLAG_HAS_RECENT_RECV | PFLAG_HAS_SEQ;
if(length>0)
pflags|=PFLAG_HAS_DATA;
if(state==STATE_WAIT_INIT || state==STATE_WAIT_INIT_ACK){
pflags|=PFLAG_HAS_CALL_ID | PFLAG_HAS_PROTO;
}
pflags|=((uint32_t) type) << 24;
s->WriteInt32(pflags);
if(pflags & PFLAG_HAS_CALL_ID){
s->WriteBytes(callID, 16);
}
s->WriteInt32(lastRemoteSeq);
s->WriteInt32(pseq);
s->WriteInt32(acks);
if(pflags & PFLAG_HAS_PROTO){
s->WriteInt32(PROTOCOL_NAME);
}
if(length>0){
if(length<=253){
s->WriteByte((unsigned char) length);
}else{
s->WriteByte(254);
2017-03-30 16:06:59 +02:00
s->WriteByte((unsigned char) (length & 0xFF));
s->WriteByte((unsigned char) ((length >> 8) & 0xFF));
s->WriteByte((unsigned char) ((length >> 16) & 0xFF));
2017-02-02 17:24:40 +01:00
}
}
}else{
s->WriteInt32(TLID_SIMPLE_AUDIO_BLOCK);
int64_t randomID;
crypto.rand_bytes((uint8_t *) &randomID, 8);
s->WriteInt64(randomID);
unsigned char randBytes[7];
crypto.rand_bytes(randBytes, 7);
s->WriteByte(7);
2017-03-30 16:06:59 +02:00
s->WriteBytes(randBytes, 7);
2017-02-02 17:24:40 +01:00
uint32_t lenWithHeader=length+13;
if(lenWithHeader>0){
if(lenWithHeader<=253){
s->WriteByte((unsigned char) lenWithHeader);
}else{
s->WriteByte(254);
2017-03-30 16:06:59 +02:00
s->WriteByte((unsigned char) (lenWithHeader & 0xFF));
s->WriteByte((unsigned char) ((lenWithHeader >> 8) & 0xFF));
s->WriteByte((unsigned char) ((lenWithHeader >> 16) & 0xFF));
2017-02-02 17:24:40 +01:00
}
}
s->WriteByte(type);
s->WriteInt32(lastRemoteSeq);
s->WriteInt32(pseq);
s->WriteInt32(acks);
2018-06-04 21:37:43 +02:00
if(peerVersion>=6){
2018-06-12 16:41:36 +02:00
MutexGuard m(queuedPacketsMutex);
2018-06-04 21:37:43 +02:00
if(currentExtras.empty()){
s->WriteByte(0);
}else{
s->WriteByte(XPFLAG_HAS_EXTRA);
s->WriteByte(static_cast<unsigned char>(currentExtras.size()));
for(vector<UnacknowledgedExtraData>::iterator x=currentExtras.begin();x!=currentExtras.end();++x){
LOGV("Writing extra into header: type %u, length %lu", x->type, x->data.Length());
assert(x->data.Length()<=254);
s->WriteByte(static_cast<unsigned char>(x->data.Length()+1));
s->WriteByte(x->type);
s->WriteBytes(*x->data, x->data.Length());
if(x->firstContainingSeq==0)
x->firstContainingSeq=pseq;
}
}
}
2017-02-02 17:24:40 +01:00
}
if(type==PKT_STREAM_DATA || type==PKT_STREAM_DATA_X2 || type==PKT_STREAM_DATA_X3)
conctl->PacketSent(pseq, length);
2018-05-15 20:23:46 +02:00
MutexGuard m(queuedPacketsMutex);
recentOutgoingPackets.push_back(RecentOutgoingPacket{
pseq,
0,
GetCurrentTime(),
0
});
while(recentOutgoingPackets.size()>MAX_RECENT_PACKETS)
recentOutgoingPackets.erase(recentOutgoingPackets.begin());
2017-02-02 17:24:40 +01:00
lastSentSeq=pseq;
//LOGI("packet header size %d", s->GetLength());
}
void VoIPController::UpdateAudioBitrate(){
2017-02-02 17:24:40 +01:00
if(encoder){
2017-03-30 16:06:59 +02:00
if(dataSavingMode || dataSavingRequestedByPeer){
maxBitrate=maxAudioBitrateSaving;
encoder->SetBitrate(initAudioBitrateSaving);
}else if(networkType==NET_TYPE_GPRS){
maxBitrate=maxAudioBitrateGPRS;
encoder->SetBitrate(initAudioBitrateGPRS);
}else if(networkType==NET_TYPE_EDGE){
maxBitrate=maxAudioBitrateEDGE;
encoder->SetBitrate(initAudioBitrateEDGE);
2017-02-02 17:24:40 +01:00
}else{
2017-03-30 16:06:59 +02:00
maxBitrate=maxAudioBitrate;
encoder->SetBitrate(initAudioBitrate);
2017-02-02 17:24:40 +01:00
}
}
}
void VoIPController::SendInit(){
2018-05-15 20:23:46 +02:00
{
MutexGuard m(endpointsMutex);
uint32_t initSeq=GenerateOutSeq();
2018-06-04 21:37:43 +02:00
for(shared_ptr<Endpoint>& e:endpoints){
if(e->type==Endpoint::TYPE_TCP_RELAY && !useTCP)
2018-05-15 20:23:46 +02:00
continue;
unsigned char *pkt=outgoingPacketsBufferPool.Get();
if(!pkt){
LOGW("can't send init, queue overflow");
continue;
}
BufferOutputStream out(pkt, outgoingPacketsBufferPool.GetSingleBufferSize());
out.WriteInt32(PROTOCOL_VERSION);
out.WriteInt32(MIN_PROTOCOL_VERSION);
uint32_t flags=0;
if(config.enableCallUpgrade)
flags|=INIT_FLAG_GROUP_CALLS_SUPPORTED;
if(dataSavingMode)
flags|=INIT_FLAG_DATA_SAVING_ENABLED;
out.WriteInt32(flags);
if(connectionMaxLayer<74){
out.WriteByte(2); // audio codecs count
out.WriteByte(CODEC_OPUS_OLD);
out.WriteByte(0);
out.WriteByte(0);
out.WriteByte(0);
out.WriteInt32(CODEC_OPUS);
2018-06-04 21:37:43 +02:00
out.WriteByte(0); // video codecs count (decode)
out.WriteByte(0); // video codecs count (encode)
2018-05-15 20:23:46 +02:00
}else{
out.WriteByte(1);
out.WriteInt32(CODEC_OPUS);
2018-06-04 21:37:43 +02:00
/*out.WriteByte(1);
out.WriteInt32(CODEC_AVC);
out.WriteByte(1);
out.WriteInt32(CODEC_AVC);*/
out.WriteByte(0);
2018-05-15 20:23:46 +02:00
out.WriteByte(0);
}
sendQueue->Put(PendingOutgoingPacket{
/*.seq=*/initSeq,
/*.type=*/PKT_INIT,
/*.len=*/out.GetLength(),
/*.data=*/pkt,
2018-06-04 21:37:43 +02:00
/*.endpoint=*/e->id
2018-05-15 20:23:46 +02:00
});
}
2017-03-30 16:06:59 +02:00
}
2017-02-02 17:24:40 +01:00
SetState(STATE_WAIT_INIT_ACK);
}
void VoIPController::InitUDPProxy(){
if(realUdpSocket!=udpSocket){
udpSocket->Close();
delete udpSocket;
udpSocket=realUdpSocket;
}
NetworkSocket* tcp=NetworkSocket::Create(PROTO_TCP);
tcp->Connect(resolvedProxyAddress, proxyPort);
if(tcp->IsFailed()){
2018-06-04 21:37:43 +02:00
lastError=ERROR_PROXY;
SetState(STATE_FAILED);
tcp->Close();
delete tcp;
return;
}
NetworkSocketSOCKS5Proxy* udpProxy=new NetworkSocketSOCKS5Proxy(tcp, udpSocket, proxyUsername, proxyPassword);
udpProxy->InitConnection();
udpProxy->Open();
if(udpProxy->IsFailed()){
udpProxy->Close();
delete udpProxy;
useTCP=true;
useUDP=false;
udpConnectivityState=UDP_NOT_AVAILABLE;
}else{
udpSocket=udpProxy;
}
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
void VoIPController::RunRecvThread(void* arg){
2017-02-02 17:24:40 +01:00
LOGI("Receive thread starting");
2018-06-04 21:37:43 +02:00
unsigned char *buffer = (unsigned char *)malloc(1500);
2018-05-15 20:23:46 +02:00
NetworkPacket packet={0};
2017-02-02 17:24:40 +01:00
while(runReceiver){
packet.data=buffer;
2018-05-15 20:23:46 +02:00
packet.length=1500;
2018-06-04 21:37:43 +02:00
vector<NetworkSocket*> readSockets;
vector<NetworkSocket*> errorSockets;
readSockets.push_back(realUdpSocket);
errorSockets.push_back(realUdpSocket);
2018-06-04 21:37:43 +02:00
{
MutexGuard m(endpointsMutex);
for(shared_ptr<Endpoint>& e:endpoints){
if(e->type==Endpoint::TYPE_TCP_RELAY){
if(e->socket){
readSockets.push_back(e->socket);
errorSockets.push_back(e->socket);
}
}
}
2018-06-04 21:37:43 +02:00
}
2018-06-04 21:37:43 +02:00
{
MutexGuard m(socketSelectMutex);
bool selRes=NetworkSocket::Select(readSockets, errorSockets, selectCanceller);
if(!selRes){
LOGV("Select canceled");
continue;
}
}
if(!runReceiver)
return;
if(!errorSockets.empty()){
2018-06-04 21:37:43 +02:00
if(find(errorSockets.begin(), errorSockets.end(), realUdpSocket)!=errorSockets.end()){
LOGW("UDP socket failed");
SetState(STATE_FAILED);
return;
}
}
NetworkSocket* socket=NULL;
2018-06-04 21:37:43 +02:00
if(find(readSockets.begin(), readSockets.end(), realUdpSocket)!=readSockets.end()){
socket=udpSocket;
}else if(readSockets.size()>0){
socket=readSockets[0];
}else{
LOGI("no sockets to read from");
2018-05-15 20:23:46 +02:00
MutexGuard m(endpointsMutex);
2018-06-04 21:37:43 +02:00
for(vector<NetworkSocket*>::iterator itr=errorSockets.begin();itr!=errorSockets.end();++itr){
for(shared_ptr<Endpoint>& e:endpoints){
if(e->socket && e->socket==*itr){
e->socket->Close();
delete e->socket;
e->socket=NULL;
LOGI("Closing failed TCP socket for %s:%u", e->GetAddress().ToString().c_str(), e->port);
break;
}
}
}
continue;
}
socket->Receive(&packet);
if(!packet.address){
LOGE("Packet has null address. This shouldn't happen.");
continue;
2017-03-31 07:33:30 +02:00
}
size_t len=packet.length;
if(!len){
LOGE("Packet has zero length.");
continue;
}
2017-06-07 17:46:59 +02:00
//LOGV("Received %d bytes from %s:%d at %.5lf", len, packet.address->ToString().c_str(), packet.port, GetCurrentTime());
2018-06-04 21:37:43 +02:00
shared_ptr<Endpoint> srcEndpoint;
IPv4Address* src4=dynamic_cast<IPv4Address*>(packet.address);
if(src4){
2018-05-15 20:23:46 +02:00
MutexGuard m(endpointsMutex);
2018-06-04 21:37:43 +02:00
for(shared_ptr<Endpoint>& e:endpoints){
if(e->address==*src4 && e->port==packet.port){
if((e->type!=Endpoint::TYPE_TCP_RELAY && packet.protocol==PROTO_UDP) || (e->type==Endpoint::TYPE_TCP_RELAY && packet.protocol==PROTO_TCP)){
srcEndpoint=e;
break;
}
2017-03-30 16:06:59 +02:00
}
2017-02-02 17:24:40 +01:00
}
2018-06-04 21:37:43 +02:00
}else{
IPv6Address* src6=dynamic_cast<IPv6Address*>(packet.address);
if(src6){
MutexGuard m(endpointsMutex);
for(shared_ptr<Endpoint>& e:endpoints){
if(e->v6address==*src6 && e->port==packet.port && e->address.IsEmpty()){
if((e->type!=Endpoint::TYPE_TCP_RELAY && packet.protocol==PROTO_UDP) || (e->type==Endpoint::TYPE_TCP_RELAY && packet.protocol==PROTO_TCP)){
srcEndpoint=e;
break;
}
}
}
}
2017-02-02 17:24:40 +01:00
}
2017-02-02 17:24:40 +01:00
if(!srcEndpoint){
LOGW("Received a packet from unknown source %s:%u", packet.address->ToString().c_str(), packet.port);
2017-02-02 17:24:40 +01:00
continue;
}
if(len<=0){
//LOGW("error receiving: %d / %s", errno, strerror(errno));
2017-02-02 17:24:40 +01:00
continue;
}
if(IS_MOBILE_NETWORK(networkType))
stats.bytesRecvdMobile+=(uint64_t)len;
else
stats.bytesRecvdWifi+=(uint64_t)len;
2017-03-30 16:06:59 +02:00
try{
2018-05-15 20:23:46 +02:00
ProcessIncomingPacket(packet, srcEndpoint);
2018-06-04 21:37:43 +02:00
}catch(out_of_range x){
2018-05-15 20:23:46 +02:00
LOGW("Error parsing packet: %s", x.what());
}
}
2018-06-04 21:37:43 +02:00
free(buffer);
2018-05-15 20:23:46 +02:00
LOGI("=== recv thread exiting ===");
}
2018-05-15 20:23:46 +02:00
void VoIPController::RunSendThread(void* arg){
unsigned char buf[1500];
while(runReceiver){
PendingOutgoingPacket pkt=sendQueue->GetBlocking();
if(pkt.data){
2018-06-04 21:37:43 +02:00
shared_ptr<Endpoint> endpoint;
if(pkt.endpoint){
endpoint=GetEndpointByID(pkt.endpoint);
}
if(!endpoint){ // either packet has no endpoint specified or it no longer exists
endpoint=currentEndpoint;
}
2018-05-15 20:23:46 +02:00
if((endpoint->type==Endpoint::TYPE_TCP_RELAY && useTCP) || (endpoint->type!=Endpoint::TYPE_TCP_RELAY && useUDP)){
BufferOutputStream p(buf, sizeof(buf));
WritePacketHeader(pkt.seq, &p, pkt.type, (uint32_t)pkt.len);
p.WriteBytes(pkt.data, pkt.len);
SendPacket(p.GetBuffer(), p.GetLength(), endpoint, pkt);
}
outgoingPacketsBufferPool.Reuse(pkt.data);
}else{
LOGE("tried to send null packet");
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
}
LOGI("=== send thread exiting ===");
}
2018-06-04 21:37:43 +02:00
void VoIPController::ProcessIncomingPacket(NetworkPacket &packet, shared_ptr<Endpoint> srcEndpoint){
2018-05-15 20:23:46 +02:00
unsigned char* buffer=packet.data;
size_t len=packet.length;
BufferInputStream in(buffer, (size_t)len);
if(memcmp(buffer, srcEndpoint->type==Endpoint::TYPE_UDP_RELAY || srcEndpoint->type==Endpoint::TYPE_TCP_RELAY ? (void*)srcEndpoint->peerTag : (void*)callID, 16)!=0){
LOGW("Received packet has wrong peerTag");
return;
}
in.Seek(16);
if(in.Remaining()>=16 && (srcEndpoint->type==Endpoint::TYPE_UDP_RELAY || srcEndpoint->type==Endpoint::TYPE_TCP_RELAY)
&& *reinterpret_cast<uint64_t*>(buffer+16)==0xFFFFFFFFFFFFFFFFLL && *reinterpret_cast<uint32_t*>(buffer+24)==0xFFFFFFFF){
// relay special request response
in.Seek(16+12);
uint32_t tlid=(uint32_t) in.ReadInt32();
if(tlid==TLID_UDP_REFLECTOR_SELF_INFO){
if(srcEndpoint->type==Endpoint::TYPE_UDP_RELAY /*&& udpConnectivityState==UDP_PING_SENT*/ && in.Remaining()>=32){
2018-06-04 21:37:43 +02:00
int32_t date=in.ReadInt32();
int64_t queryID=in.ReadInt64();
2018-05-15 20:23:46 +02:00
unsigned char myIP[16];
in.ReadBytes(myIP, 16);
2018-06-04 21:37:43 +02:00
int32_t myPort=in.ReadInt32();
2018-05-15 20:23:46 +02:00
//udpConnectivityState=UDP_AVAILABLE;
2018-06-04 21:37:43 +02:00
LOGV("Received UDP ping reply from %s:%d: date=%d, queryID=%lld, my IP=%s, my port=%d", srcEndpoint->address.ToString().c_str(), srcEndpoint->port, date, queryID, IPv4Address(*reinterpret_cast<uint32_t*>(myIP+12)).ToString().c_str(), myPort);
2018-05-15 20:23:46 +02:00
srcEndpoint->udpPongCount++;
2018-06-04 21:37:43 +02:00
if(srcEndpoint->IsIPv6Only() && !didSendIPv6Endpoint){
IPv6Address realAddr(myIP);
if(realAddr==myIPv6){
LOGI("Public IPv6 matches local address");
useIPv6=true;
if(allowP2p){
didSendIPv6Endpoint=true;
BufferOutputStream o(18);
o.WriteBytes(myIP, 16);
o.WriteInt16(udpSocket->GetLocalPort());
Buffer b(move(o));
SendExtra(b, EXTRA_TYPE_IPV6_ENDPOINT);
}
}
}
2018-05-15 20:23:46 +02:00
}
}else if(tlid==TLID_UDP_REFLECTOR_PEER_INFO){
if(waitingForRelayPeerInfo && in.Remaining()>=16){
MutexGuard _m(endpointsMutex);
uint32_t myAddr=(uint32_t) in.ReadInt32();
uint32_t myPort=(uint32_t) in.ReadInt32();
uint32_t peerAddr=(uint32_t) in.ReadInt32();
uint32_t peerPort=(uint32_t) in.ReadInt32();
2018-06-04 21:37:43 +02:00
for(vector<shared_ptr<Endpoint>>::iterator itrtr=endpoints.begin(); itrtr!=endpoints.end(); ++itrtr){
shared_ptr<Endpoint> ep=*itrtr;
if(ep->type==Endpoint::TYPE_UDP_P2P_INET && !ep->IsIPv6Only()){
2018-05-15 20:23:46 +02:00
if(currentEndpoint==ep)
currentEndpoint=preferredRelay;
endpoints.erase(itrtr);
break;
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
}
2018-06-04 21:37:43 +02:00
for(vector<shared_ptr<Endpoint>>::iterator itrtr=endpoints.begin(); itrtr!=endpoints.end(); ++itrtr){
shared_ptr<Endpoint> ep=*itrtr;
2018-05-15 20:23:46 +02:00
if(ep->type==Endpoint::TYPE_UDP_P2P_LAN){
if(currentEndpoint==ep)
currentEndpoint=preferredRelay;
endpoints.erase(itrtr);
break;
2017-02-02 17:24:40 +01:00
}
}
2018-05-15 20:23:46 +02:00
IPv4Address _peerAddr(peerAddr);
2018-06-04 21:37:43 +02:00
IPv6Address emptyV6(string("::0"));
2018-05-15 20:23:46 +02:00
unsigned char peerTag[16];
2018-06-04 21:37:43 +02:00
endpoints.push_back(make_shared<Endpoint>((int64_t)(FOURCC('P','2','P','4')) << 32, (uint16_t) peerPort, _peerAddr, emptyV6, Endpoint::TYPE_UDP_P2P_INET, peerTag));
2018-05-15 20:23:46 +02:00
LOGW("Received reflector peer info, my=%08X:%u, peer=%08X:%u", myAddr, myPort, peerAddr, peerPort);
if(myAddr==peerAddr){
LOGW("Detected LAN");
IPv4Address lanAddr(0);
udpSocket->GetLocalInterfaceInfo(&lanAddr, NULL);
BufferOutputStream pkt(8);
pkt.WriteInt32(lanAddr.GetAddress());
pkt.WriteInt32(udpSocket->GetLocalPort());
2018-06-04 21:37:43 +02:00
if(peerVersion<6){
SendPacketReliably(PKT_LAN_ENDPOINT, pkt.GetBuffer(), pkt.GetLength(), 0.5, 10);
}else{
Buffer buf(move(pkt));
SendExtra(buf, EXTRA_TYPE_LAN_ENDPOINT);
}
2018-05-15 20:23:46 +02:00
}
waitingForRelayPeerInfo=false;
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
}else{
LOGV("Received relay response with unknown tl id: 0x%08X", tlid);
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
return;
}
if(in.Remaining()<40){
LOGV("Received packet is too small");
return;
}
bool retryWith2=false;
2017-02-02 17:24:40 +01:00
2018-05-15 20:23:46 +02:00
if(!useMTProto2){
2017-02-02 17:24:40 +01:00
unsigned char fingerprint[8], msgHash[16];
in.ReadBytes(fingerprint, 8);
in.ReadBytes(msgHash, 16);
2017-02-02 17:24:40 +01:00
if(memcmp(fingerprint, keyFingerprint, 8)!=0){
LOGW("Received packet has wrong key fingerprint");
2018-05-15 20:23:46 +02:00
return;
2017-02-02 17:24:40 +01:00
}
unsigned char key[32], iv[32];
2017-03-30 16:06:59 +02:00
KDF(msgHash, isOutgoing ? 8 : 0, key, iv);
2018-05-15 20:23:46 +02:00
unsigned char aesOut[MSC_STACK_FALLBACK(in.Remaining(), 1500)];
if(in.Remaining()>sizeof(aesOut))
return;
crypto.aes_ige_decrypt((unsigned char *) buffer+in.GetOffset(), aesOut, in.Remaining(), key, iv);
2018-05-15 20:23:46 +02:00
BufferInputStream _in(aesOut, in.Remaining());
2017-02-02 17:24:40 +01:00
unsigned char sha[SHA1_LENGTH];
2018-05-15 20:23:46 +02:00
uint32_t _len=(uint32_t) _in.ReadInt32();
if(_len>_in.Remaining())
_len=_in.Remaining();
crypto.sha1((uint8_t *) (aesOut), (size_t) (_len+4), sha);
2017-02-02 17:24:40 +01:00
if(memcmp(msgHash, sha+(SHA1_LENGTH-16), 16)!=0){
LOGW("Received packet has wrong hash after decryption");
2018-05-15 20:23:46 +02:00
if(state==STATE_WAIT_INIT || state==STATE_WAIT_INIT_ACK)
retryWith2=true;
else
return;
}else{
memcpy(buffer+in.GetOffset(), aesOut, in.Remaining());
in.ReadInt32();
}
}
2018-05-15 20:23:46 +02:00
if(useMTProto2 || retryWith2){
in.Seek(16); // peer tag
unsigned char fingerprint[8], msgKey[16];
in.ReadBytes(fingerprint, 8);
if(memcmp(fingerprint, keyFingerprint, 8)!=0){
LOGW("Received packet has wrong key fingerprint");
return;
}
in.ReadBytes(msgKey, 16);
unsigned char decrypted[1500];
unsigned char aesKey[32], aesIv[32];
KDF2(msgKey, isOutgoing ? 8 : 0, aesKey, aesIv);
size_t decryptedLen=in.Remaining();
if(decryptedLen>sizeof(decrypted))
return;
//LOGV("-> MSG KEY: %08x %08x %08x %08x, hashed %u", *reinterpret_cast<int32_t*>(msgKey), *reinterpret_cast<int32_t*>(msgKey+4), *reinterpret_cast<int32_t*>(msgKey+8), *reinterpret_cast<int32_t*>(msgKey+12), decryptedLen-4);
2018-06-04 21:37:43 +02:00
/*uint8_t *decryptOffset = packet.data + in.GetOffset();
if ((((intptr_t)decryptOffset) % sizeof(long)) != 0) {
LOGE("alignment2 packet.data+in.GetOffset()");
}
if (decryptedLen % sizeof(long) != 0) {
LOGE("alignment2 decryptedLen");
}*/
2018-05-15 20:23:46 +02:00
crypto.aes_ige_decrypt(packet.data+in.GetOffset(), decrypted, decryptedLen, aesKey, aesIv);
in=BufferInputStream(decrypted, decryptedLen);
//LOGD("received packet length: %d", in.ReadInt32());
BufferOutputStream buf(decryptedLen+32);
size_t x=isOutgoing ? 8 : 0;
buf.WriteBytes(encryptionKey+88+x, 32);
buf.WriteBytes(decrypted+4, decryptedLen-4);
unsigned char msgKeyLarge[32];
crypto.sha256(buf.GetBuffer(), buf.GetLength(), msgKeyLarge);
if(memcmp(msgKey, msgKeyLarge+8, 16)!=0){
LOGW("Received packet has wrong hash");
return;
}
uint32_t innerLen=(uint32_t) in.ReadInt32();
if(innerLen>decryptedLen-4){
2018-06-04 21:37:43 +02:00
LOGW("Received packet has wrong inner length (%d with total of %u)", (int)innerLen, (unsigned int)decryptedLen);
2018-05-15 20:23:46 +02:00
return;
}
if(decryptedLen-innerLen<12){
2018-05-24 18:42:28 +02:00
LOGW("Received packet has too little padding (%u)", (unsigned int)(decryptedLen-innerLen));
2018-05-15 20:23:46 +02:00
return;
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
memcpy(buffer, decrypted+4, innerLen);
in=BufferInputStream(buffer, (size_t) innerLen);
if(retryWith2){
LOGD("Successfully decrypted packet in MTProto2.0 fallback, upgrading");
useMTProto2=true;
}
}
2017-02-02 17:24:40 +01:00
2018-05-15 20:23:46 +02:00
lastRecvPacketTime=GetCurrentTime();
2017-02-02 17:24:40 +01:00
2018-05-15 20:23:46 +02:00
/*decryptedAudioBlock random_id:long random_bytes:string flags:# voice_call_id:flags.2?int128 in_seq_no:flags.4?int out_seq_no:flags.4?int
* recent_received_mask:flags.5?int proto:flags.3?int extra:flags.1?string raw_data:flags.0?string = DecryptedAudioBlock
2017-02-02 17:24:40 +01:00
simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedAudioBlock;
*/
2018-05-15 20:23:46 +02:00
uint32_t ackId, pseq, acks;
2018-06-04 21:37:43 +02:00
unsigned char type, pflags;
2018-05-15 20:23:46 +02:00
uint32_t tlid=(uint32_t) in.ReadInt32();
uint32_t packetInnerLen=0;
if(tlid==TLID_DECRYPTED_AUDIO_BLOCK){
in.ReadInt64(); // random id
uint32_t randLen=(uint32_t) in.ReadTlLength();
in.Seek(in.GetOffset()+randLen+pad4(randLen));
uint32_t flags=(uint32_t) in.ReadInt32();
type=(unsigned char) ((flags >> 24) & 0xFF);
if(!(flags & PFLAG_HAS_SEQ && flags & PFLAG_HAS_RECENT_RECV)){
LOGW("Received packet doesn't have PFLAG_HAS_SEQ, PFLAG_HAS_RECENT_RECV, or both");
2018-05-15 20:23:46 +02:00
return;
}
if(flags & PFLAG_HAS_CALL_ID){
unsigned char pktCallID[16];
in.ReadBytes(pktCallID, 16);
if(memcmp(pktCallID, callID, 16)!=0){
LOGW("Received packet has wrong call id");
2018-05-15 20:23:46 +02:00
lastError=ERROR_UNKNOWN;
SetState(STATE_FAILED);
return;
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
}
ackId=(uint32_t) in.ReadInt32();
pseq=(uint32_t) in.ReadInt32();
acks=(uint32_t) in.ReadInt32();
if(flags & PFLAG_HAS_PROTO){
uint32_t proto=(uint32_t) in.ReadInt32();
if(proto!=PROTOCOL_NAME){
LOGW("Received packet uses wrong protocol");
lastError=ERROR_INCOMPATIBLE;
SetState(STATE_FAILED);
return;
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
}
if(flags & PFLAG_HAS_EXTRA){
uint32_t extraLen=(uint32_t) in.ReadTlLength();
in.Seek(in.GetOffset()+extraLen+pad4(extraLen));
}
if(flags & PFLAG_HAS_DATA){
packetInnerLen=in.ReadTlLength();
2018-05-15 20:23:46 +02:00
}
2018-06-04 21:37:43 +02:00
pflags=0;
2018-05-15 20:23:46 +02:00
}else if(tlid==TLID_SIMPLE_AUDIO_BLOCK){
in.ReadInt64(); // random id
uint32_t randLen=(uint32_t) in.ReadTlLength();
in.Seek(in.GetOffset()+randLen+pad4(randLen));
packetInnerLen=in.ReadTlLength();
type=in.ReadByte();
ackId=(uint32_t) in.ReadInt32();
pseq=(uint32_t) in.ReadInt32();
acks=(uint32_t) in.ReadInt32();
2018-06-04 21:37:43 +02:00
if(peerVersion>=6)
pflags=in.ReadByte();
else
pflags=0;
2018-05-15 20:23:46 +02:00
}else{
LOGW("Received a packet of unknown type %08X", tlid);
return;
}
2018-06-04 21:37:43 +02:00
packetsReceived++;
2018-05-15 20:23:46 +02:00
if(seqgt(pseq, lastRemoteSeq)){
uint32_t diff=pseq-lastRemoteSeq;
if(diff>31){
memset(recvPacketTimes, 0, 32*sizeof(double));
2017-02-02 17:24:40 +01:00
}else{
2018-05-15 20:23:46 +02:00
memmove(&recvPacketTimes[diff], recvPacketTimes, (32-diff)*sizeof(double));
if(diff>1){
memset(recvPacketTimes, 0, diff*sizeof(double));
}
recvPacketTimes[0]=GetCurrentTime();
}
lastRemoteSeq=pseq;
}else if(!seqgt(pseq, lastRemoteSeq) && lastRemoteSeq-pseq<32){
if(recvPacketTimes[lastRemoteSeq-pseq]!=0){
LOGW("Received duplicated packet for seq %u", pseq);
2018-05-15 20:23:46 +02:00
return;
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
recvPacketTimes[lastRemoteSeq-pseq]=GetCurrentTime();
}else if(lastRemoteSeq-pseq>=32){
LOGW("Packet %u is out of order and too late", pseq);
2018-05-15 20:23:46 +02:00
return;
}
if(seqgt(ackId, lastRemoteAckSeq)){
//uint32_t diff=ackId-lastRemoteAckSeq;
/*if(diff>31){
memset(remoteAcks, 0, 32*sizeof(double));
}else{
memmove(&remoteAcks[diff], remoteAcks, (32-diff)*sizeof(double));
if(diff>1){
memset(remoteAcks, 0, diff*sizeof(double));
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
remoteAcks[0]=GetCurrentTime();
}*/
MutexGuard _m(queuedPacketsMutex);
if(waitingForAcks && lastRemoteAckSeq>=firstSentPing){
memset(rttHistory, 0, 32*sizeof(double));
waitingForAcks=false;
dontSendPackets=10;
LOGI("resuming sending");
}
lastRemoteAckSeq=ackId;
conctl->PacketAcknowledged(ackId);
unsigned int i;
for(i=0;i<31;i++){
2018-06-04 21:37:43 +02:00
for(vector<RecentOutgoingPacket>::iterator itr=recentOutgoingPackets.begin();itr!=recentOutgoingPackets.end();++itr){
2018-05-15 20:23:46 +02:00
if(itr->ackTime!=0)
continue;
if(((acks >> (31-i)) & 1) && itr->seq==ackId-(i+1)){
itr->ackTime=GetCurrentTime();
conctl->PacketAcknowledged(itr->seq);
2017-02-02 17:24:40 +01:00
}
}
2018-05-15 20:23:46 +02:00
/*if(remoteAcks[i+1]==0){
if((acks >> (31-i)) & 1){
remoteAcks[i+1]=GetCurrentTime();
conctl->PacketAcknowledged(ackId-(i+1));
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
}*/
}
for(i=0;i<queuedPackets.size();i++){
2018-06-04 21:37:43 +02:00
QueuedPacket& qp=queuedPackets[i];
2018-05-15 20:23:46 +02:00
int j;
bool didAck=false;
for(j=0;j<16;j++){
2018-06-04 21:37:43 +02:00
LOGD("queued packet %u, seq %u=%u", i, j, qp.seqs[j]);
if(qp.seqs[j]==0)
2018-05-15 20:23:46 +02:00
break;
2018-06-04 21:37:43 +02:00
int remoteAcksIndex=lastRemoteAckSeq-qp.seqs[j];
2018-05-15 20:23:46 +02:00
//LOGV("remote acks index %u, value %f", remoteAcksIndex, remoteAcksIndex>=0 && remoteAcksIndex<32 ? remoteAcks[remoteAcksIndex] : -1);
2018-06-04 21:37:43 +02:00
if(seqgt(lastRemoteAckSeq, qp.seqs[j]) && remoteAcksIndex>=0 && remoteAcksIndex<32){
for(RecentOutgoingPacket& opkt:recentOutgoingPackets){
if(opkt.seq==qp.seqs[j] && opkt.ackTime>0){
LOGD("did ack seq %u, removing", qp.seqs[j]);
2018-05-15 20:23:46 +02:00
didAck=true;
break;
}
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
if(didAck)
break;
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
}
if(didAck){
queuedPackets.erase(queuedPackets.begin()+i);
i--;
continue;
2017-02-02 17:24:40 +01:00
}
}
2018-06-04 21:37:43 +02:00
for(vector<UnacknowledgedExtraData>::iterator x=currentExtras.begin();x!=currentExtras.end();){
if(x->firstContainingSeq!=0 && (lastRemoteAckSeq==x->firstContainingSeq || seqgt(lastRemoteAckSeq, x->firstContainingSeq))){
LOGV("Peer acknowledged extra type %u length %lu", x->type, x->data.Length());
ProcessAcknowledgedOutgoingExtra(*x);
x=currentExtras.erase(x);
continue;
}
++x;
}
2018-05-15 20:23:46 +02:00
}
2017-02-02 17:24:40 +01:00
2018-05-15 20:23:46 +02:00
if(srcEndpoint!=currentEndpoint && (srcEndpoint->type==Endpoint::TYPE_UDP_RELAY || srcEndpoint->type==Endpoint::TYPE_TCP_RELAY) && ((currentEndpoint->type!=Endpoint::TYPE_UDP_RELAY && currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY) || currentEndpoint->averageRTT==0)){
if(seqgt(lastSentSeq-32, lastRemoteAckSeq)){
currentEndpoint=srcEndpoint;
LOGI("Peer network address probably changed, switching to relay");
if(allowP2p)
SendPublicEndpointsRequest();
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
}
2018-06-04 21:37:43 +02:00
if(pflags & XPFLAG_HAS_EXTRA){
unsigned char extraCount=in.ReadByte();
for(int i=0;i<extraCount;i++){
size_t extraLen=in.ReadByte();
Buffer xbuffer(extraLen);
in.ReadBytes(*xbuffer, extraLen);
ProcessExtraData(xbuffer);
}
}
2018-05-15 20:23:46 +02:00
//LOGV("acks: %u -> %.2lf, %.2lf, %.2lf, %.2lf, %.2lf, %.2lf, %.2lf, %.2lf", lastRemoteAckSeq, remoteAcks[0], remoteAcks[1], remoteAcks[2], remoteAcks[3], remoteAcks[4], remoteAcks[5], remoteAcks[6], remoteAcks[7]);
//LOGD("recv: %u -> %.2lf, %.2lf, %.2lf, %.2lf, %.2lf, %.2lf, %.2lf, %.2lf", lastRemoteSeq, recvPacketTimes[0], recvPacketTimes[1], recvPacketTimes[2], recvPacketTimes[3], recvPacketTimes[4], recvPacketTimes[5], recvPacketTimes[6], recvPacketTimes[7]);
//LOGI("RTT = %.3lf", GetAverageRTT());
//LOGV("Packet %u type is %d", pseq, type);
if(type==PKT_INIT){
LOGD("Received init");
if(!receivedInit){
receivedInit=true;
if((srcEndpoint->type==Endpoint::TYPE_UDP_RELAY && udpConnectivityState!=UDP_BAD && udpConnectivityState!=UDP_NOT_AVAILABLE) || srcEndpoint->type==Endpoint::TYPE_TCP_RELAY){
2017-03-30 16:06:59 +02:00
currentEndpoint=srcEndpoint;
2018-05-15 20:23:46 +02:00
if(srcEndpoint->type==Endpoint::TYPE_UDP_RELAY || (useTCP && srcEndpoint->type==Endpoint::TYPE_TCP_RELAY))
2017-03-30 16:06:59 +02:00
preferredRelay=srcEndpoint;
}
2018-05-15 20:23:46 +02:00
LogDebugInfo();
}
peerVersion=(uint32_t) in.ReadInt32();
LOGI("Peer version is %d", peerVersion);
uint32_t minVer=(uint32_t) in.ReadInt32();
if(minVer>PROTOCOL_VERSION || peerVersion<MIN_PROTOCOL_VERSION){
lastError=ERROR_INCOMPATIBLE;
2018-05-15 20:23:46 +02:00
SetState(STATE_FAILED);
return;
}
uint32_t flags=(uint32_t) in.ReadInt32();
if(flags & INIT_FLAG_DATA_SAVING_ENABLED){
dataSavingRequestedByPeer=true;
UpdateDataSavingState();
UpdateAudioBitrate();
}
if(flags & INIT_FLAG_GROUP_CALLS_SUPPORTED){
peerCapabilities|=TGVOIP_PEER_CAP_GROUP_CALLS;
}
2018-05-15 20:23:46 +02:00
unsigned int i;
unsigned int numSupportedAudioCodecs=in.ReadByte();
for(i=0; i<numSupportedAudioCodecs; i++){
if(peerVersion<5)
in.ReadByte(); // ignore for now
2018-05-15 20:23:46 +02:00
else
in.ReadInt32();
}
unsigned int numSupportedVideoCodecs=in.ReadByte();
for(i=0; i<numSupportedVideoCodecs; i++){
if(peerVersion<5)
in.ReadByte(); // ignore for now
2018-05-15 20:23:46 +02:00
else
in.ReadInt32();
}
unsigned char* buf=outgoingPacketsBufferPool.Get();
if(buf){
BufferOutputStream out(buf, outgoingPacketsBufferPool.GetSingleBufferSize());
//WritePacketHeader(out, PKT_INIT_ACK, (peerVersion>=2 ? 10 : 2)+(peerVersion>=2 ? 6 : 4)*outgoingStreams.size());
out.WriteInt32(PROTOCOL_VERSION);
out.WriteInt32(MIN_PROTOCOL_VERSION);
out.WriteByte((unsigned char) outgoingStreams.size());
2018-06-04 21:37:43 +02:00
for(vector<shared_ptr<Stream>>::iterator s=outgoingStreams.begin();s!=outgoingStreams.end();++s){
out.WriteByte((*s)->id);
out.WriteByte((*s)->type);
2018-05-15 20:23:46 +02:00
if(peerVersion<5)
2018-06-04 21:37:43 +02:00
out.WriteByte((unsigned char) ((*s)->codec==CODEC_OPUS ? CODEC_OPUS_OLD : 0));
2018-05-15 20:23:46 +02:00
else
2018-06-04 21:37:43 +02:00
out.WriteInt32((*s)->codec);
out.WriteInt16((*s)->frameDuration);
out.WriteByte((unsigned char) ((*s)->enabled ? 1 : 0));
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
sendQueue->Put(PendingOutgoingPacket{
/*.seq=*/GenerateOutSeq(),
/*.type=*/PKT_INIT_ACK,
/*.len=*/out.GetLength(),
/*.data=*/buf,
2018-06-04 21:37:43 +02:00
/*.endpoint=*/0
2018-05-15 20:23:46 +02:00
});
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
}
if(type==PKT_INIT_ACK){
LOGD("Received init ack");
2017-02-02 17:24:40 +01:00
2018-05-15 20:23:46 +02:00
if(!receivedInitAck){
receivedInitAck=true;
if(packetInnerLen>10){
peerVersion=in.ReadInt32();
uint32_t minVer=(uint32_t) in.ReadInt32();
if(minVer>PROTOCOL_VERSION || peerVersion<MIN_PROTOCOL_VERSION){
lastError=ERROR_INCOMPATIBLE;
2018-05-15 20:23:46 +02:00
SetState(STATE_FAILED);
return;
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
}else{
peerVersion=1;
}
2017-02-02 17:24:40 +01:00
2018-05-15 20:23:46 +02:00
LOGI("peer version from init ack %d", peerVersion);
2017-02-02 17:24:40 +01:00
2018-05-15 20:23:46 +02:00
unsigned char streamCount=in.ReadByte();
if(streamCount==0)
return;
2017-02-02 17:24:40 +01:00
2018-05-15 20:23:46 +02:00
int i;
2018-06-04 21:37:43 +02:00
shared_ptr<Stream> incomingAudioStream=NULL;
2018-05-15 20:23:46 +02:00
for(i=0; i<streamCount; i++){
2018-06-04 21:37:43 +02:00
shared_ptr<Stream> stm=make_shared<Stream>();
stm->id=in.ReadByte();
stm->type=in.ReadByte();
2018-05-15 20:23:46 +02:00
if(peerVersion<5){
unsigned char codec=in.ReadByte();
if(codec==CODEC_OPUS_OLD)
2018-06-04 21:37:43 +02:00
stm->codec=CODEC_OPUS;
2018-05-15 20:23:46 +02:00
}else{
2018-06-04 21:37:43 +02:00
stm->codec=(uint32_t) in.ReadInt32();
}
stm->frameDuration=(uint16_t) in.ReadInt16();
stm->enabled=in.ReadByte()==1;
if(stm->type==STREAM_TYPE_AUDIO){
stm->jitterBuffer=make_shared<JitterBuffer>(nullptr, stm->frameDuration);
if(stm->frameDuration>50)
stm->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_60", 3));
else if(stm->frameDuration>30)
stm->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_40", 4));
else
stm->jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_20", 6));
stm->decoder=NULL;
}else if(stm->type==STREAM_TYPE_VIDEO){
if(!stm->packetReassembler){
stm->packetReassembler=make_shared<PacketReassembler>();
}
}else{
LOGW("Unknown incoming stream type: %d", stm->type);
continue;
2017-03-30 16:06:59 +02:00
}
2018-05-15 20:23:46 +02:00
incomingStreams.push_back(stm);
2018-06-04 21:37:43 +02:00
if(stm->type==STREAM_TYPE_AUDIO && !incomingAudioStream)
incomingAudioStream=stm;
2018-05-15 20:23:46 +02:00
}
if(!incomingAudioStream)
return;
2018-05-15 20:23:46 +02:00
if(peerVersion>=5 && !useMTProto2){
useMTProto2=true;
LOGD("MTProto2 wasn't initially enabled for whatever reason but peer supports it; upgrading");
}
2017-02-02 17:24:40 +01:00
{
MutexGuard m(audioIOMutex);
if(!audioInput){
StartAudio();
}
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
setEstablishedAt=GetCurrentTime()+ServerConfig::GetSharedInstance()->GetDouble("established_delay_if_no_stream_data", 1.5);
if(allowP2p)
SendPublicEndpointsRequest();
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
}
if(type==PKT_STREAM_DATA || type==PKT_STREAM_DATA_X2 || type==PKT_STREAM_DATA_X3){
if(state!=STATE_ESTABLISHED && receivedInitAck)
SetState(STATE_ESTABLISHED);
int count;
switch(type){
case PKT_STREAM_DATA_X2:
count=2;
break;
case PKT_STREAM_DATA_X3:
count=3;
break;
case PKT_STREAM_DATA:
default:
count=1;
break;
}
int i;
if(srcEndpoint->type==Endpoint::TYPE_UDP_RELAY && srcEndpoint!=peerPreferredRelay){
peerPreferredRelay=srcEndpoint;
}
for(i=0;i<count;i++){
unsigned char streamID=in.ReadByte();
unsigned char flags=(unsigned char) (streamID & 0xC0);
uint16_t sdlen=(uint16_t) (flags & STREAM_DATA_FLAG_LEN16 ? in.ReadInt16() : in.ReadByte());
uint32_t pts=(uint32_t) in.ReadInt32();
//LOGD("stream data, pts=%d, len=%d, rem=%d", pts, sdlen, in.Remaining());
audioTimestampIn=pts;
if(!audioOutStarted && audioOutput){
2018-06-01 22:06:04 +02:00
MutexGuard m(audioIOMutex);
2018-05-15 20:23:46 +02:00
audioOutput->Start();
audioOutStarted=true;
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
if(in.GetOffset()+sdlen>len){
return;
}
2018-06-04 21:37:43 +02:00
if(incomingStreams.size()>0 && incomingStreams[0]->jitterBuffer /*&& !incomingStreams[0]->extraECEnabled*/)
incomingStreams[0]->jitterBuffer->HandleInput((unsigned char*) (buffer+in.GetOffset()), sdlen, pts, false);
2018-05-15 20:23:46 +02:00
if(i<count-1)
in.Seek(in.GetOffset()+sdlen);
}
}
if(type==PKT_PING){
2018-06-04 21:37:43 +02:00
//LOGD("Received ping from %s:%d", srcEndpoint->address.ToString().c_str(), srcEndpoint->port);
2018-05-15 20:23:46 +02:00
if(srcEndpoint->type!=Endpoint::TYPE_UDP_RELAY && srcEndpoint->type!=Endpoint::TYPE_TCP_RELAY && !allowP2p){
LOGW("Received p2p ping but p2p is disabled by manual override");
return;
}
unsigned char* buf=outgoingPacketsBufferPool.Get();
if(!buf){
LOGW("Dropping pong packet, queue overflow");
return;
}
BufferOutputStream pkt(buf, outgoingPacketsBufferPool.GetSingleBufferSize());
pkt.WriteInt32(pseq);
sendQueue->Put(PendingOutgoingPacket{
/*.seq=*/GenerateOutSeq(),
/*.type=*/PKT_PONG,
/*.len=*/pkt.GetLength(),
/*.data=*/buf,
2018-06-04 21:37:43 +02:00
/*.endpoint=*/srcEndpoint->id,
2018-05-15 20:23:46 +02:00
});
}
if(type==PKT_PONG){
if(packetInnerLen>=4){
uint32_t pingSeq=(uint32_t) in.ReadInt32();
if(pingSeq==srcEndpoint->lastPingSeq){
memmove(&srcEndpoint->rtts[1], srcEndpoint->rtts, sizeof(double)*5);
srcEndpoint->rtts[0]=GetCurrentTime()-srcEndpoint->lastPingTime;
int i;
srcEndpoint->averageRTT=0;
for(i=0;i<6;i++){
if(srcEndpoint->rtts[i]==0)
break;
srcEndpoint->averageRTT+=srcEndpoint->rtts[i];
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
srcEndpoint->averageRTT/=i;
LOGD("Current RTT via %s: %.3f, average: %.3f", packet.address->ToString().c_str(), srcEndpoint->rtts[0], srcEndpoint->averageRTT);
2017-02-02 17:24:40 +01:00
}
}
2018-05-15 20:23:46 +02:00
}
if(type==PKT_STREAM_STATE){
unsigned char id=in.ReadByte();
unsigned char enabled=in.ReadByte();
2018-06-04 21:37:43 +02:00
for(vector<shared_ptr<Stream>>::iterator s=incomingStreams.begin();s!=incomingStreams.end();++s){
if((*s)->id==id){
(*s)->enabled=enabled==1;
2018-05-15 20:23:46 +02:00
UpdateAudioOutputState();
break;
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
}
}
if(type==PKT_LAN_ENDPOINT){
LOGV("received lan endpoint");
uint32_t peerAddr=(uint32_t) in.ReadInt32();
uint16_t peerPort=(uint16_t) in.ReadInt32();
MutexGuard m(endpointsMutex);
bool found=false;
2018-06-04 21:37:43 +02:00
for(shared_ptr<Endpoint>& e:endpoints){
if(e->type==Endpoint::TYPE_UDP_P2P_LAN){
if(currentEndpoint==e)
2018-05-15 20:23:46 +02:00
currentEndpoint=preferredRelay;
found=true;
2018-06-04 21:37:43 +02:00
e->address=peerAddr;
2018-05-15 20:23:46 +02:00
break;
2017-02-02 17:24:40 +01:00
}
}
2018-05-15 20:23:46 +02:00
if(!found){
2018-06-04 21:37:43 +02:00
IPv4Address v4addr(peerAddr);
IPv6Address v6addr(string("::0"));
unsigned char peerTag[16];
endpoints.push_back(make_shared<Endpoint>((int64_t)(FOURCC('L','A','N','4')) << 32, peerPort, v4addr, v6addr, Endpoint::TYPE_UDP_P2P_LAN, peerTag));
2018-05-15 20:23:46 +02:00
}
}
if(type==PKT_NETWORK_CHANGED && currentEndpoint->type!=Endpoint::TYPE_UDP_RELAY && currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY){
currentEndpoint=preferredRelay;
if(allowP2p)
SendPublicEndpointsRequest();
if(peerVersion>=2){
uint32_t flags=(uint32_t) in.ReadInt32();
dataSavingRequestedByPeer=(flags & INIT_FLAG_DATA_SAVING_ENABLED)==INIT_FLAG_DATA_SAVING_ENABLED;
UpdateDataSavingState();
UpdateAudioBitrate();
}
}
2018-06-04 21:37:43 +02:00
if(type==PKT_STREAM_EC){
unsigned char streamID=in.ReadByte();
uint32_t lastTimestamp=(uint32_t)in.ReadInt32();
unsigned char count=in.ReadByte();
for(shared_ptr<Stream>& stm:incomingStreams){
if(stm->id==streamID){
for(unsigned int i=0;i<count;i++){
unsigned char dlen=in.ReadByte();
unsigned char data[256];
in.ReadBytes(data, dlen);
if(stm->jitterBuffer){
stm->jitterBuffer->HandleInput(data, dlen, lastTimestamp-(count-i-1)*stm->frameDuration, true);
}
}
break;
}
}
2018-05-15 20:23:46 +02:00
}
}
2018-06-04 21:37:43 +02:00
void VoIPController::ProcessExtraData(Buffer &data){
BufferInputStream in(*data, data.Length());
unsigned char type=in.ReadByte();
unsigned char fullHash[SHA1_LENGTH];
crypto.sha1(*data, data.Length(), fullHash);
uint64_t hash=*reinterpret_cast<uint64_t*>(fullHash);
if(lastReceivedExtrasByType[type]==hash){
2018-05-15 20:23:46 +02:00
return;
}
2018-06-04 21:37:43 +02:00
lastReceivedExtrasByType[type]=hash;
if(type==EXTRA_TYPE_STREAM_FLAGS){
unsigned char id=in.ReadByte();
uint32_t flags=static_cast<uint32_t>(in.ReadInt32());
for(shared_ptr<Stream>& s:incomingStreams){
if(s->id==id){
s->enabled=(flags & STREAM_FLAG_ENABLED)==STREAM_FLAG_ENABLED;
if(flags & STREAM_FLAG_EXTRA_EC){
if(!s->extraECEnabled){
s->extraECEnabled=true;
if(s->jitterBuffer)
s->jitterBuffer->SetMinPacketCount(4);
2018-05-15 20:23:46 +02:00
}
2018-06-04 21:37:43 +02:00
}else{
if(s->extraECEnabled){
s->extraECEnabled=false;
if(s->jitterBuffer)
s->jitterBuffer->SetMinPacketCount(2);
2017-02-02 17:24:40 +01:00
}
}
2018-06-04 21:37:43 +02:00
UpdateAudioOutputState();
break;
2017-02-02 17:24:40 +01:00
}
}
2018-06-04 21:37:43 +02:00
}else if(type==EXTRA_TYPE_STREAM_CSD){
2018-05-15 20:23:46 +02:00
2018-06-04 21:37:43 +02:00
}else if(type==EXTRA_TYPE_LAN_ENDPOINT){
if(!allowP2p)
return;
LOGV("received lan endpoint (extra)");
uint32_t peerAddr=(uint32_t) in.ReadInt32();
uint16_t peerPort=(uint16_t) in.ReadInt32();
MutexGuard m(endpointsMutex);
bool found=false;
for(shared_ptr<Endpoint>& e:endpoints){
if(e->type==Endpoint::TYPE_UDP_P2P_LAN){
if(currentEndpoint==e)
currentEndpoint=preferredRelay;
found=true;
e->address=peerAddr;
2018-05-15 20:23:46 +02:00
break;
2018-06-04 21:37:43 +02:00
}
2018-05-15 20:23:46 +02:00
}
2018-06-04 21:37:43 +02:00
if(!found){
IPv4Address v4addr(peerAddr);
IPv6Address v6addr(string("::0"));
unsigned char peerTag[16];
endpoints.push_back(make_shared<Endpoint>((int64_t)(FOURCC('L','A','N','4')) << 32, peerPort, v4addr, v6addr, Endpoint::TYPE_UDP_P2P_LAN, peerTag));
}
}else if(type==EXTRA_TYPE_NETWORK_CHANGED){
if(currentEndpoint->type!=Endpoint::TYPE_UDP_RELAY && currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY){
currentEndpoint=preferredRelay;
if(allowP2p)
SendPublicEndpointsRequest();
//if(peerVersion>=2){
uint32_t flags=(uint32_t) in.ReadInt32();
dataSavingRequestedByPeer=(flags & INIT_FLAG_DATA_SAVING_ENABLED)==INIT_FLAG_DATA_SAVING_ENABLED;
UpdateDataSavingState();
UpdateAudioBitrate();
//}
}
}else if(type==EXTRA_TYPE_GROUP_CALL_KEY){
if(!didReceiveGroupCallKey && !didSendGroupCallKey){
unsigned char groupKey[256];
in.ReadBytes(groupKey, 256);
if(callbacks.groupCallKeyReceived)
callbacks.groupCallKeyReceived(this, groupKey);
didReceiveGroupCallKey=true;
}
}else if(type==EXTRA_TYPE_REQUEST_GROUP){
if(!didInvokeUpgradeCallback){
if(callbacks.upgradeToGroupCallRequested)
callbacks.upgradeToGroupCallRequested(this);
didInvokeUpgradeCallback=true;
}
}else if(type==EXTRA_TYPE_IPV6_ENDPOINT){
if(!allowP2p)
return;
unsigned char _addr[16];
in.ReadBytes(_addr, 16);
IPv6Address addr(_addr);
uint16_t port=static_cast<uint16_t>(in.ReadInt16());
MutexGuard m(endpointsMutex);
peerIPv6Available=true;
for(shared_ptr<Endpoint>& e:endpoints){
if(e->type==Endpoint::TYPE_UDP_P2P_INET && e->IsIPv6Only()){
e->v6address=addr;
if(!myIPv6.IsEmpty())
currentEndpoint=e;
2018-05-15 20:23:46 +02:00
return;
}
2017-02-02 17:24:40 +01:00
}
2018-06-04 21:37:43 +02:00
shared_ptr<Endpoint> ep=make_shared<Endpoint>();
ep->type=Endpoint::TYPE_UDP_P2P_INET;
ep->port=port;
ep->v6address=addr;
ep->id=(int64_t)(FOURCC('P','2','P','6')) << 32;
endpoints.push_back(ep);
if(!myIPv6.IsEmpty())
currentEndpoint=ep;
2017-02-02 17:24:40 +01:00
}
}
2018-06-04 21:37:43 +02:00
void VoIPController::ProcessAcknowledgedOutgoingExtra(VoIPController::UnacknowledgedExtraData &extra){
if(extra.type==EXTRA_TYPE_GROUP_CALL_KEY){
if(!didReceiveGroupCallKeyAck){
didReceiveGroupCallKeyAck=true;
if(callbacks.groupCallKeySent)
callbacks.groupCallKeySent(this);
}
}
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
void VoIPController::RunTickThread(void* arg){
2017-02-02 17:24:40 +01:00
uint32_t tickCount=0;
double startTime=GetCurrentTime();
2017-02-02 17:24:40 +01:00
while(runReceiver){
#ifndef _WIN32
2017-02-02 17:24:40 +01:00
usleep(100000);
#else
Sleep(100);
#endif
int prevSignalBarCount=GetSignalBarsCount();
2017-08-21 18:02:37 +02:00
signalBarCount=4;
2017-02-02 17:24:40 +01:00
tickCount++;
if(connectionInitTime==0)
continue;
double time=GetCurrentTime();
2017-08-21 18:02:37 +02:00
if(state==STATE_RECONNECTING)
signalBarCount=1;
if(tickCount%5==0 && (state==STATE_ESTABLISHED || state==STATE_RECONNECTING)){
2017-02-02 17:24:40 +01:00
memmove(&rttHistory[1], rttHistory, 31*sizeof(double));
rttHistory[0]=GetAverageRTT();
/*if(rttHistory[16]>0){
LOGI("rtt diff: %.3lf", rttHistory[0]-rttHistory[16]);
}*/
int i;
double v=0;
for(i=1;i<32;i++){
v+=rttHistory[i-1]-rttHistory[i];
}
v=v/32;
if(rttHistory[0]>10.0 && rttHistory[8]>10.0 && (networkType==NET_TYPE_EDGE || networkType==NET_TYPE_GPRS)){
waitingForAcks=true;
2017-08-21 18:02:37 +02:00
signalBarCount=1;
2017-02-02 17:24:40 +01:00
}else{
waitingForAcks=false;
}
//LOGI("%.3lf/%.3lf, rtt diff %.3lf, waiting=%d, queue=%d", rttHistory[0], rttHistory[8], v, waitingForAcks, sendQueue->Size());
2018-06-04 21:37:43 +02:00
for(vector<shared_ptr<Stream>>::iterator stm=incomingStreams.begin();stm!=incomingStreams.end();++stm){
if((*stm)->jitterBuffer){
int lostCount=(*stm)->jitterBuffer->GetAndResetLostPacketCount();
2018-05-15 20:23:46 +02:00
if(lostCount>0 || (lostCount<0 && recvLossCount>((uint32_t) -lostCount)))
recvLossCount+=lostCount;
}
2017-03-30 16:06:59 +02:00
}
2017-02-02 17:24:40 +01:00
}
if(dontSendPackets>0)
dontSendPackets--;
2018-05-15 20:23:46 +02:00
unsigned int i;
2017-02-02 17:24:40 +01:00
conctl->Tick();
if(useTCP && !didAddTcpRelays){
2018-06-04 21:37:43 +02:00
vector<shared_ptr<Endpoint>> relays;
for(shared_ptr<Endpoint>& e:endpoints){
if(e->type!=Endpoint::TYPE_UDP_RELAY)
continue;
2018-06-04 21:37:43 +02:00
shared_ptr<Endpoint> tcpRelay=make_shared<Endpoint>(*e);
2018-05-15 20:23:46 +02:00
tcpRelay->type=Endpoint::TYPE_TCP_RELAY;
tcpRelay->averageRTT=0;
tcpRelay->lastPingSeq=0;
tcpRelay->lastPingTime=0;
memset(tcpRelay->rtts, 0, sizeof(tcpRelay->rtts));
2018-05-15 20:23:46 +02:00
tcpRelay->udpPongCount=0;
2018-06-04 21:37:43 +02:00
tcpRelay->id=tcpRelay->id ^ ((int64_t)(FOURCC('T','C','P',0)) << 32);
2018-05-15 20:23:46 +02:00
if(setCurrentEndpointToTCP && currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY){
setCurrentEndpointToTCP=false;
currentEndpoint=tcpRelay;
preferredRelay=tcpRelay;
}
relays.push_back(tcpRelay);
}
endpoints.insert(endpoints.end(), relays.begin(), relays.end());
didAddTcpRelays=true;
}
if(state==STATE_ESTABLISHED && encoder && conctl){
if((audioInput && !audioInput->IsInitialized()) || (audioOutput && !audioOutput->IsInitialized())){
LOGE("Audio I/O failed");
2018-05-15 20:23:46 +02:00
lastError=ERROR_AUDIO_IO;
SetState(STATE_FAILED);
}
2017-02-02 17:24:40 +01:00
int act=conctl->GetBandwidthControlAction();
2018-06-04 21:37:43 +02:00
if(shittyInternetMode){
encoder->SetBitrate(8000);
}else if(act==TGVOIP_CONCTL_ACT_DECREASE){
2017-02-02 17:24:40 +01:00
uint32_t bitrate=encoder->GetBitrate();
if(bitrate>8000)
2017-03-30 16:06:59 +02:00
encoder->SetBitrate(bitrate<(minAudioBitrate+audioBitrateStepDecr) ? minAudioBitrate : (bitrate-audioBitrateStepDecr));
2017-02-02 17:24:40 +01:00
}else if(act==TGVOIP_CONCTL_ACT_INCREASE){
uint32_t bitrate=encoder->GetBitrate();
if(bitrate<maxBitrate)
2017-03-30 16:06:59 +02:00
encoder->SetBitrate(bitrate+audioBitrateStepIncr);
2017-02-02 17:24:40 +01:00
}
2018-06-04 21:37:43 +02:00
//encoder->SetBitrate(6000);
2017-02-02 17:24:40 +01:00
if(tickCount%10==0 && encoder){
uint32_t sendLossCount=conctl->GetSendLossCount();
memmove(sendLossCountHistory+1, sendLossCountHistory, 31*sizeof(uint32_t));
sendLossCountHistory[0]=sendLossCount-prevSendLossCount;
prevSendLossCount=sendLossCount;
double avgSendLossCount=0;
for(i=0;i<10;i++){
avgSendLossCount+=sendLossCountHistory[i];
}
2018-06-04 21:37:43 +02:00
double packetsPerSec=1000/(double)outgoingStreams[0]->frameDuration;
2017-02-02 17:24:40 +01:00
avgSendLossCount=avgSendLossCount/10/packetsPerSec;
//LOGV("avg send loss: %.1f%%", avgSendLossCount*100);
2018-06-04 21:37:43 +02:00
if(avgSendLossCount>0.125 && networkType!=NET_TYPE_GPRS && networkType!=NET_TYPE_EDGE){
encoder->SetPacketLoss(40);
signalBarCount=1;
if(!shittyInternetMode){
// Shitty Internet Mode™. Redundant redundancy you can trust.
shittyInternetMode=true;
for(shared_ptr<Stream>& s:outgoingStreams){
if(s->type==STREAM_TYPE_AUDIO){
s->extraECEnabled=true;
SendStreamFlags(*s);
break;
}
}
if(encoder)
encoder->SetSecondaryEncoderEnabled(true);
LOGW("Enabling extra EC");
}
}else if(avgSendLossCount>0.1){
2017-02-02 17:24:40 +01:00
encoder->SetPacketLoss(40);
2018-05-15 20:23:46 +02:00
signalBarCount=1;
2017-02-02 17:24:40 +01:00
}else if(avgSendLossCount>0.075){
encoder->SetPacketLoss(35);
2018-05-15 20:23:46 +02:00
signalBarCount=MIN(signalBarCount, 2);
2017-02-02 17:24:40 +01:00
}else if(avgSendLossCount>0.0625){
encoder->SetPacketLoss(30);
2018-05-15 20:23:46 +02:00
signalBarCount=MIN(signalBarCount, 2);
2017-02-02 17:24:40 +01:00
}else if(avgSendLossCount>0.05){
encoder->SetPacketLoss(25);
2018-05-15 20:23:46 +02:00
signalBarCount=MIN(signalBarCount, 3);
2017-02-02 17:24:40 +01:00
}else if(avgSendLossCount>0.025){
encoder->SetPacketLoss(20);
2018-05-15 20:23:46 +02:00
signalBarCount=MIN(signalBarCount, 3);
2017-02-02 17:24:40 +01:00
}else if(avgSendLossCount>0.01){
encoder->SetPacketLoss(17);
}else{
encoder->SetPacketLoss(15);
}
2017-08-21 18:02:37 +02:00
2018-06-04 21:37:43 +02:00
if((avgSendLossCount<0.15 || networkType==NET_TYPE_EDGE || networkType==NET_TYPE_GPRS) && shittyInternetMode){
shittyInternetMode=false;
for(shared_ptr<Stream>& s:outgoingStreams){
if(s->type==STREAM_TYPE_AUDIO){
s->extraECEnabled=false;
SendStreamFlags(*s);
break;
}
}
if(encoder)
encoder->SetSecondaryEncoderEnabled(false);
LOGW("Disabling extra EC");
}
2017-02-02 17:24:40 +01:00
}
}
2018-05-15 20:23:46 +02:00
if(currentEndpoint->type==Endpoint::TYPE_TCP_RELAY){
signalBarCount=MIN(signalBarCount, 3);
}
2017-02-02 17:24:40 +01:00
bool areThereAnyEnabledStreams=false;
for(i=0;i<outgoingStreams.size();i++){
2018-06-04 21:37:43 +02:00
if(outgoingStreams[i]->enabled)
2017-02-02 17:24:40 +01:00
areThereAnyEnabledStreams=true;
}
if((waitingForAcks && tickCount%10==0) || (!areThereAnyEnabledStreams && tickCount%2==0)){
unsigned char* buf=outgoingPacketsBufferPool.Get();
if(buf){
sendQueue->Put(PendingOutgoingPacket{
/*.seq=*/(firstSentPing=GenerateOutSeq()),
/*.type=*/PKT_NOP,
/*.len=*/0,
/*.data=*/buf,
2018-06-04 21:37:43 +02:00
/*.endpoint=*/0
});
2017-02-02 17:24:40 +01:00
}
}
if(state==STATE_WAIT_INIT_ACK && GetCurrentTime()-stateChangeTime>.5){
SendInit();
}
if(waitingForRelayPeerInfo && GetCurrentTime()-publicEndpointsReqTime>5){
2018-06-04 21:37:43 +02:00
if(publicEndpointsReqCount>=10){
publicEndpointsReqCount=0;
waitingForRelayPeerInfo=false;
}else{
LOGD("Resending peer relay info request");
SendPublicEndpointsRequest();
publicEndpointsReqCount++;
}
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
{
MutexGuard m(queuedPacketsMutex);
for(i=0; i<queuedPackets.size(); i++){
2018-06-04 21:37:43 +02:00
QueuedPacket& qp=queuedPackets[i];
if(qp.timeout>0 && qp.firstSentTime>0 && GetCurrentTime()-qp.firstSentTime>=qp.timeout){
2018-05-15 20:23:46 +02:00
LOGD("Removing queued packet because of timeout");
queuedPackets.erase(queuedPackets.begin()+i);
i--;
continue;
2017-02-02 17:24:40 +01:00
}
2018-06-04 21:37:43 +02:00
if(GetCurrentTime()-qp.lastSentTime>=qp.retryInterval){
2018-05-15 20:23:46 +02:00
unsigned char *buf=outgoingPacketsBufferPool.Get();
if(buf){
2018-05-15 20:23:46 +02:00
uint32_t seq=GenerateOutSeq();
2018-06-04 21:37:43 +02:00
memmove(&qp.seqs[1], qp.seqs, 4*9);
qp.seqs[0]=seq;
qp.lastSentTime=GetCurrentTime();
//LOGD("Sending queued packet, seq=%u, type=%u, len=%u", seq, qp.type, qp.data.Length());
if(qp.firstSentTime==0)
qp.firstSentTime=qp.lastSentTime;
if(qp.data.Length())
memcpy(buf, *qp.data, qp.data.Length());
sendQueue->Put(PendingOutgoingPacket{
2018-05-15 20:23:46 +02:00
/*.seq=*/seq,
2018-06-04 21:37:43 +02:00
/*.type=*/qp.type,
/*.len=*/qp.data.Length(),
/*.data=*/buf,
2018-06-04 21:37:43 +02:00
/*.endpoint=*/0
});
}
2017-02-02 17:24:40 +01:00
}
}
2018-05-15 20:23:46 +02:00
}
2018-06-04 21:37:43 +02:00
for(vector<shared_ptr<Stream>>::iterator stm=incomingStreams.begin();stm!=incomingStreams.end();++stm){
if((*stm)->jitterBuffer){
(*stm)->jitterBuffer->Tick();
2018-05-15 20:23:46 +02:00
//double avgDelay=stm->jitterBuffer->GetAverageDelay();
double avgLateCount[3];
2018-06-04 21:37:43 +02:00
(*stm)->jitterBuffer->GetAverageLateCount(avgLateCount);
2018-05-15 20:23:46 +02:00
/*if(avgDelay>=5)
signalBarCount=1;
else if(avgDelay>=4)
signalBarCount=MIN(signalBarCount, 2);
else if(avgDelay>=3)
signalBarCount=MIN(signalBarCount, 3);*/
if(avgLateCount[2]>=0.2)
signalBarCount=1;
else if(avgLateCount[2]>=0.1)
signalBarCount=MIN(signalBarCount, 2);
2017-02-02 17:24:40 +01:00
}
}
2018-05-15 20:23:46 +02:00
{
MutexGuard m(endpointsMutex);
SendRelayPings();
if(udpConnectivityState==UDP_UNKNOWN){
2018-06-04 21:37:43 +02:00
for(shared_ptr<Endpoint>& e:endpoints){
if(e->type==Endpoint::TYPE_UDP_RELAY){
SendUdpPing(e);
2018-05-15 20:23:46 +02:00
}
}
2018-05-15 20:23:46 +02:00
udpConnectivityState=UDP_PING_SENT;
lastUdpPingTime=time;
udpPingCount=1;
}else if(udpConnectivityState==UDP_PING_SENT || udpConnectivityState==UDP_BAD){
int targetPingCount=udpConnectivityState==UDP_BAD ? 10 : 4;
if(time-lastUdpPingTime>=(udpPingCount<targetPingCount ? 0.5 : 1.0)){
if(udpPingCount<targetPingCount){
2018-06-04 21:37:43 +02:00
for(shared_ptr<Endpoint>& e:endpoints){
if(e->type==Endpoint::TYPE_UDP_RELAY){
SendUdpPing(e);
2018-05-15 20:23:46 +02:00
}
}
2018-05-15 20:23:46 +02:00
udpPingCount++;
lastUdpPingTime=time;
}else{
double avgPongs=0;
int count=0;
2018-06-04 21:37:43 +02:00
for(shared_ptr<Endpoint>& e:endpoints){
if(e->type==Endpoint::TYPE_UDP_RELAY){
if(e->udpPongCount>0){
avgPongs+=(double) e->udpPongCount;
2018-05-15 20:23:46 +02:00
count++;
}
}
}
if(count>0)
avgPongs/=(double)count;
else
avgPongs=0.0;
LOGI("UDP ping reply count: %.2f", avgPongs);
bool configUseTCP=ServerConfig::GetSharedInstance()->GetBoolean("use_tcp", true);
if(configUseTCP){
if(avgPongs==0.0 || (udpConnectivityState==UDP_BAD && avgPongs<7.0)){
udpConnectivityState=UDP_NOT_AVAILABLE;
useTCP=true;
useUDP=false;
waitingForRelayPeerInfo=false;
if(currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY)
setCurrentEndpointToTCP=true;
}else if(avgPongs<3.0){
udpConnectivityState=UDP_BAD;
useTCP=true;
setCurrentEndpointToTCP=true;
}else{
udpConnectivityState=UDP_AVAILABLE;
}
}else{
udpConnectivityState=UDP_NOT_AVAILABLE;
}
//LOGW("No UDP ping replies received; assuming no connectivity and trying TCP")
//udpConnectivityState=UDP_NOT_AVAILABLE;
//useTCP=true;
}
}
}
}
2017-02-02 17:24:40 +01:00
if(state==STATE_ESTABLISHED || state==STATE_RECONNECTING){
2018-06-04 21:37:43 +02:00
if(time-lastRecvPacketTime>=config.recvTimeout){
2018-05-15 20:23:46 +02:00
if(currentEndpoint && currentEndpoint->type!=Endpoint::TYPE_UDP_RELAY && currentEndpoint->type!=Endpoint::TYPE_TCP_RELAY){
2017-02-02 17:24:40 +01:00
LOGW("Packet receive timeout, switching to relay");
2017-03-30 16:06:59 +02:00
currentEndpoint=preferredRelay;
2018-06-04 21:37:43 +02:00
for(shared_ptr<Endpoint>& e:endpoints){
2018-05-15 20:23:46 +02:00
if(e->type==Endpoint::TYPE_UDP_P2P_INET || e->type==Endpoint::TYPE_UDP_P2P_LAN){
e->averageRTT=0;
memset(e->rtts, 0, sizeof(e->rtts));
2017-03-30 16:06:59 +02:00
}
}
2017-02-02 17:24:40 +01:00
if(allowP2p){
SendPublicEndpointsRequest();
}
UpdateDataSavingState();
UpdateAudioBitrate();
BufferOutputStream s(4);
2017-02-02 17:24:40 +01:00
s.WriteInt32(dataSavingMode ? INIT_FLAG_DATA_SAVING_ENABLED : 0);
2018-06-04 21:37:43 +02:00
if(peerVersion<6){
SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20);
}else{
Buffer buf(move(s));
SendExtra(buf, EXTRA_TYPE_NETWORK_CHANGED);
}
lastRecvPacketTime=time;
2017-02-02 17:24:40 +01:00
}else{
LOGW("Packet receive timeout, disconnecting");
2018-05-15 20:23:46 +02:00
lastError=ERROR_TIMEOUT;
2017-02-02 17:24:40 +01:00
SetState(STATE_FAILED);
}
}
}else if(state==STATE_WAIT_INIT || state==STATE_WAIT_INIT_ACK){
2018-06-04 21:37:43 +02:00
if(GetCurrentTime()-connectionInitTime>=config.initTimeout){
2017-02-02 17:24:40 +01:00
LOGW("Init timeout, disconnecting");
2018-05-15 20:23:46 +02:00
lastError=ERROR_TIMEOUT;
2017-02-02 17:24:40 +01:00
SetState(STATE_FAILED);
}
}
if(state==STATE_ESTABLISHED && time-lastRecvPacketTime>=reconnectingTimeout){
SetState(STATE_RECONNECTING);
}
if(state!=STATE_ESTABLISHED && setEstablishedAt>0 && time>=setEstablishedAt){
SetState(STATE_ESTABLISHED);
setEstablishedAt=0;
}
2018-05-15 20:23:46 +02:00
if(tickCount%10==0){
signalBarsHistory[(tickCount/10)%sizeof(signalBarsHistory)]=(unsigned char) signalBarCount;
//LOGV("Signal bar count history %08X", *reinterpret_cast<uint32_t *>(&signalBarsHistory));
int _signalBarCount=GetSignalBarsCount();
if(_signalBarCount!=prevSignalBarCount){
LOGD("SIGNAL BAR COUNT CHANGED: %d", _signalBarCount);
if(callbacks.signalBarCountChanged)
callbacks.signalBarCountChanged(this, _signalBarCount);
}
2017-08-21 18:02:37 +02:00
}
2018-05-15 20:23:46 +02:00
if(statsDump && incomingStreams.size()==1){
2018-06-04 21:37:43 +02:00
shared_ptr<JitterBuffer>& jitterBuffer=incomingStreams[0]->jitterBuffer;
//fprintf(statsDump, "Time\tRTT\tLISeq\tLASeq\tCWnd\tBitrate\tJitter\tJDelay\tAJDelay\n");
fprintf(statsDump, "%.3f\t%.3f\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%.3f\t%.3f\t%.3f\n",
GetCurrentTime()-startTime,
currentEndpoint->rtts[0],
lastRemoteSeq,
seq,
lastRemoteAckSeq,
recvLossCount,
conctl ? conctl->GetSendLossCount() : 0,
2017-04-19 15:39:27 +02:00
conctl ? (int)conctl->GetInflightDataSize() : 0,
encoder ? encoder->GetBitrate() : 0,
encoder ? encoder->GetPacketLoss() : 0,
jitterBuffer ? jitterBuffer->GetLastMeasuredJitter() : 0,
jitterBuffer ? jitterBuffer->GetLastMeasuredDelay()*0.06 : 0,
jitterBuffer ? jitterBuffer->GetAverageDelay()*0.06 : 0);
}
2017-02-02 17:24:40 +01:00
}
LOGI("=== tick thread exiting ===");
}
Endpoint& VoIPController::GetRemoteEndpoint(){
return *currentEndpoint;
2017-02-02 17:24:40 +01:00
}
2018-06-04 21:37:43 +02:00
void VoIPController::SendPacket(unsigned char *data, size_t len, shared_ptr<Endpoint> ep, PendingOutgoingPacket& srcPacket){
2017-02-02 17:24:40 +01:00
if(stopping)
return;
2018-05-15 20:23:46 +02:00
if(ep->type==Endpoint::TYPE_TCP_RELAY && !useTCP)
return;
BufferOutputStream out(len+128);
2018-05-15 20:23:46 +02:00
if(ep->type==Endpoint::TYPE_UDP_RELAY || ep->type==Endpoint::TYPE_TCP_RELAY)
out.WriteBytes((unsigned char*)ep->peerTag, 16);
2017-02-02 17:24:40 +01:00
else
out.WriteBytes(callID, 16);
if(len>0){
2018-05-15 20:23:46 +02:00
if(useMTProto2){
BufferOutputStream inner(len+128);
inner.WriteInt32((uint32_t)len);
inner.WriteBytes(data, len);
2017-02-02 17:24:40 +01:00
size_t padLen=16-inner.GetLength()%16;
2018-05-15 20:23:46 +02:00
if(padLen<12)
padLen+=16;
unsigned char padding[28];
2017-02-02 17:24:40 +01:00
crypto.rand_bytes((uint8_t *) padding, padLen);
inner.WriteBytes(padding, padLen);
2018-05-15 20:23:46 +02:00
assert(inner.GetLength()%16==0);
unsigned char key[32], iv[32], msgKey[16];
out.WriteBytes(keyFingerprint, 8);
BufferOutputStream buf(len+32);
size_t x=isOutgoing ? 0 : 8;
buf.WriteBytes(encryptionKey+88+x, 32);
buf.WriteBytes(inner.GetBuffer()+4, inner.GetLength()-4);
unsigned char msgKeyLarge[32];
crypto.sha256(buf.GetBuffer(), buf.GetLength(), msgKeyLarge);
memcpy(msgKey, msgKeyLarge+8, 16);
KDF2(msgKey, isOutgoing ? 0 : 8, key, iv);
out.WriteBytes(msgKey, 16);
//LOGV("<- MSG KEY: %08x %08x %08x %08x, hashed %u", *reinterpret_cast<int32_t*>(msgKey), *reinterpret_cast<int32_t*>(msgKey+4), *reinterpret_cast<int32_t*>(msgKey+8), *reinterpret_cast<int32_t*>(msgKey+12), inner.GetLength()-4);
unsigned char aesOut[MSC_STACK_FALLBACK(inner.GetLength(), 1500)];
crypto.aes_ige_encrypt(inner.GetBuffer(), aesOut, inner.GetLength(), key, iv);
out.WriteBytes(aesOut, inner.GetLength());
}else{
BufferOutputStream inner(len+128);
inner.WriteInt32(len);
inner.WriteBytes(data, len);
if(inner.GetLength()%16!=0){
size_t padLen=16-inner.GetLength()%16;
unsigned char padding[16];
crypto.rand_bytes((uint8_t *) padding, padLen);
inner.WriteBytes(padding, padLen);
}
assert(inner.GetLength()%16==0);
unsigned char key[32], iv[32], msgHash[SHA1_LENGTH];
crypto.sha1((uint8_t *) inner.GetBuffer(), len+4, msgHash);
out.WriteBytes(keyFingerprint, 8);
out.WriteBytes((msgHash+(SHA1_LENGTH-16)), 16);
KDF(msgHash+(SHA1_LENGTH-16), isOutgoing ? 0 : 8, key, iv);
unsigned char aesOut[MSC_STACK_FALLBACK(inner.GetLength(), 1500)];
crypto.aes_ige_encrypt(inner.GetBuffer(), aesOut, inner.GetLength(), key, iv);
out.WriteBytes(aesOut, inner.GetLength());
2017-02-02 17:24:40 +01:00
}
}
//LOGV("Sending %d bytes to %s:%d", out.GetLength(), ep->address.ToString().c_str(), ep->port);
2018-05-15 20:23:46 +02:00
NetworkPacket pkt={0};
2018-06-04 21:37:43 +02:00
pkt.address=&ep->GetAddress();
pkt.port=ep->port;
pkt.length=out.GetLength();
pkt.data=out.GetBuffer();
2018-05-15 20:23:46 +02:00
pkt.protocol=ep->type==Endpoint::TYPE_TCP_RELAY ? PROTO_TCP : PROTO_UDP;
ActuallySendPacket(pkt, ep);
}
2018-06-04 21:37:43 +02:00
void VoIPController::ActuallySendPacket(NetworkPacket &pkt, shared_ptr<Endpoint> ep){
2018-05-15 20:23:46 +02:00
//LOGI("Sending packet of %d bytes", pkt.length);
if(IS_MOBILE_NETWORK(networkType))
stats.bytesSentMobile+=(uint64_t)pkt.length;
else
stats.bytesSentWifi+=(uint64_t)pkt.length;
if(ep->type==Endpoint::TYPE_TCP_RELAY){
if(ep->socket && !ep->socket->IsFailed()){
ep->socket->Send(&pkt);
}else{
2018-05-15 20:23:46 +02:00
if(ep->socket){
LOGD("closing failed TCP socket: %s:%u", ep->address.ToString().c_str(), ep->port);
ep->socket->Close();
delete ep->socket;
ep->socket=NULL;
}
LOGI("connecting to tcp: %s:%u", ep->address.ToString().c_str(), ep->port);
NetworkSocket* s;
if(proxyProtocol==PROXY_NONE){
s=NetworkSocket::Create(PROTO_TCP);
}else if(proxyProtocol==PROXY_SOCKS5){
NetworkSocket* rawTcp=NetworkSocket::Create(PROTO_TCP);
openingTcpSocket=rawTcp;
rawTcp->Connect(resolvedProxyAddress, proxyPort);
if(rawTcp->IsFailed()){
openingTcpSocket=NULL;
rawTcp->Close();
delete rawTcp;
LOGW("Error connecting to SOCKS5 proxy");
return;
}
NetworkSocketSOCKS5Proxy* proxy=new NetworkSocketSOCKS5Proxy(rawTcp, NULL, proxyUsername, proxyPassword);
2018-05-10 14:33:14 +02:00
openingTcpSocket=proxy;
proxy->InitConnection();
if(proxy->IsFailed()){
openingTcpSocket=NULL;
LOGW("Proxy initialization failed");
proxy->Close();
delete proxy;
return;
}
s=proxy;
2017-07-04 02:04:59 +02:00
}/*else if(proxyProtocol==PROXY_HTTP){
s=NetworkSocket::Create(PROTO_TCP);
2017-07-04 02:04:59 +02:00
}*/else{
LOGE("Unsupported proxy protocol %d", proxyProtocol);
SetState(STATE_FAILED);
return;
}
s->Connect(&ep->address, ep->port);
if(s->IsFailed()){
2018-05-10 14:33:14 +02:00
openingTcpSocket=NULL;
s->Close();
delete s;
LOGW("Error connecting to %s:%u", ep->address.ToString().c_str(), ep->port);
}else{
NetworkSocketTCPObfuscated* tcpWrapper=new NetworkSocketTCPObfuscated(s);
openingTcpSocket=tcpWrapper;
tcpWrapper->InitConnection();
openingTcpSocket=NULL;
if(tcpWrapper->IsFailed()){
tcpWrapper->Close();
delete tcpWrapper;
LOGW("Error initializing connection to %s:%u", ep->address.ToString().c_str(), ep->port);
}else{
tcpWrapper->Send(&pkt);
ep->socket=tcpWrapper;
selectCanceller->CancelSelect();
}
}
}
}else{
udpSocket->Send(&pkt);
}
2017-02-02 17:24:40 +01:00
}
void VoIPController::SetNetworkType(int type){
2017-02-02 17:24:40 +01:00
networkType=type;
UpdateDataSavingState();
UpdateAudioBitrate();
2018-06-04 21:37:43 +02:00
myIPv6=IPv6Address();
string itfName=udpSocket->GetLocalInterfaceInfo(NULL, &myIPv6);
LOGI("Local IPv6 address: %s", myIPv6.ToString().c_str());
if(itfName!=activeNetItfName){
udpSocket->OnActiveInterfaceChanged();
LOGI("Active network interface changed: %s -> %s", activeNetItfName.c_str(), itfName.c_str());
bool isFirstChange=activeNetItfName.length()==0;
activeNetItfName=itfName;
2017-02-02 17:24:40 +01:00
if(isFirstChange)
return;
2018-05-15 20:23:46 +02:00
if(currentEndpoint && currentEndpoint->type!=Endpoint::TYPE_UDP_RELAY){
if(preferredRelay->type==Endpoint::TYPE_UDP_RELAY)
currentEndpoint=preferredRelay;
2018-05-15 20:23:46 +02:00
MutexGuard m(endpointsMutex);
2018-06-04 21:37:43 +02:00
for(vector<shared_ptr<Endpoint>>::iterator itr=endpoints.begin();itr!=endpoints.end();){
shared_ptr<Endpoint> endpoint=*itr;
2018-05-15 20:23:46 +02:00
if(endpoint->type==Endpoint::TYPE_UDP_RELAY && useTCP){
useTCP=false;
2018-05-15 20:23:46 +02:00
if(preferredRelay->type==Endpoint::TYPE_TCP_RELAY){
preferredRelay=endpoint;
currentEndpoint=endpoint;
}
2018-05-15 20:23:46 +02:00
}else if(endpoint->type==Endpoint::TYPE_TCP_RELAY && endpoint->socket){
endpoint->socket->Close();
}
2018-05-15 20:23:46 +02:00
//if(endpoint->type==Endpoint::TYPE_UDP_P2P_INET){
endpoint->averageRTT=0;
memset(endpoint->rtts, 0, sizeof(endpoint->rtts));
//}
2018-05-15 20:23:46 +02:00
if(endpoint->type==Endpoint::TYPE_UDP_P2P_LAN){
2017-03-30 16:06:59 +02:00
itr=endpoints.erase(itr);
}else{
++itr;
2017-02-02 17:24:40 +01:00
}
}
}
udpConnectivityState=UDP_UNKNOWN;
udpPingCount=0;
lastUdpPingTime=0;
if(proxyProtocol==PROXY_SOCKS5)
InitUDPProxy();
2017-02-02 17:24:40 +01:00
if(allowP2p && currentEndpoint){
SendPublicEndpointsRequest();
}
BufferOutputStream s(4);
2017-02-02 17:24:40 +01:00
s.WriteInt32(dataSavingMode ? INIT_FLAG_DATA_SAVING_ENABLED : 0);
2018-06-04 21:37:43 +02:00
if(peerVersion<6){
SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20);
}else{
Buffer buf(move(s));
SendExtra(buf, EXTRA_TYPE_NETWORK_CHANGED);
}
selectCanceller->CancelSelect();
2018-06-04 21:37:43 +02:00
didSendIPv6Endpoint=false;
udpPingCount=0;
AddIPv6Relays();
2017-02-02 17:24:40 +01:00
}
LOGI("set network type: %d, active interface %s", type, activeNetItfName.c_str());
2018-05-15 20:23:46 +02:00
}
2018-06-04 21:37:43 +02:00
void VoIPController::AddIPv6Relays(){
if(!myIPv6.IsEmpty() && !didAddIPv6Relays){
unordered_map<string, vector<shared_ptr<Endpoint>>> endpointsByAddress;
MutexGuard m(endpointsMutex);
for(shared_ptr<Endpoint>& e:endpoints){
if((e->type==Endpoint::TYPE_UDP_RELAY || e->type==Endpoint::TYPE_TCP_RELAY) && !e->v6address.IsEmpty() && !e->address.IsEmpty()){
endpointsByAddress[e->v6address.ToString()].push_back(e);
}
}
int globalId=callID[15];
for(unordered_map<string, vector<shared_ptr<Endpoint>>>::iterator addr=endpointsByAddress.begin();addr!=endpointsByAddress.end();++addr){
shared_ptr<Endpoint> best=NULL;
int bestDiff=256;
for(shared_ptr<Endpoint>& e:addr->second){
int epId=(int) (e->id & 0xFF);
int diff=abs(globalId-epId);
//if(diff<bestDiff){
best=e;
bestDiff=diff;
//}
//}
if(best){
didAddIPv6Relays=true;
shared_ptr<Endpoint> v6only=make_shared<Endpoint>(*best);
v6only->address=IPv4Address(0);
v6only->id=v6only->id ^ ((int64_t)(FOURCC('I','P','v','6')) << 32);
endpoints.push_back(v6only);
LOGD("Adding IPv6-only endpoint [%s]:%u", v6only->v6address.ToString().c_str(), v6only->port);
}
}
}
2018-05-15 20:23:46 +02:00
}
2017-02-02 17:24:40 +01:00
}
double VoIPController::GetAverageRTT(){
2017-02-02 17:24:40 +01:00
if(lastSentSeq>=lastRemoteAckSeq){
uint32_t diff=lastSentSeq-lastRemoteAckSeq;
//LOGV("rtt diff=%u", diff);
if(diff<32){
double res=0;
int count=0;
2018-05-15 20:23:46 +02:00
/*for(i=diff;i<32;i++){
2017-02-02 17:24:40 +01:00
if(remoteAcks[i-diff]>0){
res+=(remoteAcks[i-diff]-sentPacketTimes[i]);
count++;
}
2018-05-15 20:23:46 +02:00
}*/
2018-05-28 01:17:22 +02:00
MutexGuard m(queuedPacketsMutex);
2018-05-15 20:23:46 +02:00
for(std::vector<RecentOutgoingPacket>::iterator itr=recentOutgoingPackets.begin();itr!=recentOutgoingPackets.end();++itr){
if(itr->ackTime>0){
res+=(itr->ackTime-itr->sendTime);
count++;
}
2017-02-02 17:24:40 +01:00
}
if(count>0)
res/=count;
return res;
}
}
return 999;
}
2017-03-30 16:06:59 +02:00
#if defined(__APPLE__)
static void initMachTimestart() {
2018-06-04 21:37:43 +02:00
mach_timebase_info_data_t tb = { 0, 0 };
mach_timebase_info(&tb);
VoIPController::machTimebase = tb.numer;
VoIPController::machTimebase /= tb.denom;
VoIPController::machTimestart = mach_absolute_time();
2017-03-30 16:06:59 +02:00
}
#endif
double VoIPController::GetCurrentTime(){
2017-02-02 17:24:40 +01:00
#if defined(__linux__)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec+(double)ts.tv_nsec/1000000000.0;
#elif defined(__APPLE__)
2018-06-04 21:37:43 +02:00
static pthread_once_t token = PTHREAD_ONCE_INIT;
pthread_once(&token, &initMachTimestart);
2017-02-02 17:24:40 +01:00
return (mach_absolute_time() - machTimestart) * machTimebase / 1000000000.0f;
#elif defined(_WIN32)
if(!didInitWin32TimeScale){
LARGE_INTEGER scale;
QueryPerformanceFrequency(&scale);
win32TimeScale=scale.QuadPart;
didInitWin32TimeScale=true;
}
LARGE_INTEGER t;
QueryPerformanceCounter(&t);
return (double)t.QuadPart/(double)win32TimeScale;
2017-02-02 17:24:40 +01:00
#endif
}
void VoIPController::SetState(int state){
2017-02-02 17:24:40 +01:00
this->state=state;
LOGV("Call state changed to %d", state);
2017-02-02 17:24:40 +01:00
stateChangeTime=GetCurrentTime();
2018-05-15 20:23:46 +02:00
if(callbacks.connectionStateChanged){
callbacks.connectionStateChanged(this, state);
2017-02-02 17:24:40 +01:00
}
2018-05-15 20:23:46 +02:00
if(state==STATE_ESTABLISHED)
SetMicMute(micMuted);
2017-02-02 17:24:40 +01:00
}
void VoIPController::SetMicMute(bool mute){
2017-02-02 17:24:40 +01:00
micMuted=mute;
if(audioInput){
if(mute)
audioInput->Stop();
else
audioInput->Start();
2017-03-30 16:06:59 +02:00
if(!audioInput->IsInitialized()){
2018-05-15 20:23:46 +02:00
lastError=ERROR_AUDIO_IO;
2017-03-30 16:06:59 +02:00
SetState(STATE_FAILED);
return;
}
2017-02-02 17:24:40 +01:00
}
if(echoCanceller)
echoCanceller->Enable(!mute);
2018-05-15 20:23:46 +02:00
if(state==STATE_ESTABLISHED){
2018-06-04 21:37:43 +02:00
for(shared_ptr<Stream>& s:outgoingStreams){
if(s->type==STREAM_TYPE_AUDIO){
s->enabled=!mute;
if(peerVersion<6){
unsigned char buf[2];
buf[0]=s->id;
buf[1]=(char) (mute ? 0 : 1);
SendPacketReliably(PKT_STREAM_STATE, buf, 2, .5f, 20);
}else{
SendStreamFlags(*s);
}
2018-05-15 20:23:46 +02:00
}
2017-02-02 17:24:40 +01:00
}
}
}
void VoIPController::UpdateAudioOutputState(){
2017-02-02 17:24:40 +01:00
bool areAnyAudioStreamsEnabled=false;
2018-06-04 21:37:43 +02:00
for(vector<shared_ptr<Stream>>::iterator s=incomingStreams.begin();s!=incomingStreams.end();++s){
if((*s)->type==STREAM_TYPE_AUDIO && (*s)->enabled)
2017-02-02 17:24:40 +01:00
areAnyAudioStreamsEnabled=true;
}
2018-05-15 20:23:46 +02:00
/*if(jitterBuffer){
2017-02-02 17:24:40 +01:00
jitterBuffer->Reset();
}
if(decoder){
decoder->ResetQueue();
2018-05-15 20:23:46 +02:00
}*/
2017-02-02 17:24:40 +01:00
if(audioOutput){
if(audioOutput->IsPlaying()!=areAnyAudioStreamsEnabled){
if(areAnyAudioStreamsEnabled)
audioOutput->Start();
else
audioOutput->Stop();
}
}
}
2018-06-04 21:37:43 +02:00
void VoIPController::SendStreamFlags(Stream& stream){
BufferOutputStream s(5);
s.WriteByte(stream.id);
uint32_t flags=0;
if(stream.enabled)
flags|=STREAM_FLAG_ENABLED;
if(stream.extraECEnabled)
flags|=STREAM_FLAG_EXTRA_EC;
s.WriteInt32(flags);
Buffer buf(move(s));
SendExtra(buf, EXTRA_TYPE_STREAM_FLAGS);
}
void VoIPController::KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv){
2017-02-02 17:24:40 +01:00
uint8_t sA[SHA1_LENGTH], sB[SHA1_LENGTH], sC[SHA1_LENGTH], sD[SHA1_LENGTH];
BufferOutputStream buf(128);
2017-03-30 16:06:59 +02:00
buf.WriteBytes(msgKey, 16);
2017-02-02 17:24:40 +01:00
buf.WriteBytes(encryptionKey+x, 32);
2017-03-30 16:06:59 +02:00
crypto.sha1(buf.GetBuffer(), buf.GetLength(), sA);
2017-02-02 17:24:40 +01:00
buf.Reset();
buf.WriteBytes(encryptionKey+32+x, 16);
2017-03-30 16:06:59 +02:00
buf.WriteBytes(msgKey, 16);
2017-02-02 17:24:40 +01:00
buf.WriteBytes(encryptionKey+48+x, 16);
2017-03-30 16:06:59 +02:00
crypto.sha1(buf.GetBuffer(), buf.GetLength(), sB);
2017-02-02 17:24:40 +01:00
buf.Reset();
buf.WriteBytes(encryptionKey+64+x, 32);
2017-03-30 16:06:59 +02:00
buf.WriteBytes(msgKey, 16);
crypto.sha1(buf.GetBuffer(), buf.GetLength(), sC);
2017-02-02 17:24:40 +01:00
buf.Reset();
2017-03-30 16:06:59 +02:00
buf.WriteBytes(msgKey, 16);
2017-02-02 17:24:40 +01:00
buf.WriteBytes(encryptionKey+96+x, 32);
2017-03-30 16:06:59 +02:00
crypto.sha1(buf.GetBuffer(), buf.GetLength(), sD);
2017-02-02 17:24:40 +01:00
buf.Reset();
2017-03-30 16:06:59 +02:00
buf.WriteBytes(sA, 8);
buf.WriteBytes(sB+8, 12);
buf.WriteBytes(sC+4, 12);
2017-02-02 17:24:40 +01:00
assert(buf.GetLength()==32);
memcpy(aesKey, buf.GetBuffer(), 32);
buf.Reset();
2017-03-30 16:06:59 +02:00
buf.WriteBytes(sA+8, 12);
buf.WriteBytes(sB, 8);
buf.WriteBytes(sC+16, 4);
buf.WriteBytes(sD, 8);
2017-02-02 17:24:40 +01:00
assert(buf.GetLength()==32);
memcpy(aesIv, buf.GetBuffer(), 32);
}
2018-05-15 20:23:46 +02:00
void VoIPController::KDF2(unsigned char* msgKey, size_t x, unsigned char *aesKey, unsigned char *aesIv){
uint8_t sA[32], sB[32];
BufferOutputStream buf(128);
buf.WriteBytes(msgKey, 16);
buf.WriteBytes(encryptionKey+x, 36);
crypto.sha256(buf.GetBuffer(), buf.GetLength(), sA);
buf.Reset();
buf.WriteBytes(encryptionKey+40+x, 36);
buf.WriteBytes(msgKey, 16);
crypto.sha256(buf.GetBuffer(), buf.GetLength(), sB);
buf.Reset();
buf.WriteBytes(sA, 8);
buf.WriteBytes(sB+8, 16);
buf.WriteBytes(sA+24, 8);
memcpy(aesKey, buf.GetBuffer(), 32);
buf.Reset();
buf.WriteBytes(sB, 8);
buf.WriteBytes(sA+8, 16);
buf.WriteBytes(sB+24, 8);
memcpy(aesIv, buf.GetBuffer(), 32);
}
2018-06-04 21:37:43 +02:00
string VoIPController::GetDebugString(){
string r="Remote endpoints: \n";
char buffer[2048];
for(shared_ptr<Endpoint>& endpoint:endpoints){
2017-02-02 17:24:40 +01:00
const char* type;
switch(endpoint->type){
2018-05-15 20:23:46 +02:00
case Endpoint::TYPE_UDP_P2P_INET:
2017-02-02 17:24:40 +01:00
type="UDP_P2P_INET";
break;
2018-05-15 20:23:46 +02:00
case Endpoint::TYPE_UDP_P2P_LAN:
2017-02-02 17:24:40 +01:00
type="UDP_P2P_LAN";
break;
2018-05-15 20:23:46 +02:00
case Endpoint::TYPE_UDP_RELAY:
2017-02-02 17:24:40 +01:00
type="UDP_RELAY";
break;
2018-05-15 20:23:46 +02:00
case Endpoint::TYPE_TCP_RELAY:
2017-02-02 17:24:40 +01:00
type="TCP_RELAY";
break;
default:
type="UNKNOWN";
break;
}
2018-06-04 21:37:43 +02:00
snprintf(buffer, sizeof(buffer), "%s:%u %dms %d [%s%s]\n", endpoint->address.IsEmpty() ? ("["+endpoint->v6address.ToString()+"]").c_str() : endpoint->address.ToString().c_str(), endpoint->port, (int)(endpoint->averageRTT*1000), endpoint->udpPongCount, type, currentEndpoint==endpoint ? ", IN_USE" : "");
r+=buffer;
}
if(shittyInternetMode){
r+="ShittyInternetMode enabled\n";
2017-02-02 17:24:40 +01:00
}
double avgLate[3];
2018-06-04 21:37:43 +02:00
shared_ptr<JitterBuffer> jitterBuffer=incomingStreams.size()==1 ? incomingStreams[0]->jitterBuffer : NULL;
2017-02-02 17:24:40 +01:00
if(jitterBuffer)
jitterBuffer->GetAverageLateCount(avgLate);
else
memset(avgLate, 0, 3*sizeof(double));
2018-06-04 21:37:43 +02:00
snprintf(buffer, sizeof(buffer),
"Jitter buffer: %d/%.2f | %.1f, %.1f, %.1f\n"
2017-02-02 17:24:40 +01:00
"RTT avg/min: %d/%d\n"
"Congestion window: %d/%d bytes\n"
2018-05-15 20:23:46 +02:00
"Key fingerprint: %02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX%s\n"
2017-02-02 17:24:40 +01:00
"Last sent/ack'd seq: %u/%u\n"
"Last recvd seq: %u\n"
2017-03-30 16:06:59 +02:00
"Send/recv losses: %u/%u (%d%%)\n"
2017-02-02 17:24:40 +01:00
"Audio bitrate: %d kbit\n"
// "Packet grouping: %d\n"
"Frame size out/in: %d/%d\n"
"Bytes sent/recvd: %llu/%llu",
jitterBuffer ? jitterBuffer->GetMinPacketCount() : 0, jitterBuffer ? jitterBuffer->GetAverageDelay() : 0, avgLate[0], avgLate[1], avgLate[2],
2017-02-02 17:24:40 +01:00
// (int)(GetAverageRTT()*1000), 0,
(int)(conctl->GetAverageRTT()*1000), (int)(conctl->GetMinimumRTT()*1000),
2017-04-19 15:39:27 +02:00
int(conctl->GetInflightDataSize()), int(conctl->GetCongestionWindow()),
2017-02-02 17:24:40 +01:00
keyFingerprint[0],keyFingerprint[1],keyFingerprint[2],keyFingerprint[3],keyFingerprint[4],keyFingerprint[5],keyFingerprint[6],keyFingerprint[7],
2018-05-15 20:23:46 +02:00
useMTProto2 ? " (MTProto2.0)" : "",
2017-04-19 15:39:27 +02:00
lastSentSeq, lastRemoteAckSeq, lastRemoteSeq,
2017-03-30 16:06:59 +02:00
conctl->GetSendLossCount(), recvLossCount, encoder ? encoder->GetPacketLoss() : 0,
2017-02-02 17:24:40 +01:00
encoder ? (encoder->GetBitrate()/1000) : 0,
// audioPacketGrouping,
2018-06-04 21:37:43 +02:00
outgoingStreams[0]->frameDuration, incomingStreams.size()>0 ? incomingStreams[0]->frameDuration : 0,
2017-04-19 15:39:27 +02:00
(long long unsigned int)(stats.bytesSentMobile+stats.bytesSentWifi),
(long long unsigned int)(stats.bytesRecvdMobile+stats.bytesRecvdWifi));
2018-06-04 21:37:43 +02:00
r+=buffer;
return r;
2017-02-02 17:24:40 +01:00
}
void VoIPController::SendPublicEndpointsRequest(){
2018-06-04 21:37:43 +02:00
if(!allowP2p)
return;
2017-02-02 17:24:40 +01:00
LOGI("Sending public endpoints request");
2018-06-04 21:37:43 +02:00
MutexGuard m(endpointsMutex);
for(shared_ptr<Endpoint>& e:endpoints){
if(e->type==Endpoint::TYPE_UDP_RELAY && !e->IsIPv6Only()){
SendPublicEndpointsRequest(*e);
}
}
}
void VoIPController::SendPublicEndpointsRequest(Endpoint& relay){
if(!useUDP)
return;
LOGD("Sending public endpoints request to %s:%d", relay.address.ToString().c_str(), relay.port);
2017-02-02 17:24:40 +01:00
publicEndpointsReqTime=GetCurrentTime();
waitingForRelayPeerInfo=true;
unsigned char buf[32];
memcpy(buf, relay.peerTag, 16);
2017-02-02 17:24:40 +01:00
memset(buf+16, 0xFF, 16);
2018-05-15 20:23:46 +02:00
NetworkPacket pkt={0};
pkt.data=buf;
pkt.length=32;
pkt.address=(NetworkAddress*)&relay.address;
pkt.port=relay.port;
2017-06-07 17:46:59 +02:00
pkt.protocol=PROTO_UDP;
udpSocket->Send(&pkt);
2017-02-02 17:24:40 +01:00
}
2018-06-04 21:37:43 +02:00
shared_ptr<Endpoint> VoIPController::GetEndpointByType(int type){
2018-05-15 20:23:46 +02:00
if(type==Endpoint::TYPE_UDP_RELAY && preferredRelay)
2017-02-02 17:24:40 +01:00
return preferredRelay;
2018-06-04 21:37:43 +02:00
for(shared_ptr<Endpoint>& e:endpoints){
if(e->type==type)
return e;
}
return NULL;
}
shared_ptr<Endpoint> VoIPController::GetEndpointByID(int64_t id){
for(shared_ptr<Endpoint>& e:endpoints){
if(e->id==id)
return e;
2017-02-02 17:24:40 +01:00
}
return NULL;
}
float VoIPController::GetOutputLevel(){
2018-06-04 21:37:43 +02:00
if(!audioOutput || !audioOutStarted){
return 0.0;
}
return audioOutput->GetLevel();
2017-02-02 17:24:40 +01:00
}
void VoIPController::SendPacketReliably(unsigned char type, unsigned char *data, size_t len, double retryInterval, double timeout){
2017-04-19 15:39:27 +02:00
LOGD("Send reliably, type=%u, len=%u, retry=%.3f, timeout=%.3f", type, unsigned(len), retryInterval, timeout);
2018-06-04 21:37:43 +02:00
QueuedPacket pkt;
2017-02-02 17:24:40 +01:00
if(data){
2018-06-04 21:37:43 +02:00
Buffer b(len);
b.CopyFrom(data, 0, len);
pkt={move(b)};
}
pkt.type=type;
pkt.retryInterval=retryInterval;
pkt.timeout=timeout;
pkt.firstSentTime=0;
pkt.lastSentTime=0;
2018-05-15 20:23:46 +02:00
MutexGuard m(queuedPacketsMutex);
2018-06-04 21:37:43 +02:00
queuedPackets.push_back(move(pkt));
}
void VoIPController::SendExtra(Buffer &data, unsigned char type){
MutexGuard m(queuedPacketsMutex);
LOGV("Sending extra type %u length %lu", type, data.Length());
for(vector<UnacknowledgedExtraData>::iterator x=currentExtras.begin();x!=currentExtras.end();++x){
if(x->type==type){
x->firstContainingSeq=0;
x->data=move(data);
return;
}
}
UnacknowledgedExtraData xd={type, move(data), 0};
currentExtras.push_back(move(xd));
2017-02-02 17:24:40 +01:00
}
2018-06-04 21:59:58 +02:00
void VoIPController::SetConfig(const Config& cfg){
2018-06-04 21:37:43 +02:00
config=cfg;
2017-03-30 16:06:59 +02:00
if(tgvoipLogFile){
fclose(tgvoipLogFile);
2018-05-15 20:23:46 +02:00
tgvoipLogFile=NULL;
2017-03-30 16:06:59 +02:00
}
2018-06-04 21:37:43 +02:00
if(!config.logFilePath.empty()){
tgvoipLogFile=fopen(config.logFilePath.c_str(), "a");
2018-05-15 20:23:46 +02:00
tgvoip_log_file_write_header(tgvoipLogFile);
}else{
tgvoipLogFile=NULL;
}
2018-05-15 20:23:46 +02:00
if(statsDump){
fclose(statsDump);
2018-05-15 20:23:46 +02:00
statsDump=NULL;
}
2018-06-04 21:37:43 +02:00
if(!config.statsDumpFilePath.empty()){
statsDump=fopen(config.statsDumpFilePath.c_str(), "w");
if(statsDump)
fprintf(statsDump, "Time\tRTT\tLRSeq\tLSSeq\tLASeq\tLostR\tLostS\tCWnd\tBitrate\tLoss%%\tJitter\tJDelay\tAJDelay\n");
else
2018-06-04 21:37:43 +02:00
LOGW("Failed to open stats dump file %s for writing", config.statsDumpFilePath.c_str());
2018-05-15 20:23:46 +02:00
}else{
statsDump=NULL;
}
2017-02-02 17:24:40 +01:00
UpdateDataSavingState();
UpdateAudioBitrate();
}
void VoIPController::UpdateDataSavingState(){
2018-06-04 21:37:43 +02:00
if(config.dataSaving==DATA_SAVING_ALWAYS){
2017-02-02 17:24:40 +01:00
dataSavingMode=true;
2018-06-04 21:37:43 +02:00
}else if(config.dataSaving==DATA_SAVING_MOBILE){
2017-02-02 17:24:40 +01:00
dataSavingMode=networkType==NET_TYPE_GPRS || networkType==NET_TYPE_EDGE ||
networkType==NET_TYPE_3G || networkType==NET_TYPE_HSPA || networkType==NET_TYPE_LTE || networkType==NET_TYPE_OTHER_MOBILE;
}else{
dataSavingMode=false;
}
2018-06-04 21:37:43 +02:00
LOGI("update data saving mode, config %d, enabled %d, reqd by peer %d", config.dataSaving, dataSavingMode, dataSavingRequestedByPeer);
2017-02-02 17:24:40 +01:00
}
void VoIPController::DebugCtl(int request, int param){
2017-02-02 17:24:40 +01:00
if(request==1){ // set bitrate
maxBitrate=param;
if(encoder){
encoder->SetBitrate(maxBitrate);
}
}else if(request==2){ // set packet loss
if(encoder){
encoder->SetPacketLoss(param);
}
}else if(request==3){ // force enable/disable p2p
allowP2p=param==1;
2018-05-15 20:23:46 +02:00
if(!allowP2p && currentEndpoint && currentEndpoint->type!=Endpoint::TYPE_UDP_RELAY){
2017-02-02 17:24:40 +01:00
currentEndpoint=preferredRelay;
}else if(allowP2p){
SendPublicEndpointsRequest();
}
BufferOutputStream s(4);
2017-02-02 17:24:40 +01:00
s.WriteInt32(dataSavingMode ? INIT_FLAG_DATA_SAVING_ENABLED : 0);
SendPacketReliably(PKT_NETWORK_CHANGED, s.GetBuffer(), s.GetLength(), 1, 20);
}else if(request==4){
if(echoCanceller)
echoCanceller->Enable(param==1);
}
}
const char* VoIPController::GetVersion(){
2017-02-02 17:24:40 +01:00
return LIBTGVOIP_VERSION;
}
int64_t VoIPController::GetPreferredRelayID(){
2017-02-02 17:24:40 +01:00
if(preferredRelay)
return preferredRelay->id;
return 0;
}
int VoIPController::GetLastError(){
2017-02-02 17:24:40 +01:00
return lastError;
}
2018-06-04 21:37:43 +02:00
void VoIPController::GetStats(TrafficStats *stats){
memcpy(stats, &this->stats, sizeof(TrafficStats));
2017-02-02 17:24:40 +01:00
}
2017-03-30 16:06:59 +02:00
#ifdef TGVOIP_USE_AUDIO_SESSION
void VoIPController::SetAcquireAudioSession(void (^completion)(void (^)())) {
2018-06-04 21:37:43 +02:00
this->acquireAudioSession = [completion copy];
2017-03-30 16:06:59 +02:00
}
void VoIPController::ReleaseAudioSession(void (^completion)()) {
2018-06-04 21:37:43 +02:00
completion();
2017-03-30 16:06:59 +02:00
}
#endif
void VoIPController::LogDebugInfo(){
2018-06-04 21:37:43 +02:00
string json="{\"endpoints\":[";
for(vector<shared_ptr<Endpoint>>::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){
shared_ptr<Endpoint> e=*itr;
2017-03-30 16:06:59 +02:00
char buffer[1024];
const char* typeStr="unknown";
switch(e->type){
2018-05-15 20:23:46 +02:00
case Endpoint::TYPE_UDP_RELAY:
2017-03-30 16:06:59 +02:00
typeStr="udp_relay";
break;
2018-05-15 20:23:46 +02:00
case Endpoint::TYPE_UDP_P2P_INET:
2017-03-30 16:06:59 +02:00
typeStr="udp_p2p_inet";
break;
2018-05-15 20:23:46 +02:00
case Endpoint::TYPE_UDP_P2P_LAN:
2017-03-30 16:06:59 +02:00
typeStr="udp_p2p_lan";
break;
2018-05-15 20:23:46 +02:00
case Endpoint::TYPE_TCP_RELAY:
typeStr="tcp_relay";
break;
2017-03-30 16:06:59 +02:00
}
2018-06-04 21:37:43 +02:00
snprintf(buffer, 1024, "{\"address\":\"%s\",\"port\":%u,\"type\":\"%s\",\"rtt\":%u%s%s}", e->address.ToString().c_str(), e->port, typeStr, (unsigned int)round(e->averageRTT*1000), currentEndpoint==e ? ",\"in_use\":true" : "", preferredRelay==e ? ",\"preferred\":true" : "");
2017-03-30 16:06:59 +02:00
json+=buffer;
if(itr!=endpoints.end()-1)
2017-03-30 16:06:59 +02:00
json+=",";
}
json+="],";
char buffer[1024];
const char* netTypeStr;
switch(networkType){
case NET_TYPE_WIFI:
netTypeStr="wifi";
break;
case NET_TYPE_GPRS:
netTypeStr="gprs";
break;
case NET_TYPE_EDGE:
netTypeStr="edge";
break;
case NET_TYPE_3G:
netTypeStr="3g";
break;
case NET_TYPE_HSPA:
netTypeStr="hspa";
break;
case NET_TYPE_LTE:
netTypeStr="lte";
break;
case NET_TYPE_ETHERNET:
netTypeStr="ethernet";
break;
case NET_TYPE_OTHER_HIGH_SPEED:
netTypeStr="other_high_speed";
break;
case NET_TYPE_OTHER_LOW_SPEED:
netTypeStr="other_low_speed";
break;
case NET_TYPE_DIALUP:
netTypeStr="dialup";
break;
case NET_TYPE_OTHER_MOBILE:
netTypeStr="other_mobile";
break;
default:
netTypeStr="unknown";
break;
}
snprintf(buffer, 1024, "\"time\":%u,\"network_type\":\"%s\"}", (unsigned int)time(NULL), netTypeStr);
json+=buffer;
debugLogs.push_back(json);
}
2018-06-04 21:37:43 +02:00
string VoIPController::GetDebugLog(){
string log="{\"events\":[";
2017-03-30 16:06:59 +02:00
2018-06-04 21:37:43 +02:00
for(vector<string>::iterator itr=debugLogs.begin();itr!=debugLogs.end();++itr){
2017-03-30 16:06:59 +02:00
log+=(*itr);
if((itr+1)!=debugLogs.end())
2017-03-30 16:06:59 +02:00
log+=",";
}
log+="],\"libtgvoip_version\":\"" LIBTGVOIP_VERSION "\"}";
return log;
}
void VoIPController::GetDebugLog(char *buffer){
2017-03-30 16:06:59 +02:00
strcpy(buffer, GetDebugLog().c_str());
}
size_t VoIPController::GetDebugLogLength(){
2017-03-30 16:06:59 +02:00
size_t len=128;
2018-06-04 21:37:43 +02:00
for(vector<string>::iterator itr=debugLogs.begin();itr!=debugLogs.end();++itr){
2017-03-30 16:06:59 +02:00
len+=(*itr).length()+1;
}
return len;
}
2018-06-04 21:37:43 +02:00
vector<AudioInputDevice> VoIPController::EnumerateAudioInputs(){
vector<AudioInputDevice> devs;
audio::AudioInput::EnumerateDevices(devs);
return devs;
}
2018-06-04 21:37:43 +02:00
vector<AudioOutputDevice> VoIPController::EnumerateAudioOutputs(){
vector<AudioOutputDevice> devs;
audio::AudioOutput::EnumerateDevices(devs);
return devs;
}
2018-06-04 21:37:43 +02:00
void VoIPController::SetCurrentAudioInput(string id){
currentAudioInput=id;
if(audioInput)
audioInput->SetCurrentDevice(id);
}
2018-06-04 21:37:43 +02:00
void VoIPController::SetCurrentAudioOutput(string id){
currentAudioOutput=id;
if(audioOutput)
audioOutput->SetCurrentDevice(id);
}
2018-06-04 21:37:43 +02:00
string VoIPController::GetCurrentAudioInputID(){
return currentAudioInput;
}
2018-06-04 21:37:43 +02:00
string VoIPController::GetCurrentAudioOutputID(){
return currentAudioOutput;
}
2018-06-04 21:37:43 +02:00
void VoIPController::SetProxy(int protocol, string address, uint16_t port, string username, string password){
proxyProtocol=protocol;
proxyAddress=address;
proxyPort=port;
proxyUsername=username;
proxyPassword=password;
}
2018-06-04 21:37:43 +02:00
void VoIPController::SendUdpPing(shared_ptr<Endpoint> endpoint){
2018-05-15 20:23:46 +02:00
if(endpoint->type!=Endpoint::TYPE_UDP_RELAY)
return;
2018-06-04 21:37:43 +02:00
LOGV("Sending UDP ping to %s:%d", endpoint->GetAddress().ToString().c_str(), endpoint->port);
BufferOutputStream p(1024);
p.WriteBytes(endpoint->peerTag, 16);
p.WriteInt32(-1);
p.WriteInt32(-1);
p.WriteInt32(-1);
p.WriteInt32(-2);
p.WriteInt64(12345);
2018-05-15 20:23:46 +02:00
NetworkPacket pkt={0};
2018-06-04 21:37:43 +02:00
pkt.address=&endpoint->GetAddress();
pkt.port=endpoint->port;
pkt.protocol=PROTO_UDP;
pkt.data=p.GetBuffer();
pkt.length=p.GetLength();
udpSocket->Send(&pkt);
}
2018-05-15 20:23:46 +02:00
void VoIPController::SendRelayPings(){
//LOGV("Send relay pings 1");
if((state==STATE_ESTABLISHED || state==STATE_RECONNECTING) && endpoints.size()>1){
2018-06-04 21:37:43 +02:00
shared_ptr<Endpoint> minPingRelay=preferredRelay;
2018-05-15 20:23:46 +02:00
double minPing=preferredRelay->averageRTT*(preferredRelay->type==Endpoint::TYPE_TCP_RELAY ? 2 : 1);
2018-06-04 21:37:43 +02:00
for(shared_ptr<Endpoint>& endpoint:endpoints){
2018-05-15 20:23:46 +02:00
if(endpoint->type==Endpoint::TYPE_TCP_RELAY && !useTCP)
continue;
if(GetCurrentTime()-endpoint->lastPingTime>=10){
2018-06-04 21:37:43 +02:00
LOGV("Sending ping to %s", endpoint->GetAddress().ToString().c_str());
2018-05-15 20:23:46 +02:00
unsigned char* buf=outgoingPacketsBufferPool.Get();
if(buf){
sendQueue->Put(PendingOutgoingPacket{
/*.seq=*/(endpoint->lastPingSeq=GenerateOutSeq()),
/*.type=*/PKT_PING,
/*.len=*/0,
/*.data=*/buf,
2018-06-04 21:37:43 +02:00
/*.endpoint=*/endpoint->id
2018-05-15 20:23:46 +02:00
});
}
endpoint->lastPingTime=GetCurrentTime();
}
if(endpoint->type==Endpoint::TYPE_UDP_RELAY || (useTCP && endpoint->type==Endpoint::TYPE_TCP_RELAY)){
double k=endpoint->type==Endpoint::TYPE_UDP_RELAY ? 1 : 2;
if(endpoint->averageRTT>0 && endpoint->averageRTT*k<minPing*relaySwitchThreshold){
minPing=endpoint->averageRTT*k;
minPingRelay=endpoint;
}
}
}
if(minPingRelay!=preferredRelay){
preferredRelay=minPingRelay;
LOGV("set preferred relay to %s", preferredRelay->address.ToString().c_str());
if(currentEndpoint->type==Endpoint::TYPE_UDP_RELAY || currentEndpoint->type==Endpoint::TYPE_TCP_RELAY)
currentEndpoint=preferredRelay;
LogDebugInfo();
}
if(currentEndpoint->type==Endpoint::TYPE_UDP_RELAY){
2018-06-04 21:37:43 +02:00
shared_ptr<Endpoint> p2p=GetEndpointByType(Endpoint::TYPE_UDP_P2P_INET);
2018-05-15 20:23:46 +02:00
if(p2p){
2018-06-04 21:37:43 +02:00
shared_ptr<Endpoint> lan=GetEndpointByType(Endpoint::TYPE_UDP_P2P_LAN);
2018-05-15 20:23:46 +02:00
if(lan && lan->averageRTT>0 && lan->averageRTT<minPing*relayToP2pSwitchThreshold){
currentEndpoint=lan;
LOGI("Switching to p2p (LAN)");
LogDebugInfo();
}else{
if(p2p->averageRTT>0 && p2p->averageRTT<minPing*relayToP2pSwitchThreshold){
currentEndpoint=p2p;
LOGI("Switching to p2p (Inet)");
LogDebugInfo();
}
}
}
}else{
if(minPing>0 && minPing<currentEndpoint->averageRTT*p2pToRelaySwitchThreshold){
LOGI("Switching to relay");
currentEndpoint=preferredRelay;
LogDebugInfo();
}
}
}
}
void VoIPController::StartAudio(){
2018-06-04 21:37:43 +02:00
shared_ptr<Stream>& outgoingAudioStream=outgoingStreams[0];
2018-05-15 20:23:46 +02:00
LOGI("before create audio io");
void* platformSpecific=NULL;
#ifdef __APPLE__
platformSpecific=appleAudioIO;
#endif
audioInput=tgvoip::audio::AudioInput::Create(currentAudioInput, platformSpecific);
audioInput->Configure(48000, 16, 1);
audioOutput=tgvoip::audio::AudioOutput::Create(currentAudioOutput, platformSpecific);
audioOutput->Configure(48000, 16, 1);
2018-06-04 21:37:43 +02:00
LOGI("AEC: %d NS: %d AGC: %d", config.enableAEC, config.enableNS, config.enableAGC);
2018-05-15 20:23:46 +02:00
echoCanceller=new EchoCanceller(config.enableAEC, config.enableNS, config.enableAGC);
2018-06-04 21:37:43 +02:00
encoder=new OpusEncoder(audioInput, peerVersion>=6);
2018-05-15 20:23:46 +02:00
encoder->SetCallback(AudioInputCallback, this);
2018-06-04 21:37:43 +02:00
encoder->SetOutputFrameDuration(outgoingAudioStream->frameDuration);
2018-05-15 20:23:46 +02:00
encoder->SetEchoCanceller(echoCanceller);
2018-06-04 21:37:43 +02:00
encoder->SetSecondaryEncoderEnabled(false);
2018-05-15 20:23:46 +02:00
encoder->Start();
if(!micMuted){
audioInput->Start();
if(!audioInput->IsInitialized()){
LOGE("Erorr initializing audio capture");
lastError=ERROR_AUDIO_IO;
SetState(STATE_FAILED);
return;
}
}
if(!audioOutput->IsInitialized()){
LOGE("Erorr initializing audio playback");
lastError=ERROR_AUDIO_IO;
SetState(STATE_FAILED);
return;
}
UpdateAudioBitrate();
/*voip_stream_t* incomingAudioStream=incomingStreams[0];
jitterBuffer=new JitterBuffer(NULL, incomingAudioStream->frameDuration);
decoder=new OpusDecoder(audioOutput);
decoder->SetEchoCanceller(echoCanceller);
decoder->SetJitterBuffer(jitterBuffer);
decoder->SetFrameDuration(incomingAudioStream->frameDuration);
decoder->Start();
if(incomingAudioStream->frameDuration>50)
jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_60", 3));
else if(incomingAudioStream->frameDuration>30)
jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_40", 4));
else
jitterBuffer->SetMinPacketCount((uint32_t) ServerConfig::GetSharedInstance()->GetInt("jitter_initial_delay_20", 6));*/
//audioOutput->Start();
OnAudioOutputReady();
}
void VoIPController::OnAudioOutputReady(){
2018-06-04 21:37:43 +02:00
shared_ptr<Stream>& stm=incomingStreams[0];
2018-05-15 20:23:46 +02:00
outputAGC=new AutomaticGainControl();
outputAGC->SetPassThrough(!outputAGCEnabled);
2018-06-04 21:37:43 +02:00
stm->decoder=make_shared<OpusDecoder>((unique_ptr<MediaStreamItf>&)audioOutput, true, peerVersion>=6);
stm->decoder->AddAudioEffect(outputAGC);
stm->decoder->SetEchoCanceller(echoCanceller);
stm->decoder->SetJitterBuffer(stm->jitterBuffer);
stm->decoder->SetFrameDuration(stm->frameDuration);
stm->decoder->Start();
2018-05-15 20:23:46 +02:00
}
2017-08-21 18:02:37 +02:00
int VoIPController::GetSignalBarsCount(){
unsigned char avg=0;
2018-05-15 20:23:46 +02:00
for(unsigned int i=0;i<sizeof(signalBarsHistory);i++)
avg+=signalBarsHistory[i];
return avg >> 2;
2017-08-21 18:02:37 +02:00
}
2018-05-15 20:23:46 +02:00
void VoIPController::SetCallbacks(VoIPController::Callbacks callbacks){
this->callbacks=callbacks;
if(callbacks.connectionStateChanged)
callbacks.connectionStateChanged(this, state);
2017-08-21 18:02:37 +02:00
}
void VoIPController::SetAudioOutputGainControlEnabled(bool enabled){
LOGD("New output AGC state: %d", enabled);
outputAGCEnabled=enabled;
if(outputAGC)
outputAGC->SetPassThrough(!enabled);
}
2018-05-15 20:23:46 +02:00
uint32_t VoIPController::GetPeerCapabilities(){
return peerCapabilities;
}
void VoIPController::SendGroupCallKey(unsigned char *key){
if(!(peerCapabilities & TGVOIP_PEER_CAP_GROUP_CALLS)){
LOGE("Tried to send group call key but peer isn't capable of them");
return;
}
if(didSendGroupCallKey){
LOGE("Tried to send a group call key repeatedly");
return;
}
if(!isOutgoing){
LOGE("You aren't supposed to send group call key in an incoming call, use VoIPController::RequestCallUpgrade() instead");
return;
}
didSendGroupCallKey=true;
2018-06-04 21:37:43 +02:00
Buffer buf(256);
buf.CopyFrom(key, 0, 256);
SendExtra(buf, EXTRA_TYPE_GROUP_CALL_KEY);
2018-05-15 20:23:46 +02:00
}
void VoIPController::RequestCallUpgrade(){
if(!(peerCapabilities & TGVOIP_PEER_CAP_GROUP_CALLS)){
LOGE("Tried to send group call key but peer isn't capable of them");
return;
}
if(didSendUpgradeRequest){
LOGE("Tried to send upgrade request repeatedly");
return;
}
if(isOutgoing){
LOGE("You aren't supposed to send an upgrade request in an outgoing call, generate an encryption key and use VoIPController::SendGroupCallKey instead");
return;
}
didSendUpgradeRequest=true;
2018-06-04 21:37:43 +02:00
Buffer empty(0);
SendExtra(empty, EXTRA_TYPE_REQUEST_GROUP);
2018-05-15 20:23:46 +02:00
}
2017-12-27 18:25:47 +01:00
void VoIPController::SetEchoCancellationStrength(int strength){
echoCancellationStrength=strength;
if(echoCanceller)
echoCanceller->SetAECStrength(strength);
}
Endpoint::Endpoint(int64_t id, uint16_t port, IPv4Address& _address, IPv6Address& _v6address, char type, unsigned char peerTag[16]) : address(_address), v6address(_v6address){
this->id=id;
this->port=port;
this->type=type;
memcpy(this->peerTag, peerTag, 16);
2018-05-15 20:23:46 +02:00
if(type==TYPE_UDP_RELAY && ServerConfig::GetSharedInstance()->GetBoolean("force_tcp", false))
this->type=TYPE_TCP_RELAY;
lastPingSeq=0;
lastPingTime=0;
averageRTT=0;
memset(rtts, 0, sizeof(rtts));
socket=NULL;
2018-05-15 20:23:46 +02:00
udpPongCount=0;
}
2017-03-30 16:06:59 +02:00
2018-06-04 21:37:43 +02:00
Endpoint::Endpoint() : address(0), v6address(string("::0")) {
lastPingSeq=0;
lastPingTime=0;
averageRTT=0;
memset(rtts, 0, sizeof(rtts));
socket=NULL;
2018-05-15 20:23:46 +02:00
udpPongCount=0;
}
2018-06-04 21:37:43 +02:00
NetworkAddress &Endpoint::GetAddress(){
return IsIPv6Only() ? (NetworkAddress&)v6address : (NetworkAddress&)address;
}
bool Endpoint::IsIPv6Only(){
return address.IsEmpty() && !v6address.IsEmpty();
}
Endpoint::~Endpoint(){
if(socket){
socket->Close();
delete socket;
}
}