1 /*=========================================================================*\
4 \*=========================================================================*/
16 /* min and max macros */
18 #define MIN(x, y) ((x) < (y) ? x : y)
21 #define MAX(x, y) ((x) > (y) ? x : y)
24 /*=========================================================================*\
25 * Internal function prototypes
26 \*=========================================================================*/
27 static int global_create(lua_State
*L
);
28 static int global_create6(lua_State
*L
);
29 static int meth_send(lua_State
*L
);
30 static int meth_sendto(lua_State
*L
);
31 static int meth_receive(lua_State
*L
);
32 static int meth_receivefrom(lua_State
*L
);
33 static int meth_getfamily(lua_State
*L
);
34 static int meth_getsockname(lua_State
*L
);
35 static int meth_getpeername(lua_State
*L
);
36 static int meth_setsockname(lua_State
*L
);
37 static int meth_setpeername(lua_State
*L
);
38 static int meth_close(lua_State
*L
);
39 static int meth_setoption(lua_State
*L
);
40 static int meth_getoption(lua_State
*L
);
41 static int meth_settimeout(lua_State
*L
);
42 static int meth_getfd(lua_State
*L
);
43 static int meth_setfd(lua_State
*L
);
44 static int meth_dirty(lua_State
*L
);
46 /* udp object methods */
47 static luaL_Reg udp_methods
[] = {
49 {"__tostring", auxiliar_tostring
},
50 {"close", meth_close
},
51 {"dirty", meth_dirty
},
52 {"getfamily", meth_getfamily
},
53 {"getfd", meth_getfd
},
54 {"getpeername", meth_getpeername
},
55 {"getsockname", meth_getsockname
},
56 {"receive", meth_receive
},
57 {"receivefrom", meth_receivefrom
},
59 {"sendto", meth_sendto
},
60 {"setfd", meth_setfd
},
61 {"setoption", meth_setoption
},
62 {"getoption", meth_getoption
},
63 {"setpeername", meth_setpeername
},
64 {"setsockname", meth_setsockname
},
65 {"settimeout", meth_settimeout
},
69 /* socket options for setoption */
70 static t_opt optset
[] = {
71 {"dontroute", opt_set_dontroute
},
72 {"broadcast", opt_set_broadcast
},
73 {"reuseaddr", opt_set_reuseaddr
},
74 {"reuseport", opt_set_reuseport
},
75 {"ip-multicast-if", opt_set_ip_multicast_if
},
76 {"ip-multicast-ttl", opt_set_ip_multicast_ttl
},
77 {"ip-multicast-loop", opt_set_ip_multicast_loop
},
78 {"ip-add-membership", opt_set_ip_add_membership
},
79 {"ip-drop-membership", opt_set_ip_drop_membersip
},
80 {"ipv6-v6only", opt_set_ip6_v6only
},
84 /* socket options for getoption */
85 static t_opt optget
[] = {
86 {"ip-multicast-if", opt_get_ip_multicast_if
},
87 {"ip-multicast-loop", opt_get_ip_multicast_loop
},
91 /* functions in library namespace */
92 static luaL_Reg func
[] = {
93 {"udp", global_create
},
94 {"udp6", global_create6
},
98 /*-------------------------------------------------------------------------*\
100 \*-------------------------------------------------------------------------*/
101 int udp_open(lua_State
*L
)
104 auxiliar_newclass(L
, "udp.connected", udp_methods
);
105 auxiliar_newclass(L
, "udp.unconnected", udp_methods
);
106 /* create class groups */
107 auxiliar_add2group(L
, "udp.connected", "udp{any}");
108 auxiliar_add2group(L
, "udp.unconnected", "udp{any}");
109 auxiliar_add2group(L
, "udp.connected", "select{able}");
110 auxiliar_add2group(L
, "udp.unconnected", "select{able}");
111 /* define library functions */
112 luaL_openlib(L
, NULL
, func
, 0);
116 /*=========================================================================*\
118 \*=========================================================================*/
119 const char *udp_strerror(int err
) {
120 /* a 'closed' error on an unconnected means the target address was not
121 * accepted by the transport layer */
122 if (err
== IO_CLOSED
) return "refused";
123 else return socket_strerror(err
);
126 /*-------------------------------------------------------------------------*\
127 * Send data through connected udp socket
128 \*-------------------------------------------------------------------------*/
129 static int meth_send(lua_State
*L
) {
130 p_udp udp
= (p_udp
) auxiliar_checkclass(L
, "udp.connected", 1);
131 p_timeout tm
= &udp
->tm
;
132 size_t count
, sent
= 0;
134 const char *data
= luaL_checklstring(L
, 2, &count
);
135 timeout_markstart(tm
);
136 err
= socket_send(&udp
->sock
, data
, count
, &sent
, tm
);
137 if (err
!= IO_DONE
) {
139 lua_pushstring(L
, udp_strerror(err
));
142 lua_pushnumber(L
, (lua_Number
) sent
);
146 /*-------------------------------------------------------------------------*\
147 * Send data through unconnected udp socket
148 \*-------------------------------------------------------------------------*/
149 static int meth_sendto(lua_State
*L
) {
150 p_udp udp
= (p_udp
) auxiliar_checkclass(L
, "udp.unconnected", 1);
151 size_t count
, sent
= 0;
152 const char *data
= luaL_checklstring(L
, 2, &count
);
153 const char *ip
= luaL_checkstring(L
, 3);
154 unsigned short port
= (unsigned short) luaL_checknumber(L
, 4);
155 p_timeout tm
= &udp
->tm
;
157 switch (udp
->family
) {
159 struct sockaddr_in addr
;
160 memset(&addr
, 0, sizeof(addr
));
161 if (!inet_pton(AF_INET
, ip
, &addr
.sin_addr
))
162 luaL_argerror(L
, 3, "invalid ip address");
163 addr
.sin_family
= AF_INET
;
164 addr
.sin_port
= htons(port
);
165 timeout_markstart(tm
);
166 err
= socket_sendto(&udp
->sock
, data
, count
, &sent
,
167 (SA
*) &addr
, sizeof(addr
), tm
);
171 struct sockaddr_in6 addr
;
172 memset(&addr
, 0, sizeof(addr
));
173 if (!inet_pton(AF_INET6
, ip
, &addr
.sin6_addr
))
174 luaL_argerror(L
, 3, "invalid ip address");
175 addr
.sin6_family
= AF_INET6
;
176 addr
.sin6_port
= htons(port
);
177 timeout_markstart(tm
);
178 err
= socket_sendto(&udp
->sock
, data
, count
, &sent
,
179 (SA
*) &addr
, sizeof(addr
), tm
);
184 lua_pushfstring(L
, "unknown family %d", udp
->family
);
187 if (err
!= IO_DONE
) {
189 lua_pushstring(L
, udp_strerror(err
));
192 lua_pushnumber(L
, (lua_Number
) sent
);
196 /*-------------------------------------------------------------------------*\
197 * Receives data from a UDP socket
198 \*-------------------------------------------------------------------------*/
199 static int meth_receive(lua_State
*L
) {
200 p_udp udp
= (p_udp
) auxiliar_checkgroup(L
, "udp{any}", 1);
201 char buffer
[UDP_DATAGRAMSIZE
];
202 size_t got
, count
= (size_t) luaL_optnumber(L
, 2, sizeof(buffer
));
204 p_timeout tm
= &udp
->tm
;
205 count
= MIN(count
, sizeof(buffer
));
206 timeout_markstart(tm
);
207 err
= socket_recv(&udp
->sock
, buffer
, count
, &got
, tm
);
208 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
209 if (err
== IO_CLOSED
)
211 if (err
!= IO_DONE
) {
213 lua_pushstring(L
, udp_strerror(err
));
216 lua_pushlstring(L
, buffer
, got
);
220 /*-------------------------------------------------------------------------*\
221 * Receives data and sender from a UDP socket
222 \*-------------------------------------------------------------------------*/
223 static int meth_receivefrom(lua_State
*L
) {
224 p_udp udp
= (p_udp
) auxiliar_checkclass(L
, "udp.unconnected", 1);
225 char buffer
[UDP_DATAGRAMSIZE
];
226 size_t got
, count
= (size_t) luaL_optnumber(L
, 2, sizeof(buffer
));
228 p_timeout tm
= &udp
->tm
;
229 timeout_markstart(tm
);
230 count
= MIN(count
, sizeof(buffer
));
231 switch (udp
->family
) {
233 struct sockaddr_in addr
;
234 socklen_t addr_len
= sizeof(addr
);
235 err
= socket_recvfrom(&udp
->sock
, buffer
, count
, &got
,
236 (SA
*) &addr
, &addr_len
, tm
);
237 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
238 if (err
== IO_CLOSED
)
240 if (err
== IO_DONE
) {
241 char addrstr
[INET_ADDRSTRLEN
];
242 lua_pushlstring(L
, buffer
, got
);
243 if (!inet_ntop(AF_INET
, &addr
.sin_addr
,
244 addrstr
, sizeof(addrstr
))) {
246 lua_pushstring(L
, "invalid source address");
249 lua_pushstring(L
, addrstr
);
250 lua_pushnumber(L
, ntohs(addr
.sin_port
));
256 struct sockaddr_in6 addr
;
257 socklen_t addr_len
= sizeof(addr
);
258 err
= socket_recvfrom(&udp
->sock
, buffer
, count
, &got
,
259 (SA
*) &addr
, &addr_len
, tm
);
260 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
261 if (err
== IO_CLOSED
)
263 if (err
== IO_DONE
) {
264 char addrstr
[INET6_ADDRSTRLEN
];
265 lua_pushlstring(L
, buffer
, got
);
266 if (!inet_ntop(AF_INET6
, &addr
.sin6_addr
,
267 addrstr
, sizeof(addrstr
))) {
269 lua_pushstring(L
, "invalid source address");
272 lua_pushstring(L
, addrstr
);
273 lua_pushnumber(L
, ntohs(addr
.sin6_port
));
280 lua_pushfstring(L
, "unknown family %d", udp
->family
);
284 lua_pushstring(L
, udp_strerror(err
));
288 /*-------------------------------------------------------------------------*\
289 * Returns family as string
290 \*-------------------------------------------------------------------------*/
291 static int meth_getfamily(lua_State
*L
)
293 p_udp udp
= (p_udp
) auxiliar_checkgroup(L
, "udp{any}", 1);
294 if (udp
->family
== PF_INET6
) {
295 lua_pushliteral(L
, "inet6");
298 lua_pushliteral(L
, "inet4");
303 /*-------------------------------------------------------------------------*\
304 * Select support methods
305 \*-------------------------------------------------------------------------*/
306 static int meth_getfd(lua_State
*L
) {
307 p_udp udp
= (p_udp
) auxiliar_checkgroup(L
, "udp{any}", 1);
308 lua_pushnumber(L
, (int) udp
->sock
);
312 /* this is very dangerous, but can be handy for those that are brave enough */
313 static int meth_setfd(lua_State
*L
) {
314 p_udp udp
= (p_udp
) auxiliar_checkgroup(L
, "udp{any}", 1);
315 udp
->sock
= (t_socket
) luaL_checknumber(L
, 2);
319 static int meth_dirty(lua_State
*L
) {
320 p_udp udp
= (p_udp
) auxiliar_checkgroup(L
, "udp{any}", 1);
322 lua_pushboolean(L
, 0);
326 /*-------------------------------------------------------------------------*\
327 * Just call inet methods
328 \*-------------------------------------------------------------------------*/
329 static int meth_getpeername(lua_State
*L
) {
330 p_udp udp
= (p_udp
) auxiliar_checkclass(L
, "udp.connected", 1);
331 return inet_meth_getpeername(L
, &udp
->sock
, udp
->family
);
334 static int meth_getsockname(lua_State
*L
) {
335 p_udp udp
= (p_udp
) auxiliar_checkgroup(L
, "udp{any}", 1);
336 return inet_meth_getsockname(L
, &udp
->sock
, udp
->family
);
339 /*-------------------------------------------------------------------------*\
340 * Just call option handler
341 \*-------------------------------------------------------------------------*/
342 static int meth_setoption(lua_State
*L
) {
343 p_udp udp
= (p_udp
) auxiliar_checkgroup(L
, "udp{any}", 1);
344 return opt_meth_setoption(L
, optset
, &udp
->sock
);
347 /*-------------------------------------------------------------------------*\
348 * Just call option handler
349 \*-------------------------------------------------------------------------*/
350 static int meth_getoption(lua_State
*L
) {
351 p_udp udp
= (p_udp
) auxiliar_checkgroup(L
, "udp{any}", 1);
352 return opt_meth_getoption(L
, optget
, &udp
->sock
);
355 /*-------------------------------------------------------------------------*\
356 * Just call tm methods
357 \*-------------------------------------------------------------------------*/
358 static int meth_settimeout(lua_State
*L
) {
359 p_udp udp
= (p_udp
) auxiliar_checkgroup(L
, "udp{any}", 1);
360 return timeout_meth_settimeout(L
, &udp
->tm
);
363 /*-------------------------------------------------------------------------*\
364 * Turns a master udp object into a client object.
365 \*-------------------------------------------------------------------------*/
366 static int meth_setpeername(lua_State
*L
) {
367 p_udp udp
= (p_udp
) auxiliar_checkgroup(L
, "udp{any}", 1);
368 p_timeout tm
= &udp
->tm
;
369 const char *address
= luaL_checkstring(L
, 2);
370 int connecting
= strcmp(address
, "*");
371 const char *port
= connecting
? luaL_checkstring(L
, 3): "0";
372 struct addrinfo connecthints
;
374 memset(&connecthints
, 0, sizeof(connecthints
));
375 connecthints
.ai_socktype
= SOCK_DGRAM
;
376 /* make sure we try to connect only to the same family */
377 connecthints
.ai_family
= udp
->family
;
379 err
= inet_tryconnect(&udp
->sock
, address
, port
, tm
, &connecthints
);
382 lua_pushstring(L
, err
);
385 auxiliar_setclass(L
, "udp.connected", 1);
387 /* we ignore possible errors because Mac OS X always
388 * returns EAFNOSUPPORT */
389 inet_trydisconnect(&udp
->sock
, udp
->family
, tm
);
390 auxiliar_setclass(L
, "udp.unconnected", 1);
392 /* change class to connected or unconnected depending on address */
393 lua_pushnumber(L
, 1);
397 /*-------------------------------------------------------------------------*\
398 * Closes socket used by object
399 \*-------------------------------------------------------------------------*/
400 static int meth_close(lua_State
*L
) {
401 p_udp udp
= (p_udp
) auxiliar_checkgroup(L
, "udp{any}", 1);
402 socket_destroy(&udp
->sock
);
403 lua_pushnumber(L
, 1);
407 /*-------------------------------------------------------------------------*\
408 * Turns a master object into a server object
409 \*-------------------------------------------------------------------------*/
410 static int meth_setsockname(lua_State
*L
) {
411 p_udp udp
= (p_udp
) auxiliar_checkclass(L
, "udp.unconnected", 1);
412 const char *address
= luaL_checkstring(L
, 2);
413 const char *port
= luaL_checkstring(L
, 3);
415 struct addrinfo bindhints
;
416 memset(&bindhints
, 0, sizeof(bindhints
));
417 bindhints
.ai_socktype
= SOCK_DGRAM
;
418 bindhints
.ai_family
= udp
->family
;
419 bindhints
.ai_flags
= AI_PASSIVE
;
420 err
= inet_trybind(&udp
->sock
, address
, port
, &bindhints
);
423 lua_pushstring(L
, err
);
426 lua_pushnumber(L
, 1);
430 /*=========================================================================*\
432 \*=========================================================================*/
433 /*-------------------------------------------------------------------------*\
434 * Creates a master udp object
435 \*-------------------------------------------------------------------------*/
436 static int udp_create(lua_State
*L
, int family
) {
438 const char *err
= inet_trycreate(&sock
, family
, SOCK_DGRAM
);
439 /* try to allocate a system socket */
441 /* allocate udp object */
442 p_udp udp
= (p_udp
) lua_newuserdata(L
, sizeof(t_udp
));
443 auxiliar_setclass(L
, "udp.unconnected", -1);
444 /* initialize remaining structure fields */
445 socket_setnonblocking(&sock
);
446 if (family
== PF_INET6
) {
448 setsockopt(sock
, IPPROTO_IPV6
, IPV6_V6ONLY
,
449 (void *)&yes
, sizeof(yes
));
452 timeout_init(&udp
->tm
, -1, -1);
453 udp
->family
= family
;
457 lua_pushstring(L
, err
);
462 static int global_create(lua_State
*L
) {
463 return udp_create(L
, AF_INET
);
466 static int global_create6(lua_State
*L
) {
467 return udp_create(L
, AF_INET6
);