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