Add native Windows build of meshtasticd (#11031)

This commit is contained in:
Thomas Göttgens authored and GitHub committed 2026-07-19 23:31:19 +02:00
1 parent 4726375282
commit a808e992a1
16 files changed
+910 -21

No files matched your search

+92 -11
View File
@@ -3,13 +3,92 @@
#include "GpsdSerial.h"
#include "configuration.h"
#include <arpa/inet.h>
#include <cerrno>
#ifdef _WIN32
#include <mutex>
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#endif
namespace
{
// Winsock needs explicit init, closesocket(), ioctlsocket() and WSAGetLastError().
// SOCKET fits the header's `int` on Win64, and INVALID_SOCKET narrows to -1.
#ifdef _WIN32
// Done lazily to keep the dependency local to the one file that needs it.
void initSocketsOnce()
{
static std::once_flag flag;
std::call_once(flag, [] {
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
});
}
void closeSocket(int fd)
{
::closesocket(static_cast<SOCKET>(fd));
}
void setNonBlocking(int fd)
{
u_long mode = 1;
::ioctlsocket(static_cast<SOCKET>(fd), FIONBIO, &mode);
}
// Winsock has no MSG_DONTWAIT, but the socket is already non-blocking so a plain
// recv() has the same semantics.
int recvNonBlocking(int fd, void *buf, size_t len)
{
return ::recv(static_cast<SOCKET>(fd), static_cast<char *>(buf), static_cast<int>(len), 0);
}
int sendAll(int fd, const void *buf, size_t len)
{
return ::send(static_cast<SOCKET>(fd), static_cast<const char *>(buf), static_cast<int>(len), 0);
}
bool lastErrorWasWouldBlock()
{
return WSAGetLastError() == WSAEWOULDBLOCK;
}
#else
void initSocketsOnce() {}
void closeSocket(int fd)
{
::close(fd);
}
void setNonBlocking(int fd)
{
::fcntl(fd, F_SETFL, O_NONBLOCK);
}
int recvNonBlocking(int fd, void *buf, size_t len)
{
return static_cast<int>(::recv(fd, buf, len, MSG_DONTWAIT));
}
int sendAll(int fd, const void *buf, size_t len)
{
return static_cast<int>(::write(fd, buf, len));
}
bool lastErrorWasWouldBlock()
{
return errno == EAGAIN || errno == EWOULDBLOCK;
}
#endif
} // namespace
namespace arduino
{
@@ -28,6 +107,8 @@ bool GpsdSerial::connectToGpsd()
if (_host.empty())
return false;
initSocketsOnce();
struct addrinfo hints = {}, *res = nullptr;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
@@ -41,12 +122,12 @@ bool GpsdSerial::connectToGpsd()
// Try every address returned by getaddrinfo (e.g. ::1 before 127.0.0.1).
int fd = -1;
for (struct addrinfo *rp = res; rp != nullptr; rp = rp->ai_next) {
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
fd = static_cast<int>(socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol));
if (fd < 0)
continue;
if (connect(fd, rp->ai_addr, rp->ai_addrlen) == 0)
if (connect(fd, rp->ai_addr, static_cast<int>(rp->ai_addrlen)) == 0)
break; // connected
::close(fd);
closeSocket(fd);
fd = -1;
}
freeaddrinfo(res);
@@ -57,11 +138,11 @@ bool GpsdSerial::connectToGpsd()
}
// Switch to non-blocking so available()/read() never stall the GPS thread.
fcntl(fd, F_SETFL, O_NONBLOCK);
setNonBlocking(fd);
// Ask gpsd to stream raw NMEA sentences.
const char watchCmd[] = "?WATCH={\"enable\":true,\"nmea\":true}\n";
::write(fd, watchCmd, sizeof(watchCmd) - 1);
sendAll(fd, watchCmd, sizeof(watchCmd) - 1);
_sockfd = fd;
_rxBuf.clear();
@@ -80,7 +161,7 @@ void GpsdSerial::begin(unsigned long /*baud*/, uint16_t /*config*/)
void GpsdSerial::end()
{
if (_sockfd >= 0) {
::close(_sockfd);
closeSocket(_sockfd);
_sockfd = -1;
}
_rxBuf.clear();
@@ -96,18 +177,18 @@ void GpsdSerial::fillBuffer()
return;
uint8_t tmp[256];
ssize_t n;
while (_rxBuf.size() < RX_BUF_MAX && (n = recv(_sockfd, tmp, sizeof(tmp), MSG_DONTWAIT)) > 0) {
int n;
while (_rxBuf.size() < RX_BUF_MAX && (n = recvNonBlocking(_sockfd, tmp, sizeof(tmp))) > 0) {
size_t space = RX_BUF_MAX - _rxBuf.size();
size_t toCopy = (static_cast<size_t>(n) < space) ? static_cast<size_t>(n) : space;
for (size_t i = 0; i < toCopy; i++)
_rxBuf.push_back(tmp[i]);
}
if (n == 0 || (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) {
if (n == 0 || (n < 0 && !lastErrorWasWouldBlock())) {
// gpsd closed the connection or a real error occurred.
LOG_WARN("gpsdSerial: disconnected, will retry");
::close(_sockfd);
closeSocket(_sockfd);
_sockfd = -1;
_rxBuf.clear();
}