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