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