void TCPSocket::SetTimeout(int socket) { if (setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, &timeout.Timeval(), sizeof(timeout.Timeval())) < 0) throw NetworkSystemError(errno); if (setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, &timeout.Timeval(), sizeof(timeout.Timeval())) < 0) throw NetworkSystemError(errno); }
void Interfaces::Load() { struct ifaddrs* ifaddr, *ifa; if (getifaddrs(&ifaddr) == -1) return throw NetworkSystemError(errno); std::shared_ptr<struct ifaddrs> ifaddrGuard(ifaddr, freeifaddrs); IPAddress ip; for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { if (!ifa->ifa_addr) continue; if (ifa->ifa_addr->sa_family == AF_INET) { struct sockaddr_in* addr4 = reinterpret_cast<struct sockaddr_in*>(ifa->ifa_addr); ip = IPAddress(&addr4->sin_addr, sizeof(addr4->sin_addr)); } else if (ifa->ifa_addr->sa_family == AF_INET6) { struct sockaddr_in6* addr6 = reinterpret_cast<struct sockaddr_in6*>(ifa->ifa_addr); ip = IPAddress(&addr6->sin6_addr, sizeof(addr6->sin6_addr)); } else continue; std::string name = ifa->ifa_name; std::map<std::string, Interface>::iterator it = interfaces.insert(std::make_pair(name, Interface(name))).first; it->second.addresses.emplace_back(ip); } }
void TCPSocket::Write(const char* buffer, size_t bufferLen) { if (tls.get()) { tls->Write(buffer, bufferLen); return; } size_t written = 0; ssize_t result; while (bufferLen - written > 0) { while ((result = write(socket, buffer + written, bufferLen - written)) < 0) { boost::this_thread::interruption_point(); if (errno != EINTR) { if (errno == EWOULDBLOCK || errno == EAGAIN || errno == ETIMEDOUT) throw TimeoutError(); else throw NetworkSystemError(errno); } } boost::this_thread::interruption_point(); written += result; } }
void TCPSocket::Accept(TCPListener& listener) { struct sockaddr_storage addrStor; socklen_t addrLen = sizeof(addrStor); struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addrStor); int socket; while ((socket = accept(listener.Socket(), addr, &addrLen)) < 0) { boost::this_thread::interruption_point(); if (errno != EINTR) { if (errno == EWOULDBLOCK || errno == EAGAIN || errno == ETIMEDOUT) throw TimeoutError(); else throw NetworkSystemError(errno); } } auto socketGuard = util::MakeScopeError([&socket]() { close(socket); }); (void) socketGuard; boost::this_thread::interruption_point(); PopulateRemoteEndpoint(socket); PopulateLocalEndpoint(socket); std::lock_guard<std::mutex> lock(socketMutex); this->socket = socket; }
void TCPSocket::Connect(const Endpoint& remoteEndpoint, const Endpoint* localEndpoint) { assert(socket < 0); int socket = ::socket(static_cast<int>(remoteEndpoint.Family()), SOCK_STREAM, 0); if (socket < 0) throw NetworkSystemError(errno); auto socketGuard = util::MakeScopeError([&socket]() { close(socket); }); (void) socketGuard; int optVal = 1; setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &optVal, sizeof(optVal)); SetTimeout(socket); if (localEndpoint) { socklen_t addrLen = localEndpoint->Length(); struct sockaddr_storage addrStor; memcpy(&addrStor, localEndpoint->Addr(), addrLen); struct sockaddr* addr = reinterpret_cast<struct sockaddr*>(&addrStor); if (bind(socket, addr, addrLen) < 0) { int errno_ = errno; throw util::net::NetworkSystemError(errno_); } } while (connect(socket, remoteEndpoint.Addr(), remoteEndpoint.Length()) < 0) { boost::this_thread::interruption_point(); if (errno != EINTR) { int errno_ = errno; if (errno_ == EWOULDBLOCK || errno_ == EAGAIN || errno_ == ETIMEDOUT) throw TimeoutError(); else throw NetworkSystemError(errno_); } } boost::this_thread::interruption_point(); PopulateRemoteEndpoint(socket); PopulateLocalEndpoint(socket); std::lock_guard<std::mutex> lock(socketMutex); this->socket = socket; }
void IPAddress::ToStringv6() const { char str[INET6_ADDRSTRLEN]; if (!inet_ntop(static_cast<int>(IPFamily::IPv6), &data, str, sizeof(str))) throw NetworkSystemError(errno); asString = str; }
void TCPSocket::PopulateRemoteEndpoint(int socket) { struct sockaddr_storage remoteAddrStor; socklen_t remoteLen = sizeof(remoteAddrStor); struct sockaddr* remoteAddr = reinterpret_cast<struct sockaddr*>(&remoteAddrStor); if (getpeername(socket, (struct sockaddr*) remoteAddr, &remoteLen) < 0) throw NetworkSystemError(errno); remoteEndpoint = Endpoint(*remoteAddr, remoteLen); }
void TCPSocket::PopulateLocalEndpoint(int socket) { struct sockaddr_storage localAddrStor; socklen_t localLen = sizeof(localAddrStor); struct sockaddr* localAddr = reinterpret_cast<struct sockaddr*>(&localAddrStor); if (getsockname(socket, (struct sockaddr*) localAddr, &localLen) < 0) throw NetworkSystemError(errno); localEndpoint = Endpoint(*localAddr, localLen); }
void Resolver::Resolve() { const char* charService = nullptr; if (port >= 0) { std::string service; try { service = boost::lexical_cast<std::string>(port); } catch (const boost::bad_lexical_cast&) { throw NetworkError("Invalid port number"); } charService = service.c_str(); } struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_flags = AI_PASSIVE; hints.ai_socktype = static_cast<int>(socketType); const char* charHostname = nullptr; if (!hostname.empty()) charHostname = hostname.c_str(); int error = getaddrinfo(charHostname, charService, &hints, &res); if (error) { if (error == EAI_SYSTEM) throw NetworkSystemError(errno); else throw ResolverError(error); } struct addrinfo* current = res; while (current) { results.emplace_back(Endpoint(*current->ai_addr, current->ai_addrlen)); current = current->ai_next; } freeaddrinfo(res); res = nullptr; }
size_t TCPSocket::Read(char* buffer, size_t bufferSize) { if (tls.get()) return tls->Read(buffer, bufferSize); ssize_t result; while ((result = read(socket, buffer, bufferSize)) < 0) { boost::this_thread::interruption_point(); if (errno != EINTR) { if (errno == EWOULDBLOCK || errno == EAGAIN || errno == ETIMEDOUT) throw TimeoutError(); else throw NetworkSystemError(errno); } } boost::this_thread::interruption_point(); if (!result) throw EndOfStream(); return result; }