Message.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. */
  15. #ifndef Message_H
  16. #define Message_H
  17. #include "exception/Except.h"
  18. #include <stdint.h>
  19. #include "memory/Allocator.h"
  20. #include "util/Bits.h"
  21. #include "util/Endian.h"
  22. #include "util/UniqueName.h"
  23. struct Message
  24. {
  25. /** The length of the message. */
  26. int32_t length;
  27. /** The number of bytes of padding BEFORE where bytes begins. */
  28. int32_t padding;
  29. /** The content. */
  30. uint8_t* bytes;
  31. /** Amount of bytes of storage space available in the message. */
  32. int32_t capacity;
  33. #ifdef PARANOIA
  34. /** This is used inside of Iface.h to support Iface_next() */
  35. struct Iface* currentIface;
  36. #endif
  37. /** The allocator which allocated space for this message. */
  38. struct Allocator* alloc;
  39. };
  40. #define Message_STACK(name, messageLength, amountOfPadding) \
  41. uint8_t UniqueName_get()[messageLength + amountOfPadding]; \
  42. name = &(struct Message){ \
  43. .length = messageLength, \
  44. .bytes = UniqueName_last() + amountOfPadding, \
  45. .padding = amountOfPadding, \
  46. .capacity = messageLength \
  47. }
  48. static inline struct Message* Message_new(uint32_t messageLength,
  49. uint32_t amountOfPadding,
  50. struct Allocator* alloc)
  51. {
  52. uint8_t* buff = Allocator_malloc(alloc, messageLength + amountOfPadding);
  53. struct Message* out = Allocator_calloc(alloc, sizeof(struct Message), 1);
  54. out->bytes = &buff[amountOfPadding];
  55. out->length = out->capacity = messageLength;
  56. out->padding = amountOfPadding;
  57. out->alloc = alloc;
  58. return out;
  59. }
  60. static inline struct Message* Message_clone(struct Message* toClone, struct Allocator* alloc)
  61. {
  62. Assert_true(toClone->capacity >= toClone->length);
  63. int32_t len = toClone->capacity + toClone->padding;
  64. uint8_t* allocation = Allocator_malloc(alloc, len + 8);
  65. while (((uintptr_t)allocation % 8) != (((uintptr_t)toClone->bytes - toClone->padding) % 8)) {
  66. allocation++;
  67. }
  68. Bits_memcpy(allocation, toClone->bytes - toClone->padding, len);
  69. return Allocator_clone(alloc, (&(struct Message) {
  70. .length = toClone->length,
  71. .padding = toClone->padding,
  72. .bytes = allocation + toClone->padding,
  73. .capacity = toClone->capacity,
  74. .alloc = alloc
  75. }));
  76. }
  77. static inline void Message_copyOver(struct Message* output,
  78. struct Message* input,
  79. struct Allocator* allocator)
  80. {
  81. size_t inTotalLength = input->length + input->padding;
  82. size_t outTotalLength = output->length + output->padding;
  83. uint8_t* allocation = output->bytes - output->padding;
  84. if (inTotalLength > outTotalLength) {
  85. allocation = Allocator_realloc(allocator, allocation, inTotalLength);
  86. }
  87. Bits_memcpy(allocation, input->bytes - input->padding, inTotalLength);
  88. output->bytes = allocation + input->padding;
  89. output->length = input->length;
  90. output->padding = input->padding;
  91. }
  92. /**
  93. * Pretend to shift the content forward by amount.
  94. * Really it shifts the bytes value backward.
  95. */
  96. static inline int Message_shift(struct Message* toShift, int32_t amount, struct Except* eh)
  97. {
  98. if (amount > 0 && toShift->padding < amount) {
  99. Except_throw(eh, "buffer overflow adding %d to length %d", amount, toShift->length);
  100. } else if (toShift->length < (-amount)) {
  101. Except_throw(eh, "buffer underflow");
  102. }
  103. toShift->length += amount;
  104. toShift->capacity += amount;
  105. toShift->bytes -= amount;
  106. toShift->padding -= amount;
  107. return 1;
  108. }
  109. static inline void Message_reset(struct Message* toShift)
  110. {
  111. Assert_true(toShift->length <= toShift->capacity);
  112. toShift->length = toShift->capacity;
  113. Message_shift(toShift, -toShift->length, NULL);
  114. }
  115. static inline void Message_push(struct Message* restrict msg,
  116. const void* restrict object,
  117. size_t size,
  118. struct Except* eh)
  119. {
  120. Message_shift(msg, (int)size, eh);
  121. if (object) {
  122. Bits_memcpy(msg->bytes, object, size);
  123. } else {
  124. Bits_memset(msg->bytes, 0x00, size);
  125. }
  126. }
  127. static inline void Message_pop(struct Message* restrict msg,
  128. void* restrict object,
  129. size_t size,
  130. struct Except* eh)
  131. {
  132. Message_shift(msg, -((int)size), eh);
  133. if (object) {
  134. Bits_memcpy(object, &msg->bytes[-((int)size)], size);
  135. }
  136. }
  137. #define Message_popGeneric(size) \
  138. static inline uint ## size ## _t Message_pop ## size (struct Message* msg, struct Except* eh) \
  139. { \
  140. uint ## size ## _t out; \
  141. Message_pop(msg, &out, (size)/8, eh); \
  142. return Endian_bigEndianToHost ## size (out); \
  143. }
  144. Message_popGeneric(8)
  145. Message_popGeneric(16)
  146. Message_popGeneric(32)
  147. Message_popGeneric(64)
  148. #define Message_pushGeneric(size) \
  149. static inline void Message_push ## size \
  150. (struct Message* msg, uint ## size ## _t dat, struct Except* eh) \
  151. { \
  152. uint ## size ## _t x = Endian_hostToBigEndian ## size (dat); \
  153. Message_push(msg, &x, (size)/8, eh); \
  154. }
  155. Message_pushGeneric(8)
  156. Message_pushGeneric(16)
  157. Message_pushGeneric(32)
  158. Message_pushGeneric(64)
  159. #endif