aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Nehab <diego.nehab@gmail.com>2016-07-22 14:06:30 -0300
committerGitHub <noreply@github.com>2016-07-22 14:06:30 -0300
commit316a9455b9cb4637fe6e62b20fbe05f5141fec54 (patch)
treee23e0e39cb27a23c68233758dd69ea9574d71ec8
parent30a64c585a444d3007976a4b4a1b8014d7797e04 (diff)
parent2205c2053c9bdd270c90f93d23fe44c9674bad3e (diff)
downloadluasocket-316a9455b9cb4637fe6e62b20fbe05f5141fec54.tar.gz
luasocket-316a9455b9cb4637fe6e62b20fbe05f5141fec54.tar.bz2
luasocket-316a9455b9cb4637fe6e62b20fbe05f5141fec54.zip
Merge pull request #181 from enginix/master
Add support for datagram unix domain sockets
-rw-r--r--src/makefile3
-rw-r--r--src/unix.c328
-rw-r--r--src/unixtcp.c357
-rw-r--r--src/unixtcp.h21
-rw-r--r--src/unixudp.c407
-rw-r--r--src/unixudp.h20
-rw-r--r--test/unixtcpclnt.lua (renamed from test/unixclnt.lua)2
-rw-r--r--test/unixtcpsrvr.lua (renamed from test/unixsrvr.lua)2
-rw-r--r--test/unixudpclnt.lua9
-rw-r--r--test/unixudpsrvr.lua9
10 files changed, 842 insertions, 316 deletions
diff --git a/src/makefile b/src/makefile
index 2e00950..2ffd7d9 100644
--- a/src/makefile
+++ b/src/makefile
@@ -307,6 +307,9 @@ UNIX_OBJS=\
307 timeout.$(O) \ 307 timeout.$(O) \
308 io.$(O) \ 308 io.$(O) \
309 usocket.$(O) \ 309 usocket.$(O) \
310 unixtcp.$(O) \
311 unixudp.$(O) \
312 compat.$(O) \
310 unix.$(O) 313 unix.$(O)
311 314
312#------ 315#------
diff --git a/src/unix.c b/src/unix.c
index 5bc3148..2009c19 100644
--- a/src/unix.c
+++ b/src/unix.c
@@ -2,329 +2,29 @@
2* Unix domain socket 2* Unix domain socket
3* LuaSocket toolkit 3* LuaSocket toolkit
4\*=========================================================================*/ 4\*=========================================================================*/
5#include <string.h>
6
7#include "lua.h" 5#include "lua.h"
8#include "lauxlib.h" 6#include "lauxlib.h"
9 7
10#include "auxiliar.h" 8#include "unixtcp.h"
11#include "socket.h" 9#include "unixudp.h"
12#include "options.h"
13#include "unix.h"
14#include <sys/un.h>
15
16/*=========================================================================*\
17* Internal function prototypes
18\*=========================================================================*/
19static int global_create(lua_State *L);
20static int meth_connect(lua_State *L);
21static int meth_listen(lua_State *L);
22static int meth_bind(lua_State *L);
23static int meth_send(lua_State *L);
24static int meth_shutdown(lua_State *L);
25static int meth_receive(lua_State *L);
26static int meth_accept(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_getfd(lua_State *L);
31static int meth_setfd(lua_State *L);
32static int meth_dirty(lua_State *L);
33static int meth_getstats(lua_State *L);
34static int meth_setstats(lua_State *L);
35
36static const char *unix_tryconnect(p_unix un, const char *path);
37static const char *unix_trybind(p_unix un, const char *path);
38
39/* unix object methods */
40static luaL_Reg unix_methods[] = {
41 {"__gc", meth_close},
42 {"__tostring", auxiliar_tostring},
43 {"accept", meth_accept},
44 {"bind", meth_bind},
45 {"close", meth_close},
46 {"connect", meth_connect},
47 {"dirty", meth_dirty},
48 {"getfd", meth_getfd},
49 {"getstats", meth_getstats},
50 {"setstats", meth_setstats},
51 {"listen", meth_listen},
52 {"receive", meth_receive},
53 {"send", meth_send},
54 {"setfd", meth_setfd},
55 {"setoption", meth_setoption},
56 {"setpeername", meth_connect},
57 {"setsockname", meth_bind},
58 {"settimeout", meth_settimeout},
59 {"shutdown", meth_shutdown},
60 {NULL, NULL}
61};
62
63/* socket option handlers */
64static t_opt optset[] = {
65 {"keepalive", opt_set_keepalive},
66 {"reuseaddr", opt_set_reuseaddr},
67 {"linger", opt_set_linger},
68 {NULL, NULL}
69};
70
71/*-------------------------------------------------------------------------*\
72* Initializes module
73\*-------------------------------------------------------------------------*/
74int luaopen_socket_unix(lua_State *L) {
75 /* create classes */
76 auxiliar_newclass(L, "unix{master}", unix_methods);
77 auxiliar_newclass(L, "unix{client}", unix_methods);
78 auxiliar_newclass(L, "unix{server}", unix_methods);
79 /* create class groups */
80 auxiliar_add2group(L, "unix{master}", "unix{any}");
81 auxiliar_add2group(L, "unix{client}", "unix{any}");
82 auxiliar_add2group(L, "unix{server}", "unix{any}");
83 /* return the function instead of the 'socket' table */
84 lua_pushcfunction(L, global_create);
85 return 1;
86}
87
88/*=========================================================================*\
89* Lua methods
90\*=========================================================================*/
91/*-------------------------------------------------------------------------*\
92* Just call buffered IO methods
93\*-------------------------------------------------------------------------*/
94static int meth_send(lua_State *L) {
95 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
96 return buffer_meth_send(L, &un->buf);
97}
98
99static int meth_receive(lua_State *L) {
100 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
101 return buffer_meth_receive(L, &un->buf);
102}
103
104static int meth_getstats(lua_State *L) {
105 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
106 return buffer_meth_getstats(L, &un->buf);
107}
108
109static int meth_setstats(lua_State *L) {
110 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
111 return buffer_meth_setstats(L, &un->buf);
112}
113
114/*-------------------------------------------------------------------------*\
115* Just call option handler
116\*-------------------------------------------------------------------------*/
117static int meth_setoption(lua_State *L) {
118 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
119 return opt_meth_setoption(L, optset, &un->sock);
120}
121
122/*-------------------------------------------------------------------------*\
123* Select support methods
124\*-------------------------------------------------------------------------*/
125static int meth_getfd(lua_State *L) {
126 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
127 lua_pushnumber(L, (int) un->sock);
128 return 1;
129}
130
131/* this is very dangerous, but can be handy for those that are brave enough */
132static int meth_setfd(lua_State *L) {
133 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
134 un->sock = (t_socket) luaL_checknumber(L, 2);
135 return 0;
136}
137
138static int meth_dirty(lua_State *L) {
139 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
140 lua_pushboolean(L, !buffer_isempty(&un->buf));
141 return 1;
142}
143 10
144/*-------------------------------------------------------------------------*\ 11/*-------------------------------------------------------------------------*\
145* Waits for and returns a client object attempting connection to the 12* Modules and functions
146* server object
147\*-------------------------------------------------------------------------*/ 13\*-------------------------------------------------------------------------*/
148static int meth_accept(lua_State *L) { 14static const luaL_Reg mod[] = {
149 p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1); 15 {"tcp", unixtcp_open},
150 p_timeout tm = timeout_markstart(&server->tm); 16 {"udp", unixudp_open},
151 t_socket sock; 17 {NULL, NULL}
152 int err = socket_accept(&server->sock, &sock, NULL, NULL, tm); 18};
153 /* if successful, push client socket */
154 if (err == IO_DONE) {
155 p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
156 auxiliar_setclass(L, "unix{client}", -1);
157 /* initialize structure fields */
158 socket_setnonblocking(&sock);
159 clnt->sock = sock;
160 io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
161 (p_error) socket_ioerror, &clnt->sock);
162 timeout_init(&clnt->tm, -1, -1);
163 buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
164 return 1;
165 } else {
166 lua_pushnil(L);
167 lua_pushstring(L, socket_strerror(err));
168 return 2;
169 }
170}
171
172/*-------------------------------------------------------------------------*\
173* Binds an object to an address
174\*-------------------------------------------------------------------------*/
175static const char *unix_trybind(p_unix un, const char *path) {
176 struct sockaddr_un local;
177 size_t len = strlen(path);
178 int err;
179 if (len >= sizeof(local.sun_path)) return "path too long";
180 memset(&local, 0, sizeof(local));
181 strcpy(local.sun_path, path);
182 local.sun_family = AF_UNIX;
183#ifdef UNIX_HAS_SUN_LEN
184 local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
185 + len + 1;
186 err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
187
188#else
189 err = socket_bind(&un->sock, (SA *) &local,
190 sizeof(local.sun_family) + len);
191#endif
192 if (err != IO_DONE) socket_destroy(&un->sock);
193 return socket_strerror(err);
194}
195
196static int meth_bind(lua_State *L) {
197 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
198 const char *path = luaL_checkstring(L, 2);
199 const char *err = unix_trybind(un, path);
200 if (err) {
201 lua_pushnil(L);
202 lua_pushstring(L, err);
203 return 2;
204 }
205 lua_pushnumber(L, 1);
206 return 1;
207}
208
209/*-------------------------------------------------------------------------*\
210* Turns a master unix object into a client object.
211\*-------------------------------------------------------------------------*/
212static const char *unix_tryconnect(p_unix un, const char *path)
213{
214 struct sockaddr_un remote;
215 int err;
216 size_t len = strlen(path);
217 if (len >= sizeof(remote.sun_path)) return "path too long";
218 memset(&remote, 0, sizeof(remote));
219 strcpy(remote.sun_path, path);
220 remote.sun_family = AF_UNIX;
221 timeout_markstart(&un->tm);
222#ifdef UNIX_HAS_SUN_LEN
223 remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
224 + len + 1;
225 err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
226#else
227 err = socket_connect(&un->sock, (SA *) &remote,
228 sizeof(remote.sun_family) + len, &un->tm);
229#endif
230 if (err != IO_DONE) socket_destroy(&un->sock);
231 return socket_strerror(err);
232}
233
234static int meth_connect(lua_State *L)
235{
236 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
237 const char *path = luaL_checkstring(L, 2);
238 const char *err = unix_tryconnect(un, path);
239 if (err) {
240 lua_pushnil(L);
241 lua_pushstring(L, err);
242 return 2;
243 }
244 /* turn master object into a client object */
245 auxiliar_setclass(L, "unix{client}", 1);
246 lua_pushnumber(L, 1);
247 return 1;
248}
249
250/*-------------------------------------------------------------------------*\
251* Closes socket used by object
252\*-------------------------------------------------------------------------*/
253static int meth_close(lua_State *L)
254{
255 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
256 socket_destroy(&un->sock);
257 lua_pushnumber(L, 1);
258 return 1;
259}
260
261/*-------------------------------------------------------------------------*\
262* Puts the sockt in listen mode
263\*-------------------------------------------------------------------------*/
264static int meth_listen(lua_State *L)
265{
266 p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
267 int backlog = (int) luaL_optnumber(L, 2, 32);
268 int err = socket_listen(&un->sock, backlog);
269 if (err != IO_DONE) {
270 lua_pushnil(L);
271 lua_pushstring(L, socket_strerror(err));
272 return 2;
273 }
274 /* turn master object into a server object */
275 auxiliar_setclass(L, "unix{server}", 1);
276 lua_pushnumber(L, 1);
277 return 1;
278}
279 19
280/*-------------------------------------------------------------------------*\ 20/*-------------------------------------------------------------------------*\
281* Shuts the connection down partially 21* Initializes module
282\*-------------------------------------------------------------------------*/ 22\*-------------------------------------------------------------------------*/
283static int meth_shutdown(lua_State *L) 23int luaopen_socket_unix(lua_State *L)
284{ 24{
285 /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */ 25 int i;
286 static const char* methods[] = { "receive", "send", "both", NULL }; 26 lua_newtable(L);
287 p_unix tcp = (p_unix) auxiliar_checkclass(L, "unix{client}", 1); 27 for (i = 0; mod[i].name; i++) mod[i].func(L);
288 int how = luaL_checkoption(L, 2, "both", methods); 28 return 1;
289 socket_shutdown(&tcp->sock, how);
290 lua_pushnumber(L, 1);
291 return 1;
292} 29}
293 30
294/*-------------------------------------------------------------------------*\
295* Just call tm methods
296\*-------------------------------------------------------------------------*/
297static int meth_settimeout(lua_State *L) {
298 p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
299 return timeout_meth_settimeout(L, &un->tm);
300}
301
302/*=========================================================================*\
303* Library functions
304\*=========================================================================*/
305/*-------------------------------------------------------------------------*\
306* Creates a master unix object
307\*-------------------------------------------------------------------------*/
308static int global_create(lua_State *L) {
309 t_socket sock;
310 int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
311 /* try to allocate a system socket */
312 if (err == IO_DONE) {
313 /* allocate unix object */
314 p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
315 /* set its type as master object */
316 auxiliar_setclass(L, "unix{master}", -1);
317 /* initialize remaining structure fields */
318 socket_setnonblocking(&sock);
319 un->sock = sock;
320 io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
321 (p_error) socket_ioerror, &un->sock);
322 timeout_init(&un->tm, -1, -1);
323 buffer_init(&un->buf, &un->io, &un->tm);
324 return 1;
325 } else {
326 lua_pushnil(L);
327 lua_pushstring(L, socket_strerror(err));
328 return 2;
329 }
330}
diff --git a/src/unixtcp.c b/src/unixtcp.c
new file mode 100644
index 0000000..747ef5f
--- /dev/null
+++ b/src/unixtcp.c
@@ -0,0 +1,357 @@
1/*=========================================================================*\
2* Unix domain socket tcp sub module
3* LuaSocket toolkit
4\*=========================================================================*/
5#include <string.h>
6
7#include "lua.h"
8#include "lauxlib.h"
9#include "compat.h"
10
11#include "auxiliar.h"
12#include "socket.h"
13#include "options.h"
14#include "unixtcp.h"
15#include <sys/un.h>
16
17/*=========================================================================*\
18* Internal function prototypes
19\*=========================================================================*/
20static int global_create(lua_State *L);
21static int meth_connect(lua_State *L);
22static int meth_listen(lua_State *L);
23static int meth_bind(lua_State *L);
24static int meth_send(lua_State *L);
25static int meth_shutdown(lua_State *L);
26static int meth_receive(lua_State *L);
27static int meth_accept(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_getfd(lua_State *L);
32static int meth_setfd(lua_State *L);
33static int meth_dirty(lua_State *L);
34static int meth_getstats(lua_State *L);
35static int meth_setstats(lua_State *L);
36static int meth_getsockname(lua_State *L);
37
38static const char *unixtcp_tryconnect(p_unix un, const char *path);
39static const char *unixtcp_trybind(p_unix un, const char *path);
40
41/* unixtcp object methods */
42static luaL_Reg unixtcp_methods[] = {
43 {"__gc", meth_close},
44 {"__tostring", auxiliar_tostring},
45 {"accept", meth_accept},
46 {"bind", meth_bind},
47 {"close", meth_close},
48 {"connect", meth_connect},
49 {"dirty", meth_dirty},
50 {"getfd", meth_getfd},
51 {"getstats", meth_getstats},
52 {"setstats", meth_setstats},
53 {"listen", meth_listen},
54 {"receive", meth_receive},
55 {"send", meth_send},
56 {"setfd", meth_setfd},
57 {"setoption", meth_setoption},
58 {"setpeername", meth_connect},
59 {"setsockname", meth_bind},
60 {"getsockname", meth_getsockname},
61 {"settimeout", meth_settimeout},
62 {"shutdown", meth_shutdown},
63 {NULL, NULL}
64};
65
66/* socket option handlers */
67static t_opt optset[] = {
68 {"keepalive", opt_set_keepalive},
69 {"reuseaddr", opt_set_reuseaddr},
70 {"linger", opt_set_linger},
71 {NULL, NULL}
72};
73
74/* functions in library namespace */
75static luaL_Reg func[] = {
76 {"tcp", global_create},
77 {NULL, NULL}
78};
79
80/*-------------------------------------------------------------------------*\
81* Initializes module
82\*-------------------------------------------------------------------------*/
83int unixtcp_open(lua_State *L)
84{
85 /* create classes */
86 auxiliar_newclass(L, "unixtcp{master}", unixtcp_methods);
87 auxiliar_newclass(L, "unixtcp{client}", unixtcp_methods);
88 auxiliar_newclass(L, "unixtcp{server}", unixtcp_methods);
89
90 /* create class groups */
91 auxiliar_add2group(L, "unixtcp{master}", "unixtcp{any}");
92 auxiliar_add2group(L, "unixtcp{client}", "unixtcp{any}");
93 auxiliar_add2group(L, "unixtcp{server}", "unixtcp{any}");
94
95 luaL_setfuncs(L, func, 0);
96 return 0;
97}
98
99/*=========================================================================*\
100* Lua methods
101\*=========================================================================*/
102/*-------------------------------------------------------------------------*\
103* Just call buffered IO methods
104\*-------------------------------------------------------------------------*/
105static int meth_send(lua_State *L) {
106 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{client}", 1);
107 return buffer_meth_send(L, &un->buf);
108}
109
110static int meth_receive(lua_State *L) {
111 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{client}", 1);
112 return buffer_meth_receive(L, &un->buf);
113}
114
115static int meth_getstats(lua_State *L) {
116 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{client}", 1);
117 return buffer_meth_getstats(L, &un->buf);
118}
119
120static int meth_setstats(lua_State *L) {
121 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{client}", 1);
122 return buffer_meth_setstats(L, &un->buf);
123}
124
125/*-------------------------------------------------------------------------*\
126* Just call option handler
127\*-------------------------------------------------------------------------*/
128static int meth_setoption(lua_State *L) {
129 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
130 return opt_meth_setoption(L, optset, &un->sock);
131}
132
133/*-------------------------------------------------------------------------*\
134* Select support methods
135\*-------------------------------------------------------------------------*/
136static int meth_getfd(lua_State *L) {
137 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
138 lua_pushnumber(L, (int) un->sock);
139 return 1;
140}
141
142/* this is very dangerous, but can be handy for those that are brave enough */
143static int meth_setfd(lua_State *L) {
144 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
145 un->sock = (t_socket) luaL_checknumber(L, 2);
146 return 0;
147}
148
149static int meth_dirty(lua_State *L) {
150 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
151 lua_pushboolean(L, !buffer_isempty(&un->buf));
152 return 1;
153}
154
155/*-------------------------------------------------------------------------*\
156* Waits for and returns a client object attempting connection to the
157* server object
158\*-------------------------------------------------------------------------*/
159static int meth_accept(lua_State *L) {
160 p_unix server = (p_unix) auxiliar_checkclass(L, "unixtcp{server}", 1);
161 p_timeout tm = timeout_markstart(&server->tm);
162 t_socket sock;
163 int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
164 /* if successful, push client socket */
165 if (err == IO_DONE) {
166 p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
167 auxiliar_setclass(L, "unixtcp{client}", -1);
168 /* initialize structure fields */
169 socket_setnonblocking(&sock);
170 clnt->sock = sock;
171 io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
172 (p_error) socket_ioerror, &clnt->sock);
173 timeout_init(&clnt->tm, -1, -1);
174 buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
175 return 1;
176 } else {
177 lua_pushnil(L);
178 lua_pushstring(L, socket_strerror(err));
179 return 2;
180 }
181}
182
183/*-------------------------------------------------------------------------*\
184* Binds an object to an address
185\*-------------------------------------------------------------------------*/
186static const char *unixtcp_trybind(p_unix un, const char *path) {
187 struct sockaddr_un local;
188 size_t len = strlen(path);
189 int err;
190 if (len >= sizeof(local.sun_path)) return "path too long";
191 memset(&local, 0, sizeof(local));
192 strcpy(local.sun_path, path);
193 local.sun_family = AF_UNIX;
194#ifdef UNIX_HAS_SUN_LEN
195 local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
196 + len + 1;
197 err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
198
199#else
200 err = socket_bind(&un->sock, (SA *) &local,
201 sizeof(local.sun_family) + len);
202#endif
203 if (err != IO_DONE) socket_destroy(&un->sock);
204 return socket_strerror(err);
205}
206
207static int meth_bind(lua_State *L) {
208 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{master}", 1);
209 const char *path = luaL_checkstring(L, 2);
210 const char *err = unixtcp_trybind(un, path);
211 if (err) {
212 lua_pushnil(L);
213 lua_pushstring(L, err);
214 return 2;
215 }
216 lua_pushnumber(L, 1);
217 return 1;
218}
219
220static int meth_getsockname(lua_State *L)
221{
222 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
223 struct sockaddr_un peer = {0};
224 socklen_t peer_len = sizeof(peer);
225
226 if (getsockname(un->sock, (SA *) &peer, &peer_len) < 0) {
227 lua_pushnil(L);
228 lua_pushstring(L, socket_strerror(errno));
229 return 2;
230 }
231
232 lua_pushstring(L, peer.sun_path);
233 return 1;
234}
235
236/*-------------------------------------------------------------------------*\
237* Turns a master unixtcp object into a client object.
238\*-------------------------------------------------------------------------*/
239static const char *unixtcp_tryconnect(p_unix un, const char *path)
240{
241 struct sockaddr_un remote;
242 int err;
243 size_t len = strlen(path);
244 if (len >= sizeof(remote.sun_path)) return "path too long";
245 memset(&remote, 0, sizeof(remote));
246 strcpy(remote.sun_path, path);
247 remote.sun_family = AF_UNIX;
248 timeout_markstart(&un->tm);
249#ifdef UNIX_HAS_SUN_LEN
250 remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
251 + len + 1;
252 err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
253#else
254 err = socket_connect(&un->sock, (SA *) &remote,
255 sizeof(remote.sun_family) + len, &un->tm);
256#endif
257 if (err != IO_DONE) socket_destroy(&un->sock);
258 return socket_strerror(err);
259}
260
261static int meth_connect(lua_State *L)
262{
263 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{master}", 1);
264 const char *path = luaL_checkstring(L, 2);
265 const char *err = unixtcp_tryconnect(un, path);
266 if (err) {
267 lua_pushnil(L);
268 lua_pushstring(L, err);
269 return 2;
270 }
271 /* turn master object into a client object */
272 auxiliar_setclass(L, "unixtcp{client}", 1);
273 lua_pushnumber(L, 1);
274 return 1;
275}
276
277/*-------------------------------------------------------------------------*\
278* Closes socket used by object
279\*-------------------------------------------------------------------------*/
280static int meth_close(lua_State *L)
281{
282 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
283 socket_destroy(&un->sock);
284 lua_pushnumber(L, 1);
285 return 1;
286}
287
288/*-------------------------------------------------------------------------*\
289* Puts the sockt in listen mode
290\*-------------------------------------------------------------------------*/
291static int meth_listen(lua_State *L)
292{
293 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{master}", 1);
294 int backlog = (int) luaL_optnumber(L, 2, 32);
295 int err = socket_listen(&un->sock, backlog);
296 if (err != IO_DONE) {
297 lua_pushnil(L);
298 lua_pushstring(L, socket_strerror(err));
299 return 2;
300 }
301 /* turn master object into a server object */
302 auxiliar_setclass(L, "unixtcp{server}", 1);
303 lua_pushnumber(L, 1);
304 return 1;
305}
306
307/*-------------------------------------------------------------------------*\
308* Shuts the connection down partially
309\*-------------------------------------------------------------------------*/
310static int meth_shutdown(lua_State *L)
311{
312 /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
313 static const char* methods[] = { "receive", "send", "both", NULL };
314 p_unix tcp = (p_unix) auxiliar_checkclass(L, "unixtcp{client}", 1);
315 int how = luaL_checkoption(L, 2, "both", methods);
316 socket_shutdown(&tcp->sock, how);
317 lua_pushnumber(L, 1);
318 return 1;
319}
320
321/*-------------------------------------------------------------------------*\
322* Just call tm methods
323\*-------------------------------------------------------------------------*/
324static int meth_settimeout(lua_State *L) {
325 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
326 return timeout_meth_settimeout(L, &un->tm);
327}
328
329/*=========================================================================*\
330* Library functions
331\*=========================================================================*/
332/*-------------------------------------------------------------------------*\
333* Creates a master unixtcp object
334\*-------------------------------------------------------------------------*/
335static int global_create(lua_State *L) {
336 t_socket sock;
337 int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
338 /* try to allocate a system socket */
339 if (err == IO_DONE) {
340 /* allocate unixtcp object */
341 p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
342 /* set its type as master object */
343 auxiliar_setclass(L, "unixtcp{master}", -1);
344 /* initialize remaining structure fields */
345 socket_setnonblocking(&sock);
346 un->sock = sock;
347 io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
348 (p_error) socket_ioerror, &un->sock);
349 timeout_init(&un->tm, -1, -1);
350 buffer_init(&un->buf, &un->io, &un->tm);
351 return 1;
352 } else {
353 lua_pushnil(L);
354 lua_pushstring(L, socket_strerror(err));
355 return 2;
356 }
357}
diff --git a/src/unixtcp.h b/src/unixtcp.h
new file mode 100644
index 0000000..0eababc
--- /dev/null
+++ b/src/unixtcp.h
@@ -0,0 +1,21 @@
1#ifndef UNIXTCP_H
2#define UNIXTCP_H
3/*=========================================================================*\
4* UNIX TCP object
5* LuaSocket toolkit
6*
7* The unixtcp.h module is basicly a glue that puts together modules buffer.h,
8* timeout.h socket.h and inet.h to provide the LuaSocket UNIX TCP (AF_UNIX,
9* SOCK_STREAM) support.
10*
11* Three classes are defined: master, client and server. The master class is
12* a newly created unixtcp object, that has not been bound or connected. Server
13* objects are unixtcp objects bound to some local address. Client objects are
14* unixtcp objects either connected to some address or returned by the accept
15* method of a server object.
16\*=========================================================================*/
17#include "unix.h"
18
19int unixtcp_open(lua_State *L);
20
21#endif /* UNIXTCP_H */
diff --git a/src/unixudp.c b/src/unixudp.c
new file mode 100644
index 0000000..0e0a19a
--- /dev/null
+++ b/src/unixudp.c
@@ -0,0 +1,407 @@
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}
diff --git a/src/unixudp.h b/src/unixudp.h
new file mode 100644
index 0000000..ccfdc07
--- /dev/null
+++ b/src/unixudp.h
@@ -0,0 +1,20 @@
1#ifndef UNIXUDP_H
2#define UNIXUDP_H
3/*=========================================================================*\
4* UDP object
5* LuaSocket toolkit
6*
7* The udp.h module provides LuaSocket with support for UDP protocol
8* (AF_INET, SOCK_DGRAM).
9*
10* Two classes are defined: connected and unconnected. UDP objects are
11* originally unconnected. They can be "connected" to a given address
12* with a call to the setpeername function. The same function can be used to
13* break the connection.
14\*=========================================================================*/
15
16#include "unix.h"
17
18int unixudp_open(lua_State *L);
19
20#endif /* UNIXUDP_H */
diff --git a/test/unixclnt.lua b/test/unixtcpclnt.lua
index 5171535..652a680 100644
--- a/test/unixclnt.lua
+++ b/test/unixtcpclnt.lua
@@ -1,6 +1,6 @@
1socket = require"socket" 1socket = require"socket"
2socket.unix = require"socket.unix" 2socket.unix = require"socket.unix"
3c = assert(socket.unix()) 3c = assert(socket.unix.tcp())
4assert(c:connect("/tmp/foo")) 4assert(c:connect("/tmp/foo"))
5while 1 do 5while 1 do
6 local l = io.read() 6 local l = io.read()
diff --git a/test/unixsrvr.lua b/test/unixtcpsrvr.lua
index 81b9c99..2a2b065 100644
--- a/test/unixsrvr.lua
+++ b/test/unixtcpsrvr.lua
@@ -1,6 +1,6 @@
1 socket = require"socket" 1 socket = require"socket"
2 socket.unix = require"socket.unix" 2 socket.unix = require"socket.unix"
3 u = assert(socket.unix()) 3 u = assert(socket.unix.tcp())
4 assert(u:bind("/tmp/foo")) 4 assert(u:bind("/tmp/foo"))
5 assert(u:listen()) 5 assert(u:listen())
6 c = assert(u:accept()) 6 c = assert(u:accept())
diff --git a/test/unixudpclnt.lua b/test/unixudpclnt.lua
new file mode 100644
index 0000000..bbbff7f
--- /dev/null
+++ b/test/unixudpclnt.lua
@@ -0,0 +1,9 @@
1socket = require"socket"
2socket.unix = require"socket.unix"
3c = assert(socket.unix.udp())
4c:bind("/tmp/bar")
5while 1 do
6 local l = io.read("*l")
7 assert(c:sendto(l, "/tmp/foo"))
8 print(assert(c:receivefrom()))
9end
diff --git a/test/unixudpsrvr.lua b/test/unixudpsrvr.lua
new file mode 100644
index 0000000..5ed71dc
--- /dev/null
+++ b/test/unixudpsrvr.lua
@@ -0,0 +1,9 @@
1 socket = require"socket"
2 socket.unix = require"socket.unix"
3 u = assert(socket.unix.udp())
4 assert(u:bind("/tmp/foo"))
5 while 1 do
6 x, r = assert(u:receivefrom())
7 print(x, r)
8 assert(u:sendto(">" .. x, r))
9 end