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