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
udp_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 *
udp_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;
}
|