Message.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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 <http://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/UniqueName.h"
  22. struct Message
  23. {
  24. /** The length of the message. */
  25. int32_t length;
  26. /** The number of bytes of padding BEFORE where bytes begins. */
  27. int32_t padding;
  28. /** The content. */
  29. uint8_t* bytes;
  30. /** Amount of bytes of storage space available in the message. */
  31. uint32_t capacity;
  32. /** The allocator which allocated space for this message. */
  33. struct Allocator* alloc;
  34. };
  35. #define Message_STACK(name, messageLength, amountOfPadding) \
  36. uint8_t UniqueName_get()[messageLength + amountOfPadding]; \
  37. name = &(struct Message){ \
  38. .length = messageLength, \
  39. .bytes = UniqueName_last() + amountOfPadding, \
  40. .padding = amountOfPadding, \
  41. .capacity = messageLength \
  42. }
  43. static inline struct Message* Message_new(uint32_t messageLength,
  44. uint32_t amountOfPadding,
  45. struct Allocator* alloc)
  46. {
  47. uint8_t* buff = Allocator_malloc(alloc, messageLength + amountOfPadding);
  48. struct Message* out = Allocator_malloc(alloc, sizeof(struct Message));
  49. out->bytes = &buff[amountOfPadding];
  50. out->length = out->capacity = messageLength;
  51. out->padding = amountOfPadding;
  52. out->alloc = alloc;
  53. return out;
  54. }
  55. static inline struct Message* Message_clone(struct Message* toClone,
  56. struct Allocator* allocator)
  57. {
  58. uint32_t len = toClone->length + toClone->padding;
  59. if (len < (toClone->capacity + toClone->padding)) {
  60. len = (toClone->capacity + toClone->padding);
  61. }
  62. uint8_t* allocation = Allocator_malloc(allocator, len);
  63. Bits_memcpy(allocation, toClone->bytes - toClone->padding, len);
  64. return Allocator_clone(allocator, (&(struct Message) {
  65. .length = toClone->length,
  66. .padding = toClone->padding,
  67. .bytes = allocation + toClone->padding,
  68. .capacity = toClone->length,
  69. .alloc = allocator
  70. }));
  71. }
  72. static inline void Message_copyOver(struct Message* output,
  73. struct Message* input,
  74. struct Allocator* allocator)
  75. {
  76. size_t inTotalLength = input->length + input->padding;
  77. size_t outTotalLength = output->length + output->padding;
  78. uint8_t* allocation = output->bytes - output->padding;
  79. if (inTotalLength > outTotalLength) {
  80. allocation = Allocator_realloc(allocator, allocation, inTotalLength);
  81. }
  82. Bits_memcpy(allocation, input->bytes - input->padding, inTotalLength);
  83. output->bytes = allocation + input->padding;
  84. output->length = input->length;
  85. output->padding = input->padding;
  86. }
  87. /**
  88. * Pretend to shift the content forward by amount.
  89. * Really it shifts the bytes value backward.
  90. */
  91. static inline int Message_shift(struct Message* toShift, int32_t amount, struct Except* eh)
  92. {
  93. if (amount > 0 && toShift->padding < amount) {
  94. Except_throw(eh, "buffer overflow");
  95. } else if (toShift->length < (-amount)) {
  96. Except_throw(eh, "buffer underflow");
  97. }
  98. toShift->length += amount;
  99. toShift->capacity += amount;
  100. toShift->bytes -= amount;
  101. toShift->padding -= amount;
  102. return 1;
  103. }
  104. static inline void Message_push(struct Message* restrict msg,
  105. const void* restrict object,
  106. size_t size,
  107. struct Except* eh)
  108. {
  109. Message_shift(msg, (int)size, eh);
  110. Bits_memcpy(msg->bytes, object, size);
  111. }
  112. static inline void Message_pop(struct Message* restrict msg,
  113. void* restrict object,
  114. size_t size,
  115. struct Except* eh)
  116. {
  117. Message_shift(msg, -((int)size), eh);
  118. Bits_memcpy(object, &msg->bytes[-((int)size)], size);
  119. }
  120. #define Message_popGeneric(size) \
  121. static inline uint ## size ## _t Message_pop ## size (struct Message* msg, struct Except* eh) \
  122. { \
  123. uint ## size ## _t out; \
  124. Message_pop(msg, &out, (size)/8, eh); \
  125. return Endian_bigEndianToHost ## size (out); \
  126. }
  127. Message_popGeneric(8)
  128. Message_popGeneric(16)
  129. Message_popGeneric(32)
  130. Message_popGeneric(64)
  131. #define Message_pushGeneric(size) \
  132. static inline void Message_push ## size \
  133. (struct Message* msg, uint ## size ## _t dat, struct Except* eh) \
  134. { \
  135. uint ## size ## _t x = Endian_hostToBigEndian ## size (dat); \
  136. Message_push(msg, &x, (size)/8, eh); \
  137. }
  138. Message_pushGeneric(8)
  139. Message_pushGeneric(16)
  140. Message_pushGeneric(32)
  141. Message_pushGeneric(64)
  142. #endif