beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / luasocket / src / udp.c
blob8e88b1784a265dc36d9ab2c9254c6d02999d7843
1 /*=========================================================================*\
2 * UDP object
3 * LuaSocket toolkit
4 \*=========================================================================*/
5 #include <string.h>
7 #include "lua.h"
8 #include "lauxlib.h"
10 #include "auxiliar.h"
11 #include "socket.h"
12 #include "inet.h"
13 #include "options.h"
14 #include "udp.h"
16 /* min and max macros */
17 #ifndef MIN
18 #define MIN(x, y) ((x) < (y) ? x : y)
19 #endif
20 #ifndef MAX
21 #define MAX(x, y) ((x) > (y) ? x : y)
22 #endif
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[] = {
48 {"__gc", meth_close},
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},
58 {"send", meth_send},
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},
66 {NULL, NULL}
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},
81 {NULL, NULL}
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},
88 {NULL, NULL}
91 /* functions in library namespace */
92 static luaL_Reg func[] = {
93 {"udp", global_create},
94 {"udp6", global_create6},
95 {NULL, NULL}
98 /*-------------------------------------------------------------------------*\
99 * Initializes module
100 \*-------------------------------------------------------------------------*/
101 int udp_open(lua_State *L)
103 /* create classes */
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);
113 return 0;
116 /*=========================================================================*\
117 * Lua methods
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;
133 int err;
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) {
138 lua_pushnil(L);
139 lua_pushstring(L, udp_strerror(err));
140 return 2;
142 lua_pushnumber(L, (lua_Number) sent);
143 return 1;
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;
156 int err;
157 switch (udp->family) {
158 case PF_INET: {
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);
168 break;
170 case PF_INET6: {
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);
180 break;
182 default:
183 lua_pushnil(L);
184 lua_pushfstring(L, "unknown family %d", udp->family);
185 return 2;
187 if (err != IO_DONE) {
188 lua_pushnil(L);
189 lua_pushstring(L, udp_strerror(err));
190 return 2;
192 lua_pushnumber(L, (lua_Number) sent);
193 return 1;
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));
203 int err;
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)
210 err = IO_DONE;
211 if (err != IO_DONE) {
212 lua_pushnil(L);
213 lua_pushstring(L, udp_strerror(err));
214 return 2;
216 lua_pushlstring(L, buffer, got);
217 return 1;
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));
227 int err;
228 p_timeout tm = &udp->tm;
229 timeout_markstart(tm);
230 count = MIN(count, sizeof(buffer));
231 switch (udp->family) {
232 case PF_INET: {
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)
239 err = IO_DONE;
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))) {
245 lua_pushnil(L);
246 lua_pushstring(L, "invalid source address");
247 return 2;
249 lua_pushstring(L, addrstr);
250 lua_pushnumber(L, ntohs(addr.sin_port));
251 return 3;
253 break;
255 case PF_INET6: {
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)
262 err = IO_DONE;
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))) {
268 lua_pushnil(L);
269 lua_pushstring(L, "invalid source address");
270 return 2;
272 lua_pushstring(L, addrstr);
273 lua_pushnumber(L, ntohs(addr.sin6_port));
274 return 3;
276 break;
278 default:
279 lua_pushnil(L);
280 lua_pushfstring(L, "unknown family %d", udp->family);
281 return 2;
283 lua_pushnil(L);
284 lua_pushstring(L, udp_strerror(err));
285 return 2;
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");
296 return 1;
297 } else {
298 lua_pushliteral(L, "inet4");
299 return 1;
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);
309 return 1;
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);
316 return 0;
319 static int meth_dirty(lua_State *L) {
320 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
321 (void) udp;
322 lua_pushboolean(L, 0);
323 return 1;
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;
373 const char *err;
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;
378 if (connecting) {
379 err = inet_tryconnect(&udp->sock, address, port, tm, &connecthints);
380 if (err) {
381 lua_pushnil(L);
382 lua_pushstring(L, err);
383 return 2;
385 auxiliar_setclass(L, "udp.connected", 1);
386 } else {
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);
394 return 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);
404 return 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);
414 const char *err;
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);
421 if (err) {
422 lua_pushnil(L);
423 lua_pushstring(L, err);
424 return 2;
426 lua_pushnumber(L, 1);
427 return 1;
430 /*=========================================================================*\
431 * Library functions
432 \*=========================================================================*/
433 /*-------------------------------------------------------------------------*\
434 * Creates a master udp object
435 \*-------------------------------------------------------------------------*/
436 static int udp_create(lua_State *L, int family) {
437 t_socket sock;
438 const char *err = inet_trycreate(&sock, family, SOCK_DGRAM);
439 /* try to allocate a system socket */
440 if (!err) {
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) {
447 int yes = 1;
448 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
449 (void *)&yes, sizeof(yes));
451 udp->sock = sock;
452 timeout_init(&udp->tm, -1, -1);
453 udp->family = family;
454 return 1;
455 } else {
456 lua_pushnil(L);
457 lua_pushstring(L, err);
458 return 2;
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);