]> jfr.im git - irc/quakenet/newserv.git/blame - lua/luasocket.c
LUA: port luadb to dbapi2 to drop postgres dependency
[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>
839f8d67 5#include <sys/types.h>
065c0091 6#include <sys/socket.h>
839f8d67
CP
7#include <netinet/in.h>
8
0555113a 9#ifndef __USE_MISC
839f8d67 10#define __USE_MISC /* inet_aton */
0555113a 11#endif
839f8d67
CP
12
13#include <arpa/inet.h>
065c0091 14#include <sys/un.h>
839f8d67 15#include <sys/poll.h>
065c0091 16#include <errno.h>
5d59fe79 17#include <fcntl.h>
065c0091
CP
18#include "../lib/strlfunc.h"
19#include "../core/events.h"
20
21#include "lua.h"
22#include "luabot.h"
23
9a2954da 24#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
25
26/*
27 * instead of these identifiers I could just use the file descriptor...
28 * BUT I can't remember the exact semantics of the fd table WRT reuse...
29 */
30static long nextidentifier = 0;
5d59fe79 31static void lua_socket_poll_event(int fd, short events);
065c0091 32
839f8d67 33static int setnonblock(int fd) {
60aab72f
CP
34 int ret;
35
60aab72f
CP
36 /* WTB exceptions */
37 ret = fcntl(fd, F_GETFL, 0);
38 if(ret < 0) {
39 close(fd);
40 return -1;
41 }
42
43 ret = fcntl(fd, F_SETFL, ret | O_NONBLOCK);
44 if(ret < 0) {
45 close(fd);
46 return -1;
47 }
48
49 return fd;
50}
839f8d67
CP
51static int getunixsocket(char *path, struct sockaddr_un *r) {
52 int fd = socket(AF_UNIX, SOCK_STREAM, 0);
53
54 if(fd <= -1)
55 return -1;
56
57 memset(r, 0, sizeof(struct sockaddr_un));
58 r->sun_family = PF_UNIX;
59 strlcpy(r->sun_path, path, sizeof(r->sun_path));
60
61 return setnonblock(fd);
62}
63
64/* note ADDRESS not HOSTNAME */
65static int getipsocket(char *address, int port, int protocol, struct sockaddr_in *r) {
66 int fd;
67 int val = 1;
68
69 memset(r, 0, sizeof(struct sockaddr_in));
70 r->sin_family = PF_INET;
71
72 if(address) {
73 if(!inet_aton(address, &r->sin_addr)) {
74 Error("lua", ERR_ERROR, "Could not parse address: %s", address);
75 return -1;
76 }
77 } else {
78 address = INADDR_ANY;
79 }
80
81 fd = socket(AF_INET, protocol, 0);
82
83 if(fd <= -1)
84 return -1;
85
86 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
87
88 r->sin_port = htons(port);
89 return setnonblock(fd);
90}
60aab72f
CP
91
92static void registerluasocket(lua_list *ll, lua_socket *ls, int mask, int settag) {
93 /* this whole identifier thing should probably use userdata stuff */
94 ls->identifier = nextidentifier++;
95
96 if(settag) {
97 ls->tag = luaL_ref(ll->l, LUA_REGISTRYINDEX);
98 ls->handler = luaL_ref(ll->l, LUA_REGISTRYINDEX);
99 }
100 ls->l = ll;
101
102 ls->next = ll->sockets;
103 ll->sockets = ls;
104
105 registerhandler(ls->fd, mask, lua_socket_poll_event);
106}
107
839f8d67
CP
108static int handleconnect(int ret, lua_State *l, lua_list *ll, lua_socket *ls) {
109 if(ret == 0) {
110 ls->state = SOCKET_CONNECTED;
111 } else if(ret == -1 && (errno == EINPROGRESS)) {
112 ls->state = SOCKET_CONNECTING;
113 } else {
114 luafree(ls);
115 close(ls->fd);
116 return 0;
117 }
118
119 ls->parent = NULL;
120 registerluasocket(ll, ls, (ls->state==SOCKET_CONNECTED?POLLIN:POLLOUT) | POLLERR | POLLHUP, 1);
121
122 lua_pushboolean(l, ls->state==SOCKET_CONNECTED?1:0);
123 lua_pushlong(l, ls->identifier);
124 return 2;
125}
126
065c0091 127static int lua_socket_unix_connect(lua_State *l) {
60aab72f 128 int ret;
065c0091
CP
129 struct sockaddr_un r;
130 char *path;
131 lua_socket *ls;
132 lua_list *ll;
133
134 ll = lua_listfromstate(l);
135 if(!ll)
136 return 0;
137
9a2954da
CP
138 if(!lua_isfunction(l, 2))
139 return 0;
140
065c0091
CP
141 path = (char *)lua_tostring(l, 1);
142 if(!path)
143 return 0;
144
d0e17ef9 145 ls = (lua_socket *)luamalloc(sizeof(lua_socket));
065c0091
CP
146 if(!ls)
147 return 0;
148
839f8d67 149 ls->sockettype = PF_UNIX;
60aab72f
CP
150 ls->fd = getunixsocket(path, &r);
151 if(ls->fd < 0) {
d0e17ef9 152 luafree(ls);
065c0091
CP
153 return 0;
154 }
155
60aab72f 156 ret = connect(ls->fd, (struct sockaddr *)&r, sizeof(r.sun_family) + strlen(r.sun_path));
839f8d67 157 return handleconnect(ret, l, ll, ls);
60aab72f
CP
158}
159
160static int lua_socket_unix_bind(lua_State *l) {
161 lua_list *ll;
162 char *path;
163 lua_socket *ls;
164 struct sockaddr_un r;
165
166 ll = lua_listfromstate(l);
167 if(!ll)
5d59fe79 168 return 0;
5d59fe79 169
60aab72f
CP
170 if(!lua_isfunction(l, 2))
171 return 0;
172
173 path = (char *)lua_tostring(l, 1);
174 if(!path)
175 return 0;
176
177 ls = (lua_socket *)luamalloc(sizeof(lua_socket));
178 if(!ls)
179 return 0;
180
839f8d67 181 ls->sockettype = PF_UNIX;
60aab72f
CP
182 ls->fd = getunixsocket(path, &r);
183 if(ls->fd <= -1) {
d0e17ef9 184 luafree(ls);
5d59fe79
CP
185 return 0;
186 }
187
60aab72f 188 unlink(path);
9a2954da 189
60aab72f
CP
190 if(
191 (bind(ls->fd, (struct sockaddr *)&r, strlen(r.sun_path) + sizeof(r.sun_family)) == -1) ||
192 (listen(ls->fd, 5) == -1)
193 ) {
194 close(ls->fd);
195 luafree(ls);
196 return 0;
197 }
065c0091 198
60aab72f
CP
199 ls->state = SOCKET_LISTENING;
200 ls->parent = NULL;
065c0091 201
60aab72f 202 registerluasocket(ll, ls, POLLIN, 1);
065c0091
CP
203
204 lua_pushlong(l, ls->identifier);
60aab72f 205 return 1;
065c0091
CP
206}
207
839f8d67
CP
208static int lua_socket_ip_connect(lua_State *l, int protocol) {
209 int ret;
210 struct sockaddr_in r;
211 char *address;
212 int port;
213 lua_socket *ls;
214 lua_list *ll;
215
216 ll = lua_listfromstate(l);
217 if(!ll)
218 return 0;
219
220 if(!lua_isfunction(l, 3) || !lua_islong(l, 2))
221 return 0;
222
223 address = (char *)lua_tostring(l, 1);
224 if(!address)
225 return 0;
226
227 port = lua_tolong(l, 2);
228
229 ls = (lua_socket *)luamalloc(sizeof(lua_socket));
230 if(!ls)
231 return 0;
232
233 ls->sockettype = PF_INET;
234 ls->fd = getipsocket(address, port, protocol, &r);
235 if(ls->fd < 0) {
236 luafree(ls);
237 return 0;
238 }
239
240 ret = connect(ls->fd, (struct sockaddr *)&r, sizeof(struct sockaddr_in));
241 return handleconnect(ret, l, ll, ls);
242}
243
244static int lua_socket_ip_bind(lua_State *l, int protocol) {
245 lua_list *ll;
246 char *address;
247 int port;
248 lua_socket *ls;
249 struct sockaddr_in r;
250
251 ll = lua_listfromstate(l);
252 if(!ll)
253 return 0;
254
255 if(!lua_isfunction(l, 3) || !lua_islong(l, 2))
256 return 0;
257
258 /* address can be nil or a string */
259 if(!lua_isnil(l, 1) && !lua_isstring(l, 1))
260 return 0;
261
262 address = (char *)lua_tostring(l, 1);
263 port = lua_tolong(l, 2);
264
265 ls = (lua_socket *)luamalloc(sizeof(lua_socket));
266 if(!ls)
267 return 0;
268
269 ls->sockettype = PF_INET;
270 ls->fd = getipsocket(address, port, protocol, &r);
271 if(ls->fd <= -1) {
272 luafree(ls);
273 return 0;
274 }
275
276 if(
277 (bind(ls->fd, (struct sockaddr *)&r, sizeof(struct sockaddr_in)) == -1) ||
278 (listen(ls->fd, 5) == -1)
279 ) {
280 close(ls->fd);
281 luafree(ls);
282 return 0;
283 }
284
285 ls->state = SOCKET_LISTENING;
286 ls->parent = NULL;
287
288 registerluasocket(ll, ls, POLLIN, 1);
289
290 lua_pushlong(l, ls->identifier);
291 return 1;
292}
293
294static int lua_socket_tcp_connect(lua_State *l) {
295 return lua_socket_ip_connect(l, SOCK_STREAM);
296}
297
298static int lua_socket_tcp_bind(lua_State *l) {
299 return lua_socket_ip_bind(l, SOCK_STREAM);
300}
301
302static int lua_socket_udp_connect(lua_State *l) {
303 return lua_socket_ip_connect(l, SOCK_DGRAM);
304}
305
306static int lua_socket_udp_bind(lua_State *l) {
307 return lua_socket_ip_bind(l, SOCK_DGRAM);
308}
309
5d59fe79 310static lua_socket *socketbyfd(int fd) {
065c0091
CP
311 lua_list *l;
312 lua_socket *ls;
313
314 for(l=lua_head;l;l=l->next)
315 for(ls=l->sockets;ls;ls=ls->next)
316 if(ls->fd == fd)
317 return ls;
318
319 return NULL;
320}
321
5d59fe79 322static lua_socket *socketbyidentifier(long identifier) {
065c0091
CP
323 lua_list *l;
324 lua_socket *ls;
325
326 for(l=lua_head;l;l=l->next)
327 for(ls=l->sockets;ls;ls=ls->next)
328 if(ls->identifier == identifier)
329 return ls;
330
331 return NULL;
332}
333
5d59fe79 334static void lua_socket_call_close(lua_socket *ls) {
065c0091
CP
335 lua_socket *p, *c;
336
60aab72f
CP
337 for(c=ls->l->sockets;c;c=p) {
338 p = c->next;
339 if(c->parent == ls)
340 lua_socket_call_close(c);
341 }
342
065c0091
CP
343 for(c=ls->l->sockets,p=NULL;c;p=c,c=c->next) {
344 if(c == ls) {
5d59fe79
CP
345 if(ls->state == SOCKET_CLOSED)
346 return;
347
348 ls->state = SOCKET_CLOSED;
065c0091
CP
349 deregisterhandler(ls->fd, 1);
350
351 lua_vnpcall(ls, "close", "");
352
353 if(!p) {
354 ls->l->sockets = ls->next;
355 } else {
356 p->next = ls->next;
357 }
358
60aab72f
CP
359 if(!ls->parent) {
360 luaL_unref(ls->l->l, LUA_REGISTRYINDEX, ls->tag);
361 luaL_unref(ls->l->l, LUA_REGISTRYINDEX, ls->handler);
362 }
065c0091 363
d0e17ef9 364 luafree(ls);
065c0091
CP
365 return;
366 }
367 }
065c0091
CP
368}
369
370static int lua_socket_write(lua_State *l) {
371 char *buf;
372 long len;
373 lua_socket *ls;
374 int ret;
375
065c0091 376 buf = (char *)lua_tostring(l, 2);
065c0091 377
5d59fe79
CP
378 if(!lua_islong(l, 1) || !buf) {
379 lua_pushint(l, -1);
380 return 1;
381 }
065c0091
CP
382 len = lua_strlen(l, 2);
383
384 ls = socketbyidentifier(lua_tolong(l, 1));
5d59fe79 385 if(!ls || (ls->state != SOCKET_CONNECTED)) {
065c0091
CP
386 lua_pushint(l, -1);
387 return 1;
388 }
389
5d59fe79
CP
390 ret = write(ls->fd, buf, len);
391 if(ret == -1 && (errno == EAGAIN)) {
392 deregisterhandler(ls->fd, 0);
393 registerhandler(ls->fd, POLLIN | POLLOUT | POLLERR | POLLHUP, lua_socket_poll_event);
9a2954da
CP
394
395 lua_pushint(l, 0);
396 return 1;
5d59fe79
CP
397 }
398
399 if(ret == -1)
400 lua_socket_call_close(ls);
401
9a2954da
CP
402 if(ret < len) {
403 deregisterhandler(ls->fd, 0);
404 registerhandler(ls->fd, POLLIN | POLLOUT | POLLERR | POLLHUP, lua_socket_poll_event);
405 }
406
5d59fe79 407 lua_pushint(l, ret);
065c0091
CP
408 return 1;
409}
410
411static int lua_socket_close(lua_State *l) {
412 lua_socket *ls;
413
414 if(!lua_islong(l, 1))
415 LUA_RETURN(l, LUA_FAIL);
416
417 ls = socketbyidentifier(lua_tolong(l, 1));
5d59fe79 418 if(!ls || (ls->state == SOCKET_CLOSED))
065c0091
CP
419 LUA_RETURN(l, LUA_FAIL);
420
421 lua_socket_call_close(ls);
422
423 LUA_RETURN(l, LUA_OK);
424}
425
5d59fe79 426static void lua_socket_poll_event(int fd, short events) {
065c0091 427 lua_socket *ls = socketbyfd(fd);
5d59fe79 428 if(!ls || (ls->state == SOCKET_CLOSED))
065c0091
CP
429 return;
430
431 if(events & (POLLERR | POLLHUP)) {
432 lua_socket_call_close(ls);
433 return;
434 }
065c0091 435
5d59fe79
CP
436 switch(ls->state) {
437 case SOCKET_CONNECTING:
438 if(events & POLLOUT) {
439 deregisterhandler(fd, 0);
440 registerhandler(fd, POLLIN | POLLERR | POLLHUP, lua_socket_poll_event);
441 ls->state = SOCKET_CONNECTED;
065c0091 442
5d59fe79
CP
443 lua_vnpcall(ls, "connect", "");
444 }
445 break;
446 case SOCKET_CONNECTED:
447 if(events & POLLOUT) {
448 deregisterhandler(fd, 0);
449 registerhandler(fd, POLLIN | POLLERR | POLLHUP, lua_socket_poll_event);
065c0091 450
5d59fe79
CP
451 lua_vnpcall(ls, "flush", "");
452 }
453 if(events & POLLIN) {
454 char buf[8192 * 2];
455 int bytesread;
456
457 bytesread = read(fd, buf, sizeof(buf));
458 if((bytesread == -1) && (errno == EAGAIN))
459 return;
460
461 if(bytesread <= 0) {
462 lua_socket_call_close(ls);
463 return;
464 }
465
77762537 466 lua_vnpcall(ls, "read", "L", buf, (long)bytesread);
5d59fe79
CP
467 }
468 break;
60aab72f
CP
469 case SOCKET_LISTENING:
470 if(events & POLLIN) {
839f8d67
CP
471 struct sockaddr_in rip;
472 struct sockaddr_un run;
60aab72f 473 lua_socket *ls2;
839f8d67
CP
474 unsigned int len;
475 int fd2;
476
477 if(ls->sockettype == PF_INET) {
478 len = sizeof(rip);
479 fd2 = accept(fd, (struct sockaddr *)&rip, &len);
480 } else {
481 len = sizeof(run);
482 fd2 = accept(fd, (struct sockaddr *)&run, &len);
483 }
60aab72f
CP
484 if(fd2 == -1)
485 return;
486
487 ls2 = (lua_socket *)luamalloc(sizeof(lua_socket));
488 if(!ls2) {
489 close(fd2);
490 return;
491 }
492
493 ls2->fd = fd2;
494 ls2->state = SOCKET_CONNECTED;
495 ls2->tag = ls->tag;
496 ls2->handler = ls->handler;
497 ls2->parent = ls;
839f8d67 498 ls2->sockettype = ls->sockettype;
60aab72f
CP
499
500 registerluasocket(ls->l, ls2, POLLIN | POLLERR | POLLHUP, 0);
501 lua_vnpcall(ls, "accept", "l", ls2->identifier);
502 }
503 break;
065c0091
CP
504 }
505}
506
507void lua_socket_closeall(lua_list *l) {
508 while(l->sockets)
509 lua_socket_call_close(l->sockets);
510}
511
c7ec7d64 512void lua_registersocketcommands(lua_State *l) {
065c0091 513 lua_register(l, "socket_unix_connect", lua_socket_unix_connect);
60aab72f 514 lua_register(l, "socket_unix_bind", lua_socket_unix_bind);
839f8d67
CP
515 lua_register(l, "socket_tcp_connect", lua_socket_tcp_connect);
516 lua_register(l, "socket_tcp_bind", lua_socket_tcp_bind);
517 lua_register(l, "socket_udp_connect", lua_socket_udp_connect);
518 lua_register(l, "socket_udp_bind", lua_socket_udp_bind);
065c0091
CP
519 lua_register(l, "socket_close", lua_socket_close);
520 lua_register(l, "socket_write", lua_socket_write);
521}