]> jfr.im git - irc/quakenet/newserv.git/blob - lua/luasocket.c
merge
[irc/quakenet/newserv.git] / lua / luasocket.c
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>
10 #include <fcntl.h>
11 #include "../lib/strlfunc.h"
12 #include "../core/events.h"
13
14 #include "lua.h"
15 #include "luabot.h"
16
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__)
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 */
23 static long nextidentifier = 0;
24 static void lua_socket_poll_event(int fd, short events);
25
26 static int lua_socket_unix_connect(lua_State *l) {
27 int len, ret;
28 struct sockaddr_un r;
29 char *path;
30 lua_socket *ls;
31 lua_list *ll;
32
33 ll = lua_listfromstate(l);
34 if(!ll)
35 return 0;
36
37 if(!lua_isfunction(l, 2))
38 return 0;
39
40 path = (char *)lua_tostring(l, 1);
41 if(!path)
42 return 0;
43
44 ls = (lua_socket *)luamalloc(sizeof(lua_socket));
45 if(!ls)
46 return 0;
47
48 ls->fd = socket(AF_UNIX, SOCK_STREAM, 0);
49 if(ls->fd <= -1) {
50 luafree(ls);
51 return 0;
52 }
53
54 memset(&r, 0, sizeof(r));
55 r.sun_family = AF_UNIX;
56 strlcpy(r.sun_path, path, sizeof(r.sun_path));
57
58 /* don't really like this, there's a macro in sys/un.h but it's not there under FreeBSD */
59 len = sizeof(r.sun_family) + strlen(r.sun_path) + 1;
60
61 /* WTB exceptions */
62 ret = fcntl(ls->fd, F_GETFL, 0);
63 if(ret < 0) {
64 luafree(ls);
65 close(ls->fd);
66 return 0;
67 }
68
69 ret = fcntl(ls->fd, F_SETFL, ret | O_NONBLOCK);
70 if(ret < 0) {
71 luafree(ls);
72 close(ls->fd);
73 return 0;
74 }
75
76 ret = connect(ls->fd, (struct sockaddr *)&r, len);
77 if(ret == 0) {
78 ls->state = SOCKET_CONNECTED;
79 } else if(ret == -1 && (errno == EINPROGRESS)) {
80 ls->state = SOCKET_CONNECTING;
81 } else {
82 luafree(ls);
83 close(ls->fd);
84 return 0;
85 }
86
87 /* this whole identifier thing should probably use userdata stuff */
88 ls->identifier = nextidentifier++;
89 ls->tag = luaL_ref(l, LUA_REGISTRYINDEX);
90 ls->handler = luaL_ref(l, LUA_REGISTRYINDEX);
91
92 ls->l = ll;
93
94 ls->next = ll->sockets;
95 ll->sockets = ls;
96
97 registerhandler(ls->fd, (ls->state==SOCKET_CONNECTED?POLLIN:POLLOUT) | POLLERR | POLLHUP, lua_socket_poll_event);
98
99 lua_pushboolean(l, ls->state==SOCKET_CONNECTED?1:0);
100 lua_pushlong(l, ls->identifier);
101 return 2;
102 }
103
104 static lua_socket *socketbyfd(int fd) {
105 lua_list *l;
106 lua_socket *ls;
107
108 for(l=lua_head;l;l=l->next)
109 for(ls=l->sockets;ls;ls=ls->next)
110 if(ls->fd == fd)
111 return ls;
112
113 return NULL;
114 }
115
116 static lua_socket *socketbyidentifier(long identifier) {
117 lua_list *l;
118 lua_socket *ls;
119
120 for(l=lua_head;l;l=l->next)
121 for(ls=l->sockets;ls;ls=ls->next)
122 if(ls->identifier == identifier)
123 return ls;
124
125 return NULL;
126 }
127
128 static void lua_socket_call_close(lua_socket *ls) {
129 lua_socket *p, *c;
130
131 for(c=ls->l->sockets,p=NULL;c;p=c,c=c->next) {
132 if(c == ls) {
133 if(ls->state == SOCKET_CLOSED)
134 return;
135
136 ls->state = SOCKET_CLOSED;
137 deregisterhandler(ls->fd, 1);
138
139 lua_vnpcall(ls, "close", "");
140
141 if(!p) {
142 ls->l->sockets = ls->next;
143 } else {
144 p->next = ls->next;
145 }
146
147 luaL_unref(ls->l->l, LUA_REGISTRYINDEX, ls->tag);
148 luaL_unref(ls->l->l, LUA_REGISTRYINDEX, ls->handler);
149
150 luafree(ls);
151 return;
152 }
153 }
154
155 }
156
157 static int lua_socket_write(lua_State *l) {
158 char *buf;
159 long len;
160 lua_socket *ls;
161 int ret;
162
163 buf = (char *)lua_tostring(l, 2);
164
165 if(!lua_islong(l, 1) || !buf) {
166 lua_pushint(l, -1);
167 return 1;
168 }
169 len = lua_strlen(l, 2);
170
171 ls = socketbyidentifier(lua_tolong(l, 1));
172 if(!ls || (ls->state != SOCKET_CONNECTED)) {
173 lua_pushint(l, -1);
174 return 1;
175 }
176
177 ret = write(ls->fd, buf, len);
178 if(ret == -1 && (errno == EAGAIN)) {
179 deregisterhandler(ls->fd, 0);
180 registerhandler(ls->fd, POLLIN | POLLOUT | POLLERR | POLLHUP, lua_socket_poll_event);
181
182 lua_pushint(l, 0);
183 return 1;
184 }
185
186 if(ret == -1)
187 lua_socket_call_close(ls);
188
189 if(ret < len) {
190 deregisterhandler(ls->fd, 0);
191 registerhandler(ls->fd, POLLIN | POLLOUT | POLLERR | POLLHUP, lua_socket_poll_event);
192 }
193
194 lua_pushint(l, ret);
195 return 1;
196 }
197
198 static int lua_socket_close(lua_State *l) {
199 lua_socket *ls;
200
201 if(!lua_islong(l, 1))
202 LUA_RETURN(l, LUA_FAIL);
203
204 ls = socketbyidentifier(lua_tolong(l, 1));
205 if(!ls || (ls->state == SOCKET_CLOSED))
206 LUA_RETURN(l, LUA_FAIL);
207
208 lua_socket_call_close(ls);
209
210 LUA_RETURN(l, LUA_OK);
211 }
212
213 static void lua_socket_poll_event(int fd, short events) {
214 lua_socket *ls = socketbyfd(fd);
215 if(!ls || (ls->state == SOCKET_CLOSED))
216 return;
217
218 if(events & (POLLERR | POLLHUP)) {
219 lua_socket_call_close(ls);
220 return;
221 }
222
223 switch(ls->state) {
224 case SOCKET_CONNECTING:
225 if(events & POLLOUT) {
226 deregisterhandler(fd, 0);
227 registerhandler(fd, POLLIN | POLLERR | POLLHUP, lua_socket_poll_event);
228 ls->state = SOCKET_CONNECTED;
229
230 lua_vnpcall(ls, "connect", "");
231 }
232 break;
233 case SOCKET_CONNECTED:
234 if(events & POLLOUT) {
235 deregisterhandler(fd, 0);
236 registerhandler(fd, POLLIN | POLLERR | POLLHUP, lua_socket_poll_event);
237
238 lua_vnpcall(ls, "flush", "");
239 }
240 if(events & POLLIN) {
241 char buf[8192 * 2];
242 int bytesread;
243
244 bytesread = read(fd, buf, sizeof(buf));
245 if((bytesread == -1) && (errno == EAGAIN))
246 return;
247
248 if(bytesread <= 0) {
249 lua_socket_call_close(ls);
250 return;
251 }
252
253 lua_vnpcall(ls, "read", "L", buf, (long)bytesread);
254 }
255 break;
256 }
257 }
258
259 void lua_socket_closeall(lua_list *l) {
260 while(l->sockets)
261 lua_socket_call_close(l->sockets);
262 }
263
264 void lua_registersocketcommands(lua_State *l) {
265 lua_register(l, "socket_unix_connect", lua_socket_unix_connect);
266 lua_register(l, "socket_close", lua_socket_close);
267 lua_register(l, "socket_write", lua_socket_write);
268 }