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:
parent
c63a3bbdcf
commit
1be4d016a4
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
230
VoIPController.h
230
VoIPController.h
@ -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
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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",
|
||||
|
10
logging.cpp
10
logging.cpp
@ -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
|
||||
|
10
logging.h
10
logging.h
@ -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)
|
||||
|
||||
|
@ -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);
|
||||
|
@ -11,7 +11,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void __tgvoip_call_tglog(char* format, ...);
|
||||
void __tgvoip_call_tglog(const char* format, ...);
|
||||
|
||||
#if defined __cplusplus
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user