1 /*=========================================================================*\
2 * Unix domain socket
3 * LuaSocket toolkit
4 *
5 * RCS ID: $Id: unix.c,v 1.13 2006/03/13 07:16:39 diego Exp $
6 \*=========================================================================*/
7 #include <string.h>
8 
9 #include "lua.h"
10 #include "lauxlib.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 /*=========================================================================*\
19 * Internal function prototypes
20 \*=========================================================================*/
21 static int global_create(lua_State *L);
22 static int meth_connect(lua_State *L);
23 static int meth_listen(lua_State *L);
24 static int meth_bind(lua_State *L);
25 static int meth_send(lua_State *L);
26 static int meth_shutdown(lua_State *L);
27 static int meth_receive(lua_State *L);
28 static int meth_accept(lua_State *L);
29 static int meth_close(lua_State *L);
30 static int meth_setoption(lua_State *L);
31 static int meth_settimeout(lua_State *L);
32 static int meth_getfd(lua_State *L);
33 static int meth_setfd(lua_State *L);
34 static int meth_dirty(lua_State *L);
35 static int meth_getstats(lua_State *L);
36 static int meth_setstats(lua_State *L);
37 
38 static const char *unix_tryconnect(p_unix un, const char *path);
39 static const char *unix_trybind(p_unix un, const char *path);
40 
41 /* unix object methods */
42 static luaL_reg un[] = {
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     {"settimeout",  meth_settimeout},
61     {"shutdown",    meth_shutdown},
62     {NULL,          NULL}
63 };
64 
65 /* socket option handlers */
66 static t_opt opt[] = {
67     {"keepalive",   opt_keepalive},
68     {"reuseaddr",   opt_reuseaddr},
69     {"linger",      opt_linger},
70     {NULL,          NULL}
71 };
72 
73 /* our socket creation function */
74 static luaL_reg func[] = {
75     {"unix", global_create},
76     {NULL,          NULL}
77 };
78 
79 
80 /*-------------------------------------------------------------------------*\
81 * Initializes module
82 \*-------------------------------------------------------------------------*/
luaopen_socket_unix(lua_State * L)83 int luaopen_socket_unix(lua_State *L) {
84     /* create classes */
85     auxiliar_newclass(L, "unix{master}", un);
86     auxiliar_newclass(L, "unix{client}", un);
87     auxiliar_newclass(L, "unix{server}", un);
88     /* create class groups */
89     auxiliar_add2group(L, "unix{master}", "unix{any}");
90     auxiliar_add2group(L, "unix{client}", "unix{any}");
91     auxiliar_add2group(L, "unix{server}", "unix{any}");
92     /* make sure the function ends up in the package table */
93     luaL_openlib(L, "socket", func, 0);
94     /* return the function instead of the 'socket' table */
95     lua_pushstring(L, "unix");
96     lua_gettable(L, -2);
97     return 1;
98 }
99 
100 /*=========================================================================*\
101 * Lua methods
102 \*=========================================================================*/
103 /*-------------------------------------------------------------------------*\
104 * Just call buffered IO methods
105 \*-------------------------------------------------------------------------*/
meth_send(lua_State * L)106 static int meth_send(lua_State *L) {
107     p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
108     return buffer_meth_send(L, &un->buf);
109 }
110 
meth_receive(lua_State * L)111 static int meth_receive(lua_State *L) {
112     p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
113     return buffer_meth_receive(L, &un->buf);
114 }
115 
meth_getstats(lua_State * L)116 static int meth_getstats(lua_State *L) {
117     p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
118     return buffer_meth_getstats(L, &un->buf);
119 }
120 
meth_setstats(lua_State * L)121 static int meth_setstats(lua_State *L) {
122     p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
123     return buffer_meth_setstats(L, &un->buf);
124 }
125 
126 /*-------------------------------------------------------------------------*\
127 * Just call option handler
128 \*-------------------------------------------------------------------------*/
meth_setoption(lua_State * L)129 static int meth_setoption(lua_State *L) {
130     p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
131     return opt_meth_setoption(L, opt, &un->sock);
132 }
133 
134 /*-------------------------------------------------------------------------*\
135 * Select support methods
136 \*-------------------------------------------------------------------------*/
meth_getfd(lua_State * L)137 static int meth_getfd(lua_State *L) {
138     p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
139     lua_pushnumber(L, (int) un->sock);
140     return 1;
141 }
142 
143 /* this is very dangerous, but can be handy for those that are brave enough */
meth_setfd(lua_State * L)144 static int meth_setfd(lua_State *L) {
145     p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
146     un->sock = (t_socket) luaL_checknumber(L, 2);
147     return 0;
148 }
149 
meth_dirty(lua_State * L)150 static int meth_dirty(lua_State *L) {
151     p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
152     lua_pushboolean(L, !buffer_isempty(&un->buf));
153     return 1;
154 }
155 
156 /*-------------------------------------------------------------------------*\
157 * Waits for and returns a client object attempting connection to the
158 * server object
159 \*-------------------------------------------------------------------------*/
meth_accept(lua_State * L)160 static int meth_accept(lua_State *L) {
161     p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1);
162     p_timeout tm = timeout_markstart(&server->tm);
163     t_socket sock;
164     int err = socket_accept(&server->sock, &sock, NULL, NULL, tm);
165     /* if successful, push client socket */
166     if (err == IO_DONE) {
167         p_unix clnt = (p_unix) lua_newuserdata(L, sizeof(t_unix));
168         auxiliar_setclass(L, "unix{client}", -1);
169         /* initialize structure fields */
170         socket_setnonblocking(&sock);
171         clnt->sock = sock;
172         io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
173                 (p_error) socket_ioerror, &clnt->sock);
174         timeout_init(&clnt->tm, -1, -1);
175         buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
176         return 1;
177     } else {
178         lua_pushnil(L);
179         lua_pushstring(L, socket_strerror(err));
180         return 2;
181     }
182 }
183 
184 /*-------------------------------------------------------------------------*\
185 * Binds an object to an address
186 \*-------------------------------------------------------------------------*/
unix_trybind(p_unix un,const char * path)187 static const char *unix_trybind(p_unix un, const char *path) {
188     struct sockaddr_un local;
189     size_t len = strlen(path);
190     int err;
191     if (len >= sizeof(local.sun_path)) return "path too long";
192     memset(&local, 0, sizeof(local));
193     strcpy(local.sun_path, path);
194     local.sun_family = AF_UNIX;
195 #ifdef UNIX_HAS_SUN_LEN
196     local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
197         + len + 1;
198     err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
199 
200 #else
201     err = socket_bind(&un->sock, (SA *) &local,
202             sizeof(local.sun_family) + len);
203 #endif
204     if (err != IO_DONE) socket_destroy(&un->sock);
205     return socket_strerror(err);
206 }
207 
meth_bind(lua_State * L)208 static int meth_bind(lua_State *L) {
209     p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
210     const char *path =  luaL_checkstring(L, 2);
211     const char *err = unix_trybind(un, path);
212     if (err) {
213         lua_pushnil(L);
214         lua_pushstring(L, err);
215         return 2;
216     }
217     lua_pushnumber(L, 1);
218     return 1;
219 }
220 
221 /*-------------------------------------------------------------------------*\
222 * Turns a master unix object into a client object.
223 \*-------------------------------------------------------------------------*/
unix_tryconnect(p_unix un,const char * path)224 static const char *unix_tryconnect(p_unix un, const char *path)
225 {
226     struct sockaddr_un remote;
227     int err;
228     size_t len = strlen(path);
229     if (len >= sizeof(remote.sun_path)) return "path too long";
230     memset(&remote, 0, sizeof(remote));
231     strcpy(remote.sun_path, path);
232     remote.sun_family = AF_UNIX;
233     timeout_markstart(&un->tm);
234 #ifdef UNIX_HAS_SUN_LEN
235     remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
236         + len + 1;
237     err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
238 #else
239     err = socket_connect(&un->sock, (SA *) &remote,
240             sizeof(remote.sun_family) + len, &un->tm);
241 #endif
242     if (err != IO_DONE) socket_destroy(&un->sock);
243     return socket_strerror(err);
244 }
245 
meth_connect(lua_State * L)246 static int meth_connect(lua_State *L)
247 {
248     p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
249     const char *path =  luaL_checkstring(L, 2);
250     const char *err = unix_tryconnect(un, path);
251     if (err) {
252         lua_pushnil(L);
253         lua_pushstring(L, err);
254         return 2;
255     }
256     /* turn master object into a client object */
257     auxiliar_setclass(L, "unix{client}", 1);
258     lua_pushnumber(L, 1);
259     return 1;
260 }
261 
262 /*-------------------------------------------------------------------------*\
263 * Closes socket used by object
264 \*-------------------------------------------------------------------------*/
meth_close(lua_State * L)265 static int meth_close(lua_State *L)
266 {
267     p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
268     socket_destroy(&un->sock);
269     lua_pushnumber(L, 1);
270     return 1;
271 }
272 
273 /*-------------------------------------------------------------------------*\
274 * Puts the sockt in listen mode
275 \*-------------------------------------------------------------------------*/
meth_listen(lua_State * L)276 static int meth_listen(lua_State *L)
277 {
278     p_unix un = (p_unix) auxiliar_checkclass(L, "unix{master}", 1);
279     int backlog = (int) luaL_optnumber(L, 2, 32);
280     int err = socket_listen(&un->sock, backlog);
281     if (err != IO_DONE) {
282         lua_pushnil(L);
283         lua_pushstring(L, socket_strerror(err));
284         return 2;
285     }
286     /* turn master object into a server object */
287     auxiliar_setclass(L, "unix{server}", 1);
288     lua_pushnumber(L, 1);
289     return 1;
290 }
291 
292 /*-------------------------------------------------------------------------*\
293 * Shuts the connection down partially
294 \*-------------------------------------------------------------------------*/
meth_shutdown(lua_State * L)295 static int meth_shutdown(lua_State *L)
296 {
297     p_unix un = (p_unix) auxiliar_checkclass(L, "unix{client}", 1);
298     const char *how = luaL_optstring(L, 2, "both");
299     switch (how[0]) {
300         case 'b':
301             if (strcmp(how, "both")) goto error;
302             socket_shutdown(&un->sock, 2);
303             break;
304         case 's':
305             if (strcmp(how, "send")) goto error;
306             socket_shutdown(&un->sock, 1);
307             break;
308         case 'r':
309             if (strcmp(how, "receive")) goto error;
310             socket_shutdown(&un->sock, 0);
311             break;
312     }
313     lua_pushnumber(L, 1);
314     return 1;
315 error:
316     luaL_argerror(L, 2, "invalid shutdown method");
317     return 0;
318 }
319 
320 /*-------------------------------------------------------------------------*\
321 * Just call tm methods
322 \*-------------------------------------------------------------------------*/
meth_settimeout(lua_State * L)323 static int meth_settimeout(lua_State *L) {
324     p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
325     return timeout_meth_settimeout(L, &un->tm);
326 }
327 
328 /*=========================================================================*\
329 * Library functions
330 \*=========================================================================*/
331 /*-------------------------------------------------------------------------*\
332 * Creates a master unix object
333 \*-------------------------------------------------------------------------*/
global_create(lua_State * L)334 static int global_create(lua_State *L) {
335     t_socket sock;
336     int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
337     /* try to allocate a system socket */
338     if (err == IO_DONE) {
339         /* allocate unix object */
340         p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
341         /* set its type as master object */
342         auxiliar_setclass(L, "unix{master}", -1);
343         /* initialize remaining structure fields */
344         socket_setnonblocking(&sock);
345         un->sock = sock;
346         io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
347                 (p_error) socket_ioerror, &un->sock);
348         timeout_init(&un->tm, -1, -1);
349         buffer_init(&un->buf, &un->io, &un->tm);
350         return 1;
351     } else {
352         lua_pushnil(L);
353         lua_pushstring(L, socket_strerror(err));
354         return 2;
355     }
356 }
357