1 /**
2 * collectd - src/libcollectdclient/network_buffer.c
3 * Copyright (C) 2010 Florian octo Forster
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation; only version 2.1 of the License is
8 * applicable.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Authors:
20 * Florian octo Forster <octo at verplant.org>
21 **/
23 #include "config.h"
25 #include <stdlib.h>
26 #include <string.h>
27 #include <math.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <arpa/inet.h> /* htons */
32 #include <pthread.h>
34 #if HAVE_LIBGCRYPT
35 #include <gcrypt.h>
36 GCRY_THREAD_OPTION_PTHREAD_IMPL;
37 #endif
39 #include "collectd/network_buffer.h"
41 #define TYPE_HOST 0x0000
42 #define TYPE_TIME 0x0001
43 #define TYPE_PLUGIN 0x0002
44 #define TYPE_PLUGIN_INSTANCE 0x0003
45 #define TYPE_TYPE 0x0004
46 #define TYPE_TYPE_INSTANCE 0x0005
47 #define TYPE_VALUES 0x0006
48 #define TYPE_INTERVAL 0x0007
50 /* Types to transmit notifications */
51 #define TYPE_MESSAGE 0x0100
52 #define TYPE_SEVERITY 0x0101
54 #define TYPE_SIGN_SHA256 0x0200
55 #define TYPE_ENCR_AES256 0x0210
57 #define PART_SIGNATURE_SHA256_SIZE 36
58 #define PART_ENCRYPTION_AES256_SIZE 42
60 #define ADD_GENERIC(nb,srcptr,size) do { \
61 assert ((size) <= (nb)->free); \
62 memcpy ((nb)->ptr, (srcptr), (size)); \
63 (nb)->ptr += (size); \
64 (nb)->free -= (size); \
65 } while (0)
67 #define ADD_STATIC(nb,var) \
68 ADD_GENERIC(nb,&(var),sizeof(var));
70 /*
71 * Data types
72 */
73 struct lcc_network_buffer_s
74 {
75 char *buffer;
76 size_t size;
78 lcc_value_list_t state;
79 char *ptr;
80 size_t free;
82 lcc_security_level_t seclevel;
83 char *username;
84 char *password;
86 gcry_cipher_hd_t encr_cypher;
87 size_t encr_header_len;
88 char encr_iv[16];
89 };
91 #define SSTRNCPY(dst,src,sz) do { \
92 strncpy ((dst), (src), (sz)); \
93 (dst)[(sz) - 1] = 0; \
94 } while (0)
96 /*
97 * Private functions
98 */
99 static _Bool have_gcrypt (void) /* {{{ */
100 {
101 static _Bool result = 0;
102 static _Bool need_init = 1;
104 if (!need_init)
105 return (result);
106 need_init = 0;
108 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
110 if (!gcry_check_version (GCRYPT_VERSION))
111 return (0);
113 gcry_control (GCRYCTL_INIT_SECMEM, 32768, 0);
114 gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
116 result = 1;
117 return (1);
118 } /* }}} _Bool have_gcrypt */
120 static uint64_t htonll (uint64_t val) /* {{{ */
121 {
122 static int config = 0;
124 uint32_t hi;
125 uint32_t lo;
127 if (config == 0)
128 {
129 uint16_t h = 0x1234;
130 uint16_t n = htons (h);
132 if (h == n)
133 config = 1;
134 else
135 config = 2;
136 }
138 if (config == 1)
139 return (val);
141 hi = (uint32_t) (val >> 32);
142 lo = (uint32_t) (val & 0x00000000FFFFFFFF);
144 hi = htonl (hi);
145 lo = htonl (lo);
147 return ((((uint64_t) lo) << 32) | ((uint64_t) hi));
148 } /* }}} uint64_t htonll */
150 static double htond (double val) /* {{{ */
151 {
152 static int config = 0;
154 union { uint8_t byte[8]; double floating; } in;
155 union { uint8_t byte[8]; double floating; } out;
157 if (config == 0)
158 {
159 double d = 8.642135e130;
160 uint8_t c[8];
162 memcpy (c, &d, 8);
164 if ((c[0] == 0x2f) && (c[1] == 0x25)
165 && (c[2] == 0xc0) && (c[3] == 0xc7)
166 && (c[4] == 0x43) && (c[5] == 0x2b)
167 && (c[6] == 0x1f) && (c[7] == 0x5b))
168 config = 1; /* need nothing */
169 else if ((c[7] == 0x2f) && (c[6] == 0x25)
170 && (c[5] == 0xc0) && (c[4] == 0xc7)
171 && (c[3] == 0x43) && (c[2] == 0x2b)
172 && (c[1] == 0x1f) && (c[0] == 0x5b))
173 config = 2; /* endian flip */
174 else if ((c[4] == 0x2f) && (c[5] == 0x25)
175 && (c[6] == 0xc0) && (c[7] == 0xc7)
176 && (c[0] == 0x43) && (c[1] == 0x2b)
177 && (c[2] == 0x1f) && (c[3] == 0x5b))
178 config = 3; /* int swap */
179 else
180 config = 4;
181 }
183 if (isnan (val))
184 {
185 out.byte[0] = out.byte[1] = out.byte[2] = out.byte[3] = 0x00;
186 out.byte[4] = out.byte[5] = 0x00;
187 out.byte[6] = 0xf8;
188 out.byte[7] = 0x7f;
189 return (out.floating);
190 }
191 else if (config == 1)
192 return (val);
193 else if (config == 2)
194 {
195 in.floating = val;
196 out.byte[0] = in.byte[7];
197 out.byte[1] = in.byte[6];
198 out.byte[2] = in.byte[5];
199 out.byte[3] = in.byte[4];
200 out.byte[4] = in.byte[3];
201 out.byte[5] = in.byte[2];
202 out.byte[6] = in.byte[1];
203 out.byte[7] = in.byte[0];
204 return (out.floating);
205 }
206 else if (config == 3)
207 {
208 in.floating = val;
209 out.byte[0] = in.byte[4];
210 out.byte[1] = in.byte[5];
211 out.byte[2] = in.byte[6];
212 out.byte[3] = in.byte[7];
213 out.byte[4] = in.byte[0];
214 out.byte[5] = in.byte[1];
215 out.byte[6] = in.byte[2];
216 out.byte[7] = in.byte[3];
217 return (out.floating);
218 }
219 else
220 {
221 /* If in doubt, just copy the value back to the caller. */
222 return (val);
223 }
224 } /* }}} double htond */
226 static int nb_add_values (char **ret_buffer, /* {{{ */
227 size_t *ret_buffer_len,
228 const lcc_value_list_t *vl)
229 {
230 char *packet_ptr;
231 size_t packet_len;
233 uint16_t pkg_type;
234 uint16_t pkg_length;
235 uint16_t pkg_num_values;
236 uint8_t pkg_values_types[vl->values_len];
237 value_t pkg_values[vl->values_len];
239 size_t offset;
240 size_t i;
242 packet_len = sizeof (pkg_type) + sizeof (pkg_length)
243 + sizeof (pkg_num_values)
244 + sizeof (pkg_values_types)
245 + sizeof (pkg_values);
247 if (*ret_buffer_len < packet_len)
248 return (ENOMEM);
250 pkg_type = htons (TYPE_VALUES);
251 pkg_length = htons ((uint16_t) packet_len);
252 pkg_num_values = htons ((uint16_t) vl->values_len);
254 for (i = 0; i < vl->values_len; i++)
255 {
256 pkg_values_types[i] = (uint8_t) vl->values_types[i];
257 switch (vl->values_types[i])
258 {
259 case LCC_TYPE_COUNTER:
260 pkg_values[i].counter = (counter_t) htonll (vl->values[i].counter);
261 break;
263 case LCC_TYPE_GAUGE:
264 pkg_values[i].gauge = (gauge_t) htond (vl->values[i].gauge);
265 break;
267 case LCC_TYPE_DERIVE:
268 pkg_values[i].derive = (derive_t) htonll (vl->values[i].derive);
269 break;
271 case LCC_TYPE_ABSOLUTE:
272 pkg_values[i].absolute = (absolute_t) htonll (vl->values[i].absolute);
273 break;
275 default:
276 return (EINVAL);
277 } /* switch (vl->values_types[i]) */
278 } /* for (vl->values_len) */
280 /*
281 * Use `memcpy' to write everything to the buffer, because the pointer
282 * may be unaligned and some architectures, such as SPARC, can't handle
283 * that.
284 */
285 packet_ptr = *ret_buffer;
286 offset = 0;
287 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
288 offset += sizeof (pkg_type);
289 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
290 offset += sizeof (pkg_length);
291 memcpy (packet_ptr + offset, &pkg_num_values, sizeof (pkg_num_values));
292 offset += sizeof (pkg_num_values);
293 memcpy (packet_ptr + offset, pkg_values_types, sizeof (pkg_values_types));
294 offset += sizeof (pkg_values_types);
295 memcpy (packet_ptr + offset, pkg_values, sizeof (pkg_values));
296 offset += sizeof (pkg_values);
298 assert (offset == packet_len);
300 *ret_buffer = packet_ptr + packet_len;
301 *ret_buffer_len -= packet_len;
302 return (0);
303 } /* }}} int nb_add_values */
305 static int nb_add_number (char **ret_buffer, /* {{{ */
306 size_t *ret_buffer_len,
307 uint16_t type, uint64_t value)
308 {
309 char *packet_ptr;
310 size_t packet_len;
312 uint16_t pkg_type;
313 uint16_t pkg_length;
314 uint64_t pkg_value;
316 size_t offset;
318 packet_len = sizeof (pkg_type)
319 + sizeof (pkg_length)
320 + sizeof (pkg_value);
322 if (*ret_buffer_len < packet_len)
323 return (ENOMEM);
325 pkg_type = htons (type);
326 pkg_length = htons ((uint16_t) packet_len);
327 pkg_value = htonll (value);
329 packet_ptr = *ret_buffer;
330 offset = 0;
331 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
332 offset += sizeof (pkg_type);
333 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
334 offset += sizeof (pkg_length);
335 memcpy (packet_ptr + offset, &pkg_value, sizeof (pkg_value));
336 offset += sizeof (pkg_value);
338 assert (offset == packet_len);
340 *ret_buffer = packet_ptr + packet_len;
341 *ret_buffer_len -= packet_len;
342 return (0);
343 } /* }}} int nb_add_number */
345 static int nb_add_string (char **ret_buffer, /* {{{ */
346 size_t *ret_buffer_len,
347 uint16_t type, const char *str, size_t str_len)
348 {
349 char *packet_ptr;
350 size_t packet_len;
352 uint16_t pkg_type;
353 uint16_t pkg_length;
355 size_t offset;
357 packet_len = sizeof (pkg_type)
358 + sizeof (pkg_length)
359 + str_len + 1;
360 if (*ret_buffer_len < packet_len)
361 return (ENOMEM);
363 pkg_type = htons (type);
364 pkg_length = htons ((uint16_t) packet_len);
366 packet_ptr = *ret_buffer;
367 offset = 0;
368 memcpy (packet_ptr + offset, &pkg_type, sizeof (pkg_type));
369 offset += sizeof (pkg_type);
370 memcpy (packet_ptr + offset, &pkg_length, sizeof (pkg_length));
371 offset += sizeof (pkg_length);
372 memcpy (packet_ptr + offset, str, str_len);
373 offset += str_len;
374 memset (packet_ptr + offset, 0, 1);
375 offset += 1;
377 assert (offset == packet_len);
379 *ret_buffer = packet_ptr + packet_len;
380 *ret_buffer_len -= packet_len;
381 return (0);
382 } /* }}} int nb_add_string */
384 static int nb_add_value_list (lcc_network_buffer_t *nb, /* {{{ */
385 const lcc_value_list_t *vl)
386 {
387 char *buffer = nb->ptr;
388 size_t buffer_size = nb->free;
390 const lcc_identifier_t *ident_src;
391 lcc_identifier_t *ident_dst;
393 ident_src = &vl->identifier;
394 ident_dst = &nb->state.identifier;
396 if (strcmp (ident_dst->host, ident_src->host) != 0)
397 {
398 if (nb_add_string (&buffer, &buffer_size, TYPE_HOST,
399 ident_src->host, strlen (ident_src->host)) != 0)
400 return (-1);
401 SSTRNCPY (ident_dst->host, ident_src->host, sizeof (ident_dst->host));
402 }
404 if (strcmp (ident_dst->plugin, ident_src->plugin) != 0)
405 {
406 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN,
407 ident_src->plugin, strlen (ident_src->plugin)) != 0)
408 return (-1);
409 SSTRNCPY (ident_dst->plugin, ident_src->plugin,
410 sizeof (ident_dst->plugin));
411 }
413 if (strcmp (ident_dst->plugin_instance,
414 ident_src->plugin_instance) != 0)
415 {
416 if (nb_add_string (&buffer, &buffer_size, TYPE_PLUGIN_INSTANCE,
417 ident_src->plugin_instance,
418 strlen (ident_src->plugin_instance)) != 0)
419 return (-1);
420 SSTRNCPY (ident_dst->plugin_instance, ident_src->plugin_instance,
421 sizeof (ident_dst->plugin_instance));
422 }
424 if (strcmp (ident_dst->type, ident_src->type) != 0)
425 {
426 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE,
427 ident_src->type, strlen (ident_src->type)) != 0)
428 return (-1);
429 SSTRNCPY (ident_dst->type, ident_src->type, sizeof (ident_dst->type));
430 }
432 if (strcmp (ident_dst->type_instance,
433 ident_src->type_instance) != 0)
434 {
435 if (nb_add_string (&buffer, &buffer_size, TYPE_TYPE_INSTANCE,
436 ident_src->type_instance,
437 strlen (ident_src->type_instance)) != 0)
438 return (-1);
439 SSTRNCPY (ident_dst->type_instance, ident_src->type_instance,
440 sizeof (ident_dst->type_instance));
441 }
443 if (nb->state.time != vl->time)
444 {
445 if (nb_add_number (&buffer, &buffer_size, TYPE_TIME,
446 (uint64_t) vl->time))
447 return (-1);
448 nb->state.time = vl->time;
449 }
451 if (nb->state.interval != vl->interval)
452 {
453 if (nb_add_number (&buffer, &buffer_size, TYPE_INTERVAL,
454 (uint64_t) vl->interval))
455 return (-1);
456 nb->state.interval = vl->interval;
457 }
459 if (nb_add_values (&buffer, &buffer_size, vl) != 0)
460 return (-1);
462 nb->ptr = buffer;
463 nb->free = buffer_size;
464 return (0);
465 } /* }}} int nb_add_value_list */
467 static int nb_add_signature (lcc_network_buffer_t *nb) /* {{{ */
468 {
469 char *buffer;
470 size_t buffer_size;
472 gcry_md_hd_t hd;
473 gcry_error_t err;
474 unsigned char *hash;
475 const size_t hash_length = 32;
477 /* The type, length and username have already been filled in by
478 * "lcc_network_buffer_initialize". All we do here is calculate the hash over
479 * the username and the data and add the hash value to the buffer. */
481 buffer = nb->buffer + PART_SIGNATURE_SHA256_SIZE;
482 assert (nb->size >= (nb->free + PART_SIGNATURE_SHA256_SIZE));
483 buffer_size = nb->size - (nb->free + PART_SIGNATURE_SHA256_SIZE);
485 hd = NULL;
486 err = gcry_md_open (&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
487 if (err != 0)
488 return (-1);
490 assert (nb->password != NULL);
491 err = gcry_md_setkey (hd, nb->password, strlen (nb->password));
492 if (err != 0)
493 {
494 gcry_md_close (hd);
495 return (-1);
496 }
498 gcry_md_write (hd, buffer, buffer_size);
499 hash = gcry_md_read (hd, GCRY_MD_SHA256);
500 if (hash == NULL)
501 {
502 gcry_md_close (hd);
503 return (-1);
504 }
506 assert (((2 * sizeof (uint16_t)) + hash_length) == PART_SIGNATURE_SHA256_SIZE);
507 memcpy (nb->buffer + (2 * sizeof (uint16_t)), hash, hash_length);
509 gcry_md_close (hd);
510 return (0);
511 } /* }}} int nb_add_signature */
513 static int nb_add_encryption (lcc_network_buffer_t *nb) /* {{{ */
514 {
515 size_t package_length;
516 char *encr_ptr; /* pointer to data being encrypted */
517 size_t encr_size;
519 char *hash_ptr; /* pointer to data being hashed */
520 size_t hash_size;
521 char hash[20];
523 uint16_t pkg_length;
524 gcry_error_t err;
526 /* Fill in the package length */
527 package_length = nb->size - nb->free;
528 pkg_length = htons ((uint16_t) package_length);
529 memcpy (nb->buffer + 2, &pkg_length, sizeof (pkg_length));
531 /* Calculate what to hash */
532 hash_ptr = nb->buffer + PART_ENCRYPTION_AES256_SIZE;
533 hash_size = package_length - nb->encr_header_len;
535 /* Calculate what to encrypt */
536 encr_ptr = hash_ptr - sizeof (hash);
537 encr_size = hash_size + sizeof (hash);
539 /* Calculate the SHA-1 hash */
540 gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash_ptr, hash_size);
541 memcpy (encr_ptr, hash, sizeof (hash));
543 if (nb->encr_cypher == NULL)
544 {
545 unsigned char password_hash[32];
547 err = gcry_cipher_open (&nb->encr_cypher,
548 GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB, /* flags = */ 0);
549 if (err != 0)
550 return (-1);
552 /* Calculate our 256bit key used for AES */
553 gcry_md_hash_buffer (GCRY_MD_SHA256, password_hash,
554 nb->password, strlen (nb->password));
556 err = gcry_cipher_setkey (nb->encr_cypher,
557 password_hash, sizeof (password_hash));
558 if (err != 0)
559 {
560 gcry_cipher_close (nb->encr_cypher);
561 nb->encr_cypher = NULL;
562 return (-1);
563 }
564 }
565 else /* if (nb->encr_cypher != NULL) */
566 {
567 gcry_cipher_reset (nb->encr_cypher);
568 }
570 /* Set the initialization vector */
571 err = gcry_cipher_setiv (nb->encr_cypher,
572 nb->encr_iv, sizeof (nb->encr_iv));
573 if (err != 0)
574 {
575 gcry_cipher_close (nb->encr_cypher);
576 nb->encr_cypher = NULL;
577 return (-1);
578 }
580 /* Encrypt the buffer in-place */
581 err = gcry_cipher_encrypt (nb->encr_cypher,
582 encr_ptr, encr_size,
583 /* in = */ NULL, /* in len = */ 0);
584 if (err != 0)
585 {
586 gcry_cipher_close (nb->encr_cypher);
587 nb->encr_cypher = NULL;
588 return (-1);
589 }
591 return (0);
592 } /* }}} int nb_add_encryption */
594 /*
595 * Public functions
596 */
597 lcc_network_buffer_t *lcc_network_buffer_create (size_t size) /* {{{ */
598 {
599 lcc_network_buffer_t *nb;
601 if (size == 0)
602 size = LCC_NETWORK_BUFFER_SIZE_DEFAULT;
604 if (size < 128)
605 {
606 errno = EINVAL;
607 return (NULL);
608 }
610 nb = malloc (sizeof (*nb));
611 if (nb == NULL)
612 return (NULL);
613 memset (nb, 0, sizeof (*nb));
615 nb->size = size;
616 nb->buffer = malloc (nb->size);
617 if (nb->buffer == NULL)
618 {
619 free (nb);
620 return (NULL);
621 }
622 memset (nb->buffer, 0, nb->size);
624 nb->ptr = nb->buffer;
625 nb->free = nb->size;
627 nb->seclevel = NONE;
628 nb->username = NULL;
629 nb->password = NULL;
631 return (nb);
632 } /* }}} lcc_network_buffer_t *lcc_network_buffer_create */
634 void lcc_network_buffer_destroy (lcc_network_buffer_t *nb) /* {{{ */
635 {
636 if (nb == NULL)
637 return;
639 free (nb->buffer);
640 free (nb);
641 } /* }}} void lcc_network_buffer_destroy */
643 int lcc_network_buffer_set_security_level (lcc_network_buffer_t *nb, /* {{{ */
644 lcc_security_level_t level,
645 const char *username, const char *password)
646 {
647 char *username_copy;
648 char *password_copy;
650 if (level == NONE)
651 {
652 free (nb->username);
653 free (nb->password);
654 nb->username = NULL;
655 nb->password = NULL;
656 nb->seclevel = NONE;
657 lcc_network_buffer_initialize (nb);
658 return (0);
659 }
661 if (!have_gcrypt ())
662 return (ENOTSUP);
664 username_copy = strdup (username);
665 password_copy = strdup (password);
666 if ((username_copy == NULL) || (password_copy == NULL))
667 {
668 free (username_copy);
669 free (password_copy);
670 return (ENOMEM);
671 }
673 free (nb->username);
674 free (nb->password);
675 nb->username = username_copy;
676 nb->password = password_copy;
677 nb->seclevel = level;
679 lcc_network_buffer_initialize (nb);
680 return (0);
681 } /* }}} int lcc_network_buffer_set_security_level */
683 int lcc_network_buffer_initialize (lcc_network_buffer_t *nb) /* {{{ */
684 {
685 if (nb == NULL)
686 return (EINVAL);
688 memset (nb->buffer, 0, nb->size);
689 memset (&nb->state, 0, sizeof (nb->state));
690 nb->ptr = nb->buffer;
691 nb->free = nb->size;
693 if (nb->seclevel == SIGN)
694 {
695 size_t username_len;
696 uint16_t pkg_type = htons (TYPE_SIGN_SHA256);
697 uint16_t pkg_length = PART_SIGNATURE_SHA256_SIZE;
699 assert (nb->username != NULL);
700 username_len = strlen (nb->username);
701 pkg_length = htons (pkg_length + ((uint16_t) username_len));
703 /* Fill in everything but the hash value here. */
704 memcpy (nb->ptr, &pkg_type, sizeof (pkg_type));
705 memcpy (nb->ptr + sizeof (pkg_type), &pkg_length, sizeof (pkg_length));
706 nb->ptr += PART_SIGNATURE_SHA256_SIZE;
707 nb->free -= PART_SIGNATURE_SHA256_SIZE;
709 memcpy (nb->ptr, nb->username, username_len);
710 nb->ptr += username_len;
711 nb->free -= username_len;
712 }
713 else if (nb->seclevel == ENCRYPT)
714 {
715 size_t username_length = strlen (nb->username);
716 uint16_t pkg_type = htons (TYPE_ENCR_AES256);
717 uint16_t pkg_length = 0; /* Filled in in finalize. */
718 uint16_t pkg_user_len = htons ((uint16_t) username_length);
719 char hash[20];
721 nb->encr_header_len = username_length;
722 nb->encr_header_len += PART_ENCRYPTION_AES256_SIZE;
724 gcry_randomize ((void *) &nb->encr_iv, sizeof (nb->encr_iv),
725 GCRY_STRONG_RANDOM);
727 /* Filled in in finalize. */
728 memset (hash, 0, sizeof (hash));
730 ADD_STATIC (nb, pkg_type);
731 ADD_STATIC (nb, pkg_length);
732 ADD_STATIC (nb, pkg_user_len);
733 ADD_GENERIC (nb, nb->username, username_length);
734 ADD_GENERIC (nb, nb->encr_iv, sizeof (nb->encr_iv));
735 ADD_GENERIC (nb, hash, sizeof (hash));
736 assert ((nb->encr_header_len + nb->free) == nb->size);
737 }
739 return (0);
740 } /* }}} int lcc_network_buffer_initialize */
742 int lcc_network_buffer_finalize (lcc_network_buffer_t *nb) /* {{{ */
743 {
744 if (nb == NULL)
745 return (EINVAL);
747 if (nb->seclevel == SIGN)
748 nb_add_signature (nb);
749 else if (nb->seclevel == ENCRYPT)
750 nb_add_encryption (nb);
752 return (0);
753 } /* }}} int lcc_network_buffer_finalize */
755 int lcc_network_buffer_add_value (lcc_network_buffer_t *nb, /* {{{ */
756 const lcc_value_list_t *vl)
757 {
758 int status;
760 if ((nb == NULL) || (vl == NULL))
761 return (EINVAL);
763 status = nb_add_value_list (nb, vl);
764 return (status);
765 } /* }}} int lcc_network_buffer_add_value */
767 int lcc_network_buffer_get (lcc_network_buffer_t *nb, /* {{{ */
768 void *buffer, size_t *buffer_size)
769 {
770 size_t sz_required;
771 size_t sz_available;
773 if ((nb == NULL) || (buffer_size == NULL))
774 return (EINVAL);
776 assert (nb->size >= nb->free);
777 sz_required = nb->size - nb->free;
778 sz_available = *buffer_size;
780 *buffer_size = sz_required;
781 if (buffer != NULL)
782 memcpy (buffer, nb->buffer,
783 (sz_available < sz_required) ? sz_available : sz_required);
785 return (0);
786 } /* }}} int lcc_network_buffer_get */
788 /* vim: set sw=2 sts=2 et fdm=marker : */