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