1
0
mirror of https://github.com/danog/libtgvoip.git synced 2025-01-22 13:01:21 +01:00

Detect when proxy does not support UDP and persist that across calls

This commit is contained in:
Grishka 2018-12-19 19:51:45 +03:00
parent a7546d438a
commit fed3bb73ee
3 changed files with 111 additions and 10 deletions

View File

@ -845,6 +845,46 @@ void VoIPController::SetConfig(const Config& cfg){
UpdateAudioBitrateLimit();
}
void VoIPController::SetPersistentState(vector<uint8_t> state){
using namespace json11;
if(state.empty())
return;
string jsonErr;
string json=string(state.begin(), state.end());
Json _obj=Json::parse(json, jsonErr);
if(!jsonErr.empty()){
LOGE("Error parsing persistable state: %s", jsonErr.c_str());
return;
}
Json::object obj=_obj.object_items();
if(obj.find("proxy")!=obj.end()){
Json::object proxy=obj["proxy"].object_items();
lastTestedProxyServer=proxy["server"].string_value();
proxySupportsUDP=proxy["udp"].bool_value();
proxySupportsTCP=proxy["tcp"].bool_value();
}
}
vector<uint8_t> VoIPController::GetPersistentState(){
using namespace json11;
Json::object obj=Json::object{
{"ver", 1},
};
if(proxyProtocol==PROXY_SOCKS5){
char pbuf[128];
snprintf(pbuf, sizeof(pbuf), "%s:%u", proxyAddress.c_str(), proxyPort);
obj.insert({"proxy", Json::object{
{"server", string(pbuf)},
{"udp", proxySupportsUDP},
{"tcp", proxySupportsTCP}
}});
}
const char* jstr=Json(obj).dump().c_str();
return vector<uint8_t>(jstr, jstr+strlen(jstr));
}
#pragma mark - Internal intialization
void VoIPController::InitializeTimers(){
@ -877,8 +917,6 @@ void VoIPController::InitializeTimers(){
}, 0.1, 0.1);
}
udpConnectivityState=UDP_PING_PENDING;
udpPingTimeoutID=messageThread.Post(std::bind(&VoIPController::SendUdpPings, this), 0.0, 0.5);
messageThread.Post(std::bind(&VoIPController::SendRelayPings, this), 0.0, 2.0);
}
@ -1373,6 +1411,14 @@ void VoIPController::InitUDPProxy(){
delete udpSocket;
udpSocket=realUdpSocket;
}
char sbuf[128];
snprintf(sbuf, sizeof(sbuf), "%s:%u", proxyAddress.c_str(), proxyPort);
string proxyHostPort(sbuf);
if(proxyHostPort==lastTestedProxyServer && !proxySupportsUDP){
LOGI("Proxy does not support UDP - using UDP directly instead");
return;
}
NetworkSocket* tcp=NetworkSocket::Create(PROTO_TCP);
tcp->Connect(resolvedProxyAddress, proxyPort);
@ -1410,12 +1456,11 @@ void VoIPController::InitUDPProxy(){
if(udpProxy->IsFailed()){
udpProxy->Close();
delete udpProxy;
useTCP=true;
useUDP=false;
udpConnectivityState=UDP_NOT_AVAILABLE;
proxySupportsUDP=false;
}else{
udpSocket=udpProxy;
}
ResetUdpAvailability();
}
void VoIPController::RunRecvThread(){
@ -1429,6 +1474,9 @@ void VoIPController::RunRecvThread(){
SetState(STATE_FAILED);
return;
}
}else{
udpConnectivityState=UDP_PING_PENDING;
udpPingTimeoutID=messageThread.Post(std::bind(&VoIPController::SendUdpPings, this), 0.0, 0.5);
}
while(runReceiver){
@ -3144,6 +3192,17 @@ void VoIPController::EvaluateUdpPingResults(){
else
avgPongs=0.0;
LOGI("UDP ping reply count: %.2f", avgPongs);
if(avgPongs==0.0 && proxyProtocol==PROXY_SOCKS5 && udpSocket!=realUdpSocket){
LOGI("Proxy does not let UDP through, closing proxy connection and using UDP directly");
NetworkSocket* proxySocket=udpSocket;
proxySocket->Close();
udpSocket=realUdpSocket;
selectCanceller->CancelSelect();
delete proxySocket;
proxySupportsUDP=false;
ResetUdpAvailability();
return;
}
bool configUseTCP=ServerConfig::GetSharedInstance()->GetBoolean("use_tcp", true);
if(configUseTCP){
if(avgPongs==0.0 || (udpConnectivityState==UDP_BAD && avgPongs<7.0)){

View File

@ -369,6 +369,15 @@ namespace tgvoip{
static int32_t GetConnectionMaxLayer(){
return 92;
};
/**
* Get the persistable state of the library, like proxy capabilities, to save somewhere on the disk. Call this at the end of the call.
* Using this will speed up the connection establishment in some cases.
*/
std::vector<uint8_t> GetPersistentState();
/**
* Load the persistable state. Call this before starting the call.
*/
void SetPersistentState(std::vector<uint8_t> state);
#if defined(TGVOIP_USE_CALLBACK_AUDIO_IO)
void SetAudioDataCallbacks(std::function<void(int16_t*, size_t)> input, std::function<void(int16_t*, size_t)> output);
@ -692,10 +701,15 @@ namespace tgvoip{
std::function<void(int16_t*, size_t)> audioInputDataCallback;
std::function<void(int16_t*, size_t)> audioOutputDataCallback;
#endif
video::VideoSource* videoSource=NULL;
video::VideoRenderer* videoRenderer=NULL;
double firstVideoFrameTime=0.0;
/*** persistable state values ***/
bool proxySupportsUDP=true;
bool proxySupportsTCP=true;
std::string lastTestedProxyServer="";
/*** server config values ***/
uint32_t maxAudioBitrate;

View File

@ -38,6 +38,7 @@ jclass jniUtilitiesClass=NULL;
struct ImplDataAndroid{
jobject javaObject;
std::string persistentStateFile="";
};
#ifndef TGVOIP_PACKAGE_PATH
@ -115,9 +116,12 @@ namespace tgvoip {
#pragma mark - VoIPController
jlong VoIPController_nativeInit(JNIEnv* env, jobject thiz) {
ImplDataAndroid* impl=(ImplDataAndroid*) malloc(sizeof(ImplDataAndroid));
jlong VoIPController_nativeInit(JNIEnv* env, jobject thiz, jstring persistentStateFile) {
ImplDataAndroid* impl=new ImplDataAndroid();
impl->javaObject=env->NewGlobalRef(thiz);
if(persistentStateFile){
impl->persistentStateFile=jni::JavaStringToStdString(env, persistentStateFile);
}
VoIPController* cntrlr=new VoIPController();
cntrlr->implData=impl;
VoIPController::Callbacks callbacks;
@ -127,6 +131,22 @@ namespace tgvoip {
callbacks.groupCallKeySent=groupCallKeySent;
callbacks.upgradeToGroupCallRequested=callUpgradeRequestReceived;
cntrlr->SetCallbacks(callbacks);
if(!impl->persistentStateFile.empty()){
FILE* f=fopen(impl->persistentStateFile.c_str(), "r");
if(f){
fseek(f, 0, SEEK_END);
size_t len=static_cast<size_t>(ftell(f));
fseek(f, 0, SEEK_SET);
if(len<1024*512 && len>0){
char *fbuf=static_cast<char *>(malloc(len));
fread(fbuf, 1, len, f);
std::vector<uint8_t> state(fbuf, fbuf+len);
free(fbuf);
cntrlr->SetPersistentState(state);
}
fclose(f);
}
}
return (jlong)(intptr_t)cntrlr;
}
@ -196,9 +216,17 @@ namespace tgvoip {
VoIPController* ctlr=((VoIPController*)(intptr_t)inst);
ImplDataAndroid* impl=(ImplDataAndroid*)ctlr->implData;
ctlr->Stop();
std::vector<uint8_t> state=ctlr->GetPersistentState();
delete ctlr;
env->DeleteGlobalRef(impl->javaObject);
free(impl);
if(!impl->persistentStateFile.empty()){
FILE* f=fopen(impl->persistentStateFile.c_str(), "w");
if(f){
fwrite(state.data(), 1, state.size(), f);
fclose(f);
}
}
delete impl;
}
jstring VoIPController_nativeGetDebugString(JNIEnv* env, jobject thiz, jlong inst){
@ -520,7 +548,7 @@ extern "C" void tgvoipRegisterNatives(JNIEnv* env){
// VoIPController
JNINativeMethod controllerMethods[]={
{"nativeInit", "()J", (void*)&tgvoip::VoIPController_nativeInit},
{"nativeInit", "(Ljava/lang/String;)J", (void*)&tgvoip::VoIPController_nativeInit},
{"nativeStart", "(J)V", (void*)&tgvoip::VoIPController_nativeStart},
{"nativeConnect", "(J)V", (void*)&tgvoip::VoIPController_nativeConnect},
{"nativeSetProxy", "(JLjava/lang/String;ILjava/lang/String;Ljava/lang/String;)V", (void*)&tgvoip::VoIPController_nativeSetProxy},