2025-04-28 12:25:20 +08:00
|
|
|
#include "XNUDPService.h"
|
|
|
|
#include "XNUDPService_p.h"
|
|
|
|
#include <XNCore/XNServiceManager.h>
|
|
|
|
#include <XNCore/XNDDSManager.h>
|
2025-05-22 16:22:48 +08:00
|
|
|
#include <fstream>
|
|
|
|
#include <sstream>
|
|
|
|
#include <cstring>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <XNCore/XNByteArray.h>
|
|
|
|
|
|
|
|
XN_SERVICE_INITIALIZE(XNUDPService)
|
|
|
|
|
|
|
|
XNUDPService::XNUDPService() : XNServiceObject(new XNUDPServicePrivate())
|
2025-04-28 12:25:20 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
XNUDPService::~XNUDPService()
|
|
|
|
{
|
2025-05-22 16:22:48 +08:00
|
|
|
T_D();
|
|
|
|
if (d->udpSocket >= 0) {
|
|
|
|
close(d->udpSocket);
|
|
|
|
d->udpSocket = -1;
|
|
|
|
}
|
|
|
|
};
|
2025-04-28 12:25:20 +08:00
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
XNUDPService::XNUDPService(PrivateType *p) : XNServiceObject(p)
|
2025-04-28 12:25:20 +08:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
void XNUDPService::Initialize()
|
2025-04-28 12:25:20 +08:00
|
|
|
{
|
2025-05-22 16:22:48 +08:00
|
|
|
XNServiceObject::Initialize();
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
// 读取配置文件
|
2025-05-22 16:22:48 +08:00
|
|
|
std::ifstream file(GetXmlPath());
|
|
|
|
if (!file.is_open()) {
|
|
|
|
LOG_WARNING("Failed to open config file:%s", GetXmlPath().c_str());
|
2025-04-28 12:25:20 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
std::stringstream buffer;
|
|
|
|
buffer << file.rdbuf();
|
|
|
|
std::string content = buffer.str();
|
2025-04-28 12:25:20 +08:00
|
|
|
file.close();
|
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
// 简单的XML解析
|
|
|
|
size_t udpPos = content.find("<UDP>");
|
|
|
|
if (udpPos != std::string::npos) {
|
|
|
|
size_t localPortPos = content.find("<LocalPort>", udpPos);
|
|
|
|
size_t targetHostPos = content.find("<TargetHost>", udpPos);
|
|
|
|
size_t targetPortPos = content.find("<TargetPort>", udpPos);
|
|
|
|
|
|
|
|
if (localPortPos != std::string::npos) {
|
|
|
|
size_t endPos = content.find("</LocalPort>", localPortPos);
|
|
|
|
d->localPort = std::stoi(content.substr(localPortPos + 11, endPos - localPortPos - 11));
|
|
|
|
}
|
|
|
|
if (targetHostPos != std::string::npos) {
|
|
|
|
size_t endPos = content.find("</TargetHost>", targetHostPos);
|
|
|
|
d->targetHost = content.substr(targetHostPos + 12, endPos - targetHostPos - 12);
|
|
|
|
}
|
|
|
|
if (targetPortPos != std::string::npos) {
|
|
|
|
size_t endPos = content.find("</TargetPort>", targetPortPos);
|
|
|
|
d->targetPort =
|
|
|
|
std::stoi(content.substr(targetPortPos + 12, endPos - targetPortPos - 12));
|
|
|
|
}
|
2025-04-28 12:25:20 +08:00
|
|
|
} else {
|
|
|
|
LOG_WARNING("UDP configuration not found, using default values");
|
|
|
|
d->localPort = 12345;
|
|
|
|
d->targetHost = "127.0.0.1";
|
|
|
|
d->targetPort = 54321;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
void XNUDPService::PrepareForExecute()
|
2025-04-28 12:25:20 +08:00
|
|
|
{
|
2025-05-22 16:22:48 +08:00
|
|
|
XNServiceObject::PrepareForExecute();
|
|
|
|
T_D();
|
2025-04-28 12:25:20 +08:00
|
|
|
// 初始化UDP socket
|
2025-05-22 16:22:48 +08:00
|
|
|
d->udpSocket = socket(AF_INET, SOCK_DGRAM, 0);
|
|
|
|
if (d->udpSocket < 0) {
|
|
|
|
LOG_WARNING("Failed to create UDP socket");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 设置非阻塞模式
|
|
|
|
int flags = fcntl(d->udpSocket, F_GETFL, 0);
|
|
|
|
fcntl(d->udpSocket, F_SETFL, flags | O_NONBLOCK);
|
2025-04-28 12:25:20 +08:00
|
|
|
|
|
|
|
// 绑定本地端口
|
2025-05-22 16:22:48 +08:00
|
|
|
struct sockaddr_in localAddr;
|
|
|
|
memset(&localAddr, 0, sizeof(localAddr));
|
|
|
|
localAddr.sin_family = AF_INET;
|
|
|
|
localAddr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
localAddr.sin_port = htons(d->localPort);
|
|
|
|
|
|
|
|
if (bind(d->udpSocket, (struct sockaddr *)&localAddr, sizeof(localAddr)) < 0) {
|
|
|
|
LOG_WARNING("UDP socket bind failed on port:%d", d->localPort);
|
|
|
|
close(d->udpSocket);
|
|
|
|
d->udpSocket = -1;
|
2025-04-28 12:25:20 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RegisterRTEventHandler("SendUDPData",
|
|
|
|
std::bind(&XNUDPService::SendData, this, std::placeholders::_1));
|
|
|
|
}
|
|
|
|
|
|
|
|
void XNUDPService::HandleIncomingData()
|
|
|
|
{
|
2025-05-22 16:22:48 +08:00
|
|
|
T_D();
|
|
|
|
if (d->udpSocket < 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
char buffer[65536];
|
|
|
|
struct sockaddr_in senderAddr;
|
|
|
|
socklen_t senderLen = sizeof(senderAddr);
|
2025-04-28 12:25:20 +08:00
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
while (true) {
|
|
|
|
ssize_t bytesRead = recvfrom(d->udpSocket, buffer, sizeof(buffer), 0,
|
|
|
|
(struct sockaddr *)&senderAddr, &senderLen);
|
2025-04-28 12:25:20 +08:00
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
if (bytesRead <= 0) {
|
|
|
|
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
|
|
break; // 没有更多数据
|
|
|
|
}
|
|
|
|
LOG_WARNING("Error reading from UDP socket");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bytesRead <= 6) {
|
|
|
|
LOG_WARNING("Invalid size of UDP datagram received, size:%zd", bytesRead);
|
2025-04-28 16:41:21 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
// 解析数据包头
|
|
|
|
uint8_t header = buffer[0];
|
|
|
|
uint8_t type = buffer[1];
|
|
|
|
uint8_t subType1 = buffer[2];
|
|
|
|
uint8_t subType2 = buffer[3];
|
|
|
|
uint16_t size = (buffer[4] << 8) | buffer[5];
|
|
|
|
|
2025-04-28 16:41:21 +08:00
|
|
|
if (header != 0x0b) {
|
2025-05-22 16:22:48 +08:00
|
|
|
LOG_WARNING("Invalid header of UDP datagram received, header:%d", header);
|
2025-04-28 16:41:21 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
if (bytesRead < size) {
|
|
|
|
LOG_WARNING("Invalid size of UDP datagram received, size:%zd, expected:%d", bytesRead,
|
|
|
|
size);
|
2025-04-28 12:25:20 +08:00
|
|
|
continue;
|
|
|
|
}
|
2025-04-28 16:41:21 +08:00
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
std::vector<uint8_t> datagram(buffer, buffer + bytesRead);
|
|
|
|
|
2025-04-28 16:41:21 +08:00
|
|
|
if (type == 0x04) {
|
|
|
|
if (subType1 == 0x00 && subType2 == 0x00) {
|
2025-04-29 11:55:56 +08:00
|
|
|
TriggerRTEvent("ATA04AeroInput", datagram);
|
2025-04-28 12:25:20 +08:00
|
|
|
continue;
|
2025-04-28 16:41:21 +08:00
|
|
|
} else if (subType1 == 0x01 && subType2 == 0x00) {
|
2025-04-29 11:55:56 +08:00
|
|
|
TriggerRTEvent("ATA04GhInput", datagram);
|
2025-04-28 12:25:20 +08:00
|
|
|
continue;
|
2025-04-28 16:41:21 +08:00
|
|
|
} else if (subType1 == 0x02 && subType2 == 0x00) {
|
2025-04-29 11:55:56 +08:00
|
|
|
TriggerRTEvent("ATA04WbInput", datagram);
|
2025-04-28 12:25:20 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2025-04-29 11:55:56 +08:00
|
|
|
TriggerRTEvent("ReceiveUDPData", datagram);
|
2025-04-28 12:25:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
void XNUDPService::SendData(const std::any &data)
|
2025-04-28 12:25:20 +08:00
|
|
|
{
|
2025-05-22 16:22:48 +08:00
|
|
|
T_D();
|
|
|
|
if (d->udpSocket < 0) {
|
2025-04-28 12:25:20 +08:00
|
|
|
LOG_WARNING("UDP socket not initialized");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
struct sockaddr_in targetAddr;
|
|
|
|
memset(&targetAddr, 0, sizeof(targetAddr));
|
|
|
|
targetAddr.sin_family = AF_INET;
|
|
|
|
targetAddr.sin_port = htons(d->targetPort);
|
|
|
|
inet_pton(AF_INET, d->targetHost.c_str(), &targetAddr.sin_addr);
|
|
|
|
|
|
|
|
XNByteArray packet = std::any_cast<XNByteArray>(data);
|
|
|
|
ssize_t bytesSent = sendto(d->udpSocket, packet.data(), packet.size(), 0,
|
|
|
|
(struct sockaddr *)&targetAddr, sizeof(targetAddr));
|
2025-04-28 12:25:20 +08:00
|
|
|
|
2025-05-22 16:22:48 +08:00
|
|
|
if (bytesSent < 0) {
|
|
|
|
LOG_WARNING("Failed to send UDP datagram: %s", strerror(errno));
|
2025-04-28 12:25:20 +08:00
|
|
|
}
|
|
|
|
}
|