]>
jfr.im git - irc/quakenet/newserv.git/blob - lua/luasocket.c
1 /* Copyright (C) Chris Porter 2007 */
6 #include <sys/socket.h>
7 #include <netinet/in.h>
10 #define __USE_MISC /* inet_aton */
13 #include <arpa/inet.h>
18 #include "../lib/strlfunc.h"
19 #include "../core/events.h"
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__)
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...
30 static long nextidentifier
= 0;
31 static void lua_socket_poll_event(int fd
, short events
);
33 static int setnonblock(int fd
) {
37 ret
= fcntl(fd
, F_GETFL
, 0);
43 ret
= fcntl(fd
, F_SETFL
, ret
| O_NONBLOCK
);
51 static int getunixsocket(char *path
, struct sockaddr_un
*r
) {
52 int fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
57 memset(r
, 0, sizeof(struct sockaddr_un
));
58 r
->sun_family
= PF_UNIX
;
59 strlcpy(r
->sun_path
, path
, sizeof(r
->sun_path
));
61 return setnonblock(fd
);
64 /* note ADDRESS not HOSTNAME */
65 static int getipsocket(char *address
, int port
, int protocol
, struct sockaddr_in
*r
) {
69 memset(r
, 0, sizeof(struct sockaddr_in
));
70 r
->sin_family
= PF_INET
;
73 if(!inet_aton(address
, &r
->sin_addr
)) {
74 Error("lua", ERR_ERROR
, "Could not parse address: %s", address
);
81 fd
= socket(AF_INET
, protocol
, 0);
86 setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof(val
));
88 r
->sin_port
= htons(port
);
89 return setnonblock(fd
);
92 static 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
++;
97 ls
->tag
= luaL_ref(ll
->l
, LUA_REGISTRYINDEX
);
98 ls
->handler
= luaL_ref(ll
->l
, LUA_REGISTRYINDEX
);
102 ls
->next
= ll
->sockets
;
105 registerhandler(ls
->fd
, mask
, lua_socket_poll_event
);
108 static int handleconnect(int ret
, lua_State
*l
, lua_list
*ll
, lua_socket
*ls
) {
110 ls
->state
= SOCKET_CONNECTED
;
111 } else if(ret
== -1 && (errno
== EINPROGRESS
)) {
112 ls
->state
= SOCKET_CONNECTING
;
120 registerluasocket(ll
, ls
, (ls
->state
==SOCKET_CONNECTED
?POLLIN
:POLLOUT
) | POLLERR
| POLLHUP
, 1);
122 lua_pushboolean(l
, ls
->state
==SOCKET_CONNECTED
?1:0);
123 lua_pushlong(l
, ls
->identifier
);
127 static int lua_socket_unix_connect(lua_State
*l
) {
129 struct sockaddr_un r
;
134 ll
= lua_listfromstate(l
);
138 if(!lua_isfunction(l
, 2))
141 path
= (char *)lua_tostring(l
, 1);
145 ls
= (lua_socket
*)luamalloc(sizeof(lua_socket
));
149 ls
->sockettype
= PF_UNIX
;
150 ls
->fd
= getunixsocket(path
, &r
);
156 ret
= connect(ls
->fd
, (struct sockaddr
*)&r
, sizeof(r
.sun_family
) + strlen(r
.sun_path
));
157 return handleconnect(ret
, l
, ll
, ls
);
160 static int lua_socket_unix_bind(lua_State
*l
) {
164 struct sockaddr_un r
;
166 ll
= lua_listfromstate(l
);
170 if(!lua_isfunction(l
, 2))
173 path
= (char *)lua_tostring(l
, 1);
177 ls
= (lua_socket
*)luamalloc(sizeof(lua_socket
));
181 ls
->sockettype
= PF_UNIX
;
182 ls
->fd
= getunixsocket(path
, &r
);
191 (bind(ls
->fd
, (struct sockaddr
*)&r
, strlen(r
.sun_path
) + sizeof(r
.sun_family
)) == -1) ||
192 (listen(ls
->fd
, 5) == -1)
199 ls
->state
= SOCKET_LISTENING
;
202 registerluasocket(ll
, ls
, POLLIN
, 1);
204 lua_pushlong(l
, ls
->identifier
);
208 static int lua_socket_ip_connect(lua_State
*l
, int protocol
) {
210 struct sockaddr_in r
;
216 ll
= lua_listfromstate(l
);
220 if(!lua_isfunction(l
, 3) || !lua_islong(l
, 2))
223 address
= (char *)lua_tostring(l
, 1);
227 port
= lua_tolong(l
, 2);
229 ls
= (lua_socket
*)luamalloc(sizeof(lua_socket
));
233 ls
->sockettype
= PF_INET
;
234 ls
->fd
= getipsocket(address
, port
, protocol
, &r
);
240 ret
= connect(ls
->fd
, (struct sockaddr
*)&r
, sizeof(struct sockaddr_in
));
241 return handleconnect(ret
, l
, ll
, ls
);
244 static int lua_socket_ip_bind(lua_State
*l
, int protocol
) {
249 struct sockaddr_in r
;
251 ll
= lua_listfromstate(l
);
255 if(!lua_isfunction(l
, 3) || !lua_islong(l
, 2))
258 /* address can be nil or a string */
259 if(!lua_isnil(l
, 1) && !lua_isstring(l
, 1))
262 address
= (char *)lua_tostring(l
, 1);
263 port
= lua_tolong(l
, 2);
265 ls
= (lua_socket
*)luamalloc(sizeof(lua_socket
));
269 ls
->sockettype
= PF_INET
;
270 ls
->fd
= getipsocket(address
, port
, protocol
, &r
);
277 (bind(ls
->fd
, (struct sockaddr
*)&r
, sizeof(struct sockaddr_in
)) == -1) ||
278 (listen(ls
->fd
, 5) == -1)
285 ls
->state
= SOCKET_LISTENING
;
288 registerluasocket(ll
, ls
, POLLIN
, 1);
290 lua_pushlong(l
, ls
->identifier
);
294 static int lua_socket_tcp_connect(lua_State
*l
) {
295 return lua_socket_ip_connect(l
, SOCK_STREAM
);
298 static int lua_socket_tcp_bind(lua_State
*l
) {
299 return lua_socket_ip_bind(l
, SOCK_STREAM
);
302 static int lua_socket_udp_connect(lua_State
*l
) {
303 return lua_socket_ip_connect(l
, SOCK_DGRAM
);
306 static int lua_socket_udp_bind(lua_State
*l
) {
307 return lua_socket_ip_bind(l
, SOCK_DGRAM
);
310 static lua_socket
*socketbyfd(int fd
) {
314 for(l
=lua_head
;l
;l
=l
->next
)
315 for(ls
=l
->sockets
;ls
;ls
=ls
->next
)
322 static lua_socket
*socketbyidentifier(long identifier
) {
326 for(l
=lua_head
;l
;l
=l
->next
)
327 for(ls
=l
->sockets
;ls
;ls
=ls
->next
)
328 if(ls
->identifier
== identifier
)
334 static void lua_socket_call_close(lua_socket
*ls
) {
337 for(c
=ls
->l
->sockets
;c
;c
=p
) {
340 lua_socket_call_close(c
);
343 for(c
=ls
->l
->sockets
,p
=NULL
;c
;p
=c
,c
=c
->next
) {
345 if(ls
->state
== SOCKET_CLOSED
)
348 ls
->state
= SOCKET_CLOSED
;
349 deregisterhandler(ls
->fd
, 1);
351 lua_vnpcall(ls
, "close", "");
354 ls
->l
->sockets
= ls
->next
;
360 luaL_unref(ls
->l
->l
, LUA_REGISTRYINDEX
, ls
->tag
);
361 luaL_unref(ls
->l
->l
, LUA_REGISTRYINDEX
, ls
->handler
);
370 static int lua_socket_write(lua_State
*l
) {
376 buf
= (char *)lua_tostring(l
, 2);
378 if(!lua_islong(l
, 1) || !buf
) {
382 len
= lua_strlen(l
, 2);
384 ls
= socketbyidentifier(lua_tolong(l
, 1));
385 if(!ls
|| (ls
->state
!= SOCKET_CONNECTED
)) {
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
);
400 lua_socket_call_close(ls
);
403 deregisterhandler(ls
->fd
, 0);
404 registerhandler(ls
->fd
, POLLIN
| POLLOUT
| POLLERR
| POLLHUP
, lua_socket_poll_event
);
411 static int lua_socket_close(lua_State
*l
) {
414 if(!lua_islong(l
, 1))
415 LUA_RETURN(l
, LUA_FAIL
);
417 ls
= socketbyidentifier(lua_tolong(l
, 1));
418 if(!ls
|| (ls
->state
== SOCKET_CLOSED
))
419 LUA_RETURN(l
, LUA_FAIL
);
421 lua_socket_call_close(ls
);
423 LUA_RETURN(l
, LUA_OK
);
426 static void lua_socket_poll_event(int fd
, short events
) {
427 lua_socket
*ls
= socketbyfd(fd
);
428 if(!ls
|| (ls
->state
== SOCKET_CLOSED
))
431 if(events
& (POLLERR
| POLLHUP
)) {
432 lua_socket_call_close(ls
);
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
;
443 lua_vnpcall(ls
, "connect", "");
446 case SOCKET_CONNECTED
:
447 if(events
& POLLOUT
) {
448 deregisterhandler(fd
, 0);
449 registerhandler(fd
, POLLIN
| POLLERR
| POLLHUP
, lua_socket_poll_event
);
451 lua_vnpcall(ls
, "flush", "");
453 if(events
& POLLIN
) {
457 bytesread
= read(fd
, buf
, sizeof(buf
));
458 if((bytesread
== -1) && (errno
== EAGAIN
))
462 lua_socket_call_close(ls
);
466 lua_vnpcall(ls
, "read", "L", buf
, (long)bytesread
);
469 case SOCKET_LISTENING
:
470 if(events
& POLLIN
) {
471 struct sockaddr_in rip
;
472 struct sockaddr_un run
;
477 if(ls
->sockettype
== PF_INET
) {
479 fd2
= accept(fd
, (struct sockaddr
*)&rip
, &len
);
482 fd2
= accept(fd
, (struct sockaddr
*)&run
, &len
);
487 ls2
= (lua_socket
*)luamalloc(sizeof(lua_socket
));
494 ls2
->state
= SOCKET_CONNECTED
;
496 ls2
->handler
= ls
->handler
;
498 ls2
->sockettype
= ls
->sockettype
;
500 registerluasocket(ls
->l
, ls2
, POLLIN
| POLLERR
| POLLHUP
, 0);
501 lua_vnpcall(ls
, "accept", "l", ls2
->identifier
);
507 void lua_socket_closeall(lua_list
*l
) {
509 lua_socket_call_close(l
->sockets
);
512 void lua_registersocketcommands(lua_State
*l
) {
513 lua_register(l
, "socket_unix_connect", lua_socket_unix_connect
);
514 lua_register(l
, "socket_unix_bind", lua_socket_unix_bind
);
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
);
519 lua_register(l
, "socket_close", lua_socket_close
);
520 lua_register(l
, "socket_write", lua_socket_write
);