mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-03 19:30:09 +00:00
Added TCP fallback
Support for Windows Phone Silverlight Various fixes
This commit is contained in:
parent
6883bbf5d6
commit
cd8d78b366
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -46,7 +46,7 @@ private:
|
||||
bool isConnected;
|
||||
bool didStart;
|
||||
bool isLocked;
|
||||
unsigned char remainingData[10240];
|
||||
unsigned char remainingData[960*8*2];
|
||||
size_t remainingDataSize;
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -44,7 +44,7 @@ private:
|
||||
bool isConnected;
|
||||
bool didStart;
|
||||
bool isLocked;
|
||||
unsigned char remainingData[10240];
|
||||
unsigned char remainingData[960*8*2];
|
||||
size_t remainingDataSize;
|
||||
};
|
||||
|
||||
|
@ -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(){
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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(){
|
||||
|
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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
|
@ -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:
|
||||
|
Loading…
x
Reference in New Issue
Block a user