/lib/net.c

https://github.com/ncsurobotics/svr · C · 146 lines · 57 code · 22 blank · 67 comment · 8 complexity · 789d80c922f5624210d5d0120acc72aa MD5 · raw file

  1. /**
  2. * \file net.c
  3. * \brief Message transmission/receipt
  4. */
  5. #include "svr.h"
  6. /**
  7. * \defgroup Net Message IO
  8. * \ingroup Comm
  9. * \brief Send and receive messages
  10. * \{
  11. */
  12. /**
  13. * \brief Send a packed message
  14. *
  15. * Send a packed message over a socket
  16. *
  17. * \param socket Socket to send the message over
  18. * \param packed_message Packed message to send
  19. */
  20. int SVR_Net_sendPackedMessage(int socket, SVR_PackedMessage* packed_message) {
  21. ssize_t sent_bytes, n;
  22. /* Send message body */
  23. sent_bytes = 0;
  24. while(sent_bytes < packed_message->length) {
  25. n = send(socket, ((uint8_t*)packed_message->data) + sent_bytes, packed_message->length - sent_bytes, 0);
  26. if(n < 0) {
  27. return n;
  28. }
  29. sent_bytes += n;
  30. }
  31. /* Send payload */
  32. sent_bytes = 0;
  33. while(sent_bytes < packed_message->payload_size) {
  34. n = send(socket, ((uint8_t*)packed_message->payload) + sent_bytes, packed_message->payload_size - sent_bytes, 0);
  35. if(n < 0) {
  36. return n;
  37. }
  38. sent_bytes += n;
  39. }
  40. return packed_message->length + packed_message->payload_size;
  41. }
  42. /**
  43. * \brief Send a message
  44. *
  45. * Send the message to the given client. The message will be packed using the
  46. * SVR_Arena associated with the original message
  47. *
  48. * \param socket The socket to use for IO
  49. * \param message The message to send
  50. */
  51. int SVR_Net_sendMessage(int socket, SVR_Message* message) {
  52. SVR_PackedMessage* packed_message = SVR_Message_pack(message);
  53. return SVR_Net_sendPackedMessage(socket, packed_message);
  54. }
  55. /**
  56. * \brief Read from a socket
  57. *
  58. * Read data from a socket. This function is guaranteed to return the requested
  59. * number of bytes so long as no errors occur and the socket is not shut down.
  60. *
  61. * \param socket The socket to read from
  62. * \param buffer A pointer to a buffer to write to
  63. * \param len The amount of data to read
  64. * \param flags Additional flags as described in recv(2)
  65. * \return Return the number of bytes read (len) or -1 if an error occurs or 0
  66. * if the remote partner performs a shutdown
  67. */
  68. static int SVR_Net_recv(int socket, void* buffer, size_t len, int flags) {
  69. int read = 0;
  70. int n;
  71. while(read < len) {
  72. n = recv(socket, ((char*)buffer) + read, len - read, flags | MSG_WAITALL);
  73. if(n <= 0) {
  74. return n;
  75. }
  76. read += n;
  77. }
  78. return read;
  79. }
  80. /**
  81. * \brief Receive a message
  82. *
  83. * Receive a message from the given socket. Will not retrieve the payload. If a
  84. * payload accompanies the message a call to SVR_Net_receivePayload should be
  85. * made after this call
  86. */
  87. SVR_Message* SVR_Net_receiveMessage(int socket) {
  88. SVR_PackedMessage* packed_message;
  89. uint16_t message_length;
  90. ssize_t n = 0;
  91. /* The first byte received should be the size of the message that follows
  92. minus the header data */
  93. n = SVR_Net_recv(socket, &message_length, sizeof(uint16_t), MSG_PEEK);
  94. if(n <= 0) {
  95. return NULL;
  96. }
  97. /* Create space for the message and receive it */
  98. message_length = ntohs(message_length);
  99. packed_message = SVR_PackedMessage_new(message_length + SVR_MESSAGE_PREFIX_LEN);
  100. n = SVR_Net_recv(socket, packed_message->data, packed_message->length, 0);
  101. if(n <= 0) {
  102. SVR_PackedMessage_release(packed_message);
  103. return NULL;
  104. }
  105. return SVR_PackedMessage_unpack(packed_message);
  106. }
  107. /**
  108. * \brief Receive a message payload
  109. *
  110. * Receive the payload that follows a message. SVR_Net_receiveMessage does not
  111. * receive the payload to allow the caller to decide how to allocate space for
  112. * it. A call to SVR_Net_receivePayload *must* be made immediately after
  113. * receiving a message having a payload.
  114. *
  115. * \param socket The socket to receive from
  116. * \param message A payload of length message->payload_size will be stored to
  117. * message->payload
  118. * \return On success returns the number of bytes received, on failure returns
  119. * one of the return codes for the recv function
  120. */
  121. int SVR_Net_receivePayload(int socket, SVR_Message* message) {
  122. return SVR_Net_recv(socket, message->payload, message->payload_size, 0);
  123. }
  124. /** \} */