1 /*=========================================================================*\
2 * UDP object
3 * LuaSocket toolkit
4 \*=========================================================================*/
5 #include <string.h>
6 
7 #include "lua.h"
8 #include "lauxlib.h"
9 
10 #include "auxiliar.h"
11 #include "socket.h"
12 #include "inet.h"
13 #include "options.h"
14 #include "udp.h"
15 
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
23 
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);
45 
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}
67 };
68 
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}
82 };
83 
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}
89 };
90 
91 /* functions in library namespace */
92 static luaL_Reg func[] = {
93     {"udp", global_create},
94     {"udp6", global_create6},
95     {NULL, NULL}
96 };
97 
98 /*-------------------------------------------------------------------------*\
99 * Initializes module
100 \*-------------------------------------------------------------------------*/
udp_open(lua_State * L)101 int udp_open(lua_State *L)
102 {
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;
114 }
115 
116 /*=========================================================================*\
117 * Lua methods
118 \*=========================================================================*/
udp_strerror(int err)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);
124 }
125 
126 /*-------------------------------------------------------------------------*\
127 * Send data through connected udp socket
128 \*-------------------------------------------------------------------------*/
meth_send(lua_State * L)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;
141     }
142     lua_pushnumber(L, (lua_Number) sent);
143     return 1;
144 }
145 
146 /*-------------------------------------------------------------------------*\
147 * Send data through unconnected udp socket
148 \*-------------------------------------------------------------------------*/
meth_sendto(lua_State * L)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;
169 	}
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;
181 	}
182 	default:
183             lua_pushnil(L);
184             lua_pushfstring(L, "unknown family %d", udp->family);
185             return 2;
186     }
187     if (err != IO_DONE) {
188         lua_pushnil(L);
189         lua_pushstring(L, udp_strerror(err));
190         return 2;
191     }
192     lua_pushnumber(L, (lua_Number) sent);
193     return 1;
194 }
195 
196 /*-------------------------------------------------------------------------*\
197 * Receives data from a UDP socket
198 \*-------------------------------------------------------------------------*/
meth_receive(lua_State * L)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;
215     }
216     lua_pushlstring(L, buffer, got);
217     return 1;
218 }
219 
220 /*-------------------------------------------------------------------------*\
221 * Receives data and sender from a UDP socket
222 \*-------------------------------------------------------------------------*/
meth_receivefrom(lua_State * L)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;
248 		}
249 		lua_pushstring(L, addrstr);
250 		lua_pushnumber(L, ntohs(addr.sin_port));
251 		return 3;
252 	    }
253 	    break;
254 	}
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;
271 		}
272 		lua_pushstring(L, addrstr);
273 		lua_pushnumber(L, ntohs(addr.sin6_port));
274 		return 3;
275 	    }
276 	    break;
277 	}
278     default:
279         lua_pushnil(L);
280         lua_pushfstring(L, "unknown family %d", udp->family);
281         return 2;
282     }
283     lua_pushnil(L);
284     lua_pushstring(L, udp_strerror(err));
285     return 2;
286 }
287 
288 /*-------------------------------------------------------------------------*\
289 * Returns family as string
290 \*-------------------------------------------------------------------------*/
meth_getfamily(lua_State * L)291 static int meth_getfamily(lua_State *L)
292 {
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;
300     }
301 }
302 
303 /*-------------------------------------------------------------------------*\
304 * Select support methods
305 \*-------------------------------------------------------------------------*/
meth_getfd(lua_State * L)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;
310 }
311 
312 /* this is very dangerous, but can be handy for those that are brave enough */
meth_setfd(lua_State * L)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;
317 }
318 
meth_dirty(lua_State * L)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;
324 }
325 
326 /*-------------------------------------------------------------------------*\
327 * Just call inet methods
328 \*-------------------------------------------------------------------------*/
meth_getpeername(lua_State * L)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);
332 }
333 
meth_getsockname(lua_State * L)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);
337 }
338 
339 /*-------------------------------------------------------------------------*\
340 * Just call option handler
341 \*-------------------------------------------------------------------------*/
meth_setoption(lua_State * L)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);
345 }
346 
347 /*-------------------------------------------------------------------------*\
348 * Just call option handler
349 \*-------------------------------------------------------------------------*/
meth_getoption(lua_State * L)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);
353 }
354 
355 /*-------------------------------------------------------------------------*\
356 * Just call tm methods
357 \*-------------------------------------------------------------------------*/
meth_settimeout(lua_State * L)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);
361 }
362 
363 /*-------------------------------------------------------------------------*\
364 * Turns a master udp object into a client object.
365 \*-------------------------------------------------------------------------*/
meth_setpeername(lua_State * L)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;
384         }
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);
391     }
392     /* change class to connected or unconnected depending on address */
393     lua_pushnumber(L, 1);
394     return 1;
395 }
396 
397 /*-------------------------------------------------------------------------*\
398 * Closes socket used by object
399 \*-------------------------------------------------------------------------*/
meth_close(lua_State * L)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;
405 }
406 
407 /*-------------------------------------------------------------------------*\
408 * Turns a master object into a server object
409 \*-------------------------------------------------------------------------*/
meth_setsockname(lua_State * L)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;
425     }
426     lua_pushnumber(L, 1);
427     return 1;
428 }
429 
430 /*=========================================================================*\
431 * Library functions
432 \*=========================================================================*/
433 /*-------------------------------------------------------------------------*\
434 * Creates a master udp object
435 \*-------------------------------------------------------------------------*/
udp_create(lua_State * L,int family)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));
450         }
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;
459     }
460 }
461 
global_create(lua_State * L)462 static int global_create(lua_State *L) {
463 	return udp_create(L, AF_INET);
464 }
465 
global_create6(lua_State * L)466 static int global_create6(lua_State *L) {
467 	return udp_create(L, AF_INET6);
468 }
469