Mercurial > luasocket
comparison src/tcp.c @ 0:4b915342e2a8
LuaSocket 2.0.2 + CMake build description.
author | Eric Wing <ewing . public |-at-| gmail . com> |
---|---|
date | Tue, 26 Aug 2008 18:40:01 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4b915342e2a8 |
---|---|
1 /*=========================================================================*\ | |
2 * TCP object | |
3 * LuaSocket toolkit | |
4 * | |
5 * RCS ID: $Id: tcp.c,v 1.41 2005/10/07 04:40:59 diego Exp $ | |
6 \*=========================================================================*/ | |
7 #include <string.h> | |
8 | |
9 #include "lua.h" | |
10 #include "lauxlib.h" | |
11 | |
12 #include "auxiliar.h" | |
13 #include "socket.h" | |
14 #include "inet.h" | |
15 #include "options.h" | |
16 #include "tcp.h" | |
17 | |
18 /*=========================================================================*\ | |
19 * Internal function prototypes | |
20 \*=========================================================================*/ | |
21 static int global_create(lua_State *L); | |
22 static int meth_connect(lua_State *L); | |
23 static int meth_listen(lua_State *L); | |
24 static int meth_bind(lua_State *L); | |
25 static int meth_send(lua_State *L); | |
26 static int meth_getstats(lua_State *L); | |
27 static int meth_setstats(lua_State *L); | |
28 static int meth_getsockname(lua_State *L); | |
29 static int meth_getpeername(lua_State *L); | |
30 static int meth_shutdown(lua_State *L); | |
31 static int meth_receive(lua_State *L); | |
32 static int meth_accept(lua_State *L); | |
33 static int meth_close(lua_State *L); | |
34 static int meth_setoption(lua_State *L); | |
35 static int meth_settimeout(lua_State *L); | |
36 static int meth_getfd(lua_State *L); | |
37 static int meth_setfd(lua_State *L); | |
38 static int meth_dirty(lua_State *L); | |
39 | |
40 /* tcp object methods */ | |
41 static luaL_reg tcp[] = { | |
42 {"__gc", meth_close}, | |
43 {"__tostring", auxiliar_tostring}, | |
44 {"accept", meth_accept}, | |
45 {"bind", meth_bind}, | |
46 {"close", meth_close}, | |
47 {"connect", meth_connect}, | |
48 {"dirty", meth_dirty}, | |
49 {"getfd", meth_getfd}, | |
50 {"getpeername", meth_getpeername}, | |
51 {"getsockname", meth_getsockname}, | |
52 {"getstats", meth_getstats}, | |
53 {"setstats", meth_setstats}, | |
54 {"listen", meth_listen}, | |
55 {"receive", meth_receive}, | |
56 {"send", meth_send}, | |
57 {"setfd", meth_setfd}, | |
58 {"setoption", meth_setoption}, | |
59 {"setpeername", meth_connect}, | |
60 {"setsockname", meth_bind}, | |
61 {"settimeout", meth_settimeout}, | |
62 {"shutdown", meth_shutdown}, | |
63 {NULL, NULL} | |
64 }; | |
65 | |
66 /* socket option handlers */ | |
67 static t_opt opt[] = { | |
68 {"keepalive", opt_keepalive}, | |
69 {"reuseaddr", opt_reuseaddr}, | |
70 {"tcp-nodelay", opt_tcp_nodelay}, | |
71 {"linger", opt_linger}, | |
72 {NULL, NULL} | |
73 }; | |
74 | |
75 /* functions in library namespace */ | |
76 static luaL_reg func[] = { | |
77 {"tcp", global_create}, | |
78 {NULL, NULL} | |
79 }; | |
80 | |
81 /*-------------------------------------------------------------------------*\ | |
82 * Initializes module | |
83 \*-------------------------------------------------------------------------*/ | |
84 int tcp_open(lua_State *L) | |
85 { | |
86 /* create classes */ | |
87 auxiliar_newclass(L, "tcp{master}", tcp); | |
88 auxiliar_newclass(L, "tcp{client}", tcp); | |
89 auxiliar_newclass(L, "tcp{server}", tcp); | |
90 /* create class groups */ | |
91 auxiliar_add2group(L, "tcp{master}", "tcp{any}"); | |
92 auxiliar_add2group(L, "tcp{client}", "tcp{any}"); | |
93 auxiliar_add2group(L, "tcp{server}", "tcp{any}"); | |
94 /* define library functions */ | |
95 luaL_openlib(L, NULL, func, 0); | |
96 return 0; | |
97 } | |
98 | |
99 /*=========================================================================*\ | |
100 * Lua methods | |
101 \*=========================================================================*/ | |
102 /*-------------------------------------------------------------------------*\ | |
103 * Just call buffered IO methods | |
104 \*-------------------------------------------------------------------------*/ | |
105 static int meth_send(lua_State *L) { | |
106 p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); | |
107 return buffer_meth_send(L, &tcp->buf); | |
108 } | |
109 | |
110 static int meth_receive(lua_State *L) { | |
111 p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); | |
112 return buffer_meth_receive(L, &tcp->buf); | |
113 } | |
114 | |
115 static int meth_getstats(lua_State *L) { | |
116 p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); | |
117 return buffer_meth_getstats(L, &tcp->buf); | |
118 } | |
119 | |
120 static int meth_setstats(lua_State *L) { | |
121 p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); | |
122 return buffer_meth_setstats(L, &tcp->buf); | |
123 } | |
124 | |
125 /*-------------------------------------------------------------------------*\ | |
126 * Just call option handler | |
127 \*-------------------------------------------------------------------------*/ | |
128 static int meth_setoption(lua_State *L) | |
129 { | |
130 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | |
131 return opt_meth_setoption(L, opt, &tcp->sock); | |
132 } | |
133 | |
134 /*-------------------------------------------------------------------------*\ | |
135 * Select support methods | |
136 \*-------------------------------------------------------------------------*/ | |
137 static int meth_getfd(lua_State *L) | |
138 { | |
139 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | |
140 lua_pushnumber(L, (int) tcp->sock); | |
141 return 1; | |
142 } | |
143 | |
144 /* this is very dangerous, but can be handy for those that are brave enough */ | |
145 static int meth_setfd(lua_State *L) | |
146 { | |
147 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | |
148 tcp->sock = (t_socket) luaL_checknumber(L, 2); | |
149 return 0; | |
150 } | |
151 | |
152 static int meth_dirty(lua_State *L) | |
153 { | |
154 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | |
155 lua_pushboolean(L, !buffer_isempty(&tcp->buf)); | |
156 return 1; | |
157 } | |
158 | |
159 /*-------------------------------------------------------------------------*\ | |
160 * Waits for and returns a client object attempting connection to the | |
161 * server object | |
162 \*-------------------------------------------------------------------------*/ | |
163 static int meth_accept(lua_State *L) | |
164 { | |
165 p_tcp server = (p_tcp) auxiliar_checkclass(L, "tcp{server}", 1); | |
166 p_timeout tm = timeout_markstart(&server->tm); | |
167 t_socket sock; | |
168 int err = socket_accept(&server->sock, &sock, NULL, NULL, tm); | |
169 /* if successful, push client socket */ | |
170 if (err == IO_DONE) { | |
171 p_tcp clnt = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); | |
172 auxiliar_setclass(L, "tcp{client}", -1); | |
173 /* initialize structure fields */ | |
174 socket_setnonblocking(&sock); | |
175 clnt->sock = sock; | |
176 io_init(&clnt->io, (p_send) socket_send, (p_recv) socket_recv, | |
177 (p_error) socket_ioerror, &clnt->sock); | |
178 timeout_init(&clnt->tm, -1, -1); | |
179 buffer_init(&clnt->buf, &clnt->io, &clnt->tm); | |
180 return 1; | |
181 } else { | |
182 lua_pushnil(L); | |
183 lua_pushstring(L, socket_strerror(err)); | |
184 return 2; | |
185 } | |
186 } | |
187 | |
188 /*-------------------------------------------------------------------------*\ | |
189 * Binds an object to an address | |
190 \*-------------------------------------------------------------------------*/ | |
191 static int meth_bind(lua_State *L) | |
192 { | |
193 p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); | |
194 const char *address = luaL_checkstring(L, 2); | |
195 unsigned short port = (unsigned short) luaL_checknumber(L, 3); | |
196 const char *err = inet_trybind(&tcp->sock, address, port); | |
197 if (err) { | |
198 lua_pushnil(L); | |
199 lua_pushstring(L, err); | |
200 return 2; | |
201 } | |
202 lua_pushnumber(L, 1); | |
203 return 1; | |
204 } | |
205 | |
206 /*-------------------------------------------------------------------------*\ | |
207 * Turns a master tcp object into a client object. | |
208 \*-------------------------------------------------------------------------*/ | |
209 static int meth_connect(lua_State *L) | |
210 { | |
211 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | |
212 const char *address = luaL_checkstring(L, 2); | |
213 unsigned short port = (unsigned short) luaL_checknumber(L, 3); | |
214 p_timeout tm = timeout_markstart(&tcp->tm); | |
215 const char *err = inet_tryconnect(&tcp->sock, address, port, tm); | |
216 /* have to set the class even if it failed due to non-blocking connects */ | |
217 auxiliar_setclass(L, "tcp{client}", 1); | |
218 if (err) { | |
219 lua_pushnil(L); | |
220 lua_pushstring(L, err); | |
221 return 2; | |
222 } | |
223 /* turn master object into a client object */ | |
224 lua_pushnumber(L, 1); | |
225 return 1; | |
226 } | |
227 | |
228 /*-------------------------------------------------------------------------*\ | |
229 * Closes socket used by object | |
230 \*-------------------------------------------------------------------------*/ | |
231 static int meth_close(lua_State *L) | |
232 { | |
233 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | |
234 socket_destroy(&tcp->sock); | |
235 lua_pushnumber(L, 1); | |
236 return 1; | |
237 } | |
238 | |
239 /*-------------------------------------------------------------------------*\ | |
240 * Puts the sockt in listen mode | |
241 \*-------------------------------------------------------------------------*/ | |
242 static int meth_listen(lua_State *L) | |
243 { | |
244 p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); | |
245 int backlog = (int) luaL_optnumber(L, 2, 32); | |
246 int err = socket_listen(&tcp->sock, backlog); | |
247 if (err != IO_DONE) { | |
248 lua_pushnil(L); | |
249 lua_pushstring(L, socket_strerror(err)); | |
250 return 2; | |
251 } | |
252 /* turn master object into a server object */ | |
253 auxiliar_setclass(L, "tcp{server}", 1); | |
254 lua_pushnumber(L, 1); | |
255 return 1; | |
256 } | |
257 | |
258 /*-------------------------------------------------------------------------*\ | |
259 * Shuts the connection down partially | |
260 \*-------------------------------------------------------------------------*/ | |
261 static int meth_shutdown(lua_State *L) | |
262 { | |
263 p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{client}", 1); | |
264 const char *how = luaL_optstring(L, 2, "both"); | |
265 switch (how[0]) { | |
266 case 'b': | |
267 if (strcmp(how, "both")) goto error; | |
268 socket_shutdown(&tcp->sock, 2); | |
269 break; | |
270 case 's': | |
271 if (strcmp(how, "send")) goto error; | |
272 socket_shutdown(&tcp->sock, 1); | |
273 break; | |
274 case 'r': | |
275 if (strcmp(how, "receive")) goto error; | |
276 socket_shutdown(&tcp->sock, 0); | |
277 break; | |
278 } | |
279 lua_pushnumber(L, 1); | |
280 return 1; | |
281 error: | |
282 luaL_argerror(L, 2, "invalid shutdown method"); | |
283 return 0; | |
284 } | |
285 | |
286 /*-------------------------------------------------------------------------*\ | |
287 * Just call inet methods | |
288 \*-------------------------------------------------------------------------*/ | |
289 static int meth_getpeername(lua_State *L) | |
290 { | |
291 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | |
292 return inet_meth_getpeername(L, &tcp->sock); | |
293 } | |
294 | |
295 static int meth_getsockname(lua_State *L) | |
296 { | |
297 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | |
298 return inet_meth_getsockname(L, &tcp->sock); | |
299 } | |
300 | |
301 /*-------------------------------------------------------------------------*\ | |
302 * Just call tm methods | |
303 \*-------------------------------------------------------------------------*/ | |
304 static int meth_settimeout(lua_State *L) | |
305 { | |
306 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); | |
307 return timeout_meth_settimeout(L, &tcp->tm); | |
308 } | |
309 | |
310 /*=========================================================================*\ | |
311 * Library functions | |
312 \*=========================================================================*/ | |
313 /*-------------------------------------------------------------------------*\ | |
314 * Creates a master tcp object | |
315 \*-------------------------------------------------------------------------*/ | |
316 static int global_create(lua_State *L) | |
317 { | |
318 t_socket sock; | |
319 const char *err = inet_trycreate(&sock, SOCK_STREAM); | |
320 /* try to allocate a system socket */ | |
321 if (!err) { | |
322 /* allocate tcp object */ | |
323 p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); | |
324 /* set its type as master object */ | |
325 auxiliar_setclass(L, "tcp{master}", -1); | |
326 /* initialize remaining structure fields */ | |
327 socket_setnonblocking(&sock); | |
328 tcp->sock = sock; | |
329 io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv, | |
330 (p_error) socket_ioerror, &tcp->sock); | |
331 timeout_init(&tcp->tm, -1, -1); | |
332 buffer_init(&tcp->buf, &tcp->io, &tcp->tm); | |
333 return 1; | |
334 } else { | |
335 lua_pushnil(L); | |
336 lua_pushstring(L, err); | |
337 return 2; | |
338 } | |
339 } |