Allow default name for sections
[oonf.git] / src-api / rfc5444 / rfc5444_writer.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include <assert.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include "common/avl.h"
47 #include "common/avl_comp.h"
48 #include "common/common_types.h"
49 #include "common/list.h"
50 #include "rfc5444/rfc5444_context.h"
51 #include "rfc5444/rfc5444_writer.h"
52 #include "rfc5444/rfc5444_api_config.h"
53
54 static void _register_addrtlvtype(struct rfc5444_writer *writer,
55     struct rfc5444_writer_message *msg,
56     struct rfc5444_writer_tlvtype *type);
57 static int _msgaddr_avl_comp(const void *k1, const void *k2);
58 static void *_copy_addrtlv_value(struct rfc5444_writer *writer, const void *value, size_t length);
59 static void _free_tlvtype_tlvs(struct rfc5444_writer *writer, struct rfc5444_writer_tlvtype *tlvtype);
60 static void _lazy_free_message(struct rfc5444_writer *writer, struct rfc5444_writer_message *msg);
61 static struct rfc5444_writer_message *_get_message(struct rfc5444_writer *writer, uint8_t msgid);
62 static struct rfc5444_writer_address *_malloc_address_entry(void);
63 static struct rfc5444_writer_addrtlv *_malloc_addrtlv_entry(void);
64
65 /**
66  * @param type TLV type
67  * @param exttype TLV extension type
68  * @return combined type
69  */
70 static INLINE int
71 _get_fulltype(uint8_t type, uint8_t exttype) {
72   return type * 256 + exttype;
73 }
74
75 /**
76  * Creates a new rfc5444 writer context
77  * @param writer pointer to writer context
78  */
79 void
80 rfc5444_writer_init(struct rfc5444_writer *writer) {
81   assert (writer->msg_buffer != NULL && writer->msg_size > 0);
82   assert (writer->addrtlv_buffer != NULL && writer->addrtlv_size > 0);
83
84   /* set default memory handler functions */
85   if (!writer->malloc_address_entry)
86     writer->malloc_address_entry = _malloc_address_entry;
87   if (!writer->malloc_addrtlv_entry)
88     writer->malloc_addrtlv_entry = _malloc_addrtlv_entry;
89   if (!writer->free_address_entry)
90     writer->free_address_entry = free;
91   if (!writer->free_addrtlv_entry)
92     writer->free_addrtlv_entry = free;
93
94   list_init_head(&writer->_targets);
95
96   /* initialize packet buffer */
97   writer->_msg.buffer = writer->msg_buffer;
98   _rfc5444_tlv_writer_init(&writer->_msg, 0, writer->msg_size);
99
100   list_init_head(&writer->_pkthandlers);
101   list_init_head(&writer->_targets);
102   list_init_head(&writer->_addr_tlvtype_head);
103
104   avl_init(&writer->_msgcreators, avl_comp_uint8, false);
105
106 #if WRITER_STATE_MACHINE == true
107   writer->_state = RFC5444_WRITER_NONE;
108 #endif
109 }
110
111 /**
112  * Cleanup a writer context and free all reserved memory
113  * This function must not be called outside the message_addresses callback.
114  *
115  * @param writer pointer to writer context
116  */
117 void
118 rfc5444_writer_cleanup(struct rfc5444_writer *writer) {
119   struct rfc5444_writer_message *msg, *safe_msg;
120   struct rfc5444_writer_pkthandler *pkt, *safe_pkt;
121   struct rfc5444_writer_content_provider *provider, *safe_prv;
122   struct rfc5444_writer_tlvtype *tlvtype, *safe_tt;
123   struct rfc5444_writer_target *interf, *safe_interf;
124
125   assert(writer);
126 #if WRITER_STATE_MACHINE == true
127   assert(writer->_state == RFC5444_WRITER_NONE);
128 #endif
129
130   /* remove all packet handlers */
131   list_for_each_element_safe(&writer->_pkthandlers, pkt, _pkthandle_node, safe_pkt) {
132     rfc5444_writer_unregister_pkthandler(writer, pkt);
133   }
134
135   /* remove all _targets */
136   list_for_each_element_safe(&writer->_targets, interf, _target_node, safe_interf) {
137     rfc5444_writer_unregister_target(writer, interf);
138   }
139
140   /* remove all generic address tlvtypes */
141   list_for_each_element_safe(&writer->_addr_tlvtype_head, tlvtype, _tlvtype_node, safe_tt) {
142     rfc5444_writer_unregister_addrtlvtype(writer, tlvtype);
143   }
144
145   /* remove all message creators */
146   avl_for_each_element_safe(&writer->_msgcreators, msg, _msgcreator_node, safe_msg) {
147     /* prevent message from being freed in the middle of the processing */
148     msg->_registered = true;
149
150     /* remove all message content providers */
151     avl_for_each_element_safe(&msg->_provider_tree, provider, _provider_node, safe_prv) {
152       rfc5444_writer_unregister_content_provider(writer, provider, NULL, 0);
153     }
154
155     /* remove all registered address tlvs */
156     list_for_each_element_safe(&msg->_msgspecific_tlvtype_head, tlvtype, _tlvtype_node, safe_tt) {
157       rfc5444_writer_unregister_addrtlvtype(writer, tlvtype);
158     }
159
160     /* remove message and addresses */
161     rfc5444_writer_unregister_message(writer, msg);
162   }
163 }
164
165 /**
166  * Adds a tlv to an address.
167  * This function must not be called outside the message_addresses callback.
168  *
169  * @param writer pointer to writer context
170  * @param addr pointer to address object
171  * @param tlvtype pointer to predefined tlvtype object
172  * @param value pointer to value or NULL if no value
173  * @param length length of value in bytes or 0 if no value
174  * @param allow_dup true if multiple TLVs of the same type are allowed,
175  *   false otherwise
176  * @return RFC5444_OKAY if tlv has been added successfully, RFC5444_... otherwise
177  */
178 enum rfc5444_result
179 rfc5444_writer_add_addrtlv(struct rfc5444_writer *writer, struct rfc5444_writer_address *addr,
180     struct rfc5444_writer_tlvtype *tlvtype, const void *value, size_t length, bool allow_dup) {
181   struct rfc5444_writer_addrtlv *addrtlv;
182
183 #if WRITER_STATE_MACHINE == true
184   assert(writer->_state == RFC5444_WRITER_ADD_ADDRESSES);
185 #endif
186
187   /* check for collision if necessary */
188   if (!allow_dup && avl_find(&addr->_addrtlv_tree, &tlvtype->_full_type) != NULL) {
189     return RFC5444_DUPLICATE_TLV;
190   }
191
192   if ((addrtlv = writer->malloc_addrtlv_entry()) == NULL) {
193     /* out of memory error */
194     return RFC5444_OUT_OF_MEMORY;
195   }
196
197   /* set back pointer */
198   addrtlv->address = addr;
199   addrtlv->tlvtype = tlvtype;
200
201   /* copy value(length) */
202   addrtlv->length = length;
203   if (length > 0 && (addrtlv->value = _copy_addrtlv_value(writer, value, length)) == NULL) {
204     writer->free_addrtlv_entry(addrtlv);
205     return RFC5444_OUT_OF_ADDRTLV_MEM;
206   }
207
208   /* add to address tree */
209   addrtlv->addrtlv_node.key = &tlvtype->_full_type;
210   avl_insert(&addr->_addrtlv_tree, &addrtlv->addrtlv_node);
211
212   /* add to tlvtype tree */
213   addrtlv->tlv_node.key = &addr->index;
214   avl_insert(&tlvtype->_tlv_tree, &addrtlv->tlv_node);
215
216   return RFC5444_OKAY;
217 }
218
219 /**
220  * Add a network prefix to a rfc5444 message.
221  * This function must not be called outside the message_addresses callback.
222  *
223  * @param writer pointer to writer context
224  * @param msg pointer to message object
225  * @param addr_ptr pointer to binary address in network byte order
226  * @param prefix prefix length
227  * @param mandatory true if address is mandatory for all fragments of message
228  * @return pointer to address object, NULL if an error happened
229  */
230 struct rfc5444_writer_address *
231 rfc5444_writer_add_address(struct rfc5444_writer *writer __attribute__ ((unused)),
232     struct rfc5444_writer_message *msg, const void *addr_ptr, uint8_t prefix, bool mandatory) {
233   struct rfc5444_writer_address *address;
234   const uint8_t *addr;
235 #if CLEAR_ADDRESS_POSTFIX == true
236   int i, p;
237   uint8_t cleaned_addr[RFC5444_MAX_ADDRLEN];
238 #endif
239
240 #if WRITER_STATE_MACHINE == true
241   assert(writer->_state == RFC5444_WRITER_ADD_ADDRESSES);
242 #endif
243
244   addr = addr_ptr;
245 #if CLEAR_ADDRESS_POSTFIX == true
246   /* only copy prefix part of address */
247   for (p = prefix, i=0; i < _msg->addr_len; i++, p -= 8) {
248     if (p > 7) {
249       cleaned_addr[i] = addr[i];
250     }
251     else if (p <= 0) {
252       cleaned_addr[i] = 0;
253     }
254     else {
255       uint8_t mask = 255 << (8-p);
256       cleaned_addr[i] = addr[i] & mask;
257     }
258   }
259
260   address = avl_find_element(&_msg->_addr_tree, cleaned_addr, address, _addr_tree_node);
261 #else
262   address = avl_find_element(&msg->_addr_tree, addr, address, _addr_tree_node);
263 #endif
264
265
266   if (address == NULL) {
267     if ((address = writer->malloc_address_entry()) == NULL) {
268       return NULL;
269     }
270
271 #if CLEAR_ADDRESS_POSTFIX == true
272     memcpy(address->addr, cleaned_addr, _msg->addr_len);
273 #else
274     memcpy(address->addr, addr, msg->addr_len);
275 #endif
276     address->prefixlen = prefix;
277
278     address->_addr_tree_node.key = address->addr;
279
280     list_add_tail(&msg->_addr_head, &address->_addr_node);
281     avl_insert(&msg->_addr_tree, &address->_addr_tree_node);
282
283     avl_init(&address->_addrtlv_tree, avl_comp_uint32, true);
284   }
285
286   address->_mandatory_addr |= mandatory;
287
288   return address;
289 }
290
291 /**
292  * Register an tlv type for addressblocks of a certain message.
293  * This function must NOT be called from the rfc5444 writer callbacks.
294  *
295  * @param writer pointer to writer context
296  * @param msgtype messagetype for this tlv, -1 to registere a generic
297  *   (not message specific) address TLV type
298  * @param type pointer to tlvtype structure, type and exttype must be already initialized
299  * @return 0 if addresstlvtype was registered, -1 otherwise
300  */
301 int
302 rfc5444_writer_register_addrtlvtype(struct rfc5444_writer *writer,
303     struct rfc5444_writer_tlvtype *type, int msgtype) {
304   struct rfc5444_writer_message *msg = NULL;
305
306 #if WRITER_STATE_MACHINE == true
307   assert(writer->_state == RFC5444_WRITER_NONE);
308 #endif
309   if (msgtype >= 0 && msgtype <= 255) {
310     if ((msg = _get_message(writer, msgtype)) == NULL) {
311       /* out of memory error ? */
312       return -1;
313     }
314   }
315
316   _register_addrtlvtype(writer, msg, type);
317   return 0;
318 }
319
320 /**
321  * Remove registration of tlvtype for addresses.
322  * This function must not be called outside the message_addresses callback.
323  *
324  * @param writer pointer to writer context
325  * @param tlvtype pointer to tlvtype object
326  */
327 void
328 rfc5444_writer_unregister_addrtlvtype(struct rfc5444_writer *writer, struct rfc5444_writer_tlvtype *tlvtype) {
329 #if WRITER_STATE_MACHINE == true
330   assert(writer->_state == RFC5444_WRITER_NONE);
331 #endif
332   if (!list_is_node_added(&tlvtype->_tlvtype_node)) {
333     return;
334   }
335
336   _free_tlvtype_tlvs(writer, tlvtype);
337   list_remove(&tlvtype->_tlvtype_node);
338
339   if (tlvtype->_creator) {
340     /* message specific address tlv, see if we need to remove the message itself */
341     _lazy_free_message(writer, tlvtype->_creator);
342   }
343 }
344
345 /**
346  * Register a content provider for a message type
347  * This function must not be called outside the message_addresses callback.
348  *
349  * @param writer pointer to writer context
350  * @param cpr pointer to message content provider object
351  * @param addrtlvs pointer to array of tlvtype definitions
352  * @param addrtlvs_count length of addressblock tlv array
353  * @return -1 if an error happened, 0 otherwise
354  */
355 int
356 rfc5444_writer_register_msgcontentprovider(struct rfc5444_writer *writer,
357     struct rfc5444_writer_content_provider *cpr,
358     struct rfc5444_writer_tlvtype *addrtlvs, size_t addrtlvs_count) {
359   struct rfc5444_writer_message *msg;
360   size_t i;
361
362 #if WRITER_STATE_MACHINE == true
363   assert(writer->_state == RFC5444_WRITER_NONE);
364 #endif
365   /* first allocate the message if necessary */
366   if ((msg = _get_message(writer, cpr->msg_type)) == NULL) {
367     return -1;
368   }
369
370   for (i=0; i<addrtlvs_count; i++) {
371     _register_addrtlvtype(writer, msg, &addrtlvs[i]);
372   }
373
374   cpr->creator = msg;
375   cpr->_provider_node.key = &cpr->priority;
376
377   avl_insert(&msg->_provider_tree, &cpr->_provider_node);
378   return 0;
379 }
380
381 /**
382  * Unregister a message content provider
383  * This function must not be called outside the message_addresses callback.
384  * @param writer pointer to writer context
385  * @param cpr pointer to message context provider object
386  * @param addrtlvs pointer to array of addressblock tlv definitions
387  * @param addrtlvs_count length of addressblock tlv array
388  */
389 void
390 rfc5444_writer_unregister_content_provider(
391     struct rfc5444_writer *writer, struct rfc5444_writer_content_provider *cpr,
392     struct rfc5444_writer_tlvtype *addrtlvs, size_t addrtlvs_count) {
393   size_t i;
394 #if WRITER_STATE_MACHINE == true
395   assert(writer->_state == RFC5444_WRITER_NONE);
396 #endif
397
398   if (!avl_is_node_added(&cpr->_provider_node)) {
399     return;
400   }
401
402   for (i=0; i<addrtlvs_count; i++) {
403     rfc5444_writer_unregister_addrtlvtype(writer, &addrtlvs[i]);
404   }
405   avl_remove(&cpr->creator->_provider_tree, &cpr->_provider_node);
406   _lazy_free_message(writer, cpr->creator);
407 }
408
409 /**
410  * Register a message type for the writer
411  * This function must not be called outside the message_addresses callback.
412  *
413  * @param writer pointer to writer context
414  * @param msgid message type
415  * @param target_specific true if an unique message must be created for each
416  *   interface
417  * @param addr_len address length in bytes for this message
418  * @return message object, NULL if an error happened
419  */
420 struct rfc5444_writer_message *
421 rfc5444_writer_register_message(struct rfc5444_writer *writer, uint8_t msgid,
422     bool if_specific, uint8_t addr_len) {
423   struct rfc5444_writer_message *msg;
424
425 #if WRITER_STATE_MACHINE == true
426   assert(writer->_state == RFC5444_WRITER_NONE);
427 #endif
428
429   msg = _get_message(writer, msgid);
430   if (msg == NULL) {
431     /* out of memory error */
432     return NULL;
433   }
434
435   if (msg->_registered) {
436     /* message was already _registered */
437     return NULL;
438   }
439
440   /* mark message as _registered */
441   msg->_registered = true;
442
443   /* set real address length and target_specific flag */
444   msg->addr_len = addr_len;
445   msg->target_specific = if_specific;
446   return msg;
447 }
448
449 /**
450  * Unregisters a message type
451  * This function must not be called outside the message_addresses callback.
452  *
453  * @param writer pointer to writer context
454  * @param msg pointer to message object
455  */
456 void
457 rfc5444_writer_unregister_message(struct rfc5444_writer *writer,
458     struct rfc5444_writer_message *msg) {
459 #if WRITER_STATE_MACHINE == true
460   assert(writer->_state == RFC5444_WRITER_NONE);
461 #endif
462
463   if (!avl_is_node_added(&msg->_msgcreator_node)) {
464     return;
465   }
466
467   /* free addresses */
468   _rfc5444_writer_free_addresses(writer, msg);
469
470   /* mark message as unregistered */
471   msg->_registered = false;
472   _lazy_free_message(writer, msg);
473 }
474
475 /**
476  * Registers a packet handler for the writer
477  * This function must not be called outside the message_addresses callback.
478  *
479  * @param writer pointer to writer context
480  * @param pkt pointer to packet handler object
481  */
482 void
483 rfc5444_writer_register_pkthandler(struct rfc5444_writer *writer,
484     struct rfc5444_writer_pkthandler *pkt) {
485
486 #if WRITER_STATE_MACHINE == true
487   assert(writer->_state == RFC5444_WRITER_NONE);
488 #endif
489
490   list_add_tail(&writer->_pkthandlers, &pkt->_pkthandle_node);
491 }
492
493 /**
494  * Unregisters a packet handler
495  * This function must not be called outside the message_addresses callback.
496  *
497  * @param writer pointer to writer context
498  * @param pkt pointer to packet handler object
499  */
500 void
501 rfc5444_writer_unregister_pkthandler(
502     struct rfc5444_writer *writer __attribute__ ((unused)),
503     struct rfc5444_writer_pkthandler *pkt) {
504 #if WRITER_STATE_MACHINE == true
505   assert(writer->_state == RFC5444_WRITER_NONE);
506 #endif
507   if (list_is_node_added(&pkt->_pkthandle_node)) {
508     list_remove(&pkt->_pkthandle_node);
509   }
510 }
511
512 /**
513  * Registers a new outgoing interface for the writer context
514  * @param writer pointer to writer context
515  * @param interf pointer to interface object
516  */
517 void
518 rfc5444_writer_register_target(struct rfc5444_writer *writer,
519     struct rfc5444_writer_target *interf) {
520 #if WRITER_STATE_MACHINE == true
521   assert(writer->_state == RFC5444_WRITER_NONE);
522 #endif
523
524   assert (interf->packet_buffer != NULL && interf->packet_size > 0);
525
526   interf->_pkt.buffer = interf->packet_buffer;
527   _rfc5444_tlv_writer_init(&interf->_pkt, interf->packet_size, interf->packet_size);
528
529   interf->_is_flushed = true;
530
531   list_add_tail(&writer->_targets, &interf->_target_node);
532 }
533
534 /**
535  * Unregisters an interface from the writer context and free
536  * all allocated memory associated with the interface
537  * @param writer pointer to writer context
538  * @param interf pointer to interface object
539  */
540 void
541 rfc5444_writer_unregister_target(
542     struct rfc5444_writer *writer  __attribute__ ((unused)),
543     struct rfc5444_writer_target *interf) {
544 #if WRITER_STATE_MACHINE == true
545   assert(writer->_state == RFC5444_WRITER_NONE);
546 #endif
547
548   /* remove interface from writer */
549   if (list_is_node_added(&interf->_target_node)) {
550     list_remove(&interf->_target_node);
551   }
552 }
553
554 /**
555  * Creates a rfc5444 writer object
556  * @param writer pointer to writer context
557  * @param msgid message type
558  * @return pointer to message object, NULL if an error happened
559  */
560 static struct rfc5444_writer_message *
561 _get_message(struct rfc5444_writer *writer, uint8_t msgid) {
562   struct rfc5444_writer_message *msg;
563
564   msg = avl_find_element(&writer->_msgcreators, &msgid, msg, _msgcreator_node);
565   if (msg != NULL) {
566     return msg;
567   }
568
569   if ((msg = calloc(1, sizeof(*msg))) == NULL) {
570     return NULL;
571   }
572
573   /* initialize key */
574   msg->type = msgid;
575   msg->_msgcreator_node.key = &msg->type;
576   if (avl_insert(&writer->_msgcreators, &msg->_msgcreator_node)) {
577     free(msg);
578     return NULL;
579   }
580
581   /* pre-initialize addr_len */
582   msg->addr_len = RFC5444_MAX_ADDRLEN;
583
584   /* initialize list/tree heads */
585   avl_init(&msg->_provider_tree, avl_comp_uint32, true);
586
587   list_init_head(&msg->_msgspecific_tlvtype_head);
588
589   avl_init(&msg->_addr_tree, _msgaddr_avl_comp, false);
590   list_init_head(&msg->_addr_head);
591   return msg;
592 }
593
594 /**
595  * Register an tlv type for addressblocks of a certain message.
596  * This function must NOT be called from the rfc5444 writer callbacks.
597  *
598  * @param writer pointer to writer context
599  * @param msg pointer to allocated rfc5444_writer_message, NULL
600  *   if generic address tlvtype
601  * @param tlvtype pointer to preallocated rfc5444_writer_tlvtype,
602  *    type and exttype must already be initialized
603  */
604 static void
605 _register_addrtlvtype(struct rfc5444_writer *writer,
606     struct rfc5444_writer_message *msg,
607     struct rfc5444_writer_tlvtype *tlvtype) {
608   /* initialize addrtlv fields */
609   tlvtype->_creator = msg;
610   tlvtype->_full_type = _get_fulltype(tlvtype->type, tlvtype->exttype);
611
612   avl_init(&tlvtype->_tlv_tree, avl_comp_uint32, true);
613
614   if (msg) {
615     /* add to message creator list */
616     list_add_tail(&msg->_msgspecific_tlvtype_head, &tlvtype->_tlvtype_node);
617   }
618   else {
619     /* add to generic address tlvtype list */
620     list_add_tail(&writer->_addr_tlvtype_head, &tlvtype->_tlvtype_node);
621   }
622 }
623
624 /**
625  * AVL tree comparator for comparing addresses.
626  * Custom pointer points to corresponding rfc5444_writer_message.
627  */
628 static int
629 _msgaddr_avl_comp(const void *k1, const void *k2) {
630   return memcmp(k1, k2, 16);
631 }
632
633 /**
634  * Copies the value of an address tlv into the internal static buffer
635  * @param writer pointer to writer context
636  * @param value pointer to tlv value
637  * @param length number of bytes of tlv value
638  */
639 static void *
640 _copy_addrtlv_value(struct rfc5444_writer *writer, const void *value, size_t length) {
641   void *ptr;
642   if (writer->_addrtlv_used + length > writer->addrtlv_size) {
643     /* not enough memory for addrtlv values */
644     return NULL;
645   }
646
647   ptr = &writer->addrtlv_buffer[writer->_addrtlv_used];
648   memcpy(ptr, value, length);
649   writer->_addrtlv_used += length;
650
651   return ptr;
652 }
653
654 /**
655  * Free memory of all temporary allocated tlvs of a certain type
656  * @param writer pointer to writer context
657  * @param tlvtype pointer to tlvtype object
658  */
659 static void
660 _free_tlvtype_tlvs(struct rfc5444_writer *writer, struct rfc5444_writer_tlvtype *tlvtype) {
661   struct rfc5444_writer_addrtlv *addrtlv, *ptr;
662
663   avl_remove_all_elements(&tlvtype->_tlv_tree, addrtlv, tlv_node, ptr) {
664     /* remove from address too */
665     avl_remove(&addrtlv->address->_addrtlv_tree, &addrtlv->addrtlv_node);
666     writer->free_addrtlv_entry(addrtlv);
667   }
668 }
669
670 /**
671  * Free all allocated addresses in a writers context
672  * @param writer pointer to writer context
673  * @param msg pointer to message object
674  */
675 void
676 _rfc5444_writer_free_addresses(struct rfc5444_writer *writer, struct rfc5444_writer_message *msg) {
677   struct rfc5444_writer_address *addr, *safe_addr;
678   struct rfc5444_writer_addrtlv *addrtlv, *safe_addrtlv;
679
680   avl_remove_all_elements(&msg->_addr_tree, addr, _addr_tree_node, safe_addr) {
681     /* remove from list too */
682     list_remove(&addr->_addr_node);
683
684     avl_remove_all_elements(&addr->_addrtlv_tree, addrtlv, addrtlv_node, safe_addrtlv) {
685       /* remove from tlvtype too */
686       avl_remove(&addrtlv->tlvtype->_tlv_tree, &addrtlv->tlv_node);
687       writer->free_addrtlv_entry(addrtlv);
688     }
689     writer->free_address_entry(addr);
690   }
691
692   /* allow overwriting of addrtlv-value buffer */
693   writer->_addrtlv_used = 0;
694 }
695 /**
696  * Free message object if not in use anymore
697  * @param writer pointer to writer context
698  * @param _msg pointer to message object
699  */
700 static void
701 _lazy_free_message(struct rfc5444_writer *writer, struct rfc5444_writer_message *msg) {
702   if (!msg->_registered
703       && list_is_empty(&msg->_addr_head)
704       && list_is_empty(&msg->_msgspecific_tlvtype_head)
705       && avl_is_empty(&msg->_provider_tree)) {
706     avl_remove(&writer->_msgcreators, &msg->_msgcreator_node);
707     free(msg);
708   }
709 }
710
711 /**
712  * Default allocater for address objects
713  * @return pointer to cleaned address object, NULL if an error happened
714  */
715 static struct rfc5444_writer_address*
716 _malloc_address_entry(void) {
717   return calloc(1, sizeof(struct rfc5444_writer_address));
718 }
719
720 /**
721  * Default allocator for address tlv object.
722  * @return pointer to cleaned address tlv object, NULL if an error happened
723  */
724 static struct rfc5444_writer_addrtlv*
725 _malloc_addrtlv_entry(void) {
726   return calloc(1, sizeof(struct rfc5444_writer_addrtlv));
727 }