network.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #include "network.h"
  2. #include <unistd.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <errno.h>
  6. #include <arpa/inet.h>
  7. /**
  8. * Try to read exactly `n` bytes from a file descriptor.
  9. * Returns -1 on error, otherwise number of bytes read.
  10. * The return value can be smaller than `n` if the
  11. * file descriptor encounters EOF.
  12. *
  13. * In case of error, errno is set by underlying call to
  14. * read(), but the number of succesfully read bytes is lost.
  15. */
  16. ssize_t read_nbytes(int fd, size_t n, uint8_t* buffer) {
  17. size_t read_bytes = 0;
  18. int res;
  19. while (read_bytes < n) {
  20. res = read(fd, buffer+read_bytes, n-read_bytes);
  21. if (res < 0) {
  22. return res;
  23. }
  24. if (res == 0) {
  25. return read_bytes;
  26. }
  27. read_bytes += res;
  28. }
  29. return read_bytes;
  30. }
  31. /**
  32. * Try to read a single serialized packet from a file descriptor.
  33. * Returns -1 on error, with errno appropriately set.
  34. * Returns 0 if EOF was encountered before the end of packet.
  35. * Otherwise returns the type field of the packet.
  36. */
  37. int recv_packet(int fd, uint8_t* buf, size_t* n) {
  38. uint16_t size;
  39. if (*n < sizeof(size)) {
  40. errno = ENOBUFS;
  41. return -1;
  42. }
  43. ssize_t res = read_nbytes(fd, sizeof(size), buf);
  44. if (res < 0) {
  45. return res;
  46. }
  47. if (res < (ssize_t)sizeof(size)) {
  48. // Stream ended before we could read size of packet.
  49. return 0;
  50. }
  51. // Size of packet including the size field itself.
  52. size = ntohs(*((uint16_t*)buf));
  53. if (size > *n) {
  54. errno = ENOBUFS;
  55. return -1;
  56. }
  57. res = read_nbytes(fd, size-sizeof(size), buf+sizeof(size));
  58. if (res < 0) {
  59. return res;
  60. }
  61. if (res == 0) {
  62. // Stream ended before we could read packet in full.
  63. return 0;
  64. }
  65. *n = sizeof(size)+res;
  66. // pkt->type
  67. return buf[2];
  68. }
  69. /**
  70. * Read and discard data from file descriptor until EOF.
  71. * Returns the number of bytes read.
  72. *
  73. * Useful in a shutdown procedure.
  74. */
  75. int recv_dump_all(int fd) {
  76. char buf[PKT_SIZE_MAX];
  77. int s;
  78. while ((s = recv(fd, buf, PKT_SIZE_MAX, 0)) > 0);
  79. return s;
  80. }
  81. /**
  82. * Equivalent to a single recv with length of PKT_SIZE_MAX,
  83. * but discard the resulting data.
  84. *
  85. * Useful in a shutdown procedure.
  86. */
  87. int recv_dump(int fd) {
  88. char buf[PKT_SIZE_MAX];
  89. return recv(fd, buf, PKT_SIZE_MAX, 0);
  90. }
  91. /**
  92. * Transmit a single packet (or any arbitrary buffer) taking
  93. * care of partial sends.
  94. *
  95. * Returns the number of bytes sent. If this is less than
  96. * `length`, an error has occured, and errno is set by underlying send.
  97. */
  98. size_t send_packet(int fd, uint8_t* buf, size_t length) {
  99. size_t sent = 0;
  100. int n;
  101. while (sent < length) {
  102. if ((n = send(fd, buf+sent, length-sent, 0)) == -1) {
  103. return sent;
  104. }
  105. sent += n;
  106. }
  107. return sent;
  108. }