diff options
Diffstat (limited to 'src/tcp.c')
-rw-r--r-- | src/tcp.c | 85 |
1 files changed, 81 insertions, 4 deletions
@@ -1,5 +1,6 @@ | |||
1 | /*=========================================================================*\ | 1 | /*=========================================================================*\ |
2 | * TCP object | 2 | * TCP object |
3 | * LuaSocket toolkit | ||
3 | * | 4 | * |
4 | * RCS ID: $Id$ | 5 | * RCS ID: $Id$ |
5 | \*=========================================================================*/ | 6 | \*=========================================================================*/ |
@@ -13,7 +14,6 @@ | |||
13 | #include "auxiliar.h" | 14 | #include "auxiliar.h" |
14 | #include "socket.h" | 15 | #include "socket.h" |
15 | #include "inet.h" | 16 | #include "inet.h" |
16 | #include "error.h" | ||
17 | #include "tcp.h" | 17 | #include "tcp.h" |
18 | 18 | ||
19 | /*=========================================================================*\ | 19 | /*=========================================================================*\ |
@@ -28,9 +28,13 @@ static int meth_getpeername(lua_State *L); | |||
28 | static int meth_receive(lua_State *L); | 28 | static int meth_receive(lua_State *L); |
29 | static int meth_accept(lua_State *L); | 29 | static int meth_accept(lua_State *L); |
30 | static int meth_close(lua_State *L); | 30 | static int meth_close(lua_State *L); |
31 | static int meth_setoption(lua_State *L); | ||
31 | static int meth_timeout(lua_State *L); | 32 | static int meth_timeout(lua_State *L); |
32 | static int meth_fd(lua_State *L); | 33 | static int meth_fd(lua_State *L); |
33 | static int meth_dirty(lua_State *L); | 34 | static int meth_dirty(lua_State *L); |
35 | static int opt_nodelay(lua_State *L); | ||
36 | static int opt_keepalive(lua_State *L); | ||
37 | static int opt_linger(lua_State *L); | ||
34 | 38 | ||
35 | /* tcp object methods */ | 39 | /* tcp object methods */ |
36 | static luaL_reg tcp[] = { | 40 | static luaL_reg tcp[] = { |
@@ -45,11 +49,21 @@ static luaL_reg tcp[] = { | |||
45 | {"getsockname", meth_getsockname}, | 49 | {"getsockname", meth_getsockname}, |
46 | {"timeout", meth_timeout}, | 50 | {"timeout", meth_timeout}, |
47 | {"close", meth_close}, | 51 | {"close", meth_close}, |
52 | {"setoption", meth_setoption}, | ||
53 | {"__gc", meth_close}, | ||
48 | {"fd", meth_fd}, | 54 | {"fd", meth_fd}, |
49 | {"dirty", meth_dirty}, | 55 | {"dirty", meth_dirty}, |
50 | {NULL, NULL} | 56 | {NULL, NULL} |
51 | }; | 57 | }; |
52 | 58 | ||
59 | /* socket option handlers */ | ||
60 | static luaL_reg opt[] = { | ||
61 | {"keepalive", opt_keepalive}, | ||
62 | {"nodelay", opt_nodelay}, | ||
63 | {"linger", opt_linger}, | ||
64 | {NULL, NULL} | ||
65 | }; | ||
66 | |||
53 | /* functions in library namespace */ | 67 | /* functions in library namespace */ |
54 | static luaL_reg func[] = { | 68 | static luaL_reg func[] = { |
55 | {"tcp", global_create}, | 69 | {"tcp", global_create}, |
@@ -71,6 +85,7 @@ void tcp_open(lua_State *L) | |||
71 | aux_add2group(L, "tcp{server}", "tcp{any}"); | 85 | aux_add2group(L, "tcp{server}", "tcp{any}"); |
72 | aux_add2group(L, "tcp{client}", "tcp{client, server}"); | 86 | aux_add2group(L, "tcp{client}", "tcp{client, server}"); |
73 | aux_add2group(L, "tcp{server}", "tcp{client, server}"); | 87 | aux_add2group(L, "tcp{server}", "tcp{client, server}"); |
88 | /* both server and client objects are selectable */ | ||
74 | aux_add2group(L, "tcp{client}", "select{able}"); | 89 | aux_add2group(L, "tcp{client}", "select{able}"); |
75 | aux_add2group(L, "tcp{server}", "select{able}"); | 90 | aux_add2group(L, "tcp{server}", "select{able}"); |
76 | /* define library functions */ | 91 | /* define library functions */ |
@@ -97,18 +112,80 @@ static int meth_receive(lua_State *L) | |||
97 | } | 112 | } |
98 | 113 | ||
99 | /*-------------------------------------------------------------------------*\ | 114 | /*-------------------------------------------------------------------------*\ |
115 | * Option handlers | ||
116 | \*-------------------------------------------------------------------------*/ | ||
117 | static int meth_setoption(lua_State *L) | ||
118 | { | ||
119 | return aux_meth_setoption(L, opt); | ||
120 | } | ||
121 | |||
122 | static int opt_boolean(lua_State *L, int level, int name) | ||
123 | { | ||
124 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1); | ||
125 | int val = aux_checkboolean(L, 2); | ||
126 | if (setsockopt(tcp->sock, level, name, (char *) &val, sizeof(val)) < 0) { | ||
127 | lua_pushnil(L); | ||
128 | lua_pushstring(L, "setsockopt failed"); | ||
129 | return 2; | ||
130 | } | ||
131 | lua_pushnumber(L, 1); | ||
132 | return 1; | ||
133 | } | ||
134 | |||
135 | /* disables the Nagle algorithm */ | ||
136 | static int opt_nodelay(lua_State *L) | ||
137 | { | ||
138 | struct protoent *pe = getprotobyname("TCP"); | ||
139 | if (!pe) { | ||
140 | lua_pushnil(L); | ||
141 | lua_pushstring(L, "getprotobyname"); | ||
142 | return 2; | ||
143 | } | ||
144 | return opt_boolean(L, pe->p_proto, TCP_NODELAY); | ||
145 | } | ||
146 | |||
147 | static int opt_keepalive(lua_State *L) | ||
148 | { | ||
149 | return opt_boolean(L, SOL_SOCKET, SO_KEEPALIVE); | ||
150 | } | ||
151 | |||
152 | int opt_linger(lua_State *L) | ||
153 | { | ||
154 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client}", 1); | ||
155 | struct linger li; | ||
156 | if (!lua_istable(L, 2)) | ||
157 | luaL_typerror(L, 2, lua_typename(L, LUA_TTABLE)); | ||
158 | lua_pushstring(L, "onoff"); | ||
159 | lua_gettable(L, 2); | ||
160 | if (!lua_isnumber(L, -1)) luaL_argerror(L, 2, "invalid onoff field"); | ||
161 | li.l_onoff = (int) lua_tonumber(L, -1); | ||
162 | lua_pushstring(L, "linger"); | ||
163 | lua_gettable(L, 2); | ||
164 | if (!lua_isnumber(L, -1)) luaL_argerror(L, 2, "invalid linger field"); | ||
165 | li.l_linger = (int) lua_tonumber(L, -1); | ||
166 | if (setsockopt(tcp->sock, SOL_SOCKET, SO_LINGER, | ||
167 | (char *) &li, sizeof(li) < 0)) { | ||
168 | lua_pushnil(L); | ||
169 | lua_pushstring(L, "setsockopt failed"); | ||
170 | return 2; | ||
171 | } | ||
172 | lua_pushnumber(L, 1); | ||
173 | return 1; | ||
174 | } | ||
175 | |||
176 | /*-------------------------------------------------------------------------*\ | ||
100 | * Select support methods | 177 | * Select support methods |
101 | \*-------------------------------------------------------------------------*/ | 178 | \*-------------------------------------------------------------------------*/ |
102 | static int meth_fd(lua_State *L) | 179 | static int meth_fd(lua_State *L) |
103 | { | 180 | { |
104 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client, server}", 1); | 181 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{client, server}", 1); |
105 | lua_pushnumber(L, tcp->sock); | 182 | lua_pushnumber(L, tcp->sock); |
106 | return 1; | 183 | return 1; |
107 | } | 184 | } |
108 | 185 | ||
109 | static int meth_dirty(lua_State *L) | 186 | static int meth_dirty(lua_State *L) |
110 | { | 187 | { |
111 | p_tcp tcp = (p_tcp) aux_checkclass(L, "tcp{client, server}", 1); | 188 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{client, server}", 1); |
112 | lua_pushboolean(L, !buf_isempty(&tcp->buf)); | 189 | lua_pushboolean(L, !buf_isempty(&tcp->buf)); |
113 | return 1; | 190 | return 1; |
114 | } | 191 | } |
@@ -207,7 +284,7 @@ static int meth_accept(lua_State *L) | |||
207 | if (client->sock == SOCK_INVALID) { | 284 | if (client->sock == SOCK_INVALID) { |
208 | if (tm_get(tm) == 0) { | 285 | if (tm_get(tm) == 0) { |
209 | lua_pushnil(L); | 286 | lua_pushnil(L); |
210 | error_push(L, IO_TIMEOUT); | 287 | io_pusherror(L, IO_TIMEOUT); |
211 | return 2; | 288 | return 2; |
212 | } | 289 | } |
213 | } else break; | 290 | } else break; |