aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/makefile2
-rw-r--r--src/unix.c328
-rw-r--r--src/unixtcp.c338
-rw-r--r--src/unixtcp.h21
-rw-r--r--src/unixudp.c388
-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, 803 insertions, 316 deletions
diff --git a/src/makefile b/src/makefile
index 2e00950..0e4a544 100644
--- a/src/makefile
+++ b/src/makefile
@@ -307,6 +307,8 @@ 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) \
310 unix.$(O) 312 unix.$(O)
311 313
312#------ 314#------
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..88baac0
--- /dev/null
+++ b/src/unixtcp.c
@@ -0,0 +1,338 @@
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
10#include "auxiliar.h"
11#include "socket.h"
12#include "options.h"
13#include "unixtcp.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 *unixtcp_tryconnect(p_unix un, const char *path);
37static const char *unixtcp_trybind(p_unix un, const char *path);
38
39/* unixtcp object methods */
40static luaL_Reg unixtcp_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/* functions in library namespace */
72static luaL_Reg func[] = {
73 {"tcp", global_create},
74 {NULL, NULL}
75};
76
77/*-------------------------------------------------------------------------*\
78* Initializes module
79\*-------------------------------------------------------------------------*/
80int unixtcp_open(lua_State *L)
81{
82 /* create classes */
83 auxiliar_newclass(L, "unixtcp{master}", unixtcp_methods);
84 auxiliar_newclass(L, "unixtcp{client}", unixtcp_methods);
85 auxiliar_newclass(L, "unixtcp{server}", unixtcp_methods);
86
87 /* create class groups */
88 auxiliar_add2group(L, "unixtcp{master}", "unixtcp{any}");
89 auxiliar_add2group(L, "unixtcp{client}", "unixtcp{any}");
90 auxiliar_add2group(L, "unixtcp{server}", "unixtcp{any}");
91
92 luaL_setfuncs(L, func, 0);
93 return 1;
94}
95
96/*=========================================================================*\
97* Lua methods
98\*=========================================================================*/
99/*-------------------------------------------------------------------------*\
100* Just call buffered IO methods
101\*-------------------------------------------------------------------------*/
102static int meth_send(lua_State *L) {
103 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{client}", 1);
104 return buffer_meth_send(L, &un->buf);
105}
106
107static int meth_receive(lua_State *L) {
108 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{client}", 1);
109 return buffer_meth_receive(L, &un->buf);
110}
111
112static int meth_getstats(lua_State *L) {
113 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{client}", 1);
114 return buffer_meth_getstats(L, &un->buf);
115}
116
117static int meth_setstats(lua_State *L) {
118 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{client}", 1);
119 return buffer_meth_setstats(L, &un->buf);
120}
121
122/*-------------------------------------------------------------------------*\
123* Just call option handler
124\*-------------------------------------------------------------------------*/
125static int meth_setoption(lua_State *L) {
126 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
127 return opt_meth_setoption(L, optset, &un->sock);
128}
129
130/*-------------------------------------------------------------------------*\
131* Select support methods
132\*-------------------------------------------------------------------------*/
133static int meth_getfd(lua_State *L) {
134 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
135 lua_pushnumber(L, (int) un->sock);
136 return 1;
137}
138
139/* this is very dangerous, but can be handy for those that are brave enough */
140static int meth_setfd(lua_State *L) {
141 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
142 un->sock = (t_socket) luaL_checknumber(L, 2);
143 return 0;
144}
145
146static int meth_dirty(lua_State *L) {
147 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
148 lua_pushboolean(L, !buffer_isempty(&un->buf));
149 return 1;
150}
151
152/*-------------------------------------------------------------------------*\
153* Waits for and returns a client object attempting connection to the
154* server object
155\*-------------------------------------------------------------------------*/
156static int meth_accept(lua_State *L) {
157 p_unix server = (p_unix) auxiliar_checkclass(L, "unixtcp{server}", 1);
158 p_timeout tm = timeout_markstart(&server->tm);
159 t_socket sock;
160 int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
161 /* if successful, push client socket */
162 if (err == IO_DONE) {
163 p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
164 auxiliar_setclass(L, "unixtcp{client}", -1);
165 /* initialize structure fields */
166 socket_setnonblocking(&sock);
167 clnt->sock = sock;
168 io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
169 (p_error) socket_ioerror, &clnt->sock);
170 timeout_init(&clnt->tm, -1, -1);
171 buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
172 return 1;
173 } else {
174 lua_pushnil(L);
175 lua_pushstring(L, socket_strerror(err));
176 return 2;
177 }
178}
179
180/*-------------------------------------------------------------------------*\
181* Binds an object to an address
182\*-------------------------------------------------------------------------*/
183static const char *unixtcp_trybind(p_unix un, const char *path) {
184 struct sockaddr_un local;
185 size_t len = strlen(path);
186 int err;
187 if (len >= sizeof(local.sun_path)) return "path too long";
188 memset(&local, 0, sizeof(local));
189 strcpy(local.sun_path, path);
190 local.sun_family = AF_UNIX;
191#ifdef UNIX_HAS_SUN_LEN
192 local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
193 + len + 1;
194 err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
195
196#else
197 err = socket_bind(&un->sock, (SA *) &local,
198 sizeof(local.sun_family) + len);
199#endif
200 if (err != IO_DONE) socket_destroy(&un->sock);
201 return socket_strerror(err);
202}
203
204static int meth_bind(lua_State *L) {
205 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{master}", 1);
206 const char *path = luaL_checkstring(L, 2);
207 const char *err = unixtcp_trybind(un, path);
208 if (err) {
209 lua_pushnil(L);
210 lua_pushstring(L, err);
211 return 2;
212 }
213 lua_pushnumber(L, 1);
214 return 1;
215}
216
217/*-------------------------------------------------------------------------*\
218* Turns a master unixtcp object into a client object.
219\*-------------------------------------------------------------------------*/
220static const char *unixtcp_tryconnect(p_unix un, const char *path)
221{
222 struct sockaddr_un remote;
223 int err;
224 size_t len = strlen(path);
225 if (len >= sizeof(remote.sun_path)) return "path too long";
226 memset(&remote, 0, sizeof(remote));
227 strcpy(remote.sun_path, path);
228 remote.sun_family = AF_UNIX;
229 timeout_markstart(&un->tm);
230#ifdef UNIX_HAS_SUN_LEN
231 remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
232 + len + 1;
233 err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
234#else
235 err = socket_connect(&un->sock, (SA *) &remote,
236 sizeof(remote.sun_family) + len, &un->tm);
237#endif
238 if (err != IO_DONE) socket_destroy(&un->sock);
239 return socket_strerror(err);
240}
241
242static int meth_connect(lua_State *L)
243{
244 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{master}", 1);
245 const char *path = luaL_checkstring(L, 2);
246 const char *err = unixtcp_tryconnect(un, path);
247 if (err) {
248 lua_pushnil(L);
249 lua_pushstring(L, err);
250 return 2;
251 }
252 /* turn master object into a client object */
253 auxiliar_setclass(L, "unixtcp{client}", 1);
254 lua_pushnumber(L, 1);
255 return 1;
256}
257
258/*-------------------------------------------------------------------------*\
259* Closes socket used by object
260\*-------------------------------------------------------------------------*/
261static int meth_close(lua_State *L)
262{
263 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
264 socket_destroy(&un->sock);
265 lua_pushnumber(L, 1);
266 return 1;
267}
268
269/*-------------------------------------------------------------------------*\
270* Puts the sockt in listen mode
271\*-------------------------------------------------------------------------*/
272static int meth_listen(lua_State *L)
273{
274 p_unix un = (p_unix) auxiliar_checkclass(L, "unixtcp{master}", 1);
275 int backlog = (int) luaL_optnumber(L, 2, 32);
276 int err = socket_listen(&un->sock, backlog);
277 if (err != IO_DONE) {
278 lua_pushnil(L);
279 lua_pushstring(L, socket_strerror(err));
280 return 2;
281 }
282 /* turn master object into a server object */
283 auxiliar_setclass(L, "unixtcp{server}", 1);
284 lua_pushnumber(L, 1);
285 return 1;
286}
287
288/*-------------------------------------------------------------------------*\
289* Shuts the connection down partially
290\*-------------------------------------------------------------------------*/
291static int meth_shutdown(lua_State *L)
292{
293 /* SHUT_RD, SHUT_WR, SHUT_RDWR have the value 0, 1, 2, so we can use method index directly */
294 static const char* methods[] = { "receive", "send", "both", NULL };
295 p_unix tcp = (p_unix) auxiliar_checkclass(L, "unixtcp{client}", 1);
296 int how = luaL_checkoption(L, 2, "both", methods);
297 socket_shutdown(&tcp->sock, how);
298 lua_pushnumber(L, 1);
299 return 1;
300}
301
302/*-------------------------------------------------------------------------*\
303* Just call tm methods
304\*-------------------------------------------------------------------------*/
305static int meth_settimeout(lua_State *L) {
306 p_unix un = (p_unix) auxiliar_checkgroup(L, "unixtcp{any}", 1);
307 return timeout_meth_settimeout(L, &un->tm);
308}
309
310/*=========================================================================*\
311* Library functions
312\*=========================================================================*/
313/*-------------------------------------------------------------------------*\
314* Creates a master unixtcp object
315\*-------------------------------------------------------------------------*/
316static int global_create(lua_State *L) {
317 t_socket sock;
318 int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
319 /* try to allocate a system socket */
320 if (err == IO_DONE) {
321 /* allocate unixtcp object */
322 p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
323 /* set its type as master object */
324 auxiliar_setclass(L, "unixtcp{master}", -1);
325 /* initialize remaining structure fields */
326 socket_setnonblocking(&sock);
327 un->sock = sock;
328 io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
329 (p_error) socket_ioerror, &un->sock);
330 timeout_init(&un->tm, -1, -1);
331 buffer_init(&un->buf, &un->io, &un->tm);
332 return 1;
333 } else {
334 lua_pushnil(L);
335 lua_pushstring(L, socket_strerror(err));
336 return 2;
337 }
338}
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..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}
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