123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- #include "network.h"
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <arpa/inet.h>
- /**
- * Try to read exactly `n` bytes from a file descriptor.
- * Returns -1 on error, otherwise number of bytes read.
- * The return value can be smaller than `n` if the
- * file descriptor encounters EOF.
- *
- * In case of error, errno is set by underlying call to
- * read(), but the number of succesfully read bytes is lost.
- */
- ssize_t read_nbytes(int fd, size_t n, uint8_t* buffer) {
- size_t read_bytes = 0;
- int res;
- while (read_bytes < n) {
- res = read(fd, buffer+read_bytes, n-read_bytes);
- if (res < 0) {
- return res;
- }
- if (res == 0) {
- return read_bytes;
- }
- read_bytes += res;
- }
- return read_bytes;
- }
- /**
- * Try to read a single serialized packet from a file descriptor.
- * Returns -1 on error, with errno appropriately set.
- * Returns 0 if EOF was encountered before the end of packet.
- * Otherwise returns the type field of the packet.
- */
- int recv_packet(int fd, uint8_t* buf, size_t* n) {
- uint16_t size;
- if (*n < sizeof(size)) {
- errno = ENOBUFS;
- return -1;
- }
- ssize_t res = read_nbytes(fd, sizeof(size), buf);
- if (res < 0) {
- return res;
- }
- if (res < (ssize_t)sizeof(size)) {
- // Stream ended before we could read size of packet.
- return 0;
- }
- // Size of packet including the size field itself.
- size = ntohs(*((uint16_t*)buf));
- if (size > *n) {
- errno = ENOBUFS;
- return -1;
- }
- res = read_nbytes(fd, size-sizeof(size), buf+sizeof(size));
- if (res < 0) {
- return res;
- }
- if (res == 0) {
- // Stream ended before we could read packet in full.
- return 0;
- }
- *n = sizeof(size)+res;
- // pkt->type
- return buf[2];
- }
- /**
- * Read and discard data from file descriptor until EOF.
- * Returns the number of bytes read.
- *
- * Useful in a shutdown procedure.
- */
- int recv_dump_all(int fd) {
- char buf[PKT_SIZE_MAX];
- int s;
- while ((s = recv(fd, buf, PKT_SIZE_MAX, 0)) > 0);
- return s;
- }
- /**
- * Equivalent to a single recv with length of PKT_SIZE_MAX,
- * but discard the resulting data.
- *
- * Useful in a shutdown procedure.
- */
- int recv_dump(int fd) {
- char buf[PKT_SIZE_MAX];
- return recv(fd, buf, PKT_SIZE_MAX, 0);
- }
- /**
- * Transmit a single packet (or any arbitrary buffer) taking
- * care of partial sends.
- *
- * Returns the number of bytes sent. If this is less than
- * `length`, an error has occured, and errno is set by underlying send.
- */
- size_t send_packet(int fd, uint8_t* buf, size_t length) {
- size_t sent = 0;
- int n;
- while (sent < length) {
- if ((n = send(fd, buf+sent, length-sent, 0)) == -1) {
- return sent;
- }
- sent += n;
- }
- return sent;
- }
|