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