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