PUD: only use setupNodeIdBinaryBufferForOlsrCache
[olsrd.git] / lib / pud / wireformat / src / wireFormat.c
1 #include <OlsrdPudWireFormat/wireFormat.h>
2 #include <OlsrdPudWireFormat/compiler.h>
3
4 /* ************************************************************************
5  * VALIDITY TIME CACHE
6  * ************************************************************************ */
7
8 static unsigned long long cachedValidityTimeMsn[16];
9
10 static bool cachedValidityTimeMsnValid = false;
11
12 /**
13  Setup of cache of calculated most significant nibble results of the validity
14  time calculation to speed up run-time calculations. This method has to be
15  called once upon first use of ValidityTime functions.
16  */
17 static void setupCachedValidityTimeMsn(void) {
18         unsigned int msn;
19         for (msn = 0; msn < 16; msn++) {
20                 cachedValidityTimeMsn[msn] = PUD_VALIDITY_TIME_FROM_OLSR(msn, 0);
21         }
22         cachedValidityTimeMsnValid = true;
23 }
24
25 /* ************************************************************************
26  * NODEID CACHE
27  * ************************************************************************ */
28
29 /** The size of the cached nodeId buffer */
30 #define PUD_CACHED_NODEID_BUFFER_SIZE 256
31
32 /** The cached nodeId buffer: contains a pre-processed version of the nodeId
33  in order to improve performance. It is currently used for nodeIdTypes
34  PUD_NODEIDTYPE_MSISDN, PUD_NODEIDTYPE_TETRA, PUD_NODEIDTYPE_MMSI,
35  PUD_NODEIDTYPE_URN, PUD_NODEIDTYPE_192, PUD_NODEIDTYPE_193
36  (so basically for numbers that will not change) */
37 static unsigned char cachedNodeIdBuffer[PUD_CACHED_NODEID_BUFFER_SIZE];
38
39 /** The number of bytes stored in cachedNodeIdBuffer */
40 static unsigned int cachedNodeIdBufferLength = 0;
41
42 /**
43  Setup a nodeId buffer in the cachedNodeIdBuffer.
44
45  @param val
46  The value to setup in the cache
47  @param bytes
48  The number of bytes used by the number in the wire format
49
50  @return
51  - true when the number is valid
52  - false otherwise
53  */
54 bool setupNodeIdBinaryBufferForOlsrCache(void * val, size_t bytes) {
55         if (bytes >= PUD_CACHED_NODEID_BUFFER_SIZE) {
56                 return false;
57         }
58
59         memcpy(cachedNodeIdBuffer, val, bytes);
60         cachedNodeIdBufferLength = bytes;
61         return true;
62 }
63
64 /* ************************************************************************
65  * Validity Time
66  * ************************************************************************ */
67
68 /* inline getValidityTime */
69
70 /**
71  Set the validity time of the position update message
72
73  @param validityTimeField
74  A pointer to the validity time field
75  @param validityTime
76  The validity time in seconds
77  */
78 void setValidityTime(uint8_t * validityTimeField,
79                 unsigned long long validityTime) {
80         unsigned int msn = 1;
81         unsigned long long lsn = 0;
82         unsigned long long upperBound;
83
84         if (!cachedValidityTimeMsnValid) {
85                 setupCachedValidityTimeMsn();
86         }
87         upperBound = cachedValidityTimeMsn[msn];
88         while ((msn < 16) && (validityTime >= upperBound)) {
89                 msn++;
90                 upperBound = cachedValidityTimeMsn[msn];
91         }
92         msn--;
93
94         if (unlikely(validityTime >= upperBound)) {
95                 lsn = 15;
96         } else {
97                 unsigned long lowerBound = PUD_VALIDITY_TIME_FROM_OLSR(msn, 0);
98                 unsigned long resolution = (1 << msn);
99                 lsn = ((validityTime - lowerBound + (resolution >> 1)) / resolution);
100         }
101
102         assert(msn <= 15);
103         assert(lsn <= 15);
104
105         *validityTimeField = ((msn << 4) | lsn);
106 }
107
108 /* ************************************************************************
109  * UplinkPositionUpdate
110  * ************************************************************************ */
111
112 /* inline uint8_t getUplinkMessageType */
113 /* inline void setUplinkMessageType */
114
115 /* inline uint16_t getUplinkMessageLength */
116 /* inline void setUplinkMessageLength */
117
118 /* inline bool getUplinkMessageIPv6 */
119 /* inline void setUplinkMessageIPv6 */
120
121 /* inline void setUplinkMessagePadding */
122
123 /* ************************************************************************
124  * OLSR Header
125  * ************************************************************************ */
126
127 /* inline union olsr_ip_addr * getOlsrMessageOriginator */
128
129 /* inline PudOlsrPositionUpdate * getOlsrMessagePayload */
130
131 /* ************************************************************************
132  * PudOlsrPositionUpdate
133  * ************************************************************************ */
134
135 /* inline uint8_t getPositionUpdateVersion */
136 /* inline void setPositionUpdateVersion */
137
138 /* inline uint8_t getPositionUpdateSmask */
139 /* inline void setPositionUpdateSmask */
140
141 /* ************************************************************************
142  * GpsInfo
143  * ************************************************************************ */
144
145 /* inline void setPositionUpdateTime */
146
147 /**
148  Convert the time of an OLSR message (the number of seconds after midnight) to
149  a time structure, based on midnight of the current day.
150
151  @param olsrGpsMessage
152  A pointer to the position update message
153  @param baseDate
154  The base date from which to determine the time (number of seconds since Epoch,
155  UTC)
156  @param nowStruct
157  A pointer to the time structure into which to put the converted time
158  */
159 void getPositionUpdateTime(PudOlsrPositionUpdate * olsrGpsMessage,
160                 time_t baseDate, struct tm *nowStruct) {
161         uint32_t olsrTime = olsrGpsMessage->gpsInfo.time;
162         unsigned int secNow;
163
164         time_t now = baseDate;
165         gmtime_r(&now, nowStruct);
166
167         secNow = ((nowStruct->tm_hour * 60 * 60) + (nowStruct->tm_min * 60)
168                         + nowStruct->tm_sec);
169
170         if (secNow <= (12 * 60 * 60)) {
171                 /* we are now in the first 12h of the day */
172                 if (unlikely(olsrTime > (secNow + (12 * 60 * 60)))) {
173                         /* the message was sent more than 12h later in time:
174                          the message was sent yesterday: adjust the date by -1 day */
175                         now -= (24 * 60 * 60);
176                         gmtime_r(&now, nowStruct);
177                 }
178         } else {
179                 /* we are now in the last 12h of the day */
180                 if (unlikely(olsrTime < (secNow - (12 * 60 * 60)))) {
181                         /* the message was sent more than 12h earlier in time:
182                          the message was sent tomorrow: adjust the date by +1 day */
183                         now += (24 * 60 * 60);
184                         gmtime_r(&now, nowStruct);
185                 }
186         }
187
188         nowStruct->tm_hour = ((olsrTime % (24 * 60 * 60)) / 3600);
189         nowStruct->tm_min = ((olsrTime % (60 * 60)) / 60);
190         nowStruct->tm_sec = (olsrTime % 60);
191 }
192
193 /* inline double getPositionUpdateLatitude */
194 /* inline void setPositionUpdateLatitude */
195
196 /* inline double getPositionUpdateLongitude */
197 /* inline void setPositionUpdateLongitude */
198
199 /* inline long getPositionUpdateAltitude */
200 /* inline void setPositionUpdateAltitude */
201
202 /* inline unsigned long getPositionUpdateSpeed */
203 /* inline void setPositionUpdateSpeed */
204
205 /* inline unsigned long getPositionUpdateTrack */
206 /* inline void setPositionUpdateTrack */
207
208 /* inline double getPositionUpdateHdop */
209 /* inline void setPositionUpdateHdop */
210
211 /* ************************************************************************
212  * NodeInfo
213  * ************************************************************************ */
214
215 /* inline NodeIdType getPositionUpdateNodeIdType */
216 /* inline void setPositionUpdateNodeIdType */
217
218 /**
219  Get the nodeId and its size, accounting for nodeId presence
220
221  @param ipVersion
222  The IP version (AF_INET or AF_INET6)
223  @param olsrMessage
224  A pointer to the OLSR message
225  @param nodeId
226  A pointer to the location where a pointer to the nodeId (as contained in the
227  olsrMessage) can be stored
228  @param nodeIdSize
229  A pointer to the location where the number of bytes in the nodeId can be
230  stored
231  */
232 void getPositionUpdateNodeId(int ipVersion, union olsr_message * olsrMessage,
233                 unsigned char ** nodeId, unsigned int * nodeIdSize) {
234         PudOlsrPositionUpdate * olsrGpsMessage = getOlsrMessagePayload(ipVersion,
235                         olsrMessage);
236
237         *nodeId = &olsrGpsMessage->nodeInfo.nodeId;
238
239         switch (getPositionUpdateNodeIdType(ipVersion, olsrGpsMessage)) {
240         case PUD_NODEIDTYPE_MAC: /* hardware address */
241                 *nodeIdSize = PUD_NODEIDTYPE_MAC_BYTES;
242                 break;
243
244         case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
245                 *nodeIdSize = PUD_NODEIDTYPE_MSISDN_BYTES;
246                 break;
247
248         case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
249                 *nodeIdSize = PUD_NODEIDTYPE_TETRA_BYTES;
250                 break;
251
252         case PUD_NODEIDTYPE_DNS: /* DNS name */
253                 *nodeIdSize = strlen((char *) *nodeId);
254                 /* FIXME for no '\0' at the end, need to scan from the end until
255                  * encountering a non-zero byte: end of string address and
256                  * subtract the string start address */
257                 break;
258
259         case PUD_NODEIDTYPE_MMSI: /* an AIS MMSI number */
260                 *nodeIdSize = PUD_NODEIDTYPE_MMSI_BYTES;
261                 break;
262
263         case PUD_NODEIDTYPE_URN: /* a URN number */
264                 *nodeIdSize = PUD_NODEIDTYPE_URN_BYTES;
265                 break;
266
267         case PUD_NODEIDTYPE_192:
268                 *nodeIdSize = PUD_NODEIDTYPE_192_BYTES;
269                 break;
270
271         case PUD_NODEIDTYPE_193:
272                 *nodeIdSize = PUD_NODEIDTYPE_193_BYTES;
273                 break;
274
275         case PUD_NODEIDTYPE_194:
276                 *nodeIdSize = PUD_NODEIDTYPE_194_BYTES;
277                 break;
278
279         case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
280         case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
281         default: /* unsupported */
282         {
283                 *nodeId = (unsigned char *) getOlsrMessageOriginator(ipVersion,
284                                 olsrMessage);
285                 *nodeIdSize =
286                                 (ipVersion == AF_INET) ?
287                                                 PUD_NODEIDTYPE_IPV4_BYTES : PUD_NODEIDTYPE_IPV6_BYTES;
288         }
289                 break;
290         }
291
292         return;
293 }
294
295 /**
296  Convert the node information to the node information for an OLSR message and
297  put it in the PUD message in the OLSR message. Also updates the PUD message
298  smask.
299
300  @param ipVersion
301  The IP version (AF_INET or AF_INET6)
302  @param olsrGpsMessage
303  A pointer to the PUD message in the OLSR message
304  @param olsrMessageSize
305  The maximum number of bytes available for the olsrMessage
306  @param nodeIdType
307  The nodeIdType
308  @param nodeId
309  The (configured) nodeId
310  @param nodeIdLength
311  The number of bytes in the nodeId
312
313  @return
314  The number of bytes written in the PUD message in the OLSR message (for ALL
315  the node information)
316  */
317 size_t setPositionUpdateNodeInfo(int ipVersion,
318                 PudOlsrPositionUpdate * olsrGpsMessage, unsigned int olsrMessageSize,
319                 NodeIdType nodeIdType, unsigned char * nodeId, size_t nodeIdLength) {
320         unsigned char * buffer;
321         unsigned int length = 0;
322
323         setPositionUpdateNodeIdType(olsrGpsMessage, nodeIdType);
324         switch (nodeIdType) {
325         case PUD_NODEIDTYPE_MAC: /* hardware address */
326                 length = nodeIdLength;
327                 setPositionUpdateNodeId(olsrGpsMessage, nodeId, nodeIdLength, false);
328                 break;
329
330         case PUD_NODEIDTYPE_MSISDN: /* an MSISDN number */
331         case PUD_NODEIDTYPE_TETRA: /* a Tetra number */
332         case PUD_NODEIDTYPE_MMSI: /* an AIS MMSI number */
333         case PUD_NODEIDTYPE_URN: /* a URN number */
334         case PUD_NODEIDTYPE_192:
335         case PUD_NODEIDTYPE_193:
336         case PUD_NODEIDTYPE_194:
337                 buffer = &cachedNodeIdBuffer[0];
338                 length = cachedNodeIdBufferLength;
339                 setPositionUpdateNodeId(olsrGpsMessage, buffer, length, false);
340                 break;
341
342         case PUD_NODEIDTYPE_DNS: /* DNS name */
343         {
344                 long charsAvailable = olsrMessageSize
345                                 - (PUD_OLSRWIREFORMATSIZE + sizeof(NodeInfo)
346                                                 - sizeof(olsrGpsMessage->nodeInfo.nodeId)) - 1;
347
348                 length = nodeIdLength + 1;
349                 if (unlikely((long) length > charsAvailable)) {
350                         length = charsAvailable;
351                 }
352
353                 setPositionUpdateNodeId(olsrGpsMessage, nodeId, length, true);
354         }
355                 break;
356
357         case PUD_NODEIDTYPE_IPV4: /* IPv4 address */
358         case PUD_NODEIDTYPE_IPV6: /* IPv6 address */
359                 /* explicit return: no nodeId information in message */
360                 return 0;
361
362         default: /* unsupported */
363                 /* fallback to IP address */
364                 setPositionUpdateNodeIdType(olsrGpsMessage,
365                                 (ipVersion == AF_INET) ? PUD_NODEIDTYPE_IPV4 :
366                                 PUD_NODEIDTYPE_IPV6);
367
368                 /* explicit return: no nodeId information in message */
369                 return 0;
370         }
371
372         setPositionUpdateFlags(olsrGpsMessage,
373                         getPositionUpdateFlags(olsrGpsMessage) | PUD_FLAGS_ID);
374         return ((sizeof(NodeInfo)
375                         - (sizeof(olsrGpsMessage->nodeInfo.nodeId) /* nodeId placeholder */))
376                         + length);
377 }