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