summaryrefslogtreecommitdiff
path: root/scalls/recvfrom.c
blob: 1770fa14cb17bfd4295af9ed19ef388d63a0947b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <assert.h>
#include <fs/vfs.h>
#include <math.h>
#include <poll.h>
#include <scalls/recvfrom.h>

size_t syscall_recvfrom(
    int socket, void *buffer, size_t length, int flags,
    struct two_args
        *extra_args /*struct sockaddr *address, socklen_t *address_len*/) {

  struct sockaddr *address = (struct sockaddr *)extra_args->a;
  socklen_t *address_len = (socklen_t *)extra_args->b;
  kprintf("address: %x\n", address);
  kprintf("address_len: %x\n", address_len);

  if (flags & MSG_WAITALL) {
    struct pollfd fds[1];
    fds[0].fd = socket;
    fds[0].events = POLLIN;
    poll(fds, 1, 0);
  }

  uint16_t data_length;
  socklen_t tmp_socklen;
  vfs_pread(socket, &tmp_socklen, sizeof(socklen_t), 0);
  if (address_len)
    *address_len = tmp_socklen;
  if (address) {
    vfs_pread(socket, address, tmp_socklen, 0);
  } else {
    // We still have to throwaway the data.
    char devnull[100];
    for (; tmp_socklen;) {
      int rc = vfs_pread(socket, devnull, min(tmp_socklen, 100), 0);
      assert(rc >= 0);
      tmp_socklen -= rc;
    }
  }

  vfs_pread(socket, &data_length, sizeof(data_length), 0);
  // If it is reading less than the packet length that could cause
  // problems as the next read will not be put at a new header. Luckily
  // it seems as if other UNIX systems can discard the rest of the
  // packet if not read.

  // Read in the data requested
  int read_len = min(length, data_length);
  int rc = vfs_pread(socket, buffer, read_len, 0);
  // Discard the rest of the packet
  int rest = data_length - read_len;
  char devnull[100];
  for (; rest;) {
    int rc = vfs_pread(socket, devnull, 100, 0);
    assert(rc >= 0);
    rest -= rc;
  }
  return rc;
}