aboutsummaryrefslogtreecommitdiff
path: root/src/unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/unix.c')
-rw-r--r--src/unix.c324
1 files changed, 324 insertions, 0 deletions
diff --git a/src/unix.c b/src/unix.c
new file mode 100644
index 0000000..b2c4659
--- /dev/null
+++ b/src/unix.c
@@ -0,0 +1,324 @@
1/*=========================================================================*\
2* Unix domain socket
3* LuaSocket toolkit
4*
5* RCS ID: $Id$
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\*=========================================================================*/
21static int global_create(lua_State *L);
22static int meth_connect(lua_State *L);
23static int meth_listen(lua_State *L);
24static int meth_bind(lua_State *L);
25static int meth_send(lua_State *L);
26static int meth_shutdown(lua_State *L);
27static int meth_receive(lua_State *L);
28static int meth_accept(lua_State *L);
29static int meth_close(lua_State *L);
30static int meth_setoption(lua_State *L);
31static int meth_settimeout(lua_State *L);
32static int meth_getfd(lua_State *L);
33static int meth_setfd(lua_State *L);
34static int meth_dirty(lua_State *L);
35
36static const char *unix_tryconnect(p_unix unix, const char *path);
37static const char *unix_trybind(p_unix unix, const char *path);
38
39/* unix object methods */
40static luaL_reg unix[] = {
41 {"__gc", meth_close},
42 {"__tostring", aux_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 {"listen", meth_listen},
50 {"receive", meth_receive},
51 {"send", meth_send},
52 {"setfd", meth_setfd},
53 {"setoption", meth_setoption},
54 {"setpeername", meth_connect},
55 {"setsockname", meth_bind},
56 {"settimeout", meth_settimeout},
57 {"shutdown", meth_shutdown},
58 {NULL, NULL}
59};
60
61/* socket option handlers */
62static t_opt opt[] = {
63 {"keepalive", opt_keepalive},
64 {"reuseaddr", opt_reuseaddr},
65 {"linger", opt_linger},
66 {NULL, NULL}
67};
68
69/* functions in library namespace */
70static luaL_reg func[] = {
71 {"unix", global_create},
72 {NULL, NULL}
73};
74
75/*-------------------------------------------------------------------------*\
76* Initializes module
77\*-------------------------------------------------------------------------*/
78int unix_open(lua_State *L) {
79 /* create classes */
80 aux_newclass(L, "unix{master}", unix);
81 aux_newclass(L, "unix{client}", unix);
82 aux_newclass(L, "unix{server}", unix);
83 /* create class groups */
84 aux_add2group(L, "unix{master}", "unix{any}");
85 aux_add2group(L, "unix{client}", "unix{any}");
86 aux_add2group(L, "unix{server}", "unix{any}");
87 aux_add2group(L, "unix{client}", "unix{client,server}");
88 aux_add2group(L, "unix{server}", "unix{client,server}");
89 /* define library functions */
90 luaL_openlib(L, NULL, func, 0);
91 return 0;
92}
93
94/*=========================================================================*\
95* Lua methods
96\*=========================================================================*/
97/*-------------------------------------------------------------------------*\
98* Just call buffered IO methods
99\*-------------------------------------------------------------------------*/
100static int meth_send(lua_State *L) {
101 p_unix unix = (p_unix) aux_checkclass(L, "unix{client}", 1);
102 return buf_meth_send(L, &unix->buf);
103}
104
105static int meth_receive(lua_State *L) {
106 p_unix unix = (p_unix) aux_checkclass(L, "unix{client}", 1);
107 return buf_meth_receive(L, &unix->buf);
108}
109
110/*-------------------------------------------------------------------------*\
111* Just call option handler
112\*-------------------------------------------------------------------------*/
113static int meth_setoption(lua_State *L) {
114 p_unix unix = aux_checkgroup(L, "unix{any}", 1);
115 return opt_meth_setoption(L, opt, &unix->sock);
116}
117
118/*-------------------------------------------------------------------------*\
119* Select support methods
120\*-------------------------------------------------------------------------*/
121static int meth_getfd(lua_State *L) {
122 p_unix unix = (p_unix) aux_checkgroup(L, "unix{any}", 1);
123 lua_pushnumber(L, (int) unix->sock);
124 return 1;
125}
126
127/* this is very dangerous, but can be handy for those that are brave enough */
128static int meth_setfd(lua_State *L) {
129 p_unix unix = (p_unix) aux_checkgroup(L, "unix{any}", 1);
130 unix->sock = (t_sock) luaL_checknumber(L, 2);
131 return 0;
132}
133
134static int meth_dirty(lua_State *L) {
135 p_unix unix = (p_unix) aux_checkgroup(L, "unix{any}", 1);
136 lua_pushboolean(L, !buf_isempty(&unix->buf));
137 return 1;
138}
139
140/*-------------------------------------------------------------------------*\
141* Waits for and returns a client object attempting connection to the
142* server object
143\*-------------------------------------------------------------------------*/
144static int meth_accept(lua_State *L) {
145 p_unix server = (p_unix) aux_checkclass(L, "unix{server}", 1);
146 p_tm tm = tm_markstart(&server->tm);
147 t_sock sock;
148 const char *err = sock_accept(&server->sock, &sock, NULL, NULL, tm);
149 /* if successful, push client socket */
150 if (!err) {
151 p_unix clnt = lua_newuserdata(L, sizeof(t_unix));
152 aux_setclass(L, "unix{client}", -1);
153 /* initialize structure fields */
154 sock_setnonblocking(&sock);
155 clnt->sock = sock;
156 io_init(&clnt->io, (p_send)sock_send, (p_recv)sock_recv, &clnt->sock);
157 tm_init(&clnt->tm, -1, -1);
158 buf_init(&clnt->buf, &clnt->io, &clnt->tm);
159 return 1;
160 } else {
161 lua_pushnil(L);
162 lua_pushstring(L, err);
163 return 2;
164 }
165}
166
167/*-------------------------------------------------------------------------*\
168* Binds an object to an address
169\*-------------------------------------------------------------------------*/
170static const char *unix_trybind(p_unix unix, const char *path) {
171 struct sockaddr_un local;
172 int len = strlen(path);
173 const char *err;
174 if (len >= 92) return "path too long";
175 memset(&local, 0, sizeof(local));
176 strcpy(local.sun_path, path);
177 local.sun_family = AF_UNIX;
178 err = sock_bind(&unix->sock, (SA *) &local,
179 sizeof(local.sun_family) + len);
180 if (err) sock_destroy(&unix->sock);
181 return err;
182}
183
184static int meth_bind(lua_State *L) {
185 p_unix unix = (p_unix) aux_checkclass(L, "unix{master}", 1);
186 const char *path = luaL_checkstring(L, 2);
187 const char *err = unix_trybind(unix, path);
188 if (err) {
189 lua_pushnil(L);
190 lua_pushstring(L, err);
191 return 2;
192 }
193 lua_pushnumber(L, 1);
194 return 1;
195}
196
197/*-------------------------------------------------------------------------*\
198* Turns a master unix object into a client object.
199\*-------------------------------------------------------------------------*/
200static const char *unix_tryconnect(p_unix unix, const char *path)
201{
202 struct sockaddr_un remote;
203 const char *err;
204 int len = strlen(path);
205 if (len >= 92) return "path too long";
206 memset(&remote, 0, sizeof(remote));
207 strcpy(remote.sun_path, path);
208 remote.sun_family = AF_UNIX;
209 tm_markstart(&unix->tm);
210 err = sock_connect(&unix->sock, (SA *) &remote,
211 sizeof(remote.sun_family) + len, &unix->tm);
212 if (err) sock_destroy(&unix->sock);
213 return err;
214}
215
216static int meth_connect(lua_State *L)
217{
218 p_unix unix = (p_unix) aux_checkclass(L, "unix{master}", 1);
219 const char *path = luaL_checkstring(L, 2);
220 const char *err = unix_tryconnect(unix, path);
221 if (err) {
222 lua_pushnil(L);
223 lua_pushstring(L, err);
224 return 2;
225 }
226 /* turn master object into a client object */
227 aux_setclass(L, "unix{client}", 1);
228 lua_pushnumber(L, 1);
229 return 1;
230}
231
232/*-------------------------------------------------------------------------*\
233* Closes socket used by object
234\*-------------------------------------------------------------------------*/
235static int meth_close(lua_State *L)
236{
237 p_unix unix = (p_unix) aux_checkgroup(L, "unix{any}", 1);
238 sock_destroy(&unix->sock);
239 return 0;
240}
241
242/*-------------------------------------------------------------------------*\
243* Puts the sockt in listen mode
244\*-------------------------------------------------------------------------*/
245static int meth_listen(lua_State *L)
246{
247 p_unix unix = (p_unix) aux_checkclass(L, "unix{master}", 1);
248 int backlog = (int) luaL_optnumber(L, 2, 32);
249 const char *err = sock_listen(&unix->sock, backlog);
250 if (err) {
251 lua_pushnil(L);
252 lua_pushstring(L, err);
253 return 2;
254 }
255 /* turn master object into a server object */
256 aux_setclass(L, "unix{server}", 1);
257 lua_pushnumber(L, 1);
258 return 1;
259}
260
261/*-------------------------------------------------------------------------*\
262* Shuts the connection down partially
263\*-------------------------------------------------------------------------*/
264static int meth_shutdown(lua_State *L)
265{
266 p_unix unix = (p_unix) aux_checkgroup(L, "unix{client}", 1);
267 const char *how = luaL_optstring(L, 2, "both");
268 switch (how[0]) {
269 case 'b':
270 if (strcmp(how, "both")) goto error;
271 sock_shutdown(&unix->sock, 2);
272 break;
273 case 's':
274 if (strcmp(how, "send")) goto error;
275 sock_shutdown(&unix->sock, 1);
276 break;
277 case 'r':
278 if (strcmp(how, "receive")) goto error;
279 sock_shutdown(&unix->sock, 0);
280 break;
281 }
282 lua_pushnumber(L, 1);
283 return 1;
284error:
285 luaL_argerror(L, 2, "invalid shutdown method");
286 return 0;
287}
288
289/*-------------------------------------------------------------------------*\
290* Just call tm methods
291\*-------------------------------------------------------------------------*/
292static int meth_settimeout(lua_State *L) {
293 p_unix unix = (p_unix) aux_checkgroup(L, "unix{any}", 1);
294 return tm_meth_settimeout(L, &unix->tm);
295}
296
297/*=========================================================================*\
298* Library functions
299\*=========================================================================*/
300/*-------------------------------------------------------------------------*\
301* Creates a master unix object
302\*-------------------------------------------------------------------------*/
303static int global_create(lua_State *L) {
304 t_sock sock;
305 const char *err = sock_create(&sock, AF_UNIX, SOCK_STREAM, 0);
306 /* try to allocate a system socket */
307 if (!err) {
308 /* allocate unix object */
309 p_unix unix = (p_unix) lua_newuserdata(L, sizeof(t_unix));
310 /* set its type as master object */
311 aux_setclass(L, "unix{master}", -1);
312 /* initialize remaining structure fields */
313 sock_setnonblocking(&sock);
314 unix->sock = sock;
315 io_init(&unix->io, (p_send) sock_send, (p_recv) sock_recv, &unix->sock);
316 tm_init(&unix->tm, -1, -1);
317 buf_init(&unix->buf, &unix->io, &unix->tm);
318 return 1;
319 } else {
320 lua_pushnil(L);
321 lua_pushstring(L, err);
322 return 2;
323 }
324}