PUD: make name a normal char array in _TRxTxNetworkInterface
[olsrd.git] / lib / pud / src / pud.c
1 #include "pud.h"
2
3 /* Plugin includes */
4 #include "dedup.h"
5 #include "networkInterfaces.h"
6 #include "configuration.h"
7 #include "gpsConversion.h"
8 #include "receiver.h"
9 #include "state.h"
10 #include "compiler.h"
11
12 /* OLSRD includes */
13 #include "olsr.h"
14 #include "ipcalc.h"
15 #include "net_olsr.h"
16 #include "parser.h"
17
18 /* System includes */
19
20 /** The size of the buffer in which the received NMEA string is stored */
21 #define BUFFER_SIZE_RX_NMEA             2048
22
23 /** The size of the buffer in which the received downlink message is stored */
24 #define BUFFER_SIZE_RX_DOWNLINK 2048
25
26 /** The size of the buffer in which the converted NMEA string is assembled for
27  * transmission over OSLR */
28 #define BUFFER_SIZE_TX_OLSR     512
29
30 /** The de-duplication list */
31 static DeDupList deDupList;
32
33 /**
34  Report a plugin error.
35
36  @param useErrno
37  when true then errno is used in the error message; the error reason is also
38  reported.
39  @param format
40  a pointer to the format string
41  @param ...
42  arguments to the format string
43  */
44 void pudError(bool useErrno, const char *format, ...) {
45         char strDesc[256];
46         char *stringErr = NULL;
47
48         if (useErrno) {
49                 stringErr = strerror(errno);
50         }
51
52         if ((format == NULL) || (*format == '\0')) {
53                 if (useErrno) {
54                         olsr_printf(0, "%s: %s\n", PUD_PLUGIN_ABBR, stringErr);
55                 } else {
56                         olsr_printf(0, "%s: Unknown error\n", PUD_PLUGIN_ABBR);
57                 }
58         } else {
59                 va_list arglist;
60
61                 va_start(arglist, format);
62                 vsnprintf(strDesc, sizeof(strDesc), format, arglist);
63                 va_end(arglist);
64
65                 strDesc[sizeof(strDesc) - 1] = '\0'; /* Ensures null termination */
66
67                 if (useErrno) {
68                         olsr_printf(0, "%s: %s: %s\n", PUD_PLUGIN_ABBR, strDesc, stringErr);
69                 } else {
70                         olsr_printf(0, "%s: %s\n", PUD_PLUGIN_ABBR, strDesc);
71                 }
72         }
73 }
74
75 /**
76  Sends a buffer out on all transmit interfaces
77
78  @param buffer
79  the buffer
80  @param bufferLength
81  the number of bytes in the buffer
82  */
83 static void sendToAllTxInterfaces(unsigned char *buffer,
84                 unsigned int bufferLength) {
85         union olsr_sockaddr * txAddress = getTxMcAddr();
86         void * addr;
87         socklen_t addrSize;
88         TRxTxNetworkInterface *txNetworkInterfaces = getTxNetworkInterfaces();
89
90         if (txAddress->in.sa_family == AF_INET) {
91                 addr = &txAddress->in4;
92                 addrSize = sizeof(struct sockaddr_in);
93         } else {
94                 addr = &txAddress->in6;
95                 addrSize = sizeof(struct sockaddr_in6);
96         }
97
98         while (txNetworkInterfaces != NULL) {
99                 TRxTxNetworkInterface *networkInterface = txNetworkInterfaces;
100                 errno = 0;
101                 if (sendto(networkInterface->socketFd, buffer, bufferLength, 0, addr, addrSize) < 0) {
102                         pudError(true, "Transmit error on interface %s", &networkInterface->name[0]);
103                 }
104                 txNetworkInterfaces = networkInterface->next;
105         }
106 }
107
108 /**
109  Called by OLSR core when a packet for the plugin is received from the OLSR
110  network. It converts the packet into an NMEA string and transmits it over all
111  transmit non-OLSR network interfaces.
112
113  @param olsrMessage
114  a pointer to the received OLSR message
115  @param in_if
116  a pointer to the OLSR network interface on which the packet was received
117  @param ipaddr
118  a pointer to the IP address of the sender
119
120  @return
121  - true when the packet was processed
122  - false otherwise
123  */
124 bool packetReceivedFromOlsr(union olsr_message *olsrMessage,
125                 struct interface *in_if __attribute__ ((unused)), union olsr_ip_addr *ipaddr __attribute__ ((unused))) {
126         const union olsr_ip_addr * originator = getOlsrMessageOriginator(
127                         olsr_cnf->ip_version, olsrMessage);
128         unsigned int transmitStringLength;
129         unsigned char buffer[BUFFER_SIZE_TX_OLSR];
130
131         /* when we do not loopback then check if the message originated from this
132          * node: back off */
133         if (!getUseLoopback() && ipequal(originator, &olsr_cnf->main_addr)) {
134                 return false;
135         }
136
137         /* do deduplication: when we have already seen this message from the same
138          * originator then just back off */
139         if (likely(getUseDeDup())) {
140                 if (isInDeDupList(&deDupList, olsrMessage)) {
141                         return false;
142                 }
143
144                 addToDeDup(&deDupList, olsrMessage);
145         }
146
147         transmitStringLength = gpsFromOlsr(olsrMessage, &buffer[0], sizeof(buffer));
148         if (unlikely(transmitStringLength == 0)) {
149                 return false;
150         }
151
152         sendToAllTxInterfaces(&buffer[0], transmitStringLength);
153
154         return true;
155 }
156
157 /**
158  Called by OLSR core when a packet for the plugin is received from the downlink.
159  It unpacks the messages and distributes them into OLSR and on the LAN.
160
161  @param skfd
162  the socket file descriptor on which the packet is received
163  @param data
164  a pointer to the network interface structure on which the packet was received
165  @param flags
166  unused
167  */
168 static void packetReceivedFromDownlink(int skfd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
169         if (skfd >= 0) {
170                 unsigned char rxBuffer[BUFFER_SIZE_RX_DOWNLINK];
171                 ssize_t rxCount = 0;
172                 ssize_t rxIndex = 0;
173
174                 /* Receive the captured Ethernet frame */
175                 errno = 0;
176                 rxCount = recvfrom(skfd, &rxBuffer[0], (sizeof(rxBuffer) - 1), 0, NULL, NULL);
177                 if (rxCount < 0) {
178                         pudError(true, "Receive error in %s, ignoring message.", __func__);
179                         return;
180                 }
181
182                 while (rxIndex < rxCount) {
183                         UplinkMessage * msg = (UplinkMessage *) &rxBuffer[rxIndex];
184                         uint8_t type;
185                         uint16_t uplinkMessageLength;
186                         uint16_t olsrMessageLength;
187                         bool ipv6;
188                         union olsr_message * olsrMessage;
189
190                         type = getUplinkMessageType(&msg->header);
191                         olsrMessageLength = getUplinkMessageLength(&msg->header);
192                         uplinkMessageLength = olsrMessageLength + sizeof(UplinkHeader);
193
194                         if (unlikely((rxIndex + uplinkMessageLength) > rxCount)) {
195                                 pudError(false, "Received wrong length (%d) in %s,"
196                                                 " ignoring the rest of the messages.", olsrMessageLength,
197                                                 __func__);
198                                 return;
199                         }
200
201                         rxIndex += uplinkMessageLength;
202
203                         if (type != POSITION) {
204                                 pudError(false, "Received wrong type (%d) in %s,"
205                                                 " ignoring message.", type, __func__);
206                                 continue;
207                         }
208
209                         ipv6 = getUplinkMessageIPv6(&msg->header);
210                         if (unlikely(ipv6 && (olsr_cnf->ip_version != AF_INET6))) {
211                                 pudError(false, "Received wrong IPv6 status (%s) in %s,"
212                                                 " ignoring message.", (ipv6 ? "true" : "false"),
213                                                 __func__);
214                                 continue;
215                         }
216
217                         olsrMessage = &msg->msg.olsrMessage;
218
219                         /* we now have a position update (olsrMessage) of a certain length
220                          * (olsrMessageLength). this needs to be transmitted over OLSR and on the LAN */
221
222                         /* send out over OLSR interfaces */
223                         {
224                                 int r;
225                                 struct interface *ifn;
226                                 for (ifn = ifnet; ifn; ifn = ifn->int_next) {
227                                         r = net_outbuffer_push(ifn, olsrMessage, olsrMessageLength);
228                                         if (r != (int) olsrMessageLength) {
229                                                 pudError(
230                                                                 false,
231                                                                 "Could not send to OLSR interface %s: %s"
232                                                                                 " (length=%u, r=%d)",
233                                                                 ifn->int_name,
234                                                                 ((r == -1) ? "no buffer was found" :
235                                                                         (r == 0) ? "there was not enough room in the buffer" :
236                                                                                         "unknown reason"), olsrMessageLength, r);
237                                         }
238                                 }
239                         }
240
241                         /* send out over tx interfaces */
242                         (void) packetReceivedFromOlsr(olsrMessage, NULL, NULL);
243                 }
244         }
245 }
246
247 /**
248  Called by OLSR core when a packet for the plugin is received from the non-OLSR
249  network. It converts the packet into the internal OLSR wire format for a
250  position update and transmits it over all OLSR network interfaces.
251
252  @param skfd
253  the socket file descriptor on which the packet is received
254  @param data
255  a pointer to the network interface structure on which the packet was received
256  @param flags
257  unused
258  */
259 static void packetReceivedForOlsr(int skfd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
260         if (skfd >= 0) {
261                 unsigned char rxBuffer[BUFFER_SIZE_RX_NMEA];
262                 ssize_t rxCount;
263                 union olsr_sockaddr sender;
264                 socklen_t senderSize = sizeof(sender);
265
266                 assert(data != NULL);
267
268                 /* Receive the captured Ethernet frame */
269                 memset(&sender, 0, senderSize);
270                 errno = 0;
271                 rxCount = recvfrom(skfd, &rxBuffer[0], (sizeof(rxBuffer) - 1), 0,
272                                 (struct sockaddr *)&sender, &senderSize);
273                 if (rxCount < 0) {
274                         pudError(true, "Receive error in %s, ignoring message.", __func__);
275                         return;
276                 }
277
278                 /* make sure the string is null-terminated */
279                 rxBuffer[rxCount] = '\0';
280
281                 /* only accept messages from configured IP addresses */
282                 if (!isRxAllowedSourceIpAddress(&sender)) {
283                         return;
284                 }
285
286                 /* we have the received string in the rxBuffer now */
287
288                 /* hand the NMEA information to the receiver */
289                 (void) receiverUpdateGpsInformation(&rxBuffer[0], rxCount);
290         }
291 }
292
293 /**
294  Initialise the plugin: check the configuration, initialise the NMEA parser,
295  create network interface sockets, hookup the plugin to OLSR and setup data
296  that can be setup in advance.
297
298  @return
299  - false upon failure
300  - true otherwise
301  */
302 bool initPud(void) {
303         if (!checkConfig()) {
304                 pudError(false, "Invalid configuration");
305                 goto error;
306         }
307
308         initState();
309
310         if (!initDeDupList(&deDupList, getDeDupDepth())) {
311                 pudError(false, "Could not initialise de-duplication list");
312                 goto error;
313         }
314
315         if (!startReceiver()) {
316                 pudError(false, "Could not start receiver");
317                 goto error;
318         }
319
320         /*
321          * Creates receive and transmit sockets and register the receive sockets
322          * with the OLSR stack
323          */
324         if (!createNetworkInterfaces(&packetReceivedForOlsr,
325                         &packetReceivedFromDownlink)) {
326                 pudError(false, "Could not create require network interfaces");
327                 goto error;
328         }
329
330         if (!checkRunSetup()) {
331                 pudError(false, "Invalid configuration");
332                 goto error;
333         }
334
335         /*
336          * Tell OLSR to call packetReceivedFromOlsr when the packets for this
337          * plugin arrive from the OLSR network
338          */
339         olsr_parser_add_function(&packetReceivedFromOlsr, PUD_OLSR_MSG_TYPE);
340
341         return true;
342
343         error: closePud();
344         return false;
345 }
346
347 /**
348  Stop the plugin: shut down all created network interface sockets and destroy
349  the NMEA parser.
350  */
351 void closePud(void) {
352         closeNetworkInterfaces();
353         stopReceiver();
354         destroyDeDupList(&deDupList);
355 }