Added TCP fallback

Support for Windows Phone Silverlight
Various fixes
This commit is contained in:
Grishka 2017-06-06 04:44:16 +03:00
parent 6883bbf5d6
commit cd8d78b366
18 changed files with 728 additions and 227 deletions

View File

@ -4,6 +4,7 @@
#include "NetworkSocket.h"
#include <stdexcept>
#include <algorithm>
#include <stdlib.h>
#include <string.h>
#if defined(_WIN32)
@ -13,130 +14,162 @@
#endif
#include "logging.h"
#include "VoIPServerConfig.h"
#include "VoIPController.h"
#define MIN_UDP_PORT 16384
#define MAX_UDP_PORT 32768
namespace tgvoip {
using namespace tgvoip;
#pragma mark - NetworkSocket
NetworkSocket::NetworkSocket(){
ipv6Timeout=ServerConfig::GetSharedInstance()->GetDouble("nat64_fallback_timeout", 3);
failed=false;
}
NetworkSocket::NetworkSocket(){
ipv6Timeout=ServerConfig::GetSharedInstance()->GetDouble("nat64_fallback_timeout", 3);
failed=false;
}
NetworkSocket::~NetworkSocket(){
}
std::string NetworkSocket::GetLocalInterfaceInfo(IPv4Address *inet4addr, IPv6Address *inet6addr){
std::string r="not implemented";
return r;
}
uint16_t NetworkSocket::GenerateLocalPort(){
return (uint16_t) ((rand()%(MAX_UDP_PORT-MIN_UDP_PORT))+MIN_UDP_PORT);
}
void NetworkSocket::SetMaxPriority(){
}
bool NetworkSocket::IsFailed(){
return failed;
}
NetworkSocket *NetworkSocket::Create(){
#ifndef _WIN32
return new NetworkSocketPosix();
#else
return new NetworkSocketWinsock();
#endif
}
#pragma mark - NetworkAddress
bool NetworkAddress::operator==(const NetworkAddress &other){
IPv4Address* self4=dynamic_cast<IPv4Address*>(this);
IPv4Address* other4=dynamic_cast<IPv4Address*>((NetworkAddress*)&other);
if(self4 && other4){
return self4->GetAddress()==other4->GetAddress();
}
IPv6Address* self6=dynamic_cast<IPv6Address*>(this);
IPv6Address* other6=dynamic_cast<IPv6Address*>((NetworkAddress*)&other);
if(self6 && other6){
return memcmp(self6->GetAddress(), other6->GetAddress(), 16)==0;
}
return false;
}
bool NetworkAddress::operator!=(const NetworkAddress &other){
return !(*this == other);
}
#pragma mark - IPv4Address
IPv4Address::IPv4Address(std::string addr){
#ifndef _WIN32
this->address=NetworkSocketPosix::StringToV4Address(addr);
#else
this->address=NetworkSocketWinsock::StringToV4Address(addr);
#endif
}
IPv4Address::IPv4Address(uint32_t addr){
this->address=addr;
}
std::string IPv4Address::ToString(){
#ifndef _WIN32
return NetworkSocketPosix::V4AddressToString(address);
#else
return NetworkSocketWinsock::V4AddressToString(address);
#endif
}
/*sockaddr &IPv4Address::ToSockAddr(uint16_t port){
sockaddr_in sa;
sa.sin_family=AF_INET;
sa.sin_addr=addr;
sa.sin_port=port;
return *((sockaddr *) &sa);
}*/
uint32_t IPv4Address::GetAddress(){
return address;
}
#pragma mark - IPv6Address
IPv6Address::IPv6Address(std::string addr){
#ifndef _WIN32
NetworkSocketPosix::StringToV6Address(addr, this->address);
#else
NetworkSocketWinsock::StringToV6Address(addr, this->address);
#endif
}
IPv6Address::IPv6Address(uint8_t addr[16]){
memcpy(address, addr, 16);
}
std::string IPv6Address::ToString(){
return "";
}
/*sockaddr &IPv6Address::ToSockAddr(uint16_t port){
sockaddr_in6 sa;
sa.sin6_family=AF_INET6;
sa.sin6_addr=addr;
sa.sin6_port=port;
return *((sockaddr *) &sa);
}*/
const uint8_t *IPv6Address::GetAddress(){
return address;
}
NetworkSocket::~NetworkSocket(){
}
std::string NetworkSocket::GetLocalInterfaceInfo(IPv4Address *inet4addr, IPv6Address *inet6addr){
std::string r="not implemented";
return r;
}
uint16_t NetworkSocket::GenerateLocalPort(){
return (uint16_t) ((rand()%(MAX_UDP_PORT-MIN_UDP_PORT))+MIN_UDP_PORT);
}
void NetworkSocket::SetMaxPriority(){
}
bool NetworkSocket::IsFailed(){
return failed;
}
NetworkSocket *NetworkSocket::Create(){
#ifndef _WIN32
return new NetworkSocketPosix();
#else
return new NetworkSocketWinsock();
#endif
}
void NetworkSocket::GenerateTCPO2States(unsigned char* buffer, TCPO2State* recvState, TCPO2State* sendState){
memset(recvState, 0, sizeof(TCPO2State));
memset(sendState, 0, sizeof(TCPO2State));
unsigned char nonce[64];
uint32_t *first = reinterpret_cast<uint32_t*>(nonce), *second = first + 1;
uint32_t first1 = 0x44414548U, first2 = 0x54534f50U, first3 = 0x20544547U, first4 = 0x20544547U, first5 = 0xeeeeeeeeU;
uint32_t second1 = 0;
do {
VoIPController::crypto.rand_bytes(nonce, sizeof(nonce));
} while (*first == first1 || *first == first2 || *first == first3 || *first == first4 || *first == first5 || *second == second1 || *reinterpret_cast<unsigned char*>(nonce) == 0xef);
// prepare encryption key/iv
memcpy(sendState->key, nonce + 8, 32);
memcpy(sendState->iv, nonce + 8 + 32, 16);
// prepare decryption key/iv
char reversed[48];
memcpy(reversed, nonce + 8, sizeof(reversed));
std::reverse(reversed, reversed + sizeof(reversed));
memcpy(recvState->key, reversed, 32);
memcpy(recvState->iv, reversed + 32, 16);
// write protocol identifier
*reinterpret_cast<uint32_t*>(nonce + 56) = 0xefefefefU;
memcpy(buffer, nonce, 56);
EncryptForTCPO2(nonce, sizeof(nonce), sendState);
memcpy(buffer+56, nonce+56, 8);
}
void NetworkSocket::EncryptForTCPO2(unsigned char *buffer, size_t len, TCPO2State *state){
VoIPController::crypto.aes_ctr_encrypt(buffer, len, state->key, state->iv, state->ecount, &state->num);
}
bool NetworkAddress::operator==(const NetworkAddress &other){
IPv4Address* self4=dynamic_cast<IPv4Address*>(this);
IPv4Address* other4=dynamic_cast<IPv4Address*>((NetworkAddress*)&other);
if(self4 && other4){
return self4->GetAddress()==other4->GetAddress();
}
IPv6Address* self6=dynamic_cast<IPv6Address*>(this);
IPv6Address* other6=dynamic_cast<IPv6Address*>((NetworkAddress*)&other);
if(self6 && other6){
return memcmp(self6->GetAddress(), other6->GetAddress(), 16)==0;
}
return false;
}
bool NetworkAddress::operator!=(const NetworkAddress &other){
return !(*this == other);
}
IPv4Address::IPv4Address(std::string addr){
#ifndef _WIN32
this->address=NetworkSocketPosix::StringToV4Address(addr);
#else
this->address=NetworkSocketWinsock::StringToV4Address(addr);
#endif
}
IPv4Address::IPv4Address(uint32_t addr){
this->address=addr;
}
IPv4Address::IPv4Address(){
this->address=0;
}
std::string IPv4Address::ToString(){
#ifndef _WIN32
return NetworkSocketPosix::V4AddressToString(address);
#else
return NetworkSocketWinsock::V4AddressToString(address);
#endif
}
/*sockaddr &IPv4Address::ToSockAddr(uint16_t port){
sockaddr_in sa;
sa.sin_family=AF_INET;
sa.sin_addr=addr;
sa.sin_port=port;
return *((sockaddr *) &sa);
}*/
uint32_t IPv4Address::GetAddress(){
return address;
}
IPv6Address::IPv6Address(std::string addr){
#ifndef _WIN32
NetworkSocketPosix::StringToV6Address(addr, this->address);
#else
NetworkSocketWinsock::StringToV6Address(addr, this->address);
#endif
}
IPv6Address::IPv6Address(uint8_t addr[16]){
memcpy(address, addr, 16);
}
IPv6Address::IPv6Address(){
memset(address, 0, 16);
}
std::string IPv6Address::ToString(){
return "";
}
/*sockaddr &IPv6Address::ToSockAddr(uint16_t port){
sockaddr_in6 sa;
sa.sin6_family=AF_INET6;
sa.sin6_addr=addr;
sa.sin6_port=port;
return *((sockaddr *) &sa);
}*/
const uint8_t *IPv6Address::GetAddress(){
return address;
}

View File

@ -9,6 +9,19 @@
#include <string>
namespace tgvoip {
enum NetworkProtocol{
PROTO_UDP=0,
PROTO_TCP
};
struct TCPO2State{
unsigned char key[32];
unsigned char iv[16];
unsigned char ecount[16];
uint32_t num;
};
class NetworkAddress{
public:
virtual std::string ToString()=0;
@ -21,6 +34,7 @@ namespace tgvoip {
public:
IPv4Address(std::string addr);
IPv4Address(uint32_t addr);
IPv4Address();
virtual std::string ToString();
//virtual sockaddr& ToSockAddr(uint16_t port);
uint32_t GetAddress();
@ -33,6 +47,7 @@ namespace tgvoip {
public:
IPv6Address(std::string addr);
IPv6Address(uint8_t addr[16]);
IPv6Address();
virtual std::string ToString();
//virtual sockaddr& ToSockAddr(uint16_t port);
const uint8_t* GetAddress();
@ -45,6 +60,7 @@ namespace tgvoip {
size_t length;
NetworkAddress* address;
uint16_t port;
NetworkProtocol protocol;
};
typedef struct NetworkPacket NetworkPacket;
@ -66,6 +82,8 @@ namespace tgvoip {
protected:
virtual uint16_t GenerateLocalPort();
virtual void SetMaxPriority();
static void GenerateTCPO2States(unsigned char* buffer, TCPO2State* recvState, TCPO2State* sendState);
static void EncryptForTCPO2(unsigned char* buffer, size_t len, TCPO2State* state);
double ipv6Timeout;
unsigned char nat64Prefix[12];
bool failed;

View File

@ -71,12 +71,19 @@ 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);
AES_ctr128_encrypt(inout, inout, length, &akey, iv, ecount, num);
}
voip_crypto_functions_t VoIPController::crypto={
tgvoip_openssl_rand_bytes,
tgvoip_openssl_sha1,
tgvoip_openssl_sha256,
tgvoip_openssl_aes_ige_encrypt,
tgvoip_openssl_aes_ige_decrypt
tgvoip_openssl_aes_ige_decrypt,
tgvoip_openssl_aes_ctr_encrypt
};
#else
@ -146,6 +153,9 @@ VoIPController::VoIPController() : activeNetItfName(""), currentAudioInput("defa
receivedInitAck=false;
peerPreferredRelay=NULL;
statsDump=NULL;
useTCP=false;
didAddTcpRelays=false;
enableTcpAt=0;
socket=NetworkSocket::Create();
@ -287,8 +297,14 @@ void VoIPController::SetRemoteEndpoints(std::vector<Endpoint> endpoints, bool al
size_t i;
lock_mutex(endpointsMutex);
this->endpoints.clear();
didAddTcpRelays=false;
useTCP=true;
for(std::vector<Endpoint>::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){
this->endpoints.push_back(new Endpoint(*itrtr));
if(itrtr->type==EP_TYPE_TCP_RELAY)
didAddTcpRelays=true;
if(itrtr->type==EP_TYPE_UDP_RELAY)
useTCP=false;
}
unlock_mutex(endpointsMutex);
currentEndpoint=this->endpoints[0];
@ -316,7 +332,7 @@ void* VoIPController::StartTickThread(void* controller){
void VoIPController::Start(){
int res;
LOGW("Starting voip controller");
int32_t cfgFrameSize=ServerConfig::GetSharedInstance()->GetInt("audio_frame_size", 60);
int32_t cfgFrameSize=60; //ServerConfig::GetSharedInstance()->GetInt("audio_frame_size", 60);
if(cfgFrameSize==20 || cfgFrameSize==40 || cfgFrameSize==60)
outgoingStreams[0]->frameDuration=(uint16_t) cfgFrameSize;
socket->Open();
@ -402,6 +418,7 @@ void VoIPController::HandleAudioInput(unsigned char *data, size_t len){
void VoIPController::Connect(){
assert(state!=STATE_WAIT_INIT_ACK);
connectionInitTime=GetCurrentTime();
enableTcpAt=connectionInitTime+5;
SendInit();
}
@ -537,6 +554,8 @@ void VoIPController::SendInit(){
out->WriteByte(0); // video codecs count
lock_mutex(endpointsMutex);
for(std::vector<Endpoint*>::iterator itr=endpoints.begin();itr!=endpoints.end();++itr){
if((*itr)->type==EP_TYPE_TCP_RELAY && !useTCP)
continue;
SendPacket(out->GetBuffer(), out->GetLength(), *itr);
}
unlock_mutex(endpointsMutex);
@ -574,8 +593,10 @@ void VoIPController::RunRecvThread(){
lock_mutex(endpointsMutex);
for(std::vector<Endpoint*>::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){
if((*itrtr)->address==*src4 && (*itrtr)->port==packet.port){
srcEndpoint=*itrtr;
break;
if(((*itrtr)->type!=EP_TYPE_TCP_RELAY && packet.protocol==PROTO_UDP) || ((*itrtr)->type==EP_TYPE_TCP_RELAY && packet.protocol==PROTO_TCP)){
srcEndpoint=*itrtr;
break;
}
}
}
unlock_mutex(endpointsMutex);
@ -595,7 +616,7 @@ void VoIPController::RunRecvThread(){
stats.bytesRecvdWifi+=(uint64_t)len;
BufferInputStream in(buffer, (size_t)len);
try{
if(memcmp(buffer, srcEndpoint->type==EP_TYPE_UDP_RELAY ? srcEndpoint->peerTag : callID, 16)!=0){
if(memcmp(buffer, srcEndpoint->type==EP_TYPE_UDP_RELAY || srcEndpoint->type==EP_TYPE_TCP_RELAY ? srcEndpoint->peerTag : callID, 16)!=0){
LOGW("Received packet has wrong peerTag");
continue;
@ -859,7 +880,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA
if(!receivedInit){
receivedInit=true;
currentEndpoint=srcEndpoint;
if(srcEndpoint->type==EP_TYPE_UDP_RELAY)
if(srcEndpoint->type==EP_TYPE_UDP_RELAY || (useTCP && srcEndpoint->type==EP_TYPE_TCP_RELAY))
preferredRelay=srcEndpoint;
LogDebugInfo();
}
@ -1131,7 +1152,7 @@ simpleAudioBlock random_id:long random_bytes:string raw_data:string = DecryptedA
endpoints.push_back(new Endpoint(0, peerPort, v4addr, v6addr, EP_TYPE_UDP_P2P_LAN, peerTag));
unlock_mutex(endpointsMutex);
}
if(type==PKT_NETWORK_CHANGED){
if(type==PKT_NETWORK_CHANGED && currentEndpoint->type!=EP_TYPE_UDP_RELAY && currentEndpoint->type!=EP_TYPE_TCP_RELAY){
currentEndpoint=preferredRelay;
if(allowP2p)
SendPublicEndpointsRequest();
@ -1211,6 +1232,7 @@ void VoIPController::RunTickThread(){
Sleep(100);
#endif
tickCount++;
double time=GetCurrentTime();
if(tickCount%5==0 && state==STATE_ESTABLISHED){
memmove(&rttHistory[1], rttHistory, 31*sizeof(double));
rttHistory[0]=GetAverageRTT();
@ -1244,6 +1266,26 @@ void VoIPController::RunTickThread(){
conctl->Tick();
if(!useTCP && ((state==STATE_WAIT_INIT_ACK && tickCount>=50) || (state==STATE_ESTABLISHED && time-lastRecvPacketTime>=5.0))){
useTCP=true;
if(!didAddTcpRelays){
std::vector<Endpoint *> relays;
for(std::vector<Endpoint *>::iterator itr=endpoints.begin(); itr!=endpoints.end(); ++itr){
if((*itr)->type!=EP_TYPE_UDP_RELAY)
continue;
Endpoint *tcpRelay=new Endpoint(**itr);
tcpRelay->type=EP_TYPE_TCP_RELAY;
tcpRelay->averageRTT=0;
tcpRelay->lastPingSeq=0;
tcpRelay->lastPingTime=0;
memset(tcpRelay->rtts, 0, sizeof(tcpRelay->rtts));
relays.push_back(tcpRelay);
}
endpoints.insert(endpoints.end(), relays.begin(), relays.end());
didAddTcpRelays=true;
}
}
if(state==STATE_ESTABLISHED){
if((audioInput && !audioInput->IsInitialized()) || (audioOutput && !audioOutput->IsInitialized())){
LOGE("Audio I/O failed");
@ -1372,6 +1414,8 @@ void VoIPController::RunTickThread(){
double minPing=preferredRelay->averageRTT;
for(std::vector<Endpoint*>::iterator e=endpoints.begin();e!=endpoints.end();++e){
Endpoint* endpoint=*e;
if(endpoint->type==EP_TYPE_TCP_RELAY && !useTCP)
continue;
if(GetCurrentTime()-endpoint->lastPingTime>=10){
LOGV("Sending ping to %s", endpoint->address.ToString().c_str());
BufferOutputStream pkt(32);
@ -1380,9 +1424,10 @@ void VoIPController::RunTickThread(){
endpoint->lastPingSeq=seq;
SendPacket(pkt.GetBuffer(), pkt.GetLength(), endpoint);
}
if(endpoint->type==EP_TYPE_UDP_RELAY){
if(endpoint->averageRTT>0 && endpoint->averageRTT<minPing*relaySwitchThreshold){
minPing=endpoint->averageRTT;
if(endpoint->type==EP_TYPE_UDP_RELAY || (useTCP && endpoint->type==EP_TYPE_TCP_RELAY)){
double k=endpoint->type==EP_TYPE_UDP_RELAY ? 1 : 2;
if(endpoint->averageRTT>0 && endpoint->averageRTT*k<minPing*relaySwitchThreshold){
minPing=endpoint->averageRTT*k;
minPingRelay=endpoint;
}
}
@ -1390,7 +1435,7 @@ void VoIPController::RunTickThread(){
if(minPingRelay!=preferredRelay){
preferredRelay=minPingRelay;
LOGV("set preferred relay to %s", preferredRelay->address.ToString().c_str());
if(currentEndpoint->type==EP_TYPE_UDP_RELAY)
if(currentEndpoint->type==EP_TYPE_UDP_RELAY || currentEndpoint->type==EP_TYPE_TCP_RELAY)
currentEndpoint=preferredRelay;
LogDebugInfo();
/*BufferOutputStream pkt(32);
@ -1427,7 +1472,7 @@ void VoIPController::RunTickThread(){
if(state==STATE_ESTABLISHED){
if(GetCurrentTime()-lastRecvPacketTime>=config.recv_timeout){
if(currentEndpoint && currentEndpoint->type!=EP_TYPE_UDP_RELAY){
if(currentEndpoint && currentEndpoint->type!=EP_TYPE_UDP_RELAY && currentEndpoint->type!=EP_TYPE_TCP_RELAY){
LOGW("Packet receive timeout, switching to relay");
currentEndpoint=preferredRelay;
for(std::vector<Endpoint*>::iterator itrtr=endpoints.begin();itrtr!=endpoints.end();++itrtr){
@ -1498,11 +1543,13 @@ Endpoint& VoIPController::GetRemoteEndpoint(){
void VoIPController::SendPacket(unsigned char *data, size_t len, Endpoint* ep){
if(stopping)
return;
if(ep->type==EP_TYPE_TCP_RELAY && !useTCP)
return;
//dst.sin_addr=ep->address;
//dst.sin_port=htons(ep->port);
//dst.sin_family=AF_INET;
BufferOutputStream out(len+128);
if(ep->type==EP_TYPE_UDP_RELAY)
if(ep->type==EP_TYPE_UDP_RELAY || ep->type==EP_TYPE_TCP_RELAY)
out.WriteBytes((unsigned char*)ep->peerTag, 16);
else
out.WriteBytes(callID, 16);
@ -1537,6 +1584,7 @@ void VoIPController::SendPacket(unsigned char *data, size_t len, Endpoint* ep){
pkt.port=ep->port;
pkt.length=out.GetLength();
pkt.data=out.GetBuffer();
pkt.protocol=ep->type==EP_TYPE_TCP_RELAY ? PROTO_TCP : PROTO_UDP;
socket->Send(&pkt);
}
@ -1554,13 +1602,21 @@ void VoIPController::SetNetworkType(int type){
if(isFirstChange)
return;
if(currentEndpoint && currentEndpoint->type!=EP_TYPE_UDP_RELAY){
currentEndpoint=preferredRelay;
if(preferredRelay->type==EP_TYPE_UDP_RELAY)
currentEndpoint=preferredRelay;
for(std::vector<Endpoint*>::iterator itr=endpoints.begin();itr!=endpoints.end();){
Endpoint* endpoint=*itr;
if(endpoint->type==EP_TYPE_UDP_P2P_INET){
if(endpoint->type==EP_TYPE_UDP_RELAY && useTCP){
useTCP=false;
if(preferredRelay->type==EP_TYPE_TCP_RELAY){
preferredRelay=endpoint;
currentEndpoint=endpoint;
}
}
//if(endpoint->type==EP_TYPE_UDP_P2P_INET){
endpoint->averageRTT=0;
memset(endpoint->rtts, 0, sizeof(endpoint->rtts));
}
//}
if(endpoint->type==EP_TYPE_UDP_P2P_LAN){
delete endpoint;
itr=endpoints.erase(itr);
@ -1987,6 +2043,9 @@ void VoIPController::LogDebugInfo(){
case EP_TYPE_UDP_P2P_LAN:
typeStr="udp_p2p_lan";
break;
case EP_TYPE_TCP_RELAY:
typeStr="tcp_relay";
break;
}
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" : "");
json+=buffer;

View File

@ -29,7 +29,7 @@
#include "CongestionControl.h"
#include "NetworkSocket.h"
#define LIBTGVOIP_VERSION "0.4.1"
#define LIBTGVOIP_VERSION "0.4.2"
#define PKT_INIT 1
#define PKT_INIT_ACK 2
@ -180,6 +180,7 @@ struct voip_crypto_functions_t{
void (*sha256)(uint8_t* msg, size_t length, uint8_t* output);
void (*aes_ige_encrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
void (*aes_ige_decrypt)(uint8_t* in, uint8_t* out, size_t length, uint8_t* key, uint8_t* iv);
void (*aes_ctr_encrypt)(uint8_t* inout, size_t length, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num);
};
typedef struct voip_crypto_functions_t voip_crypto_functions_t;
@ -362,6 +363,9 @@ private:
FILE* statsDump;
std::string currentAudioInput;
std::string currentAudioOutput;
bool useTCP;
bool didAddTcpRelays;
double enableTcpAt;
/*** server config values ***/
uint32_t maxAudioBitrate;

View File

@ -26,31 +26,31 @@
<DefaultLanguage>en-US</DefaultLanguage>
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
<AppContainerApplication>true</AppContainerApplication>
<ApplicationType>Windows Phone</ApplicationType>
<ApplicationType>Windows Phone Silverlight</ApplicationType>
<ApplicationTypeRevision>8.1</ApplicationTypeRevision>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120_wp81</PlatformToolset>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v120_wp81</PlatformToolset>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v120_wp81</PlatformToolset>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<PlatformToolset>v120_wp81</PlatformToolset>
<PlatformToolset>v120</PlatformToolset>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@ -78,7 +78,7 @@
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_APM_DEBUG_DUMP=0;TGVOIP_USE_CUSTOM_CRYPTO;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_WINRT_DLL;TGVOIP_WP_SILVERLIGHT;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_APM_DEBUG_DUMP=0;TGVOIP_USE_CUSTOM_CRYPTO;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
@ -88,13 +88,13 @@
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<AdditionalDependencies>ws2_32.lib;mmdevapi.lib;../TelegramClient/$(Platform)/$(Configuration)/TelegramClient.Opus/TelegramClient.Opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;phoneaudioses.lib;../TelegramClient/$(Platform)/$(Configuration)/TelegramClient.Opus/TelegramClient.Opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_WINRT_DLL;TGVOIP_WP_SILVERLIGHT;NDEBUG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
@ -104,13 +104,13 @@
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<AdditionalDependencies>ws2_32.lib;mmdevapi.lib;../TelegramClient/$(Platform)/$(Configuration)/TelegramClient.Opus/TelegramClient.Opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;phoneaudioses.lib;../TelegramClient/$(Platform)/$(Configuration)/TelegramClient.Opus/TelegramClient.Opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_APM_DEBUG_DUMP=0;TGVOIP_USE_CUSTOM_CRYPTO;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_WINRT_DLL;TGVOIP_WP_SILVERLIGHT;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_APM_DEBUG_DUMP=0;TGVOIP_USE_CUSTOM_CRYPTO;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
@ -120,13 +120,13 @@
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<AdditionalDependencies>ws2_32.lib;mmdevapi.lib;../TelegramClient/$(Platform)/$(Configuration)/TelegramClient.Opus/TelegramClient.Opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;phoneaudioses.lib;../TelegramClient/$(Platform)/$(Configuration)/TelegramClient.Opus/TelegramClient.Opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">
<ClCompile>
<PrecompiledHeader>NotUsing</PrecompiledHeader>
<PreprocessorDefinitions>_WINRT_DLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_APM_DEBUG_DUMP=0;TGVOIP_USE_CUSTOM_CRYPTO;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_WINRT_DLL;TGVOIP_WP_SILVERLIGHT;NDEBUG;_CRT_SECURE_NO_WARNINGS;NOMINMAX;WEBRTC_APM_DEBUG_DUMP=0;TGVOIP_USE_CUSTOM_CRYPTO;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<PrecompiledHeaderOutputFile>$(IntDir)pch.pch</PrecompiledHeaderOutputFile>
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
@ -136,7 +136,7 @@
<Link>
<SubSystem>Console</SubSystem>
<IgnoreAllDefaultLibraries>false</IgnoreAllDefaultLibraries>
<AdditionalDependencies>ws2_32.lib;mmdevapi.lib;../TelegramClient/$(Platform)/$(Configuration)/TelegramClient.Opus/TelegramClient.Opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>ws2_32.lib;phoneaudioses.lib;../TelegramClient/$(Platform)/$(Configuration)/TelegramClient.Opus/TelegramClient.Opus.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>

View File

@ -16,7 +16,7 @@
void tgvoip_log_file_printf(char level, const char* msg, ...);
void tgvoip_log_file_write_header();
#if !defined(snprintf) && defined(_WIN32)
#if !defined(snprintf) && defined(_WIN32) && defined(__cplusplus_winrt)
#define snprintf _snprintf
#endif

View File

@ -169,7 +169,7 @@ void AudioInputPulse::SetCurrentDevice(std::string devID){
pa_buffer_attr bufferAttr={
.maxlength=960*6,
.tlength=960*4,
.tlength=960*6,
.prebuf=0,
.minreq=960*2
};

View File

@ -46,7 +46,7 @@ private:
bool isConnected;
bool didStart;
bool isLocked;
unsigned char remainingData[10240];
unsigned char remainingData[960*8*2];
size_t remainingDataSize;
};

View File

@ -171,7 +171,7 @@ void AudioOutputPulse::SetCurrentDevice(std::string devID){
pa_buffer_attr bufferAttr={
.maxlength=960*6,
.tlength=960*4,
.tlength=960*6,
.prebuf=0,
.minreq=960*2
};
@ -283,6 +283,7 @@ void AudioOutputPulse::StreamWriteCallback(pa_stream *stream, size_t requestedBy
if(remainingDataSize+960*2>=sizeof(remainingData)){
LOGE("Can't provide %d bytes of audio data at a time", (int)bytesToFill);
failed=true;
pa_threaded_mainloop_unlock(mainloop);
return;
}
InvokeCallback(remainingData+remainingDataSize, 960*2);

View File

@ -44,7 +44,7 @@ private:
bool isConnected;
bool didStart;
bool isLocked;
unsigned char remainingData[10240];
unsigned char remainingData[960*8*2];
size_t remainingDataSize;
};

View File

@ -1,5 +1,7 @@
//
// Created by Grishka on 10.04.17.
// 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.
//
#include "NetworkSocketPosix.h"
@ -10,29 +12,42 @@
#include <net/if.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/tcp.h>
#include "../../logging.h"
#include "../../VoIPController.h"
#include "../../BufferInputStream.h"
#include "../../BufferOutputStream.h"
using namespace tgvoip;
NetworkSocketPosix::NetworkSocketPosix() : lastRecvdV4(0), lastRecvdV6("::0"){
needUpdateNat64Prefix=true;
nat64Present=false;
switchToV6at=0;
isV4Available=false;
useTCP=false;
closing=false;
int p[2];
int pipeRes=pipe(p);
assert(pipeRes==0);
pipeRead=p[0];
pipeWrite=p[1];
}
NetworkSocketPosix::~NetworkSocketPosix(){
close(pipeRead);
close(pipeWrite);
}
void NetworkSocketPosix::SetMaxPriority(){
#ifdef __APPLE__
int prio=NET_SERVICE_TYPE_VO;
int res=setsockopt(fd, SOL_SOCKET, SO_NET_SERVICE_TYPE, &prio, sizeof(prio));
if(res<0){
LOGE("error setting darwin-specific net priority: %d / %s", errno, strerror(errno));
}
int res=setsockopt(fd, SOL_SOCKET, SO_NET_SERVICE_TYPE, &prio, sizeof(prio));
if(res<0){
LOGE("error setting darwin-specific net priority: %d / %s", errno, strerror(errno));
}
#else
int prio=5;
int res=setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio));
@ -52,6 +67,74 @@ void NetworkSocketPosix::Send(NetworkPacket *packet){
LOGW("tried to send null packet");
return;
}
if(packet->protocol==PROTO_TCP){
//LOGV("Sending TCP packet to %s:%u", packet->address->ToString().c_str(), packet->port);
IPv4Address* v4addr=dynamic_cast<IPv4Address*>(packet->address);
if(v4addr){
TCPSocket* _socket=NULL;
for(std::vector<TCPSocket>::iterator itr=tcpSockets.begin();itr!=tcpSockets.end();++itr){
if(itr->address==*v4addr && itr->port==packet->port){
_socket=&*itr;
break;
}
}
if(!_socket){
TCPSocket s;
s.fd=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
s.port=packet->port;
s.address=IPv4Address(*v4addr);
int opt=1;
setsockopt(s.fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
timeval timeout;
timeout.tv_sec=1;
timeout.tv_usec=0;
setsockopt(s.fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
timeout.tv_sec=60;
setsockopt(s.fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=s.address.GetAddress();
addr.sin_port=htons(s.port);
int res=connect(s.fd, (const sockaddr*) &addr, sizeof(addr));
if(res!=0){
LOGW("error connecting TCP socket to %s:%u: %d / %s; %d / %s", s.address.ToString().c_str(), s.port, res, strerror(res), errno, strerror(errno));
close(s.fd);
return;
}else{
//LOGI("connected successfully, fd=%d", s.fd);
char c=1;
write(pipeWrite, &c, 1);
}
unsigned char buf[64];
GenerateTCPO2States(buf, &s.recvState, &s.sendState);
send(s.fd, buf, sizeof(buf), 0);
tcpSockets.push_back(s);
_socket=&tcpSockets[tcpSockets.size()-1];
}
if(_socket){
//LOGV("sending to %s:%u, fd=%d, size=%d (%d)", _socket->address.ToString().c_str(), _socket->port, _socket->fd, packet->length, packet->length%4);
BufferOutputStream os(packet->length+4);
size_t len=packet->length/4;
if(len<0x7F){
os.WriteByte((unsigned char)len);
}else{
os.WriteByte(0x7F);
os.WriteByte((unsigned char)(len & 0xFF));
os.WriteByte((unsigned char)((len >> 8) & 0xFF));
os.WriteByte((unsigned char)((len >> 16) & 0xFF));
}
os.WriteBytes(packet->data, packet->length);
EncryptForTCPO2(os.GetBuffer(), os.GetLength(), &_socket->sendState);
int res=send(_socket->fd, os.GetBuffer(), os.GetLength(), 0);
if(res<0){
LOGW("error sending to TCP: %d / %s; %d / %s", res, strerror(res), errno, strerror(errno));
}
}
}else{
LOGW("TCP over IPv6 isn't supported yet");
}
return;
}
sockaddr_in6 addr;
IPv4Address* v4addr=dynamic_cast<IPv4Address*>(packet->address);
if(v4addr){
@ -103,6 +186,7 @@ void NetworkSocketPosix::Send(NetworkPacket *packet){
}else{
IPv6Address* v6addr=dynamic_cast<IPv6Address*>(packet->address);
assert(v6addr!=NULL);
memcpy(addr.sin6_addr.s6_addr, v6addr->GetAddress(), 16);
}
addr.sin6_port=htons(packet->port);
char buf[INET6_ADDRSTRLEN];
@ -118,30 +202,119 @@ void NetworkSocketPosix::Send(NetworkPacket *packet){
}
void NetworkSocketPosix::Receive(NetworkPacket *packet){
int addrLen=sizeof(sockaddr_in6);
sockaddr_in6 srcAddr;
ssize_t len=recvfrom(fd, packet->data, packet->length, 0, (sockaddr *) &srcAddr, (socklen_t *) &addrLen);
if(len>0)
packet->length=(size_t) len;
else{
LOGE("error receiving %d / %s", errno, strerror(errno));
packet->length=0;
return;
while(true){
fd_set readSet, errSet;
FD_ZERO(&readSet);
FD_ZERO(&errSet);
FD_SET(pipeRead, &readSet);
FD_SET(fd, &readSet);
FD_SET(fd, &errSet);
int maxfd=pipeRead>fd ? pipeRead : fd;
for(std::vector<TCPSocket>::iterator itr=tcpSockets.begin(); itr!=tcpSockets.end(); ++itr){
FD_SET(itr->fd, &readSet);
FD_SET(itr->fd, &errSet);
if(itr->fd>maxfd)
maxfd=itr->fd;
}
int res=select(maxfd+1, &readSet, NULL, &errSet, NULL);
if(FD_ISSET(pipeRead, &readSet)){
char d;
read(pipeRead, &d, 1);
if(closing){
packet->length=0;
return;
}
continue;
}
if(FD_ISSET(fd, &readSet) || FD_ISSET(fd, &errSet)){
int addrLen=sizeof(sockaddr_in6);
sockaddr_in6 srcAddr;
ssize_t len=recvfrom(fd, packet->data, packet->length, 0, (sockaddr *) &srcAddr, (socklen_t *) &addrLen);
if(len>0)
packet->length=(size_t) len;
else{
LOGE("error receiving %d / %s", errno, strerror(errno));
packet->length=0;
return;
}
//LOGV("Received %d bytes from %s:%d at %.5lf", len, inet_ntoa(srcAddr.sin_addr), ntohs(srcAddr.sin_port), GetCurrentTime());
if(!isV4Available && IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr)){
isV4Available=true;
LOGI("Detected IPv4 connectivity, will not try IPv6");
}
if(IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr) || (nat64Present && memcmp(nat64Prefix, srcAddr.sin6_addr.s6_addr, 12)==0)){
in_addr v4addr=*((in_addr *) &srcAddr.sin6_addr.s6_addr[12]);
lastRecvdV4=IPv4Address(v4addr.s_addr);
packet->address=&lastRecvdV4;
}else{
lastRecvdV6=IPv6Address(srcAddr.sin6_addr.s6_addr);
packet->address=&lastRecvdV6;
}
packet->protocol=PROTO_UDP;
packet->port=ntohs(srcAddr.sin6_port);
return;
}
for(std::vector<TCPSocket>::iterator itr=tcpSockets.begin(); itr!=tcpSockets.end();){
if(FD_ISSET(itr->fd, &readSet)){
unsigned char len1;
size_t packetLen=0;
size_t offset=0;
ssize_t len=recv(itr->fd, &len1, 1, 0);
if(len<=0)
goto failed;
EncryptForTCPO2(&len1, 1, &itr->recvState);
if(len1<0x7F){
packetLen=(size_t)len1*4;
}else{
unsigned char len2[3];
len=recv(itr->fd, len2, 3, 0);
if(len<=0)
goto failed;
EncryptForTCPO2(len2, 3, &itr->recvState);
packetLen=((size_t)len2[0] | ((size_t)len2[1] << 8) | ((size_t)len2[2] << 16))*4;
}
if(packetLen>packet->length){
LOGW("packet too big to fit into buffer");
packet->length=0;
return;
}
while(offset<packetLen){
len=recv(itr->fd, packet->data+offset, packetLen-offset, 0);
if(len<=0)
goto failed;
offset+=len;
}
EncryptForTCPO2(packet->data, packetLen, &itr->recvState);
packet->address=&itr->address;
packet->length=packetLen;
packet->port=itr->port;
packet->protocol=PROTO_TCP;
return;
failed:
packet->length=0;
close(itr->fd);
itr=tcpSockets.erase(itr);
continue;
}
if(FD_ISSET(itr->fd, &errSet)){
close(itr->fd);
itr=tcpSockets.erase(itr);
continue;
}
++itr;
}
}
//LOGV("Received %d bytes from %s:%d at %.5lf", len, inet_ntoa(srcAddr.sin_addr), ntohs(srcAddr.sin_port), GetCurrentTime());
if(!isV4Available && IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr)){
isV4Available=true;
LOGI("Detected IPv4 connectivity, will not try IPv6");
}
if(IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr) || (nat64Present && memcmp(nat64Prefix, srcAddr.sin6_addr.s6_addr, 12)==0)){
in_addr v4addr=*((in_addr *) &srcAddr.sin6_addr.s6_addr[12]);
lastRecvdV4=IPv4Address(v4addr.s_addr);
packet->address=&lastRecvdV4;
}else{
lastRecvdV6=IPv6Address(srcAddr.sin6_addr.s6_addr);
packet->address=&lastRecvdV6;
}
packet->port=ntohs(srcAddr.sin6_port);
}
void NetworkSocketPosix::Open(){
@ -193,8 +366,15 @@ void NetworkSocketPosix::Open(){
}
void NetworkSocketPosix::Close(){
closing=true;
char c=1;
write(pipeWrite, &c, 1);
shutdown(fd, SHUT_RDWR);
close(fd);
for(std::vector<TCPSocket>::iterator itr=tcpSockets.begin(); itr!=tcpSockets.end();++itr){
shutdown(itr->fd, SHUT_RDWR);
close(itr->fd);
}
}
void NetworkSocketPosix::OnActiveInterfaceChanged(){

View File

@ -1,14 +1,27 @@
//
// Created by Grishka on 10.04.17.
// 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 LIBTGVOIP_NETWORKSOCKETPOSIX_H
#define LIBTGVOIP_NETWORKSOCKETPOSIX_H
#include "../../NetworkSocket.h"
#include <vector>
#include <sys/select.h>
#include <pthread.h>
namespace tgvoip {
struct TCPSocket{
int fd;
IPv4Address address;
uint16_t port;
TCPO2State recvState;
TCPO2State sendState;
};
class NetworkSocketPosix : public NetworkSocket{
public:
NetworkSocketPosix();
@ -31,12 +44,17 @@ protected:
private:
int fd;
std::vector<TCPSocket> tcpSockets;
bool needUpdateNat64Prefix;
bool nat64Present;
double switchToV6at;
bool isV4Available;
bool useTCP;
bool closing;
IPv4Address lastRecvdV4;
IPv6Address lastRecvdV6;
int pipeRead;
int pipeWrite;
};
}

View File

@ -19,7 +19,9 @@
#include <vector>
#pragma warning(push)
#pragma warning(disable : 4201)
#ifndef TGVOIP_WP_SILVERLIGHT
#include <mmdeviceapi.h>
#endif
#ifdef TGVOIP_WINDOWS_DESKTOP
#include <audiopolicy.h>
#include <functiondiscoverykeys.h>

View File

@ -19,7 +19,9 @@
#include <vector>
#pragma warning(push)
#pragma warning(disable : 4201)
#ifndef TGVOIP_WP_SILVERLIGHT
#include <mmdeviceapi.h>
#endif
#ifdef TGVOIP_WINDOWS_DESKTOP
#include <audiopolicy.h>
#include <functiondiscoverykeys.h>

View File

@ -23,6 +23,7 @@ NetworkSocketWinsock::NetworkSocketWinsock() : lastRecvdV4(0), lastRecvdV6("::0"
nat64Present=false;
switchToV6at=0;
isV4Available=false;
closing=false;
#ifdef TGVOIP_WINXP_COMPAT
DWORD version=GetVersion();
@ -45,6 +46,70 @@ void NetworkSocketWinsock::SetMaxPriority(){
}
void NetworkSocketWinsock::Send(NetworkPacket *packet){
if(packet->protocol==PROTO_TCP){
//LOGV("Sending TCP packet to %s:%u", packet->address->ToString().c_str(), packet->port);
IPv4Address* v4addr=dynamic_cast<IPv4Address*>(packet->address);
if(v4addr){
TCPSocket* _socket=NULL;
for(std::vector<TCPSocket>::iterator itr=tcpSockets.begin();itr!=tcpSockets.end();++itr){
if(itr->address==*v4addr && itr->port==packet->port){
_socket=&*itr;
break;
}
}
if(!_socket){
TCPSocket s;
s.fd=socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
s.port=packet->port;
s.address=IPv4Address(*v4addr);
int opt=1;
setsockopt(s.fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(opt));
timeval timeout;
timeout.tv_sec=1;
timeout.tv_usec=0;
setsockopt(s.fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout));
timeout.tv_sec=60;
setsockopt(s.fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
sockaddr_in addr;
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=s.address.GetAddress();
addr.sin_port=htons(s.port);
int res=connect(s.fd, (const sockaddr*) &addr, sizeof(addr));
if(res!=0){
LOGW("error connecting TCP socket to %s:%u: %d / %s; %d / %s", s.address.ToString().c_str(), s.port, res, strerror(res), errno, strerror(errno));
closesocket(s.fd);
return;
}
unsigned char buf[64];
GenerateTCPO2States(buf, &s.recvState, &s.sendState);
send(s.fd, (const char*)buf, sizeof(buf), 0);
tcpSockets.push_back(s);
_socket=&tcpSockets[tcpSockets.size()-1];
}
if(_socket){
//LOGV("sending to %s:%u, fd=%d, size=%d (%d)", _socket->address.ToString().c_str(), _socket->port, _socket->fd, packet->length, packet->length%4);
BufferOutputStream os(packet->length+4);
size_t len=packet->length/4;
if(len<0x7F){
os.WriteByte((unsigned char)len);
}else{
os.WriteByte(0x7F);
os.WriteByte((unsigned char)(len & 0xFF));
os.WriteByte((unsigned char)((len >> 8) & 0xFF));
os.WriteByte((unsigned char)((len >> 16) & 0xFF));
}
os.WriteBytes(packet->data, packet->length);
EncryptForTCPO2(os.GetBuffer(), os.GetLength(), &_socket->sendState);
int res=send(_socket->fd, (const char*)os.GetBuffer(), os.GetLength(), 0);
if(res<0){
LOGW("error sending to TCP: %d / %s; %d / %s", res, strerror(res), errno, strerror(errno));
}
}
}else{
LOGW("TCP over IPv6 isn't supported yet");
}
return;
}
sockaddr_in6 addr;
IPv4Address* v4addr=dynamic_cast<IPv4Address*>(packet->address);
if(v4addr){
@ -130,49 +195,131 @@ void NetworkSocketWinsock::Send(NetworkPacket *packet){
}
void NetworkSocketWinsock::Receive(NetworkPacket *packet){
sockaddr_in6 srcAddr;
sockaddr_in srcAddr4;
sockaddr* addr;
int addrLen;
if(isAtLeastVista){
addr=(sockaddr*)&srcAddr;
addrLen=sizeof(srcAddr);
}else{
addr=(sockaddr*)&srcAddr4;
addrLen=sizeof(srcAddr4);
}
//DWORD len;
//WSABUF buf;
//buf.buf=(char*) packet->data;
//buf.len=packet->length;
//int res=WSARecvFrom(fd, &buf, 1, &len, 0, (sockaddr*) &srcAddr, &addrLen, NULL, NULL);
int res=recvfrom(fd, (char*)packet->data, packet->length, 0, addr, &addrLen);
if(res!=SOCKET_ERROR)
packet->length=(size_t) res;
else{
packet->length=0;
int error=WSAGetLastError();
LOGE("error receiving: %d", error);
return;
}
//LOGV("Received %d bytes from %s:%d at %.5lf", len, inet_ntoa(srcAddr.sin_addr), ntohs(srcAddr.sin_port), GetCurrentTime());
if(addr->sa_family==AF_INET){
packet->port=ntohs(srcAddr4.sin_port);
lastRecvdV4=IPv4Address(srcAddr4.sin_addr.s_addr);
packet->address=&lastRecvdV4;
}else{
packet->port=ntohs(srcAddr.sin6_port);
if(!isV4Available && IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr)){
isV4Available=true;
LOGI("Detected IPv4 connectivity, will not try IPv6");
fd_set readSet;
fd_set errSet;
timeval timeout={0, 500000};
while(true){
do{
FD_ZERO(&readSet);
FD_ZERO(&errSet);
FD_SET(fd, &readSet);
FD_SET(fd, &errSet);
for(std::vector<TCPSocket>::iterator itr=tcpSockets.begin(); itr!=tcpSockets.end(); ++itr){
FD_SET(itr->fd, &readSet);
FD_SET(itr->fd, &errSet);
}
}while(select(0, &readSet, NULL, &errSet, &timeout)==0);
if(closing){
packet->length=0;
return;
}
if(IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr) || (nat64Present && memcmp(nat64Prefix, srcAddr.sin6_addr.s6_addr, 12)==0)){
in_addr v4addr=*((in_addr *)&srcAddr.sin6_addr.s6_addr[12]);
lastRecvdV4=IPv4Address(v4addr.s_addr);
packet->address=&lastRecvdV4;
}else{
lastRecvdV6=IPv6Address(srcAddr.sin6_addr.s6_addr);
packet->address=&lastRecvdV6;
if(FD_ISSET(fd, &readSet) || FD_ISSET(fd, &errSet)){
sockaddr_in6 srcAddr;
sockaddr_in srcAddr4;
sockaddr* addr;
int addrLen;
if(isAtLeastVista){
addr=(sockaddr*)&srcAddr;
addrLen=sizeof(srcAddr);
}else{
addr=(sockaddr*)&srcAddr4;
addrLen=sizeof(srcAddr4);
}
//DWORD len;
//WSABUF buf;
//buf.buf=(char*) packet->data;
//buf.len=packet->length;
//int res=WSARecvFrom(fd, &buf, 1, &len, 0, (sockaddr*) &srcAddr, &addrLen, NULL, NULL);
int res=recvfrom(fd, (char*)packet->data, packet->length, 0, addr, &addrLen);
if(res!=SOCKET_ERROR)
packet->length=(size_t) res;
else{
packet->length=0;
int error=WSAGetLastError();
LOGE("error receiving: %d", error);
return;
}
//LOGV("Received %d bytes from %s:%d at %.5lf", len, inet_ntoa(srcAddr.sin_addr), ntohs(srcAddr.sin_port), GetCurrentTime());
if(addr->sa_family==AF_INET){
packet->port=ntohs(srcAddr4.sin_port);
lastRecvdV4=IPv4Address(srcAddr4.sin_addr.s_addr);
packet->address=&lastRecvdV4;
}else{
packet->port=ntohs(srcAddr.sin6_port);
if(!isV4Available && IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr)){
isV4Available=true;
LOGI("Detected IPv4 connectivity, will not try IPv6");
}
if(IN6_IS_ADDR_V4MAPPED(&srcAddr.sin6_addr) || (nat64Present && memcmp(nat64Prefix, srcAddr.sin6_addr.s6_addr, 12)==0)){
in_addr v4addr=*((in_addr *)&srcAddr.sin6_addr.s6_addr[12]);
lastRecvdV4=IPv4Address(v4addr.s_addr);
packet->address=&lastRecvdV4;
}else{
lastRecvdV6=IPv6Address(srcAddr.sin6_addr.s6_addr);
packet->address=&lastRecvdV6;
}
}
return;
}
for(std::vector<TCPSocket>::iterator itr=tcpSockets.begin(); itr!=tcpSockets.end();){
if(FD_ISSET(itr->fd, &readSet)){
unsigned char len1;
size_t packetLen=0;
size_t offset=0;
int len=recv(itr->fd, (char*)&len1, 1, 0);
if(len<=0)
goto failed;
EncryptForTCPO2(&len1, 1, &itr->recvState);
if(len1<0x7F){
packetLen=(size_t)len1*4;
}else{
unsigned char len2[3];
len=recv(itr->fd, (char*)len2, 3, 0);
if(len<=0)
goto failed;
EncryptForTCPO2(len2, 3, &itr->recvState);
packetLen=((size_t)len2[0] | ((size_t)len2[1] << 8) | ((size_t)len2[2] << 16))*4;
}
if(packetLen>packet->length){
LOGW("packet too big to fit into buffer");
packet->length=0;
return;
}
while(offset<packetLen){
len=recv(itr->fd, (char*)packet->data+offset, packetLen-offset, 0);
if(len<=0)
goto failed;
offset+=len;
}
EncryptForTCPO2(packet->data, packetLen, &itr->recvState);
packet->address=&itr->address;
packet->length=packetLen;
packet->port=itr->port;
packet->protocol=PROTO_TCP;
return;
failed:
packet->length=0;
closesocket(itr->fd);
itr=tcpSockets.erase(itr);
continue;
}
if(FD_ISSET(itr->fd, &errSet)){
closesocket(itr->fd);
itr=tcpSockets.erase(itr);
continue;
}
++itr;
}
}
}
@ -258,7 +405,12 @@ void NetworkSocketWinsock::Open(){
}
void NetworkSocketWinsock::Close(){
closing=true;
closesocket(fd);
for(std::vector<TCPSocket>::iterator itr=tcpSockets.begin(); itr!=tcpSockets.end();++itr){
//shutdown(itr->fd, SHUT_RDWR);
closesocket(itr->fd);
}
}
void NetworkSocketWinsock::OnActiveInterfaceChanged(){

View File

@ -9,9 +9,18 @@
#include "../../NetworkSocket.h"
#include <stdint.h>
#include <vector>
namespace tgvoip {
struct TCPSocket{
uintptr_t fd;
IPv4Address address;
uint16_t port;
TCPO2State recvState;
TCPO2State sendState;
};
class NetworkSocketWinsock : public NetworkSocket{
public:
NetworkSocketWinsock();
@ -41,6 +50,8 @@ private:
IPv4Address lastRecvdV4;
IPv6Address lastRecvdV6;
bool isAtLeastVista;
std::vector<TCPSocket> tcpSockets;
bool closing;
};

View File

@ -8,11 +8,16 @@
#include "WindowsSandboxUtils.h"
#include <audioclient.h>
#include <windows.h>
#ifdef TGVOIP_WP_SILVERLIGHT
#include <phoneaudioclient.h>
#endif
using namespace tgvoip;
using namespace Microsoft::WRL;
IAudioClient2* WindowsSandboxUtils::ActivateAudioDevice(const wchar_t* devID, HRESULT* callRes, HRESULT* actRes) {
#ifndef TGVOIP_WP_SILVERLIGHT
// Did I say that I hate pointlessly asynchronous things?
HANDLE event = CreateEventEx(NULL, NULL, 0, EVENT_ALL_ACCESS);
ActivationHandler activationHandler(event);
@ -26,8 +31,18 @@ IAudioClient2* WindowsSandboxUtils::ActivateAudioDevice(const wchar_t* devID, HR
if (actRes)
*actRes = activationHandler.actResult;
return activationHandler.client;
#else
IAudioClient2* client;
HRESULT res=ActivateAudioInterface(devID, __uuidof(IAudioClient2), (void**)&client);
if(callRes)
*callRes=S_OK;
if(actRes)
*actRes=res;
return client;
#endif
}
#ifndef TGVOIP_WP_SILVERLIGHT
ActivationHandler::ActivationHandler(HANDLE _event) : event(_event)
{
@ -48,4 +63,6 @@ STDMETHODIMP ActivationHandler::ActivateCompleted(IActivateAudioInterfaceAsyncOp
SetEvent(event);
return hr;
}
}
#endif

View File

@ -7,7 +7,9 @@
#include <audioclient.h>
#include <windows.h>
#ifndef TGVOIP_WP_SILVERLIGHT
#include <mmdeviceapi.h>
#endif
#include <wrl.h>
#include <wrl/implements.h>
@ -15,6 +17,7 @@ using namespace Microsoft::WRL;
namespace tgvoip {
#ifndef TGVOIP_WP_SILVERLIGHT
class ActivationHandler :
public RuntimeClass< RuntimeClassFlags< ClassicCom >, FtmBase, IActivateAudioInterfaceCompletionHandler >
{
@ -26,6 +29,7 @@ namespace tgvoip {
IAudioClient2* client;
HRESULT actResult;
};
#endif
class WindowsSandboxUtils {
public: