// // libtgvoip is free and unencumbered public domain software. // For more information, see http://unlicense.org or the UNLICENSE file // you should have received with this source code distribution. // #include #include #include "NetworkSocketWinsock.h" #if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP #else #include #endif #include #include "../../logging.h" #include "../../VoIPController.h" #include "WindowsSpecific.h" #include "../../Buffers.h" using namespace tgvoip; NetworkSocketWinsock::NetworkSocketWinsock(NetworkProtocol protocol) : NetworkSocket(protocol), lastRecvdV4(0), lastRecvdV6("::0"){ needUpdateNat64Prefix=true; nat64Present=false; switchToV6at=0; isV4Available=false; closing=false; fd=INVALID_SOCKET; #ifdef TGVOIP_WINXP_COMPAT DWORD version=GetVersion(); isAtLeastVista=LOBYTE(LOWORD(version))>=6; // Vista is 6.0, XP is 5.1 and 5.2 #else isAtLeastVista=true; #endif WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); LOGD("Initialized winsock, version %d.%d", wsaData.wHighVersion, wsaData.wVersion); tcpConnectedAddress=NULL; if(protocol==PROTO_TCP) timeout=10.0; lastSuccessfulOperationTime=VoIPController::GetCurrentTime(); } NetworkSocketWinsock::~NetworkSocketWinsock(){ if(tcpConnectedAddress) delete tcpConnectedAddress; if(pendingOutgoingPacket) delete pendingOutgoingPacket; } void NetworkSocketWinsock::SetMaxPriority(){ } void NetworkSocketWinsock::Send(NetworkPacket *packet){ if(!packet || (protocol==PROTO_UDP && !packet->address)){ LOGW("tried to send null packet"); return; } int res; if(protocol==PROTO_UDP){ IPv4Address *v4addr=dynamic_cast(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(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; }else{ IPv6Address *v6addr=dynamic_cast(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); } if(res==SOCKET_ERROR){ int error=WSAGetLastError(); if(error==WSAEWOULDBLOCK){ if(pendingOutgoingPacket){ LOGE("Got EAGAIN but there's already a pending packet"); failed=true; }else{ LOGV("Socket %d not ready to send", fd); pendingOutgoingPacket=new Buffer(packet->length); pendingOutgoingPacket->CopyFrom(packet->data, 0, packet->length); readyToSend=false; } }else{ LOGE("error sending: %d / %s", error, WindowsSpecific::GetErrorMessage(error).c_str()); if(error==WSAENETUNREACH && !isV4Available && VoIPController::GetCurrentTime()length && protocol==PROTO_TCP){ if(pendingOutgoingPacket){ LOGE("send returned less than packet length but there's already a pending packet"); failed=true; }else{ LOGV("Socket %d not ready to send", fd); pendingOutgoingPacket=new Buffer(packet->length-res); pendingOutgoingPacket->CopyFrom(packet->data+res, 0, packet->length-res); readyToSend=false; } } } bool NetworkSocketWinsock::OnReadyToSend(){ if(pendingOutgoingPacket){ NetworkPacket pkt={0}; pkt.data=**pendingOutgoingPacket; pkt.length=pendingOutgoingPacket->Length(); Send(&pkt); delete pendingOutgoingPacket; pendingOutgoingPacket=NULL; return false; } readyToSend=true; return true; } void NetworkSocketWinsock::Receive(NetworkPacket *packet){ if(protocol==PROTO_UDP){ if(isAtLeastVista){ int addrLen=sizeof(sockaddr_in6); sockaddr_in6 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{ int error=WSAGetLastError(); LOGE("error receiving %d / %s", error, WindowsSpecific::GetErrorMessage(error).c_str()); 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->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; return; } 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){ int error=WSAGetLastError(); LOGE("Error receiving from TCP socket: %d / %s", error, WindowsSpecific::GetErrorMessage(error).c_str()); failed=true; }else{ packet->length=(size_t)res; packet->address=tcpConnectedAddress; packet->port=tcpConnectedPort; packet->protocol=PROTO_TCP; } } } void NetworkSocketWinsock::Open(){ 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; } } u_long one=1; ioctlsocket(fd, FIONBIO, &one); 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{ 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)); }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) localUdpPort=ntohs(((sockaddr_in6*)addr)->sin6_port); else localUdpPort=ntohs(((sockaddr_in*)addr)->sin_port); LOGD("Bound to local UDP port %u", localUdpPort); needUpdateNat64Prefix=true; isV4Available=false; switchToV6at=VoIPController::GetCurrentTime()+ipv6Timeout; } } void NetworkSocketWinsock::Close(){ closing=true; failed=true; if(fd!=INVALID_SOCKET) closesocket(fd); } void NetworkSocketWinsock::OnActiveInterfaceChanged(){ needUpdateNat64Prefix=true; isV4Available=false; switchToV6at=VoIPController::GetCurrentTime()+ipv6Timeout; } std::string NetworkSocketWinsock::GetLocalInterfaceInfo(IPv4Address *v4addr, IPv6Address *v6addr){ #if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP Windows::Networking::Connectivity::ConnectionProfile^ profile=Windows::Networking::Connectivity::NetworkInformation::GetInternetConnectionProfile(); if(profile){ Windows::Foundation::Collections::IVectorView^ hostnames=Windows::Networking::Connectivity::NetworkInformation::GetHostNames(); for(unsigned int i=0;iSize;i++){ Windows::Networking::HostName^ n = hostnames->GetAt(i); if(n->Type!=Windows::Networking::HostNameType::Ipv4 && n->Type!=Windows::Networking::HostNameType::Ipv6) continue; if(n->IPInformation->NetworkAdapter->Equals(profile->NetworkAdapter)){ if(v4addr && n->Type==Windows::Networking::HostNameType::Ipv4){ char buf[INET_ADDRSTRLEN]; WideCharToMultiByte(CP_UTF8, 0, n->RawName->Data(), -1, buf, sizeof(buf), NULL, NULL); *v4addr=IPv4Address(buf); }else if(v6addr && n->Type==Windows::Networking::HostNameType::Ipv6){ char buf[INET6_ADDRSTRLEN]; WideCharToMultiByte(CP_UTF8, 0, n->RawName->Data(), -1, buf, sizeof(buf), NULL, NULL); *v6addr=IPv6Address(buf); } } } char buf[128]; WideCharToMultiByte(CP_UTF8, 0, profile->NetworkAdapter->NetworkAdapterId.ToString()->Data(), -1, buf, sizeof(buf), NULL, NULL); return std::string(buf); } return ""; #else IP_ADAPTER_ADDRESSES* addrs=(IP_ADAPTER_ADDRESSES*)malloc(15*1024); ULONG size=15*1024; ULONG flags=GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_SKIP_FRIENDLY_NAME; ULONG res=GetAdaptersAddresses(AF_UNSPEC, flags, NULL, addrs, &size); if(res==ERROR_BUFFER_OVERFLOW){ addrs=(IP_ADAPTER_ADDRESSES*)realloc(addrs, size); res=GetAdaptersAddresses(AF_UNSPEC, flags, NULL, addrs, &size); } ULONG bestMetric=0; std::string bestName(""); if(res==ERROR_SUCCESS){ IP_ADAPTER_ADDRESSES* current=addrs; while(current){ char* name=current->AdapterName; LOGV("Adapter '%s':", name); IP_ADAPTER_UNICAST_ADDRESS* curAddr=current->FirstUnicastAddress; if(current->OperStatus!=IfOperStatusUp){ LOGV("-> (down)"); current=current->Next; continue; } if(current->IfType==IF_TYPE_SOFTWARE_LOOPBACK){ LOGV("-> (loopback)"); current=current->Next; continue; } if(isAtLeastVista) LOGV("v4 metric: %u, v6 metric: %u", current->Ipv4Metric, current->Ipv6Metric); while(curAddr){ sockaddr* addr=curAddr->Address.lpSockaddr; if(addr->sa_family==AF_INET && v4addr){ sockaddr_in* ipv4=(sockaddr_in*)addr; LOGV("-> V4: %s", V4AddressToString(ipv4->sin_addr.s_addr).c_str()); uint32_t ip=ntohl(ipv4->sin_addr.s_addr); if((ip & 0xFFFF0000)!=0xA9FE0000){ if(isAtLeastVista){ if(current->Ipv4Metric>bestMetric){ bestMetric=current->Ipv4Metric; bestName=std::string(current->AdapterName); *v4addr=IPv4Address(ipv4->sin_addr.s_addr); } }else{ bestName=std::string(current->AdapterName); *v4addr=IPv4Address(ipv4->sin_addr.s_addr); } } }else if(addr->sa_family==AF_INET6 && v6addr){ sockaddr_in6* ipv6=(sockaddr_in6*)addr; LOGV("-> V6: %s", V6AddressToString(ipv6->sin6_addr.s6_addr).c_str()); if(!IN6_IS_ADDR_LINKLOCAL(&ipv6->sin6_addr)){ *v6addr=IPv6Address(ipv6->sin6_addr.s6_addr); } } curAddr=curAddr->Next; } current=current->Next; } } free(addrs); return bestName; #endif } uint16_t NetworkSocketWinsock::GetLocalPort(){ if(!isAtLeastVista){ sockaddr_in addr; size_t addrLen=sizeof(sockaddr_in); getsockname(fd, (sockaddr*)&addr, (socklen_t*)&addrLen); return ntohs(addr.sin_port); } sockaddr_in6 addr; size_t addrLen=sizeof(sockaddr_in6); getsockname(fd, (sockaddr*)&addr, (socklen_t*) &addrLen); return ntohs(addr.sin6_port); } std::string NetworkSocketWinsock::V4AddressToString(uint32_t address){ char buf[INET_ADDRSTRLEN]; sockaddr_in addr; ZeroMemory(&addr, sizeof(addr)); addr.sin_family=AF_INET; addr.sin_addr.s_addr=address; DWORD len=sizeof(buf); #if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP wchar_t wbuf[INET_ADDRSTRLEN]; ZeroMemory(wbuf, sizeof(wbuf)); WSAAddressToStringW((sockaddr*)&addr, sizeof(addr), NULL, wbuf, &len); WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, sizeof(buf), NULL, NULL); #else WSAAddressToStringA((sockaddr*)&addr, sizeof(addr), NULL, buf, &len); #endif return std::string(buf); } std::string NetworkSocketWinsock::V6AddressToString(const unsigned char *address){ char buf[INET6_ADDRSTRLEN]; sockaddr_in6 addr; ZeroMemory(&addr, sizeof(addr)); addr.sin6_family=AF_INET6; memcpy(addr.sin6_addr.s6_addr, address, 16); DWORD len=sizeof(buf); #if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP wchar_t wbuf[INET6_ADDRSTRLEN]; ZeroMemory(wbuf, sizeof(wbuf)); WSAAddressToStringW((sockaddr*)&addr, sizeof(addr), NULL, wbuf, &len); WideCharToMultiByte(CP_UTF8, 0, wbuf, -1, buf, sizeof(buf), NULL, NULL); #else WSAAddressToStringA((sockaddr*)&addr, sizeof(addr), NULL, buf, &len); #endif return std::string(buf); } uint32_t NetworkSocketWinsock::StringToV4Address(std::string address){ sockaddr_in addr; ZeroMemory(&addr, sizeof(addr)); addr.sin_family=AF_INET; int size=sizeof(addr); #if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP wchar_t buf[INET_ADDRSTRLEN]; MultiByteToWideChar(CP_UTF8, 0, address.c_str(), -1, buf, INET_ADDRSTRLEN); WSAStringToAddressW(buf, AF_INET, NULL, (sockaddr*)&addr, &size); #else WSAStringToAddressA((char*)address.c_str(), AF_INET, NULL, (sockaddr*)&addr, &size); #endif return addr.sin_addr.s_addr; } void NetworkSocketWinsock::StringToV6Address(std::string address, unsigned char *out){ sockaddr_in6 addr; ZeroMemory(&addr, sizeof(addr)); addr.sin6_family=AF_INET6; int size=sizeof(addr); #if WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP wchar_t buf[INET6_ADDRSTRLEN]; MultiByteToWideChar(CP_UTF8, 0, address.c_str(), -1, buf, INET6_ADDRSTRLEN); WSAStringToAddressW(buf, AF_INET, NULL, (sockaddr*)&addr, &size); #else WSAStringToAddressA((char*)address.c_str(), AF_INET, NULL, (sockaddr*)&addr, &size); #endif memcpy(out, addr.sin6_addr.s6_addr, 16); } void NetworkSocketWinsock::Connect(const NetworkAddress *address, uint16_t port){ const IPv4Address* v4addr=dynamic_cast(address); const IPv6Address* v6addr=dynamic_cast(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(&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(&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==INVALID_SOCKET){ LOGE("Error creating TCP socket: %d", WSAGetLastError()); failed=true; return; } u_long one=1; ioctlsocket(fd, FIONBIO, &one); int opt=1; setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(opt)); DWORD timeout=5000; setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout)); timeout=60000; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)); int res=connect(fd, (const sockaddr*) addr, addrLen); if(res!=0){ int error=WSAGetLastError(); if(error!=WSAEINPROGRESS && error!=WSAEWOULDBLOCK){ LOGW("error connecting TCP socket to %s:%u: %d / %s", address->ToString().c_str(), port, error, WindowsSpecific::GetErrorMessage(error).c_str()); 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){ DWORD timeout=sendTimeout*1000; setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout)); timeout=recvTimeout*1000; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout)); } bool NetworkSocketWinsock::Select(std::vector &readFds, std::vector& writeFds, std::vector &errorFds, SocketSelectCanceller* _canceller){ fd_set readSet; fd_set errorSet; fd_set writeSet; SocketSelectCancellerWin32* canceller=dynamic_cast(_canceller); timeval timeout={0, 10000}; bool anyFailed=false; int res=0; do{ FD_ZERO(&readSet); FD_ZERO(&writeSet); FD_ZERO(&errorSet); for(std::vector::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(NetworkSocket*& s:writeFds){ int sfd=GetDescriptorFromSocket(s); if(sfd==0){ LOGW("can't select on one of sockets because it's not a NetworkSocketWinsock instance"); continue; } FD_SET(sfd, &writeSet); } for(std::vector::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; } if((*itr)->timeout>0 && VoIPController::GetCurrentTime()-(*itr)->lastSuccessfulOperationTime>(*itr)->timeout){ LOGW("Socket %d timed out", sfd); (*itr)->failed=true; } anyFailed |= (*itr)->IsFailed(); FD_SET(sfd, &errorSet); } if(canceller && canceller->canceled) break; res=select(0, &readSet, &writeSet, &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::iterator itr=readFds.begin(); while(itr!=readFds.end()){ int sfd=GetDescriptorFromSocket(*itr); if(FD_ISSET(sfd, &readSet)) (*itr)->lastSuccessfulOperationTime=VoIPController::GetCurrentTime(); if(sfd==0 || !FD_ISSET(sfd, &readSet) || !(*itr)->OnReadyToReceive()){ itr=readFds.erase(itr); }else{ ++itr; } } itr=writeFds.begin(); while(itr!=writeFds.end()){ int sfd=GetDescriptorFromSocket(*itr); if(FD_ISSET(sfd, &writeSet)){ (*itr)->lastSuccessfulOperationTime=VoIPController::GetCurrentTime(); LOGI("Socket %d is ready to send", sfd); } if(sfd==0 || !FD_ISSET(sfd, &writeSet) || !(*itr)->OnReadyToSend()){ itr=writeFds.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(socket); if(sp) return sp->fd; NetworkSocketWrapper* sw=dynamic_cast(socket); if(sw) return GetDescriptorFromSocket(sw->GetWrapped()); return 0; }