summaryrefslogtreecommitdiff
path: root/lib/tests/udp.c
blob: 6c43a2ffbd3a62db6fcf8d1ae7fdd8f269d0c6df (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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <stdio.h>
#include <event2/event.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <netdb.h>
#include <sys/select.h>
#include <sys/time.h>
#include "udp.h"

static struct addrinfo *
_resolve (const char *str)
{
  static int first = 1;
  static struct addrinfo hints, *result = NULL;
  struct addrinfo *rp = NULL;
  int r;

  if (first)
    {
      first = 0;
      memset (&hints, 0, sizeof (hints));
      hints.ai_family = AF_INET; /* AF_UNSPEC */
      hints.ai_socktype = SOCK_DGRAM;
      r = getaddrinfo (NULL, str, &hints, &result);
      if (r)
	fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (r));
    }

  if (result)
    {
      rp = result;
      result = result->ai_next;
    }

  return rp;
}

ssize_t
poll (struct polldata *data)
{
  int r;
  long timeout;
  fd_set rfds;
  ssize_t len;
  uint8_t buf[4096];

  FD_ZERO (&rfds);
  FD_SET (data->s, &rfds);
  if (data->timeout)
    timeout = data->timeout->tv_sec; /* Save from destruction (Linux).  */
  //fprintf (stderr, "calling select with timeout %ld\n", timeout);
  r = select (data->s + 1, &rfds, NULL, NULL, data->timeout);
  if (data->timeout)
    data->timeout->tv_sec = timeout; /* Restore.  */
  //fprintf (stderr, "select returning %d\n", r);
  if (r > 0)
    {
      len = recv (data->s, buf, sizeof (buf), 0);
      if (len > 0)
	return data->cb (buf, len);
    }
  return r;
}

struct polldata *
server (const char *bindto, struct timeval *timeout, data_cb cb)
{
  struct addrinfo *res;
  int s = -1;

  for (res = _resolve (bindto); res; res = _resolve (bindto))
    {
      s = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
      if (s >= 0)
	{
	  if (bind (s, res->ai_addr, res->ai_addrlen) == 0)
	    break;		/* Done.  */
	  else
	    {
	      close (s);
	      s = -1;
	    }
	}
    }

  if (s >= 0)
    {
      struct polldata *data = malloc (sizeof (struct polldata));
      assert (data);
      memset (data, 0, sizeof (struct polldata));
      data->s = s;
      data->cb = cb;
      if (timeout)
	{
	  data->timeout = malloc (sizeof (struct timeval));
	  assert (data->timeout);
	  memcpy (data->timeout, timeout, sizeof (struct timeval));
	}
      return data;
    }

  return NULL;
}