Static Webview - RTC - UDP - TCP - WSS
This commit is contained in:
@ -44,6 +44,7 @@ public:
|
||||
bool isConnected;
|
||||
bool isBound;
|
||||
bool isListening;
|
||||
bool connectInProgress;
|
||||
std::string lastError;
|
||||
|
||||
#ifdef _WIN32
|
||||
@ -58,7 +59,8 @@ public:
|
||||
void* ssl_cred_handle_;
|
||||
void* ssl_context_handle_;
|
||||
bool ssl_context_initialized_;
|
||||
std::vector<char> ssl_buffer_;
|
||||
std::vector<char> ssl_buffer_;
|
||||
std::vector<char> ssl_send_buffer_;
|
||||
#else
|
||||
SSL* ssl;
|
||||
SSL_CTX* ssl_ctx;
|
||||
@ -67,7 +69,7 @@ public:
|
||||
#endif
|
||||
|
||||
RunTSocket(int socket_id) : id(socket_id), isBlocking(true), isConnected(false),
|
||||
isBound(false), isListening(false) {
|
||||
isBound(false), isListening(false), connectInProgress(false) {
|
||||
#ifdef _WIN32
|
||||
socket_fd = INVALID_SOCKET;
|
||||
#else
|
||||
@ -245,6 +247,14 @@ extern "C" int runt_socket_create() {
|
||||
int no_sigpipe = 1;
|
||||
setsockopt(socket->socket_fd, SOL_SOCKET, SO_NOSIGPIPE, (const char*)&no_sigpipe, sizeof(no_sigpipe));
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
u_long mode = 1;
|
||||
ioctlsocket(socket->socket_fd, FIONBIO, &mode);
|
||||
#else
|
||||
int flags = fcntl(socket->socket_fd, F_GETFL, 0);
|
||||
fcntl(socket->socket_fd, F_SETFL, flags | O_NONBLOCK);
|
||||
#endif
|
||||
socket->isBlocking = false;
|
||||
|
||||
g_sockets[socket_id] = std::move(socket);
|
||||
#ifdef DEBUG_NETWORK
|
||||
@ -399,6 +409,20 @@ extern "C" bool runt_socket_connect(int socket_id, const char* hostname, int por
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
int err = WSAGetLastError();
|
||||
if (err == WSAEWOULDBLOCK || err == WSAEINPROGRESS) {
|
||||
connected = true;
|
||||
socket->connectInProgress = true;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
if (errno == EINPROGRESS || errno == EWOULDBLOCK) {
|
||||
connected = true;
|
||||
socket->connectInProgress = true;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
freeaddrinfo(result);
|
||||
@ -413,7 +437,7 @@ extern "C" bool runt_socket_connect(int socket_id, const char* hostname, int por
|
||||
return false;
|
||||
}
|
||||
|
||||
socket->isConnected = true;
|
||||
socket->isConnected = !socket->connectInProgress;
|
||||
#ifdef DEBUG_NETWORK
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "Connected successfully to %s:%d", hostname, port);
|
||||
#endif
|
||||
@ -447,7 +471,8 @@ extern "C" int runt_socket_send(int socket_id, const char* data, int length) {
|
||||
}
|
||||
|
||||
int total_size = stream_sizes.cbHeader + length + stream_sizes.cbTrailer;
|
||||
char* encrypt_buffer = new char[total_size];
|
||||
socket->ssl_send_buffer_.resize(total_size);
|
||||
char* encrypt_buffer = socket->ssl_send_buffer_.data();
|
||||
|
||||
SecBufferDesc message_desc;
|
||||
SecBuffer message_buffers[4];
|
||||
@ -479,15 +504,12 @@ extern "C" int runt_socket_send(int socket_id, const char* data, int length) {
|
||||
|
||||
if (status != SEC_E_OK) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "SChannel encrypt failed: 0x%x", status);
|
||||
delete[] encrypt_buffer;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int total_encrypted = message_buffers[0].cbBuffer + message_buffers[1].cbBuffer + message_buffers[2].cbBuffer;
|
||||
int sent = send(socket->socket_fd, encrypt_buffer, total_encrypted, 0);
|
||||
|
||||
delete[] encrypt_buffer;
|
||||
|
||||
if (sent != total_encrypted) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Failed to send encrypted SSL data");
|
||||
return -1;
|
||||
@ -644,11 +666,13 @@ extern "C" int runt_socket_recv(int socket_id, int max_length, char** out_data)
|
||||
int received = recv(socket->socket_fd, recv_buffer, sizeof(recv_buffer), 0);
|
||||
if (received <= 0) {
|
||||
delete[] buffer;
|
||||
if (received < 0 && WSAGetLastError() == WSAEWOULDBLOCK) return 0;
|
||||
if (received == 0) {
|
||||
#ifdef DEBUG_NETWORK
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "SSL connection closed by server");
|
||||
#endif
|
||||
return 0;
|
||||
socket->isConnected = false;
|
||||
return -2;
|
||||
} else {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Failed to receive encrypted data for SSL read");
|
||||
return -1;
|
||||
@ -669,11 +693,13 @@ extern "C" int runt_socket_recv(int socket_id, int max_length, char** out_data)
|
||||
int received = recv(socket->socket_fd, recv_buffer, sizeof(recv_buffer), 0);
|
||||
if (received <= 0) {
|
||||
delete[] buffer;
|
||||
if (received < 0 && WSAGetLastError() == WSAEWOULDBLOCK) return 0;
|
||||
if (received == 0) {
|
||||
#ifdef DEBUG_NETWORK
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "SSL connection closed by server (no buffered data)");
|
||||
#endif
|
||||
return 0;
|
||||
socket->isConnected = false;
|
||||
return -2;
|
||||
} else {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Failed to receive encrypted data");
|
||||
return -1;
|
||||
@ -691,6 +717,10 @@ extern "C" int runt_socket_recv(int socket_id, int max_length, char** out_data)
|
||||
if (ssl_error == SSL_ERROR_WANT_READ || ssl_error == SSL_ERROR_WANT_WRITE) {
|
||||
return 0;
|
||||
}
|
||||
if (ssl_error == SSL_ERROR_ZERO_RETURN) {
|
||||
socket->isConnected = false;
|
||||
return -2;
|
||||
}
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "SSL_read failed: %d", ssl_error);
|
||||
return -1;
|
||||
}
|
||||
@ -755,6 +785,143 @@ extern "C" int runt_socket_recv(int socket_id, int max_length, char** out_data)
|
||||
return received;
|
||||
}
|
||||
|
||||
extern "C" int runt_udp_create() {
|
||||
if (!initialize_networking()) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "Failed to initialize networking");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int socket_id = g_next_socket_id++;
|
||||
auto socket = std::make_unique<RunTSocket>(socket_id);
|
||||
|
||||
#ifdef _WIN32
|
||||
socket->socket_fd = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (socket->socket_fd == INVALID_SOCKET) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "UDP socket creation failed: %d",
|
||||
WSAGetLastError());
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
socket->socket_fd = ::socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (socket->socket_fd < 0) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "UDP socket creation failed: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
int reuse = 1;
|
||||
setsockopt(socket->socket_fd, SOL_SOCKET, SO_REUSEADDR,
|
||||
(const char*)&reuse, sizeof(reuse));
|
||||
|
||||
int sndbuf = 256 * 1024;
|
||||
int rcvbuf = 256 * 1024;
|
||||
setsockopt(socket->socket_fd, SOL_SOCKET, SO_SNDBUF,
|
||||
(const char*)&sndbuf, sizeof(sndbuf));
|
||||
setsockopt(socket->socket_fd, SOL_SOCKET, SO_RCVBUF,
|
||||
(const char*)&rcvbuf, sizeof(rcvbuf));
|
||||
|
||||
#ifdef _WIN32
|
||||
u_long mode = 1;
|
||||
ioctlsocket(socket->socket_fd, FIONBIO, &mode);
|
||||
#else
|
||||
int flags = fcntl(socket->socket_fd, F_GETFL, 0);
|
||||
fcntl(socket->socket_fd, F_SETFL, flags | O_NONBLOCK);
|
||||
#endif
|
||||
socket->isBlocking = false;
|
||||
|
||||
g_sockets[socket_id] = std::move(socket);
|
||||
#ifdef DEBUG_NETWORK
|
||||
kinc_log(KINC_LOG_LEVEL_INFO, "UDP socket created: ID %d", socket_id);
|
||||
#endif
|
||||
return socket_id;
|
||||
}
|
||||
|
||||
extern "C" bool runt_udp_bind(int socket_id, const char* address,
|
||||
int port) {
|
||||
return runt_socket_bind(socket_id, address, port);
|
||||
}
|
||||
|
||||
extern "C" int runt_udp_sendto(int socket_id, const char* host, int port,
|
||||
const char* data, int length) {
|
||||
auto it = g_sockets.find(socket_id);
|
||||
if (it == g_sockets.end()) return -1;
|
||||
|
||||
auto& socket = it->second;
|
||||
if (!socket->isValid()) return -1;
|
||||
|
||||
sockaddr_in addr;
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
|
||||
if (inet_pton(AF_INET, host, &addr.sin_addr) <= 0) {
|
||||
struct addrinfo hints, *result;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
if (getaddrinfo(host, nullptr, &hints, &result) != 0) {
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR,
|
||||
"UDP resolve failed: %s", host);
|
||||
return -1;
|
||||
}
|
||||
addr.sin_addr = ((sockaddr_in*)result->ai_addr)->sin_addr;
|
||||
freeaddrinfo(result);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int sent = sendto(socket->socket_fd, data, length, 0,
|
||||
(sockaddr*)&addr, sizeof(addr));
|
||||
if (sent < 0) {
|
||||
int error = WSAGetLastError();
|
||||
if (error == WSAEWOULDBLOCK) return 0;
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "UDP sendto failed: %d", error);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
int sent = sendto(socket->socket_fd, data, length, MSG_NOSIGNAL,
|
||||
(sockaddr*)&addr, sizeof(addr));
|
||||
if (sent < 0) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) return 0;
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "UDP sendto failed: %s",
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
return sent;
|
||||
}
|
||||
|
||||
extern "C" int runt_udp_recvfrom(int socket_id, int max_length,
|
||||
char** out_data, char* out_host, int out_host_len,
|
||||
int* out_port) {
|
||||
auto it = g_sockets.find(socket_id);
|
||||
if (it == g_sockets.end()) return -1;
|
||||
|
||||
auto& socket = it->second;
|
||||
if (!socket->isValid()) return -1;
|
||||
|
||||
char* buffer = new char[max_length];
|
||||
sockaddr_in from;
|
||||
socklen_t fromlen = sizeof(from);
|
||||
|
||||
int received = recvfrom(socket->socket_fd, buffer, max_length, 0,
|
||||
(sockaddr*)&from, &fromlen);
|
||||
if (received < 0) {
|
||||
delete[] buffer;
|
||||
#ifdef _WIN32
|
||||
if (WSAGetLastError() == WSAEWOULDBLOCK) return 0;
|
||||
#else
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) return 0;
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
inet_ntop(AF_INET, &from.sin_addr, out_host, out_host_len);
|
||||
*out_port = ntohs(from.sin_port);
|
||||
*out_data = buffer;
|
||||
return received;
|
||||
}
|
||||
|
||||
extern "C" void runt_socket_close(int socket_id) {
|
||||
auto it = g_sockets.find(socket_id);
|
||||
if (it == g_sockets.end()) return;
|
||||
@ -767,11 +934,45 @@ extern "C" void runt_socket_close(int socket_id) {
|
||||
}
|
||||
|
||||
extern "C" bool runt_socket_is_connected(int socket_id) {
|
||||
auto it = g_sockets.find(socket_id);
|
||||
if (it == g_sockets.end()) return false;
|
||||
|
||||
auto& socket = it->second;
|
||||
return socket->isValid() && socket->isConnected;
|
||||
auto it = g_sockets.find(socket_id);
|
||||
if (it == g_sockets.end()) return false;
|
||||
|
||||
auto& socket = it->second;
|
||||
if (!socket->isValid()) return false;
|
||||
if (socket->isConnected) return true;
|
||||
if (!socket->connectInProgress) return false;
|
||||
|
||||
fd_set wfds, efds;
|
||||
FD_ZERO(&wfds);
|
||||
FD_ZERO(&efds);
|
||||
FD_SET(socket->socket_fd, &wfds);
|
||||
FD_SET(socket->socket_fd, &efds);
|
||||
struct timeval tv = {0, 0};
|
||||
|
||||
int sel;
|
||||
#ifdef _WIN32
|
||||
sel = ::select(0, nullptr, &wfds, &efds, &tv);
|
||||
#else
|
||||
sel = ::select(socket->socket_fd + 1, nullptr, &wfds, &efds, &tv);
|
||||
#endif
|
||||
if (sel <= 0 || (!FD_ISSET(socket->socket_fd, &wfds) &&
|
||||
!FD_ISSET(socket->socket_fd, &efds))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int err = 0;
|
||||
socklen_t errlen = sizeof(err);
|
||||
if (getsockopt(socket->socket_fd, SOL_SOCKET, SO_ERROR, (char*)&err, &errlen) != 0) {
|
||||
socket->connectInProgress = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
socket->connectInProgress = false;
|
||||
if (err == 0) {
|
||||
socket->isConnected = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" void runt_socket_set_blocking(int socket_id, bool blocking) {
|
||||
@ -925,7 +1126,10 @@ extern "C" bool runt_socket_enable_ssl(int socket_id) {
|
||||
|
||||
SSL_set_fd(socket->ssl, socket->socket_fd);
|
||||
|
||||
int flags = fcntl(socket->socket_fd, F_GETFL, 0);
|
||||
fcntl(socket->socket_fd, F_SETFL, flags & ~O_NONBLOCK);
|
||||
int ret = SSL_connect(socket->ssl);
|
||||
fcntl(socket->socket_fd, F_SETFL, flags);
|
||||
if (ret <= 0) {
|
||||
int ssl_error = SSL_get_error(socket->ssl, ret);
|
||||
kinc_log(KINC_LOG_LEVEL_ERROR, "SSL_connect failed: %d", ssl_error);
|
||||
|
||||
Reference in New Issue
Block a user