PUD: add downlink socket, no handling yet
[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
12 /* OLSRD includes */
13 #include "ipcalc.h"
14 #include "parser.h"
15 #include "olsr.h"
16
17 /* System includes */
18 #include <assert.h>
19
20 /** The size of the buffer in which the received NMEA string is stored */
21 #define BUFFER_SIZE_FOR_OLSR    2048
22
23 /** The size of the buffer in which the transmit NMEA string is assembled */
24 #define BUFFER_SIZE_FROM_OLSR   512
25
26 /** The transmit socket address */
27 static union olsr_sockaddr * txAddress;
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         TRxTxNetworkInterface *txNetworkInterfaces = getTxNetworkInterfaces();
85         while (txNetworkInterfaces != NULL) {
86                 TRxTxNetworkInterface *networkInterface = txNetworkInterfaces;
87
88 #ifdef PUD_DUMP_GPS_PACKETS_TX_NON_OLSR
89                 olsr_printf(0, "%s: packet sent to non-OLSR interface %s (%u bytes)\n",
90                                 PUD_PLUGIN_ABBR, &networkInterface->name[0], bufferLength);
91                 dump_packet(&buffer[0], bufferLength);
92 #endif
93
94                 errno = 0;
95                 if (sendto(networkInterface->socketFd, buffer, bufferLength, 0,
96                                 (struct sockaddr *) &txAddress->in, sizeof(txAddress->in)) < 0) {
97                         pudError(true, "Transmit error on interface %s",
98                                         (char *) &networkInterface->name);
99                 }
100                 txNetworkInterfaces = networkInterface->next;
101         }
102 }
103
104 /**
105  Called by OLSR core when a packet for the plugin is received from the OLSR
106  network. It converts the packet into an NMEA string and transmits it over all
107  transmit non-OLSR network interfaces.
108
109  @param olsrMessage
110  a pointer to the received OLSR message
111  @param in_if
112  a pointer to the OLSR network interface on which the packet was received
113  @param ipaddr
114  a pointer to the IP address of the sender
115
116  @return
117  - true when the packet was processed
118  - false otherwise
119  */
120 bool packetReceivedFromOlsr(union olsr_message *olsrMessage,
121                 struct interface *in_if __attribute__ ((unused)), union olsr_ip_addr *ipaddr __attribute__ ((unused))) {
122         const union olsr_ip_addr * originator = getOlsrMessageOriginator(
123                         olsr_cnf->ip_version, olsrMessage);
124         unsigned int transmitStringLength;
125         unsigned char buffer[BUFFER_SIZE_FROM_OLSR];
126
127 #ifdef PUD_DUMP_GPS_PACKETS_RX_OLSR
128         unsigned short olsrMessageSize =
129                         getOlsrMessageSize(olsr_cnf->ip_version, olsrMessage);
130 #endif
131
132         /* when we do not loopback then check if the message originated from this
133          * node: back off */
134         if (!getUseLoopback() && ipequal(originator, &olsr_cnf->main_addr)) {
135                 return false;
136         }
137
138         /* do deduplication: when we have already seen this message from the same
139          * originator then just back off */
140         if (likely(getUseDeDup())) {
141                 if (isInDeDupList(&deDupList, olsrMessage)) {
142                         return false;
143                 }
144
145                 addToDeDup(&deDupList, olsrMessage);
146         }
147
148 #ifdef PUD_DUMP_GPS_PACKETS_RX_OLSR
149         olsr_printf(0, "\n%s: packet received from OLSR interface %s (%u bytes)\n",
150                         PUD_PLUGIN_ABBR, in_if->int_name, olsrMessageSize);
151         dump_packet((unsigned char *) olsrMessage, olsrMessageSize);
152 #endif
153
154         transmitStringLength = gpsFromOlsr(olsrMessage, &buffer[0], sizeof(buffer));
155         if (unlikely(transmitStringLength == 0)) {
156                 return false;
157         }
158
159         sendToAllTxInterfaces(&buffer[0], transmitStringLength);
160
161         return true;
162 }
163
164 /**
165  Called by OLSR core when a packet for the plugin is received from the downlink.
166  It unpacks the messages and distributes them into OLSR and on the LAN.
167
168  @param skfd
169  the socket file descriptor on which the packet is received
170  @param data
171  a pointer to the network interface structure on which the packet was received
172  @param flags
173  unused
174  */
175 static void packetReceivedFromDownlink(int skfd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
176         if (skfd >= 0) {
177                 // empty now
178         }
179 }
180
181 /**
182  Called by OLSR core when a packet for the plugin is received from the non-OLSR
183  network. It converts the packet into the internal OLSR wire format for a
184  position update and transmits it over all OLSR network interfaces.
185
186  @param skfd
187  the socket file descriptor on which the packet is received
188  @param data
189  a pointer to the network interface structure on which the packet was received
190  @param flags
191  unused
192  */
193 #ifdef PUD_DUMP_GPS_PACKETS_RX_NON_OLSR
194 static void packetReceivedForOlsr(int skfd, void *data, unsigned int flags __attribute__ ((unused))) {
195 #else
196 static void packetReceivedForOlsr(int skfd, void *data __attribute__ ((unused)), unsigned int flags __attribute__ ((unused))) {
197 #endif
198         if (skfd >= 0) {
199                 unsigned char rxBuffer[BUFFER_SIZE_FOR_OLSR];
200                 ssize_t rxCount;
201                 struct sockaddr sender;
202                 socklen_t senderSize = sizeof(sender);
203
204                 assert(data != NULL);
205
206                 /* Receive the captured Ethernet frame */
207                 memset(&sender, 0, senderSize);
208                 errno = 0;
209                 rxCount = recvfrom(skfd, &rxBuffer[0], (sizeof(rxBuffer) - 1), 0,
210                                 &sender, &senderSize);
211                 if (rxCount < 0) {
212                         pudError(true, "Receive error in %s, ignoring message.", __func__);
213                         return;
214                 }
215
216                 /* make sure the string is null-terminated */
217                 rxBuffer[rxCount] = '\0';
218
219                 /* only accept messages from configured IP addresses */
220                 if (!isRxAllowedSourceIpAddress(&sender)) {
221                         return;
222                 }
223
224 #ifdef PUD_DUMP_GPS_PACKETS_RX_NON_OLSR
225                 {
226                         TRxTxNetworkInterface * networkInterface = data;
227                         void * src;
228                         in_port_t port;
229                         char fromAddr[64];
230
231                         if (olsr_cnf->ip_version == AF_INET) {
232                                 src = &((struct sockaddr_in*) &sender)->sin_addr;
233                                 port = ntohs(((struct sockaddr_in*) &sender)->sin_port);
234                         } else {
235                                 src = &((struct sockaddr_in6*) &sender)->sin6_addr;
236                                 port = ntohs(((struct sockaddr_in6*) &sender)->sin6_port);
237                         }
238
239                         inet_ntop(olsr_cnf->ip_version, src, &fromAddr[0], sizeof(fromAddr));
240                         olsr_printf(0, "\n%s: packet received from %s, port %u on non-OLSR"
241                                         " interface %s (%lu bytes)\n", PUD_PLUGIN_ABBR, &fromAddr[0],
242                                         port, &networkInterface->name[0], (size_t) rxCount);
243
244                         dump_packet(&rxBuffer[0], (size_t)rxCount);
245                 }
246 #endif
247
248                 /* we have the received string in the rxBuffer now */
249
250                 /* hand the NMEA information to the receiver */
251                 (void) receiverUpdateGpsInformation(&rxBuffer[0], rxCount);
252         }
253 }
254
255 /**
256  Initialise the plugin: check the configuration, initialise the NMEA parser,
257  create network interface sockets, hookup the plugin to OLSR and setup data
258  that can be setup in advance.
259
260  @return
261  - false upon failure
262  - true otherwise
263  */
264 bool initPud(void) {
265         if (!checkConfig()) {
266                 pudError(false, "Invalid configuration");
267                 goto error;
268         }
269
270         initDeDupList(&deDupList, getDeDupDepth());
271
272         /* set global transmit socket config */
273         txAddress = getTxMcAddr();
274
275         if (!startReceiver()) {
276                 pudError(false, "Could not start receiver");
277                 goto error;
278         }
279
280         /*
281          * Creates receive and transmit sockets and register the receive sockets
282          * with the OLSR stack
283          */
284         if (!createNetworkInterfaces(&packetReceivedForOlsr,
285                         &packetReceivedFromDownlink)) {
286                 pudError(false, "Could not create require network interfaces");
287                 goto error;
288         }
289
290         if (!checkRunSetup()) {
291                 pudError(false, "Invalid configuration");
292                 goto error;
293         }
294
295         /*
296          * Tell OLSR to launch olsr_parser when the packets for this plugin
297          * arrive from the OLSR network
298          */
299         olsr_parser_add_function(&packetReceivedFromOlsr, PUD_OLSR_MSG_TYPE);
300
301         return true;
302
303         error: closePud();
304         return false;
305 }
306
307 /**
308  Stop the plugin: shut down all created network interface sockets and destroy
309  the NMEA parser.
310  */
311 void closePud(void) {
312         closeNetworkInterfaces();
313         stopReceiver();
314         destroyDeDupList(&deDupList);
315 }