-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRP2CEmulator.cpp
151 lines (132 loc) · 3.9 KB
/
RP2CEmulator.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include "RP2CEmulator.h"
#include "NetworkTools.h"
#include <unistd.h>
#include <string.h>
#include <syslog.h>
#include <arpa/inet.h>
// #include "Dump.h"
#define RP2C_POLL_INTERVAL 15
#define RP2C_DATA_TIMEOUT 60
RP2CEmulator::RP2CEmulator(const char* address, int port) :
onReport(NULL),
number(0),
time1(0),
time2(0)
{
handle = OpenUDPSocket(address, port);
}
RP2CEmulator::~RP2CEmulator()
{
close(handle);
}
void RP2CEmulator::report(int priority, const char* format, ...)
{
if (onReport != NULL)
{
va_list arguments;
va_start(arguments, format);
onReport(priority, format, arguments);
va_end(arguments);
}
}
void RP2CEmulator::poll()
{
struct DSTR data;
memcpy(data.header.sign, DSTR_DATA_SIGN, RP2C_SIGN_LENGTH);
data.header.number = htobe16(number);
data.header.type = htole16(DSTR_TYPE_POLL);
data.header.length = 0;
sendto(handle, &data, sizeof(struct DSTRHeader),
0, (struct sockaddr*)&address, sizeof(struct sockaddr_in));
}
void RP2CEmulator::initiateConnection(const struct sockaddr_in& address)
{
memcpy(&this->address, &address, sizeof(struct sockaddr_in));
poll();
}
void RP2CEmulator::publishHeard(const struct DStarRoute& route)
{
struct DSTR data;
memcpy(data.header.sign, DSTR_DATA_SIGN, RP2C_SIGN_LENGTH);
data.header.number = htobe16(number);
data.header.type = htole16(DSTR_TYPE_LAST_HEARD);
data.header.length = sizeof(struct HeardData);
memcpy(data.data.heard.ownCall, route.ownCall1, LONG_CALLSIGN_LENGTH);
memcpy(data.data.heard.repeater1, route.repeater1, LONG_CALLSIGN_LENGTH);
sendto(handle, &data, sizeof(struct DSTRHeader) + sizeof(struct HeardData),
0, (struct sockaddr*)&address, sizeof(struct sockaddr_in));
}
void RP2CEmulator::handleInitialMessage(const struct sockaddr_in& address, struct DSTR* data)
{
time_t now = time(NULL);
if ((data->header.type == htole16(DSTR_TYPE_POLL)) && (now > time1))
{
memcpy(&this->address, &address, sizeof(struct sockaddr_in));
number = be16toh(data->header.number) + 1;
data->header.type = DSTR_TYPE_ACK;
sendto(handle, data, sizeof(struct DSTRHeader),
0, (struct sockaddr*)&address, sizeof(struct sockaddr_in));
}
report(LOG_INFO, "RP2C: connected to %s\n", inet_ntoa(address.sin_addr));
time1 = now + RP2C_POLL_INTERVAL;
time2 = now + RP2C_DATA_TIMEOUT;
}
void RP2CEmulator::handleControllerMessage(const struct sockaddr_in& address, struct DSTR* data)
{
if (data->header.type == htole16(DSTR_TYPE_ACK))
{
number = be16toh(data->header.number) + 1;
time2 = time(NULL) + RP2C_DATA_TIMEOUT;
}
if (data->header.type & DSTR_FLAG_SENT)
{
number = be16toh(data->header.number) + 1;
data->header.type = DSTR_TYPE_ACK;
data->header.length = 0;
sendto(handle, data, sizeof(struct DSTRHeader),
0, (struct sockaddr*)&address, sizeof(struct sockaddr_in));
}
}
void RP2CEmulator::receiveData()
{
char buffer[RP2C_BUFFER_SIZE];
struct sockaddr_in address;
socklen_t size = sizeof(address);
ssize_t length = recvfrom(handle, buffer, sizeof(buffer), 0, (struct sockaddr*)&address, &size);
// dump("RP2C", buffer, length);
if ((length > 0) && (strncmp(buffer, DSTR_INIT_SIGN, RP2C_SIGN_LENGTH) == 0))
handleInitialMessage(address, (struct DSTR*)buffer);
if ((length > 0) && (strncmp(buffer, DSTR_DATA_SIGN, RP2C_SIGN_LENGTH) == 0))
handleControllerMessage(address, (struct DSTR*)buffer);
}
void RP2CEmulator::doBackgroundActivity()
{
time_t now = time(NULL);
if ((now > time1) && (now < time2))
{
poll();
time1 = now + RP2C_POLL_INTERVAL;
}
if ((now >= time2) && (time1 != 0))
{
report(LOG_ERR, "RP2C: connection timed out\n");
time1 = 0;
}
}
int RP2CEmulator::getHandle()
{
return handle;
}
bool RP2CEmulator::isConnected()
{
return (time1 != 0);
}
bool RP2CEmulator::assertConnection()
{
if (time1 == 0)
{
report(LOG_ERR, "RP2C: gateway not connected\n");
return false;
}
return true;
}