fix: improve field diagnostics and mirror logs to USB CDC
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
/* Use the same PDP 1 socket path as the working WSS client. No raw ICMP
|
||||
* or optional Ping API; select + SO_ERROR distinguish timeout/refusal/success. */
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "ql_rtos.h"
|
||||
#include "ql_data_call.h"
|
||||
#include "sockets.h"
|
||||
#include "netdb.h"
|
||||
#include "hal_api.h"
|
||||
#include "net_diag_probe.h"
|
||||
#include "net_diag.h"
|
||||
|
||||
static unsigned long probe_ms(void) { return (unsigned long)hal_os_up_time_ms(); }
|
||||
|
||||
void net_diag_probe(const char *host, unsigned short port, net_probe_result *r)
|
||||
{
|
||||
struct addrinfo hints, *addresses = NULL, *address;
|
||||
struct sockaddr_in local;
|
||||
struct ql_data_call_info data;
|
||||
char service[8];
|
||||
unsigned long started;
|
||||
int fd = -1, nonblocking = 1, ret, connect_error;
|
||||
socklen_t error_size;
|
||||
memset(r, 0, sizeof(*r)); r->outcome = PROBE_LOCAL;
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM;
|
||||
snprintf(service, sizeof(service), "%u", (unsigned int)port);
|
||||
if (!net_diag_can_probe()) { r->outcome = PROBE_CANCELLED; return; }
|
||||
started = probe_ms();
|
||||
ret = getaddrinfo_with_pcid(host, service, &hints, &addresses, 1);
|
||||
r->dns_ms = probe_ms() - started; r->dns_result = ret;
|
||||
if (ret != 0 || !addresses) {
|
||||
r->outcome = PROBE_DNS; r->error = ret ? ret : -1;
|
||||
if (addresses) freeaddrinfo(addresses);
|
||||
return;
|
||||
}
|
||||
/* One address per round: avoid multiplying timeout/load by DNS answer count. */
|
||||
for (address = addresses; address; address = address->ai_next)
|
||||
if (address->ai_family == AF_INET && address->ai_addr &&
|
||||
address->ai_addrlen >= sizeof(struct sockaddr_in)) break;
|
||||
if (!address) { r->outcome = PROBE_DNS; r->error = -1; goto done; }
|
||||
inet_ntop(AF_INET, &((struct sockaddr_in *)address->ai_addr)->sin_addr, r->address, sizeof(r->address));
|
||||
if (!net_diag_can_probe()) { r->outcome = PROBE_CANCELLED; goto done; }
|
||||
memset(&data, 0, sizeof(data));
|
||||
ret = ql_get_data_call_info(1, 0, &data);
|
||||
if (ret != 0 || data.v4.state != 1) { r->error = ret ? ret : -1; goto done; }
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0) { r->error = ql_get_soc_errno(); goto done; }
|
||||
if (ioctl(fd, FIONBIO, &nonblocking) != 0) { r->error = ql_get_soc_errno(); goto done; }
|
||||
memset(&local, 0, sizeof(local));
|
||||
local.sin_family = AF_INET; local.sin_port = htons(ql_soc_generate_port());
|
||||
local.sin_addr = data.v4.addr.ip;
|
||||
if (bind(fd, (struct sockaddr *)&local, sizeof(local)) != 0) { r->error = ql_get_soc_errno(); goto done; }
|
||||
started = probe_ms();
|
||||
ret = connect(fd, address->ai_addr, address->ai_addrlen);
|
||||
r->tcp_started = 1;
|
||||
if (ret == 0) { r->outcome = PROBE_OK; goto connected; }
|
||||
connect_error = ql_get_soc_errno();
|
||||
if (connect_error != EINPROGRESS && connect_error != EWOULDBLOCK && connect_error != EALREADY) {
|
||||
r->outcome = PROBE_CONNECT; r->error = connect_error; goto connected;
|
||||
}
|
||||
/* Short slices allow OTA/sleep/shutdown to cancel within one select slice. */
|
||||
r->outcome = PROBE_TIMEOUT;
|
||||
while ((unsigned long)(probe_ms() - started) < 3000UL) {
|
||||
fd_set writable, exceptional;
|
||||
struct timeval wait;
|
||||
int error = 0;
|
||||
if (!net_diag_can_probe()) { r->outcome = PROBE_CANCELLED; break; }
|
||||
FD_ZERO(&writable); FD_ZERO(&exceptional);
|
||||
FD_SET(fd, &writable); FD_SET(fd, &exceptional);
|
||||
{
|
||||
unsigned long remaining = 3000UL - (unsigned long)(probe_ms() - started);
|
||||
if (remaining > 3000UL) break;
|
||||
wait.tv_sec = 0; wait.tv_usec = (remaining < 200UL ? remaining : 200UL) * 1000UL;
|
||||
}
|
||||
ret = select(fd + 1, NULL, &writable, &exceptional, &wait);
|
||||
if (ret < 0) { r->outcome = PROBE_LOCAL; r->error = ql_get_soc_errno(); break; }
|
||||
if (ret == 0) continue;
|
||||
if (!FD_ISSET(fd, &writable) && !FD_ISSET(fd, &exceptional)) continue;
|
||||
error_size = sizeof(error);
|
||||
ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &error_size);
|
||||
if (ret != 0) { r->outcome = PROBE_LOCAL; r->error = ql_get_soc_errno(); }
|
||||
else { r->error = error; r->outcome = error == 0 ? PROBE_OK : PROBE_CONNECT; }
|
||||
break;
|
||||
}
|
||||
connected:
|
||||
r->tcp_ms = probe_ms() - started;
|
||||
done:
|
||||
if (fd >= 0) close(fd);
|
||||
freeaddrinfo(addresses);
|
||||
}
|
||||
Reference in New Issue
Block a user