1/*=========================================================================*\
2* Unix domain socket udp submodule
3* LuaSocket toolkit
4\*=========================================================================*/
5#include <string.h>
6#include <stdlib.h>
7
8#include "lua.h"
9#include "lauxlib.h"
10#include "compat.h"
11
12#include "auxiliar.h"
13#include "socket.h"
14#include "options.h"
15#include "unix.h"
16#include <sys/un.h>
17
18#define UNIXUDP_DATAGRAMSIZE 8192
19
20/*=========================================================================*\
21* Internal function prototypes
22\*=========================================================================*/
23static int global_create(lua_State *L);
24static int meth_connect(lua_State *L);
25static int meth_bind(lua_State *L);
26static int meth_send(lua_State *L);
27static int meth_receive(lua_State *L);
28static int meth_close(lua_State *L);
29static int meth_setoption(lua_State *L);
30static int meth_settimeout(lua_State *L);
31static int meth_gettimeout(lua_State *L);
32static int meth_getfd(lua_State *L);
33static int meth_setfd(lua_State *L);
34static int meth_dirty(lua_State *L);
35static int meth_receivefrom(lua_State *L);
36static int meth_sendto(lua_State *L);
37static int meth_getsockname(lua_State *L);
38
39static const char *unixudp_tryconnect(p_unix un, const char *path);
40static const char *unixudp_trybind(p_unix un, const char *path);
41
42/* unixudp object methods */
43static luaL_Reg unixudp_methods[] = {
44 {"__gc", meth_close},
45 {"__tostring", auxiliar_tostring},
46 {"bind", meth_bind},
47 {"close", meth_close},
48 {"connect", meth_connect},
49 {"dirty", meth_dirty},
50 {"getfd", meth_getfd},
51 {"send", meth_send},
52 {"sendto", meth_sendto},
53 {"receive", meth_receive},
54 {"receivefrom", meth_receivefrom},
55 {"setfd", meth_setfd},
56 {"setoption", meth_setoption},
57 {"setpeername", meth_connect},
58 {"setsockname", meth_bind},
59 {"getsockname", meth_getsockname},
60 {"settimeout", meth_settimeout},
61 {"gettimeout", meth_gettimeout},
62 {NULL, NULL}
63};
64
65/* socket option handlers */
66static t_opt optset[] = {
67 {"reuseaddr", opt_set_reuseaddr},
68 {NULL, NULL}
69};
70
71/* functions in library namespace */
72static luaL_Reg func[] = {
73 {"udp", global_create},
74 {NULL, NULL}
75};
76
77/*-------------------------------------------------------------------------*\
78* Initializes module
79\*-------------------------------------------------------------------------*/
80int unixudp_open(lua_State *L)
81{
82 /* create classes */
83 auxiliar_newclass(L, "unixudp{connected}", unixudp_methods);
84 auxiliar_newclass(L, "unixudp{unconnected}", unixudp_methods);
85 /* create class groups */
86 auxiliar_add2group(L, "unixudp{connected}", "unixudp{any}");
87 auxiliar_add2group(L, "unixudp{unconnected}", "unixudp{any}");
88 auxiliar_add2group(L, "unixudp{connected}", "select{able}");
89 auxiliar_add2group(L, "unixudp{unconnected}", "select{able}");
90
91 luaL_setfuncs(L, func, 0);
92 return 0;
93}
94
95/*=========================================================================*\
96* Lua methods
97\*=========================================================================*/
98static const char *unixudp_strerror(int err)
99{
100 /* a 'closed' error on an unconnected means the target address was not
101 * accepted by the transport layer */
102 if (err == IO_CLOSED) return "refused";
103 else return socket_strerror(err);
104}
105
106static int meth_send(lua_State *L)
107{
108 p_unix un = (p_unix) auxiliar_checkclass(L, "unixudp{connected}", 1);
109 p_timeout tm = &un->tm;
110 size_t count, sent = 0;
111 int err;
112 const char *data = luaL_checklstring(L, 2, &count);
113 timeout_markstart(tm);
114 err = socket_send(&un->sock, data, count, &sent, tm);
115 if (err != IO_DONE) {
116 lua_pushnil(L);
117 lua_pushstring(L, unixudp_strerror(err));
118 return 2;
119 }
120 lua_pushnumber(L, (lua_Number) sent);
121 return 1;
122}
123
124/*-------------------------------------------------------------------------*\
125* Send data through unconnected unixudp socket
126\*-------------------------------------------------------------------------*/
127static int meth_sendto(lua_State *L)
128{
129 p_unix un = (p_unix) auxiliar_checkclass(L, "unixudp{unconnected}", 1);
130 size_t count, sent = 0;
131 const char *data = luaL_checklstring(L, 2, &count);
132 const char *path = luaL_checkstring(L, 3);
133 p_timeout tm = &un->tm;
134 int err;
135 struct sockaddr_un remote;
136 size_t len = strlen(path);
137
138 if (len >= sizeof(remote.sun_path)) {
139 lua_pushnil(L);
140 lua_pushstring(L, "path too long");
141 return 2;
142 }
143
144 memset(&remote, 0, sizeof(remote));
145 strcpy(remote.sun_path, path);
146 remote.sun_family = AF_UNIX;
147 timeout_markstart(tm);
148#ifdef UNIX_HAS_SUN_LEN
149 remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
150 + len + 1;
151 err = socket_sendto(&un->sock, data, count, &sent, (SA *) &remote, remote.sun_len, tm);
152#else
153 err = socket_sendto(&un->sock, data, count, &sent, (SA *) &remote,
154 sizeof(remote.sun_family) + len, tm);
155#endif
156 if (err != IO_DONE) {
157 lua_pushnil(L);
158 lua_pushstring(L, unixudp_strerror(err));
159 return 2;
160 }
161 lua_pushnumber(L, (lua_Number) sent);
162 return 1;
163}
164
165static int meth_receive(lua_State *L) {
166 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixudp{any}", 1);
167 char buf[UNIXUDP_DATAGRAMSIZE];
168 size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
169 char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
170 int err;
171 p_timeout tm = &un->tm;
172 timeout_markstart(tm);
173 if (!dgram) {
174 lua_pushnil(L);
175 lua_pushliteral(L, "out of memory");
176 return 2;
177 }
178 err = socket_recv(&un->sock, dgram, wanted, &got, tm);
179 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
180 if (err != IO_DONE && err != IO_CLOSED) {
181 lua_pushnil(L);
182 lua_pushstring(L, unixudp_strerror(err));
183 if (wanted > sizeof(buf)) free(dgram);
184 return 2;
185 }
186 lua_pushlstring(L, dgram, got);
187 if (wanted > sizeof(buf)) free(dgram);
188 return 1;
189}
190
191/*-------------------------------------------------------------------------*\
192* Receives data and sender from a UDP socket
193\*-------------------------------------------------------------------------*/
194static int meth_receivefrom(lua_State *L) {
195 p_unix un = (p_unix) auxiliar_checkclass(L, "unixudp{unconnected}", 1);
196 char buf[UNIXUDP_DATAGRAMSIZE];
197 size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
198 char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
199 struct sockaddr_un addr;
200 socklen_t addr_len = sizeof(addr);
201 int err;
202 p_timeout tm = &un->tm;
203 timeout_markstart(tm);
204 if (!dgram) {
205 lua_pushnil(L);
206 lua_pushliteral(L, "out of memory");
207 return 2;
208 }
209 err = socket_recvfrom(&un->sock, dgram, wanted, &got, (SA *) &addr,
210 &addr_len, tm);
211 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
212 if (err != IO_DONE && err != IO_CLOSED) {
213 lua_pushnil(L);
214 lua_pushstring(L, unixudp_strerror(err));
215 if (wanted > sizeof(buf)) free(dgram);
216 return 2;
217 }
218
219 lua_pushlstring(L, dgram, got);
220 /* the path may be empty, when client send without bind */
221 lua_pushstring(L, addr.sun_path);
222 if (wanted > sizeof(buf)) free(dgram);
223 return 2;
224}
225
226/*-------------------------------------------------------------------------*\
227* Just call option handler
228\*-------------------------------------------------------------------------*/
229static int meth_setoption(lua_State *L) {
230 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixudp{any}", 1);
231 return opt_meth_setoption(L, optset, &un->sock);
232}
233
234/*-------------------------------------------------------------------------*\
235* Select support methods
236\*-------------------------------------------------------------------------*/
237static int meth_getfd(lua_State *L) {
238 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixudp{any}", 1);
239 lua_pushnumber(L, (int) un->sock);
240 return 1;
241}
242
243/* this is very dangerous, but can be handy for those that are brave enough */
244static int meth_setfd(lua_State *L) {
245 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixudp{any}", 1);
246 un->sock = (t_socket) luaL_checknumber(L, 2);
247 return 0;
248}
249
250static int meth_dirty(lua_State *L) {
251 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixudp{any}", 1);
252 (void) un;
253 lua_pushboolean(L, 0);
254 return 1;
255}
256
257/*-------------------------------------------------------------------------*\
258* Binds an object to an address
259\*-------------------------------------------------------------------------*/
260static const char *unixudp_trybind(p_unix un, const char *path) {
261 struct sockaddr_un local;
262 size_t len = strlen(path);
263 int err;
264 if (len >= sizeof(local.sun_path)) return "path too long";
265 memset(&local, 0, sizeof(local));
266 strcpy(local.sun_path, path);
267 local.sun_family = AF_UNIX;
268#ifdef UNIX_HAS_SUN_LEN
269 local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
270 + len + 1;
271 err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
272
273#else
274 err = socket_bind(&un->sock, (SA *) &local,
275 sizeof(local.sun_family) + len);
276#endif
277 if (err != IO_DONE) socket_destroy(&un->sock);
278 return socket_strerror(err);
279}
280
281static int meth_bind(lua_State *L)
282{
283 p_unix un = (p_unix) auxiliar_checkclass(L, "unixudp{unconnected}", 1);
284 const char *path = luaL_checkstring(L, 2);
285 const char *err = unixudp_trybind(un, path);
286 if (err) {
287 lua_pushnil(L);
288 lua_pushstring(L, err);
289 return 2;
290 }
291 lua_pushnumber(L, 1);
292 return 1;
293}
294
295static int meth_getsockname(lua_State *L)
296{
297 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixudp{any}", 1);
298 struct sockaddr_un peer = {0};
299 socklen_t peer_len = sizeof(peer);
300
301 if (getsockname(un->sock, (SA *) &peer, &peer_len) < 0) {
302 lua_pushnil(L);
303 lua_pushstring(L, socket_strerror(errno));
304 return 2;
305 }
306
307 lua_pushstring(L, peer.sun_path);
308 return 1;
309}
310
311/*-------------------------------------------------------------------------*\
312* Turns a master unixudp object into a client object.
313\*-------------------------------------------------------------------------*/
314static const char *unixudp_tryconnect(p_unix un, const char *path)
315{
316 struct sockaddr_un remote;
317 int err;
318 size_t len = strlen(path);
319 if (len >= sizeof(remote.sun_path)) return "path too long";
320 memset(&remote, 0, sizeof(remote));
321 strcpy(remote.sun_path, path);
322 remote.sun_family = AF_UNIX;
323 timeout_markstart(&un->tm);
324#ifdef UNIX_HAS_SUN_LEN
325 remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
326 + len + 1;
327 err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
328#else
329 err = socket_connect(&un->sock, (SA *) &remote,
330 sizeof(remote.sun_family) + len, &un->tm);
331#endif
332 if (err != IO_DONE) socket_destroy(&un->sock);
333 return socket_strerror(err);
334}
335
336static int meth_connect(lua_State *L)
337{
338 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixudp{any}", 1);
339 const char *path = luaL_checkstring(L, 2);
340 const char *err = unixudp_tryconnect(un, path);
341 if (err) {
342 lua_pushnil(L);
343 lua_pushstring(L, err);
344 return 2;
345 }
346 /* turn unconnected object into a connected object */
347 auxiliar_setclass(L, "unixudp{connected}", 1);
348 lua_pushnumber(L, 1);
349 return 1;
350}
351
352/*-------------------------------------------------------------------------*\
353* Closes socket used by object
354\*-------------------------------------------------------------------------*/
355static int meth_close(lua_State *L)
356{
357 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixudp{any}", 1);
358 socket_destroy(&un->sock);
359 lua_pushnumber(L, 1);
360 return 1;
361}
362
363/*-------------------------------------------------------------------------*\
364* Just call tm methods
365\*-------------------------------------------------------------------------*/
366static int meth_settimeout(lua_State *L)
367{
368 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixudp{any}", 1);
369 return timeout_meth_settimeout(L, &un->tm);
370}
371
372static int meth_gettimeout(lua_State *L)
373{
374 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixudp{any}", 1);
375 return timeout_meth_gettimeout(L, &un->tm);
376}
377
378/*=========================================================================*\
379* Library functions
380\*=========================================================================*/
381/*-------------------------------------------------------------------------*\
382* Creates a master unixudp object
383\*-------------------------------------------------------------------------*/
384static int global_create(lua_State *L)
385{
386 t_socket sock;
387 int err = socket_create(&sock, AF_UNIX, SOCK_DGRAM, 0);
388 /* try to allocate a system socket */
389 if (err == IO_DONE) {
390 /* allocate unixudp object */
391 p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
392 /* set its type as master object */
393 auxiliar_setclass(L, "unixudp{unconnected}", -1);
394 /* initialize remaining structure fields */
395 socket_setnonblocking(&sock);
396 un->sock = sock;
397 io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
398 (p_error) socket_ioerror, &un->sock);
399 timeout_init(&un->tm, -1, -1);
400 buffer_init(&un->buf, &un->io, &un->tm);
401 return 1;
402 } else {
403 lua_pushnil(L);
404 lua_pushstring(L, socket_strerror(err));
405 return 2;
406 }
407}
408