47ea5958271480ded815a41c98fe365ef1e61424
[radsecproxy.git] / lib / tests / udp.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include <unistd.h>
4 #include <assert.h>
5 #include <stdio.h>
6 #include <event2/event.h>
7 #include <sys/socket.h>
8 #include <netinet/in.h>
9 #include <sys/types.h>
10 #include <netdb.h>
11 #include <sys/select.h>
12 #include <sys/time.h>
13 #include "udp.h"
14
15 static struct addrinfo *
16 _resolve (const char *str)
17 {
18   static int first = 1;
19   static struct addrinfo hints, *result = NULL;
20   struct addrinfo *rp = NULL;
21   int r;
22
23   if (first)
24     {
25       first = 0;
26       memset (&hints, 0, sizeof (hints));
27       hints.ai_family = AF_INET; /* AF_UNSPEC */
28       hints.ai_socktype = SOCK_DGRAM;
29       r = getaddrinfo (NULL, str, &hints, &result);
30       if (r)
31         fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (r));
32     }
33
34   if (result)
35     {
36       rp = result;
37       result = result->ai_next;
38     }
39
40   return rp;
41 }
42
43 void
44 udp_free_polldata (struct polldata *data)
45 {
46   if (data)
47     {
48       if (data->timeout)
49         free (data->timeout);
50       free (data);
51     }
52 }
53
54 /* @return if select() returns error or timeout, return select()
55    else return value from invoked callback function */
56 ssize_t
57 udp_poll (struct polldata *data)
58 {
59   int r;
60   long timeout;
61   fd_set rfds;
62   ssize_t len;
63   uint8_t buf[RS_MAX_PACKET_LEN];
64
65   FD_ZERO (&rfds);
66   FD_SET (data->s, &rfds);
67   if (data->timeout)
68     timeout = data->timeout->tv_sec; /* Save from destruction (Linux).  */
69   //fprintf (stderr, "calling select with timeout %ld\n", timeout);
70   r = select (data->s + 1, &rfds, NULL, NULL, data->timeout);
71   if (data->timeout)
72     data->timeout->tv_sec = timeout; /* Restore.  */
73   //fprintf (stderr, "select returning %d\n", r);
74   if (r > 0)
75     {
76       len = recv (data->s, buf, sizeof (buf), 0);
77       if (len > 0)
78         return data->cb (buf, len);
79     }
80   return r;
81 }
82
83 struct polldata *
84 udp_server (const char *bindto, struct timeval *timeout, data_cb cb)
85 {
86   struct addrinfo *res;
87   int s = -1;
88
89   for (res = _resolve (bindto); res; res = _resolve (bindto))
90     {
91       s = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
92       if (s >= 0)
93         {
94           if (bind (s, res->ai_addr, res->ai_addrlen) == 0)
95             break;              /* Done.  */
96           else
97             {
98               close (s);
99               s = -1;
100             }
101         }
102     }
103
104   if (s >= 0)
105     {
106       struct polldata *data = malloc (sizeof (struct polldata));
107       assert (data);
108       memset (data, 0, sizeof (struct polldata));
109       data->s = s;
110       data->cb = cb;
111       if (timeout)
112         {
113           data->timeout = malloc (sizeof (struct timeval));
114           assert (data->timeout);
115           memcpy (data->timeout, timeout, sizeof (struct timeval));
116         }
117       return data;
118     }
119
120   return NULL;
121 }
122
123 ssize_t
124 hd (const uint8_t *buf, ssize_t len)
125 {
126   int i;
127
128   printf ("# len: %ld\n", len);
129   for (i = 0; i < len; i++)
130     {
131       printf ("%02x%s", buf[i], (i+1) % 8 ? " " : "   ");
132       if ((i + 1) % 16 == 0)
133         printf ("\n");
134     }
135   printf ("\n");
136   return len;
137 }