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