diff options
author | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-01-17 00:17:46 +0000 |
---|---|---|
committer | Diego Nehab <diego@tecgraf.puc-rio.br> | 2004-01-17 00:17:46 +0000 |
commit | 076451c75336b30e6152bd5c02f355db39107f7d (patch) | |
tree | 785a6c71ca1e5246f2ce09a9b91f98eb902ac2a0 | |
parent | 89f3ecf7820857f91c4039536d2bbe3cf12d5f95 (diff) | |
download | luasocket-076451c75336b30e6152bd5c02f355db39107f7d.tar.gz luasocket-076451c75336b30e6152bd5c02f355db39107f7d.tar.bz2 luasocket-076451c75336b30e6152bd5c02f355db39107f7d.zip |
Tested in windows. Still needs more testing, but progress has been made.
-rw-r--r-- | TODO | 11 | ||||
-rw-r--r-- | luasocket.sln | 23 | ||||
-rw-r--r-- | luasocket.vcproj | 216 | ||||
-rw-r--r-- | src/inet.h | 4 | ||||
-rw-r--r-- | src/luasocket.h | 2 | ||||
-rw-r--r-- | src/tcp.c | 18 | ||||
-rw-r--r-- | src/timeout.c | 1 | ||||
-rw-r--r-- | src/udp.c | 75 | ||||
-rw-r--r-- | src/usocket.c | 92 | ||||
-rw-r--r-- | src/wsocket.c | 180 | ||||
-rw-r--r-- | test/testclnt.lua | 294 |
11 files changed, 620 insertions, 296 deletions
@@ -1,8 +1,13 @@ | |||
1 | change send/recv to avoid using select | ||
2 | 1 | ||
2 | |||
3 | |||
4 | check for interrupt compliance | ||
5 | add connect with timeout | ||
3 | add gethostname and use it in HTTP, SMTP etc, and add manual entry. | 6 | add gethostname and use it in HTTP, SMTP etc, and add manual entry. |
7 | |||
4 | add local connect, and manual entry | 8 | add local connect, and manual entry |
5 | add shutdown, and manual entry | 9 | |
10 | add shutdown manual entry | ||
6 | 11 | ||
7 | only allocate in case of success | 12 | only allocate in case of success |
8 | only call select if io fails... | 13 | only call select if io fails... |
@@ -65,6 +70,8 @@ Ajeitar o protocolo da luaopen_socket()... sei lá qual é. | |||
65 | - testar os options! | 70 | - testar os options! |
66 | - adicionar exemplos de expansão: pipe, local, named pipe | 71 | - adicionar exemplos de expansão: pipe, local, named pipe |
67 | 72 | ||
73 | * add shutdown | ||
74 | * change send/recv to avoid using select | ||
68 | * O location do "redirect" pode ser relativo ao servidor atual (não pode, | 75 | * O location do "redirect" pode ser relativo ao servidor atual (não pode, |
69 | mas os servidores fazem merda...) | 76 | mas os servidores fazem merda...) |
70 | * Ajeitar para Lua 5.0 | 77 | * Ajeitar para Lua 5.0 |
diff --git a/luasocket.sln b/luasocket.sln new file mode 100644 index 0000000..25fe127 --- /dev/null +++ b/luasocket.sln | |||
@@ -0,0 +1,23 @@ | |||
1 | Microsoft Visual Studio Solution File, Format Version 8.00 | ||
2 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "luasocket", "luasocket.vcproj", "{4FAAB633-F0E7-4D12-B680-D150A0DD7268}" | ||
3 | ProjectSection(ProjectDependencies) = postProject | ||
4 | EndProjectSection | ||
5 | EndProject | ||
6 | Global | ||
7 | GlobalSection(SolutionConfiguration) = preSolution | ||
8 | Debug = Debug | ||
9 | Release = Release | ||
10 | EndGlobalSection | ||
11 | GlobalSection(ProjectConfiguration) = postSolution | ||
12 | {4FAAB633-F0E7-4D12-B680-D150A0DD7268}.Debug.ActiveCfg = Debug|Win32 | ||
13 | {4FAAB633-F0E7-4D12-B680-D150A0DD7268}.Debug.Build.0 = Debug|Win32 | ||
14 | {4FAAB633-F0E7-4D12-B680-D150A0DD7268}.Release.ActiveCfg = Release|Win32 | ||
15 | {4FAAB633-F0E7-4D12-B680-D150A0DD7268}.Release.Build.0 = Release|Win32 | ||
16 | EndGlobalSection | ||
17 | GlobalSection(SolutionItems) = postSolution | ||
18 | EndGlobalSection | ||
19 | GlobalSection(ExtensibilityGlobals) = postSolution | ||
20 | EndGlobalSection | ||
21 | GlobalSection(ExtensibilityAddIns) = postSolution | ||
22 | EndGlobalSection | ||
23 | EndGlobal | ||
diff --git a/luasocket.vcproj b/luasocket.vcproj new file mode 100644 index 0000000..b5c4d53 --- /dev/null +++ b/luasocket.vcproj | |||
@@ -0,0 +1,216 @@ | |||
1 | <?xml version="1.0" encoding="Windows-1252"?> | ||
2 | <VisualStudioProject | ||
3 | ProjectType="Visual C++" | ||
4 | Version="7.10" | ||
5 | Name="luasocket" | ||
6 | ProjectGUID="{4FAAB633-F0E7-4D12-B680-D150A0DD7268}" | ||
7 | Keyword="Win32Proj"> | ||
8 | <Platforms> | ||
9 | <Platform | ||
10 | Name="Win32"/> | ||
11 | </Platforms> | ||
12 | <Configurations> | ||
13 | <Configuration | ||
14 | Name="Debug|Win32" | ||
15 | OutputDirectory="." | ||
16 | IntermediateDirectory="." | ||
17 | ConfigurationType="1" | ||
18 | CharacterSet="2"> | ||
19 | <Tool | ||
20 | Name="VCCLCompilerTool" | ||
21 | Optimization="0" | ||
22 | AdditionalIncludeDirectories="net/include" | ||
23 | PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE, LUASOCKET_DEBUG" | ||
24 | MinimalRebuild="TRUE" | ||
25 | BasicRuntimeChecks="3" | ||
26 | RuntimeLibrary="5" | ||
27 | UsePrecompiledHeader="0" | ||
28 | WarningLevel="3" | ||
29 | Detect64BitPortabilityProblems="TRUE" | ||
30 | DebugInformationFormat="4"/> | ||
31 | <Tool | ||
32 | Name="VCCustomBuildTool"/> | ||
33 | <Tool | ||
34 | Name="VCLinkerTool" | ||
35 | AdditionalDependencies="lua.lib lualib.lib ws2_32.lib" | ||
36 | OutputFile="$(OutDir)/luasocket.exe" | ||
37 | LinkIncremental="2" | ||
38 | AdditionalLibraryDirectories="net/lib" | ||
39 | GenerateDebugInformation="TRUE" | ||
40 | ProgramDatabaseFile="$(OutDir)/luasocket.pdb" | ||
41 | SubSystem="1" | ||
42 | TargetMachine="1"/> | ||
43 | <Tool | ||
44 | Name="VCMIDLTool"/> | ||
45 | <Tool | ||
46 | Name="VCPostBuildEventTool"/> | ||
47 | <Tool | ||
48 | Name="VCPreBuildEventTool"/> | ||
49 | <Tool | ||
50 | Name="VCPreLinkEventTool"/> | ||
51 | <Tool | ||
52 | Name="VCResourceCompilerTool"/> | ||
53 | <Tool | ||
54 | Name="VCWebServiceProxyGeneratorTool"/> | ||
55 | <Tool | ||
56 | Name="VCXMLDataGeneratorTool"/> | ||
57 | <Tool | ||
58 | Name="VCWebDeploymentTool"/> | ||
59 | <Tool | ||
60 | Name="VCManagedWrapperGeneratorTool"/> | ||
61 | <Tool | ||
62 | Name="VCAuxiliaryManagedWrapperGeneratorTool"/> | ||
63 | </Configuration> | ||
64 | <Configuration | ||
65 | Name="Release|Win32" | ||
66 | OutputDirectory="." | ||
67 | IntermediateDirectory="." | ||
68 | ConfigurationType="1" | ||
69 | CharacterSet="2"> | ||
70 | <Tool | ||
71 | Name="VCCLCompilerTool" | ||
72 | AdditionalIncludeDirectories="net/include" | ||
73 | PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE, LUASOCKET_DEBUG" | ||
74 | RuntimeLibrary="4" | ||
75 | UsePrecompiledHeader="0" | ||
76 | WarningLevel="3" | ||
77 | Detect64BitPortabilityProblems="TRUE" | ||
78 | DebugInformationFormat="3"/> | ||
79 | <Tool | ||
80 | Name="VCCustomBuildTool"/> | ||
81 | <Tool | ||
82 | Name="VCLinkerTool" | ||
83 | AdditionalDependencies="lua.lib lualib.lib ws2_32.lib" | ||
84 | OutputFile="$(OutDir)/luasocket.exe" | ||
85 | LinkIncremental="1" | ||
86 | AdditionalLibraryDirectories="net/lib" | ||
87 | GenerateDebugInformation="TRUE" | ||
88 | SubSystem="1" | ||
89 | OptimizeReferences="2" | ||
90 | EnableCOMDATFolding="2" | ||
91 | TargetMachine="1"/> | ||
92 | <Tool | ||
93 | Name="VCMIDLTool"/> | ||
94 | <Tool | ||
95 | Name="VCPostBuildEventTool"/> | ||
96 | <Tool | ||
97 | Name="VCPreBuildEventTool"/> | ||
98 | <Tool | ||
99 | Name="VCPreLinkEventTool"/> | ||
100 | <Tool | ||
101 | Name="VCResourceCompilerTool"/> | ||
102 | <Tool | ||
103 | Name="VCWebServiceProxyGeneratorTool"/> | ||
104 | <Tool | ||
105 | Name="VCXMLDataGeneratorTool"/> | ||
106 | <Tool | ||
107 | Name="VCWebDeploymentTool"/> | ||
108 | <Tool | ||
109 | Name="VCManagedWrapperGeneratorTool"/> | ||
110 | <Tool | ||
111 | Name="VCAuxiliaryManagedWrapperGeneratorTool"/> | ||
112 | </Configuration> | ||
113 | </Configurations> | ||
114 | <References> | ||
115 | </References> | ||
116 | <Files> | ||
117 | <Filter | ||
118 | Name="Source Files" | ||
119 | Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" | ||
120 | UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> | ||
121 | <File | ||
122 | RelativePath=".\auxiliar.c"> | ||
123 | </File> | ||
124 | <File | ||
125 | RelativePath=".\buffer.c"> | ||
126 | </File> | ||
127 | <File | ||
128 | RelativePath=".\code.c"> | ||
129 | </File> | ||
130 | <File | ||
131 | RelativePath=".\error.c"> | ||
132 | </File> | ||
133 | <File | ||
134 | RelativePath=".\inet.c"> | ||
135 | </File> | ||
136 | <File | ||
137 | RelativePath=".\io.c"> | ||
138 | </File> | ||
139 | <File | ||
140 | RelativePath=".\lua.c"> | ||
141 | </File> | ||
142 | <File | ||
143 | RelativePath=".\luasocket.c"> | ||
144 | </File> | ||
145 | <File | ||
146 | RelativePath=".\select.c"> | ||
147 | </File> | ||
148 | <File | ||
149 | RelativePath=".\tcp.c"> | ||
150 | </File> | ||
151 | <File | ||
152 | RelativePath=".\timeout.c"> | ||
153 | </File> | ||
154 | <File | ||
155 | RelativePath=".\udp.c"> | ||
156 | </File> | ||
157 | <File | ||
158 | RelativePath=".\wsocket.c"> | ||
159 | </File> | ||
160 | </Filter> | ||
161 | <Filter | ||
162 | Name="Header Files" | ||
163 | Filter="h;hpp;hxx;hm;inl;inc;xsd" | ||
164 | UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"> | ||
165 | <File | ||
166 | RelativePath=".\auxiliar.h"> | ||
167 | </File> | ||
168 | <File | ||
169 | RelativePath=".\buffer.h"> | ||
170 | </File> | ||
171 | <File | ||
172 | RelativePath=".\code.h"> | ||
173 | </File> | ||
174 | <File | ||
175 | RelativePath=".\error.h"> | ||
176 | </File> | ||
177 | <File | ||
178 | RelativePath=".\inet.h"> | ||
179 | </File> | ||
180 | <File | ||
181 | RelativePath=".\io.h"> | ||
182 | </File> | ||
183 | <File | ||
184 | RelativePath=".\luasocket.h"> | ||
185 | </File> | ||
186 | <File | ||
187 | RelativePath=".\select.h"> | ||
188 | </File> | ||
189 | <File | ||
190 | RelativePath=".\socket.h"> | ||
191 | </File> | ||
192 | <File | ||
193 | RelativePath=".\stdafx.h"> | ||
194 | </File> | ||
195 | <File | ||
196 | RelativePath=".\tcp.h"> | ||
197 | </File> | ||
198 | <File | ||
199 | RelativePath=".\timeout.h"> | ||
200 | </File> | ||
201 | <File | ||
202 | RelativePath=".\udp.h"> | ||
203 | </File> | ||
204 | <File | ||
205 | RelativePath=".\wsocket.h"> | ||
206 | </File> | ||
207 | </Filter> | ||
208 | <Filter | ||
209 | Name="Resource Files" | ||
210 | Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx" | ||
211 | UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"> | ||
212 | </Filter> | ||
213 | </Files> | ||
214 | <Globals> | ||
215 | </Globals> | ||
216 | </VisualStudioProject> | ||
@@ -19,6 +19,10 @@ | |||
19 | #include <lua.h> | 19 | #include <lua.h> |
20 | #include "socket.h" | 20 | #include "socket.h" |
21 | 21 | ||
22 | #ifdef WIN32 | ||
23 | #define INET_ATON | ||
24 | #endif | ||
25 | |||
22 | void inet_open(lua_State *L); | 26 | void inet_open(lua_State *L); |
23 | const char *inet_tryconnect(p_sock ps, const char *address, | 27 | const char *inet_tryconnect(p_sock ps, const char *address, |
24 | unsigned short port); | 28 | unsigned short port); |
diff --git a/src/luasocket.h b/src/luasocket.h index 7756605..ac26824 100644 --- a/src/luasocket.h +++ b/src/luasocket.h | |||
@@ -18,7 +18,9 @@ | |||
18 | /*-------------------------------------------------------------------------*\ | 18 | /*-------------------------------------------------------------------------*\ |
19 | * Library's namespace | 19 | * Library's namespace |
20 | \*-------------------------------------------------------------------------*/ | 20 | \*-------------------------------------------------------------------------*/ |
21 | #ifndef LUASOCKET_LIBNAME | ||
21 | #define LUASOCKET_LIBNAME "socket" | 22 | #define LUASOCKET_LIBNAME "socket" |
23 | #endif | ||
22 | 24 | ||
23 | /*-------------------------------------------------------------------------*\ | 25 | /*-------------------------------------------------------------------------*\ |
24 | * This macro prefixes all exported API functions | 26 | * This macro prefixes all exported API functions |
@@ -36,6 +36,7 @@ static int meth_dirty(lua_State *L); | |||
36 | static int opt_tcp_nodelay(lua_State *L); | 36 | static int opt_tcp_nodelay(lua_State *L); |
37 | static int opt_keepalive(lua_State *L); | 37 | static int opt_keepalive(lua_State *L); |
38 | static int opt_linger(lua_State *L); | 38 | static int opt_linger(lua_State *L); |
39 | static int opt_reuseaddr(lua_State *L); | ||
39 | 40 | ||
40 | /* tcp object methods */ | 41 | /* tcp object methods */ |
41 | static luaL_reg tcp[] = { | 42 | static luaL_reg tcp[] = { |
@@ -61,6 +62,7 @@ static luaL_reg tcp[] = { | |||
61 | /* socket option handlers */ | 62 | /* socket option handlers */ |
62 | static luaL_reg opt[] = { | 63 | static luaL_reg opt[] = { |
63 | {"keepalive", opt_keepalive}, | 64 | {"keepalive", opt_keepalive}, |
65 | {"reuseaddr", opt_reuseaddr}, | ||
64 | {"tcp-nodelay", opt_tcp_nodelay}, | 66 | {"tcp-nodelay", opt_tcp_nodelay}, |
65 | {"linger", opt_linger}, | 67 | {"linger", opt_linger}, |
66 | {NULL, NULL} | 68 | {NULL, NULL} |
@@ -123,7 +125,7 @@ static int meth_setoption(lua_State *L) | |||
123 | 125 | ||
124 | static int opt_boolean(lua_State *L, int level, int name) | 126 | static int opt_boolean(lua_State *L, int level, int name) |
125 | { | 127 | { |
126 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{client,server}", 1); | 128 | p_tcp tcp = (p_tcp) aux_checkgroup(L, "tcp{any}", 1); |
127 | int val = aux_checkboolean(L, 2); | 129 | int val = aux_checkboolean(L, 2); |
128 | if (setsockopt(tcp->sock, level, name, (char *) &val, sizeof(val)) < 0) { | 130 | if (setsockopt(tcp->sock, level, name, (char *) &val, sizeof(val)) < 0) { |
129 | lua_pushnil(L); | 131 | lua_pushnil(L); |
@@ -134,16 +136,16 @@ static int opt_boolean(lua_State *L, int level, int name) | |||
134 | return 1; | 136 | return 1; |
135 | } | 137 | } |
136 | 138 | ||
139 | /* enables reuse of local address */ | ||
140 | static int opt_reuseaddr(lua_State *L) | ||
141 | { | ||
142 | return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR); | ||
143 | } | ||
144 | |||
137 | /* disables the Naggle algorithm */ | 145 | /* disables the Naggle algorithm */ |
138 | static int opt_tcp_nodelay(lua_State *L) | 146 | static int opt_tcp_nodelay(lua_State *L) |
139 | { | 147 | { |
140 | struct protoent *pe = getprotobyname("TCP"); | 148 | return opt_boolean(L, IPPROTO_TCP, TCP_NODELAY); |
141 | if (!pe) { | ||
142 | lua_pushnil(L); | ||
143 | lua_pushstring(L, "getprotobyname"); | ||
144 | return 2; | ||
145 | } | ||
146 | return opt_boolean(L, pe->p_proto, TCP_NODELAY); | ||
147 | } | 149 | } |
148 | 150 | ||
149 | static int opt_keepalive(lua_State *L) | 151 | static int opt_keepalive(lua_State *L) |
diff --git a/src/timeout.c b/src/timeout.c index 5d6de99..2d88ded 100644 --- a/src/timeout.c +++ b/src/timeout.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #ifdef WIN32 | 16 | #ifdef WIN32 |
17 | #include <windows.h> | 17 | #include <windows.h> |
18 | #else | 18 | #else |
19 | #include <time.h> | ||
19 | #include <sys/time.h> | 20 | #include <sys/time.h> |
20 | #include <sys/times.h> | 21 | #include <sys/times.h> |
21 | #include <unistd.h> | 22 | #include <unistd.h> |
@@ -35,6 +35,11 @@ static int meth_fd(lua_State *L); | |||
35 | static int meth_dirty(lua_State *L); | 35 | static int meth_dirty(lua_State *L); |
36 | static int opt_dontroute(lua_State *L); | 36 | static int opt_dontroute(lua_State *L); |
37 | static int opt_broadcast(lua_State *L); | 37 | static int opt_broadcast(lua_State *L); |
38 | static int opt_reuseaddr(lua_State *L); | ||
39 | static int opt_ip_multicast_ttl(lua_State *L); | ||
40 | static int opt_ip_multicast_loop(lua_State *L); | ||
41 | static int opt_ip_add_membership(lua_State *L); | ||
42 | static int opt_ip_drop_membersip(lua_State *L); | ||
38 | 43 | ||
39 | /* udp object methods */ | 44 | /* udp object methods */ |
40 | static luaL_reg udp[] = { | 45 | static luaL_reg udp[] = { |
@@ -57,8 +62,13 @@ static luaL_reg udp[] = { | |||
57 | 62 | ||
58 | /* socket options */ | 63 | /* socket options */ |
59 | static luaL_reg opt[] = { | 64 | static luaL_reg opt[] = { |
60 | {"dontroute", opt_dontroute}, | 65 | {"dontroute", opt_dontroute}, |
61 | {"broadcast", opt_broadcast}, | 66 | {"broadcast", opt_broadcast}, |
67 | {"reuseaddr", opt_reuseaddr}, | ||
68 | {"ip-multicast-ttl", opt_ip_multicast_ttl}, | ||
69 | {"ip-multicast-loop", opt_ip_multicast_loop}, | ||
70 | {"ip-add-membership", opt_ip_add_membership}, | ||
71 | {"ip-drop-membership", opt_ip_drop_membersip}, | ||
62 | {NULL, NULL} | 72 | {NULL, NULL} |
63 | }; | 73 | }; |
64 | 74 | ||
@@ -244,11 +254,72 @@ static int opt_dontroute(lua_State *L) | |||
244 | return opt_boolean(L, SOL_SOCKET, SO_DONTROUTE); | 254 | return opt_boolean(L, SOL_SOCKET, SO_DONTROUTE); |
245 | } | 255 | } |
246 | 256 | ||
257 | static int opt_reuseaddr(lua_State *L) | ||
258 | { | ||
259 | return opt_boolean(L, SOL_SOCKET, SO_REUSEADDR); | ||
260 | } | ||
261 | |||
247 | static int opt_broadcast(lua_State *L) | 262 | static int opt_broadcast(lua_State *L) |
248 | { | 263 | { |
249 | return opt_boolean(L, SOL_SOCKET, SO_BROADCAST); | 264 | return opt_boolean(L, SOL_SOCKET, SO_BROADCAST); |
250 | } | 265 | } |
251 | 266 | ||
267 | static int opt_ip_multicast_loop(lua_State *L) | ||
268 | { | ||
269 | return opt_boolean(L, IPPROTO_IP, IP_MULTICAST_LOOP); | ||
270 | } | ||
271 | |||
272 | static int opt_ip_multicast_ttl(lua_State *L) | ||
273 | { | ||
274 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); | ||
275 | int val = (int) luaL_checknumber(L, 2); | ||
276 | if (setsockopt(udp->sock, IPPROTO_IP, IP_MULTICAST_TTL, | ||
277 | (char *) &val, sizeof(val)) < 0) { | ||
278 | lua_pushnil(L); | ||
279 | lua_pushstring(L, "setsockopt failed"); | ||
280 | return 2; | ||
281 | } | ||
282 | lua_pushnumber(L, 1); | ||
283 | return 1; | ||
284 | } | ||
285 | |||
286 | static int opt_membership(lua_State *L, int level, int name) | ||
287 | { | ||
288 | p_udp udp = (p_udp) aux_checkgroup(L, "udp{any}", 1); | ||
289 | struct ip_mreq val; | ||
290 | if (!lua_istable(L, 2)) | ||
291 | luaL_typerror(L, 2, lua_typename(L, LUA_TTABLE)); | ||
292 | lua_pushstring(L, "multiaddr"); | ||
293 | lua_gettable(L, 2); | ||
294 | if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'group' field"); | ||
295 | if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) | ||
296 | luaL_argerror(L, 3, "invalid 'multiaddr' ip address"); | ||
297 | lua_pushstring(L, "interface"); | ||
298 | lua_gettable(L, 2); | ||
299 | if (!lua_isstring(L, -1)) luaL_argerror(L, 2, "invalid 'interface' field"); | ||
300 | val.imr_interface.s_addr = htonl(INADDR_ANY); | ||
301 | if (strcmp(lua_tostring(L, -1), "*") && | ||
302 | !inet_aton(lua_tostring(L, -1), &val.imr_interface)) | ||
303 | luaL_argerror(L, 3, "invalid 'interface' ip address"); | ||
304 | if (setsockopt(udp->sock, level, name, (char *) &val, sizeof(val)) < 0) { | ||
305 | lua_pushnil(L); | ||
306 | lua_pushstring(L, "setsockopt failed"); | ||
307 | return 2; | ||
308 | } | ||
309 | lua_pushnumber(L, 1); | ||
310 | return 1; | ||
311 | } | ||
312 | |||
313 | static int opt_ip_add_membership(lua_State *L) | ||
314 | { | ||
315 | return opt_membership(L, IPPROTO_IP, IP_ADD_MEMBERSHIP); | ||
316 | } | ||
317 | |||
318 | static int opt_ip_drop_membersip(lua_State *L) | ||
319 | { | ||
320 | return opt_membership(L, IPPROTO_IP, IP_DROP_MEMBERSHIP); | ||
321 | } | ||
322 | |||
252 | /*-------------------------------------------------------------------------*\ | 323 | /*-------------------------------------------------------------------------*\ |
253 | * Just call tm methods | 324 | * Just call tm methods |
254 | \*-------------------------------------------------------------------------*/ | 325 | \*-------------------------------------------------------------------------*/ |
diff --git a/src/usocket.c b/src/usocket.c index f2d9f01..89be85e 100644 --- a/src/usocket.c +++ b/src/usocket.c | |||
@@ -145,7 +145,7 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, | |||
145 | else return IO_TIMEOUT; | 145 | else return IO_TIMEOUT; |
146 | /* here we know the connection has been closed */ | 146 | /* here we know the connection has been closed */ |
147 | } else return IO_CLOSED; | 147 | } else return IO_CLOSED; |
148 | /* here we sent successfully sent something */ | 148 | /* here we successfully sent something */ |
149 | } else { | 149 | } else { |
150 | *sent = put; | 150 | *sent = put; |
151 | return IO_DONE; | 151 | return IO_DONE; |
@@ -159,34 +159,36 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
159 | SA *addr, socklen_t addr_len, int timeout) | 159 | SA *addr, socklen_t addr_len, int timeout) |
160 | { | 160 | { |
161 | t_sock sock = *ps; | 161 | t_sock sock = *ps; |
162 | struct timeval tv; | 162 | ssize_t put; |
163 | fd_set fds; | ||
164 | ssize_t put = 0; | ||
165 | int err; | ||
166 | int ret; | 163 | int ret; |
164 | /* avoid making system calls on closed sockets */ | ||
167 | if (sock == SOCK_INVALID) return IO_CLOSED; | 165 | if (sock == SOCK_INVALID) return IO_CLOSED; |
168 | tv.tv_sec = timeout / 1000; | 166 | /* make sure we repeat in case the call was interrupted */ |
169 | tv.tv_usec = (timeout % 1000) * 1000; | 167 | do put = sendto(sock, data, count, 0, addr, addr_len); |
170 | FD_ZERO(&fds); | 168 | while (put <= 0 && errno == EINTR); |
171 | FD_SET(sock, &fds); | 169 | /* deal with failure */ |
172 | ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | 170 | if (put <= 0) { |
173 | if (ret > 0) { | 171 | /* in any case, nothing has been sent */ |
174 | put = sendto(sock, data, count, 0, addr, addr_len); | ||
175 | if (put <= 0) { | ||
176 | err = IO_CLOSED; | ||
177 | #ifdef __CYGWIN__ | ||
178 | /* this is for CYGWIN, which is like Unix but has Win32 bugs */ | ||
179 | if (sent < 0 && errno == EWOULDBLOCK) err = IO_DONE; | ||
180 | #endif | ||
181 | *sent = 0; | ||
182 | } else { | ||
183 | *sent = put; | ||
184 | err = IO_DONE; | ||
185 | } | ||
186 | return err; | ||
187 | } else { | ||
188 | *sent = 0; | 172 | *sent = 0; |
189 | return IO_TIMEOUT; | 173 | /* run select to avoid busy wait */ |
174 | if (errno != EPIPE) { | ||
175 | struct timeval tv; | ||
176 | fd_set fds; | ||
177 | tv.tv_sec = timeout / 1000; | ||
178 | tv.tv_usec = (timeout % 1000) * 1000; | ||
179 | FD_ZERO(&fds); | ||
180 | FD_SET(sock, &fds); | ||
181 | ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | ||
182 | /* tell the caller to call us again because there is more data */ | ||
183 | if (ret > 0) return IO_DONE; | ||
184 | /* tell the caller there was no data before timeout */ | ||
185 | else return IO_TIMEOUT; | ||
186 | /* here we know the connection has been closed */ | ||
187 | } else return IO_CLOSED; | ||
188 | /* here we successfully sent something */ | ||
189 | } else { | ||
190 | *sent = put; | ||
191 | return IO_DONE; | ||
190 | } | 192 | } |
191 | } | 193 | } |
192 | 194 | ||
@@ -232,28 +234,26 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | |||
232 | SA *addr, socklen_t *addr_len, int timeout) | 234 | SA *addr, socklen_t *addr_len, int timeout) |
233 | { | 235 | { |
234 | t_sock sock = *ps; | 236 | t_sock sock = *ps; |
235 | struct timeval tv; | 237 | ssize_t taken; |
236 | fd_set fds; | ||
237 | int ret; | ||
238 | if (sock == SOCK_INVALID) return IO_CLOSED; | 238 | if (sock == SOCK_INVALID) return IO_CLOSED; |
239 | ssize_t taken = 0; | 239 | do taken = recvfrom(sock, data, count, 0, addr, addr_len); |
240 | tv.tv_sec = timeout / 1000; | 240 | while (taken <= 0 && errno == EINTR); |
241 | tv.tv_usec = (timeout % 1000) * 1000; | 241 | if (taken <= 0) { |
242 | FD_ZERO(&fds); | 242 | struct timeval tv; |
243 | FD_SET(sock, &fds); | 243 | fd_set fds; |
244 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | 244 | int ret; |
245 | if (ret > 0) { | ||
246 | taken = recvfrom(sock, data, count, 0, addr, addr_len); | ||
247 | if (taken <= 0) { | ||
248 | *got = 0; | ||
249 | return IO_CLOSED; | ||
250 | } else { | ||
251 | *got = taken; | ||
252 | return IO_DONE; | ||
253 | } | ||
254 | } else { | ||
255 | *got = 0; | 245 | *got = 0; |
256 | return IO_TIMEOUT; | 246 | if (taken == 0) return IO_CLOSED; |
247 | tv.tv_sec = timeout / 1000; | ||
248 | tv.tv_usec = (timeout % 1000) * 1000; | ||
249 | FD_ZERO(&fds); | ||
250 | FD_SET(sock, &fds); | ||
251 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | ||
252 | if (ret > 0) return IO_DONE; | ||
253 | else return IO_TIMEOUT; | ||
254 | } else { | ||
255 | *got = taken; | ||
256 | return IO_DONE; | ||
257 | } | 257 | } |
258 | } | 258 | } |
259 | 259 | ||
diff --git a/src/wsocket.c b/src/wsocket.c index 59d88df..30208b9 100644 --- a/src/wsocket.c +++ b/src/wsocket.c | |||
@@ -100,7 +100,7 @@ int sock_accept(p_sock ps, p_sock pa, SA *addr, socklen_t *addr_len, | |||
100 | FD_ZERO(&fds); | 100 | FD_ZERO(&fds); |
101 | FD_SET(sock, &fds); | 101 | FD_SET(sock, &fds); |
102 | *pa = SOCK_INVALID; | 102 | *pa = SOCK_INVALID; |
103 | if (select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) <= 0) | 103 | if (select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL) <= 0) |
104 | return IO_TIMEOUT; | 104 | return IO_TIMEOUT; |
105 | if (!addr) addr = &dummy_addr; | 105 | if (!addr) addr = &dummy_addr; |
106 | if (!addr_len) addr_len = &dummy_len; | 106 | if (!addr_len) addr_len = &dummy_len; |
@@ -116,34 +116,35 @@ int sock_send(p_sock ps, const char *data, size_t count, size_t *sent, | |||
116 | int timeout) | 116 | int timeout) |
117 | { | 117 | { |
118 | t_sock sock = *ps; | 118 | t_sock sock = *ps; |
119 | struct timeval tv; | 119 | ssize_t put; |
120 | fd_set fds; | ||
121 | ssize_t put = 0; | ||
122 | if (sock == SOCK_INVALID) return IO_CLOSED; | ||
123 | int err; | ||
124 | int ret; | 120 | int ret; |
125 | tv.tv_sec = timeout / 1000; | 121 | /* avoid making system calls on closed sockets */ |
126 | tv.tv_usec = (timeout % 1000) * 1000; | 122 | if (sock == SOCK_INVALID) return IO_CLOSED; |
127 | FD_ZERO(&fds); | 123 | /* try to send something */ |
128 | FD_SET(sock, &fds); | 124 | put = send(sock, data, (int) count, 0); |
129 | ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | 125 | /* deal with failure */ |
130 | if (ret > 0) { | 126 | if (put <= 0) { |
131 | put = send(sock, data, count, 0); | 127 | /* in any case, nothing has been sent */ |
132 | if (put <= 0) { | ||
133 | /* a bug in WinSock forces us to do a busy wait until we manage | ||
134 | ** to write, because select returns immediately even though it | ||
135 | ** should have blocked us until we could write... */ | ||
136 | if (WSAGetLastError() == WSAEWOULDBLOCK) err = IO_DONE; | ||
137 | else err = IO_CLOSED; | ||
138 | *sent = 0; | ||
139 | } else { | ||
140 | *sent = put; | ||
141 | err = IO_DONE; | ||
142 | } | ||
143 | return err; | ||
144 | } else { | ||
145 | *sent = 0; | 128 | *sent = 0; |
146 | return IO_TIMEOUT; | 129 | /* run select to avoid busy wait */ |
130 | if (WSAGetLastError() == WSAEWOULDBLOCK) { | ||
131 | struct timeval tv; | ||
132 | fd_set fds; | ||
133 | tv.tv_sec = timeout / 1000; | ||
134 | tv.tv_usec = (timeout % 1000) * 1000; | ||
135 | FD_ZERO(&fds); | ||
136 | FD_SET(sock, &fds); | ||
137 | ret = select(0, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | ||
138 | /* tell the caller to call us again because there is more data */ | ||
139 | if (ret > 0) return IO_DONE; | ||
140 | /* tell the caller there was no data before timeout */ | ||
141 | else return IO_TIMEOUT; | ||
142 | /* here we know the connection has been closed */ | ||
143 | } else return IO_CLOSED; | ||
144 | /* here we successfully sent something */ | ||
145 | } else { | ||
146 | *sent = put; | ||
147 | return IO_DONE; | ||
147 | } | 148 | } |
148 | } | 149 | } |
149 | 150 | ||
@@ -154,34 +155,35 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
154 | SA *addr, socklen_t addr_len, int timeout) | 155 | SA *addr, socklen_t addr_len, int timeout) |
155 | { | 156 | { |
156 | t_sock sock = *ps; | 157 | t_sock sock = *ps; |
157 | struct timeval tv; | 158 | ssize_t put; |
158 | fd_set fds; | ||
159 | ssize_t put = 0; | ||
160 | int err; | ||
161 | int ret; | 159 | int ret; |
160 | /* avoid making system calls on closed sockets */ | ||
162 | if (sock == SOCK_INVALID) return IO_CLOSED; | 161 | if (sock == SOCK_INVALID) return IO_CLOSED; |
163 | tv.tv_sec = timeout / 1000; | 162 | /* try to send something */ |
164 | tv.tv_usec = (timeout % 1000) * 1000; | 163 | put = sendto(sock, data, (int) count, 0, addr, addr_len); |
165 | FD_ZERO(&fds); | 164 | /* deal with failure */ |
166 | FD_SET(sock, &fds); | 165 | if (put <= 0) { |
167 | ret = select(sock+1, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | 166 | /* in any case, nothing has been sent */ |
168 | if (ret > 0) { | ||
169 | put = sendto(sock, data, count, 0, addr, addr_len); | ||
170 | if (put <= 0) { | ||
171 | /* a bug in WinSock forces us to do a busy wait until we manage | ||
172 | ** to write, because select returns immediately even though it | ||
173 | ** should have blocked us until we could write... */ | ||
174 | if (WSAGetLastError() == WSAEWOULDBLOCK) err = IO_DONE; | ||
175 | else err = IO_CLOSED; | ||
176 | *sent = 0; | ||
177 | } else { | ||
178 | *sent = put; | ||
179 | err = IO_DONE; | ||
180 | } | ||
181 | return err; | ||
182 | } else { | ||
183 | *sent = 0; | 167 | *sent = 0; |
184 | return IO_TIMEOUT; | 168 | /* run select to avoid busy wait */ |
169 | if (WSAGetLastError() == WSAEWOULDBLOCK) { | ||
170 | struct timeval tv; | ||
171 | fd_set fds; | ||
172 | tv.tv_sec = timeout / 1000; | ||
173 | tv.tv_usec = (timeout % 1000) * 1000; | ||
174 | FD_ZERO(&fds); | ||
175 | FD_SET(sock, &fds); | ||
176 | ret = select(0, NULL, &fds, NULL, timeout >= 0 ? &tv : NULL); | ||
177 | /* tell the caller to call us again because there is more data */ | ||
178 | if (ret > 0) return IO_DONE; | ||
179 | /* tell the caller there was no data before timeout */ | ||
180 | else return IO_TIMEOUT; | ||
181 | /* here we know the connection has been closed */ | ||
182 | } else return IO_CLOSED; | ||
183 | /* here we successfully sent something */ | ||
184 | } else { | ||
185 | *sent = put; | ||
186 | return IO_DONE; | ||
185 | } | 187 | } |
186 | } | 188 | } |
187 | 189 | ||
@@ -191,28 +193,25 @@ int sock_sendto(p_sock ps, const char *data, size_t count, size_t *sent, | |||
191 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) | 193 | int sock_recv(p_sock ps, char *data, size_t count, size_t *got, int timeout) |
192 | { | 194 | { |
193 | t_sock sock = *ps; | 195 | t_sock sock = *ps; |
194 | struct timeval tv; | 196 | ssize_t taken; |
195 | fd_set fds; | ||
196 | int ret; | ||
197 | ssize_t taken = 0; | ||
198 | if (sock == SOCK_INVALID) return IO_CLOSED; | 197 | if (sock == SOCK_INVALID) return IO_CLOSED; |
199 | tv.tv_sec = timeout / 1000; | 198 | taken = recv(sock, data, (int) count, 0); |
200 | tv.tv_usec = (timeout % 1000) * 1000; | 199 | if (taken <= 0) { |
201 | FD_ZERO(&fds); | 200 | struct timeval tv; |
202 | FD_SET(sock, &fds); | 201 | fd_set fds; |
203 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | 202 | int ret; |
204 | if (ret > 0) { | ||
205 | taken = recv(sock, data, count, 0); | ||
206 | if (taken <= 0) { | ||
207 | *got = 0; | ||
208 | return IO_CLOSED; | ||
209 | } else { | ||
210 | *got = taken; | ||
211 | return IO_DONE; | ||
212 | } | ||
213 | } else { | ||
214 | *got = 0; | 203 | *got = 0; |
215 | return IO_TIMEOUT; | 204 | if (taken == 0) return IO_CLOSED; |
205 | tv.tv_sec = timeout / 1000; | ||
206 | tv.tv_usec = (timeout % 1000) * 1000; | ||
207 | FD_ZERO(&fds); | ||
208 | FD_SET(sock, &fds); | ||
209 | ret = select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | ||
210 | if (ret > 0) return IO_DONE; | ||
211 | else return IO_TIMEOUT; | ||
212 | } else { | ||
213 | *got = taken; | ||
214 | return IO_DONE; | ||
216 | } | 215 | } |
217 | } | 216 | } |
218 | 217 | ||
@@ -223,28 +222,25 @@ int sock_recvfrom(p_sock ps, char *data, size_t count, size_t *got, | |||
223 | SA *addr, socklen_t *addr_len, int timeout) | 222 | SA *addr, socklen_t *addr_len, int timeout) |
224 | { | 223 | { |
225 | t_sock sock = *ps; | 224 | t_sock sock = *ps; |
226 | struct timeval tv; | 225 | ssize_t taken; |
227 | fd_set fds; | ||
228 | int ret; | ||
229 | ssize_t taken = 0; | ||
230 | if (sock == SOCK_INVALID) return IO_CLOSED; | 226 | if (sock == SOCK_INVALID) return IO_CLOSED; |
231 | tv.tv_sec = timeout / 1000; | 227 | taken = recvfrom(sock, data, (int) count, 0, addr, addr_len); |
232 | tv.tv_usec = (timeout % 1000) * 1000; | 228 | if (taken <= 0) { |
233 | FD_ZERO(&fds); | 229 | struct timeval tv; |
234 | FD_SET(sock, &fds); | 230 | fd_set fds; |
235 | ret = select(sock+1, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | 231 | int ret; |
236 | if (ret > 0) { | ||
237 | taken = recvfrom(sock, data, count, 0, addr, addr_len); | ||
238 | if (taken <= 0) { | ||
239 | *got = 0; | ||
240 | return IO_CLOSED; | ||
241 | } else { | ||
242 | *got = taken; | ||
243 | return IO_DONE; | ||
244 | } | ||
245 | } else { | ||
246 | *got = 0; | 232 | *got = 0; |
247 | return IO_TIMEOUT; | 233 | if (taken == 0) return IO_CLOSED; |
234 | tv.tv_sec = timeout / 1000; | ||
235 | tv.tv_usec = (timeout % 1000) * 1000; | ||
236 | FD_ZERO(&fds); | ||
237 | FD_SET(sock, &fds); | ||
238 | ret = select(0, &fds, NULL, NULL, timeout >= 0 ? &tv : NULL); | ||
239 | if (ret > 0) return IO_DONE; | ||
240 | else return IO_TIMEOUT; | ||
241 | } else { | ||
242 | *got = taken; | ||
243 | return IO_DONE; | ||
248 | } | 244 | } |
249 | } | 245 | } |
250 | 246 | ||
diff --git a/test/testclnt.lua b/test/testclnt.lua index 2420711..6b07dca 100644 --- a/test/testclnt.lua +++ b/test/testclnt.lua | |||
@@ -99,8 +99,6 @@ else pass("connected!") end | |||
99 | control:setoption("tcp-nodelay", true) | 99 | control:setoption("tcp-nodelay", true) |
100 | 100 | ||
101 | ------------------------------------------------------------------------ | 101 | ------------------------------------------------------------------------ |
102 | test("method registration") | ||
103 | |||
104 | function test_methods(sock, methods) | 102 | function test_methods(sock, methods) |
105 | for _, v in methods do | 103 | for _, v in methods do |
106 | if type(sock[v]) ~= "function" then | 104 | if type(sock[v]) ~= "function" then |
@@ -110,38 +108,7 @@ function test_methods(sock, methods) | |||
110 | pass(sock.class .. " methods are ok") | 108 | pass(sock.class .. " methods are ok") |
111 | end | 109 | end |
112 | 110 | ||
113 | test_methods(socket.tcp(), { | ||
114 | "connect", | ||
115 | "send", | ||
116 | "receive", | ||
117 | "bind", | ||
118 | "accept", | ||
119 | "setpeername", | ||
120 | "setsockname", | ||
121 | "getpeername", | ||
122 | "getsockname", | ||
123 | "setoption", | ||
124 | "settimeout", | ||
125 | "close", | ||
126 | }) | ||
127 | |||
128 | test_methods(socket.udp(), { | ||
129 | "getpeername", | ||
130 | "getsockname", | ||
131 | "setsockname", | ||
132 | "setpeername", | ||
133 | "send", | ||
134 | "sendto", | ||
135 | "receive", | ||
136 | "receivefrom", | ||
137 | "setoption", | ||
138 | "settimeout", | ||
139 | "close", | ||
140 | }) | ||
141 | |||
142 | ------------------------------------------------------------------------ | 111 | ------------------------------------------------------------------------ |
143 | test("mixed patterns") | ||
144 | |||
145 | function test_mixed(len) | 112 | function test_mixed(len) |
146 | reconnect() | 113 | reconnect() |
147 | local inter = math.ceil(len/4) | 114 | local inter = math.ceil(len/4) |
@@ -163,21 +130,7 @@ remote "data:send(str); data:close()" | |||
163 | else fail("patterns don't match") end | 130 | else fail("patterns don't match") end |
164 | end | 131 | end |
165 | 132 | ||
166 | |||
167 | test_mixed(1) | ||
168 | test_mixed(17) | ||
169 | test_mixed(200) | ||
170 | test_mixed(4091) | ||
171 | test_mixed(80199) | ||
172 | test_mixed(4091) | ||
173 | test_mixed(200) | ||
174 | test_mixed(17) | ||
175 | test_mixed(1) | ||
176 | |||
177 | ------------------------------------------------------------------------ | 133 | ------------------------------------------------------------------------ |
178 | test("character line") | ||
179 | reconnect() | ||
180 | |||
181 | function test_asciiline(len) | 134 | function test_asciiline(len) |
182 | local str, str10, back, err | 135 | local str, str10, back, err |
183 | str = string.rep("x", math.mod(len, 10)) | 136 | str = string.rep("x", math.mod(len, 10)) |
@@ -194,22 +147,7 @@ remote "data:send(str, '\\n')" | |||
194 | else fail("lines don't match") end | 147 | else fail("lines don't match") end |
195 | end | 148 | end |
196 | 149 | ||
197 | test_asciiline(1) | ||
198 | test_asciiline(17) | ||
199 | test_asciiline(200) | ||
200 | test_asciiline(4091) | ||
201 | test_asciiline(80199) | ||
202 | test_asciiline(800000) | ||
203 | test_asciiline(80199) | ||
204 | test_asciiline(4091) | ||
205 | test_asciiline(200) | ||
206 | test_asciiline(17) | ||
207 | test_asciiline(1) | ||
208 | |||
209 | ------------------------------------------------------------------------ | 150 | ------------------------------------------------------------------------ |
210 | test("binary line") | ||
211 | reconnect() | ||
212 | |||
213 | function test_rawline(len) | 151 | function test_rawline(len) |
214 | local str, str10, back, err | 152 | local str, str10, back, err |
215 | str = string.rep(string.char(47), math.mod(len, 10)) | 153 | str = string.rep(string.char(47), math.mod(len, 10)) |
@@ -227,22 +165,7 @@ remote "data:send(str, '\\n')" | |||
227 | else fail("lines don't match") end | 165 | else fail("lines don't match") end |
228 | end | 166 | end |
229 | 167 | ||
230 | test_rawline(1) | ||
231 | test_rawline(17) | ||
232 | test_rawline(200) | ||
233 | test_rawline(4091) | ||
234 | test_rawline(80199) | ||
235 | test_rawline(800000) | ||
236 | test_rawline(80199) | ||
237 | test_rawline(4091) | ||
238 | test_rawline(200) | ||
239 | test_rawline(17) | ||
240 | test_rawline(1) | ||
241 | |||
242 | ------------------------------------------------------------------------ | 168 | ------------------------------------------------------------------------ |
243 | test("raw transfer") | ||
244 | reconnect() | ||
245 | |||
246 | function test_raw(len) | 169 | function test_raw(len) |
247 | local half = math.floor(len/2) | 170 | local half = math.floor(len/2) |
248 | local s1, s2, back, err | 171 | local s1, s2, back, err |
@@ -261,38 +184,7 @@ remote "data:send(str)" | |||
261 | else fail("blocks don't match") end | 184 | else fail("blocks don't match") end |
262 | end | 185 | end |
263 | 186 | ||
264 | test_raw(1) | ||
265 | test_raw(17) | ||
266 | test_raw(200) | ||
267 | test_raw(4091) | ||
268 | test_raw(80199) | ||
269 | test_raw(800000) | ||
270 | test_raw(80199) | ||
271 | test_raw(4091) | ||
272 | test_raw(200) | ||
273 | test_raw(17) | ||
274 | test_raw(1) | ||
275 | ------------------------------------------------------------------------ | ||
276 | test("non-blocking transfer") | ||
277 | reconnect() | ||
278 | |||
279 | -- the value is not important, we only want | ||
280 | -- to test non-blockin I/O anyways | ||
281 | data:settimeout(200) | ||
282 | test_raw(1) | ||
283 | test_raw(17) | ||
284 | test_raw(200) | ||
285 | test_raw(4091) | ||
286 | test_raw(80199) | ||
287 | test_raw(800000) | ||
288 | test_raw(80199) | ||
289 | test_raw(4091) | ||
290 | test_raw(200) | ||
291 | test_raw(17) | ||
292 | test_raw(1) | ||
293 | |||
294 | ------------------------------------------------------------------------ | 187 | ------------------------------------------------------------------------ |
295 | test("total timeout on receive") | ||
296 | function test_totaltimeoutreceive(len, tm, sl) | 188 | function test_totaltimeoutreceive(len, tm, sl) |
297 | local str, err, total | 189 | local str, err, total |
298 | reconnect() | 190 | reconnect() |
@@ -311,13 +203,8 @@ function test_totaltimeoutreceive(len, tm, sl) | |||
311 | check_timeout(tm, sl, elapsed, err, "receive", "total", | 203 | check_timeout(tm, sl, elapsed, err, "receive", "total", |
312 | string.len(str) == 2*len) | 204 | string.len(str) == 2*len) |
313 | end | 205 | end |
314 | test_totaltimeoutreceive(800091, 1, 3) | ||
315 | test_totaltimeoutreceive(800091, 2, 3) | ||
316 | test_totaltimeoutreceive(800091, 3, 2) | ||
317 | test_totaltimeoutreceive(800091, 3, 1) | ||
318 | 206 | ||
319 | ------------------------------------------------------------------------ | 207 | ------------------------------------------------------------------------ |
320 | test("total timeout on send") | ||
321 | function test_totaltimeoutsend(len, tm, sl) | 208 | function test_totaltimeoutsend(len, tm, sl) |
322 | local str, err, total | 209 | local str, err, total |
323 | reconnect() | 210 | reconnect() |
@@ -336,13 +223,8 @@ function test_totaltimeoutsend(len, tm, sl) | |||
336 | check_timeout(tm, sl, elapsed, err, "send", "total", | 223 | check_timeout(tm, sl, elapsed, err, "send", "total", |
337 | total == 2*len) | 224 | total == 2*len) |
338 | end | 225 | end |
339 | test_totaltimeoutsend(800091, 1, 3) | ||
340 | test_totaltimeoutsend(800091, 2, 3) | ||
341 | test_totaltimeoutsend(800091, 3, 2) | ||
342 | test_totaltimeoutsend(800091, 3, 1) | ||
343 | 226 | ||
344 | ------------------------------------------------------------------------ | 227 | ------------------------------------------------------------------------ |
345 | test("blocking timeout on receive") | ||
346 | function test_blockingtimeoutreceive(len, tm, sl) | 228 | function test_blockingtimeoutreceive(len, tm, sl) |
347 | local str, err, total | 229 | local str, err, total |
348 | reconnect() | 230 | reconnect() |
@@ -361,13 +243,8 @@ function test_blockingtimeoutreceive(len, tm, sl) | |||
361 | check_timeout(tm, sl, elapsed, err, "receive", "blocking", | 243 | check_timeout(tm, sl, elapsed, err, "receive", "blocking", |
362 | string.len(str) == 2*len) | 244 | string.len(str) == 2*len) |
363 | end | 245 | end |
364 | test_blockingtimeoutreceive(800091, 1, 3) | ||
365 | test_blockingtimeoutreceive(800091, 2, 3) | ||
366 | test_blockingtimeoutreceive(800091, 3, 2) | ||
367 | test_blockingtimeoutreceive(800091, 3, 1) | ||
368 | 246 | ||
369 | ------------------------------------------------------------------------ | 247 | ------------------------------------------------------------------------ |
370 | test("blocking timeout on send") | ||
371 | function test_blockingtimeoutsend(len, tm, sl) | 248 | function test_blockingtimeoutsend(len, tm, sl) |
372 | local str, err, total | 249 | local str, err, total |
373 | reconnect() | 250 | reconnect() |
@@ -386,15 +263,8 @@ function test_blockingtimeoutsend(len, tm, sl) | |||
386 | check_timeout(tm, sl, elapsed, err, "send", "blocking", | 263 | check_timeout(tm, sl, elapsed, err, "send", "blocking", |
387 | total == 2*len) | 264 | total == 2*len) |
388 | end | 265 | end |
389 | test_blockingtimeoutsend(800091, 1, 3) | ||
390 | test_blockingtimeoutsend(800091, 2, 3) | ||
391 | test_blockingtimeoutsend(800091, 3, 2) | ||
392 | test_blockingtimeoutsend(800091, 3, 1) | ||
393 | 266 | ||
394 | ------------------------------------------------------------------------ | 267 | ------------------------------------------------------------------------ |
395 | test("bugs") | ||
396 | |||
397 | io.write("empty host connect: ") | ||
398 | function empty_connect() | 268 | function empty_connect() |
399 | if data then data:close() data = nil end | 269 | if data then data:close() data = nil end |
400 | remote [[ | 270 | remote [[ |
@@ -408,27 +278,25 @@ function empty_connect() | |||
408 | else fail("should not have connected!") end | 278 | else fail("should not have connected!") end |
409 | end | 279 | end |
410 | 280 | ||
411 | empty_connect() | 281 | ------------------------------------------------------------------------ |
282 | function isclosed(c) | ||
283 | return c:fd() == -1 or c:fd() == (2^32-1) | ||
284 | end | ||
412 | 285 | ||
413 | -- io.write("active close: ") | ||
414 | function active_close() | 286 | function active_close() |
415 | reconnect() | 287 | reconnect() |
416 | if socket._isclosed(data) then fail("should not be closed") end | 288 | if isclosed(data) then fail("should not be closed") end |
417 | data:close() | 289 | data:close() |
418 | if not socket._isclosed(data) then fail("should be closed") end | 290 | if not isclosed(data) then fail("should be closed") end |
419 | data = nil | 291 | data = nil |
420 | local udp = socket.udp() | 292 | local udp = socket.udp() |
421 | if socket._isclosed(udp) then fail("should not be closed") end | 293 | if isclosed(udp) then fail("should not be closed") end |
422 | udp:close() | 294 | udp:close() |
423 | if not socket._isclosed(udp) then fail("should be closed") end | 295 | if not isclosed(udp) then fail("should be closed") end |
424 | pass("ok") | 296 | pass("ok") |
425 | end | 297 | end |
426 | 298 | ||
427 | -- active_close() | ||
428 | |||
429 | ------------------------------------------------------------------------ | 299 | ------------------------------------------------------------------------ |
430 | test("closed connection detection") | ||
431 | |||
432 | function test_closed() | 300 | function test_closed() |
433 | local back, err | 301 | local back, err |
434 | local str = 'little string' | 302 | local str = 'little string' |
@@ -453,18 +321,15 @@ function test_closed() | |||
453 | ]] | 321 | ]] |
454 | total, err = data:send(string.rep("ugauga", 100000)) | 322 | total, err = data:send(string.rep("ugauga", 100000)) |
455 | if not err then | 323 | if not err then |
456 | pass("failed: output buffer is at least %d bytes long!", total) | 324 | pass("failed: output buffer is at least %d bytes long!", total) |
457 | elseif err ~= "closed" then | 325 | elseif err ~= "closed" then |
458 | fail("got '"..err.."' instead of 'closed'.") | 326 | fail("got '"..err.."' instead of 'closed'.") |
459 | else | 327 | else |
460 | pass("graceful 'closed' received after %d bytes were sent", total) | 328 | pass("graceful 'closed' received after %d bytes were sent", total) |
461 | end | 329 | end |
462 | end | 330 | end |
463 | 331 | ||
464 | test_closed() | ||
465 | |||
466 | ------------------------------------------------------------------------ | 332 | ------------------------------------------------------------------------ |
467 | test("select function") | ||
468 | function test_selectbugs() | 333 | function test_selectbugs() |
469 | local r, s, e = socket.select(nil, nil, 0.1) | 334 | local r, s, e = socket.select(nil, nil, 0.1) |
470 | assert(type(r) == "table" and type(s) == "table" and e == "timeout") | 335 | assert(type(r) == "table" and type(s) == "table" and e == "timeout") |
@@ -481,7 +346,144 @@ function test_selectbugs() | |||
481 | pass("invalid input: ok") | 346 | pass("invalid input: ok") |
482 | end | 347 | end |
483 | 348 | ||
349 | test("method registration") | ||
350 | test_methods(socket.tcp(), { | ||
351 | "connect", | ||
352 | "send", | ||
353 | "receive", | ||
354 | "bind", | ||
355 | "accept", | ||
356 | "setpeername", | ||
357 | "setsockname", | ||
358 | "getpeername", | ||
359 | "getsockname", | ||
360 | "setoption", | ||
361 | "settimeout", | ||
362 | "close", | ||
363 | }) | ||
364 | test_methods(socket.udp(), { | ||
365 | "getpeername", | ||
366 | "getsockname", | ||
367 | "setsockname", | ||
368 | "setpeername", | ||
369 | "send", | ||
370 | "sendto", | ||
371 | "receive", | ||
372 | "receivefrom", | ||
373 | "setoption", | ||
374 | "settimeout", | ||
375 | "close", | ||
376 | }) | ||
377 | |||
378 | test("mixed patterns") | ||
379 | reconnect() | ||
380 | test_mixed(1) | ||
381 | test_mixed(17) | ||
382 | test_mixed(200) | ||
383 | test_mixed(4091) | ||
384 | test_mixed(801990) | ||
385 | test_mixed(4091) | ||
386 | test_mixed(200) | ||
387 | test_mixed(17) | ||
388 | test_mixed(1) | ||
389 | |||
390 | test("character line") | ||
391 | reconnect() | ||
392 | test_asciiline(1) | ||
393 | test_asciiline(17) | ||
394 | test_asciiline(200) | ||
395 | test_asciiline(4091) | ||
396 | test_asciiline(80199) | ||
397 | test_asciiline(8000000) | ||
398 | test_asciiline(80199) | ||
399 | test_asciiline(4091) | ||
400 | test_asciiline(200) | ||
401 | test_asciiline(17) | ||
402 | test_asciiline(1) | ||
403 | |||
404 | test("binary line") | ||
405 | reconnect() | ||
406 | test_rawline(1) | ||
407 | test_rawline(17) | ||
408 | test_rawline(200) | ||
409 | test_rawline(4091) | ||
410 | test_rawline(80199) | ||
411 | test_rawline(8000000) | ||
412 | test_rawline(80199) | ||
413 | test_rawline(4091) | ||
414 | test_rawline(200) | ||
415 | test_rawline(17) | ||
416 | test_rawline(1) | ||
417 | |||
418 | test("raw transfer") | ||
419 | reconnect() | ||
420 | test_raw(1) | ||
421 | test_raw(17) | ||
422 | test_raw(200) | ||
423 | test_raw(4091) | ||
424 | test_raw(80199) | ||
425 | test_raw(8000000) | ||
426 | test_raw(80199) | ||
427 | test_raw(4091) | ||
428 | test_raw(200) | ||
429 | test_raw(17) | ||
430 | test_raw(1) | ||
431 | |||
432 | test("non-blocking transfer") | ||
433 | reconnect() | ||
434 | -- the value is not important, we only want | ||
435 | -- to test non-blockin I/O anyways | ||
436 | data:settimeout(200) | ||
437 | test_raw(1) | ||
438 | test_raw(17) | ||
439 | test_raw(200) | ||
440 | test_raw(4091) | ||
441 | test_raw(80199) | ||
442 | test_raw(8000000) | ||
443 | test_raw(80199) | ||
444 | test_raw(4091) | ||
445 | test_raw(200) | ||
446 | test_raw(17) | ||
447 | test_raw(1) | ||
448 | |||
449 | test("select function") | ||
484 | test_selectbugs() | 450 | test_selectbugs() |
485 | 451 | ||
452 | test("empty host connect: ") | ||
453 | empty_connect() | ||
454 | |||
455 | test("active close: ") | ||
456 | active_close() | ||
457 | |||
458 | test("closed connection detection: ") | ||
459 | test_closed() | ||
460 | |||
461 | a = [[ | ||
462 | test("total timeout on send") | ||
463 | test_totaltimeoutsend(800091, 1, 3) | ||
464 | test_totaltimeoutsend(800091, 2, 3) | ||
465 | test_totaltimeoutsend(800091, 3, 2) | ||
466 | test_totaltimeoutsend(800091, 3, 1) | ||
467 | |||
468 | test("total timeout on receive") | ||
469 | test_totaltimeoutreceive(800091, 1, 3) | ||
470 | test_totaltimeoutreceive(800091, 2, 3) | ||
471 | test_totaltimeoutreceive(800091, 3, 2) | ||
472 | test_totaltimeoutreceive(800091, 3, 1) | ||
473 | |||
474 | test("blocking timeout on send") | ||
475 | test_blockingtimeoutsend(800091, 1, 3) | ||
476 | test_blockingtimeoutsend(800091, 2, 3) | ||
477 | test_blockingtimeoutsend(800091, 3, 2) | ||
478 | test_blockingtimeoutsend(800091, 3, 1) | ||
479 | |||
480 | test("blocking timeout on receive") | ||
481 | test_blockingtimeoutreceive(800091, 1, 3) | ||
482 | test_blockingtimeoutreceive(800091, 2, 3) | ||
483 | test_blockingtimeoutreceive(800091, 3, 2) | ||
484 | test_blockingtimeoutreceive(800091, 3, 1) | ||
485 | ]] | ||
486 | |||
487 | socket.done() | ||
486 | 488 | ||
487 | test(string.format("done in %.2fs", socket.time() - start)) | 489 | test(string.format("done in %.2fs", socket.time() - start)) |