feat: enhance OverteClient connection handling with TCP and UDP support; add environment variable and command-line argument overrides for URL

This commit is contained in:
MayaTheShy
2025-11-08 14:26:24 -05:00
parent f8170456ca
commit f9a7e61ff5
3 changed files with 94 additions and 23 deletions

View File

@@ -7,33 +7,66 @@
#include <glm/gtc/matrix_transform.hpp>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <fcntl.h>
#include <cstring>
using namespace std::chrono_literals;
bool OverteClient::connect() {
// Basic reachability check (TCP) if ws://host:port specified.
// Format expected: ws://host:port
auto posScheme = m_domainUrl.find("ws://");
if (posScheme != 0) {
std::cerr << "[OverteClient] Unexpected URL scheme; expected ws://" << std::endl;
}
auto hostPort = m_domainUrl.substr(5); // strip ws://
auto colon = hostPort.find(':');
std::string host = colon == std::string::npos ? hostPort : hostPort.substr(0, colon);
int port = colon == std::string::npos ? 40102 : std::stoi(hostPort.substr(colon + 1));
// Parse ws://host:port
std::string url = m_domainUrl;
if (url.empty()) url = "ws://127.0.0.1:40102";
if (url.rfind("ws://", 0) == 0) url = url.substr(5);
auto colon = url.find(':');
m_host = colon == std::string::npos ? url : url.substr(0, colon);
m_port = colon == std::string::npos ? 40102 : std::stoi(url.substr(colon + 1));
// Attempt a non-blocking TCP connect (best-effort; ignore failure but warn).
int fd = ::socket(AF_INET, SOCK_STREAM, 0);
if (fd != -1) {
sockaddr_in addr{}; addr.sin_family = AF_INET; addr.sin_port = htons(port);
addr.sin_addr.s_addr = INADDR_ANY; // Skip DNS for stub; real impl would resolve host.
if (::connect(fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == -1) {
std::cerr << "[OverteClient] Warning: unable to reach Overte domain (stub)." << std::endl;
} else {
std::cout << "[OverteClient] (Stub) TCP connect succeeded to " << host << ':' << port << std::endl;
// Resolve host:port
addrinfo hints{}; hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC;
addrinfo* res = nullptr;
int gai = ::getaddrinfo(m_host.c_str(), std::to_string(m_port).c_str(), &hints, &res);
if (gai != 0) {
std::cerr << "[OverteClient] getaddrinfo failed for " << m_host << ":" << m_port << " - " << gai_strerror(gai) << std::endl;
} else {
// Attempt TCP reachability for diagnostics
int fd = -1; addrinfo* rp = res;
for (; rp; rp = rp->ai_next) {
fd = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (fd == -1) continue;
::fcntl(fd, F_SETFL, O_NONBLOCK);
int c = ::connect(fd, rp->ai_addr, rp->ai_addrlen);
if (c == 0 || (c == -1 && errno == EINPROGRESS)) {
std::cout << "[OverteClient] TCP reachable (non-blocking) to " << m_host << ":" << m_port << std::endl;
::close(fd); fd = -1; break;
}
::close(fd); fd = -1;
}
::close(fd);
::freeaddrinfo(res);
if (fd == -1) {
// Not necessarily fatal; mixers are UDP. Continue with UDP.
}
}
// Setup UDP to target (avatar mixer guess: same port by default)
addrinfo uhints{}; uhints.ai_socktype = SOCK_DGRAM; uhints.ai_family = AF_UNSPEC;
addrinfo* ures = nullptr;
int ugai = ::getaddrinfo(m_host.c_str(), std::to_string(m_port).c_str(), &uhints, &ures);
if (ugai != 0) {
std::cerr << "[OverteClient] UDP resolve failed: " << gai_strerror(ugai) << std::endl;
} else {
for (addrinfo* rp = ures; rp; rp = rp->ai_next) {
m_udpFd = ::socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (m_udpFd == -1) continue;
::fcntl(m_udpFd, F_SETFL, O_NONBLOCK);
std::memcpy(&m_udpAddr, rp->ai_addr, rp->ai_addrlen);
m_udpAddrLen = rp->ai_addrlen;
m_udpReady = true;
std::cout << "[OverteClient] UDP socket ready for " << m_host << ":" << m_port << std::endl;
break;
}
::freeaddrinfo(ures);
}
// Simulate successful connections to mixers.
@@ -54,8 +87,8 @@ bool OverteClient::connect() {
}
bool OverteClient::connectAvatarMixer() {
// TODO: Use Overte networking layer (NodeList) to connect to AvatarMixer.
m_avatarMixer = true;
// For now, consider UDP socket readiness as mixer connectivity proxy.
m_avatarMixer = m_udpReady;
return true;
}
@@ -74,6 +107,21 @@ bool OverteClient::connectAudioMixer() {
void OverteClient::poll() {
if (!m_connected) return;
// Try a lightweight UDP ping if ready
if (m_udpReady && m_udpFd != -1) {
const char ping[4] = {'P','I','N','G'};
ssize_t s = ::sendto(m_udpFd, ping, sizeof(ping), 0, reinterpret_cast<sockaddr*>(&m_udpAddr), m_udpAddrLen);
if (s == -1 && errno != EWOULDBLOCK && errno != EAGAIN) {
std::cerr << "[OverteClient] UDP send failed: " << std::strerror(errno) << std::endl;
}
char buf[1500];
sockaddr_storage from{}; socklen_t fromlen = sizeof(from);
ssize_t r = ::recvfrom(m_udpFd, buf, sizeof(buf), 0, reinterpret_cast<sockaddr*>(&from), &fromlen);
if (r > 0) {
std::cout << "[OverteClient] UDP packet received (" << r << " bytes)" << std::endl;
}
}
// Simulate entity transforms changing slightly over time.
static auto t0 = std::chrono::steady_clock::now();
const float t = std::chrono::duration<float>(std::chrono::steady_clock::now() - t0).count();