]> jfr.im git - irc/quakenet/newserv.git/blame - lua/luasocket.c
Merge.
[irc/quakenet/newserv.git] / lua / luasocket.c
CommitLineData
065c0091
CP
1/* Copyright (C) Chris Porter 2007 */
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <sys/poll.h>
6#include <netinet/in.h>
7#include <sys/socket.h>
8#include <sys/un.h>
9#include <errno.h>
5d59fe79 10#include <fcntl.h>
065c0091
CP
11#include "../lib/strlfunc.h"
12#include "../core/events.h"
13
14#include "lua.h"
15#include "luabot.h"
16
9a2954da 17#define lua_vnpcall(F2, N2, S2, ...) _lua_vpcall(F2->l->l, (void *)F2->handler, LUA_POINTERMODE, "lsR" S2 , F2->identifier, N2, F2->tag , ##__VA_ARGS__)
065c0091
CP
18
19/*
20 * instead of these identifiers I could just use the file descriptor...
21 * BUT I can't remember the exact semantics of the fd table WRT reuse...
22 */
23static long nextidentifier = 0;
5d59fe79 24static void lua_socket_poll_event(int fd, short events);
065c0091 25
60aab72f
CP
26static int getunixsocket(char *path, struct sockaddr_un *r) {
27 int fd = socket(AF_UNIX, SOCK_STREAM, 0);
28 int ret;
29
30 if(fd <= -1)
31 return -1;
32
33 memset(r, 0, sizeof(struct sockaddr_un));
34 r->sun_family = AF_UNIX;
35 strlcpy(r->sun_path, path, sizeof(r->sun_path));
36
37 /* WTB exceptions */
38 ret = fcntl(fd, F_GETFL, 0);
39 if(ret < 0) {
40 close(fd);
41 return -1;
42 }
43
44 ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
45 if(ret < 0) {
46 close(fd);
47 return -1;
48 }
49
50 return fd;
51}
52
53static void registerluasocket(lua_list *ll, lua_socket *ls, int mask, int settag) {
54 /* this whole identifier thing should probably use userdata stuff */
55 ls->identifier = nextidentifier++;
56
57 if(settag) {
58 ls->tag = luaL_ref(ll->l, LUA_REGISTRYINDEX);
59 ls->handler = luaL_ref(ll->l, LUA_REGISTRYINDEX);
60 }
61 ls->l = ll;
62
63 ls->next = ll->sockets;
64 ll->sockets = ls;
65
66 registerhandler(ls->fd, mask, lua_socket_poll_event);
67}
68
065c0091 69static int lua_socket_unix_connect(lua_State *l) {
60aab72f 70 int ret;
065c0091
CP
71 struct sockaddr_un r;
72 char *path;
73 lua_socket *ls;
74 lua_list *ll;
75
76 ll = lua_listfromstate(l);
77 if(!ll)
78 return 0;
79
9a2954da
CP
80 if(!lua_isfunction(l, 2))
81 return 0;
82
065c0091
CP
83 path = (char *)lua_tostring(l, 1);
84 if(!path)
85 return 0;
86
d0e17ef9 87 ls = (lua_socket *)luamalloc(sizeof(lua_socket));
065c0091
CP
88 if(!ls)
89 return 0;
90
60aab72f
CP
91 ls->fd = getunixsocket(path, &r);
92 if(ls->fd < 0) {
d0e17ef9 93 luafree(ls);
065c0091
CP
94 return 0;
95 }
96
60aab72f
CP
97 ret = connect(ls->fd, (struct sockaddr *)&r, sizeof(r.sun_family) + strlen(r.sun_path));
98 if(ret == 0) {
99 ls->state = SOCKET_CONNECTED;
100 } else if(ret == -1 && (errno == EINPROGRESS)) {
101 ls->state = SOCKET_CONNECTING;
102 } else {
d0e17ef9 103 luafree(ls);
065c0091
CP
104 close(ls->fd);
105 return 0;
106 }
107
60aab72f
CP
108 ls->parent = NULL;
109 registerluasocket(ll, ls, (ls->state==SOCKET_CONNECTED?POLLIN:POLLOUT) | POLLERR | POLLHUP, 1);
110
111 lua_pushboolean(l, ls->state==SOCKET_CONNECTED?1:0);
112 lua_pushlong(l, ls->identifier);
113 return 2;
114}
115
116static int lua_socket_unix_bind(lua_State *l) {
117 lua_list *ll;
118 char *path;
119 lua_socket *ls;
120 struct sockaddr_un r;
121
122 ll = lua_listfromstate(l);
123 if(!ll)
5d59fe79 124 return 0;
5d59fe79 125
60aab72f
CP
126 if(!lua_isfunction(l, 2))
127 return 0;
128
129 path = (char *)lua_tostring(l, 1);
130 if(!path)
131 return 0;
132
133 ls = (lua_socket *)luamalloc(sizeof(lua_socket));
134 if(!ls)
135 return 0;
136
137 ls->fd = getunixsocket(path, &r);
138 if(ls->fd <= -1) {
d0e17ef9 139 luafree(ls);
5d59fe79
CP
140 return 0;
141 }
142
60aab72f 143 unlink(path);
9a2954da 144
60aab72f
CP
145 if(
146 (bind(ls->fd, (struct sockaddr *)&r, strlen(r.sun_path) + sizeof(r.sun_family)) == -1) ||
147 (listen(ls->fd, 5) == -1)
148 ) {
149 close(ls->fd);
150 luafree(ls);
151 return 0;
152 }
065c0091 153
60aab72f
CP
154 ls->state = SOCKET_LISTENING;
155 ls->parent = NULL;
065c0091 156
60aab72f 157 registerluasocket(ll, ls, POLLIN, 1);
065c0091
CP
158
159 lua_pushlong(l, ls->identifier);
60aab72f 160 return 1;
065c0091
CP
161}
162
5d59fe79 163static lua_socket *socketbyfd(int fd) {
065c0091
CP
164 lua_list *l;
165 lua_socket *ls;
166
167 for(l=lua_head;l;l=l->next)
168 for(ls=l->sockets;ls;ls=ls->next)
169 if(ls->fd == fd)
170 return ls;
171
172 return NULL;
173}
174
5d59fe79 175static lua_socket *socketbyidentifier(long identifier) {
065c0091
CP
176 lua_list *l;
177 lua_socket *ls;
178
179 for(l=lua_head;l;l=l->next)
180 for(ls=l->sockets;ls;ls=ls->next)
181 if(ls->identifier == identifier)
182 return ls;
183
184 return NULL;
185}
186
5d59fe79 187static void lua_socket_call_close(lua_socket *ls) {
065c0091
CP
188 lua_socket *p, *c;
189
60aab72f
CP
190 for(c=ls->l->sockets;c;c=p) {
191 p = c->next;
192 if(c->parent == ls)
193 lua_socket_call_close(c);
194 }
195
065c0091
CP
196 for(c=ls->l->sockets,p=NULL;c;p=c,c=c->next) {
197 if(c == ls) {
5d59fe79
CP
198 if(ls->state == SOCKET_CLOSED)
199 return;
200
201 ls->state = SOCKET_CLOSED;
065c0091
CP
202 deregisterhandler(ls->fd, 1);
203
204 lua_vnpcall(ls, "close", "");
205
206 if(!p) {
207 ls->l->sockets = ls->next;
208 } else {
209 p->next = ls->next;
210 }
211
60aab72f
CP
212 if(!ls->parent) {
213 luaL_unref(ls->l->l, LUA_REGISTRYINDEX, ls->tag);
214 luaL_unref(ls->l->l, LUA_REGISTRYINDEX, ls->handler);
215 }
065c0091 216
d0e17ef9 217 luafree(ls);
065c0091
CP
218 return;
219 }
220 }
065c0091
CP
221}
222
223static int lua_socket_write(lua_State *l) {
224 char *buf;
225 long len;
226 lua_socket *ls;
227 int ret;
228
065c0091 229 buf = (char *)lua_tostring(l, 2);
065c0091 230
5d59fe79
CP
231 if(!lua_islong(l, 1) || !buf) {
232 lua_pushint(l, -1);
233 return 1;
234 }
065c0091
CP
235 len = lua_strlen(l, 2);
236
237 ls = socketbyidentifier(lua_tolong(l, 1));
5d59fe79 238 if(!ls || (ls->state != SOCKET_CONNECTED)) {
065c0091
CP
239 lua_pushint(l, -1);
240 return 1;
241 }
242
5d59fe79
CP
243 ret = write(ls->fd, buf, len);
244 if(ret == -1 && (errno == EAGAIN)) {
245 deregisterhandler(ls->fd, 0);
246 registerhandler(ls->fd, POLLIN | POLLOUT | POLLERR | POLLHUP, lua_socket_poll_event);
9a2954da
CP
247
248 lua_pushint(l, 0);
249 return 1;
5d59fe79
CP
250 }
251
252 if(ret == -1)
253 lua_socket_call_close(ls);
254
9a2954da
CP
255 if(ret < len) {
256 deregisterhandler(ls->fd, 0);
257 registerhandler(ls->fd, POLLIN | POLLOUT | POLLERR | POLLHUP, lua_socket_poll_event);
258 }
259
5d59fe79 260 lua_pushint(l, ret);
065c0091
CP
261 return 1;
262}
263
264static int lua_socket_close(lua_State *l) {
265 lua_socket *ls;
266
267 if(!lua_islong(l, 1))
268 LUA_RETURN(l, LUA_FAIL);
269
270 ls = socketbyidentifier(lua_tolong(l, 1));
5d59fe79 271 if(!ls || (ls->state == SOCKET_CLOSED))
065c0091
CP
272 LUA_RETURN(l, LUA_FAIL);
273
274 lua_socket_call_close(ls);
275
276 LUA_RETURN(l, LUA_OK);
277}
278
5d59fe79 279static void lua_socket_poll_event(int fd, short events) {
065c0091 280 lua_socket *ls = socketbyfd(fd);
5d59fe79 281 if(!ls || (ls->state == SOCKET_CLOSED))
065c0091
CP
282 return;
283
284 if(events & (POLLERR | POLLHUP)) {
285 lua_socket_call_close(ls);
286 return;
287 }
065c0091 288
5d59fe79
CP
289 switch(ls->state) {
290 case SOCKET_CONNECTING:
291 if(events & POLLOUT) {
292 deregisterhandler(fd, 0);
293 registerhandler(fd, POLLIN | POLLERR | POLLHUP, lua_socket_poll_event);
294 ls->state = SOCKET_CONNECTED;
065c0091 295
5d59fe79
CP
296 lua_vnpcall(ls, "connect", "");
297 }
298 break;
299 case SOCKET_CONNECTED:
300 if(events & POLLOUT) {
301 deregisterhandler(fd, 0);
302 registerhandler(fd, POLLIN | POLLERR | POLLHUP, lua_socket_poll_event);
065c0091 303
5d59fe79
CP
304 lua_vnpcall(ls, "flush", "");
305 }
306 if(events & POLLIN) {
307 char buf[8192 * 2];
308 int bytesread;
309
310 bytesread = read(fd, buf, sizeof(buf));
311 if((bytesread == -1) && (errno == EAGAIN))
312 return;
313
314 if(bytesread <= 0) {
315 lua_socket_call_close(ls);
316 return;
317 }
318
77762537 319 lua_vnpcall(ls, "read", "L", buf, (long)bytesread);
5d59fe79
CP
320 }
321 break;
60aab72f
CP
322 case SOCKET_LISTENING:
323 if(events & POLLIN) {
324 struct sockaddr_un r;
325 lua_socket *ls2;
326 unsigned int len = sizeof(r);
327
328 int fd2 = accept(fd, (struct sockaddr *)&r, &len);
329 if(fd2 == -1)
330 return;
331
332 ls2 = (lua_socket *)luamalloc(sizeof(lua_socket));
333 if(!ls2) {
334 close(fd2);
335 return;
336 }
337
338 ls2->fd = fd2;
339 ls2->state = SOCKET_CONNECTED;
340 ls2->tag = ls->tag;
341 ls2->handler = ls->handler;
342 ls2->parent = ls;
343
344 registerluasocket(ls->l, ls2, POLLIN | POLLERR | POLLHUP, 0);
345 lua_vnpcall(ls, "accept", "l", ls2->identifier);
346 }
347 break;
065c0091
CP
348 }
349}
350
351void lua_socket_closeall(lua_list *l) {
352 while(l->sockets)
353 lua_socket_call_close(l->sockets);
354}
355
c7ec7d64 356void lua_registersocketcommands(lua_State *l) {
065c0091 357 lua_register(l, "socket_unix_connect", lua_socket_unix_connect);
60aab72f 358 lua_register(l, "socket_unix_bind", lua_socket_unix_bind);
065c0091
CP
359 lua_register(l, "socket_close", lua_socket_close);
360 lua_register(l, "socket_write", lua_socket_write);
361}