Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
n_network_msg.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
27#include "nilorea/n_common.h"
28#include "nilorea/n_log.h"
29#include "nilorea/n_network.h"
31
32/* Lifecycle counters. Exposed via netw_msg_stats_get(). Not
33 * thread-atomic, sampled only between ticks from the main thread,
34 * and advisory telemetry, not a correctness signal. */
35static long long g_netw_msg_created = 0;
36static long long g_netw_msg_deleted = 0;
37void netw_msg_stats_get(long long* created, long long* deleted) {
38 if (created) *created = g_netw_msg_created;
39 if (deleted) *deleted = g_netw_msg_deleted;
40}
41
42/* Process-wide byte counters for the two netw_*_msg pump points
43 * (accumulated in n_network.c). Exposed from the same header; same
44 * advisory-only / non-atomic contract. */
45extern long long g_netw_bytes_sent; /* defined in n_network.c */
46extern long long g_netw_bytes_recv; /* defined in n_network.c */
47void netw_bytes_stats_get(long long* sent, long long* recv) {
48 if (sent) *sent = g_netw_bytes_sent;
49 if (recv) *recv = g_netw_bytes_recv;
50}
51
57double double_swap(double value) {
58 double swaped = 0;
59 const unsigned char* src = (const unsigned char*)&value;
60 unsigned char* dst = (unsigned char*)&swaped;
61
62 /* swap bytes */
63 dst[0] = src[7];
64 dst[1] = src[6];
65 dst[2] = src[5];
66 dst[3] = src[4];
67 dst[4] = src[3];
68 dst[5] = src[2];
69 dst[6] = src[1];
70 dst[7] = src[0];
71
72 return swaped;
73} /* double_swap() */
74
80double htond(double value) {
81 /* if byte order is little like x86, PC, ... we swap to network notation */
82#if (BYTEORDER_ENDIAN == BYTEORDER_LITTLE_ENDIAN)
83 double ret = double_swap(value);
84#else
85 double ret = value;
86#endif
87 return ret;
88} /* htond() */
89
95double ntohd(double value) {
96 /* if byte order is little like x86, PC, ... we swap to network notation */
97#if (BYTEORDER_ENDIAN == BYTEORDER_LITTLE_ENDIAN)
98 double ret = double_swap(value);
99#else
100 double ret = value;
101#endif
102 return ret;
103} /* ntohd() */
104
111 if ((*msg)) {
112 n_log(LOG_ERR, "create_msg destination is valid and should be NULL !");
113 return FALSE;
114 }
115
116 Malloc((*msg), NETW_MSG, 1);
117 __n_assert(msg && (*msg), return FALSE);
118
119 (*msg)->tabstr = new_generic_list(MAX_LIST_ITEMS);
120 __n_assert((*msg)->tabstr, Free((*msg)); return FALSE);
121 (*msg)->tabint = new_generic_list(MAX_LIST_ITEMS);
122 __n_assert((*msg)->tabint, list_destroy(&(*msg)->tabstr); Free((*msg)); return FALSE);
123 (*msg)->tabflt = new_generic_list(MAX_LIST_ITEMS);
124 __n_assert((*msg)->tabflt, list_destroy(&(*msg)->tabstr); list_destroy(&(*msg)->tabint); Free((*msg)); return FALSE);
125
127 return TRUE;
128} /* create_msg( ... ) */
129
136 __n_assert(msg, return FALSE);
137 if ((*msg)) {
138 if ((*msg)->tabint) {
139 list_destroy(&(*msg)->tabint);
140 }
141 if ((*msg)->tabflt) {
142 list_destroy(&(*msg)->tabflt);
143 }
144 if ((*msg)->tabstr) {
145 list_destroy(&(*msg)->tabstr);
146 }
147 Free((*msg));
149 } else {
150 n_log(LOG_ERR, "(*msg) already NULL");
151 return FALSE;
152 }
153 return TRUE;
154} /* delete_msg */
155
161int empty_msg(NETW_MSG** msg) {
162 __n_assert(msg && (*msg), return FALSE);
163
164 list_empty((*msg)->tabint);
165 list_empty((*msg)->tabflt);
166 list_empty((*msg)->tabstr);
167
168 return TRUE;
169} /* empty_msg(...) */
170
178int add_nb_to_msg(NETW_MSG* msg, double value) {
179 double* new_val = NULL;
180
181 __n_assert(msg, return FALSE);
182
183 Malloc(new_val, double, 1);
184 __n_assert(new_val, return FALSE);
185
186 new_val[0] = value;
187
188 if (list_push(msg->tabflt, new_val, free) == FALSE) {
189 Free(new_val);
190 return FALSE;
191 }
192 return TRUE;
193} /* add_nb_to_msg( ... ) */
194
201int add_int_to_msg(NETW_MSG* msg, int value) {
202 int* new_val = NULL;
203
204 __n_assert(msg, return FALSE);
205
206 Malloc(new_val, int, 1);
207 __n_assert(new_val, return FALSE);
208
209 new_val[0] = value;
210
211 if (list_push(msg->tabint, new_val, free) == FALSE) {
212 Free(new_val);
213 return FALSE;
214 }
215 return TRUE;
216} /* add_int_to_msg( ... ) */
217
225 __n_assert(msg, return FALSE);
226 __n_assert(str, return FALSE);
227 __n_assert(str->data, return FALSE);
228 return list_push(msg->tabstr, str, free_nstr_ptr);
229} /* add_nstrptr_to_msg(...) */
230
238 __n_assert(msg, return FALSE);
239 __n_assert(str, return FALSE);
240 __n_assert(str->data, return FALSE);
241 N_STR* dup = nstrdup(str);
242 __n_assert(dup, return FALSE);
243 return list_push(msg->tabstr, dup, free_nstr_ptr);
244} /* add_nstrdup_to_msg(...) */
245
252int add_strdup_to_msg(NETW_MSG* msg, const char* str) {
253 __n_assert(msg, return FALSE);
254 __n_assert(str, return FALSE);
255
256 N_STR* dup = char_to_nstr(str);
257 __n_assert(dup, return FALSE);
258
259 return list_push(msg->tabstr, dup, free_nstr_ptr);
260} /* add_strdup_to_msg(...) */
261
279int add_bytes_to_msg(NETW_MSG* msg, const void* bytes, size_t len) {
280 __n_assert(msg, return FALSE);
281 __n_assert(bytes, return FALSE);
282
283 /* new_nstr(N) sets length=N and allocates N+1 bytes. The wire decoder
284 * requires written < length (length reserves room for a trailing NUL),
285 * so we ask for len+1 to keep the invariant when written == len. */
286 N_STR* blob = new_nstr(len + 1);
287 __n_assert(blob, return FALSE);
288 if (len > 0) memcpy(blob->data, bytes, len);
289 blob->data[len] = '\0';
290 blob->written = len;
291
292 if (list_push(msg->tabstr, blob, free_nstr_ptr) == FALSE) {
293 free_nstr(&blob);
294 return FALSE;
295 }
296 return TRUE;
297} /* add_bytes_to_msg(...) */
298
305int get_nb_from_msg(NETW_MSG* msg, double* value) {
306 double* val = NULL;
307
308 __n_assert(msg, return FALSE);
309
310 val = list_shift(msg->tabflt, double);
311 if (val) {
312 (*value) = val[0];
313 Free(val);
314 return TRUE;
315 }
316 return FALSE;
317} /* get_nb_from_msg(...) */
318
325int get_int_from_msg(NETW_MSG* msg, int* value) {
326 int* val = NULL;
327
328 __n_assert(msg, return FALSE);
329
330 val = list_shift(msg->tabint, int);
331 if (val) {
332 (*value) = val[0];
333 Free(val);
334 return TRUE;
335 }
336 return FALSE;
337
338} /* get_int_from_msg(...) */
339
346int get_nstr_from_msg(NETW_MSG* msg, N_STR** value) {
347 N_STR* val = NULL;
348
349 __n_assert(msg, return FALSE);
350
351 val = list_shift(msg->tabstr, N_STR);
352 if (val) {
353 if ((*value)) {
354 n_log(LOG_ERR, "Previous pointer value %p overriden by pointer %p", (*value), val);
355 }
356 (*value) = val;
357 return TRUE;
358 }
359 return FALSE;
360} /* get_nstr_from_msg(...) */
361
368int get_str_from_msg(NETW_MSG* msg, char** value) {
369 N_STR* val = NULL;
370
371 __n_assert(msg, return FALSE);
372
373 val = list_shift(msg->tabstr, N_STR);
374 if (val) {
375 if ((*value)) {
376 n_log(LOG_ERR, "Previous pointer value %p overriden by pointer %p", (*value), val);
377 }
378
379 (*value) = val->data;
380 Free(val);
381 return TRUE;
382 }
383 return FALSE;
384} /* get_str_from_msg(...) */
385
396int get_bytes_from_msg(NETW_MSG* msg, void** out_bytes, size_t* out_len) {
397 __n_assert(msg, return FALSE);
398 __n_assert(out_bytes, return FALSE);
399 __n_assert(out_len, return FALSE);
400
401 N_STR* val = list_shift(msg->tabstr, N_STR);
402 if (!val) return FALSE;
403
404 if (!val->data || val->written == 0) {
405 FreeNoLog(val->data);
406 Free(val);
407 *out_bytes = NULL;
408 *out_len = 0;
409 return FALSE;
410 }
411
412 /* Hand the allocation to the caller, reuses the N_STR buffer to
413 * avoid an extra copy. The caller frees with plain free(). */
414 *out_bytes = val->data;
415 *out_len = val->written;
416 val->data = NULL;
417 Free(val);
418 return TRUE;
419} /* get_bytes_from_msg(...) */
420
427 size_t str_length = 0;
428 LIST_NODE* node = NULL;
429
430 N_STR *strptr = NULL,
431 *generated_str = NULL;
432
433 char* charptr = NULL;
434
435 __n_assert(msg, return NULL);
436
437 /* the first thing to do is to computer the resulting string size
438 the first 12 octets are for the number of ints , floats, strings in the message
439 */
440 str_length = 3 * sizeof(int32_t) + (msg->tabint->nb_items * sizeof(int32_t)) + (msg->tabflt->nb_items * sizeof(double));
441
442 /* let's count the eventual string blocks */
443 node = msg->tabstr->start;
444 while (node) {
445 strptr = (N_STR*)node->ptr;
446 str_length += sizeof(int32_t) + sizeof(int32_t) + strptr->written;
447 node = node->next;
448 }
449
450 /* preparing the new string */
451 Malloc(generated_str, N_STR, 1);
452 __n_assert(generated_str, return NULL);
453 Malloc(generated_str->data, char, str_length + 1);
454 __n_assert(generated_str->data, Free(generated_str); return NULL);
455
456 generated_str->length = str_length + 1;
457 generated_str->written = str_length;
458
459 /* copying header */
460 charptr = generated_str->data;
461
462 /* testing limits */
463 if (msg->tabint->nb_items >= UINT32_MAX) {
464 n_log(LOG_ERR, "too much items (>=UINT32_MAX) in int list of message %p", msg);
465 free_nstr(&generated_str);
466 return NULL;
467 }
468 if (msg->tabflt->nb_items >= UINT32_MAX) {
469 n_log(LOG_ERR, "too much items (>=UINT32_MAX) in float list of message %p", msg);
470 free_nstr(&generated_str);
471 return NULL;
472 }
473 if (msg->tabstr->nb_items >= UINT32_MAX) {
474 n_log(LOG_ERR, "too much items (>=UINT32_MAX) in string list of message %p", msg);
475 free_nstr(&generated_str);
476 return NULL;
477 }
478
479 /* byte order */
480 uint32_t nb_int_items = htonl((uint32_t)msg->tabint->nb_items);
481 uint32_t nb_float_items = htonl((uint32_t)msg->tabflt->nb_items);
482 uint32_t nb_str_items = htonl((uint32_t)msg->tabstr->nb_items);
483
484 /* number of ints inside the message */
485 memcpy(charptr, &nb_int_items, sizeof(uint32_t));
486 charptr += sizeof(uint32_t);
487 /* number of doubles inside the message */
488 memcpy(charptr, &nb_float_items, sizeof(uint32_t));
489 charptr += sizeof(uint32_t);
490 /* number of string inside the message */
491 memcpy(charptr, &nb_str_items, sizeof(uint32_t));
492 charptr += sizeof(uint32_t);
493
494 /* if there are numbers, copy all them ! */
495 node = msg->tabint->start;
496 while (node) {
497 uint32_t* nbptr = (uint32_t*)node->ptr;
498 uint32_t val = htonl(nbptr[0]);
499 memcpy(charptr, &val, sizeof(uint32_t));
500 charptr += sizeof(uint32_t);
501 node = node->next;
502 }
503
504 /* if there are numbers, copy all them ! */
505 node = msg->tabflt->start;
506 while (node) {
507 const double* nbptr = (const double*)node->ptr;
508 double val = htond(nbptr[0]);
509 memcpy(charptr, &val, sizeof(double));
510 charptr += sizeof(double);
511 node = node->next;
512 }
513
514 /* if there are strings, copy all them ! */
515 if (msg->tabstr->nb_items > 0) {
516 node = msg->tabstr->start;
517 while (node) {
518 strptr = (N_STR*)node->ptr;
519 if (strptr->length >= UINT32_MAX) {
520 n_log(LOG_ERR, "string too long (>=UINT32_MAX) in string list of message %p", msg);
521 free_nstr(&generated_str);
522 return NULL;
523 }
524 uint32_t var = htonl((uint32_t)strptr->length);
525 memcpy(charptr, &var, sizeof(uint32_t));
526 charptr += sizeof(uint32_t);
527
528 if (strptr->written >= UINT32_MAX) {
529 n_log(LOG_ERR, "string too long (>=UINT32_MAX) in string list of message %p", msg);
530 free_nstr(&generated_str);
531 return NULL;
532 }
533 var = htonl((uint32_t)strptr->written);
534 memcpy(charptr, &var, sizeof(uint32_t));
535 charptr += sizeof(uint32_t);
536
537 memcpy(charptr, strptr->data, strptr->written);
538 charptr += strptr->written;
539 node = node->next;
540 }
541 }
542
543 return generated_str;
544} /* make_str_from_msg(...) */
545
552 NETW_MSG* generated_msg = NULL;
553 N_STR* tmpstr = NULL;
554
555 char* charptr = NULL;
556
557 uint32_t it,
558 nb_int = 0,
559 nb_flt = 0,
560 nb_str = 0;
561 int32_t tmpnb = 0;
562
563 double tmpflt = 0;
564
565 __n_assert(str, return NULL);
566
567 charptr = str->data;
568
569 /* need at least 3 uint32_t for the header */
570 if (str->written < 3 * sizeof(uint32_t)) {
571 n_log(LOG_ERR, "message too short: %zu bytes, need at least %zu", str->written, 3 * sizeof(uint32_t));
572 return NULL;
573 }
574
575 create_msg(&generated_msg);
576
577 __n_assert(generated_msg, return NULL);
578
579 memcpy(&nb_int, charptr, sizeof(uint32_t));
580 charptr += sizeof(uint32_t);
581 nb_int = ntohl(nb_int);
582
583 memcpy(&nb_flt, charptr, sizeof(uint32_t));
584 charptr += sizeof(uint32_t);
585 nb_flt = ntohl(nb_flt);
586
587 memcpy(&nb_str, charptr, sizeof(uint32_t));
588 charptr += sizeof(uint32_t);
589 nb_str = ntohl(nb_str);
590
591 /* validate that the message is large enough for the claimed int and float counts.
592 * Use division-based checks to avoid size_t overflow on 32-bit platforms. */
593 size_t remaining = str->written - 3 * sizeof(uint32_t);
594
595 if (nb_int > remaining / sizeof(uint32_t)) {
596 n_log(LOG_ERR, "message claims %u ints but only %zu bytes remain", nb_int, remaining);
597 delete_msg(&generated_msg);
598 return NULL;
599 }
600 remaining -= (size_t)nb_int * sizeof(uint32_t);
601
602 if (nb_flt > remaining / sizeof(double)) {
603 n_log(LOG_ERR, "message claims %u floats but only %zu bytes remain", nb_flt, remaining);
604 delete_msg(&generated_msg);
605 return NULL;
606 }
607 remaining -= (size_t)nb_flt * sizeof(double);
608
609 if (nb_int > 0) {
610 for (it = 0; it < nb_int; it++) {
611 memcpy(&tmpnb, charptr, sizeof(uint32_t));
612 tmpnb = (int32_t)ntohl((uint32_t)tmpnb);
613 charptr += sizeof(uint32_t);
614 if (add_int_to_msg(generated_msg, tmpnb) == FALSE) {
615 n_log(LOG_ERR, "failed to add int %u/%u to message", it, nb_int);
616 delete_msg(&generated_msg);
617 return NULL;
618 }
619 }
620 }
621
622 if (nb_flt > 0) {
623 for (it = 0; it < nb_flt; it++) {
624 memcpy(&tmpflt, charptr, sizeof(double));
625 tmpflt = ntohd(tmpflt);
626 charptr += sizeof(double);
627 if (add_nb_to_msg(generated_msg, tmpflt) == FALSE) {
628 n_log(LOG_ERR, "failed to add float %u/%u to message", it, nb_flt);
629 delete_msg(&generated_msg);
630 return NULL;
631 }
632 }
633 }
634
635 if (nb_str > 0) {
636 /* sanity check: each string needs at least 2 uint32_t for headers */
637 if ((size_t)nb_str > remaining / (2 * sizeof(uint32_t))) {
638 n_log(LOG_ERR, "message claims %u strings but only %zu bytes remain (need at least %zu for headers)",
639 nb_str, remaining, (size_t)nb_str * 2 * sizeof(uint32_t));
640 delete_msg(&generated_msg);
641 return NULL;
642 }
643
644 for (it = 0; it < nb_str; it++) {
645 /* check space for length + written headers */
646 if (remaining < 2 * sizeof(uint32_t)) {
647 n_log(LOG_ERR, "string %u/%u: not enough data for string headers (%zu remaining)", it, nb_str, remaining);
648 delete_msg(&generated_msg);
649 return NULL;
650 }
651
652 Malloc(tmpstr, N_STR, 1);
653 __n_assert(tmpstr, { delete_msg(&generated_msg); return NULL; });
654
655 uint32_t var = 0;
656 memcpy(&var, charptr, sizeof(uint32_t));
657 charptr += sizeof(uint32_t);
658 tmpstr->length = ntohl(var);
659
660 memcpy(&var, charptr, sizeof(uint32_t));
661 charptr += sizeof(uint32_t);
662 tmpstr->written = ntohl(var);
663 remaining -= 2 * sizeof(uint32_t);
664
665 /* validate written < length (N_STR requires room for trailing '\0') */
666 if (tmpstr->length == 0 || tmpstr->written >= tmpstr->length) {
667 n_log(LOG_ERR, "string %u/%u: written (%zu) >= length (%zu), violates N_STR invariant", it, nb_str, tmpstr->written, tmpstr->length);
668 Free(tmpstr);
669 delete_msg(&generated_msg);
670 return NULL;
671 }
672
673 /* validate remaining buffer has enough for written bytes */
674 if (tmpstr->written > remaining) {
675 n_log(LOG_ERR, "string %u/%u: written size %zu exceeds remaining %zu bytes", it, nb_str, tmpstr->written, remaining);
676 Free(tmpstr);
677 delete_msg(&generated_msg);
678 return NULL;
679 }
680
681 /* sanity cap on allocation size to prevent DoS via huge allocation */
682 if (tmpstr->length > NETW_MSG_MAX_STRING_LENGTH) {
683 n_log(LOG_ERR, "string %u/%u: length %zu exceeds NETW_MSG_MAX_STRING_LENGTH (%zu)", it, nb_str, tmpstr->length, (size_t)NETW_MSG_MAX_STRING_LENGTH);
684 Free(tmpstr);
685 delete_msg(&generated_msg);
686 return NULL;
687 }
688
689 /* allocate based on written+1 (not untrusted length) to prevent memory-DoS
690 * where attacker sets length near cap but written tiny */
691 Malloc(tmpstr->data, char, tmpstr->written + 1);
692 __n_assert(tmpstr->data, { Free(tmpstr); delete_msg(&generated_msg); return NULL; });
693 tmpstr->length = tmpstr->written + 1;
694
695 memcpy(tmpstr->data, charptr, tmpstr->written);
696 tmpstr->data[tmpstr->written] = '\0';
697 charptr += tmpstr->written;
698 remaining -= tmpstr->written;
699
700 if (add_nstrptr_to_msg(generated_msg, tmpstr) == FALSE) {
701 Free(tmpstr->data);
702 Free(tmpstr);
703 delete_msg(&generated_msg);
704 return NULL;
705 }
706 }
707 }
708 return generated_msg;
709} /* make_msg_from_str(...) */
710
711#ifndef NO_NETMSG_API
712
721N_STR* netmsg_make_ping(int type, int id_from, int id_to, int time) {
722 NETW_MSG* msg = NULL;
723
724 N_STR* tmpstr = NULL;
725
726 create_msg(&msg);
727
728 __n_assert(msg, return NULL);
729
730 if (add_int_to_msg(msg, type) == FALSE) {
731 delete_msg(&msg);
732 return NULL;
733 }
734 if (add_int_to_msg(msg, id_from) == FALSE) {
735 delete_msg(&msg);
736 return NULL;
737 }
738 if (add_int_to_msg(msg, id_to) == FALSE) {
739 delete_msg(&msg);
740 return NULL;
741 }
742 if (add_int_to_msg(msg, time) == FALSE) {
743 delete_msg(&msg);
744 return NULL;
745 }
746
747 tmpstr = make_str_from_msg(msg);
748 delete_msg(&msg);
749
750 return tmpstr;
751} /* netmsg_make_ping() */
752
761N_STR* netmsg_make_ident(int type, int id, N_STR* name, N_STR* passwd) {
762 NETW_MSG* msg = NULL;
763 N_STR* tmpstr = NULL;
764
765 create_msg(&msg);
766 __n_assert(msg, return NULL);
767
768 if (add_int_to_msg(msg, type) == FALSE) {
769 delete_msg(&msg);
770 return NULL;
771 }
772 if (add_int_to_msg(msg, id) == FALSE) {
773 delete_msg(&msg);
774 return NULL;
775 }
776
777 if (add_nstrdup_to_msg(msg, name) == FALSE) {
778 delete_msg(&msg);
779 return NULL;
780 }
781 if (add_nstrdup_to_msg(msg, passwd) == FALSE) {
782 delete_msg(&msg);
783 return NULL;
784 }
785
786 tmpstr = make_str_from_msg(msg);
787 delete_msg(&msg);
788
789 return tmpstr;
790} /* netmsg_make_ident() */
791
804N_STR* netmsg_make_position_msg(int id, double X, double Y, double vx, double vy, double acc_x, double acc_y, int time_stamp) {
805 NETW_MSG* msg = NULL;
806 N_STR* tmpstr = NULL;
807
808 create_msg(&msg);
809
810 __n_assert(msg, return NULL);
811
812 if (add_int_to_msg(msg, NETMSG_POSITION) == FALSE) {
813 delete_msg(&msg);
814 return NULL;
815 }
816 if (add_int_to_msg(msg, id) == FALSE) {
817 delete_msg(&msg);
818 return NULL;
819 }
820 if (add_nb_to_msg(msg, X) == FALSE) {
821 delete_msg(&msg);
822 return NULL;
823 }
824 if (add_nb_to_msg(msg, Y) == FALSE) {
825 delete_msg(&msg);
826 return NULL;
827 }
828 if (add_nb_to_msg(msg, vx) == FALSE) {
829 delete_msg(&msg);
830 return NULL;
831 }
832 if (add_nb_to_msg(msg, vy) == FALSE) {
833 delete_msg(&msg);
834 return NULL;
835 }
836 if (add_nb_to_msg(msg, acc_x) == FALSE) {
837 delete_msg(&msg);
838 return NULL;
839 }
840 if (add_nb_to_msg(msg, acc_y) == FALSE) {
841 delete_msg(&msg);
842 return NULL;
843 }
844 if (add_int_to_msg(msg, time_stamp) == FALSE) {
845 delete_msg(&msg);
846 return NULL;
847 }
848
849 tmpstr = make_str_from_msg(msg);
850 delete_msg(&msg);
851 return tmpstr;
852} /* netmsg_make_position_msg() */
853
864N_STR* netmsg_make_string_msg(int id_from, int id_to, N_STR* name, N_STR* chan, N_STR* txt, int color) {
865 NETW_MSG* msg = NULL;
866
867 N_STR* tmpstr = NULL;
868
869 create_msg(&msg);
870
871 __n_assert(msg, return NULL);
872
873 if (add_int_to_msg(msg, NETMSG_STRING) == FALSE) {
874 delete_msg(&msg);
875 return NULL;
876 }
877 if (add_int_to_msg(msg, id_from) == FALSE) {
878 delete_msg(&msg);
879 return NULL;
880 }
881 if (add_int_to_msg(msg, id_to) == FALSE) {
882 delete_msg(&msg);
883 return NULL;
884 }
885 if (add_int_to_msg(msg, color) == FALSE) {
886 delete_msg(&msg);
887 return NULL;
888 }
889
890 if (add_nstrdup_to_msg(msg, name) == FALSE) {
891 delete_msg(&msg);
892 return NULL;
893 }
894 if (add_nstrdup_to_msg(msg, chan) == FALSE) {
895 delete_msg(&msg);
896 return NULL;
897 }
898 if (add_nstrdup_to_msg(msg, txt) == FALSE) {
899 delete_msg(&msg);
900 return NULL;
901 }
902
903 tmpstr = make_str_from_msg(msg);
904 delete_msg(&msg);
905 __n_assert(tmpstr, return NULL);
906
907 return tmpstr;
908
909} /* netmsg_make_string_msg */
910
916 NETW_MSG* msg = NULL;
917 N_STR* tmpstr = NULL;
918
919 create_msg(&msg);
920 __n_assert(msg, return NULL);
921
922 if (add_int_to_msg(msg, NETMSG_QUIT) == FALSE) {
923 delete_msg(&msg);
924 return NULL;
925 }
926 tmpstr = make_str_from_msg(msg);
927 delete_msg(&msg);
928 __n_assert(tmpstr, return NULL);
929
930 return tmpstr;
931} /* netmsg_make_quit_msg() */
932
939 uint32_t nb_int = 0;
940 int32_t tmpnb = 0;
941 char* charptr = NULL;
942
943 __n_assert(msg, return -1);
944 __n_assert(msg->data, return -1);
945
946 /* need at least 3*uint32 header + 1*uint32 for the type int */
947 if (msg->written < 4 * sizeof(uint32_t)) return -1;
948
949 charptr = msg->data;
950
951 /* read nb_int from the header to verify the int section is present */
952 memcpy(&nb_int, charptr, sizeof(uint32_t));
953 nb_int = ntohl(nb_int);
954
955 if (nb_int < 1) {
956 n_log(LOG_ERR, "netw_msg_get_type: message has no int fields (nb_int=%u), cannot read type", nb_int);
957 return -1;
958 }
959
960 /* bypass nb_int, nb_flt, nb_str header fields to reach the first int (type) */
961 charptr += 3 * sizeof(uint32_t);
962 memcpy(&tmpnb, charptr, sizeof(uint32_t));
963 tmpnb = (int32_t)ntohl((uint32_t)tmpnb);
964
965 return tmpnb;
966} /* netw_msg_get_type(...) */
967
977int netw_get_ident(N_STR* msg, int* type, int* ident, N_STR** name, N_STR** passwd) {
978 NETW_MSG* netmsg = NULL;
979
980 __n_assert(msg, return FALSE);
981
982 netmsg = make_msg_from_str(msg);
983
984 __n_assert(netmsg, return FALSE);
985
986 if (get_int_from_msg(netmsg, type) != TRUE ||
987 get_int_from_msg(netmsg, ident) != TRUE) {
988 n_log(LOG_ERR, "failed to extract type/ident from ident message");
989 delete_msg(&netmsg);
990 return FALSE;
991 }
992
993 if ((*type) != NETMSG_IDENT_REQUEST && (*type) != NETMSG_IDENT_REPLY_OK && (*type) != NETMSG_IDENT_REPLY_NOK) {
994 n_log(LOG_ERR, "unknow (*type) %d", (*type));
995 delete_msg(&netmsg);
996 return FALSE;
997 }
998
999 if (get_nstr_from_msg(netmsg, name) != TRUE ||
1000 get_nstr_from_msg(netmsg, passwd) != TRUE) {
1001 n_log(LOG_ERR, "failed to extract name/passwd from ident message");
1002 free_nstr(name);
1003 free_nstr(passwd);
1004 delete_msg(&netmsg);
1005 return FALSE;
1006 }
1007
1008 delete_msg(&netmsg);
1009
1010 return TRUE;
1011} /* netw_get_ident( ... ) */
1012
1026int netw_get_position(N_STR* msg, int* id, double* X, double* Y, double* vx, double* vy, double* acc_x, double* acc_y, int* time_stamp) {
1027 NETW_MSG* netmsg = NULL;
1028
1029 int type = 0;
1030
1031 __n_assert(msg, return FALSE);
1032
1033 netmsg = make_msg_from_str(msg);
1034
1035 __n_assert(netmsg, return FALSE);
1036
1037 if (get_int_from_msg(netmsg, &type) != TRUE) {
1038 n_log(LOG_ERR, "failed to extract type from position message");
1039 delete_msg(&netmsg);
1040 return FALSE;
1041 }
1042
1043 if (type != NETMSG_POSITION) {
1044 delete_msg(&netmsg);
1045 return FALSE;
1046 }
1047
1048 if (get_int_from_msg(netmsg, id) != TRUE ||
1049 get_nb_from_msg(netmsg, X) != TRUE ||
1050 get_nb_from_msg(netmsg, Y) != TRUE ||
1051 get_nb_from_msg(netmsg, vx) != TRUE ||
1052 get_nb_from_msg(netmsg, vy) != TRUE ||
1053 get_nb_from_msg(netmsg, acc_x) != TRUE ||
1054 get_nb_from_msg(netmsg, acc_y) != TRUE ||
1055 get_int_from_msg(netmsg, time_stamp) != TRUE) {
1056 n_log(LOG_ERR, "failed to extract fields from position message");
1057 delete_msg(&netmsg);
1058 return FALSE;
1059 }
1060
1061 delete_msg(&netmsg);
1062
1063 return TRUE;
1064} /* netw_get_position( ... ) */
1065
1077int netw_get_string(N_STR* msg, int* id, N_STR** name, N_STR** chan, N_STR** txt, int* color) {
1078 NETW_MSG* netmsg = NULL;
1079
1080 int type = 0;
1081
1082 __n_assert(msg, return FALSE);
1083
1084 netmsg = make_msg_from_str(msg);
1085
1086 __n_assert(netmsg, return FALSE);
1087
1088 if (get_int_from_msg(netmsg, &type) != TRUE) {
1089 n_log(LOG_ERR, "failed to extract type from string message");
1090 delete_msg(&netmsg);
1091 return FALSE;
1092 }
1093
1094 if (type != NETMSG_STRING) {
1095 delete_msg(&netmsg);
1096 return FALSE;
1097 }
1098
1099 int id_to = 0;
1100 if (get_int_from_msg(netmsg, id) != TRUE ||
1101 get_int_from_msg(netmsg, &id_to) != TRUE ||
1102 get_int_from_msg(netmsg, color) != TRUE) {
1103 n_log(LOG_ERR, "failed to extract int fields from string message");
1104 delete_msg(&netmsg);
1105 return FALSE;
1106 }
1107
1108 if (get_nstr_from_msg(netmsg, name) != TRUE ||
1109 get_nstr_from_msg(netmsg, chan) != TRUE ||
1110 get_nstr_from_msg(netmsg, txt) != TRUE) {
1111 n_log(LOG_ERR, "failed to extract string fields from string message");
1112 free_nstr(name);
1113 free_nstr(chan);
1114 free_nstr(txt);
1115 delete_msg(&netmsg);
1116 return FALSE;
1117 }
1118
1119 delete_msg(&netmsg);
1120
1121 return TRUE;
1122
1123} /* netw_get_string( ... ) */
1124
1134int netw_get_ping(N_STR* msg, int* type, int* from, int* to, int* time) {
1135 NETW_MSG* netmsg;
1136
1137 __n_assert(msg, return FALSE);
1138
1139 netmsg = make_msg_from_str(msg);
1140
1141 __n_assert(netmsg, return FALSE);
1142
1143 if (get_int_from_msg(netmsg, type) != TRUE) {
1144 n_log(LOG_ERR, "failed to extract type from ping message");
1145 delete_msg(&netmsg);
1146 return FALSE;
1147 }
1148
1149 if ((*type) != NETMSG_PING_REQUEST && (*type) != NETMSG_PING_REPLY) {
1150 delete_msg(&netmsg);
1151 return FALSE;
1152 }
1153
1154 if (get_int_from_msg(netmsg, from) != TRUE ||
1155 get_int_from_msg(netmsg, to) != TRUE ||
1156 get_int_from_msg(netmsg, time) != TRUE) {
1157 n_log(LOG_ERR, "failed to extract fields from ping message");
1158 delete_msg(&netmsg);
1159 return FALSE;
1160 }
1161
1162 delete_msg(&netmsg);
1163
1164 return TRUE;
1165} /* netw_get_ping( ... ) */
1166
1173 __n_assert(msg, return FALSE);
1174
1175 NETW_MSG* netmsg = NULL;
1176 netmsg = make_msg_from_str(msg);
1177 __n_assert(netmsg, return FALSE);
1178
1179 int type = -1;
1180 get_int_from_msg(netmsg, &type);
1181 if (type != NETMSG_QUIT) {
1182 delete_msg(&netmsg);
1183 return FALSE;
1184 }
1185 delete_msg(&netmsg);
1186 return TRUE;
1187} /* netw_get_quit( ... ) */
1188
1189#endif // NO_NETMSG_API
#define FreeNoLog(__ptr)
Free Handler without log.
Definition n_common.h:272
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition n_common.h:204
#define __n_assert(__ptr, __ret)
macro to assert things
Definition n_common.h:279
#define Free(__ptr)
Free Handler to get errors.
Definition n_common.h:263
void * ptr
void pointer to store
Definition n_list.h:46
LIST_NODE * start
pointer to the start of the list
Definition n_list.h:66
size_t nb_items
number of item currently in the list
Definition n_list.h:61
struct LIST_NODE * next
pointer to the next node
Definition n_list.h:52
#define list_shift(__LIST_, __TYPE_)
Shift macro helper for void pointer casting.
Definition n_list.h:96
int list_empty(LIST *list)
Empty a LIST list of pointers.
Definition n_list.c:501
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition n_list.c:228
int list_destroy(LIST **list)
Empty and Free a list container.
Definition n_list.c:548
LIST * new_generic_list(size_t max_items)
Initialiaze a generic list container to max_items pointers.
Definition n_list.c:37
#define MAX_LIST_ITEMS
flag to pass to new_generic_list for the maximum possible number of item in a list
Definition n_list.h:75
Structure of a generic list node.
Definition n_list.h:44
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:89
#define LOG_ERR
error conditions
Definition n_log.h:76
size_t written
number of meaningful bytes in data, excluding the null terminator; the size including the null termin...
Definition n_str.h:68
char * data
the string
Definition n_str.h:63
size_t length
total allocation (in bytes) of the data buffer, padding included
Definition n_str.h:65
void free_nstr_ptr(void *ptr)
Free a N_STR pointer structure.
Definition n_str.c:70
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition n_str.h:203
N_STR * nstrdup(N_STR *str)
Duplicate a N_STR.
Definition n_str.c:716
N_STR * char_to_nstr(const char *src)
Convert a char into a N_STR, short version.
Definition n_str.c:255
N_STR * new_nstr(NSTRBYTE size)
create a new N_STR string
Definition n_str.c:207
A box including a string and his lenght.
Definition n_str.h:61
LIST * tabflt
array of casted double value
LIST * tabstr
array of N_STR
LIST * tabint
array of int
#define NETMSG_IDENT_REQUEST
Network Message is identification request: (int)type , (int)id , (N_STR *)name , (N_STR *)password.
double htond(double value)
If needed swap bytes for a double.
int get_str_from_msg(NETW_MSG *msg, char **value)
Get a string from a message string list.
int add_strdup_to_msg(NETW_MSG *msg, const char *str)
Add a copy of char *str to the string list in the message.
int netw_get_position(N_STR *msg, int *id, double *X, double *Y, double *vx, double *vy, double *acc_x, double *acc_y, int *time_stamp)
Retrieves position from netwmsg.
#define NETMSG_PING_REQUEST
Network Message is ping request: (int)type , (int)id_from , (int)id_to.
#define NETMSG_IDENT_REPLY_NOK
Network Message is identification reply NON OK: (int)type , (int)id , (N_STR *)name ,...
#define NETMSG_STRING
Network Message is string: (int)type , (int)id , (N_STR *)name , (N_STR *)chan , (N_STR *)text ,...
#define NETMSG_PING_REPLY
Network Message is ping reply: (int)type , (int)id_from , (int)id_to.
NETW_MSG * make_msg_from_str(N_STR *str)
Make a single message of the string.
int empty_msg(NETW_MSG **msg)
Empty a NETW_MSG *object.
void netw_msg_stats_get(long long *created, long long *deleted)
Read lifecycle counters.
double double_swap(double value)
Swap bytes endiannes for a double.
N_STR * make_str_from_msg(NETW_MSG *msg)
Make a single string of the message.
int netw_get_ping(N_STR *msg, int *type, int *from, int *to, int *time)
Retrieves a ping travel elapsed time.
int add_nstrptr_to_msg(NETW_MSG *msg, N_STR *str)
Add a string to the string list in the message.
int get_nb_from_msg(NETW_MSG *msg, double *value)
Get a number from a message number list.
#define NETMSG_QUIT
Network asking for exit.
int netw_get_quit(N_STR *msg)
get a formatted NETWMSG_QUIT message from the specified network
int create_msg(NETW_MSG **msg)
Create a NETW_MSG *object.
#define NETMSG_POSITION
Network Message position: (int)type , (int)id , (int)X , (int)Y , (int)x_shift , (int)y_shift ,...
N_STR * netmsg_make_position_msg(int id, double X, double Y, double vx, double vy, double acc_x, double acc_y, int time_stamp)
make a network NETMSG_POSITION message with given parameters
int netw_msg_get_type(N_STR *msg)
Get the type of message without killing the first number. Use with netw_get_XXX.
int get_nstr_from_msg(NETW_MSG *msg, N_STR **value)
Get a string from a message string list.
N_STR * netmsg_make_ident(int type, int id, N_STR *name, N_STR *passwd)
Add a formatted NETWMSG_IDENT message to the specified network.
int add_nstrdup_to_msg(NETW_MSG *msg, N_STR *str)
Add a copy of str to the string list in the message.
int add_int_to_msg(NETW_MSG *msg, int value)
Add an int to the int list int the message.
double ntohd(double value)
If needed swap bytes for a double.
void netw_bytes_stats_get(long long *sent, long long *recv)
Read process-wide network byte counters, sum of N_STR.written across every netw_add_msg / netw_get_ms...
int add_bytes_to_msg(NETW_MSG *msg, const void *bytes, size_t len)
Add a binary blob to the message (clean alias for a raw N_STR payload, distinguishes binary data from...
#define NETMSG_IDENT_REPLY_OK
Network Message is identification reply OK : (int)type , (int)id , (N_STR *)name ,...
int netw_get_string(N_STR *msg, int *id, N_STR **name, N_STR **chan, N_STR **txt, int *color)
Retrieves string from netwmsg.
#define NETW_MSG_MAX_STRING_LENGTH
Maximum allowed length for a single string inside a network message (default: 1 GB).
int delete_msg(NETW_MSG **msg)
Delete a NETW_MSG *object.
int add_nb_to_msg(NETW_MSG *msg, double value)
Add an float to the message.
N_STR * netmsg_make_quit_msg(void)
make a generic network NETMSG_QUIT message
N_STR * netmsg_make_ping(int type, int id_from, int id_to, int time)
Make a ping message to send to a network.
int netw_get_ident(N_STR *msg, int *type, int *ident, N_STR **name, N_STR **passwd)
Retrieves identification from netwmsg.
int get_bytes_from_msg(NETW_MSG *msg, void **out_bytes, size_t *out_len)
Get a binary blob from the message (counterpart of add_bytes_to_msg).
N_STR * netmsg_make_string_msg(int id_from, int id_to, N_STR *name, N_STR *chan, N_STR *txt, int color)
make a network NETMSG_STRING message with given parameters
int get_int_from_msg(NETW_MSG *msg, int *value)
Get an int from a message int list.
network message, array of char and int
Common headers and low-level functions & define.
Generic log system.
Network Engine.
static long long g_netw_msg_created
long long g_netw_bytes_sent
Add a message to send in aimed NETWORK.
Definition n_network.c:3566
static long long g_netw_msg_deleted
long long g_netw_bytes_recv
Definition n_network.c:3567
Network messages , serialization tools.