release: 1.4.4 — channel «Облако» (WebSocket via KeenDNS cloud to own Keenetic): wsgw gateway, Android 1.4.4, iOS, docs/cloud.md
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
* wg-obfuscator (one instance, iOS forbids fork) sends to 127.0.0.1:<local>;
|
||||
* we forward either over UDP to the server's obfuscator port or over TCP to
|
||||
* the server's udptcp (frames: 2-byte length + packet). Switch with pcarelay_use_tcp().
|
||||
* Mode 2 ("Облако"): packets go to a Swift callback (WebSocket to the user's Keenetic), answers come back via pcarelay_ws_in().
|
||||
*/
|
||||
#include "pcarelay.h"
|
||||
#include <arpa/inet.h>
|
||||
@@ -18,7 +19,12 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static atomic_int use_tcp = 0;
|
||||
static atomic_int use_tcp = 0; /* 0 udp, 1 tcp, 2 ws */
|
||||
static pcarelay_ws_out_fn ws_out;
|
||||
static int g_local = -1;
|
||||
static pthread_mutex_t peer_mu = PTHREAD_MUTEX_INITIALIZER;
|
||||
static struct sockaddr_storage g_peer;
|
||||
static socklen_t g_pl;
|
||||
static atomic_ullong rx_bytes = 0;
|
||||
static char g_host[256], g_udp_port[8], g_tcp_port[8];
|
||||
static int g_local_port;
|
||||
@@ -59,15 +65,17 @@ static void *loop(void *arg) {
|
||||
la.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
int local = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (local < 0 || bind(local, (struct sockaddr *)&la, sizeof la) < 0) return NULL;
|
||||
g_local = local;
|
||||
int udp = -1, tcp = -1;
|
||||
struct sockaddr_storage peer; socklen_t pl = 0;
|
||||
unsigned char buf[65537];
|
||||
time_t last_dial = 0;
|
||||
for (;;) {
|
||||
int want_tcp = atomic_load(&use_tcp);
|
||||
int mode = atomic_load(&use_tcp), want_tcp = mode == 1;
|
||||
if (mode == 2) { if (udp >= 0) { close(udp); udp = -1; } if (tcp >= 0) { close(tcp); tcp = -1; } }
|
||||
if (!want_tcp && tcp >= 0) { close(tcp); tcp = -1; }
|
||||
if (want_tcp && udp >= 0) { close(udp); udp = -1; }
|
||||
if (!want_tcp && udp < 0 && time(NULL) != last_dial) { last_dial = time(NULL); udp = dial(SOCK_DGRAM, g_udp_port); }
|
||||
if (mode == 0 && udp < 0 && time(NULL) != last_dial) { last_dial = time(NULL); udp = dial(SOCK_DGRAM, g_udp_port); }
|
||||
int up = want_tcp ? tcp : udp;
|
||||
struct pollfd p[2] = {{local, POLLIN, 0}, {up, POLLIN, 0}};
|
||||
poll(p, up >= 0 ? 2 : 1, 1000);
|
||||
@@ -75,7 +83,10 @@ static void *loop(void *arg) {
|
||||
pl = sizeof peer;
|
||||
ssize_t n = recvfrom(local, buf, 65535, 0, (struct sockaddr *)&peer, &pl);
|
||||
if (n <= 0) continue;
|
||||
if (want_tcp) {
|
||||
pthread_mutex_lock(&peer_mu); g_peer = peer; g_pl = pl; pthread_mutex_unlock(&peer_mu);
|
||||
if (mode == 2) {
|
||||
if (ws_out) ws_out(buf, (int)n);
|
||||
} else if (want_tcp) {
|
||||
if (tcp < 0 && time(NULL) != last_dial) { last_dial = time(NULL); tcp = dial(SOCK_STREAM, g_tcp_port); }
|
||||
if (tcp >= 0) {
|
||||
unsigned char h[2] = {(unsigned char)(n >> 8), (unsigned char)n};
|
||||
@@ -114,5 +125,17 @@ int pcarelay_start(int local_port, const char *host, int udp_port, int tcp_port)
|
||||
}
|
||||
|
||||
void pcarelay_use_tcp(int on) { atomic_store(&use_tcp, on ? 1 : 0); }
|
||||
int pcarelay_is_tcp(void) { return atomic_load(&use_tcp); }
|
||||
int pcarelay_is_tcp(void) { return atomic_load(&use_tcp) == 1; }
|
||||
|
||||
void pcarelay_use_ws(pcarelay_ws_out_fn out) { ws_out = out; atomic_store(&use_tcp, 2); }
|
||||
int pcarelay_is_ws(void) { return atomic_load(&use_tcp) == 2; }
|
||||
|
||||
void pcarelay_ws_in(const unsigned char *p, int n) {
|
||||
if (g_local < 0 || n <= 0) return;
|
||||
atomic_fetch_add(&rx_bytes, (unsigned long long)n);
|
||||
pthread_mutex_lock(&peer_mu);
|
||||
struct sockaddr_storage peer = g_peer; socklen_t pl = g_pl;
|
||||
pthread_mutex_unlock(&peer_mu);
|
||||
if (pl) sendto(g_local, p, (size_t)n, 0, (struct sockaddr *)&peer, pl);
|
||||
}
|
||||
unsigned long long pcarelay_rx_bytes(void) { return atomic_load(&rx_bytes); }
|
||||
|
||||
Reference in New Issue
Block a user