1
0
mirror of https://github.com/danog/libtgvoip.git synced 2024-11-30 04:39:03 +01:00

Refactor all the things!

- Added support for SOCKS5 proxy
- Also, a bunch of bugfixes
This commit is contained in:
Grishka 2017-07-03 04:42:49 +03:00
parent c63a3bbdcf
commit 1be4d016a4
30 changed files with 2140 additions and 1102 deletions

View File

@ -8,69 +8,3 @@
using namespace tgvoip;
BlockingQueue::BlockingQueue(size_t capacity) : semaphore(capacity, 0){
this->capacity=capacity;
overflowCallback=NULL;
init_mutex(mutex);
}
BlockingQueue::~BlockingQueue(){
semaphore.Release();
free_mutex(mutex);
}
void BlockingQueue::Put(void *thing){
MutexGuard sync(mutex);
queue.push_back(thing);
bool didOverflow=false;
while(queue.size()>capacity){
didOverflow=true;
if(overflowCallback){
overflowCallback(queue.front());
queue.pop_front();
}else{
abort();
}
}
if(!didOverflow)
semaphore.Release();
}
void *BlockingQueue::GetBlocking(){
semaphore.Acquire();
MutexGuard sync(mutex);
void* r=GetInternal();
return r;
}
void *BlockingQueue::Get(){
MutexGuard sync(mutex);
if(queue.size()>0)
semaphore.Acquire();
void* r=GetInternal();
return r;
}
void *BlockingQueue::GetInternal(){
if(queue.size()==0)
return NULL;
void* r=queue.front();
queue.pop_front();
return r;
}
unsigned int BlockingQueue::Size(){
return queue.size();
}
void BlockingQueue::PrepareDealloc(){
}
void BlockingQueue::SetOverflowCallback(void (*overflowCallback)(void *)){
this->overflowCallback=overflowCallback;
}

View File

@ -14,25 +14,80 @@
using namespace std;
namespace tgvoip{
template<typename T>
class BlockingQueue{
public:
BlockingQueue(size_t capacity);
~BlockingQueue();
void Put(void* thing);
void* GetBlocking();
void* Get();
unsigned int Size();
void PrepareDealloc();
void SetOverflowCallback(void (*overflowCallback)(void*));
BlockingQueue(size_t capacity) : semaphore(capacity, 0){
this->capacity=capacity;
overflowCallback=NULL;
init_mutex(mutex);
};
~BlockingQueue(){
semaphore.Release();
free_mutex(mutex);
}
void Put(T thing){
MutexGuard sync(mutex);
queue.push_back(thing);
bool didOverflow=false;
while(queue.size()>capacity){
didOverflow=true;
if(overflowCallback){
overflowCallback(queue.front());
queue.pop_front();
}else{
abort();
}
}
if(!didOverflow)
semaphore.Release();
}
T GetBlocking(){
semaphore.Acquire();
MutexGuard sync(mutex);
T r=GetInternal();
return r;
}
T Get(){
MutexGuard sync(mutex);
if(queue.size()>0)
semaphore.Acquire();
T r=GetInternal();
return r;
}
unsigned int Size(){
return queue.size();
}
void PrepareDealloc(){
}
void SetOverflowCallback(void (*overflowCallback)(T)){
this->overflowCallback=overflowCallback;
}
private:
void* GetInternal();
list<void*> queue;
T GetInternal(){
//if(queue.size()==0)
// return NULL;
T r=queue.front();
queue.pop_front();
return r;
}
list<T> queue;
size_t capacity;
//tgvoip_lock_t lock;
Semaphore semaphore;
tgvoip_mutex_t mutex;
void (*overflowCallback)(void*);
void (*overflowCallback)(T);
};
}

View File

@ -5,6 +5,7 @@
//
#include "BufferOutputStream.h"
#include <stdexcept>
#include <string.h>
using namespace tgvoip;
@ -13,10 +14,19 @@ BufferOutputStream::BufferOutputStream(size_t size){
buffer=(unsigned char*) malloc(size);
offset=0;
this->size=size;
bufferProvided=false;
}
BufferOutputStream::BufferOutputStream(unsigned char *buffer, size_t size){
this->buffer=buffer;
this->size=size;
offset=0;
bufferProvided=true;
}
BufferOutputStream::~BufferOutputStream(){
free(buffer);
if(!bufferProvided)
free(buffer);
}
void BufferOutputStream::WriteByte(unsigned char byte){
@ -69,6 +79,9 @@ size_t BufferOutputStream::GetLength(){
void BufferOutputStream::ExpandBufferIfNeeded(size_t need){
if(offset+need>size){
if(bufferProvided){
throw std::out_of_range("buffer overflow");
}
if(need<1024){
buffer=(unsigned char *) realloc(buffer, size+1024);
size+=1024;

View File

@ -15,6 +15,7 @@ class BufferOutputStream{
public:
BufferOutputStream(size_t size);
BufferOutputStream(unsigned char* buffer, size_t size);
~BufferOutputStream();
void WriteByte(unsigned char byte);
void WriteInt64(int64_t i);
@ -30,6 +31,7 @@ private:
unsigned char* buffer;
size_t size;
size_t offset;
bool bufferProvided;
};
}

View File

@ -21,6 +21,7 @@ BufferPool::BufferPool(unsigned int size, unsigned int count){
buffers[i]=buffers[0]+i*size;
}
usedBuffers=0;
this->size=size;
}
BufferPool::~BufferPool(){
@ -56,3 +57,10 @@ void BufferPool::Reuse(unsigned char* buffer){
abort();
}
size_t BufferPool::GetSingleBufferSize(){
return size;
}
size_t BufferPool::GetBufferCount(){
return (size_t) bufferCount;
}

View File

@ -17,10 +17,13 @@ public:
~BufferPool();
unsigned char* Get();
void Reuse(unsigned char* buffer);
size_t GetSingleBufferSize();
size_t GetBufferCount();
private:
uint64_t usedBuffers;
int bufferCount;
size_t size;
unsigned char* buffers[64];
tgvoip_mutex_t mutex;
};

View File

@ -75,7 +75,7 @@ EchoCanceller::EchoCanceller(bool enableAEC, bool enableNS, bool enableAGC){
webrtc::WebRtcAec_set_config(aec, config);
#endif
farendQueue=new BlockingQueue(11);
farendQueue=new BlockingQueue<int16_t*>(11);
farendBufferPool=new BufferPool(960*2, 10);
running=true;
@ -170,7 +170,7 @@ void EchoCanceller::SpeakerOutCallback(unsigned char* data, size_t len){
WebRtcAecm_BufferFarend(state, (int16_t*)(data+offset), AEC_FRAME_SIZE);
offset+=OFFSET_STEP;
}*/
unsigned char* buf=farendBufferPool->Get();
int16_t* buf=(int16_t*)farendBufferPool->Get();
if(buf){
memcpy(buf, data, 960*2);
farendQueue->Put(buf);
@ -184,7 +184,7 @@ void *EchoCanceller::StartBufferFarendThread(void *arg){
void EchoCanceller::RunBufferFarendThread(){
while(running){
int16_t* samplesIn=(int16_t *) farendQueue->GetBlocking();
int16_t* samplesIn=farendQueue->GetBlocking();
if(samplesIn){
webrtc::IFChannelBuffer* bufIn=(webrtc::IFChannelBuffer*) splittingFilterFarendIn;
webrtc::IFChannelBuffer* bufOut=(webrtc::IFChannelBuffer*) splittingFilterFarendOut;

View File

@ -40,7 +40,7 @@ private:
void* splittingFilterFarendIn; // webrtc::IFChannelBuffer
void* splittingFilterFarendOut; // webrtc::IFChannelBuffer
tgvoip_thread_t bufferFarendThread;
BlockingQueue* farendQueue;
BlockingQueue<int16_t*>* farendQueue;
BufferPool* farendBufferPool;
bool running;
void* ns; // NsxHandle

View File

@ -9,21 +9,28 @@
#include <string.h>
#if defined(_WIN32)
#include "os/windows/NetworkSocketWinsock.h"
#include <winsock2.h>
#else
#include "os/posix/NetworkSocketPosix.h"
#endif
#include "logging.h"
#include "VoIPServerConfig.h"
#include "VoIPController.h"
#include "BufferInputStream.h"
#define MIN_UDP_PORT 16384
#define MAX_UDP_PORT 32768
using namespace tgvoip;
NetworkSocket::NetworkSocket(){
NetworkSocket::NetworkSocket(NetworkProtocol protocol) : protocol(protocol){
ipv6Timeout=ServerConfig::GetSharedInstance()->GetDouble("nat64_fallback_timeout", 3);
failed=false;
proxyAddress=NULL;
proxyPort=0;
proxyUsername=NULL;
proxyPassword=NULL;
}
NetworkSocket::~NetworkSocket(){
@ -46,14 +53,29 @@ bool NetworkSocket::IsFailed(){
return failed;
}
NetworkSocket *NetworkSocket::Create(){
NetworkSocket *NetworkSocket::Create(NetworkProtocol protocol){
#ifndef _WIN32
return new NetworkSocketPosix();
return new NetworkSocketPosix(protocol);
#else
return new NetworkSocketWinsock();
return new NetworkSocketWinsock(protocol);
#endif
}
IPv4Address *NetworkSocket::ResolveDomainName(std::string name){
#ifndef _WIN32
return NetworkSocketPosix::ResolveDomainName(name);
#else
return NetworkSocketWinsock::ResolveDomainName(name);
#endif
}
void NetworkSocket::SetSocksProxy(IPv4Address *addr, uint16_t port, char *username, char *password){
proxyAddress=addr;
proxyPort=port;
proxyUsername=username;
proxyPassword=password;
}
void NetworkSocket::GenerateTCPO2States(unsigned char* buffer, TCPO2State* recvState, TCPO2State* sendState){
memset(recvState, 0, sizeof(TCPO2State));
memset(sendState, 0, sizeof(TCPO2State));
@ -87,6 +109,22 @@ void NetworkSocket::EncryptForTCPO2(unsigned char *buffer, size_t len, TCPO2Stat
VoIPController::crypto.aes_ctr_encrypt(buffer, len, state->key, state->iv, state->ecount, &state->num);
}
size_t NetworkSocket::Receive(unsigned char *buffer, size_t len){
NetworkPacket pkt;
pkt.data=buffer;
pkt.length=len;
Receive(&pkt);
return pkt.length;
}
size_t NetworkSocket::Send(unsigned char *buffer, size_t len){
NetworkPacket pkt;
pkt.data=buffer;
pkt.length=len;
Send(&pkt);
return pkt.length;
}
bool NetworkAddress::operator==(const NetworkAddress &other){
IPv4Address* self4=dynamic_cast<IPv4Address*>(this);
IPv4Address* other4=dynamic_cast<IPv4Address*>((NetworkAddress*)&other);
@ -173,3 +211,394 @@ std::string IPv6Address::ToString(){
const uint8_t *IPv6Address::GetAddress(){
return address;
}
bool NetworkSocket::Select(std::vector<NetworkSocket *> &readFds, std::vector<NetworkSocket *> &errorFds, SocketSelectCanceller *canceller){
#ifndef _WIN32
return NetworkSocketPosix::Select(readFds, errorFds, canceller);
#else
return NetworkSocketWinsock::Select(readFds, errorFds, canceller);
#endif
}
SocketSelectCanceller::~SocketSelectCanceller(){
}
SocketSelectCanceller *SocketSelectCanceller::Create(){
#ifndef _WIN32
return new SocketSelectCancellerPosix();
#else
return new SocketSelectCancellerWin32();
#endif
}
NetworkSocketTCPObfuscated::NetworkSocketTCPObfuscated(NetworkSocket *wrapped) : NetworkSocketWrapper(PROTO_TCP){
this->wrapped=wrapped;
}
NetworkSocketTCPObfuscated::~NetworkSocketTCPObfuscated(){
if(wrapped)
delete wrapped;
}
NetworkSocket *NetworkSocketTCPObfuscated::GetWrapped(){
return wrapped;
}
void NetworkSocketTCPObfuscated::InitConnection(){
unsigned char buf[64];
GenerateTCPO2States(buf, &recvState, &sendState);
wrapped->Send(buf, 64);
}
void NetworkSocketTCPObfuscated::Send(NetworkPacket *packet){
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(), &sendState);
wrapped->Send(os.GetBuffer(), os.GetLength());
//LOGD("Sent %u bytes", os.GetLength());
}
void NetworkSocketTCPObfuscated::Receive(NetworkPacket *packet){
unsigned char len1;
size_t packetLen=0;
size_t offset=0;
size_t len;
wrapped->Receive(&len1, 1);
/*if(len<=0)
goto failed;*/
EncryptForTCPO2(&len1, 1, &recvState);
if(len1<0x7F){
packetLen=(size_t)len1*4;
}else{
unsigned char len2[3];
len=wrapped->Receive(len2, 3);
/*if(len<=0)
goto failed;*/
EncryptForTCPO2(len2, 3, &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 (%u vs %u)", packetLen, packet->length);
packet->length=0;
return;
}
while(offset<packetLen){
len=wrapped->Receive(packet->data+offset, packetLen-offset);
/*if(len<=0)
goto failed;*/
offset+=len;
}
EncryptForTCPO2(packet->data, packetLen, &recvState);
//packet->address=&itr->address;
packet->length=packetLen;
//packet->port=itr->port;
packet->protocol=PROTO_TCP;
packet->address=wrapped->GetConnectedAddress();
packet->port=wrapped->GetConnectedPort();
}
void NetworkSocketTCPObfuscated::Open(){
}
void NetworkSocketTCPObfuscated::Close(){
wrapped->Close();
}
void NetworkSocketTCPObfuscated::Connect(NetworkAddress *address, uint16_t port){
}
bool NetworkSocketTCPObfuscated::IsFailed(){
return wrapped->IsFailed();
}
NetworkSocketSOCKS5Proxy::NetworkSocketSOCKS5Proxy(NetworkSocket *tcp, NetworkSocket *udp, std::string username, std::string password) : NetworkSocketWrapper(udp ? PROTO_UDP : PROTO_TCP){
this->tcp=tcp;
this->udp=udp;
this->username=username;
this->password=password;
connectedAddress=NULL;
}
NetworkSocketSOCKS5Proxy::~NetworkSocketSOCKS5Proxy(){
delete tcp;
if(connectedAddress)
delete connectedAddress;
}
void NetworkSocketSOCKS5Proxy::Send(NetworkPacket *packet){
if(protocol==PROTO_TCP){
tcp->Send(packet);
}else if(protocol==PROTO_UDP){
unsigned char buf[1500];
BufferOutputStream out(buf, sizeof(buf));
out.WriteInt16(0); // RSV
out.WriteByte(0); // FRAG
IPv4Address* v4=dynamic_cast<IPv4Address*>(packet->address);
IPv6Address* v6=dynamic_cast<IPv6Address*>(packet->address);
if(v4){
out.WriteByte(1); // ATYP (IPv4)
out.WriteInt32(v4->GetAddress());
}else{
out.WriteByte(4); // ATYP (IPv6)
out.WriteBytes((unsigned char *) v6->GetAddress(), 16);
}
out.WriteInt16(htons(packet->port));
out.WriteBytes(packet->data, packet->length);
NetworkPacket p;
p.data=buf;
p.length=out.GetLength();
p.address=connectedAddress;
p.port=connectedPort;
p.protocol=PROTO_UDP;
udp->Send(&p);
}
}
void NetworkSocketSOCKS5Proxy::Receive(NetworkPacket *packet){
if(protocol==PROTO_TCP){
tcp->Receive(packet);
}else if(protocol==PROTO_UDP){
unsigned char buf[1500];
NetworkPacket p;
p.data=buf;
p.length=sizeof(buf);
udp->Receive(&p);
if(p.length && p.address && *p.address==*connectedAddress && p.port==connectedPort){
BufferInputStream in(buf, p.length);
in.ReadInt16(); // RSV
in.ReadByte(); // FRAG
unsigned char atyp=in.ReadByte();
if(atyp==1){ // IPv4
lastRecvdV4=IPv4Address((uint32_t) in.ReadInt32());
packet->address=&lastRecvdV4;
}else if(atyp==4){ // IPv6
unsigned char addr[16];
in.ReadBytes(addr, 16);
lastRecvdV6=IPv6Address(addr);
packet->address=&lastRecvdV6;
}
packet->port=ntohs(in.ReadInt16());
if(packet->length>=in.Remaining()){
packet->length=in.Remaining();
in.ReadBytes(packet->data, in.Remaining());
}else{
packet->length=0;
LOGW("socks5: received packet too big");
}
}
}
}
void NetworkSocketSOCKS5Proxy::Open(){
if(protocol==PROTO_UDP){
unsigned char buf[1024];
BufferOutputStream out(buf, sizeof(buf));
out.WriteByte(5); // VER
out.WriteByte(3); // CMD (UDP ASSOCIATE)
out.WriteByte(0); // RSV
out.WriteByte(1); // ATYP (IPv4)
out.WriteInt32(0); // DST.ADDR
out.WriteInt16(0); // DST.PORT
tcp->Send(buf, out.GetLength());
size_t l=tcp->Receive(buf, sizeof(buf));
if(l<2 || tcp->IsFailed()){
LOGW("socks5: udp associate failed");
failed=true;
return;
}
try{
BufferInputStream in(buf, l);
unsigned char ver=in.ReadByte();
unsigned char rep=in.ReadByte();
if(ver!=5){
LOGW("socks5: udp associate: wrong ver in response");
failed=true;
return;
}
if(rep!=0){
LOGW("socks5: udp associate failed with error %02X", rep);
failed=true;
return;
}
in.ReadByte(); // RSV
unsigned char atyp=in.ReadByte();
if(atyp==1){
uint32_t addr=(uint32_t) in.ReadInt32();
connectedAddress=new IPv4Address(addr);
}else if(atyp==3){
unsigned char len=in.ReadByte();
char domain[256];
memset(domain, 0, sizeof(domain));
in.ReadBytes((unsigned char*)domain, len);
LOGD("address type is domain, address=%s", domain);
connectedAddress=ResolveDomainName(std::string(domain));
if(!connectedAddress){
LOGW("socks5: failed to resolve domain name '%s'", domain);
failed=true;
return;
}
}else if(atyp==4){
unsigned char addr[16];
in.ReadBytes(addr, 16);
connectedAddress=new IPv6Address(addr);
}else{
LOGW("socks5: unknown address type %d", atyp);
failed=true;
return;
}
connectedPort=(uint16_t)ntohs(in.ReadInt16());
tcp->SetTimeouts(0, 0);
LOGV("socks5: udp associate successful, given endpoint %s:%d", connectedAddress->ToString().c_str(), connectedPort);
}catch(std::out_of_range& x){
LOGW("socks5: udp associate response parse failed");
failed=true;
}
}
}
void NetworkSocketSOCKS5Proxy::Close(){
tcp->Close();
}
void NetworkSocketSOCKS5Proxy::Connect(NetworkAddress *address, uint16_t port){
if(!failed){
unsigned char buf[1024];
BufferOutputStream out(buf, sizeof(buf));
out.WriteByte(5); // VER
out.WriteByte(1); // CMD (CONNECT)
out.WriteByte(0); // RSV
IPv4Address* v4=dynamic_cast<IPv4Address*>(address);
IPv6Address* v6=dynamic_cast<IPv6Address*>(address);
if(v4){
out.WriteByte(1); // ATYP (IPv4)
out.WriteInt32(v4->GetAddress());
}else if(v6){
out.WriteByte(4); // ATYP (IPv6)
out.WriteBytes((unsigned char*)v6->GetAddress(), 16);
}else{
LOGW("socks5: unknown address type");
failed=true;
return;
}
out.WriteInt16(htons(port)); // DST.PORT
tcp->Send(buf, out.GetLength());
size_t l=tcp->Receive(buf, sizeof(buf));
if(l<2 || tcp->IsFailed()){
LOGW("socks5: connect failed")
failed=true;
return;
}
BufferInputStream in(buf, l);
unsigned char ver=in.ReadByte();
if(ver!=5){
LOGW("socks5: connect: wrong ver in response");
failed=true;
return;
}
unsigned char rep=in.ReadByte();
if(rep!=0){
LOGW("socks5: connect: failed with error %02X", rep);
failed=true;
return;
}
connectedAddress=v4 ? (NetworkAddress*)new IPv4Address(*v4) : (NetworkAddress*)new IPv6Address(*v6);
connectedPort=port;
LOGV("socks5: connect succeeded");
}
}
NetworkSocket *NetworkSocketSOCKS5Proxy::GetWrapped(){
return protocol==PROTO_TCP ? tcp : udp;
}
void NetworkSocketSOCKS5Proxy::InitConnection(){
unsigned char buf[1024];
BufferOutputStream p(buf, sizeof(buf));
p.WriteByte(5); // VER
if(!username.empty()){
p.WriteByte(2); // NMETHODS
p.WriteByte(0); // no auth
p.WriteByte(2); // user/pass
}else{
p.WriteByte(1); // NMETHODS
p.WriteByte(0); // no auth
}
tcp->Send(buf, p.GetLength());
size_t l=tcp->Receive(buf, sizeof(buf));
if(l<2 || tcp->IsFailed()){
failed=true;
return;
}
BufferInputStream in(buf, l);
unsigned char ver=in.ReadByte();
unsigned char chosenMethod=in.ReadByte();
LOGV("socks5: VER=%02X, METHOD=%02X", ver, chosenMethod);
if(ver!=5){
LOGW("socks5: incorrect VER in response");
failed=true;
return;
}
if(chosenMethod==0){
// connected, no further auth needed
}else if(chosenMethod==2 && !username.empty()){
p.Reset();
p.WriteByte(1); // VER
p.WriteByte((unsigned char)(username.length()>255 ? 255 : username.length())); // ULEN
p.WriteBytes((unsigned char*)username.c_str(), username.length()>255 ? 255 : username.length()); // UNAME
p.WriteByte((unsigned char)(password.length()>255 ? 255 : password.length())); // PLEN
p.WriteBytes((unsigned char*)password.c_str(), password.length()>255 ? 255 : password.length()); // PASSWD
tcp->Send(buf, p.GetLength());
l=tcp->Receive(buf, sizeof(buf));
if(l<2 || tcp->IsFailed()){
failed=true;
return;
}
in=BufferInputStream(buf, l);
ver=in.ReadByte();
unsigned char status=in.ReadByte();
LOGV("socks5: auth response VER=%02X, STATUS=%02X", ver, status);
if(ver!=1){
LOGW("socks5: auth response VER is incorrect");
failed=true;
return;
}
if(status!=0){
LOGW("socks5: username/password auth failed");
failed=true;
return;
}
}else{
LOGW("socks5: unsupported auth method");
failed=true;
return;
}
}
bool NetworkSocketSOCKS5Proxy::IsFailed(){
return NetworkSocket::IsFailed() || tcp->IsFailed();
}
NetworkAddress *NetworkSocketSOCKS5Proxy::GetConnectedAddress(){
return connectedAddress;
}
uint16_t NetworkSocketSOCKS5Proxy::GetConnectedPort(){
return connectedPort;
}

View File

@ -7,6 +7,7 @@
#include <stdint.h>
#include <string>
#include <vector>
namespace tgvoip {
@ -25,7 +26,6 @@ namespace tgvoip {
class NetworkAddress{
public:
virtual std::string ToString()=0;
//virtual sockaddr& ToSockAddr(uint16_t port)=0;
bool operator==(const NetworkAddress& other);
bool operator!=(const NetworkAddress& other);
};
@ -64,20 +64,37 @@ namespace tgvoip {
};
typedef struct NetworkPacket NetworkPacket;
class SocketSelectCanceller{
public:
virtual ~SocketSelectCanceller();
virtual void CancelSelect()=0;
static SocketSelectCanceller* Create();
};
class NetworkSocket{
public:
NetworkSocket();
NetworkSocket(NetworkProtocol protocol);
virtual ~NetworkSocket();
virtual void Send(NetworkPacket* packet)=0;
virtual void Receive(NetworkPacket* packet)=0;
size_t Receive(unsigned char* buffer, size_t len);
size_t Send(unsigned char* buffer, size_t len);
virtual void Open()=0;
virtual void Close()=0;
virtual uint16_t GetLocalPort()=0;
virtual uint16_t GetLocalPort(){ return 0; };
virtual void Connect(NetworkAddress* address, uint16_t port)=0;
virtual std::string GetLocalInterfaceInfo(IPv4Address* inet4addr, IPv6Address* inet6addr);
virtual void OnActiveInterfaceChanged()=0;
bool IsFailed();
virtual void OnActiveInterfaceChanged(){};
virtual NetworkAddress* GetConnectedAddress(){ return NULL; };
virtual uint16_t GetConnectedPort(){ return 0; };
virtual void SetTimeouts(int sendTimeout, int recvTimeout){};
static NetworkSocket* Create();
virtual bool IsFailed();
void SetSocksProxy(IPv4Address* addr, uint16_t port, char* username, char* password);
static NetworkSocket* Create(NetworkProtocol protocol);
static IPv4Address* ResolveDomainName(std::string name);
static bool Select(std::vector<NetworkSocket*>& readFds, std::vector<NetworkSocket*>& errorFds, SocketSelectCanceller* canceller);
protected:
virtual uint16_t GenerateLocalPort();
@ -87,6 +104,67 @@ namespace tgvoip {
double ipv6Timeout;
unsigned char nat64Prefix[12];
bool failed;
NetworkProtocol protocol;
IPv4Address* proxyAddress;
uint16_t proxyPort;
char* proxyUsername;
char* proxyPassword;
};
class NetworkSocketWrapper : public NetworkSocket{
public:
NetworkSocketWrapper(NetworkProtocol protocol) : NetworkSocket(protocol){};
virtual ~NetworkSocketWrapper(){};
virtual NetworkSocket* GetWrapped()=0;
virtual void InitConnection()=0;
};
class NetworkSocketTCPObfuscated : public NetworkSocketWrapper{
public:
NetworkSocketTCPObfuscated(NetworkSocket* wrapped);
virtual ~NetworkSocketTCPObfuscated();
virtual NetworkSocket* GetWrapped();
virtual void InitConnection();
virtual void Send(NetworkPacket *packet);
virtual void Receive(NetworkPacket *packet);
virtual void Open();
virtual void Close();
virtual void Connect(NetworkAddress *address, uint16_t port);
virtual bool IsFailed();
private:
NetworkSocket* wrapped;
TCPO2State recvState;
TCPO2State sendState;
};
class NetworkSocketSOCKS5Proxy : public NetworkSocketWrapper{
public:
NetworkSocketSOCKS5Proxy(NetworkSocket* tcp, NetworkSocket* udp, std::string username, std::string password);
virtual ~NetworkSocketSOCKS5Proxy();
virtual void Send(NetworkPacket *packet);
virtual void Receive(NetworkPacket *packet);
virtual void Open();
virtual void Close();
virtual void Connect(NetworkAddress *address, uint16_t port);
virtual NetworkSocket *GetWrapped();
virtual void InitConnection();
virtual bool IsFailed();
virtual NetworkAddress *GetConnectedAddress();
virtual uint16_t GetConnectedPort();
private:
NetworkSocket* tcp;
NetworkSocket* udp;
std::string username;
std::string password;
NetworkAddress* connectedAddress;
uint16_t connectedPort;
IPv4Address lastRecvdV4;
IPv6Address lastRecvdV6;
};
}

View File

@ -24,7 +24,7 @@ tgvoip::OpusDecoder::OpusDecoder(MediaStreamItf *dst) : semaphore(32, 0){
lastDecodedLen=0;
outputBufferSize=0;
lastDecodedOffset=0;
decodedQueue=new BlockingQueue(33);
decodedQueue=new BlockingQueue<unsigned char*>(33);
bufferPool=new BufferPool(PACKET_SIZE, 32);
echoCanceller=NULL;
frameDuration=20;

View File

@ -37,7 +37,7 @@ private:
static void* StartThread(void* param);
void RunThread();
::OpusDecoder* dec;
BlockingQueue* decodedQueue;
BlockingQueue<unsigned char*>* decodedQueue;
BufferPool* bufferPool;
unsigned char* buffer;
unsigned char* lastDecoded;

View File

@ -42,7 +42,7 @@ private:
uint32_t requestedBitrate;
uint32_t currentBitrate;
tgvoip_thread_t thread;
BlockingQueue queue;
BlockingQueue<unsigned char*> queue;
BufferPool bufferPool;
EchoCanceller* echoCanceller;
int complexity;

File diff suppressed because it is too large Load Diff

View File

@ -29,27 +29,13 @@
#include "CongestionControl.h"
#include "NetworkSocket.h"
#define LIBTGVOIP_VERSION "0.4.2"
#define PKT_INIT 1
#define PKT_INIT_ACK 2
#define PKT_STREAM_STATE 3
#define PKT_STREAM_DATA 4
#define PKT_UPDATE_STREAMS 5
#define PKT_PING 6
#define PKT_PONG 7
#define PKT_STREAM_DATA_X2 8
#define PKT_STREAM_DATA_X3 9
#define PKT_LAN_ENDPOINT 10
#define PKT_NETWORK_CHANGED 11
#define PKT_SWITCH_PREF_RELAY 12
#define PKT_SWITCH_TO_P2P 13
#define PKT_NOP 14
#define LIBTGVOIP_VERSION "1.0"
#define STATE_WAIT_INIT 1
#define STATE_WAIT_INIT_ACK 2
#define STATE_ESTABLISHED 3
#define STATE_FAILED 4
#define STATE_RECONNECTING 5
#define TGVOIP_ERROR_UNKNOWN 0
#define TGVOIP_ERROR_INCOMPATIBLE 1
@ -69,56 +55,19 @@
#define NET_TYPE_DIALUP 10
#define NET_TYPE_OTHER_MOBILE 11
#define IS_MOBILE_NETWORK(x) (x==NET_TYPE_GPRS || x==NET_TYPE_EDGE || x==NET_TYPE_3G || x==NET_TYPE_HSPA || x==NET_TYPE_LTE || x==NET_TYPE_OTHER_MOBILE)
#define PROTOCOL_NAME 0x50567247 // "GrVP" in little endian (reversed here)
#define PROTOCOL_VERSION 3
#define MIN_PROTOCOL_VERSION 3
#define STREAM_DATA_FLAG_LEN16 0x40
#define STREAM_DATA_FLAG_HAS_MORE_FLAGS 0x80
#define STREAM_TYPE_AUDIO 1
#define STREAM_TYPE_VIDEO 2
#define CODEC_OPUS 1
#define EP_TYPE_UDP_P2P_INET 1
#define EP_TYPE_UDP_P2P_LAN 2
#define EP_TYPE_UDP_RELAY 3
#define EP_TYPE_TCP_RELAY 4
/*flags:# voice_call_id:flags.2?int128 in_seq_no:flags.4?int out_seq_no:flags.4?int
* recent_received_mask:flags.5?int proto:flags.3?int extra:flags.1?string raw_data:flags.0?string*/
#define PFLAG_HAS_DATA 1
#define PFLAG_HAS_EXTRA 2
#define PFLAG_HAS_CALL_ID 4
#define PFLAG_HAS_PROTO 8
#define PFLAG_HAS_SEQ 16
#define PFLAG_HAS_RECENT_RECV 32
#define INIT_FLAG_DATA_SAVING_ENABLED 1
#define DATA_SAVING_NEVER 0
#define DATA_SAVING_MOBILE 1
#define DATA_SAVING_ALWAYS 2
#define TLID_DECRYPTED_AUDIO_BLOCK 0xDBF948C1
#define TLID_SIMPLE_AUDIO_BLOCK 0xCC0D0E76
#define TLID_UDP_REFLECTOR_PEER_INFO 0x27D9371C
#define PAD4(x) (4-(x+(x<=253 ? 1 : 0))%4)
#ifdef _WIN32
#undef GetCurrentTime
#endif
inline int pad4(int x){
int r=PAD4(x);
if(r==4)
return 0;
return r;
}
struct voip_stream_t{
int32_t userID;
unsigned char id;
@ -192,6 +141,12 @@ inline bool seqgt(uint32_t s1, uint32_t s2){
namespace tgvoip{
enum{
PROXY_NONE=0,
PROXY_SOCKS5,
//PROXY_HTTP
};
class Endpoint{
friend class VoIPController;
public:
@ -209,6 +164,7 @@ private:
uint32_t lastPingSeq;
double rtts[6];
double averageRTT;
NetworkSocket* socket;
};
class AudioDevice{
@ -231,41 +187,159 @@ public:
VoIPController();
~VoIPController();
/**
* Set the initial endpoints (relays)
* @param endpoints Endpoints converted from phone.PhoneConnection TL objects
* @param allowP2p Whether p2p connectivity is allowed
*/
void SetRemoteEndpoints(std::vector<Endpoint> endpoints, bool allowP2p);
/**
* Initialize and start all the internal threads
*/
void Start();
/**
* Initiate connection
*/
void Connect();
Endpoint& GetRemoteEndpoint();
/**
* Get the debug info string to be displayed in client UI
* @param buffer The buffer to put the string into
* @param len The length of the buffer
*/
void GetDebugString(char* buffer, size_t len);
/**
* Notify the library of network type change
* @param type The new network type
*/
void SetNetworkType(int type);
/**
* Get the average round-trip time for network packets
* @return
*/
double GetAverageRTT();
/**
* Set the function to be called whenever the connection state changes
* @param f
*/
void SetStateCallback(void (*f)(VoIPController*, int));
static double GetCurrentTime();
/**
* Use this field to store any of your context data associated with this call
*/
void* implData;
/**
*
* @param mute
*/
void SetMicMute(bool mute);
/**
*
* @param key
* @param isOutgoing
*/
void SetEncryptionKey(char* key, bool isOutgoing);
/**
*
* @param cfg
*/
void SetConfig(voip_config_t* cfg);
float GetOutputLevel();
void DebugCtl(int request, int param);
/**
*
* @param stats
*/
void GetStats(voip_stats_t* stats);
/**
*
* @return
*/
int64_t GetPreferredRelayID();
/**
*
* @return
*/
int GetLastError();
/**
*
*/
static voip_crypto_functions_t crypto;
/**
*
* @return
*/
static const char* GetVersion();
#ifdef TGVOIP_USE_AUDIO_SESSION
void SetAcquireAudioSession(void (^)(void (^)()));
void ReleaseAudioSession(void (^completion)());
#endif
/**
*
* @return
*/
std::string GetDebugLog();
/**
*
* @param buffer
*/
void GetDebugLog(char* buffer);
size_t GetDebugLogLength();
/**
*
* @return
*/
static std::vector<AudioInputDevice> EnumerateAudioInputs();
/**
*
* @return
*/
static std::vector<AudioOutputDevice> EnumerateAudioOutputs();
/**
*
* @param id
*/
void SetCurrentAudioInput(std::string id);
/**
*
* @param id
*/
void SetCurrentAudioOutput(std::string id);
/**
*
* @return
*/
std::string GetCurrentAudioInputID();
/**
*
* @return
*/
std::string GetCurrentAudioOutputID();
/**
* Set the proxy server to route the data through. Call this before connecting.
* @param protocol PROXY_NONE, PROXY_SOCKS4, or PROXY_SOCKS5
* @param address IP address or domain name of the server
* @param port Port of the server
* @param username Username; empty string for anonymous
* @param password Password; empty string if none
*/
void SetProxy(int protocol, std::string address, uint16_t port, std::string username, std::string password);
private:
struct PendingOutgoingPacket{
uint32_t seq;
unsigned char type;
size_t len;
unsigned char* data;
Endpoint* endpoint;
};
enum{
UDP_UNKNOWN=0,
UDP_PING_SENT,
UDP_AVAILABIE,
UDP_NOT_AVAILABLE
};
static void* StartRecvThread(void* arg);
static void* StartSendThread(void* arg);
static void* StartTickThread(void* arg);
@ -278,17 +352,18 @@ private:
void SetState(int state);
void UpdateAudioOutputState();
void SendInit();
void SendInitAck();
void InitUDPProxy();
void UpdateDataSavingState();
void KDF(unsigned char* msgKey, size_t x, unsigned char* aesKey, unsigned char* aesIv);
BufferOutputStream* GetOutgoingPacketBuffer();
uint32_t WritePacketHeader(BufferOutputStream* s, unsigned char type, uint32_t length);
void WritePacketHeader(uint32_t seq, BufferOutputStream* s, unsigned char type, uint32_t length);
static size_t AudioInputCallback(unsigned char* data, size_t length, void* param);
void SendPublicEndpointsRequest();
void SendPublicEndpointsRequest(Endpoint& relay);
Endpoint* GetEndpointByType(int type);
void SendPacketReliably(unsigned char type, unsigned char* data, size_t len, double retryInterval, double timeout);
uint32_t GenerateOutSeq();
void LogDebugInfo();
void SendUdpPing(Endpoint* endpoint);
int state;
std::vector<Endpoint*> endpoints;
Endpoint* currentEndpoint;
@ -310,9 +385,8 @@ private:
JitterBuffer* jitterBuffer;
OpusDecoder* decoder;
OpusEncoder* encoder;
BlockingQueue* sendQueue;
BlockingQueue<PendingOutgoingPacket>* sendQueue;
EchoCanceller* echoCanceller;
std::vector<BufferOutputStream*> emptySendBuffers;
tgvoip_mutex_t sendBufferMutex;
tgvoip_mutex_t endpointsMutex;
bool stopping;
@ -327,13 +401,10 @@ private:
double rttHistory[32];
bool waitingForAcks;
int networkType;
int audioPacketGrouping;
int audioPacketsWritten;
int dontSendPackets;
int lastError;
bool micMuted;
uint32_t maxBitrate;
BufferOutputStream* currentAudioPacket;
void (*stateCallback)(VoIPController*, int);
std::vector<voip_stream_t*> outgoingStreams;
std::vector<voip_stream_t*> incomingStreams;
@ -359,13 +430,29 @@ private:
bool receivedInitAck;
std::vector<std::string> debugLogs;
bool isOutgoing;
tgvoip::NetworkSocket* socket;
NetworkSocket* udpSocket;
NetworkSocket* realUdpSocket;
FILE* statsDump;
std::string currentAudioInput;
std::string currentAudioOutput;
bool useTCP;
bool useUDP;
bool didAddTcpRelays;
double enableTcpAt;
double setEstablishedAt;
SocketSelectCanceller* selectCanceller;
NetworkSocket* openingTcpSocket;
BufferPool outgoingPacketsBufferPool;
int udpConnectivityState;
double lastUdpPingTime;
int udpPingCount;
int proxyProtocol;
std::string proxyAddress;
uint16_t proxyPort;
std::string proxyUsername;
std::string proxyPassword;
IPv4Address* resolvedProxyAddress;
/*** server config values ***/
uint32_t maxAudioBitrate;
@ -382,24 +469,25 @@ private:
double relaySwitchThreshold;
double p2pToRelaySwitchThreshold;
double relayToP2pSwitchThreshold;
double reconnectingTimeout;
#ifdef TGVOIP_USE_AUDIO_SESSION
void (^acquireAudioSession)(void (^)());
bool needNotifyAcquiredAudioSession;
void (^acquireAudioSession)(void (^)());
bool needNotifyAcquiredAudioSession;
#endif
public:
#ifdef __APPLE__
static double machTimebase;
static uint64_t machTimestart;
static double machTimebase;
static uint64_t machTimestart;
#if TARGET_OS_IPHONE
// temporary fix for nasty linking errors
void SetRemoteEndpoints(voip_legacy_endpoint_t* buffer, size_t count, bool allowP2P);
// temporary fix for nasty linking errors
void SetRemoteEndpoints(voip_legacy_endpoint_t* buffer, size_t count, bool allowP2P);
#endif
#endif
#ifdef _WIN32
static int64_t win32TimeScale;
static bool didInitWin32TimeScale;
static int64_t win32TimeScale;
static bool didInitWin32TimeScale;
#endif
};

View File

@ -6,7 +6,6 @@
#include <jni.h>
#include <string.h>
#include <wchar.h>
#include <map>
#include <string>
#include <vector>
@ -88,6 +87,18 @@ extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_native
((VoIPController*)(intptr_t)inst)->Connect();
}
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetProxy(JNIEnv* env, jobject thiz, jlong inst, jstring _address, jint port, jstring _username, jstring _password){
const char* address=env->GetStringUTFChars(_address, NULL);
const char* username=_username ? env->GetStringUTFChars(_username, NULL) : NULL;
const char* password=_password ? env->GetStringUTFChars(_password, NULL) : NULL;
((VoIPController*)(intptr_t)inst)->SetProxy(PROXY_SOCKS5, address, (uint16_t)port, username ? username : "", password ? password : "");
env->ReleaseStringUTFChars(_address, address);
if(username)
env->ReleaseStringUTFChars(_username, username);
if(password)
env->ReleaseStringUTFChars(_password, password);
}
extern "C" JNIEXPORT void Java_org_telegram_messenger_voip_VoIPController_nativeSetEncryptionKey(JNIEnv* env, jobject thiz, jlong inst, jbyteArray key, jboolean isOutgoing){
jbyte* akey=env->GetByteArrayElements(key, NULL);
((VoIPController*)(intptr_t)inst)->SetEncryptionKey((char *) akey, isOutgoing);

View File

@ -132,6 +132,7 @@
<AdditionalOptions>/bigobj %(AdditionalOptions)</AdditionalOptions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>webrtc_dsp;../TelegramClient/TelegramClient.Opus/opus/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<RuntimeTypeInfo>true</RuntimeTypeInfo>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>

View File

@ -56,6 +56,8 @@
69791A4E1EE8262400BB85FB /* NetworkSocketPosix.h in Headers */ = {isa = PBXBuildFile; fileRef = 69791A4C1EE8262400BB85FB /* NetworkSocketPosix.h */; };
69791A571EE8272A00BB85FB /* Resampler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 69791A551EE8272A00BB85FB /* Resampler.cpp */; };
69791A581EE8272A00BB85FB /* Resampler.h in Headers */ = {isa = PBXBuildFile; fileRef = 69791A561EE8272A00BB85FB /* Resampler.h */; };
69960A041EF85C2900F9D091 /* DarwinSpecific.h in Headers */ = {isa = PBXBuildFile; fileRef = 69960A021EF85C2900F9D091 /* DarwinSpecific.h */; };
69960A051EF85C2900F9D091 /* DarwinSpecific.mm in Sources */ = {isa = PBXBuildFile; fileRef = 69960A031EF85C2900F9D091 /* DarwinSpecific.mm */; };
69A6DD941E95EC7700000E69 /* array_view.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A6DD011E95EC7700000E69 /* array_view.h */; };
69A6DD951E95EC7700000E69 /* atomicops.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A6DD021E95EC7700000E69 /* atomicops.h */; };
69A6DD961E95EC7700000E69 /* basictypes.h in Headers */ = {isa = PBXBuildFile; fileRef = 69A6DD031E95EC7700000E69 /* basictypes.h */; };
@ -235,6 +237,13 @@
remoteGlobalIDString = D020FB0A1D99637100F279AA;
remoteInfo = LegacyDatabase;
};
69960A0D1EF85C2900F9D091 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 692AB9071E675E8800706ACC /* Telegraph.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 099120C01EEAA63400F1366E;
remoteInfo = Widget;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
@ -288,6 +297,8 @@
69791A4C1EE8262400BB85FB /* NetworkSocketPosix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkSocketPosix.h; path = os/posix/NetworkSocketPosix.h; sourceTree = SOURCE_ROOT; };
69791A551EE8272A00BB85FB /* Resampler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Resampler.cpp; sourceTree = "<group>"; };
69791A561EE8272A00BB85FB /* Resampler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Resampler.h; sourceTree = "<group>"; };
69960A021EF85C2900F9D091 /* DarwinSpecific.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DarwinSpecific.h; sourceTree = "<group>"; };
69960A031EF85C2900F9D091 /* DarwinSpecific.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DarwinSpecific.mm; sourceTree = "<group>"; };
69A6DD011E95EC7700000E69 /* array_view.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = array_view.h; sourceTree = "<group>"; };
69A6DD021E95EC7700000E69 /* atomicops.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = atomicops.h; sourceTree = "<group>"; };
69A6DD031E95EC7700000E69 /* basictypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = basictypes.h; sourceTree = "<group>"; };
@ -522,6 +533,8 @@
692AB8C31E6759DD00706ACC /* AudioUnitIO.h */,
692AB8C41E6759DD00706ACC /* TGLogWrapper.h */,
692AB8C51E6759DD00706ACC /* TGLogWrapper.m */,
69960A021EF85C2900F9D091 /* DarwinSpecific.h */,
69960A031EF85C2900F9D091 /* DarwinSpecific.mm */,
);
path = darwin;
sourceTree = "<group>";
@ -546,6 +559,7 @@
692AB9171E675E8800706ACC /* watchkitapp Extension.appex */,
692AB9191E675E8800706ACC /* SiriIntents.appex */,
692AB91B1E675E8800706ACC /* LegacyDatabase.framework */,
69960A0E1EF85C2900F9D091 /* Widget.appex */,
);
name = Products;
sourceTree = "<group>";
@ -930,6 +944,7 @@
69A6DD9A1E95EC7700000E69 /* safe_compare.h in Headers */,
69A6DDEF1E95EC7700000E69 /* digital_agc.h in Headers */,
69A6DDF21E95EC7700000E69 /* apm_data_dumper.h in Headers */,
69960A041EF85C2900F9D091 /* DarwinSpecific.h in Headers */,
69A6DDC21E95EC7700000E69 /* spl_inl_mips.h in Headers */,
69791A581EE8272A00BB85FB /* Resampler.h in Headers */,
692AB8DB1E6759DD00706ACC /* EchoCanceller.h in Headers */,
@ -1045,6 +1060,13 @@
remoteRef = 692AB91A1E675E8800706ACC /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
69960A0E1EF85C2900F9D091 /* Widget.appex */ = {
isa = PBXReferenceProxy;
fileType = "wrapper.app-extension";
path = Widget.appex;
remoteRef = 69960A0D1EF85C2900F9D091 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
@ -1075,6 +1097,7 @@
69A6DDA41E95EC7700000E69 /* fft4g.c in Sources */,
692AB9021E6759DD00706ACC /* VoIPController.cpp in Sources */,
69A6DDB61E95EC7700000E69 /* energy.c in Sources */,
69960A051EF85C2900F9D091 /* DarwinSpecific.mm in Sources */,
69A6DDA11E95EC7700000E69 /* audio_util.cc in Sources */,
69A6DDE31E95EC7700000E69 /* echo_cancellation.cc in Sources */,
69A6DDD71E95EC7700000E69 /* sqrt_of_one_minus_x_squared.c in Sources */,
@ -1287,7 +1310,6 @@
MACH_O_TYPE = staticlib;
MACOSX_DEPLOYMENT_TARGET = 10.6;
OTHER_CFLAGS = (
"-DTGVOIP_USE_AUDIO_SESSION",
"-DTGVOIP_USE_CUSTOM_CRYPTO",
"-DWEBRTC_APM_DEBUG_DUMP=0",
"-DWEBRTC_POSIX",
@ -1323,7 +1345,6 @@
MACH_O_TYPE = staticlib;
MACOSX_DEPLOYMENT_TARGET = 10.6;
OTHER_CFLAGS = (
"-DTGVOIP_USE_AUDIO_SESSION",
"-DTGVOIP_USE_CUSTOM_CRYPTO",
"-DWEBRTC_APM_DEBUG_DUMP=0",
"-DWEBRTC_POSIX",
@ -1410,7 +1431,6 @@
MACH_O_TYPE = staticlib;
MACOSX_DEPLOYMENT_TARGET = 10.6;
OTHER_CFLAGS = (
"-DTGVOIP_USE_AUDIO_SESSION",
"-DTGVOIP_USE_CUSTOM_CRYPTO",
"-DWEBRTC_APM_DEBUG_DUMP=0",
"-DWEBRTC_POSIX",
@ -1491,7 +1511,6 @@
MACH_O_TYPE = staticlib;
MACOSX_DEPLOYMENT_TARGET = 10.6;
OTHER_CFLAGS = (
"-DTGVOIP_USE_AUDIO_SESSION",
"-DTGVOIP_USE_CUSTOM_CRYPTO",
"-DWEBRTC_APM_DEBUG_DUMP=0",
"-DWEBRTC_POSIX",

View File

@ -19,10 +19,8 @@
#ifdef __APPLE__
#include <TargetConditionals.h>
#if TARGET_OS_OSX
#include "os/darwin/DarwinSpecific.h"
#endif
#endif
FILE* tgvoipLogFile=NULL;
@ -69,11 +67,17 @@ void tgvoip_log_file_write_header(){
char systemVersion[128];
snprintf(systemVersion, sizeof(systemVersion), "%s %s (%s)", sysname.sysname, sysname.release, sysname.version);
#endif
#elif defined(__APPLE__) && TARGET_OS_OSX
#elif defined(__APPLE__)
char osxVer[128];
tgvoip::DarwinSpecific::GetSystemName(osxVer, sizeof(osxVer));
char systemVersion[128];
#if TARGET_OS_OSX
snprintf(systemVersion, sizeof(systemVersion), "OS X %s", osxVer);
#elif TARGET_OS_IPHONE
snprintf(systemVersion, sizeof(systemVersion), "iOS %s", osxVer);
#else
snprintf(systemVersion, sizeof(systemVersion), "Unknown Darwin %s", osxVer);
#endif
#else
const char* systemVersion="Unknown OS";
#endif

View File

@ -37,11 +37,11 @@ void tgvoip_log_file_write_header();
#include "os/darwin/TGLogWrapper.h"
#define LOGV(msg, ...) __tgvoip_call_tglog("V/tgvoip: " msg, ##__VA_ARGS__)
#define LOGD(msg, ...) __tgvoip_call_tglog("D/tgvoip: " msg, ##__VA_ARGS__)
#define LOGI(msg, ...) __tgvoip_call_tglog("I/tgvoip: " msg, ##__VA_ARGS__)
#define LOGW(msg, ...) __tgvoip_call_tglog("W/tgvoip: " msg, ##__VA_ARGS__)
#define LOGE(msg, ...) __tgvoip_call_tglog("E/tgvoip: " msg, ##__VA_ARGS__)
#define LOGV(msg, ...) {__tgvoip_call_tglog("V/tgvoip: " msg, ##__VA_ARGS__); tgvoip_log_file_printf('V', msg, ##__VA_ARGS__);}
#define LOGD(msg, ...) {__tgvoip_call_tglog("D/tgvoip: " msg, ##__VA_ARGS__); tgvoip_log_file_printf('D', msg, ##__VA_ARGS__);}
#define LOGI(msg, ...) {__tgvoip_call_tglog("I/tgvoip: " msg, ##__VA_ARGS__); tgvoip_log_file_printf('I', msg, ##__VA_ARGS__);}
#define LOGW(msg, ...) {__tgvoip_call_tglog("W/tgvoip: " msg, ##__VA_ARGS__); tgvoip_log_file_printf('W', msg, ##__VA_ARGS__);}
#define LOGE(msg, ...) {__tgvoip_call_tglog("E/tgvoip: " msg, ##__VA_ARGS__); tgvoip_log_file_printf('E', msg, ##__VA_ARGS__);}
#elif defined(_WIN32) && defined(_DEBUG)

View File

@ -33,8 +33,13 @@ AudioUnitIO::AudioUnitIO(){
inBufferList.mBuffers[0].mData=malloc(10240);
inBufferList.mBuffers[0].mDataByteSize=10240;
inBufferList.mNumberBuffers=1;
#ifdef TGVOIP_USE_AUDIO_SESSION
if(haveAudioSession)
ProcessAudioSessionAcquired();
#else
haveAudioSession=true;
ProcessAudioSessionAcquired();
#endif
}
AudioUnitIO::~AudioUnitIO(){
@ -98,9 +103,11 @@ void AudioUnitIO::Configure(uint32_t sampleRate, uint32_t bitsPerSample, uint32_
if(configured)
return;
#ifdef TGVOIP_USE_AUDIO_SESSION
runFakeIO=true;
start_thread(fakeIOThread, AudioUnitIO::StartFakeIOThread, this);
set_thread_priority(fakeIOThread, get_thread_max_priority());
#endif
if(haveAudioSession){
ActuallyConfigure(sampleRate, bitsPerSample, channels);

View File

@ -11,7 +11,7 @@
extern "C" {
#endif
void __tgvoip_call_tglog(char* format, ...);
void __tgvoip_call_tglog(const char* format, ...);
#if defined __cplusplus
};

View File

@ -2,9 +2,9 @@
#import <ASCommon.h>
void __tgvoip_call_tglog(char* format, ...){
void __tgvoip_call_tglog(const char* format, ...){
va_list args;
va_start(args, format);
TGLogv([[NSString alloc]initWithCString:format], args);
TGLogv([[NSString alloc]initWithUTF8String:format], args);
va_end(args);
}

View File

@ -21,7 +21,7 @@
using namespace tgvoip;
NetworkSocketPosix::NetworkSocketPosix() : lastRecvdV4(0), lastRecvdV6("::0"){
NetworkSocketPosix::NetworkSocketPosix(NetworkProtocol protocol) : NetworkSocket(protocol), lastRecvdV4(0), lastRecvdV6("::0"){
needUpdateNat64Prefix=true;
nat64Present=false;
switchToV6at=0;
@ -29,16 +29,13 @@ NetworkSocketPosix::NetworkSocketPosix() : lastRecvdV4(0), lastRecvdV6("::0"){
useTCP=false;
closing=false;
int p[2];
int pipeRes=pipe(p);
assert(pipeRes==0);
pipeRead=p[0];
pipeWrite=p[1];
tcpConnectedAddress=NULL;
tcpConnectedPort=0;
}
NetworkSocketPosix::~NetworkSocketPosix(){
close(pipeRead);
close(pipeWrite);
if(tcpConnectedAddress)
delete tcpConnectedAddress;
}
void NetworkSocketPosix::SetMaxPriority(){
@ -67,131 +64,66 @@ 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);
int res;
if(protocol==PROTO_UDP){
sockaddr_in6 addr;
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(needUpdateNat64Prefix && !isV4Available && VoIPController::GetCurrentTime()>switchToV6at && switchToV6at!=0){
LOGV("Updating NAT64 prefix");
nat64Present=false;
addrinfo *addr0;
int res=getaddrinfo("ipv4only.arpa", NULL, NULL, &addr0);
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;
LOGW("Error updating NAT64 prefix: %d / %s", res, gai_strerror(res));
}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){
if(needUpdateNat64Prefix && !isV4Available && VoIPController::GetCurrentTime()>switchToV6at && switchToV6at!=0){
LOGV("Updating NAT64 prefix");
nat64Present=false;
addrinfo* addr0;
int res=getaddrinfo("ipv4only.arpa", NULL, NULL, &addr0);
if(res!=0){
LOGW("Error updating NAT64 prefix: %d / %s", res, gai_strerror(res));
}else{
addrinfo* addrPtr;
unsigned char* addr170=NULL;
unsigned char* addr171=NULL;
for(addrPtr=addr0;addrPtr;addrPtr=addrPtr->ai_next){
if(addrPtr->ai_family==AF_INET6){
sockaddr_in6* translatedAddr=(sockaddr_in6*)addrPtr->ai_addr;
uint32_t v4part=*((uint32_t*)&translatedAddr->sin6_addr.s6_addr[12]);
if(v4part==0xAA0000C0 && !addr170){
addr170=translatedAddr->sin6_addr.s6_addr;
addrinfo *addrPtr;
unsigned char *addr170=NULL;
unsigned char *addr171=NULL;
for(addrPtr=addr0; addrPtr; addrPtr=addrPtr->ai_next){
if(addrPtr->ai_family==AF_INET6){
sockaddr_in6 *translatedAddr=(sockaddr_in6 *) addrPtr->ai_addr;
uint32_t v4part=*((uint32_t *) &translatedAddr->sin6_addr.s6_addr[12]);
if(v4part==0xAA0000C0 && !addr170){
addr170=translatedAddr->sin6_addr.s6_addr;
}
if(v4part==0xAB0000C0 && !addr171){
addr171=translatedAddr->sin6_addr.s6_addr;
}
char buf[INET6_ADDRSTRLEN];
LOGV("Got translated address: %s", inet_ntop(AF_INET6, &translatedAddr->sin6_addr, buf, sizeof(buf)));
}
if(v4part==0xAB0000C0 && !addr171){
addr171=translatedAddr->sin6_addr.s6_addr;
}
char buf[INET6_ADDRSTRLEN];
LOGV("Got translated address: %s", inet_ntop(AF_INET6, &translatedAddr->sin6_addr, buf, sizeof(buf)));
}
if(addr170 && addr171 && memcmp(addr170, addr171, 12)==0){
nat64Present=true;
memcpy(nat64Prefix, addr170, 12);
char buf[INET6_ADDRSTRLEN];
LOGV("Found nat64 prefix from %s", inet_ntop(AF_INET6, addr170, buf, sizeof(buf)));
}else{
LOGV("Didn't find nat64");
}
freeaddrinfo(addr0);
}
if(addr170 && addr171 && memcmp(addr170, addr171, 12)==0){
nat64Present=true;
memcpy(nat64Prefix, addr170, 12);
char buf[INET6_ADDRSTRLEN];
LOGV("Found nat64 prefix from %s", inet_ntop(AF_INET6, addr170, buf, sizeof(buf)));
}else{
LOGV("Didn't find nat64");
}
freeaddrinfo(addr0);
needUpdateNat64Prefix=false;
}
needUpdateNat64Prefix=false;
}
memset(&addr, 0, sizeof(sockaddr_in6));
addr.sin6_family=AF_INET6;
*((uint32_t*)&addr.sin6_addr.s6_addr[12])=v4addr->GetAddress();
if(nat64Present)
memcpy(addr.sin6_addr.s6_addr, nat64Prefix, 12);
else
addr.sin6_addr.s6_addr[11]=addr.sin6_addr.s6_addr[10]=0xFF;
memset(&addr, 0, sizeof(sockaddr_in6));
addr.sin6_family=AF_INET6;
*((uint32_t *) &addr.sin6_addr.s6_addr[12])=v4addr->GetAddress();
if(nat64Present)
memcpy(addr.sin6_addr.s6_addr, nat64Prefix, 12);
else
addr.sin6_addr.s6_addr[11]=addr.sin6_addr.s6_addr[10]=0xFF;
}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);
res=sendto(fd, packet->data, packet->length, 0, (const sockaddr *) &addr, sizeof(addr));
}else{
IPv6Address* v6addr=dynamic_cast<IPv6Address*>(packet->address);
assert(v6addr!=NULL);
memcpy(addr.sin6_addr.s6_addr, v6addr->GetAddress(), 16);
res=send(fd, packet->data, packet->length, 0);
}
addr.sin6_port=htons(packet->port);
char buf[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &addr.sin6_addr, buf, sizeof(buf));
int res=sendto(fd, packet->data, packet->length, 0, (const sockaddr *) &addr, sizeof(addr));
if(res<0){
LOGE("error sending: %d / %s", errno, strerror(errno));
if(errno==ENETUNREACH && !isV4Available && VoIPController::GetCurrentTime()<switchToV6at){
@ -202,130 +134,61 @@ void NetworkSocketPosix::Send(NetworkPacket *packet){
}
void NetworkSocketPosix::Receive(NetworkPacket *packet){
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);
if(protocol==PROTO_UDP){
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;
}
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->protocol=PROTO_UDP;
packet->port=ntohs(srcAddr.sin6_port);
}else if(protocol==PROTO_TCP){
int res=recv(fd, packet->data, packet->length, 0);
if(res<=0){
LOGE("Error receiving from TCP socket: %d / %s", errno, strerror(errno));
failed=true;
}else{
packet->length=(size_t)res;
packet->address=tcpConnectedAddress;
packet->port=tcpConnectedPort;
packet->protocol=PROTO_TCP;
}
}
}
void NetworkSocketPosix::Open(){
if(protocol!=PROTO_UDP)
return;
fd=socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
if(fd<0){
LOGE("error creating socket: %d / %s", errno, strerror(errno));
failed=true;
return;
}
int flag=0;
int res=setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &flag, sizeof(flag));
if(res<0){
LOGE("error enabling dual stack socket: %d / %s", errno, strerror(errno));
failed=true;
return;
}
SetMaxPriority();
@ -352,6 +215,7 @@ void NetworkSocketPosix::Open(){
if(res<0){
LOGE("error binding to port %u: %d / %s", ntohs(addr.sin6_port), errno, strerror(errno));
//SetState(STATE_FAILED);
failed=true;
return;
}
}
@ -367,14 +231,61 @@ void NetworkSocketPosix::Open(){
void NetworkSocketPosix::Close(){
closing=true;
char c=1;
write(pipeWrite, &c, 1);
failed=true;
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::Connect(NetworkAddress *address, uint16_t port){
IPv4Address* v4addr=dynamic_cast<IPv4Address*>(address);
IPv6Address* v6addr=dynamic_cast<IPv6Address*>(address);
sockaddr_in v4;
sockaddr_in6 v6;
sockaddr* addr=NULL;
size_t addrLen=0;
if(v4addr){
v4.sin_family=AF_INET;
v4.sin_addr.s_addr=v4addr->GetAddress();
v4.sin_port=htons(port);
addr=reinterpret_cast<sockaddr*>(&v4);
addrLen=sizeof(v4);
}else if(v6addr){
v6.sin6_family=AF_INET6;
memcpy(v6.sin6_addr.s6_addr, v6addr->GetAddress(), 16);
v6.sin6_flowinfo=0;
v6.sin6_scope_id=0;
v6.sin6_port=htons(port);
addr=reinterpret_cast<sockaddr*>(&v6);
addrLen=sizeof(v6);
}else{
LOGE("Unknown address type in TCP connect");
failed=true;
return;
}
fd=socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
if(fd==0){
LOGE("Error creating TCP socket: %d / %s", errno, strerror(errno));
failed=true;
return;
}
int opt=1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
timeval timeout;
timeout.tv_sec=5;
timeout.tv_usec=0;
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
timeout.tv_sec=60;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
int res=connect(fd, (const sockaddr*) addr, addrLen);
if(res!=0){
LOGW("error connecting TCP socket to %s:%u: %d / %s; %d / %s", address->ToString().c_str(), port, res, strerror(res), errno, strerror(errno));
close(fd);
failed=true;
return;
}
tcpConnectedAddress=v4addr ? (NetworkAddress*)new IPv4Address(*v4addr) : (NetworkAddress*)new IPv6Address(*v6addr);
tcpConnectedPort=port;
LOGI("successfully connected to %s:%d", tcpConnectedAddress->ToString().c_str(), tcpConnectedPort);
}
void NetworkSocketPosix::OnActiveInterfaceChanged(){
@ -469,3 +380,139 @@ void NetworkSocketPosix::StringToV6Address(std::string address, unsigned char *o
inet_pton(AF_INET6, address.c_str(), &addr);
memcpy(out, addr.s6_addr, 16);
}
IPv4Address *NetworkSocketPosix::ResolveDomainName(std::string name){
addrinfo* addr0;
IPv4Address* ret=NULL;
int res=getaddrinfo(name.c_str(), NULL, NULL, &addr0);
if(res!=0){
LOGW("Error updating NAT64 prefix: %d / %s", res, gai_strerror(res));
}else{
addrinfo* addrPtr;
for(addrPtr=addr0;addrPtr;addrPtr=addrPtr->ai_next){
if(addrPtr->ai_family==AF_INET){
sockaddr_in* addr=(sockaddr_in*)addrPtr->ai_addr;
ret=new IPv4Address(addr->sin_addr.s_addr);
break;
}
}
freeaddrinfo(addr0);
}
return ret;
}
NetworkAddress *NetworkSocketPosix::GetConnectedAddress(){
return tcpConnectedAddress;
}
uint16_t NetworkSocketPosix::GetConnectedPort(){
return tcpConnectedPort;
}
void NetworkSocketPosix::SetTimeouts(int sendTimeout, int recvTimeout){
timeval timeout;
timeout.tv_sec=sendTimeout;
timeout.tv_usec=0;
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
timeout.tv_sec=recvTimeout;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
}
bool NetworkSocketPosix::Select(std::vector<NetworkSocket *> &readFds, std::vector<NetworkSocket *> &errorFds, SocketSelectCanceller* _canceller){
fd_set readSet;
fd_set errorSet;
FD_ZERO(&readSet);
FD_ZERO(&errorSet);
SocketSelectCancellerPosix* canceller=dynamic_cast<SocketSelectCancellerPosix*>(_canceller);
if(canceller)
FD_SET(canceller->pipeRead, &readSet);
int maxfd=canceller ? canceller->pipeRead : 0;
for(std::vector<NetworkSocket*>::iterator itr=readFds.begin();itr!=readFds.end();++itr){
int sfd=GetDescriptorFromSocket(*itr);
if(sfd==0){
LOGW("can't select on one of sockets because it's not a NetworkSocketPosix instance");
continue;
}
FD_SET(sfd, &readSet);
if(maxfd<sfd)
maxfd=sfd;
}
bool anyFailed=false;
for(std::vector<NetworkSocket*>::iterator itr=errorFds.begin();itr!=errorFds.end();++itr){
int sfd=GetDescriptorFromSocket(*itr);
if(sfd==0){
LOGW("can't select on one of sockets because it's not a NetworkSocketPosix instance");
continue;
}
anyFailed |= (*itr)->IsFailed();
FD_SET(sfd, &errorSet);
if(maxfd<sfd)
maxfd=sfd;
}
int res=select(maxfd+1, &readSet, NULL, &errorSet, NULL);
if(canceller && FD_ISSET(canceller->pipeRead, &readSet) && !anyFailed){
char c;
read(canceller->pipeRead, &c, 1);
return false;
}else if(anyFailed){
FD_ZERO(&readSet);
FD_ZERO(&errorSet);
}
std::vector<NetworkSocket*>::iterator itr=readFds.begin();
while(itr!=readFds.end()){
int sfd=GetDescriptorFromSocket(*itr);
if(sfd==0 || !FD_ISSET(sfd, &readSet)){
itr=readFds.erase(itr);
}else{
++itr;
}
}
itr=errorFds.begin();
while(itr!=errorFds.end()){
int sfd=GetDescriptorFromSocket(*itr);
if((sfd==0 || !FD_ISSET(sfd, &errorSet)) && !(*itr)->IsFailed()){
itr=errorFds.erase(itr);
}else{
++itr;
}
}
//LOGV("select fds left: read=%d, error=%d", readFds.size(), errorFds.size());
return readFds.size()>0 || errorFds.size()>0;
}
SocketSelectCancellerPosix::SocketSelectCancellerPosix(){
int p[2];
int pipeRes=pipe(p);
assert(pipeRes==0);
pipeRead=p[0];
pipeWrite=p[1];
}
SocketSelectCancellerPosix::~SocketSelectCancellerPosix(){
close(pipeRead);
close(pipeWrite);
}
void SocketSelectCancellerPosix::CancelSelect(){
char c=1;
write(pipeWrite, &c, 1);
}
int NetworkSocketPosix::GetDescriptorFromSocket(NetworkSocket *socket){
NetworkSocketPosix* sp=dynamic_cast<NetworkSocketPosix*>(socket);
if(sp)
return sp->fd;
NetworkSocketWrapper* sw=dynamic_cast<NetworkSocketWrapper*>(socket);
if(sw)
return GetDescriptorFromSocket(sw->GetWrapped());
return 0;
}

View File

@ -14,22 +14,26 @@
namespace tgvoip {
struct TCPSocket{
int fd;
IPv4Address address;
uint16_t port;
TCPO2State recvState;
TCPO2State sendState;
class SocketSelectCancellerPosix : public SocketSelectCanceller{
friend class NetworkSocketPosix;
public:
SocketSelectCancellerPosix();
virtual ~SocketSelectCancellerPosix();
virtual void CancelSelect();
private:
int pipeRead;
int pipeWrite;
};
class NetworkSocketPosix : public NetworkSocket{
public:
NetworkSocketPosix();
NetworkSocketPosix(NetworkProtocol protocol);
virtual ~NetworkSocketPosix();
virtual void Send(NetworkPacket* packet);
virtual void Receive(NetworkPacket* packet);
virtual void Open();
virtual void Close();
virtual void Connect(NetworkAddress* address, uint16_t port);
virtual std::string GetLocalInterfaceInfo(IPv4Address* v4addr, IPv6Address* v6addr);
virtual void OnActiveInterfaceChanged();
virtual uint16_t GetLocalPort();
@ -38,13 +42,21 @@ public:
static std::string V6AddressToString(unsigned char address[16]);
static uint32_t StringToV4Address(std::string address);
static void StringToV6Address(std::string address, unsigned char* out);
static IPv4Address* ResolveDomainName(std::string name);
static bool Select(std::vector<NetworkSocket*>& readFds, std::vector<NetworkSocket*>& errorFds, SocketSelectCanceller* canceller);
virtual NetworkAddress *GetConnectedAddress();
virtual uint16_t GetConnectedPort();
virtual void SetTimeouts(int sendTimeout, int recvTimeout);
protected:
virtual void SetMaxPriority();
private:
static int GetDescriptorFromSocket(NetworkSocket* socket);
int fd;
std::vector<TCPSocket> tcpSockets;
bool needUpdateNat64Prefix;
bool nat64Present;
double switchToV6at;
@ -53,8 +65,8 @@ private:
bool closing;
IPv4Address lastRecvdV4;
IPv6Address lastRecvdV6;
int pipeRead;
int pipeWrite;
NetworkAddress* tcpConnectedAddress;
uint16_t tcpConnectedPort;
};
}

View File

@ -347,10 +347,8 @@ void AudioInputWASAPI::RunThread() {
}else if(waitResult==WAIT_OBJECT_0+2){ // audioSamplesReadyEvent
if(!audioClient)
continue;
if(bufferSize==0){
res=audioClient->GetBufferSize(&bufferSize);
CHECK_RES(res, "audioClient->GetBufferSize");
}
res=captureClient->GetNextPacketSize(&bufferSize);
CHECK_RES(res, "captureClient->GetNextPacketSize");
BYTE* data;
uint32_t framesAvailable=bufferSize;
DWORD flags;

View File

@ -30,9 +30,9 @@ SymmetricKeyAlgorithmProvider^ MicrosoftCryptoImpl::aesKeyProvider;
};*/
VoIPControllerWrapper::VoIPControllerWrapper(){
VoIPController::crypto.aes_ctr_encrypt=MicrosoftCryptoImpl::AesCtrEncrypt;
VoIPController::crypto.aes_ige_decrypt=MicrosoftCryptoImpl::AesIgeDecrypt;
VoIPController::crypto.aes_ige_encrypt=MicrosoftCryptoImpl::AesIgeEncrypt;
VoIPController::crypto.aes_ctr_encrypt = MicrosoftCryptoImpl::AesCtrEncrypt;
VoIPController::crypto.sha1=MicrosoftCryptoImpl::SHA1;
VoIPController::crypto.sha256=MicrosoftCryptoImpl::SHA256;
VoIPController::crypto.rand_bytes=MicrosoftCryptoImpl::RandBytes;
@ -55,29 +55,28 @@ void VoIPControllerWrapper::Connect(){
controller->Connect();
}
void VoIPControllerWrapper::SetPublicEndpoints(Windows::Foundation::Collections::IIterable<libtgvoip::Endpoint^>^ endpoints, bool allowP2P){
Windows::Foundation::Collections::IIterator<libtgvoip::Endpoint^>^ iterator=endpoints->First();
void VoIPControllerWrapper::SetPublicEndpoints(const Platform::Array<libtgvoip::Endpoint^>^ endpoints, bool allowP2P){
std::vector<tgvoip::Endpoint> eps;
while(iterator->HasCurrent){
libtgvoip::Endpoint^ _ep=iterator->Current;
for (int i = 0; i < endpoints->Length; i++)
{
libtgvoip::Endpoint^ _ep = endpoints[i];
tgvoip::Endpoint ep;
ep.id=_ep->id;
ep.type=EP_TYPE_UDP_RELAY;
ep.id = _ep->id;
ep.type = EP_TYPE_UDP_RELAY;
char buf[128];
if(_ep->ipv4){
if (_ep->ipv4){
WideCharToMultiByte(CP_UTF8, 0, _ep->ipv4->Data(), -1, buf, sizeof(buf), NULL, NULL);
ep.address=IPv4Address(buf);
ep.address = IPv4Address(buf);
}
if(_ep->ipv6){
if (_ep->ipv6){
WideCharToMultiByte(CP_UTF8, 0, _ep->ipv6->Data(), -1, buf, sizeof(buf), NULL, NULL);
ep.v6address=IPv6Address(buf);
ep.v6address = IPv6Address(buf);
}
ep.port=_ep->port;
if(_ep->peerTag->Length!=16)
ep.port = _ep->port;
if (_ep->peerTag->Length != 16)
throw ref new Platform::InvalidArgumentException("Peer tag must be exactly 16 bytes long");
memcpy(ep.peerTag, _ep->peerTag->Data, 16);
eps.push_back(ep);
iterator->MoveNext();
}
controller->SetRemoteEndpoints(eps, allowP2P);
}
@ -181,11 +180,6 @@ void VoIPControllerWrapper::UpdateServerConfig(Platform::String^ json){
}
void VoIPControllerWrapper::SwitchSpeaker(bool external){
#if WINAPI_FAMILY!=WINAPI_FAMILY_PHONE_APP
if (!Windows::Foundation::Metadata::ApiInformation::IsApiContractPresent("Windows.Phone.PhoneContract", 1)){
return;
}
#endif
auto routingManager = AudioRoutingManager::GetDefault();
if (external){
routingManager->SetAudioEndpoint(AudioRoutingEndpoint::Speakerphone);
@ -200,41 +194,6 @@ void VoIPControllerWrapper::SwitchSpeaker(bool external){
}
}
#define GETU32(pt) (((uint32_t)(pt)[0] << 24) ^ ((uint32_t)(pt)[1] << 16) ^ ((uint32_t)(pt)[2] << 8) ^ ((uint32_t)(pt)[3]))
#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); } typedef uint8_t u8;
#define L_ENDIAN /* increment counter (128-bit int) by 2^64 */
static void AES_ctr128_inc(unsigned char *counter)
{
unsigned long c; /* Grab 3rd dword of counter and increment */
#ifdef L_ENDIAN c = GETU32(counter + 8); c++; PUTU32(counter + 8, c);
#else c = GETU32(counter + 4); c++; PUTU32(counter + 4, c);
#endif /* if no overflow, we're done */ if (c) return; /* Grab top dword of counter and increment */
#ifdef L_ENDIAN c = GETU32(counter + 12); c++; PUTU32(counter + 12, c);
#else c = GETU32(counter + 0); c++; PUTU32(counter + 0, c);
#endif
}
void MicrosoftCryptoImpl::AesCtrEncrypt(uint8_t* inout, size_t len, uint8_t* key, uint8_t* counter, uint8_t* ecount_buf, uint32_t* num)
{
unsigned int n;
unsigned long l=len;
IBuffer^ keybuf = IBufferFromPtr(key, 32);
CryptographicKey^ _key = aesKeyProvider->CreateSymmetricKey(keybuf);
n=*num;
while (l--){
if (n==0)
{
IBuffer^ inbuf=IBufferFromPtr(counter, 16);
IBuffer^ outbuf=CryptographicEngine::Encrypt(_key, inbuf, nullptr);
IBufferToPtr(outbuf, 16, ecount_buf);
AES_ctr128_inc(counter);
}
*inout=*(inout++)^ecount_buf[n];
n=(n+1)%16;
}
*num=n;
}
void MicrosoftCryptoImpl::AesIgeEncrypt(uint8_t* in, uint8_t* out, size_t len, uint8_t* key, uint8_t* iv){
IBuffer^ keybuf=IBufferFromPtr(key, 32);
CryptographicKey^ _key=aesKeyProvider->CreateSymmetricKey(keybuf);
@ -291,6 +250,72 @@ void MicrosoftCryptoImpl::AesIgeDecrypt(uint8_t* in, uint8_t* out, size_t len, u
}
}
#define GETU32(pt) (((uint32_t)(pt)[0] << 24) ^ ((uint32_t)(pt)[1] << 16) ^ ((uint32_t)(pt)[2] << 8) ^ ((uint32_t)(pt)[3]))
#define PUTU32(ct, st) { (ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); (ct)[2] = (u8)((st) >> 8); (ct)[3] = (u8)(st); }
typedef uint8_t u8;
#define L_ENDIAN
/* increment counter (128-bit int) by 2^64 */
static void AES_ctr128_inc(unsigned char *counter) {
unsigned long c;
/* Grab 3rd dword of counter and increment */
#ifdef L_ENDIAN
c = GETU32(counter + 8);
c++;
PUTU32(counter + 8, c);
#else
c = GETU32(counter + 4);
c++;
PUTU32(counter + 4, c);
#endif
/* if no overflow, we're done */
if (c)
return;
/* Grab top dword of counter and increment */
#ifdef L_ENDIAN
c = GETU32(counter + 12);
c++;
PUTU32(counter + 12, c);
#else
c = GETU32(counter + 0);
c++;
PUTU32(counter + 0, c);
#endif
}
void MicrosoftCryptoImpl::AesCtrEncrypt(uint8_t* inout, size_t len, uint8_t* key, uint8_t* counter, uint8_t* ecount_buf, uint32_t* num){
unsigned int n;
unsigned long l = len;
//assert(in && out && key && counter && num);
//assert(*num < AES_BLOCK_SIZE);
IBuffer^ keybuf = IBufferFromPtr(key, 32);
CryptographicKey^ _key = aesKeyProvider->CreateSymmetricKey(keybuf);
n = *num;
while (l--) {
if (n == 0) {
IBuffer^ inbuf = IBufferFromPtr(counter, 16);
IBuffer^ outbuf = CryptographicEngine::Encrypt(_key, inbuf, nullptr);
IBufferToPtr(outbuf, 16, ecount_buf);
//AES_encrypt(counter, ecount_buf, key);
AES_ctr128_inc(counter);
}
*inout = *(inout++) ^ ecount_buf[n];
n = (n + 1) % 16;
}
*num = n;
}
void MicrosoftCryptoImpl::SHA1(uint8_t* msg, size_t len, uint8_t* out){
//EnterCriticalSection(&hashMutex);

View File

@ -63,7 +63,7 @@ namespace libtgvoip{
virtual ~VoIPControllerWrapper();
void Start();
void Connect();
void SetPublicEndpoints(Windows::Foundation::Collections::IIterable<Endpoint^>^ endpoints, bool allowP2P);
void SetPublicEndpoints(const Platform::Array<Endpoint^>^ endpoints, bool allowP2P);
void SetNetworkType(NetworkType type);
void SetStateCallback(IStateCallback^ callback);
void SetMicMute(bool mute);
@ -86,9 +86,9 @@ namespace libtgvoip{
ref class MicrosoftCryptoImpl{
public:
static void AesCtrEncrypt(uint8_t* inout, size_t len, uint8_t* key, uint8_t* counter, uint8_t* ecount_buf, uint32_t* num);
static void AesIgeEncrypt(uint8_t* in, uint8_t* out, size_t len, uint8_t* key, uint8_t* iv);
static void AesIgeDecrypt(uint8_t* in, uint8_t* out, size_t len, uint8_t* key, uint8_t* iv);
static void AesCtrEncrypt(uint8_t* inout, size_t len, uint8_t* key, uint8_t* iv, uint8_t* ecount, uint32_t* num);
static void SHA1(uint8_t* msg, size_t len, uint8_t* out);
static void SHA256(uint8_t* msg, size_t len, uint8_t* out);
static void RandBytes(uint8_t* buffer, size_t len);

View File

@ -18,7 +18,7 @@
using namespace tgvoip;
NetworkSocketWinsock::NetworkSocketWinsock() : lastRecvdV4(0), lastRecvdV6("::0"){
NetworkSocketWinsock::NetworkSocketWinsock(NetworkProtocol protocol) : NetworkSocket(protocol), lastRecvdV4(0), lastRecvdV6("::0"){
needUpdateNat64Prefix=true;
nat64Present=false;
switchToV6at=0;
@ -35,10 +35,12 @@ NetworkSocketWinsock::NetworkSocketWinsock() : lastRecvdV4(0), lastRecvdV6("::0"
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
LOGD("Initialized winsock, version %d.%d", wsaData.wHighVersion, wsaData.wVersion);
tcpConnectedAddress=NULL;
}
NetworkSocketWinsock::~NetworkSocketWinsock(){
if(tcpConnectedAddress)
delete tcpConnectedAddress;
}
void NetworkSocketWinsock::SetMaxPriority(){
@ -46,148 +48,81 @@ 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");
}
if(!packet || !packet->address){
LOGW("tried to send null packet");
return;
}
sockaddr_in6 addr;
IPv4Address* v4addr=dynamic_cast<IPv4Address*>(packet->address);
if(v4addr){
if(!isAtLeastVista){
sockaddr_in _addr;
_addr.sin_family=AF_INET;
_addr.sin_addr.s_addr=v4addr->GetAddress();
_addr.sin_port=htons(packet->port);
int res=sendto(fd, (char*)packet->data, packet->length, 0, (sockaddr*)&_addr, sizeof(_addr));
if(res==SOCKET_ERROR){
int error=WSAGetLastError();
LOGE("error sending: %d", error);
}
return;
}
if(needUpdateNat64Prefix && !isV4Available && VoIPController::GetCurrentTime()>switchToV6at && switchToV6at!=0){
LOGV("Updating NAT64 prefix");
nat64Present=false;
addrinfo* addr0;
int res=getaddrinfo("ipv4only.arpa", NULL, NULL, &addr0);
if(res!=0){
LOGW("Error updating NAT64 prefix: %d / %s", res, gai_strerror(res));
}else{
addrinfo* addrPtr;
unsigned char* addr170=NULL;
unsigned char* addr171=NULL;
for(addrPtr=addr0;addrPtr;addrPtr=addrPtr->ai_next){
if(addrPtr->ai_family==AF_INET6){
sockaddr_in6* translatedAddr=(sockaddr_in6*)addrPtr->ai_addr;
uint32_t v4part=*((uint32_t*)&translatedAddr->sin6_addr.s6_addr[12]);
if(v4part==0xAA0000C0 && !addr170){
addr170=translatedAddr->sin6_addr.s6_addr;
int res;
if(protocol==PROTO_UDP){
IPv4Address *v4addr=dynamic_cast<IPv4Address *>(packet->address);
if(isAtLeastVista){
sockaddr_in6 addr;
if(v4addr){
if(needUpdateNat64Prefix && !isV4Available && VoIPController::GetCurrentTime()>switchToV6at && switchToV6at!=0){
LOGV("Updating NAT64 prefix");
nat64Present=false;
addrinfo *addr0;
int res=getaddrinfo("ipv4only.arpa", NULL, NULL, &addr0);
if(res!=0){
LOGW("Error updating NAT64 prefix: %d / %s", res, gai_strerror(res));
}else{
addrinfo *addrPtr;
unsigned char *addr170=NULL;
unsigned char *addr171=NULL;
for(addrPtr=addr0; addrPtr; addrPtr=addrPtr->ai_next){
if(addrPtr->ai_family==AF_INET6){
sockaddr_in6 *translatedAddr=(sockaddr_in6 *) addrPtr->ai_addr;
uint32_t v4part=*((uint32_t *) &translatedAddr->sin6_addr.s6_addr[12]);
if(v4part==0xAA0000C0 && !addr170){
addr170=translatedAddr->sin6_addr.s6_addr;
}
if(v4part==0xAB0000C0 && !addr171){
addr171=translatedAddr->sin6_addr.s6_addr;
}
char buf[INET6_ADDRSTRLEN];
//LOGV("Got translated address: %s", inet_ntop(AF_INET6, &translatedAddr->sin6_addr, buf, sizeof(buf)));
}
}
if(v4part==0xAB0000C0 && !addr171){
addr171=translatedAddr->sin6_addr.s6_addr;
if(addr170 && addr171 && memcmp(addr170, addr171, 12)==0){
nat64Present=true;
memcpy(nat64Prefix, addr170, 12);
char buf[INET6_ADDRSTRLEN];
//LOGV("Found nat64 prefix from %s", inet_ntop(AF_INET6, addr170, buf, sizeof(buf)));
}else{
LOGV("Didn't find nat64");
}
char buf[INET6_ADDRSTRLEN];
//LOGV("Got translated address: %s", inet_ntop(AF_INET6, &translatedAddr->sin6_addr, buf, sizeof(buf)));
freeaddrinfo(addr0);
}
needUpdateNat64Prefix=false;
}
if(addr170 && addr171 && memcmp(addr170, addr171, 12)==0){
nat64Present=true;
memcpy(nat64Prefix, addr170, 12);
char buf[INET6_ADDRSTRLEN];
//LOGV("Found nat64 prefix from %s", inet_ntop(AF_INET6, addr170, buf, sizeof(buf)));
}else{
LOGV("Didn't find nat64");
}
freeaddrinfo(addr0);
}
needUpdateNat64Prefix=false;
}
memset(&addr, 0, sizeof(sockaddr_in6));
addr.sin6_family=AF_INET6;
*((uint32_t*)&addr.sin6_addr.s6_addr[12])=v4addr->GetAddress();
if(nat64Present)
memcpy(addr.sin6_addr.s6_addr, nat64Prefix, 12);
else
addr.sin6_addr.s6_addr[11]=addr.sin6_addr.s6_addr[10]=0xFF;
memset(&addr, 0, sizeof(sockaddr_in6));
addr.sin6_family=AF_INET6;
*((uint32_t *) &addr.sin6_addr.s6_addr[12])=v4addr->GetAddress();
if(nat64Present)
memcpy(addr.sin6_addr.s6_addr, nat64Prefix, 12);
else
addr.sin6_addr.s6_addr[11]=addr.sin6_addr.s6_addr[10]=0xFF;
}else{
IPv6Address* v6addr=dynamic_cast<IPv6Address*>(packet->address);
assert(v6addr!=NULL);
if(!isAtLeastVista){
return;
}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);
res=sendto(fd, (const char*)packet->data, packet->length, 0, (const sockaddr *) &addr, sizeof(addr));
}else if(v4addr){
sockaddr_in addr;
addr.sin_addr.s_addr=v4addr->GetAddress();
addr.sin_port=htons(packet->port);
addr.sin_family=AF_INET;
res=sendto(fd, (const char*)packet->data, packet->length, 0, (const sockaddr*)&addr, sizeof(addr));
}
}else{
res=send(fd, (const char*)packet->data, packet->length, 0);
}
addr.sin6_port=htons(packet->port);
//WSABUF wsaBuf;
//wsaBuf.buf=(char*) packet->data;
//wsaBuf.len=packet->length;
//int res=WSASendTo(fd, &wsaBuf, 1, NULL, 0, (const sockaddr*)&addr, sizeof(addr), NULL, NULL);
int res=sendto(fd, (char*)packet->data, packet->length, 0, (sockaddr*)&addr, sizeof(addr));
if(res==SOCKET_ERROR){
int error=WSAGetLastError();
LOGE("error sending: %d", error);
if(error==WSAENETUNREACH && !isV4Available && VoIPController::GetCurrentTime()<switchToV6at){
LOGE("error sending: %d", WSAGetLastError());
if(errno==ENETUNREACH && !isV4Available && VoIPController::GetCurrentTime()<switchToV6at){
switchToV6at=VoIPController::GetCurrentTime();
LOGI("Network unreachable, trying NAT64");
}
@ -195,223 +130,148 @@ void NetworkSocketWinsock::Send(NetworkPacket *packet){
}
void NetworkSocketWinsock::Receive(NetworkPacket *packet){
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(FD_ISSET(fd, &readSet) || FD_ISSET(fd, &errSet)){
if(protocol==PROTO_UDP){
if(isAtLeastVista){
int addrLen=sizeof(sockaddr_in6);
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);
int res=recvfrom(fd, (char*)packet->data, packet->length, 0, (sockaddr *) &srcAddr, (socklen_t *) &addrLen);
if(res!=SOCKET_ERROR)
packet->length=(size_t) res;
else{
LOGE("error receiving %d", WSAGetLastError());
packet->length=0;
int error=WSAGetLastError();
LOGE("error receiving: %d", error);
return;
}
//LOGV("Received %d bytes from %s:%d at %.5lf", res, inet_ntoa(srcAddr.sin6_addr), ntohs(srcAddr.sin6_port), GetCurrentTime());
if(addr->sa_family==AF_INET){
packet->port=ntohs(srcAddr4.sin_port);
lastRecvdV4=IPv4Address(srcAddr4.sin_addr.s_addr);
//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{
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;
}
lastRecvdV6=IPv6Address(srcAddr.sin6_addr.s6_addr);
packet->address=&lastRecvdV6;
}
packet->protocol=PROTO_UDP;
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->port=ntohs(srcAddr.sin6_port);
}else{
int addrLen=sizeof(sockaddr_in);
sockaddr_in srcAddr;
int res=recvfrom(fd, (char*)packet->data, packet->length, 0, (sockaddr *) &srcAddr, (socklen_t *) &addrLen);
if(res!=SOCKET_ERROR)
packet->length=(size_t) res;
else{
LOGE("error receiving %d", WSAGetLastError());
packet->length=0;
closesocket(itr->fd);
itr=tcpSockets.erase(itr);
continue;
return;
}
if(FD_ISSET(itr->fd, &errSet)){
closesocket(itr->fd);
itr=tcpSockets.erase(itr);
continue;
}
++itr;
lastRecvdV4=IPv4Address(srcAddr.sin_addr.s_addr);
packet->address=&lastRecvdV4;
packet->port=ntohs(srcAddr.sin_port);
}
packet->protocol=PROTO_UDP;
}else if(protocol==PROTO_TCP){
int res=recv(fd, (char*)packet->data, packet->length, 0);
if(res==SOCKET_ERROR){
LOGE("Error receiving from TCP socket: %d", WSAGetLastError());
failed=true;
}else{
packet->length=(size_t)res;
packet->address=tcpConnectedAddress;
packet->port=tcpConnectedPort;
packet->protocol=PROTO_TCP;
}
}
}
void NetworkSocketWinsock::Open(){
fd=socket(isAtLeastVista ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(fd==INVALID_SOCKET){
int error=WSAGetLastError();
LOGE("error creating socket: %d", error);
failed=true;
return;
}
int res;
if(isAtLeastVista){
DWORD flag=0;
res=setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&flag, sizeof(flag));
if(res==SOCKET_ERROR){
LOGE("error enabling dual stack socket: %d", WSAGetLastError());
if(protocol==PROTO_UDP){
fd=socket(isAtLeastVista ? AF_INET6 : AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(fd==INVALID_SOCKET){
int error=WSAGetLastError();
LOGE("error creating socket: %d", error);
failed=true;
return;
}
}
int res;
if(isAtLeastVista){
DWORD flag=0;
res=setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&flag, sizeof(flag));
if(res==SOCKET_ERROR){
LOGE("error enabling dual stack socket: %d", WSAGetLastError());
failed=true;
return;
}
}
SetMaxPriority();
SetMaxPriority();
int tries=0;
sockaddr* addr;
sockaddr_in addr4;
sockaddr_in6 addr6;
int addrLen;
if(isAtLeastVista){
//addr.sin6_addr.s_addr=0;
memset(&addr6, 0, sizeof(sockaddr_in6));
//addr.sin6_len=sizeof(sa_family_t);
addr6.sin6_family=AF_INET6;
addr=(sockaddr*)&addr6;
addrLen=sizeof(addr6);
}else{
int tries=0;
sockaddr* addr;
sockaddr_in addr4;
addr4.sin_addr.s_addr=0;
addr4.sin_family=AF_INET;
addr=(sockaddr*)&addr4;
addrLen=sizeof(addr4);
}
for(tries=0;tries<10;tries++){
uint16_t port=htons(GenerateLocalPort());
if(isAtLeastVista)
((sockaddr_in6*)addr)->sin6_port=port;
else
((sockaddr_in*)addr)->sin_port=port;
res=::bind(fd, addr, addrLen);
LOGV("trying bind to port %u", ntohs(port));
if(res<0){
LOGE("error binding to port %u: %d / %s", ntohs(port), errno, strerror(errno));
sockaddr_in6 addr6;
int addrLen;
if(isAtLeastVista){
//addr.sin6_addr.s_addr=0;
memset(&addr6, 0, sizeof(sockaddr_in6));
//addr.sin6_len=sizeof(sa_family_t);
addr6.sin6_family=AF_INET6;
addr=(sockaddr*)&addr6;
addrLen=sizeof(addr6);
}else{
break;
sockaddr_in addr4;
addr4.sin_addr.s_addr=0;
addr4.sin_family=AF_INET;
addr=(sockaddr*)&addr4;
addrLen=sizeof(addr4);
}
}
if(tries==10){
for(tries=0;tries<10;tries++){
uint16_t port=htons(GenerateLocalPort());
if(isAtLeastVista)
((sockaddr_in6*)addr)->sin6_port=port;
else
((sockaddr_in*)addr)->sin_port=port;
res=::bind(fd, addr, addrLen);
LOGV("trying bind to port %u", ntohs(port));
if(res<0){
LOGE("error binding to port %u: %d / %s", ntohs(port), errno, strerror(errno));
}else{
break;
}
}
if(tries==10){
if(isAtLeastVista)
((sockaddr_in6*)addr)->sin6_port=0;
else
((sockaddr_in*)addr)->sin_port=0;
res=::bind(fd, addr, addrLen);
if(res<0){
LOGE("error binding to port %u: %d / %s", 0, errno, strerror(errno));
//SetState(STATE_FAILED);
return;
}
}
getsockname(fd, addr, (socklen_t*) &addrLen);
uint16_t localUdpPort;
if(isAtLeastVista)
((sockaddr_in6*)addr)->sin6_port=0;
localUdpPort=ntohs(((sockaddr_in6*)addr)->sin6_port);
else
((sockaddr_in*)addr)->sin_port=0;
res=::bind(fd, addr, addrLen);
if(res<0){
LOGE("error binding to port %u: %d / %s", 0, errno, strerror(errno));
//SetState(STATE_FAILED);
return;
}
}
getsockname(fd, addr, (socklen_t*) &addrLen);
uint16_t localUdpPort;
if(isAtLeastVista)
localUdpPort=ntohs(((sockaddr_in6*)addr)->sin6_port);
else
localUdpPort=ntohs(((sockaddr_in*)addr)->sin_port);
LOGD("Bound to local UDP port %u", localUdpPort);
localUdpPort=ntohs(((sockaddr_in*)addr)->sin_port);
LOGD("Bound to local UDP port %u", localUdpPort);
needUpdateNat64Prefix=true;
isV4Available=false;
switchToV6at=VoIPController::GetCurrentTime()+ipv6Timeout;
needUpdateNat64Prefix=true;
isV4Available=false;
switchToV6at=VoIPController::GetCurrentTime()+ipv6Timeout;
}
}
void NetworkSocketWinsock::Close(){
closing=true;
failed=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(){
@ -592,3 +452,185 @@ void NetworkSocketWinsock::StringToV6Address(std::string address, unsigned char
#endif
memcpy(out, addr.sin6_addr.s6_addr, 16);
}
void NetworkSocketWinsock::Connect(NetworkAddress *address, uint16_t port){
IPv4Address* v4addr=dynamic_cast<IPv4Address*>(address);
IPv6Address* v6addr=dynamic_cast<IPv6Address*>(address);
sockaddr_in v4;
sockaddr_in6 v6;
sockaddr* addr=NULL;
size_t addrLen=0;
if(v4addr){
v4.sin_family=AF_INET;
v4.sin_addr.s_addr=v4addr->GetAddress();
v4.sin_port=htons(port);
addr=reinterpret_cast<sockaddr*>(&v4);
addrLen=sizeof(v4);
}else if(v6addr){
v6.sin6_family=AF_INET6;
memcpy(v6.sin6_addr.s6_addr, v6addr->GetAddress(), 16);
v6.sin6_flowinfo=0;
v6.sin6_scope_id=0;
v6.sin6_port=htons(port);
addr=reinterpret_cast<sockaddr*>(&v6);
addrLen=sizeof(v6);
}else{
LOGE("Unknown address type in TCP connect");
failed=true;
return;
}
fd=socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
if(fd==0){
LOGE("Error creating TCP socket: %d", WSAGetLastError());
failed=true;
return;
}
int opt=1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(opt));
timeval timeout;
timeout.tv_sec=5;
timeout.tv_usec=0;
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout));
timeout.tv_sec=60;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
int res=connect(fd, (const sockaddr*) addr, addrLen);
if(res!=0){
LOGW("error connecting TCP socket to %s:%u: %d", address->ToString().c_str(), port, WSAGetLastError());
closesocket(fd);
failed=true;
return;
}
tcpConnectedAddress=v4addr ? (NetworkAddress*)new IPv4Address(*v4addr) : (NetworkAddress*)new IPv6Address(*v6addr);
tcpConnectedPort=port;
LOGI("successfully connected to %s:%d", tcpConnectedAddress->ToString().c_str(), tcpConnectedPort);
}
IPv4Address *NetworkSocketWinsock::ResolveDomainName(std::string name){
addrinfo* addr0;
IPv4Address* ret=NULL;
int res=getaddrinfo(name.c_str(), NULL, NULL, &addr0);
if(res!=0){
LOGW("Error updating NAT64 prefix: %d / %s", res, gai_strerror(res));
}else{
addrinfo* addrPtr;
for(addrPtr=addr0;addrPtr;addrPtr=addrPtr->ai_next){
if(addrPtr->ai_family==AF_INET){
sockaddr_in* addr=(sockaddr_in*)addrPtr->ai_addr;
ret=new IPv4Address(addr->sin_addr.s_addr);
break;
}
}
freeaddrinfo(addr0);
}
return ret;
}
NetworkAddress *NetworkSocketWinsock::GetConnectedAddress(){
return tcpConnectedAddress;
}
uint16_t NetworkSocketWinsock::GetConnectedPort(){
return tcpConnectedPort;
}
void NetworkSocketWinsock::SetTimeouts(int sendTimeout, int recvTimeout){
timeval timeout;
timeout.tv_sec=sendTimeout;
timeout.tv_usec=0;
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout));
timeout.tv_sec=recvTimeout;
setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
}
bool NetworkSocketWinsock::Select(std::vector<NetworkSocket *> &readFds, std::vector<NetworkSocket *> &errorFds, SocketSelectCanceller* _canceller){
fd_set readSet;
fd_set errorSet;
SocketSelectCancellerWin32* canceller=dynamic_cast<SocketSelectCancellerWin32*>(_canceller);
timeval timeout={0, 10000};
bool anyFailed=false;
int res=0;
do{
FD_ZERO(&readSet);
FD_ZERO(&errorSet);
for(std::vector<NetworkSocket*>::iterator itr=readFds.begin();itr!=readFds.end();++itr){
int sfd=GetDescriptorFromSocket(*itr);
if(sfd==0){
LOGW("can't select on one of sockets because it's not a NetworkSocketWinsock instance");
continue;
}
FD_SET(sfd, &readSet);
}
for(std::vector<NetworkSocket*>::iterator itr=errorFds.begin();itr!=errorFds.end();++itr){
int sfd=GetDescriptorFromSocket(*itr);
if(sfd==0){
LOGW("can't select on one of sockets because it's not a NetworkSocketWinsock instance");
continue;
}
anyFailed |= (*itr)->IsFailed();
FD_SET(sfd, &errorSet);
}
if(canceller && canceller->canceled)
break;
res=select(0, &readSet, NULL, &errorSet, &timeout);
//LOGV("select result %d", res);
if(res==SOCKET_ERROR)
LOGE("SELECT ERROR %d", WSAGetLastError());
}while(res==0);
if(canceller && canceller->canceled && !anyFailed){
canceller->canceled=false;
return false;
}else if(anyFailed){
FD_ZERO(&readSet);
FD_ZERO(&errorSet);
}
std::vector<NetworkSocket*>::iterator itr=readFds.begin();
while(itr!=readFds.end()){
int sfd=GetDescriptorFromSocket(*itr);
if(sfd==0 || !FD_ISSET(sfd, &readSet)){
itr=readFds.erase(itr);
}else{
++itr;
}
}
itr=errorFds.begin();
while(itr!=errorFds.end()){
int sfd=GetDescriptorFromSocket(*itr);
if((sfd==0 || !FD_ISSET(sfd, &errorSet)) && !(*itr)->IsFailed()){
itr=errorFds.erase(itr);
}else{
++itr;
}
}
//LOGV("select fds left: read=%d, error=%d", readFds.size(), errorFds.size());
return readFds.size()>0 || errorFds.size()>0;
}
SocketSelectCancellerWin32::SocketSelectCancellerWin32(){
canceled=false;
}
SocketSelectCancellerWin32::~SocketSelectCancellerWin32(){
}
void SocketSelectCancellerWin32::CancelSelect(){
canceled=true;
}
int NetworkSocketWinsock::GetDescriptorFromSocket(NetworkSocket *socket){
NetworkSocketWinsock* sp=dynamic_cast<NetworkSocketWinsock*>(socket);
if(sp)
return sp->fd;
NetworkSocketWrapper* sw=dynamic_cast<NetworkSocketWrapper*>(socket);
if(sw)
return GetDescriptorFromSocket(sw->GetWrapped());
return 0;
}

View File

@ -13,17 +13,19 @@
namespace tgvoip {
struct TCPSocket{
uintptr_t fd;
IPv4Address address;
uint16_t port;
TCPO2State recvState;
TCPO2State sendState;
class SocketSelectCancellerWin32 : public SocketSelectCanceller{
friend class NetworkSocketWinsock;
public:
SocketSelectCancellerWin32();
virtual ~SocketSelectCancellerWin32();
virtual void CancelSelect();
private:
bool canceled;
};
class NetworkSocketWinsock : public NetworkSocket{
public:
NetworkSocketWinsock();
NetworkSocketWinsock(NetworkProtocol protocol);
virtual ~NetworkSocketWinsock();
virtual void Send(NetworkPacket* packet);
virtual void Receive(NetworkPacket* packet);
@ -32,16 +34,26 @@ public:
virtual std::string GetLocalInterfaceInfo(IPv4Address* v4addr, IPv6Address* v6addr);
virtual void OnActiveInterfaceChanged();
virtual uint16_t GetLocalPort();
virtual void Connect(NetworkAddress* address, uint16_t port);
static std::string V4AddressToString(uint32_t address);
static std::string V6AddressToString(unsigned char address[16]);
static uint32_t StringToV4Address(std::string address);
static void StringToV6Address(std::string address, unsigned char* out);
static IPv4Address* ResolveDomainName(std::string name);
static bool Select(std::vector<NetworkSocket*>& readFds, std::vector<NetworkSocket*>& errorFds, SocketSelectCanceller* canceller);
virtual NetworkAddress *GetConnectedAddress();
virtual uint16_t GetConnectedPort();
virtual void SetTimeouts(int sendTimeout, int recvTimeout);
protected:
virtual void SetMaxPriority();
private:
static int GetDescriptorFromSocket(NetworkSocket* socket);
uintptr_t fd;
bool needUpdateNat64Prefix;
bool nat64Present;
@ -50,9 +62,9 @@ private:
IPv4Address lastRecvdV4;
IPv6Address lastRecvdV6;
bool isAtLeastVista;
std::vector<TCPSocket> tcpSockets;
bool closing;
NetworkAddress* tcpConnectedAddress;
uint16_t tcpConnectedPort;
};
}