aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/reference.html2
-rw-r--r--doc/tcp.html193
-rw-r--r--doc/udp.html159
-rw-r--r--src/buffer.c24
-rw-r--r--src/inet.c132
-rw-r--r--src/inet.h10
-rw-r--r--src/io.h2
-rw-r--r--src/socket.lua10
-rw-r--r--src/tcp.c85
-rw-r--r--src/udp.c19
-rw-r--r--src/usocket.c9
-rw-r--r--test/testclnt.lua100
-rw-r--r--test/testsrvr.lua2
-rw-r--r--test/udpconnectclnt.lua2
14 files changed, 398 insertions, 351 deletions
diff --git a/doc/reference.html b/doc/reference.html
index e9bb5eb..6067ba6 100644
--- a/doc/reference.html
+++ b/doc/reference.html
@@ -160,9 +160,11 @@ Support, Manual">
160<a href="socket.html#setsize">_SETSIZE</a>, 160<a href="socket.html#setsize">_SETSIZE</a>,
161<a href="socket.html#source">source</a>, 161<a href="socket.html#source">source</a>,
162<a href="tcp.html#socket.tcp">tcp</a>, 162<a href="tcp.html#socket.tcp">tcp</a>,
163<a href="tcp.html#socket.tcp4">tcp4</a>,
163<a href="tcp.html#socket.tcp6">tcp6</a>, 164<a href="tcp.html#socket.tcp6">tcp6</a>,
164<a href="socket.html#try">try</a>, 165<a href="socket.html#try">try</a>,
165<a href="udp.html#socket.udp">udp</a>, 166<a href="udp.html#socket.udp">udp</a>,
167<a href="udp.html#socket.udp4">udp4</a>,
166<a href="udp.html#socket.udp6">udp6</a>, 168<a href="udp.html#socket.udp6">udp6</a>,
167<a href="socket.html#version">_VERSION</a>. 169<a href="socket.html#version">_VERSION</a>.
168</blockquote> 170</blockquote>
diff --git a/doc/tcp.html b/doc/tcp.html
index 4226d78..6fc9900 100644
--- a/doc/tcp.html
+++ b/doc/tcp.html
@@ -1,10 +1,10 @@
1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 1<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
2 "http://www.w3.org/TR/html4/strict.dtd"> 2 "http://www.w3.org/TR/html4/strict.dtd">
3<html> 3<html>
4 4
5<head> 5<head>
6<meta name="description" content="LuaSocket: The TCP/IP support"> 6<meta name="description" content="LuaSocket: The TCP/IP support">
7<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support"> 7<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support">
8<title>LuaSocket: TCP/IP support</title> 8<title>LuaSocket: TCP/IP support</title>
9<link rel="stylesheet" href="reference.css" type="text/css"> 9<link rel="stylesheet" href="reference.css" type="text/css">
10</head> 10</head>
@@ -28,7 +28,7 @@
28<a href="index.html#download">download</a> &middot; 28<a href="index.html#download">download</a> &middot;
29<a href="installation.html">installation</a> &middot; 29<a href="installation.html">installation</a> &middot;
30<a href="introduction.html">introduction</a> &middot; 30<a href="introduction.html">introduction</a> &middot;
31<a href="reference.html">reference</a> 31<a href="reference.html">reference</a>
32</p> 32</p>
33</center> 33</center>
34<hr> 34<hr>
@@ -36,21 +36,48 @@
36 36
37<!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 37<!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
38 38
39<h2 id="tcp">TCP</h2> 39<h2 id="tcp">TCP</h2>
40 40
41<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 41<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
42 42
43<p class=name id="socket.tcp"> 43<p class=name id="socket.tcp">
44socket.<b>tcp()</b> 44socket.<b>tcp()</b>
45</p> 45</p>
46 46
47<p class=description> 47<p class=description>
48Creates and returns an TCP master object. A master object can
49be transformed into a server object with the method
50<a href=#listen><tt>listen</tt></a> (after a call to <a
51href=#bind><tt>bind</tt></a>) or into a client object with
52the method <a href=#connect><tt>connect</tt></a>. The only other
53method supported by a master object is the
54<a href=#close><tt>close</tt></a> method.</p>
55
56<p class=return>
57In case of success, a new master object is returned. In case of error,
58<b><tt>nil</tt></b> is returned, followed by an error message.
59</p>
60
61<p class=note>
62Note: The choice between IPv4 and IPv6 happens during a call to
63<a href=#bind><tt>bind</tt></a> or <a
64href=#bind><tt>connect</tt></a>, depending on the address
65family obtained from the resolver.
66</p>
67
68<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
69
70<p class=name id="socket.tcp4">
71socket.<b>tcp4()</b>
72</p>
73
74<p class=description>
48Creates and returns an IPv4 TCP master object. A master object can 75Creates and returns an IPv4 TCP master object. A master object can
49be transformed into a server object with the method 76be transformed into a server object with the method
50<a href=#listen><tt>listen</tt></a> (after a call to <a 77<a href=#listen><tt>listen</tt></a> (after a call to <a
51href=#bind><tt>bind</tt></a>) or into a client object with 78href=#bind><tt>bind</tt></a>) or into a client object with
52the method <a href=#connect><tt>connect</tt></a>. The only other 79the method <a href=#connect><tt>connect</tt></a>. The only other
53method supported by a master object is the 80method supported by a master object is the
54<a href=#close><tt>close</tt></a> method.</p> 81<a href=#close><tt>close</tt></a> method.</p>
55 82
56<p class=return> 83<p class=return>
@@ -60,17 +87,17 @@ In case of success, a new master object is returned. In case of error,
60 87
61<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 88<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
62 89
63<p class=name id="socket.tcp6"> 90<p class=name id="socket.tcp6">
64socket.<b>tcp6()</b> 91socket.<b>tcp6()</b>
65</p> 92</p>
66 93
67<p class=description> 94<p class=description>
68Creates and returns an IPv6 TCP master object. A master object can 95Creates and returns an IPv6 TCP master object. A master object can
69be transformed into a server object with the method 96be transformed into a server object with the method
70<a href=#listen><tt>listen</tt></a> (after a call to <a 97<a href=#listen><tt>listen</tt></a> (after a call to <a
71href=#bind><tt>bind</tt></a>) or into a client object with 98href=#bind><tt>bind</tt></a>) or into a client object with
72the method <a href=#connect><tt>connect</tt></a>. The only other 99the method <a href=#connect><tt>connect</tt></a>. The only other
73method supported by a master object is the 100method supported by a master object is the
74<a href=#close><tt>close</tt></a> method.</p> 101<a href=#close><tt>close</tt></a> method.</p>
75 102
76<p class=return> 103<p class=return>
@@ -85,7 +112,7 @@ Note: The TCP object returned will have the option
85 112
86<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 113<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
87 114
88<p class=name id="accept"> 115<p class=name id="accept">
89server:<b>accept()</b> 116server:<b>accept()</b>
90</p> 117</p>
91 118
@@ -95,9 +122,9 @@ object and returns a client object representing that connection.
95</p> 122</p>
96 123
97<p class=return> 124<p class=return>
98If a connection is successfully initiated, a client object is returned. 125If a connection is successfully initiated, a client object is returned.
99If a timeout condition is met, the method returns <b><tt>nil</tt></b> 126If a timeout condition is met, the method returns <b><tt>nil</tt></b>
100followed by the error string '<tt>timeout</tt>'. Other errors are 127followed by the error string '<tt>timeout</tt>'. Other errors are
101reported by <b><tt>nil</tt></b> followed by a message describing the error. 128reported by <b><tt>nil</tt></b> followed by a message describing the error.
102</p> 129</p>
103 130
@@ -107,28 +134,28 @@ with a server object in
107the <tt>recvt</tt> parameter before a call to <tt>accept</tt> does 134the <tt>recvt</tt> parameter before a call to <tt>accept</tt> does
108<em>not</em> guarantee <tt>accept</tt> will return immediately. Use the <a 135<em>not</em> guarantee <tt>accept</tt> will return immediately. Use the <a
109href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt> 136href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt>
110might block until <em>another</em> client shows up. 137might block until <em>another</em> client shows up.
111</p> 138</p>
112 139
113<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 140<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
114 141
115<p class=name id="bind"> 142<p class=name id="bind">
116master:<b>bind(</b>address, port<b>)</b> 143master:<b>bind(</b>address, port<b>)</b>
117</p> 144</p>
118 145
119<p class=description> 146<p class=description>
120Binds a master object to <tt>address</tt> and <tt>port</tt> on the 147Binds a master object to <tt>address</tt> and <tt>port</tt> on the
121local host. 148local host.
122 149
123<p class=parameters> 150<p class=parameters>
124<tt>Address</tt> can be an IP address or a host name. 151<tt>Address</tt> can be an IP address or a host name.
125<tt>Port</tt> must be an integer number in the range [0..64K). 152<tt>Port</tt> must be an integer number in the range [0..64K).
126If <tt>address</tt> 153If <tt>address</tt>
127is '<tt>*</tt>', the system binds to all local interfaces 154is '<tt>*</tt>', the system binds to all local interfaces
128using the <tt>INADDR_ANY</tt> constant or 155using the <tt>INADDR_ANY</tt> constant or
129<tt>IN6ADDR_ANY_INIT</tt>, according to the family. 156<tt>IN6ADDR_ANY_INIT</tt>, according to the family.
130If <tt>port</tt> is 0, the system automatically 157If <tt>port</tt> is 0, the system automatically
131chooses an ephemeral port. 158chooses an ephemeral port.
132</p> 159</p>
133 160
134<p class=return> 161<p class=return>
@@ -137,13 +164,13 @@ method returns <b><tt>nil</tt></b> followed by an error message.
137</p> 164</p>
138 165
139<p class=note> 166<p class=note>
140Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a> 167Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a>
141is available and is a shortcut for the creation of server sockets. 168is available and is a shortcut for the creation of server sockets.
142</p> 169</p>
143 170
144<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 171<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
145 172
146<p class=name id="close"> 173<p class=name id="close">
147master:<b>close()</b><br> 174master:<b>close()</b><br>
148client:<b>close()</b><br> 175client:<b>close()</b><br>
149server:<b>close()</b> 176server:<b>close()</b>
@@ -154,14 +181,14 @@ Closes a TCP object. The internal socket used by the object is closed
154and the local address to which the object was 181and the local address to which the object was
155bound is made available to other applications. No further operations 182bound is made available to other applications. No further operations
156(except for further calls to the <tt>close</tt> method) are allowed on 183(except for further calls to the <tt>close</tt> method) are allowed on
157a closed socket. 184a closed socket.
158</p> 185</p>
159 186
160<p class=note> 187<p class=note>
161Note: It is important to close all used sockets once they are not 188Note: It is important to close all used sockets once they are not
162needed, since, in many systems, each socket uses a file descriptor, 189needed, since, in many systems, each socket uses a file descriptor,
163which are limited system resources. Garbage-collected objects are 190which are limited system resources. Garbage-collected objects are
164automatically closed before destruction, though. 191automatically closed before destruction, though.
165</p> 192</p>
166 193
167<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 194<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -172,19 +199,19 @@ master:<b>connect(</b>address, port<b>)</b>
172 199
173<p class=description> 200<p class=description>
174Attempts to connect a master object to a remote host, transforming it into a 201Attempts to connect a master object to a remote host, transforming it into a
175client object. 202client object.
176Client objects support methods 203Client objects support methods
177<a href=#send><tt>send</tt></a>, 204<a href=#send><tt>send</tt></a>,
178<a href=#receive><tt>receive</tt></a>, 205<a href=#receive><tt>receive</tt></a>,
179<a href=#getsockname><tt>getsockname</tt></a>, 206<a href=#getsockname><tt>getsockname</tt></a>,
180<a href=#getpeername><tt>getpeername</tt></a>, 207<a href=#getpeername><tt>getpeername</tt></a>,
181<a href=#settimeout><tt>settimeout</tt></a>, 208<a href=#settimeout><tt>settimeout</tt></a>,
182and <a href=#close><tt>close</tt></a>. 209and <a href=#close><tt>close</tt></a>.
183</p> 210</p>
184 211
185<p class=parameters> 212<p class=parameters>
186<tt>Address</tt> can be an IP address or a host name. 213<tt>Address</tt> can be an IP address or a host name.
187<tt>Port</tt> must be an integer number in the range [1..64K). 214<tt>Port</tt> must be an integer number in the range [1..64K).
188</p> 215</p>
189 216
190<p class=return> 217<p class=return>
@@ -193,14 +220,14 @@ describing the error. In case of success, the method returns 1.
193</p> 220</p>
194 221
195<p class=note> 222<p class=note>
196Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a> 223Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a>
197is available and is a shortcut for the creation of client sockets. 224is available and is a shortcut for the creation of client sockets.
198</p> 225</p>
199 226
200<p class=note> 227<p class=note>
201Note: Starting with LuaSocket 2.0, 228Note: Starting with LuaSocket 2.0,
202the <a href=#settimeout><tt>settimeout</tt></a> 229the <a href=#settimeout><tt>settimeout</tt></a>
203method affects the behavior of <tt>connect</tt>, causing it to return 230method affects the behavior of <tt>connect</tt>, causing it to return
204with an error in case of a timeout. If that happens, you can still call <a 231with an error in case of a timeout. If that happens, you can still call <a
205href=socket.html#select><tt>socket.select</tt></a> with the socket in the 232href=socket.html#select><tt>socket.select</tt></a> with the socket in the
206<tt>sendt</tt> table. The socket will be writable when the connection is 233<tt>sendt</tt> table. The socket will be writable when the connection is
@@ -227,10 +254,10 @@ Returns information about the remote side of a connected client object.
227</p> 254</p>
228 255
229<p class=return> 256<p class=return>
230Returns a string with the IP address of the peer, the 257Returns a string with the IP address of the peer, the
231port number that peer is using for the connection, 258port number that peer is using for the connection,
232and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 259and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
233In case of error, the method returns <b><tt>nil</tt></b>. 260In case of error, the method returns <b><tt>nil</tt></b>.
234</p> 261</p>
235 262
236<p class=note> 263<p class=note>
@@ -246,13 +273,13 @@ server:<b>getsockname()</b>
246</p> 273</p>
247 274
248<p class=description> 275<p class=description>
249Returns the local address information associated to the object. 276Returns the local address information associated to the object.
250</p> 277</p>
251 278
252<p class=return> 279<p class=return>
253The method returns a string with local IP address, a number with 280The method returns a string with local IP address, a number with
254the local port, 281the local port,
255and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 282and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
256In case of error, the method returns <b><tt>nil</tt></b>. 283In case of error, the method returns <b><tt>nil</tt></b>.
257</p> 284</p>
258 285
@@ -266,32 +293,32 @@ server:<b>getstats()</b><br>
266 293
267<p class=description> 294<p class=description>
268Returns accounting information on the socket, useful for throttling 295Returns accounting information on the socket, useful for throttling
269of bandwidth. 296of bandwidth.
270</p> 297</p>
271 298
272<p class=return> 299<p class=return>
273The method returns the number of bytes received, the number of bytes sent, 300The method returns the number of bytes received, the number of bytes sent,
274and the age of the socket object in seconds. 301and the age of the socket object in seconds.
275</p> 302</p>
276 303
277<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 304<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
278 305
279<p class=name id="listen"> 306<p class=name id="listen">
280master:<b>listen(</b>backlog<b>)</b> 307master:<b>listen(</b>backlog<b>)</b>
281</p> 308</p>
282 309
283<p class=description> 310<p class=description>
284Specifies the socket is willing to receive connections, transforming the 311Specifies the socket is willing to receive connections, transforming the
285object into a server object. Server objects support the 312object into a server object. Server objects support the
286<a href=#accept><tt>accept</tt></a>, 313<a href=#accept><tt>accept</tt></a>,
287<a href=#getsockname><tt>getsockname</tt></a>, 314<a href=#getsockname><tt>getsockname</tt></a>,
288<a href=#setoption><tt>setoption</tt></a>, 315<a href=#setoption><tt>setoption</tt></a>,
289<a href=#settimeout><tt>settimeout</tt></a>, 316<a href=#settimeout><tt>settimeout</tt></a>,
290and <a href=#close><tt>close</tt></a> methods. 317and <a href=#close><tt>close</tt></a> methods.
291</p> 318</p>
292 319
293<p class=parameters> 320<p class=parameters>
294The parameter <tt>backlog</tt> specifies the number of client 321The parameter <tt>backlog</tt> specifies the number of client
295connections that can 322connections that can
296be queued waiting for service. If the queue is full and another client 323be queued waiting for service. If the queue is full and another client
297attempts connection, the connection is refused. 324attempts connection, the connection is refused.
@@ -310,11 +337,11 @@ client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
310 337
311<p class=description> 338<p class=description>
312Reads data from a client object, according to the specified <em>read 339Reads data from a client object, according to the specified <em>read
313pattern</em>. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible. 340pattern</em>. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible.
314</p> 341</p>
315 342
316<p class=parameters> 343<p class=parameters>
317<tt>Pattern</tt> can be any of the following: 344<tt>Pattern</tt> can be any of the following:
318</p> 345</p>
319 346
320<ul> 347<ul>
@@ -325,7 +352,7 @@ terminated by a LF character (ASCII&nbsp;10), optionally preceded by a
325CR character (ASCII&nbsp;13). The CR and LF characters are not included in 352CR character (ASCII&nbsp;13). The CR and LF characters are not included in
326the returned line. In fact, <em>all</em> CR characters are 353the returned line. In fact, <em>all</em> CR characters are
327ignored by the pattern. This is the default pattern; 354ignored by the pattern. This is the default pattern;
328<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt> 355<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
329of bytes from the socket. 356of bytes from the socket.
330</ul> 357</ul>
331 358
@@ -347,10 +374,10 @@ closed before the transmission was completed or the string
347<p class=note> 374<p class=note>
348<b>Important note</b>: This function was changed <em>severely</em>. It used 375<b>Important note</b>: This function was changed <em>severely</em>. It used
349to support multiple patterns (but I have never seen this feature used) and 376to support multiple patterns (but I have never seen this feature used) and
350now it doesn't anymore. Partial results used to be returned in the same 377now it doesn't anymore. Partial results used to be returned in the same
351way as successful results. This last feature violated the idea that all 378way as successful results. This last feature violated the idea that all
352functions should return <tt><b>nil</b></tt> on error. Thus it was changed 379functions should return <tt><b>nil</b></tt> on error. Thus it was changed
353too. 380too.
354</p> 381</p>
355 382
356<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 383<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -366,7 +393,7 @@ Sends <tt>data</tt> through client object.
366<p class=parameters> 393<p class=parameters>
367<tt>Data</tt> is the string to be sent. The optional arguments 394<tt>Data</tt> is the string to be sent. The optional arguments
368<tt>i</tt> and <tt>j</tt> work exactly like the standard 395<tt>i</tt> and <tt>j</tt> work exactly like the standard
369<tt>string.sub</tt> Lua function to allow the selection of a 396<tt>string.sub</tt> Lua function to allow the selection of a
370substring to be sent. 397substring to be sent.
371</p> 398</p>
372 399
@@ -385,10 +412,10 @@ there was a timeout during the operation.
385</p> 412</p>
386 413
387<p class=note> 414<p class=note>
388Note: Output is <em>not</em> buffered. For small strings, 415Note: Output is <em>not</em> buffered. For small strings,
389it is always better to concatenate them in Lua 416it is always better to concatenate them in Lua
390(with the '<tt>..</tt>' operator) and send the result in one call 417(with the '<tt>..</tt>' operator) and send the result in one call
391instead of calling the method several times. 418instead of calling the method several times.
392</p> 419</p>
393 420
394<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 421<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -400,12 +427,12 @@ server:<b>setoption(</b>option [, value]<b>)</b>
400 427
401<p class=description> 428<p class=description>
402Sets options for the TCP object. Options are only needed by low-level or 429Sets options for the TCP object. Options are only needed by low-level or
403time-critical applications. You should only modify an option if you 430time-critical applications. You should only modify an option if you
404are sure you need it. 431are sure you need it.
405</p> 432</p>
406 433
407<p class=parameters> 434<p class=parameters>
408<tt>Option</tt> is a string with the option name, and <tt>value</tt> 435<tt>Option</tt> is a string with the option name, and <tt>value</tt>
409depends on the option being set: 436depends on the option being set:
410 437
411<ul> 438<ul>
@@ -413,7 +440,7 @@ depends on the option being set:
413<li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables 440<li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables
414the periodic transmission of messages on a connected socket. Should the 441the periodic transmission of messages on a connected socket. Should the
415connected party fail to respond to these messages, the connection is 442connected party fail to respond to these messages, the connection is
416considered broken and processes using the socket are notified; 443considered broken and processes using the socket are notified;
417 444
418<li> '<tt>linger</tt>': Controls the action taken when unsent data are 445<li> '<tt>linger</tt>': Controls the action taken when unsent data are
419queued on a socket and a close is performed. The value is a table with a 446queued on a socket and a close is performed. The value is a table with a
@@ -424,13 +451,13 @@ it is able to transmit the data or until '<tt>timeout</tt>' has passed. If
424'<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will 451'<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will
425process the close in a manner that allows the process to continue as 452process the close in a manner that allows the process to continue as
426quickly as possible. I do not advise you to set this to anything other than 453quickly as possible. I do not advise you to set this to anything other than
427zero; 454zero;
428 455
429<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules 456<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules
430used in validating addresses supplied in a call to 457used in validating addresses supplied in a call to
431<a href=#bind><tt>bind</tt></a> should allow reuse of local addresses; 458<a href=#bind><tt>bind</tt></a> should allow reuse of local addresses;
432 459
433<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt> 460<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt>
434disables the Nagle's algorithm for the connection; 461disables the Nagle's algorithm for the connection;
435 462
436<li> '<tt>ipv6-v6only</tt>': 463<li> '<tt>ipv6-v6only</tt>':
@@ -485,7 +512,7 @@ server:<b>setstats(</b>received, sent, age<b>)</b><br>
485 512
486<p class=description> 513<p class=description>
487Resets accounting information on the socket, useful for throttling 514Resets accounting information on the socket, useful for throttling
488of bandwidth. 515of bandwidth.
489</p> 516</p>
490 517
491<p class=parameters> 518<p class=parameters>
@@ -495,7 +522,7 @@ of bandwidth.
495</p> 522</p>
496 523
497<p class=return> 524<p class=return>
498The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise. 525The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
499</p> 526</p>
500 527
501<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 528<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -509,8 +536,8 @@ server:<b>settimeout(</b>value [, mode]<b>)</b>
509<p class=description> 536<p class=description>
510Changes the timeout values for the object. By default, 537Changes the timeout values for the object. By default,
511all I/O operations are blocking. That is, any call to the methods 538all I/O operations are blocking. That is, any call to the methods
512<a href=#send><tt>send</tt></a>, 539<a href=#send><tt>send</tt></a>,
513<a href=#receive><tt>receive</tt></a>, and 540<a href=#receive><tt>receive</tt></a>, and
514<a href=#accept><tt>accept</tt></a> 541<a href=#accept><tt>accept</tt></a>
515will block indefinitely, until the operation completes. The 542will block indefinitely, until the operation completes. The
516<tt>settimeout</tt> method defines a limit on the amount of time the 543<tt>settimeout</tt> method defines a limit on the amount of time the
@@ -521,7 +548,7 @@ time has elapsed, the affected methods give up and fail with an error code.
521<p class=parameters> 548<p class=parameters>
522The amount of time to wait is specified as the 549The amount of time to wait is specified as the
523<tt>value</tt> parameter, in seconds. There are two timeout modes and 550<tt>value</tt> parameter, in seconds. There are two timeout modes and
524both can be used together for fine tuning: 551both can be used together for fine tuning:
525</p> 552</p>
526 553
527<ul> 554<ul>
@@ -532,7 +559,7 @@ default mode;</li>
532 559
533<li> '<tt>t</tt>': <em>total</em> timeout. Specifies the upper limit on 560<li> '<tt>t</tt>': <em>total</em> timeout. Specifies the upper limit on
534the amount of time LuaSocket can block a Lua script before returning from 561the amount of time LuaSocket can block a Lua script before returning from
535a call.</li> 562a call.</li>
536</ul> 563</ul>
537 564
538<p class=parameters> 565<p class=parameters>
@@ -562,7 +589,7 @@ client:<b>shutdown(</b>mode<b>)</b><br>
562</p> 589</p>
563 590
564<p class=description> 591<p class=description>
565Shuts down part of a full-duplex connection. 592Shuts down part of a full-duplex connection.
566</p> 593</p>
567 594
568<p class=parameters> 595<p class=parameters>
@@ -608,7 +635,7 @@ server:<b>getfd()</b>
608</p> 635</p>
609 636
610<p class=description> 637<p class=description>
611Returns the underling socket descriptor or handle associated to the object. 638Returns the underling socket descriptor or handle associated to the object.
612</p> 639</p>
613 640
614<p class=return> 641<p class=return>
diff --git a/doc/udp.html b/doc/udp.html
index e5b0ad0..e313af4 100644
--- a/doc/udp.html
+++ b/doc/udp.html
@@ -4,7 +4,7 @@
4 4
5<head> 5<head>
6<meta name="description" content="LuaSocket: The UDP support"> 6<meta name="description" content="LuaSocket: The UDP support">
7<meta name="keywords" content="Lua, LuaSocket, Socket, UDP, Library, Network, Support"> 7<meta name="keywords" content="Lua, LuaSocket, Socket, UDP, Library, Network, Support">
8<title>LuaSocket: UDP support</title> 8<title>LuaSocket: UDP support</title>
9<link rel="stylesheet" href="reference.css" type="text/css"> 9<link rel="stylesheet" href="reference.css" type="text/css">
10</head> 10</head>
@@ -28,7 +28,7 @@
28<a href="index.html#download">download</a> &middot; 28<a href="index.html#download">download</a> &middot;
29<a href="installation.html">installation</a> &middot; 29<a href="installation.html">installation</a> &middot;
30<a href="introduction.html">introduction</a> &middot; 30<a href="introduction.html">introduction</a> &middot;
31<a href="reference.html">reference</a> 31<a href="reference.html">reference</a>
32</p> 32</p>
33</center> 33</center>
34<hr> 34<hr>
@@ -37,7 +37,7 @@
37 37
38<!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 38<!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
39 39
40<h2 id="udp">UDP</h2> 40<h2 id="udp">UDP</h2>
41 41
42<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 42<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
43 43
@@ -46,19 +46,56 @@ socket.<b>udp()</b>
46</p> 46</p>
47 47
48<p class="description"> 48<p class="description">
49Creates and returns an unconnected IPv4 UDP object. 49Creates and returns an unconnected UDP object.
50Unconnected objects support the 50Unconnected objects support the
51<a href="#sendto"><tt>sendto</tt></a>, 51<a href="#sendto"><tt>sendto</tt></a>,
52<a href="#receive"><tt>receive</tt></a>, 52<a href="#receive"><tt>receive</tt></a>,
53<a href="#receivefrom"><tt>receivefrom</tt></a>, 53<a href="#receivefrom"><tt>receivefrom</tt></a>,
54<a href="#getoption"><tt>getoption</tt></a>, 54<a href="#getoption"><tt>getoption</tt></a>,
55<a href="#getsockname"><tt>getsockname</tt></a>, 55<a href="#getsockname"><tt>getsockname</tt></a>,
56<a href="#setoption"><tt>setoption</tt></a>, 56<a href="#setoption"><tt>setoption</tt></a>,
57<a href="#settimeout"><tt>settimeout</tt></a>, 57<a href="#settimeout"><tt>settimeout</tt></a>,
58<a href="#setpeername"><tt>setpeername</tt></a>, 58<a href="#setpeername"><tt>setpeername</tt></a>,
59<a href="#setsockname"><tt>setsockname</tt></a>, and 59<a href="#setsockname"><tt>setsockname</tt></a>, and
60<a href="#close"><tt>close</tt></a>. 60<a href="#close"><tt>close</tt></a>.
61The <a href="#setpeername"><tt>setpeername</tt></a> 61The <a href="#setpeername"><tt>setpeername</tt></a>
62is used to connect the object.
63</p>
64
65<p class="return">
66In case of success, a new unconnected UDP object
67returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
68an error message.
69</p>
70
71<p class=note>
72Note: The choice between IPv4 and IPv6 happens during a call to
73<a href=#sendto><tt>sendto</tt></a>, <a
74href=#setpeername><tt>setpeername</tt></a>, or <a
75href=#setsockname><tt>sockname</tt></a>, depending on the address
76family obtained from the resolver.
77</p>
78
79<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
80
81<p class="name" id="socket.udp">
82socket.<b>udp4()</b>
83</p>
84
85<p class="description">
86Creates and returns an unconnected IPv4 UDP object.
87Unconnected objects support the
88<a href="#sendto"><tt>sendto</tt></a>,
89<a href="#receive"><tt>receive</tt></a>,
90<a href="#receivefrom"><tt>receivefrom</tt></a>,
91<a href="#getoption"><tt>getoption</tt></a>,
92<a href="#getsockname"><tt>getsockname</tt></a>,
93<a href="#setoption"><tt>setoption</tt></a>,
94<a href="#settimeout"><tt>settimeout</tt></a>,
95<a href="#setpeername"><tt>setpeername</tt></a>,
96<a href="#setsockname"><tt>setsockname</tt></a>, and
97<a href="#close"><tt>close</tt></a>.
98The <a href="#setpeername"><tt>setpeername</tt></a>
62is used to connect the object. 99is used to connect the object.
63</p> 100</p>
64 101
@@ -75,19 +112,19 @@ socket.<b>udp6()</b>
75</p> 112</p>
76 113
77<p class="description"> 114<p class="description">
78Creates and returns an unconnected IPv6 UDP object. 115Creates and returns an unconnected IPv6 UDP object.
79Unconnected objects support the 116Unconnected objects support the
80<a href="#sendto"><tt>sendto</tt></a>, 117<a href="#sendto"><tt>sendto</tt></a>,
81<a href="#receive"><tt>receive</tt></a>, 118<a href="#receive"><tt>receive</tt></a>,
82<a href="#receivefrom"><tt>receivefrom</tt></a>, 119<a href="#receivefrom"><tt>receivefrom</tt></a>,
83<a href="#getoption"><tt>getoption</tt></a>, 120<a href="#getoption"><tt>getoption</tt></a>,
84<a href="#getsockname"><tt>getsockname</tt></a>, 121<a href="#getsockname"><tt>getsockname</tt></a>,
85<a href="#setoption"><tt>setoption</tt></a>, 122<a href="#setoption"><tt>setoption</tt></a>,
86<a href="#settimeout"><tt>settimeout</tt></a>, 123<a href="#settimeout"><tt>settimeout</tt></a>,
87<a href="#setpeername"><tt>setpeername</tt></a>, 124<a href="#setpeername"><tt>setpeername</tt></a>,
88<a href="#setsockname"><tt>setsockname</tt></a>, and 125<a href="#setsockname"><tt>setsockname</tt></a>, and
89<a href="#close"><tt>close</tt></a>. 126<a href="#close"><tt>close</tt></a>.
90The <a href="#setpeername"><tt>setpeername</tt></a> 127The <a href="#setpeername"><tt>setpeername</tt></a>
91is used to connect the object. 128is used to connect the object.
92</p> 129</p>
93 130
@@ -102,10 +139,6 @@ Note: The TCP object returned will have the option
102"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>. 139"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
103</p> 140</p>
104 141
105
106
107<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
108
109<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 142<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
110 143
111<p class="name" id="close"> 144<p class="name" id="close">
@@ -142,10 +175,10 @@ associated with a connected UDP object.
142 175
143 176
144<p class=return> 177<p class=return>
145Returns a string with the IP address of the peer, the 178Returns a string with the IP address of the peer, the
146port number that peer is using for the connection, 179port number that peer is using for the connection,
147and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 180and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
148In case of error, the method returns <b><tt>nil</tt></b>. 181In case of error, the method returns <b><tt>nil</tt></b>.
149</p> 182</p>
150 183
151<p class="note"> 184<p class="note">
@@ -165,9 +198,9 @@ Returns the local address information associated to the object.
165 198
166 199
167<p class=return> 200<p class=return>
168The method returns a string with local IP address, a number with 201The method returns a string with local IP address, a number with
169the local port, 202the local port,
170and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 203and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
171In case of error, the method returns <b><tt>nil</tt></b>. 204In case of error, the method returns <b><tt>nil</tt></b>.
172</p> 205</p>
173 206
@@ -217,7 +250,7 @@ unconnected:<b>receivefrom(</b>[size]<b>)</b>
217</p> 250</p>
218 251
219<p class="description"> 252<p class="description">
220Works exactly as the <a href="#receive"><tt>receive</tt></a> 253Works exactly as the <a href="#receive"><tt>receive</tt></a>
221method, except it returns the IP 254method, except it returns the IP
222address and port as extra return values (and is therefore slightly less 255address and port as extra return values (and is therefore slightly less
223efficient). 256efficient).
@@ -236,7 +269,7 @@ See <a href=#setoption><tt>setoption</tt></a> for
236description of the option names and values. 269description of the option names and values.
237</p> 270</p>
238 271
239<p class="parameters"><tt>Option</tt> is a string with the option name. 272<p class="parameters"><tt>Option</tt> is a string with the option name.
240<ul> 273<ul>
241<li> '<tt>dontroute</tt>' 274<li> '<tt>dontroute</tt>'
242<li> '<tt>broadcast</tt>' 275<li> '<tt>broadcast</tt>'
@@ -246,9 +279,9 @@ description of the option names and values.
246<li> '<tt>ipv6-v6only</tt>' 279<li> '<tt>ipv6-v6only</tt>'
247<li> '<tt>ip-multicast-if</tt>' 280<li> '<tt>ip-multicast-if</tt>'
248<li> '<tt>ip-multicast-ttl</tt>' 281<li> '<tt>ip-multicast-ttl</tt>'
249<li> '<tt>ip-add-membership</tt>' 282<li> '<tt>ip-add-membership</tt>'
250<li> '<tt>ip-drop-membership</tt>' 283<li> '<tt>ip-drop-membership</tt>'
251</ul> 284</ul>
252</p> 285</p>
253 286
254<p class=return> 287<p class=return>
@@ -268,7 +301,7 @@ Sends a datagram to the UDP peer of a connected object.
268</p> 301</p>
269 302
270<p class="parameters"> 303<p class="parameters">
271<tt>Datagram</tt> is a string with the datagram contents. 304<tt>Datagram</tt> is a string with the datagram contents.
272The maximum datagram size for UDP is 64K minus IP layer overhead. 305The maximum datagram size for UDP is 64K minus IP layer overhead.
273However datagrams larger than the link layer packet size will be 306However datagrams larger than the link layer packet size will be
274fragmented, which may deteriorate performance and/or reliability. 307fragmented, which may deteriorate performance and/or reliability.
@@ -298,11 +331,11 @@ Sends a datagram to the specified IP address and port number.
298 331
299<p class="parameters"> 332<p class="parameters">
300<tt>Datagram</tt> is a string with the 333<tt>Datagram</tt> is a string with the
301datagram contents. 334datagram contents.
302The maximum datagram size for UDP is 64K minus IP layer overhead. 335The maximum datagram size for UDP is 64K minus IP layer overhead.
303However datagrams larger than the link layer packet size will be 336However datagrams larger than the link layer packet size will be
304fragmented, which may deteriorate performance and/or reliability. 337fragmented, which may deteriorate performance and/or reliability.
305<tt>Ip</tt> is the IP address of the recipient. 338<tt>Ip</tt> is the IP address of the recipient.
306Host names are <em>not</em> allowed for performance reasons. 339Host names are <em>not</em> allowed for performance reasons.
307 340
308<tt>Port</tt> is the port number at the recipient. 341<tt>Port</tt> is the port number at the recipient.
@@ -337,9 +370,9 @@ object or vice versa.
337For connected objects, outgoing datagrams 370For connected objects, outgoing datagrams
338will be sent to the specified peer, and datagrams received from 371will be sent to the specified peer, and datagrams received from
339other peers will be discarded by the OS. Connected UDP objects must 372other peers will be discarded by the OS. Connected UDP objects must
340use the <a href="#send"><tt>send</tt></a> and 373use the <a href="#send"><tt>send</tt></a> and
341<a href="#receive"><tt>receive</tt></a> methods instead of 374<a href="#receive"><tt>receive</tt></a> methods instead of
342<a href="#sendto"><tt>sendto</tt></a> and 375<a href="#sendto"><tt>sendto</tt></a> and
343<a href="#receivefrom"><tt>receivefrom</tt></a>. 376<a href="#receivefrom"><tt>receivefrom</tt></a>.
344</p> 377</p>
345 378
@@ -421,16 +454,16 @@ only modify an option if you are sure you need it.</p>
421name, and <tt>value</tt> depends on the option being set: 454name, and <tt>value</tt> depends on the option being set:
422</p> 455</p>
423 456
424<ul> 457<ul>
425<li> '<tt>dontroute</tt>': Indicates that outgoing 458<li> '<tt>dontroute</tt>': Indicates that outgoing
426messages should bypass the standard routing facilities. 459messages should bypass the standard routing facilities.
427Receives a boolean value; 460Receives a boolean value;
428<li> '<tt>broadcast</tt>': Requests permission to send 461<li> '<tt>broadcast</tt>': Requests permission to send
429broadcast datagrams on the socket. 462broadcast datagrams on the socket.
430Receives a boolean value; 463Receives a boolean value;
431<li> '<tt>reuseaddr</tt>': Indicates that the rules used in 464<li> '<tt>reuseaddr</tt>': Indicates that the rules used in
432validating addresses supplied in a <tt>bind()</tt> call 465validating addresses supplied in a <tt>bind()</tt> call
433should allow reuse of local addresses. 466should allow reuse of local addresses.
434Receives a boolean value; 467Receives a boolean value;
435<li> '<tt>reuseport</tt>': Allows completely duplicate 468<li> '<tt>reuseport</tt>': Allows completely duplicate
436bindings by multiple processes if they all set 469bindings by multiple processes if they all set
@@ -442,7 +475,7 @@ datagram is delivered to the sending host as long as it is a
442member of the multicast group. 475member of the multicast group.
443Receives a boolean value; 476Receives a boolean value;
444<li> '<tt>ipv6-v6only</tt>': 477<li> '<tt>ipv6-v6only</tt>':
445Specifies whether to restrict <tt>inet6</tt> sockets to 478Specifies whether to restrict <tt>inet6</tt> sockets to
446sending and receiving only IPv6 packets. 479sending and receiving only IPv6 packets.
447Receive a boolean value; 480Receive a boolean value;
448<li> '<tt>ip-multicast-if</tt>': 481<li> '<tt>ip-multicast-if</tt>':
@@ -451,9 +484,9 @@ are sent.
451Receives an IP address; 484Receives an IP address;
452<li> '<tt>ip-multicast-ttl</tt>': 485<li> '<tt>ip-multicast-ttl</tt>':
453Sets the Time To Live in the IP header for outgoing 486Sets the Time To Live in the IP header for outgoing
454multicast datagrams. 487multicast datagrams.
455Receives a number; 488Receives a number;
456<li> '<tt>ip-add-membership</tt>': 489<li> '<tt>ip-add-membership</tt>':
457Joins the multicast group specified. 490Joins the multicast group specified.
458Receives a table with fields 491Receives a table with fields
459<tt>multiaddr</tt> and <tt>interface</tt>, each containing an 492<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
@@ -463,7 +496,7 @@ group specified.
463Receives a table with fields 496Receives a table with fields
464<tt>multiaddr</tt> and <tt>interface</tt>, each containing an 497<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
465IP address. 498IP address.
466</ul> 499</ul>
467 500
468<p class="return"> 501<p class="return">
469The method returns 1 in case of success, or 502The method returns 1 in case of success, or
@@ -482,14 +515,14 @@ unconnected:<b>settimeout(</b>value<b>)</b>
482</p> 515</p>
483 516
484<p class="description"> 517<p class="description">
485Changes the timeout values for the object. By default, the 518Changes the timeout values for the object. By default, the
486<a href="#receive"><tt>receive</tt></a> and 519<a href="#receive"><tt>receive</tt></a> and
487<a href="#receivefrom"><tt>receivefrom</tt></a> 520<a href="#receivefrom"><tt>receivefrom</tt></a>
488operations are blocking. That is, any call to the methods will block 521operations are blocking. That is, any call to the methods will block
489indefinitely, until data arrives. The <tt>settimeout</tt> function defines 522indefinitely, until data arrives. The <tt>settimeout</tt> function defines
490a limit on the amount of time the functions can block. When a timeout is 523a limit on the amount of time the functions can block. When a timeout is
491set and the specified amount of time has elapsed, the affected methods 524set and the specified amount of time has elapsed, the affected methods
492give up and fail with an error code. 525give up and fail with an error code.
493</p> 526</p>
494 527
495<p class="parameters"> 528<p class="parameters">
@@ -524,7 +557,7 @@ imperative nature obvious.
524<a href="index.html#download">download</a> &middot; 557<a href="index.html#download">download</a> &middot;
525<a href="installation.html">installation</a> &middot; 558<a href="installation.html">installation</a> &middot;
526<a href="introduction.html">introduction</a> &middot; 559<a href="introduction.html">introduction</a> &middot;
527<a href="reference.html">reference</a> 560<a href="reference.html">reference</a>
528</p> 561</p>
529<p> 562<p>
530<small> 563<small>
diff --git a/src/buffer.c b/src/buffer.c
index 8fc1166..fff1634 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -38,7 +38,7 @@ int buffer_open(lua_State *L) {
38} 38}
39 39
40/*-------------------------------------------------------------------------*\ 40/*-------------------------------------------------------------------------*\
41* Initializes C structure 41* Initializes C structure
42\*-------------------------------------------------------------------------*/ 42\*-------------------------------------------------------------------------*/
43void buffer_init(p_buffer buf, p_io io, p_timeout tm) { 43void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
44 buf->first = buf->last = 0; 44 buf->first = buf->last = 0;
@@ -62,8 +62,8 @@ int buffer_meth_getstats(lua_State *L, p_buffer buf) {
62* object:setstats() interface 62* object:setstats() interface
63\*-------------------------------------------------------------------------*/ 63\*-------------------------------------------------------------------------*/
64int buffer_meth_setstats(lua_State *L, p_buffer buf) { 64int buffer_meth_setstats(lua_State *L, p_buffer buf) {
65 buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received); 65 buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received);
66 buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent); 66 buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent);
67 if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4); 67 if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
68 lua_pushnumber(L, 1); 68 lua_pushnumber(L, 1);
69 return 1; 69 return 1;
@@ -88,7 +88,7 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
88 /* check if there was an error */ 88 /* check if there was an error */
89 if (err != IO_DONE) { 89 if (err != IO_DONE) {
90 lua_pushnil(L); 90 lua_pushnil(L);
91 lua_pushstring(L, buf->io->error(buf->io->ctx, err)); 91 lua_pushstring(L, buf->io->error(buf->io->ctx, err));
92 lua_pushnumber(L, (lua_Number) (sent+start-1)); 92 lua_pushnumber(L, (lua_Number) (sent+start-1));
93 } else { 93 } else {
94 lua_pushnumber(L, (lua_Number) (sent+start-1)); 94 lua_pushnumber(L, (lua_Number) (sent+start-1));
@@ -111,7 +111,7 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
111 size_t size; 111 size_t size;
112 const char *part = luaL_optlstring(L, 3, "", &size); 112 const char *part = luaL_optlstring(L, 3, "", &size);
113 timeout_markstart(buf->tm); 113 timeout_markstart(buf->tm);
114 /* initialize buffer with optional extra prefix 114 /* initialize buffer with optional extra prefix
115 * (useful for concatenating previous partial results) */ 115 * (useful for concatenating previous partial results) */
116 luaL_buffinit(L, &b); 116 luaL_buffinit(L, &b);
117 luaL_addlstring(&b, part, size); 117 luaL_addlstring(&b, part, size);
@@ -119,12 +119,12 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
119 if (!lua_isnumber(L, 2)) { 119 if (!lua_isnumber(L, 2)) {
120 const char *p= luaL_optstring(L, 2, "*l"); 120 const char *p= luaL_optstring(L, 2, "*l");
121 if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); 121 if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
122 else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); 122 else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
123 else luaL_argcheck(L, 0, 2, "invalid receive pattern"); 123 else luaL_argcheck(L, 0, 2, "invalid receive pattern");
124 /* get a fixed number of bytes (minus what was already partially 124 /* get a fixed number of bytes (minus what was already partially
125 * received) */ 125 * received) */
126 } else { 126 } else {
127 double n = lua_tonumber(L, 2); 127 double n = lua_tonumber(L, 2);
128 size_t wanted = (size_t) n; 128 size_t wanted = (size_t) n;
129 luaL_argcheck(L, n >= 0, 2, "invalid receive pattern"); 129 luaL_argcheck(L, n >= 0, 2, "invalid receive pattern");
130 if (size == 0 || wanted > size) 130 if (size == 0 || wanted > size)
@@ -135,8 +135,8 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
135 /* we can't push anyting in the stack before pushing the 135 /* we can't push anyting in the stack before pushing the
136 * contents of the buffer. this is the reason for the complication */ 136 * contents of the buffer. this is the reason for the complication */
137 luaL_pushresult(&b); 137 luaL_pushresult(&b);
138 lua_pushstring(L, buf->io->error(buf->io->ctx, err)); 138 lua_pushstring(L, buf->io->error(buf->io->ctx, err));
139 lua_pushvalue(L, -2); 139 lua_pushvalue(L, -2);
140 lua_pushnil(L); 140 lua_pushnil(L);
141 lua_replace(L, -4); 141 lua_replace(L, -4);
142 } else { 142 } else {
@@ -219,7 +219,7 @@ static int recvall(p_buffer buf, luaL_Buffer *b) {
219} 219}
220 220
221/*-------------------------------------------------------------------------*\ 221/*-------------------------------------------------------------------------*\
222* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF 222* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
223* are not returned by the function and are discarded from the buffer 223* are not returned by the function and are discarded from the buffer
224\*-------------------------------------------------------------------------*/ 224\*-------------------------------------------------------------------------*/
225static int recvline(p_buffer buf, luaL_Buffer *b) { 225static int recvline(p_buffer buf, luaL_Buffer *b) {
@@ -249,7 +249,7 @@ static int recvline(p_buffer buf, luaL_Buffer *b) {
249static void buffer_skip(p_buffer buf, size_t count) { 249static void buffer_skip(p_buffer buf, size_t count) {
250 buf->received += count; 250 buf->received += count;
251 buf->first += count; 251 buf->first += count;
252 if (buffer_isempty(buf)) 252 if (buffer_isempty(buf))
253 buf->first = buf->last = 0; 253 buf->first = buf->last = 0;
254} 254}
255 255
diff --git a/src/inet.c b/src/inet.c
index 68087db..8f0fac2 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -94,7 +94,7 @@ static int inet_global_getnameinfo(lua_State *L) {
94 94
95 memset(&hints, 0, sizeof(hints)); 95 memset(&hints, 0, sizeof(hints));
96 hints.ai_socktype = SOCK_STREAM; 96 hints.ai_socktype = SOCK_STREAM;
97 hints.ai_family = PF_UNSPEC; 97 hints.ai_family = AF_UNSPEC;
98 98
99 ret = getaddrinfo(host, serv, &hints, &resolved); 99 ret = getaddrinfo(host, serv, &hints, &resolved);
100 if (ret != 0) { 100 if (ret != 0) {
@@ -105,8 +105,8 @@ static int inet_global_getnameinfo(lua_State *L) {
105 105
106 lua_newtable(L); 106 lua_newtable(L);
107 for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) { 107 for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) {
108 getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, 108 getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen,
109 hbuf, host? (socklen_t) sizeof(hbuf): 0, 109 hbuf, host? (socklen_t) sizeof(hbuf): 0,
110 sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0); 110 sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0);
111 if (host) { 111 if (host) {
112 lua_pushnumber(L, i); 112 lua_pushnumber(L, i);
@@ -146,7 +146,7 @@ static int inet_global_toip(lua_State *L)
146int inet_optfamily(lua_State* L, int narg, const char* def) 146int inet_optfamily(lua_State* L, int narg, const char* def)
147{ 147{
148 static const char* optname[] = { "unspec", "inet", "inet6", NULL }; 148 static const char* optname[] = { "unspec", "inet", "inet6", NULL };
149 static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 }; 149 static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 };
150 150
151 return optvalue[luaL_checkoption(L, narg, def, optname)]; 151 return optvalue[luaL_checkoption(L, narg, def, optname)];
152} 152}
@@ -167,7 +167,7 @@ static int inet_global_getaddrinfo(lua_State *L)
167 int i = 1, ret = 0; 167 int i = 1, ret = 0;
168 memset(&hints, 0, sizeof(hints)); 168 memset(&hints, 0, sizeof(hints));
169 hints.ai_socktype = SOCK_STREAM; 169 hints.ai_socktype = SOCK_STREAM;
170 hints.ai_family = PF_UNSPEC; 170 hints.ai_family = AF_UNSPEC;
171 ret = getaddrinfo(hostname, NULL, &hints, &resolved); 171 ret = getaddrinfo(hostname, NULL, &hints, &resolved);
172 if (ret != 0) { 172 if (ret != 0) {
173 lua_pushnil(L); 173 lua_pushnil(L);
@@ -177,7 +177,7 @@ static int inet_global_getaddrinfo(lua_State *L)
177 lua_newtable(L); 177 lua_newtable(L);
178 for (iterator = resolved; iterator; iterator = iterator->ai_next) { 178 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
179 char hbuf[NI_MAXHOST]; 179 char hbuf[NI_MAXHOST];
180 ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, 180 ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen,
181 hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST); 181 hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
182 if (ret){ 182 if (ret){
183 freeaddrinfo(resolved); 183 freeaddrinfo(resolved);
@@ -198,6 +198,16 @@ static int inet_global_getaddrinfo(lua_State *L)
198 lua_pushliteral(L, "inet6"); 198 lua_pushliteral(L, "inet6");
199 lua_settable(L, -3); 199 lua_settable(L, -3);
200 break; 200 break;
201 case AF_UNSPEC:
202 lua_pushliteral(L, "family");
203 lua_pushliteral(L, "unspec");
204 lua_settable(L, -3);
205 break;
206 default:
207 lua_pushliteral(L, "family");
208 lua_pushliteral(L, "unknown");
209 lua_settable(L, -3);
210 break;
201 } 211 }
202 lua_pushliteral(L, "addr"); 212 lua_pushliteral(L, "addr");
203 lua_pushstring(L, hbuf); 213 lua_pushstring(L, hbuf);
@@ -254,12 +264,11 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
254 } 264 }
255 lua_pushstring(L, name); 265 lua_pushstring(L, name);
256 lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10)); 266 lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10));
257 if (family == PF_INET) { 267 switch (family) {
258 lua_pushliteral(L, "inet"); 268 case AF_INET: lua_pushliteral(L, "inet"); break;
259 } else if (family == PF_INET6) { 269 case AF_INET6: lua_pushliteral(L, "inet6"); break;
260 lua_pushliteral(L, "inet6"); 270 case AF_UNSPEC: lua_pushliteral(L, "unspec"); break;
261 } else { 271 default: lua_pushliteral(L, "unknown"); break;
262 lua_pushliteral(L, "uknown family");
263 } 272 }
264 return 3; 273 return 3;
265} 274}
@@ -279,7 +288,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
279 lua_pushstring(L, socket_strerror(errno)); 288 lua_pushstring(L, socket_strerror(errno));
280 return 2; 289 return 2;
281 } 290 }
282 err=getnameinfo((struct sockaddr *)&peer, peer_len, 291 err=getnameinfo((struct sockaddr *)&peer, peer_len,
283 name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV); 292 name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
284 if (err) { 293 if (err) {
285 lua_pushnil(L); 294 lua_pushnil(L);
@@ -288,12 +297,11 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
288 } 297 }
289 lua_pushstring(L, name); 298 lua_pushstring(L, name);
290 lua_pushstring(L, port); 299 lua_pushstring(L, port);
291 if (family == PF_INET) { 300 switch (family) {
292 lua_pushliteral(L, "inet"); 301 case AF_INET: lua_pushliteral(L, "inet"); break;
293 } else if (family == PF_INET6) { 302 case AF_INET6: lua_pushliteral(L, "inet6"); break;
294 lua_pushliteral(L, "inet6"); 303 case AF_UNSPEC: lua_pushliteral(L, "unspec"); break;
295 } else { 304 default: lua_pushliteral(L, "unknown"); break;
296 lua_pushliteral(L, "uknown family");
297 } 305 }
298 return 3; 306 return 3;
299} 307}
@@ -354,21 +362,21 @@ const char *inet_trycreate(p_socket ps, int family, int type) {
354const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm) 362const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
355{ 363{
356 switch (family) { 364 switch (family) {
357 case PF_INET: { 365 case AF_INET: {
358 struct sockaddr_in sin; 366 struct sockaddr_in sin;
359 memset((char *) &sin, 0, sizeof(sin)); 367 memset((char *) &sin, 0, sizeof(sin));
360 sin.sin_family = AF_UNSPEC; 368 sin.sin_family = AF_UNSPEC;
361 sin.sin_addr.s_addr = INADDR_ANY; 369 sin.sin_addr.s_addr = INADDR_ANY;
362 return socket_strerror(socket_connect(ps, (SA *) &sin, 370 return socket_strerror(socket_connect(ps, (SA *) &sin,
363 sizeof(sin), tm)); 371 sizeof(sin), tm));
364 } 372 }
365 case PF_INET6: { 373 case AF_INET6: {
366 struct sockaddr_in6 sin6; 374 struct sockaddr_in6 sin6;
367 struct in6_addr addrany = IN6ADDR_ANY_INIT; 375 struct in6_addr addrany = IN6ADDR_ANY_INIT;
368 memset((char *) &sin6, 0, sizeof(sin6)); 376 memset((char *) &sin6, 0, sizeof(sin6));
369 sin6.sin6_family = AF_UNSPEC; 377 sin6.sin6_family = AF_UNSPEC;
370 sin6.sin6_addr = addrany; 378 sin6.sin6_addr = addrany;
371 return socket_strerror(socket_connect(ps, (SA *) &sin6, 379 return socket_strerror(socket_connect(ps, (SA *) &sin6,
372 sizeof(sin6), tm)); 380 sizeof(sin6), tm));
373 } 381 }
374 } 382 }
@@ -383,6 +391,7 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
383{ 391{
384 struct addrinfo *iterator = NULL, *resolved = NULL; 392 struct addrinfo *iterator = NULL, *resolved = NULL;
385 const char *err = NULL; 393 const char *err = NULL;
394 int current_family = *family;
386 /* try resolving */ 395 /* try resolving */
387 err = socket_gaistrerror(getaddrinfo(address, serv, 396 err = socket_gaistrerror(getaddrinfo(address, serv,
388 connecthints, &resolved)); 397 connecthints, &resolved));
@@ -397,23 +406,23 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
397 * that shows up while iterating. if there was a 406 * that shows up while iterating. if there was a
398 * bind, all families will be the same and we will 407 * bind, all families will be the same and we will
399 * not enter this branch. */ 408 * not enter this branch. */
400 if (*family != iterator->ai_family) { 409 if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
401 socket_destroy(ps); 410 socket_destroy(ps);
402 err = socket_strerror(socket_create(ps, iterator->ai_family, 411 err = socket_strerror(socket_create(ps, iterator->ai_family,
403 iterator->ai_socktype, iterator->ai_protocol)); 412 iterator->ai_socktype, iterator->ai_protocol));
404 if (err != NULL) { 413 if (err) continue;
405 freeaddrinfo(resolved); 414 current_family = iterator->ai_family;
406 return err; 415 /* set non-blocking before connect */
407 }
408 *family = iterator->ai_family;
409 /* all sockets initially non-blocking */
410 socket_setnonblocking(ps); 416 socket_setnonblocking(ps);
411 } 417 }
412 /* try connecting to remote address */ 418 /* try connecting to remote address */
413 err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, 419 err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
414 (socklen_t) iterator->ai_addrlen, tm)); 420 (socklen_t) iterator->ai_addrlen, tm));
415 /* if success, break out of loop */ 421 /* if success, break out of loop */
416 if (err == NULL) break; 422 if (err == NULL) {
423 *family = current_family;
424 break;
425 }
417 } 426 }
418 freeaddrinfo(resolved); 427 freeaddrinfo(resolved);
419 /* here, if err is set, we failed */ 428 /* here, if err is set, we failed */
@@ -423,29 +432,27 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
423/*-------------------------------------------------------------------------*\ 432/*-------------------------------------------------------------------------*\
424* Tries to accept a socket 433* Tries to accept a socket
425\*-------------------------------------------------------------------------*/ 434\*-------------------------------------------------------------------------*/
426const char *inet_tryaccept(p_socket server, int family, p_socket client, 435const char *inet_tryaccept(p_socket server, int family, p_socket client,
427 p_timeout tm) 436 p_timeout tm) {
428{
429 socklen_t len; 437 socklen_t len;
430 t_sockaddr_storage addr; 438 t_sockaddr_storage addr;
431 if (family == PF_INET6) { 439 switch (family) {
432 len = sizeof(struct sockaddr_in6); 440 case AF_INET6: len = sizeof(struct sockaddr_in6); break;
433 } else { 441 case AF_INET: len = sizeof(struct sockaddr_in); break;
434 len = sizeof(struct sockaddr_in); 442 default: len = sizeof(addr); break;
435 } 443 }
436 return socket_strerror(socket_accept(server, client, (SA *) &addr, 444 return socket_strerror(socket_accept(server, client, (SA *) &addr,
437 &len, tm)); 445 &len, tm));
438} 446}
439 447
440/*-------------------------------------------------------------------------*\ 448/*-------------------------------------------------------------------------*\
441* Tries to bind socket to (address, port) 449* Tries to bind socket to (address, port)
442\*-------------------------------------------------------------------------*/ 450\*-------------------------------------------------------------------------*/
443const char *inet_trybind(p_socket ps, const char *address, const char *serv, 451const char *inet_trybind(p_socket ps, int *family, const char *address,
444 struct addrinfo *bindhints) 452 const char *serv, struct addrinfo *bindhints) {
445{
446 struct addrinfo *iterator = NULL, *resolved = NULL; 453 struct addrinfo *iterator = NULL, *resolved = NULL;
447 const char *err = NULL; 454 const char *err = NULL;
448 t_socket sock = *ps; 455 int current_family = *family;
449 /* translate luasocket special values to C */ 456 /* translate luasocket special values to C */
450 if (strcmp(address, "*") == 0) address = NULL; 457 if (strcmp(address, "*") == 0) address = NULL;
451 if (!serv) serv = "0"; 458 if (!serv) serv = "0";
@@ -457,35 +464,32 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv,
457 } 464 }
458 /* iterate over resolved addresses until one is good */ 465 /* iterate over resolved addresses until one is good */
459 for (iterator = resolved; iterator; iterator = iterator->ai_next) { 466 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
460 if(sock == SOCKET_INVALID) { 467 if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
461 err = socket_strerror(socket_create(&sock, iterator->ai_family, 468 socket_destroy(ps);
469 err = socket_strerror(socket_create(ps, iterator->ai_family,
462 iterator->ai_socktype, iterator->ai_protocol)); 470 iterator->ai_socktype, iterator->ai_protocol));
463 if(err) 471 if (err) continue;
464 continue; 472 current_family = iterator->ai_family;
465 } 473 }
466 /* try binding to local address */ 474 /* try binding to local address */
467 err = socket_strerror(socket_bind(&sock, 475 err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr,
468 (SA *) iterator->ai_addr,
469 (socklen_t) iterator->ai_addrlen)); 476 (socklen_t) iterator->ai_addrlen));
470
471 /* keep trying unless bind succeeded */ 477 /* keep trying unless bind succeeded */
472 if (err) { 478 if (err == NULL) {
473 if(sock != *ps) 479 *family = current_family;
474 socket_destroy(&sock); 480 /* set to non-blocking after bind */
475 } else { 481 socket_setnonblocking(ps);
476 /* remember what we connected to, particularly the family */
477 *bindhints = *iterator;
478 break; 482 break;
479 } 483 }
480 } 484 }
481 /* cleanup and return error */ 485 /* cleanup and return error */
482 freeaddrinfo(resolved); 486 freeaddrinfo(resolved);
483 *ps = sock; 487 /* here, if err is set, we failed */
484 return err; 488 return err;
485} 489}
486 490
487/*-------------------------------------------------------------------------*\ 491/*-------------------------------------------------------------------------*\
488* Some systems do not provide these so that we provide our own. 492* Some systems do not provide these so that we provide our own.
489\*-------------------------------------------------------------------------*/ 493\*-------------------------------------------------------------------------*/
490#ifdef LUASOCKET_INET_ATON 494#ifdef LUASOCKET_INET_ATON
491int inet_aton(const char *cp, struct in_addr *inp) 495int inet_aton(const char *cp, struct in_addr *inp)
@@ -510,7 +514,7 @@ int inet_aton(const char *cp, struct in_addr *inp)
510#endif 514#endif
511 515
512#ifdef LUASOCKET_INET_PTON 516#ifdef LUASOCKET_INET_PTON
513int inet_pton(int af, const char *src, void *dst) 517int inet_pton(int af, const char *src, void *dst)
514{ 518{
515 struct addrinfo hints, *res; 519 struct addrinfo hints, *res;
516 int ret = 1; 520 int ret = 1;
@@ -527,7 +531,7 @@ int inet_pton(int af, const char *src, void *dst)
527 } else { 531 } else {
528 ret = -1; 532 ret = -1;
529 } 533 }
530 freeaddrinfo(res); 534 freeaddrinfo(res);
531 return ret; 535 return ret;
532} 536}
533 537
diff --git a/src/inet.h b/src/inet.h
index 1f1a96a..b85c20e 100644
--- a/src/inet.h
+++ b/src/inet.h
@@ -1,12 +1,12 @@
1#ifndef INET_H 1#ifndef INET_H
2#define INET_H 2#define INET_H
3/*=========================================================================*\ 3/*=========================================================================*\
4* Internet domain functions 4* Internet domain functions
5* LuaSocket toolkit 5* LuaSocket toolkit
6* 6*
7* This module implements the creation and connection of internet domain 7* This module implements the creation and connection of internet domain
8* sockets, on top of the socket.h interface, and the interface of with the 8* sockets, on top of the socket.h interface, and the interface of with the
9* resolver. 9* resolver.
10* 10*
11* The function inet_aton is provided for the platforms where it is not 11* The function inet_aton is provided for the platforms where it is not
12* available. The module also implements the interface of the internet 12* available. The module also implements the interface of the internet
@@ -27,8 +27,8 @@ int inet_open(lua_State *L);
27const char *inet_trycreate(p_socket ps, int family, int type); 27const char *inet_trycreate(p_socket ps, int family, int type);
28const char *inet_tryconnect(p_socket ps, int *family, const char *address, 28const char *inet_tryconnect(p_socket ps, int *family, const char *address,
29 const char *serv, p_timeout tm, struct addrinfo *connecthints); 29 const char *serv, p_timeout tm, struct addrinfo *connecthints);
30const char *inet_trybind(p_socket ps, const char *address, const char *serv, 30const char *inet_trybind(p_socket ps, int *family, const char *address,
31 struct addrinfo *bindhints); 31 const char *serv, struct addrinfo *bindhints);
32const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm); 32const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
33const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm); 33const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
34 34
diff --git a/src/io.h b/src/io.h
index 76a3e58..8cca08a 100644
--- a/src/io.h
+++ b/src/io.h
@@ -22,7 +22,7 @@ enum {
22 IO_DONE = 0, /* operation completed successfully */ 22 IO_DONE = 0, /* operation completed successfully */
23 IO_TIMEOUT = -1, /* operation timed out */ 23 IO_TIMEOUT = -1, /* operation timed out */
24 IO_CLOSED = -2, /* the connection has been closed */ 24 IO_CLOSED = -2, /* the connection has been closed */
25 IO_UNKNOWN = -3 25 IO_UNKNOWN = -3
26}; 26};
27 27
28/* interface to error message function */ 28/* interface to error message function */
diff --git a/src/socket.lua b/src/socket.lua
index 3913e6f..d1c0b16 100644
--- a/src/socket.lua
+++ b/src/socket.lua
@@ -32,23 +32,23 @@ function _M.bind(host, port, backlog)
32 err = "no info on address" 32 err = "no info on address"
33 for i, alt in base.ipairs(addrinfo) do 33 for i, alt in base.ipairs(addrinfo) do
34 if alt.family == "inet" then 34 if alt.family == "inet" then
35 sock, err = socket.tcp() 35 sock, err = socket.tcp4()
36 else 36 else
37 sock, err = socket.tcp6() 37 sock, err = socket.tcp6()
38 end 38 end
39 if not sock then return nil, err end 39 if not sock then return nil, err end
40 sock:setoption("reuseaddr", true) 40 sock:setoption("reuseaddr", true)
41 res, err = sock:bind(alt.addr, port) 41 res, err = sock:bind(alt.addr, port)
42 if not res then 42 if not res then
43 sock:close() 43 sock:close()
44 else 44 else
45 res, err = sock:listen(backlog) 45 res, err = sock:listen(backlog)
46 if not res then 46 if not res then
47 sock:close() 47 sock:close()
48 else 48 else
49 return sock 49 return sock
50 end 50 end
51 end 51 end
52 end 52 end
53 return nil, err 53 return nil, err
54end 54end
diff --git a/src/tcp.c b/src/tcp.c
index dcac0c8..4d12f08 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -18,6 +18,7 @@
18* Internal function prototypes 18* Internal function prototypes
19\*=========================================================================*/ 19\*=========================================================================*/
20static int global_create(lua_State *L); 20static int global_create(lua_State *L);
21static int global_create4(lua_State *L);
21static int global_create6(lua_State *L); 22static int global_create6(lua_State *L);
22static int global_connect(lua_State *L); 23static int global_connect(lua_State *L);
23static int meth_connect(lua_State *L); 24static int meth_connect(lua_State *L);
@@ -90,6 +91,7 @@ static t_opt optset[] = {
90/* functions in library namespace */ 91/* functions in library namespace */
91static luaL_Reg func[] = { 92static luaL_Reg func[] = {
92 {"tcp", global_create}, 93 {"tcp", global_create},
94 {"tcp4", global_create4},
93 {"tcp6", global_create6}, 95 {"tcp6", global_create6},
94 {"connect", global_connect}, 96 {"connect", global_connect},
95 {NULL, NULL} 97 {NULL, NULL}
@@ -213,8 +215,7 @@ static int meth_accept(lua_State *L)
213/*-------------------------------------------------------------------------*\ 215/*-------------------------------------------------------------------------*\
214* Binds an object to an address 216* Binds an object to an address
215\*-------------------------------------------------------------------------*/ 217\*-------------------------------------------------------------------------*/
216static int meth_bind(lua_State *L) 218static int meth_bind(lua_State *L) {
217{
218 p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1); 219 p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
219 const char *address = luaL_checkstring(L, 2); 220 const char *address = luaL_checkstring(L, 2);
220 const char *port = luaL_checkstring(L, 3); 221 const char *port = luaL_checkstring(L, 3);
@@ -224,7 +225,7 @@ static int meth_bind(lua_State *L)
224 bindhints.ai_socktype = SOCK_STREAM; 225 bindhints.ai_socktype = SOCK_STREAM;
225 bindhints.ai_family = tcp->family; 226 bindhints.ai_family = tcp->family;
226 bindhints.ai_flags = AI_PASSIVE; 227 bindhints.ai_flags = AI_PASSIVE;
227 err = inet_trybind(&tcp->sock, address, port, &bindhints); 228 err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints);
228 if (err) { 229 if (err) {
229 lua_pushnil(L); 230 lua_pushnil(L);
230 lua_pushstring(L, err); 231 lua_pushstring(L, err);
@@ -237,8 +238,7 @@ static int meth_bind(lua_State *L)
237/*-------------------------------------------------------------------------*\ 238/*-------------------------------------------------------------------------*\
238* Turns a master tcp object into a client object. 239* Turns a master tcp object into a client object.
239\*-------------------------------------------------------------------------*/ 240\*-------------------------------------------------------------------------*/
240static int meth_connect(lua_State *L) 241static int meth_connect(lua_State *L) {
241{
242 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); 242 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
243 const char *address = luaL_checkstring(L, 2); 243 const char *address = luaL_checkstring(L, 2);
244 const char *port = luaL_checkstring(L, 3); 244 const char *port = luaL_checkstring(L, 3);
@@ -249,7 +249,7 @@ static int meth_connect(lua_State *L)
249 /* make sure we try to connect only to the same family */ 249 /* make sure we try to connect only to the same family */
250 connecthints.ai_family = tcp->family; 250 connecthints.ai_family = tcp->family;
251 timeout_markstart(&tcp->tm); 251 timeout_markstart(&tcp->tm);
252 err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, 252 err = inet_tryconnect(&tcp->sock, &tcp->family, address, port,
253 &tcp->tm, &connecthints); 253 &tcp->tm, &connecthints);
254 /* have to set the class even if it failed due to non-blocking connects */ 254 /* have to set the class even if it failed due to non-blocking connects */
255 auxiliar_setclass(L, "tcp{client}", 1); 255 auxiliar_setclass(L, "tcp{client}", 1);
@@ -279,9 +279,12 @@ static int meth_close(lua_State *L)
279static int meth_getfamily(lua_State *L) 279static int meth_getfamily(lua_State *L)
280{ 280{
281 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1); 281 p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
282 if (tcp->family == PF_INET6) { 282 if (tcp->family == AF_INET6) {
283 lua_pushliteral(L, "inet6"); 283 lua_pushliteral(L, "inet6");
284 return 1; 284 return 1;
285 } else if (tcp->family == AF_INET) {
286 lua_pushliteral(L, "inet4");
287 return 1;
285 } else { 288 } else {
286 lua_pushliteral(L, "inet4"); 289 lua_pushliteral(L, "inet4");
287 return 1; 290 return 1;
@@ -353,7 +356,12 @@ static int meth_settimeout(lua_State *L)
353\*-------------------------------------------------------------------------*/ 356\*-------------------------------------------------------------------------*/
354static int tcp_create(lua_State *L, int family) { 357static int tcp_create(lua_State *L, int family) {
355 t_socket sock; 358 t_socket sock;
356 const char *err = inet_trycreate(&sock, family, SOCK_STREAM); 359 /* if family is AF_UNSPEC, we create an AF_INET socket
360 * but store AF_UNSPEC into tcp-family. This will allow it
361 * later be replaced with an AF_INET6 socket if
362 * trybind or tryconnect prefer it instead. */
363 const char *err = inet_trycreate(&sock, family == AF_UNSPEC?
364 AF_INET: family, SOCK_STREAM);
357 /* try to allocate a system socket */ 365 /* try to allocate a system socket */
358 if (!err) { 366 if (!err) {
359 /* allocate tcp object */ 367 /* allocate tcp object */
@@ -363,7 +371,7 @@ static int tcp_create(lua_State *L, int family) {
363 auxiliar_setclass(L, "tcp{master}", -1); 371 auxiliar_setclass(L, "tcp{master}", -1);
364 /* initialize remaining structure fields */ 372 /* initialize remaining structure fields */
365 socket_setnonblocking(&sock); 373 socket_setnonblocking(&sock);
366 if (family == PF_INET6) { 374 if (family == AF_INET6) {
367 int yes = 1; 375 int yes = 1;
368 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, 376 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
369 (void *)&yes, sizeof(yes)); 377 (void *)&yes, sizeof(yes));
@@ -383,6 +391,10 @@ static int tcp_create(lua_State *L, int family) {
383} 391}
384 392
385static int global_create(lua_State *L) { 393static int global_create(lua_State *L) {
394 return tcp_create(L, AF_UNSPEC);
395}
396
397static int global_create4(lua_State *L) {
386 return tcp_create(L, AF_INET); 398 return tcp_create(L, AF_INET);
387} 399}
388 400
@@ -390,53 +402,6 @@ static int global_create6(lua_State *L) {
390 return tcp_create(L, AF_INET6); 402 return tcp_create(L, AF_INET6);
391} 403}
392 404
393#if 0
394static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
395 struct addrinfo *connecthints, p_tcp tcp) {
396 struct addrinfo *iterator = NULL, *resolved = NULL;
397 const char *err = NULL;
398 /* try resolving */
399 err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv,
400 connecthints, &resolved));
401 if (err != NULL) {
402 if (resolved) freeaddrinfo(resolved);
403 return err;
404 }
405 /* iterate over all returned addresses trying to connect */
406 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
407 p_timeout tm = timeout_markstart(&tcp->tm);
408 /* create new socket if necessary. if there was no
409 * bind, we need to create one for every new family
410 * that shows up while iterating. if there was a
411 * bind, all families will be the same and we will
412 * not enter this branch. */
413 if (tcp->family != iterator->ai_family) {
414 socket_destroy(&tcp->sock);
415 err = socket_strerror(socket_create(&tcp->sock,
416 iterator->ai_family, iterator->ai_socktype,
417 iterator->ai_protocol));
418 if (err != NULL) {
419 freeaddrinfo(resolved);
420 return err;
421 }
422 tcp->family = iterator->ai_family;
423 /* all sockets initially non-blocking */
424 socket_setnonblocking(&tcp->sock);
425 }
426 /* finally try connecting to remote address */
427 err = socket_strerror(socket_connect(&tcp->sock,
428 (SA *) iterator->ai_addr,
429 (socklen_t) iterator->ai_addrlen, tm));
430 /* if success, break out of loop */
431 if (err == NULL) break;
432 }
433
434 freeaddrinfo(resolved);
435 /* here, if err is set, we failed */
436 return err;
437}
438#endif
439
440static int global_connect(lua_State *L) { 405static int global_connect(lua_State *L) {
441 const char *remoteaddr = luaL_checkstring(L, 1); 406 const char *remoteaddr = luaL_checkstring(L, 1);
442 const char *remoteserv = luaL_checkstring(L, 2); 407 const char *remoteserv = luaL_checkstring(L, 2);
@@ -453,26 +418,26 @@ static int global_connect(lua_State *L) {
453 timeout_init(&tcp->tm, -1, -1); 418 timeout_init(&tcp->tm, -1, -1);
454 buffer_init(&tcp->buf, &tcp->io, &tcp->tm); 419 buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
455 tcp->sock = SOCKET_INVALID; 420 tcp->sock = SOCKET_INVALID;
456 tcp->family = PF_UNSPEC; 421 tcp->family = AF_UNSPEC;
457 /* allow user to pick local address and port */ 422 /* allow user to pick local address and port */
458 memset(&bindhints, 0, sizeof(bindhints)); 423 memset(&bindhints, 0, sizeof(bindhints));
459 bindhints.ai_socktype = SOCK_STREAM; 424 bindhints.ai_socktype = SOCK_STREAM;
460 bindhints.ai_family = family; 425 bindhints.ai_family = family;
461 bindhints.ai_flags = AI_PASSIVE; 426 bindhints.ai_flags = AI_PASSIVE;
462 if (localaddr) { 427 if (localaddr) {
463 err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints); 428 err = inet_trybind(&tcp->sock, &tcp->family, localaddr,
429 localserv, &bindhints);
464 if (err) { 430 if (err) {
465 lua_pushnil(L); 431 lua_pushnil(L);
466 lua_pushstring(L, err); 432 lua_pushstring(L, err);
467 return 2; 433 return 2;
468 } 434 }
469 tcp->family = bindhints.ai_family;
470 } 435 }
471 /* try to connect to remote address and port */ 436 /* try to connect to remote address and port */
472 memset(&connecthints, 0, sizeof(connecthints)); 437 memset(&connecthints, 0, sizeof(connecthints));
473 connecthints.ai_socktype = SOCK_STREAM; 438 connecthints.ai_socktype = SOCK_STREAM;
474 /* make sure we try to connect only to the same family */ 439 /* make sure we try to connect only to the same family */
475 connecthints.ai_family = bindhints.ai_family; 440 connecthints.ai_family = tcp->family;
476 err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, 441 err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv,
477 &tcp->tm, &connecthints); 442 &tcp->tm, &connecthints);
478 if (err) { 443 if (err) {
diff --git a/src/udp.c b/src/udp.c
index 7ff00f5..6600859 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -27,6 +27,7 @@
27* Internal function prototypes 27* Internal function prototypes
28\*=========================================================================*/ 28\*=========================================================================*/
29static int global_create(lua_State *L); 29static int global_create(lua_State *L);
30static int global_create4(lua_State *L);
30static int global_create6(lua_State *L); 31static int global_create6(lua_State *L);
31static int meth_send(lua_State *L); 32static int meth_send(lua_State *L);
32static int meth_sendto(lua_State *L); 33static int meth_sendto(lua_State *L);
@@ -107,6 +108,7 @@ static t_opt optget[] = {
107/* functions in library namespace */ 108/* functions in library namespace */
108static luaL_Reg func[] = { 109static luaL_Reg func[] = {
109 {"udp", global_create}, 110 {"udp", global_create},
111 {"udp4", global_create4},
110 {"udp6", global_create6}, 112 {"udp6", global_create6},
111 {NULL, NULL} 113 {NULL, NULL}
112}; 114};
@@ -264,7 +266,7 @@ static int meth_receivefrom(lua_State *L)
264static int meth_getfamily(lua_State *L) 266static int meth_getfamily(lua_State *L)
265{ 267{
266 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1); 268 p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
267 if (udp->family == PF_INET6) { 269 if (udp->family == AF_INET6) {
268 lua_pushliteral(L, "inet6"); 270 lua_pushliteral(L, "inet6");
269 return 1; 271 return 1;
270 } else { 272 } else {
@@ -391,7 +393,7 @@ static int meth_setsockname(lua_State *L) {
391 bindhints.ai_socktype = SOCK_DGRAM; 393 bindhints.ai_socktype = SOCK_DGRAM;
392 bindhints.ai_family = udp->family; 394 bindhints.ai_family = udp->family;
393 bindhints.ai_flags = AI_PASSIVE; 395 bindhints.ai_flags = AI_PASSIVE;
394 err = inet_trybind(&udp->sock, address, port, &bindhints); 396 err = inet_trybind(&udp->sock, &udp->family, address, port, &bindhints);
395 if (err) { 397 if (err) {
396 lua_pushnil(L); 398 lua_pushnil(L);
397 lua_pushstring(L, err); 399 lua_pushstring(L, err);
@@ -409,7 +411,12 @@ static int meth_setsockname(lua_State *L) {
409\*-------------------------------------------------------------------------*/ 411\*-------------------------------------------------------------------------*/
410static int udp_create(lua_State *L, int family) { 412static int udp_create(lua_State *L, int family) {
411 t_socket sock; 413 t_socket sock;
412 const char *err = inet_trycreate(&sock, family, SOCK_DGRAM); 414 /* if family is AF_UNSPEC, we create an AF_INET socket
415 * but store AF_UNSPEC into tcp-family. This will allow it
416 * later be replaced with an AF_INET6 socket if
417 * trybind or tryconnect prefer it instead. */
418 const char *err = inet_trycreate(&sock, family == AF_UNSPEC?
419 AF_INET: family, SOCK_DGRAM);
413 /* try to allocate a system socket */ 420 /* try to allocate a system socket */
414 if (!err) { 421 if (!err) {
415 /* allocate udp object */ 422 /* allocate udp object */
@@ -417,7 +424,7 @@ static int udp_create(lua_State *L, int family) {
417 auxiliar_setclass(L, "udp{unconnected}", -1); 424 auxiliar_setclass(L, "udp{unconnected}", -1);
418 /* initialize remaining structure fields */ 425 /* initialize remaining structure fields */
419 socket_setnonblocking(&sock); 426 socket_setnonblocking(&sock);
420 if (family == PF_INET6) { 427 if (family == AF_INET6) {
421 int yes = 1; 428 int yes = 1;
422 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, 429 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
423 (void *)&yes, sizeof(yes)); 430 (void *)&yes, sizeof(yes));
@@ -434,6 +441,10 @@ static int udp_create(lua_State *L, int family) {
434} 441}
435 442
436static int global_create(lua_State *L) { 443static int global_create(lua_State *L) {
444 return udp_create(L, AF_UNSPEC);
445}
446
447static int global_create4(lua_State *L) {
437 return udp_create(L, AF_INET); 448 return udp_create(L, AF_INET);
438} 449}
439 450
diff --git a/src/usocket.c b/src/usocket.c
index 99e551b..8adc573 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -211,6 +211,8 @@ int socket_send(p_socket ps, const char *data, size_t count,
211 err = errno; 211 err = errno;
212 /* EPIPE means the connection was closed */ 212 /* EPIPE means the connection was closed */
213 if (err == EPIPE) return IO_CLOSED; 213 if (err == EPIPE) return IO_CLOSED;
214 /* EPROTOTYPE means the connection is being closed (on Yosemite!)*/
215 if (err == EPROTOTYPE) continue;
214 /* we call was interrupted, just try again */ 216 /* we call was interrupted, just try again */
215 if (err == EINTR) continue; 217 if (err == EINTR) continue;
216 /* if failed fatal reason, report error */ 218 /* if failed fatal reason, report error */
@@ -239,6 +241,7 @@ int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
239 } 241 }
240 err = errno; 242 err = errno;
241 if (err == EPIPE) return IO_CLOSED; 243 if (err == EPIPE) return IO_CLOSED;
244 if (err == EPROTOTYPE) continue;
242 if (err == EINTR) continue; 245 if (err == EINTR) continue;
243 if (err != EAGAIN) return err; 246 if (err != EAGAIN) return err;
244 if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err; 247 if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
@@ -317,6 +320,8 @@ int socket_write(p_socket ps, const char *data, size_t count,
317 err = errno; 320 err = errno;
318 /* EPIPE means the connection was closed */ 321 /* EPIPE means the connection was closed */
319 if (err == EPIPE) return IO_CLOSED; 322 if (err == EPIPE) return IO_CLOSED;
323 /* EPROTOTYPE means the connection is being closed (on Yosemite!)*/
324 if (err == EPROTOTYPE) continue;
320 /* we call was interrupted, just try again */ 325 /* we call was interrupted, just try again */
321 if (err == EINTR) continue; 326 if (err == EINTR) continue;
322 /* if failed fatal reason, report error */ 327 /* if failed fatal reason, report error */
@@ -410,7 +415,9 @@ const char *socket_strerror(int err) {
410 case ECONNABORTED: return PIE_CONNABORTED; 415 case ECONNABORTED: return PIE_CONNABORTED;
411 case ECONNRESET: return PIE_CONNRESET; 416 case ECONNRESET: return PIE_CONNRESET;
412 case ETIMEDOUT: return PIE_TIMEDOUT; 417 case ETIMEDOUT: return PIE_TIMEDOUT;
413 default: return strerror(err); 418 default: {
419 return strerror(err);
420 }
414 } 421 }
415} 422}
416 423
diff --git a/test/testclnt.lua b/test/testclnt.lua
index 0014781..abf9608 100644
--- a/test/testclnt.lua
+++ b/test/testclnt.lua
@@ -8,7 +8,7 @@ function printf(...)
8end 8end
9 9
10function pass(...) 10function pass(...)
11 printf(...) 11 printf(...)
12 io.stderr:write("\n") 12 io.stderr:write("\n")
13end 13end
14 14
@@ -45,30 +45,30 @@ function check_timeout(tm, sl, elapsed, err, opp, mode, alldone)
45 if not err then warn("must be buffered") 45 if not err then warn("must be buffered")
46 elseif err == "timeout" then pass("proper timeout") 46 elseif err == "timeout" then pass("proper timeout")
47 else fail("unexpected error '%s'", err) end 47 else fail("unexpected error '%s'", err) end
48 else 48 else
49 if err ~= "timeout" then fail("should have timed out") 49 if err ~= "timeout" then fail("should have timed out")
50 else pass("proper timeout") end 50 else pass("proper timeout") end
51 end 51 end
52 else 52 else
53 if mode == "total" then 53 if mode == "total" then
54 if elapsed > tm then 54 if elapsed > tm then
55 if err ~= "timeout" then fail("should have timed out") 55 if err ~= "timeout" then fail("should have timed out")
56 else pass("proper timeout") end 56 else pass("proper timeout") end
57 elseif elapsed < tm then 57 elseif elapsed < tm then
58 if err then fail(err) 58 if err then fail(err)
59 else pass("ok") end 59 else pass("ok") end
60 else 60 else
61 if alldone then 61 if alldone then
62 if err then fail("unexpected error '%s'", err) 62 if err then fail("unexpected error '%s'", err)
63 else pass("ok") end 63 else pass("ok") end
64 else 64 else
65 if err ~= "timeout" then fail(err) 65 if err ~= "timeout" then fail(err)
66 else pass("proper timeoutk") end 66 else pass("proper timeoutk") end
67 end 67 end
68 end 68 end
69 else 69 else
70 if err then fail(err) 70 if err then fail(err)
71 else pass("ok") end 71 else pass("ok") end
72 end 72 end
73 end 73 end
74end 74end
@@ -104,8 +104,8 @@ control:setoption("tcp-nodelay", true)
104------------------------------------------------------------------------ 104------------------------------------------------------------------------
105function test_methods(sock, methods) 105function test_methods(sock, methods)
106 for _, v in pairs(methods) do 106 for _, v in pairs(methods) do
107 if type(sock[v]) ~= "function" then 107 if type(sock[v]) ~= "function" then
108 fail(sock.class .. " method '" .. v .. "' not registered") 108 fail(sock.class .. " method '" .. v .. "' not registered")
109 end 109 end
110 end 110 end
111 pass(sock.class .. " methods are ok") 111 pass(sock.class .. " methods are ok")
@@ -121,7 +121,7 @@ function test_mixed(len)
121 local p3 = "raw " .. string.rep("z", inter) .. "bytes" 121 local p3 = "raw " .. string.rep("z", inter) .. "bytes"
122 local p4 = "end" .. string.rep("w", inter) .. "bytes" 122 local p4 = "end" .. string.rep("w", inter) .. "bytes"
123 local bp1, bp2, bp3, bp4 123 local bp1, bp2, bp3, bp4
124remote (string.format("str = data:receive(%d)", 124remote (string.format("str = data:receive(%d)",
125 string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4))) 125 string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4)))
126 sent, err = data:send(p1..p2..p3..p4) 126 sent, err = data:send(p1..p2..p3..p4)
127 if err then fail(err) end 127 if err then fail(err) end
@@ -166,7 +166,7 @@ function test_rawline(len)
166 io.stderr:write("length " .. len .. ": ") 166 io.stderr:write("length " .. len .. ": ")
167 local str, str10, back, err 167 local str, str10, back, err
168 str = string.rep(string.char(47), math.mod(len, 10)) 168 str = string.rep(string.char(47), math.mod(len, 10))
169 str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100), 169 str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100),
170 math.floor(len/10)) 170 math.floor(len/10))
171 str = str .. str10 171 str = str .. str10
172remote "str = data:receive()" 172remote "str = data:receive()"
@@ -216,7 +216,7 @@ function test_totaltimeoutreceive(len, tm, sl)
216 data:settimeout(tm, "total") 216 data:settimeout(tm, "total")
217local t = socket.gettime() 217local t = socket.gettime()
218 str, err, partial, elapsed = data:receive(2*len) 218 str, err, partial, elapsed = data:receive(2*len)
219 check_timeout(tm, sl, elapsed, err, "receive", "total", 219 check_timeout(tm, sl, elapsed, err, "receive", "total",
220 string.len(str or partial) == 2*len) 220 string.len(str or partial) == 2*len)
221end 221end
222 222
@@ -236,7 +236,7 @@ function test_totaltimeoutsend(len, tm, sl)
236 data:settimeout(tm, "total") 236 data:settimeout(tm, "total")
237 str = string.rep("a", 2*len) 237 str = string.rep("a", 2*len)
238 total, err, partial, elapsed = data:send(str) 238 total, err, partial, elapsed = data:send(str)
239 check_timeout(tm, sl, elapsed, err, "send", "total", 239 check_timeout(tm, sl, elapsed, err, "send", "total",
240 total == 2*len) 240 total == 2*len)
241end 241end
242 242
@@ -256,7 +256,7 @@ function test_blockingtimeoutreceive(len, tm, sl)
256 ]], 2*tm, len, sl, sl)) 256 ]], 2*tm, len, sl, sl))
257 data:settimeout(tm) 257 data:settimeout(tm)
258 str, err, partial, elapsed = data:receive(2*len) 258 str, err, partial, elapsed = data:receive(2*len)
259 check_timeout(tm, sl, elapsed, err, "receive", "blocking", 259 check_timeout(tm, sl, elapsed, err, "receive", "blocking",
260 string.len(str or partial) == 2*len) 260 string.len(str or partial) == 2*len)
261end 261end
262 262
@@ -290,10 +290,10 @@ function empty_connect()
290 data = server:accept() 290 data = server:accept()
291 ]] 291 ]]
292 data, err = socket.connect("", port) 292 data, err = socket.connect("", port)
293 if not data then 293 if not data then
294 pass("ok") 294 pass("ok")
295 data = socket.connect(host, port) 295 data = socket.connect(host, port)
296 else 296 else
297 pass("gethostbyname returns localhost on empty string...") 297 pass("gethostbyname returns localhost on empty string...")
298 end 298 end
299end 299end
@@ -327,7 +327,7 @@ function test_closed()
327 data:close() 327 data:close()
328 data = nil 328 data = nil
329 ]], str)) 329 ]], str))
330 -- try to get a line 330 -- try to get a line
331 back, err, partial = data:receive() 331 back, err, partial = data:receive()
332 if not err then fail("should have gotten 'closed'.") 332 if not err then fail("should have gotten 'closed'.")
333 elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.") 333 elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.")
@@ -340,25 +340,25 @@ function test_closed()
340 data = nil 340 data = nil
341 ]] 341 ]]
342 total, err, partial = data:send(string.rep("ugauga", 100000)) 342 total, err, partial = data:send(string.rep("ugauga", 100000))
343 if not err then 343 if not err then
344 pass("failed: output buffer is at least %d bytes long!", total) 344 pass("failed: output buffer is at least %d bytes long!", total)
345 elseif err ~= "closed" then 345 elseif err ~= "closed" then
346 fail("got '"..err.."' instead of 'closed'.") 346 fail("got '"..err.."' instead of 'closed'.")
347 else 347 else
348 pass("graceful 'closed' received after %d bytes were sent", partial) 348 pass("graceful 'closed' received after %d bytes were sent", partial)
349 end 349 end
350end 350end
351 351
352------------------------------------------------------------------------ 352------------------------------------------------------------------------
353function test_selectbugs() 353function test_selectbugs()
354 local r, s, e = socket.select(nil, nil, 0.1) 354 local r, s, e = socket.select(nil, nil, 0.1)
355 assert(type(r) == "table" and type(s) == "table" and 355 assert(type(r) == "table" and type(s) == "table" and
356 (e == "timeout" or e == "error")) 356 (e == "timeout" or e == "error"))
357 pass("both nil: ok") 357 pass("both nil: ok")
358 local udp = socket.udp() 358 local udp = socket.udp()
359 udp:close() 359 udp:close()
360 r, s, e = socket.select({ udp }, { udp }, 0.1) 360 r, s, e = socket.select({ udp }, { udp }, 0.1)
361 assert(type(r) == "table" and type(s) == "table" and 361 assert(type(r) == "table" and type(s) == "table" and
362 (e == "timeout" or e == "error")) 362 (e == "timeout" or e == "error"))
363 pass("closed sockets: ok") 363 pass("closed sockets: ok")
364 e = pcall(socket.select, "wrong", 1, 0.1) 364 e = pcall(socket.select, "wrong", 1, 0.1)
@@ -389,7 +389,7 @@ function accept_timeout()
389 local t = socket.gettime() 389 local t = socket.gettime()
390 s:settimeout(1) 390 s:settimeout(1)
391 local c, e = s:accept() 391 local c, e = s:accept()
392 assert(not c, "should not accept") 392 assert(not c, "should not accept")
393 assert(e == "timeout", string.format("wrong error message (%s)", e)) 393 assert(e == "timeout", string.format("wrong error message (%s)", e))
394 t = socket.gettime() - t 394 t = socket.gettime() - t
395 assert(t < 2, string.format("took to long to give up (%gs)", t)) 395 assert(t < 2, string.format("took to long to give up (%gs)", t))
@@ -407,9 +407,9 @@ function connect_timeout()
407 local t = socket.gettime() 407 local t = socket.gettime()
408 local r, e = c:connect("10.0.0.1", 81) 408 local r, e = c:connect("10.0.0.1", 81)
409 assert(not r, "should not connect") 409 assert(not r, "should not connect")
410 assert(socket.gettime() - t < 2, "took too long to give up.") 410 assert(socket.gettime() - t < 2, "took too long to give up.")
411 c:close() 411 c:close()
412 pass("ok") 412 pass("ok")
413end 413end
414 414
415------------------------------------------------------------------------ 415------------------------------------------------------------------------
@@ -447,16 +447,14 @@ end
447 447
448------------------------------------------------------------------------ 448------------------------------------------------------------------------
449function rebind_test() 449function rebind_test()
450 --local c ,c1 = socket.bind("localhost", 0)
451 local c ,c1 = socket.bind("127.0.0.1", 0) 450 local c ,c1 = socket.bind("127.0.0.1", 0)
452 if not c then pass ("failed to bind! " .. tostring(c) .. ' ' .. tostring(c1)) return end 451 if not c then pass ("failed to bind! " .. tostring(c) .. ' ' .. tostring(c1)) return end
453 assert(c,c1) 452 assert(c,c1)
454
455 local i, p = c:getsockname() 453 local i, p = c:getsockname()
456 local s, e = socket.tcp() 454 local s, e = socket.tcp()
457 assert(s, e) 455 assert(s, e)
458 s:setoption("reuseaddr", false) 456 s:setoption("reuseaddr", false)
459 r, e = s:bind("localhost", p) 457 r, e = s:bind(i, p)
460 assert(not r, "managed to rebind!") 458 assert(not r, "managed to rebind!")
461 assert(e) 459 assert(e)
462 pass("ok") 460 pass("ok")
@@ -476,9 +474,9 @@ function getstats_test()
476 data:receive(c) 474 data:receive(c)
477 t = t + c 475 t = t + c
478 local r, s, a = data:getstats() 476 local r, s, a = data:getstats()
479 assert(r == t, "received count failed" .. tostring(r) 477 assert(r == t, "received count failed" .. tostring(r)
480 .. "/" .. tostring(t)) 478 .. "/" .. tostring(t))
481 assert(s == t, "sent count failed" .. tostring(s) 479 assert(s == t, "sent count failed" .. tostring(s)
482 .. "/" .. tostring(t)) 480 .. "/" .. tostring(t))
483 end 481 end
484 pass("ok") 482 pass("ok")
@@ -486,7 +484,7 @@ end
486 484
487 485
488------------------------------------------------------------------------ 486------------------------------------------------------------------------
489function test_nonblocking(size) 487function test_nonblocking(size)
490 reconnect() 488 reconnect()
491 printf("testing " .. 2*size .. " bytes: ") 489 printf("testing " .. 2*size .. " bytes: ")
492remote(string.format([[ 490remote(string.format([[
@@ -545,7 +543,7 @@ function test_readafterclose()
545 data:close() 543 data:close()
546 data = nil 544 data = nil
547 ]])) 545 ]]))
548 data:close() 546 data:close()
549 back, err, partial = data:receive("*a") 547 back, err, partial = data:receive("*a")
550 assert(back == nil and err == "closed", "should have returned 'closed'") 548 assert(back == nil and err == "closed", "should have returned 'closed'")
551 pass("ok") 549 pass("ok")
@@ -555,7 +553,7 @@ function test_readafterclose()
555 data:close() 553 data:close()
556 data = nil 554 data = nil
557 ]])) 555 ]]))
558 data:close() 556 data:close()
559 back, err, partial = data:receive() 557 back, err, partial = data:receive()
560 assert(back == nil and err == "closed", "should have returned 'closed'") 558 assert(back == nil and err == "closed", "should have returned 'closed'")
561 pass("ok") 559 pass("ok")
@@ -565,7 +563,7 @@ function test_readafterclose()
565 data:close() 563 data:close()
566 data = nil 564 data = nil
567 ]])) 565 ]]))
568 data:close() 566 data:close()
569 back, err, partial = data:receive(1) 567 back, err, partial = data:receive(1)
570 assert(back == nil and err == "closed", "should have returned 'closed'") 568 assert(back == nil and err == "closed", "should have returned 'closed'")
571 pass("ok") 569 pass("ok")
@@ -575,7 +573,7 @@ function test_readafterclose()
575 data:close() 573 data:close()
576 data = nil 574 data = nil
577 ]])) 575 ]]))
578 data:close() 576 data:close()
579 back, err, partial = data:receive(0) 577 back, err, partial = data:receive(0)
580 assert(back == nil and err == "closed", "should have returned 'closed'") 578 assert(back == nil and err == "closed", "should have returned 'closed'")
581 pass("ok") 579 pass("ok")
@@ -593,7 +591,7 @@ function test_writeafterclose()
593 while not err do 591 while not err do
594 sent, err, errsent, time = data:send(str) 592 sent, err, errsent, time = data:send(str)
595 end 593 end
596 assert(err == "closed", "should have returned 'closed'") 594 assert(err == "closed", "got " .. err .. " instead of 'closed'")
597 pass("ok") 595 pass("ok")
598end 596end
599 597
@@ -648,18 +646,18 @@ else io.stderr:write("Warning! IPv6 does not support!\n") end
648end 646end
649 647
650local udp_methods = { 648local udp_methods = {
651 "close", 649 "close",
652 "dirty", 650 "dirty",
653 "getfamily", 651 "getfamily",
654 "getfd", 652 "getfd",
655 "getoption", 653 "getoption",
656 "getpeername", 654 "getpeername",
657 "getsockname", 655 "getsockname",
658 "receive", 656 "receive",
659 "receivefrom", 657 "receivefrom",
660 "send", 658 "send",
661 "sendto", 659 "sendto",
662 "setfd", 660 "setfd",
663 "setoption", 661 "setoption",
664 "setpeername", 662 "setpeername",
665 "setsockname", 663 "setsockname",
@@ -674,6 +672,9 @@ if sock then test_methods(socket.udp6(), udp_methods)
674else io.stderr:write("Warning! IPv6 does not support!\n") end 672else io.stderr:write("Warning! IPv6 does not support!\n") end
675end 673end
676 674
675test("closed connection detection: ")
676test_closed()
677
677test("partial receive") 678test("partial receive")
678test_partialrecv() 679test_partialrecv()
679 680
@@ -697,9 +698,6 @@ rebind_test()
697test("active close: ") 698test("active close: ")
698active_close() 699active_close()
699 700
700test("closed connection detection: ")
701test_closed()
702
703test("accept function: ") 701test("accept function: ")
704accept_timeout() 702accept_timeout()
705accept_errors() 703accept_errors()
diff --git a/test/testsrvr.lua b/test/testsrvr.lua
index 72b93ab..1eb2d5b 100644
--- a/test/testsrvr.lua
+++ b/test/testsrvr.lua
@@ -6,7 +6,7 @@ ack = "\n";
6while 1 do 6while 1 do
7 print("server: waiting for client connection..."); 7 print("server: waiting for client connection...");
8 control = assert(server:accept()); 8 control = assert(server:accept());
9 while 1 do 9 while 1 do
10 command, emsg = control:receive(); 10 command, emsg = control:receive();
11 if emsg == "closed" then 11 if emsg == "closed" then
12 control:close() 12 control:close()
diff --git a/test/udpconnectclnt.lua b/test/udpconnectclnt.lua
index effe13a..ad6ab6a 100644
--- a/test/udpconnectclnt.lua
+++ b/test/udpconnectclnt.lua
@@ -1,7 +1,7 @@
1local socket = require"socket" 1local socket = require"socket"
2local udp = socket.udp 2local udp = socket.udp
3local localhost = "127.0.0.1" 3local localhost = "127.0.0.1"
4local port = arg[1] 4local port = assert(arg[1], "missing port argument")
5 5
6se = udp(); se:setoption("reuseaddr", true) 6se = udp(); se:setoption("reuseaddr", true)
7se:setsockname(localhost, 5062) 7se:setsockname(localhost, 5062)