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