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