aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDiego Nehab <diego.nehab@gmail.com>2015-08-25 15:43:48 -0300
committerDiego Nehab <diego.nehab@gmail.com>2015-08-25 15:43:48 -0300
commit4110e4125dace9df3a744067066e5dee62670561 (patch)
tree10927b57ea5c543054d01bd2bd538a4f97128678
parent46d7e75f3e71d75bf07ae83d7df4aa276e484473 (diff)
parent77bba625d7aaa0f9e118879163687fcbcb0b5a7b (diff)
downloadluasocket-4110e4125dace9df3a744067066e5dee62670561.tar.gz
luasocket-4110e4125dace9df3a744067066e5dee62670561.tar.bz2
luasocket-4110e4125dace9df3a744067066e5dee62670561.zip
Merge branch 'agnostic'
Seems safe to move to master.
-rw-r--r--doc/reference.html2
-rw-r--r--doc/tcp.html199
-rw-r--r--doc/udp.html165
-rw-r--r--src/buffer.c24
-rw-r--r--src/inet.c145
-rw-r--r--src/inet.h12
-rw-r--r--src/io.h2
-rw-r--r--src/socket.lua10
-rw-r--r--src/tcp.c123
-rw-r--r--src/udp.c57
-rw-r--r--src/usocket.c9
-rw-r--r--test/testclnt.lua119
-rw-r--r--test/testsrvr.lua2
-rw-r--r--test/udpconnectclnt.lua2
14 files changed, 460 insertions, 411 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..fb627a1 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,54 @@
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<p class=note>
69Note: Before the choice between IPv4 and IPv6 happens,
70the internal socket object is invalid and therefore <a
71href=#setoption><tt>setoption</tt></a> will fail.
72</p>
73
74<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
75
76<p class=name id="socket.tcp4">
77socket.<b>tcp4()</b>
78</p>
79
80<p class=description>
48Creates and returns an IPv4 TCP master object. A master object can 81Creates and returns an IPv4 TCP master object. A master object can
49be transformed into a server object with the method 82be transformed into a server object with the method
50<a href=#listen><tt>listen</tt></a> (after a call to <a 83<a href=#listen><tt>listen</tt></a> (after a call to <a
51href=#bind><tt>bind</tt></a>) or into a client object with 84href=#bind><tt>bind</tt></a>) or into a client object with
52the method <a href=#connect><tt>connect</tt></a>. The only other 85the method <a href=#connect><tt>connect</tt></a>. The only other
53method supported by a master object is the 86method supported by a master object is the
54<a href=#close><tt>close</tt></a> method.</p> 87<a href=#close><tt>close</tt></a> method.</p>
55 88
56<p class=return> 89<p class=return>
@@ -60,17 +93,17 @@ In case of success, a new master object is returned. In case of error,
60 93
61<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 94<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
62 95
63<p class=name id="socket.tcp6"> 96<p class=name id="socket.tcp6">
64socket.<b>tcp6()</b> 97socket.<b>tcp6()</b>
65</p> 98</p>
66 99
67<p class=description> 100<p class=description>
68Creates and returns an IPv6 TCP master object. A master object can 101Creates and returns an IPv6 TCP master object. A master object can
69be transformed into a server object with the method 102be transformed into a server object with the method
70<a href=#listen><tt>listen</tt></a> (after a call to <a 103<a href=#listen><tt>listen</tt></a> (after a call to <a
71href=#bind><tt>bind</tt></a>) or into a client object with 104href=#bind><tt>bind</tt></a>) or into a client object with
72the method <a href=#connect><tt>connect</tt></a>. The only other 105the method <a href=#connect><tt>connect</tt></a>. The only other
73method supported by a master object is the 106method supported by a master object is the
74<a href=#close><tt>close</tt></a> method.</p> 107<a href=#close><tt>close</tt></a> method.</p>
75 108
76<p class=return> 109<p class=return>
@@ -85,7 +118,7 @@ Note: The TCP object returned will have the option
85 118
86<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 119<!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
87 120
88<p class=name id="accept"> 121<p class=name id="accept">
89server:<b>accept()</b> 122server:<b>accept()</b>
90</p> 123</p>
91 124
@@ -95,9 +128,9 @@ object and returns a client object representing that connection.
95</p> 128</p>
96 129
97<p class=return> 130<p class=return>
98If a connection is successfully initiated, a client object is returned. 131If a connection is successfully initiated, a client object is returned.
99If a timeout condition is met, the method returns <b><tt>nil</tt></b> 132If a timeout condition is met, the method returns <b><tt>nil</tt></b>
100followed by the error string '<tt>timeout</tt>'. Other errors are 133followed by the error string '<tt>timeout</tt>'. Other errors are
101reported by <b><tt>nil</tt></b> followed by a message describing the error. 134reported by <b><tt>nil</tt></b> followed by a message describing the error.
102</p> 135</p>
103 136
@@ -107,28 +140,28 @@ with a server object in
107the <tt>recvt</tt> parameter before a call to <tt>accept</tt> does 140the <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 141<em>not</em> guarantee <tt>accept</tt> will return immediately. Use the <a
109href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt> 142href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt>
110might block until <em>another</em> client shows up. 143might block until <em>another</em> client shows up.
111</p> 144</p>
112 145
113<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 146<!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
114 147
115<p class=name id="bind"> 148<p class=name id="bind">
116master:<b>bind(</b>address, port<b>)</b> 149master:<b>bind(</b>address, port<b>)</b>
117</p> 150</p>
118 151
119<p class=description> 152<p class=description>
120Binds a master object to <tt>address</tt> and <tt>port</tt> on the 153Binds a master object to <tt>address</tt> and <tt>port</tt> on the
121local host. 154local host.
122 155
123<p class=parameters> 156<p class=parameters>
124<tt>Address</tt> can be an IP address or a host name. 157<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). 158<tt>Port</tt> must be an integer number in the range [0..64K).
126If <tt>address</tt> 159If <tt>address</tt>
127is '<tt>*</tt>', the system binds to all local interfaces 160is '<tt>*</tt>', the system binds to all local interfaces
128using the <tt>INADDR_ANY</tt> constant or 161using the <tt>INADDR_ANY</tt> constant or
129<tt>IN6ADDR_ANY_INIT</tt>, according to the family. 162<tt>IN6ADDR_ANY_INIT</tt>, according to the family.
130If <tt>port</tt> is 0, the system automatically 163If <tt>port</tt> is 0, the system automatically
131chooses an ephemeral port. 164chooses an ephemeral port.
132</p> 165</p>
133 166
134<p class=return> 167<p class=return>
@@ -137,13 +170,13 @@ method returns <b><tt>nil</tt></b> followed by an error message.
137</p> 170</p>
138 171
139<p class=note> 172<p class=note>
140Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a> 173Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a>
141is available and is a shortcut for the creation of server sockets. 174is available and is a shortcut for the creation of server sockets.
142</p> 175</p>
143 176
144<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 177<!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
145 178
146<p class=name id="close"> 179<p class=name id="close">
147master:<b>close()</b><br> 180master:<b>close()</b><br>
148client:<b>close()</b><br> 181client:<b>close()</b><br>
149server:<b>close()</b> 182server:<b>close()</b>
@@ -154,14 +187,14 @@ Closes a TCP object. The internal socket used by the object is closed
154and the local address to which the object was 187and the local address to which the object was
155bound is made available to other applications. No further operations 188bound is made available to other applications. No further operations
156(except for further calls to the <tt>close</tt> method) are allowed on 189(except for further calls to the <tt>close</tt> method) are allowed on
157a closed socket. 190a closed socket.
158</p> 191</p>
159 192
160<p class=note> 193<p class=note>
161Note: It is important to close all used sockets once they are not 194Note: It is important to close all used sockets once they are not
162needed, since, in many systems, each socket uses a file descriptor, 195needed, since, in many systems, each socket uses a file descriptor,
163which are limited system resources. Garbage-collected objects are 196which are limited system resources. Garbage-collected objects are
164automatically closed before destruction, though. 197automatically closed before destruction, though.
165</p> 198</p>
166 199
167<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 200<!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -172,19 +205,19 @@ master:<b>connect(</b>address, port<b>)</b>
172 205
173<p class=description> 206<p class=description>
174Attempts to connect a master object to a remote host, transforming it into a 207Attempts to connect a master object to a remote host, transforming it into a
175client object. 208client object.
176Client objects support methods 209Client objects support methods
177<a href=#send><tt>send</tt></a>, 210<a href=#send><tt>send</tt></a>,
178<a href=#receive><tt>receive</tt></a>, 211<a href=#receive><tt>receive</tt></a>,
179<a href=#getsockname><tt>getsockname</tt></a>, 212<a href=#getsockname><tt>getsockname</tt></a>,
180<a href=#getpeername><tt>getpeername</tt></a>, 213<a href=#getpeername><tt>getpeername</tt></a>,
181<a href=#settimeout><tt>settimeout</tt></a>, 214<a href=#settimeout><tt>settimeout</tt></a>,
182and <a href=#close><tt>close</tt></a>. 215and <a href=#close><tt>close</tt></a>.
183</p> 216</p>
184 217
185<p class=parameters> 218<p class=parameters>
186<tt>Address</tt> can be an IP address or a host name. 219<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). 220<tt>Port</tt> must be an integer number in the range [1..64K).
188</p> 221</p>
189 222
190<p class=return> 223<p class=return>
@@ -193,14 +226,14 @@ describing the error. In case of success, the method returns 1.
193</p> 226</p>
194 227
195<p class=note> 228<p class=note>
196Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a> 229Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a>
197is available and is a shortcut for the creation of client sockets. 230is available and is a shortcut for the creation of client sockets.
198</p> 231</p>
199 232
200<p class=note> 233<p class=note>
201Note: Starting with LuaSocket 2.0, 234Note: Starting with LuaSocket 2.0,
202the <a href=#settimeout><tt>settimeout</tt></a> 235the <a href=#settimeout><tt>settimeout</tt></a>
203method affects the behavior of <tt>connect</tt>, causing it to return 236method 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 237with 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 238href=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 239<tt>sendt</tt> table. The socket will be writable when the connection is
@@ -227,10 +260,10 @@ Returns information about the remote side of a connected client object.
227</p> 260</p>
228 261
229<p class=return> 262<p class=return>
230Returns a string with the IP address of the peer, the 263Returns a string with the IP address of the peer, the
231port number that peer is using for the connection, 264port number that peer is using for the connection,
232and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 265and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
233In case of error, the method returns <b><tt>nil</tt></b>. 266In case of error, the method returns <b><tt>nil</tt></b>.
234</p> 267</p>
235 268
236<p class=note> 269<p class=note>
@@ -246,13 +279,13 @@ server:<b>getsockname()</b>
246</p> 279</p>
247 280
248<p class=description> 281<p class=description>
249Returns the local address information associated to the object. 282Returns the local address information associated to the object.
250</p> 283</p>
251 284
252<p class=return> 285<p class=return>
253The method returns a string with local IP address, a number with 286The method returns a string with local IP address, a number with
254the local port, 287the local port,
255and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 288and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
256In case of error, the method returns <b><tt>nil</tt></b>. 289In case of error, the method returns <b><tt>nil</tt></b>.
257</p> 290</p>
258 291
@@ -266,32 +299,32 @@ server:<b>getstats()</b><br>
266 299
267<p class=description> 300<p class=description>
268Returns accounting information on the socket, useful for throttling 301Returns accounting information on the socket, useful for throttling
269of bandwidth. 302of bandwidth.
270</p> 303</p>
271 304
272<p class=return> 305<p class=return>
273The method returns the number of bytes received, the number of bytes sent, 306The method returns the number of bytes received, the number of bytes sent,
274and the age of the socket object in seconds. 307and the age of the socket object in seconds.
275</p> 308</p>
276 309
277<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 310<!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
278 311
279<p class=name id="listen"> 312<p class=name id="listen">
280master:<b>listen(</b>backlog<b>)</b> 313master:<b>listen(</b>backlog<b>)</b>
281</p> 314</p>
282 315
283<p class=description> 316<p class=description>
284Specifies the socket is willing to receive connections, transforming the 317Specifies the socket is willing to receive connections, transforming the
285object into a server object. Server objects support the 318object into a server object. Server objects support the
286<a href=#accept><tt>accept</tt></a>, 319<a href=#accept><tt>accept</tt></a>,
287<a href=#getsockname><tt>getsockname</tt></a>, 320<a href=#getsockname><tt>getsockname</tt></a>,
288<a href=#setoption><tt>setoption</tt></a>, 321<a href=#setoption><tt>setoption</tt></a>,
289<a href=#settimeout><tt>settimeout</tt></a>, 322<a href=#settimeout><tt>settimeout</tt></a>,
290and <a href=#close><tt>close</tt></a> methods. 323and <a href=#close><tt>close</tt></a> methods.
291</p> 324</p>
292 325
293<p class=parameters> 326<p class=parameters>
294The parameter <tt>backlog</tt> specifies the number of client 327The parameter <tt>backlog</tt> specifies the number of client
295connections that can 328connections that can
296be queued waiting for service. If the queue is full and another client 329be queued waiting for service. If the queue is full and another client
297attempts connection, the connection is refused. 330attempts connection, the connection is refused.
@@ -310,11 +343,11 @@ client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
310 343
311<p class=description> 344<p class=description>
312Reads data from a client object, according to the specified <em>read 345Reads 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. 346pattern</em>. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible.
314</p> 347</p>
315 348
316<p class=parameters> 349<p class=parameters>
317<tt>Pattern</tt> can be any of the following: 350<tt>Pattern</tt> can be any of the following:
318</p> 351</p>
319 352
320<ul> 353<ul>
@@ -325,7 +358,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 358CR character (ASCII&nbsp;13). The CR and LF characters are not included in
326the returned line. In fact, <em>all</em> CR characters are 359the returned line. In fact, <em>all</em> CR characters are
327ignored by the pattern. This is the default pattern; 360ignored by the pattern. This is the default pattern;
328<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt> 361<li> <tt>number</tt>: causes the method to read a specified <tt>number</tt>
329of bytes from the socket. 362of bytes from the socket.
330</ul> 363</ul>
331 364
@@ -347,10 +380,10 @@ closed before the transmission was completed or the string
347<p class=note> 380<p class=note>
348<b>Important note</b>: This function was changed <em>severely</em>. It used 381<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 382to 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 383now 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 384way 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 385functions should return <tt><b>nil</b></tt> on error. Thus it was changed
353too. 386too.
354</p> 387</p>
355 388
356<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 389<!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -366,7 +399,7 @@ Sends <tt>data</tt> through client object.
366<p class=parameters> 399<p class=parameters>
367<tt>Data</tt> is the string to be sent. The optional arguments 400<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 401<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 402<tt>string.sub</tt> Lua function to allow the selection of a
370substring to be sent. 403substring to be sent.
371</p> 404</p>
372 405
@@ -385,10 +418,10 @@ there was a timeout during the operation.
385</p> 418</p>
386 419
387<p class=note> 420<p class=note>
388Note: Output is <em>not</em> buffered. For small strings, 421Note: Output is <em>not</em> buffered. For small strings,
389it is always better to concatenate them in Lua 422it is always better to concatenate them in Lua
390(with the '<tt>..</tt>' operator) and send the result in one call 423(with the '<tt>..</tt>' operator) and send the result in one call
391instead of calling the method several times. 424instead of calling the method several times.
392</p> 425</p>
393 426
394<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 427<!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -400,12 +433,12 @@ server:<b>setoption(</b>option [, value]<b>)</b>
400 433
401<p class=description> 434<p class=description>
402Sets options for the TCP object. Options are only needed by low-level or 435Sets options for the TCP object. Options are only needed by low-level or
403time-critical applications. You should only modify an option if you 436time-critical applications. You should only modify an option if you
404are sure you need it. 437are sure you need it.
405</p> 438</p>
406 439
407<p class=parameters> 440<p class=parameters>
408<tt>Option</tt> is a string with the option name, and <tt>value</tt> 441<tt>Option</tt> is a string with the option name, and <tt>value</tt>
409depends on the option being set: 442depends on the option being set:
410 443
411<ul> 444<ul>
@@ -413,7 +446,7 @@ depends on the option being set:
413<li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables 446<li> '<tt>keepalive</tt>': Setting this option to <tt>true</tt> enables
414the periodic transmission of messages on a connected socket. Should the 447the periodic transmission of messages on a connected socket. Should the
415connected party fail to respond to these messages, the connection is 448connected party fail to respond to these messages, the connection is
416considered broken and processes using the socket are notified; 449considered broken and processes using the socket are notified;
417 450
418<li> '<tt>linger</tt>': Controls the action taken when unsent data are 451<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 452queued on a socket and a close is performed. The value is a table with a
@@ -424,13 +457,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 457'<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 458process 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 459quickly as possible. I do not advise you to set this to anything other than
427zero; 460zero;
428 461
429<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules 462<li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules
430used in validating addresses supplied in a call to 463used in validating addresses supplied in a call to
431<a href=#bind><tt>bind</tt></a> should allow reuse of local addresses; 464<a href=#bind><tt>bind</tt></a> should allow reuse of local addresses;
432 465
433<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt> 466<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt>
434disables the Nagle's algorithm for the connection; 467disables the Nagle's algorithm for the connection;
435 468
436<li> '<tt>ipv6-v6only</tt>': 469<li> '<tt>ipv6-v6only</tt>':
@@ -485,7 +518,7 @@ server:<b>setstats(</b>received, sent, age<b>)</b><br>
485 518
486<p class=description> 519<p class=description>
487Resets accounting information on the socket, useful for throttling 520Resets accounting information on the socket, useful for throttling
488of bandwidth. 521of bandwidth.
489</p> 522</p>
490 523
491<p class=parameters> 524<p class=parameters>
@@ -495,7 +528,7 @@ of bandwidth.
495</p> 528</p>
496 529
497<p class=return> 530<p class=return>
498The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise. 531The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
499</p> 532</p>
500 533
501<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 534<!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -509,8 +542,8 @@ server:<b>settimeout(</b>value [, mode]<b>)</b>
509<p class=description> 542<p class=description>
510Changes the timeout values for the object. By default, 543Changes the timeout values for the object. By default,
511all I/O operations are blocking. That is, any call to the methods 544all I/O operations are blocking. That is, any call to the methods
512<a href=#send><tt>send</tt></a>, 545<a href=#send><tt>send</tt></a>,
513<a href=#receive><tt>receive</tt></a>, and 546<a href=#receive><tt>receive</tt></a>, and
514<a href=#accept><tt>accept</tt></a> 547<a href=#accept><tt>accept</tt></a>
515will block indefinitely, until the operation completes. The 548will block indefinitely, until the operation completes. The
516<tt>settimeout</tt> method defines a limit on the amount of time the 549<tt>settimeout</tt> method defines a limit on the amount of time the
@@ -521,7 +554,7 @@ time has elapsed, the affected methods give up and fail with an error code.
521<p class=parameters> 554<p class=parameters>
522The amount of time to wait is specified as the 555The amount of time to wait is specified as the
523<tt>value</tt> parameter, in seconds. There are two timeout modes and 556<tt>value</tt> parameter, in seconds. There are two timeout modes and
524both can be used together for fine tuning: 557both can be used together for fine tuning:
525</p> 558</p>
526 559
527<ul> 560<ul>
@@ -532,7 +565,7 @@ default mode;</li>
532 565
533<li> '<tt>t</tt>': <em>total</em> timeout. Specifies the upper limit on 566<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 567the amount of time LuaSocket can block a Lua script before returning from
535a call.</li> 568a call.</li>
536</ul> 569</ul>
537 570
538<p class=parameters> 571<p class=parameters>
@@ -562,7 +595,7 @@ client:<b>shutdown(</b>mode<b>)</b><br>
562</p> 595</p>
563 596
564<p class=description> 597<p class=description>
565Shuts down part of a full-duplex connection. 598Shuts down part of a full-duplex connection.
566</p> 599</p>
567 600
568<p class=parameters> 601<p class=parameters>
@@ -608,7 +641,7 @@ server:<b>getfd()</b>
608</p> 641</p>
609 642
610<p class=description> 643<p class=description>
611Returns the underling socket descriptor or handle associated to the object. 644Returns the underling socket descriptor or handle associated to the object.
612</p> 645</p>
613 646
614<p class=return> 647<p class=return>
diff --git a/doc/udp.html b/doc/udp.html
index e5b0ad0..a300f2f 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,62 @@ 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<p class=note>
80Note: Before the choice between IPv4 and IPv6 happens,
81the internal socket object is invalid and therefore <a
82href=#setoption><tt>setoption</tt></a> will fail.
83</p>
84
85<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
86
87<p class="name" id="socket.udp">
88socket.<b>udp4()</b>
89</p>
90
91<p class="description">
92Creates and returns an unconnected IPv4 UDP object.
93Unconnected objects support the
94<a href="#sendto"><tt>sendto</tt></a>,
95<a href="#receive"><tt>receive</tt></a>,
96<a href="#receivefrom"><tt>receivefrom</tt></a>,
97<a href="#getoption"><tt>getoption</tt></a>,
98<a href="#getsockname"><tt>getsockname</tt></a>,
99<a href="#setoption"><tt>setoption</tt></a>,
100<a href="#settimeout"><tt>settimeout</tt></a>,
101<a href="#setpeername"><tt>setpeername</tt></a>,
102<a href="#setsockname"><tt>setsockname</tt></a>, and
103<a href="#close"><tt>close</tt></a>.
104The <a href="#setpeername"><tt>setpeername</tt></a>
62is used to connect the object. 105is used to connect the object.
63</p> 106</p>
64 107
@@ -75,19 +118,19 @@ socket.<b>udp6()</b>
75</p> 118</p>
76 119
77<p class="description"> 120<p class="description">
78Creates and returns an unconnected IPv6 UDP object. 121Creates and returns an unconnected IPv6 UDP object.
79Unconnected objects support the 122Unconnected objects support the
80<a href="#sendto"><tt>sendto</tt></a>, 123<a href="#sendto"><tt>sendto</tt></a>,
81<a href="#receive"><tt>receive</tt></a>, 124<a href="#receive"><tt>receive</tt></a>,
82<a href="#receivefrom"><tt>receivefrom</tt></a>, 125<a href="#receivefrom"><tt>receivefrom</tt></a>,
83<a href="#getoption"><tt>getoption</tt></a>, 126<a href="#getoption"><tt>getoption</tt></a>,
84<a href="#getsockname"><tt>getsockname</tt></a>, 127<a href="#getsockname"><tt>getsockname</tt></a>,
85<a href="#setoption"><tt>setoption</tt></a>, 128<a href="#setoption"><tt>setoption</tt></a>,
86<a href="#settimeout"><tt>settimeout</tt></a>, 129<a href="#settimeout"><tt>settimeout</tt></a>,
87<a href="#setpeername"><tt>setpeername</tt></a>, 130<a href="#setpeername"><tt>setpeername</tt></a>,
88<a href="#setsockname"><tt>setsockname</tt></a>, and 131<a href="#setsockname"><tt>setsockname</tt></a>, and
89<a href="#close"><tt>close</tt></a>. 132<a href="#close"><tt>close</tt></a>.
90The <a href="#setpeername"><tt>setpeername</tt></a> 133The <a href="#setpeername"><tt>setpeername</tt></a>
91is used to connect the object. 134is used to connect the object.
92</p> 135</p>
93 136
@@ -102,10 +145,6 @@ Note: The TCP object returned will have the option
102"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>. 145"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
103</p> 146</p>
104 147
105
106
107<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
108
109<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 148<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
110 149
111<p class="name" id="close"> 150<p class="name" id="close">
@@ -142,10 +181,10 @@ associated with a connected UDP object.
142 181
143 182
144<p class=return> 183<p class=return>
145Returns a string with the IP address of the peer, the 184Returns a string with the IP address of the peer, the
146port number that peer is using for the connection, 185port number that peer is using for the connection,
147and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 186and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
148In case of error, the method returns <b><tt>nil</tt></b>. 187In case of error, the method returns <b><tt>nil</tt></b>.
149</p> 188</p>
150 189
151<p class="note"> 190<p class="note">
@@ -165,9 +204,9 @@ Returns the local address information associated to the object.
165 204
166 205
167<p class=return> 206<p class=return>
168The method returns a string with local IP address, a number with 207The method returns a string with local IP address, a number with
169the local port, 208the local port,
170and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 209and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
171In case of error, the method returns <b><tt>nil</tt></b>. 210In case of error, the method returns <b><tt>nil</tt></b>.
172</p> 211</p>
173 212
@@ -217,7 +256,7 @@ unconnected:<b>receivefrom(</b>[size]<b>)</b>
217</p> 256</p>
218 257
219<p class="description"> 258<p class="description">
220Works exactly as the <a href="#receive"><tt>receive</tt></a> 259Works exactly as the <a href="#receive"><tt>receive</tt></a>
221method, except it returns the IP 260method, except it returns the IP
222address and port as extra return values (and is therefore slightly less 261address and port as extra return values (and is therefore slightly less
223efficient). 262efficient).
@@ -236,7 +275,7 @@ See <a href=#setoption><tt>setoption</tt></a> for
236description of the option names and values. 275description of the option names and values.
237</p> 276</p>
238 277
239<p class="parameters"><tt>Option</tt> is a string with the option name. 278<p class="parameters"><tt>Option</tt> is a string with the option name.
240<ul> 279<ul>
241<li> '<tt>dontroute</tt>' 280<li> '<tt>dontroute</tt>'
242<li> '<tt>broadcast</tt>' 281<li> '<tt>broadcast</tt>'
@@ -246,9 +285,9 @@ description of the option names and values.
246<li> '<tt>ipv6-v6only</tt>' 285<li> '<tt>ipv6-v6only</tt>'
247<li> '<tt>ip-multicast-if</tt>' 286<li> '<tt>ip-multicast-if</tt>'
248<li> '<tt>ip-multicast-ttl</tt>' 287<li> '<tt>ip-multicast-ttl</tt>'
249<li> '<tt>ip-add-membership</tt>' 288<li> '<tt>ip-add-membership</tt>'
250<li> '<tt>ip-drop-membership</tt>' 289<li> '<tt>ip-drop-membership</tt>'
251</ul> 290</ul>
252</p> 291</p>
253 292
254<p class=return> 293<p class=return>
@@ -268,7 +307,7 @@ Sends a datagram to the UDP peer of a connected object.
268</p> 307</p>
269 308
270<p class="parameters"> 309<p class="parameters">
271<tt>Datagram</tt> is a string with the datagram contents. 310<tt>Datagram</tt> is a string with the datagram contents.
272The maximum datagram size for UDP is 64K minus IP layer overhead. 311The maximum datagram size for UDP is 64K minus IP layer overhead.
273However datagrams larger than the link layer packet size will be 312However datagrams larger than the link layer packet size will be
274fragmented, which may deteriorate performance and/or reliability. 313fragmented, which may deteriorate performance and/or reliability.
@@ -298,11 +337,11 @@ Sends a datagram to the specified IP address and port number.
298 337
299<p class="parameters"> 338<p class="parameters">
300<tt>Datagram</tt> is a string with the 339<tt>Datagram</tt> is a string with the
301datagram contents. 340datagram contents.
302The maximum datagram size for UDP is 64K minus IP layer overhead. 341The maximum datagram size for UDP is 64K minus IP layer overhead.
303However datagrams larger than the link layer packet size will be 342However datagrams larger than the link layer packet size will be
304fragmented, which may deteriorate performance and/or reliability. 343fragmented, which may deteriorate performance and/or reliability.
305<tt>Ip</tt> is the IP address of the recipient. 344<tt>Ip</tt> is the IP address of the recipient.
306Host names are <em>not</em> allowed for performance reasons. 345Host names are <em>not</em> allowed for performance reasons.
307 346
308<tt>Port</tt> is the port number at the recipient. 347<tt>Port</tt> is the port number at the recipient.
@@ -337,9 +376,9 @@ object or vice versa.
337For connected objects, outgoing datagrams 376For connected objects, outgoing datagrams
338will be sent to the specified peer, and datagrams received from 377will be sent to the specified peer, and datagrams received from
339other peers will be discarded by the OS. Connected UDP objects must 378other peers will be discarded by the OS. Connected UDP objects must
340use the <a href="#send"><tt>send</tt></a> and 379use the <a href="#send"><tt>send</tt></a> and
341<a href="#receive"><tt>receive</tt></a> methods instead of 380<a href="#receive"><tt>receive</tt></a> methods instead of
342<a href="#sendto"><tt>sendto</tt></a> and 381<a href="#sendto"><tt>sendto</tt></a> and
343<a href="#receivefrom"><tt>receivefrom</tt></a>. 382<a href="#receivefrom"><tt>receivefrom</tt></a>.
344</p> 383</p>
345 384
@@ -421,16 +460,16 @@ only modify an option if you are sure you need it.</p>
421name, and <tt>value</tt> depends on the option being set: 460name, and <tt>value</tt> depends on the option being set:
422</p> 461</p>
423 462
424<ul> 463<ul>
425<li> '<tt>dontroute</tt>': Indicates that outgoing 464<li> '<tt>dontroute</tt>': Indicates that outgoing
426messages should bypass the standard routing facilities. 465messages should bypass the standard routing facilities.
427Receives a boolean value; 466Receives a boolean value;
428<li> '<tt>broadcast</tt>': Requests permission to send 467<li> '<tt>broadcast</tt>': Requests permission to send
429broadcast datagrams on the socket. 468broadcast datagrams on the socket.
430Receives a boolean value; 469Receives a boolean value;
431<li> '<tt>reuseaddr</tt>': Indicates that the rules used in 470<li> '<tt>reuseaddr</tt>': Indicates that the rules used in
432validating addresses supplied in a <tt>bind()</tt> call 471validating addresses supplied in a <tt>bind()</tt> call
433should allow reuse of local addresses. 472should allow reuse of local addresses.
434Receives a boolean value; 473Receives a boolean value;
435<li> '<tt>reuseport</tt>': Allows completely duplicate 474<li> '<tt>reuseport</tt>': Allows completely duplicate
436bindings by multiple processes if they all set 475bindings by multiple processes if they all set
@@ -442,7 +481,7 @@ datagram is delivered to the sending host as long as it is a
442member of the multicast group. 481member of the multicast group.
443Receives a boolean value; 482Receives a boolean value;
444<li> '<tt>ipv6-v6only</tt>': 483<li> '<tt>ipv6-v6only</tt>':
445Specifies whether to restrict <tt>inet6</tt> sockets to 484Specifies whether to restrict <tt>inet6</tt> sockets to
446sending and receiving only IPv6 packets. 485sending and receiving only IPv6 packets.
447Receive a boolean value; 486Receive a boolean value;
448<li> '<tt>ip-multicast-if</tt>': 487<li> '<tt>ip-multicast-if</tt>':
@@ -451,9 +490,9 @@ are sent.
451Receives an IP address; 490Receives an IP address;
452<li> '<tt>ip-multicast-ttl</tt>': 491<li> '<tt>ip-multicast-ttl</tt>':
453Sets the Time To Live in the IP header for outgoing 492Sets the Time To Live in the IP header for outgoing
454multicast datagrams. 493multicast datagrams.
455Receives a number; 494Receives a number;
456<li> '<tt>ip-add-membership</tt>': 495<li> '<tt>ip-add-membership</tt>':
457Joins the multicast group specified. 496Joins the multicast group specified.
458Receives a table with fields 497Receives a table with fields
459<tt>multiaddr</tt> and <tt>interface</tt>, each containing an 498<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
@@ -463,7 +502,7 @@ group specified.
463Receives a table with fields 502Receives a table with fields
464<tt>multiaddr</tt> and <tt>interface</tt>, each containing an 503<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
465IP address. 504IP address.
466</ul> 505</ul>
467 506
468<p class="return"> 507<p class="return">
469The method returns 1 in case of success, or 508The method returns 1 in case of success, or
@@ -482,14 +521,14 @@ unconnected:<b>settimeout(</b>value<b>)</b>
482</p> 521</p>
483 522
484<p class="description"> 523<p class="description">
485Changes the timeout values for the object. By default, the 524Changes the timeout values for the object. By default, the
486<a href="#receive"><tt>receive</tt></a> and 525<a href="#receive"><tt>receive</tt></a> and
487<a href="#receivefrom"><tt>receivefrom</tt></a> 526<a href="#receivefrom"><tt>receivefrom</tt></a>
488operations are blocking. That is, any call to the methods will block 527operations are blocking. That is, any call to the methods will block
489indefinitely, until data arrives. The <tt>settimeout</tt> function defines 528indefinitely, until data arrives. The <tt>settimeout</tt> function defines
490a limit on the amount of time the functions can block. When a timeout is 529a 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 530set and the specified amount of time has elapsed, the affected methods
492give up and fail with an error code. 531give up and fail with an error code.
493</p> 532</p>
494 533
495<p class="parameters"> 534<p class="parameters">
@@ -524,7 +563,7 @@ imperative nature obvious.
524<a href="index.html#download">download</a> &middot; 563<a href="index.html#download">download</a> &middot;
525<a href="installation.html">installation</a> &middot; 564<a href="installation.html">installation</a> &middot;
526<a href="introduction.html">introduction</a> &middot; 565<a href="introduction.html">introduction</a> &middot;
527<a href="reference.html">reference</a> 566<a href="reference.html">reference</a>
528</p> 567</p>
529<p> 568<p>
530<small> 569<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..331b800 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}
@@ -344,8 +352,13 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp)
344/*-------------------------------------------------------------------------*\ 352/*-------------------------------------------------------------------------*\
345* Tries to create a new inet socket 353* Tries to create a new inet socket
346\*-------------------------------------------------------------------------*/ 354\*-------------------------------------------------------------------------*/
347const char *inet_trycreate(p_socket ps, int family, int type) { 355const char *inet_trycreate(p_socket ps, int family, int type, int protocol) {
348 return socket_strerror(socket_create(ps, family, type, 0)); 356 const char *err = socket_strerror(socket_create(ps, family, type, protocol));
357 if (err == NULL && family == AF_INET6) {
358 int yes = 1;
359 setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes));
360 }
361 return err;
349} 362}
350 363
351/*-------------------------------------------------------------------------*\ 364/*-------------------------------------------------------------------------*\
@@ -354,21 +367,21 @@ const char *inet_trycreate(p_socket ps, int family, int type) {
354const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm) 367const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
355{ 368{
356 switch (family) { 369 switch (family) {
357 case PF_INET: { 370 case AF_INET: {
358 struct sockaddr_in sin; 371 struct sockaddr_in sin;
359 memset((char *) &sin, 0, sizeof(sin)); 372 memset((char *) &sin, 0, sizeof(sin));
360 sin.sin_family = AF_UNSPEC; 373 sin.sin_family = AF_UNSPEC;
361 sin.sin_addr.s_addr = INADDR_ANY; 374 sin.sin_addr.s_addr = INADDR_ANY;
362 return socket_strerror(socket_connect(ps, (SA *) &sin, 375 return socket_strerror(socket_connect(ps, (SA *) &sin,
363 sizeof(sin), tm)); 376 sizeof(sin), tm));
364 } 377 }
365 case PF_INET6: { 378 case AF_INET6: {
366 struct sockaddr_in6 sin6; 379 struct sockaddr_in6 sin6;
367 struct in6_addr addrany = IN6ADDR_ANY_INIT; 380 struct in6_addr addrany = IN6ADDR_ANY_INIT;
368 memset((char *) &sin6, 0, sizeof(sin6)); 381 memset((char *) &sin6, 0, sizeof(sin6));
369 sin6.sin6_family = AF_UNSPEC; 382 sin6.sin6_family = AF_UNSPEC;
370 sin6.sin6_addr = addrany; 383 sin6.sin6_addr = addrany;
371 return socket_strerror(socket_connect(ps, (SA *) &sin6, 384 return socket_strerror(socket_connect(ps, (SA *) &sin6,
372 sizeof(sin6), tm)); 385 sizeof(sin6), tm));
373 } 386 }
374 } 387 }
@@ -383,6 +396,7 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
383{ 396{
384 struct addrinfo *iterator = NULL, *resolved = NULL; 397 struct addrinfo *iterator = NULL, *resolved = NULL;
385 const char *err = NULL; 398 const char *err = NULL;
399 int current_family = *family;
386 /* try resolving */ 400 /* try resolving */
387 err = socket_gaistrerror(getaddrinfo(address, serv, 401 err = socket_gaistrerror(getaddrinfo(address, serv,
388 connecthints, &resolved)); 402 connecthints, &resolved));
@@ -397,23 +411,23 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
397 * that shows up while iterating. if there was a 411 * that shows up while iterating. if there was a
398 * bind, all families will be the same and we will 412 * bind, all families will be the same and we will
399 * not enter this branch. */ 413 * not enter this branch. */
400 if (*family != iterator->ai_family) { 414 if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
401 socket_destroy(ps); 415 socket_destroy(ps);
402 err = socket_strerror(socket_create(ps, iterator->ai_family, 416 err = inet_trycreate(ps, iterator->ai_family,
403 iterator->ai_socktype, iterator->ai_protocol)); 417 iterator->ai_socktype, iterator->ai_protocol);
404 if (err != NULL) { 418 if (err) continue;
405 freeaddrinfo(resolved); 419 current_family = iterator->ai_family;
406 return err; 420 /* set non-blocking before connect */
407 }
408 *family = iterator->ai_family;
409 /* all sockets initially non-blocking */
410 socket_setnonblocking(ps); 421 socket_setnonblocking(ps);
411 } 422 }
412 /* try connecting to remote address */ 423 /* try connecting to remote address */
413 err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, 424 err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
414 (socklen_t) iterator->ai_addrlen, tm)); 425 (socklen_t) iterator->ai_addrlen, tm));
415 /* if success, break out of loop */ 426 /* if success, break out of loop */
416 if (err == NULL) break; 427 if (err == NULL) {
428 *family = current_family;
429 break;
430 }
417 } 431 }
418 freeaddrinfo(resolved); 432 freeaddrinfo(resolved);
419 /* here, if err is set, we failed */ 433 /* here, if err is set, we failed */
@@ -423,29 +437,27 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
423/*-------------------------------------------------------------------------*\ 437/*-------------------------------------------------------------------------*\
424* Tries to accept a socket 438* Tries to accept a socket
425\*-------------------------------------------------------------------------*/ 439\*-------------------------------------------------------------------------*/
426const char *inet_tryaccept(p_socket server, int family, p_socket client, 440const char *inet_tryaccept(p_socket server, int family, p_socket client,
427 p_timeout tm) 441 p_timeout tm) {
428{
429 socklen_t len; 442 socklen_t len;
430 t_sockaddr_storage addr; 443 t_sockaddr_storage addr;
431 if (family == PF_INET6) { 444 switch (family) {
432 len = sizeof(struct sockaddr_in6); 445 case AF_INET6: len = sizeof(struct sockaddr_in6); break;
433 } else { 446 case AF_INET: len = sizeof(struct sockaddr_in); break;
434 len = sizeof(struct sockaddr_in); 447 default: len = sizeof(addr); break;
435 } 448 }
436 return socket_strerror(socket_accept(server, client, (SA *) &addr, 449 return socket_strerror(socket_accept(server, client, (SA *) &addr,
437 &len, tm)); 450 &len, tm));
438} 451}
439 452
440/*-------------------------------------------------------------------------*\ 453/*-------------------------------------------------------------------------*\
441* Tries to bind socket to (address, port) 454* Tries to bind socket to (address, port)
442\*-------------------------------------------------------------------------*/ 455\*-------------------------------------------------------------------------*/
443const char *inet_trybind(p_socket ps, const char *address, const char *serv, 456const char *inet_trybind(p_socket ps, int *family, const char *address,
444 struct addrinfo *bindhints) 457 const char *serv, struct addrinfo *bindhints) {
445{
446 struct addrinfo *iterator = NULL, *resolved = NULL; 458 struct addrinfo *iterator = NULL, *resolved = NULL;
447 const char *err = NULL; 459 const char *err = NULL;
448 t_socket sock = *ps; 460 int current_family = *family;
449 /* translate luasocket special values to C */ 461 /* translate luasocket special values to C */
450 if (strcmp(address, "*") == 0) address = NULL; 462 if (strcmp(address, "*") == 0) address = NULL;
451 if (!serv) serv = "0"; 463 if (!serv) serv = "0";
@@ -457,35 +469,32 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv,
457 } 469 }
458 /* iterate over resolved addresses until one is good */ 470 /* iterate over resolved addresses until one is good */
459 for (iterator = resolved; iterator; iterator = iterator->ai_next) { 471 for (iterator = resolved; iterator; iterator = iterator->ai_next) {
460 if(sock == SOCKET_INVALID) { 472 if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
461 err = socket_strerror(socket_create(&sock, iterator->ai_family, 473 socket_destroy(ps);
462 iterator->ai_socktype, iterator->ai_protocol)); 474 err = inet_trycreate(ps, iterator->ai_family,
463 if(err) 475 iterator->ai_socktype, iterator->ai_protocol);
464 continue; 476 if (err) continue;
477 current_family = iterator->ai_family;
465 } 478 }
466 /* try binding to local address */ 479 /* try binding to local address */
467 err = socket_strerror(socket_bind(&sock, 480 err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr,
468 (SA *) iterator->ai_addr,
469 (socklen_t) iterator->ai_addrlen)); 481 (socklen_t) iterator->ai_addrlen));
470
471 /* keep trying unless bind succeeded */ 482 /* keep trying unless bind succeeded */
472 if (err) { 483 if (err == NULL) {
473 if(sock != *ps) 484 *family = current_family;
474 socket_destroy(&sock); 485 /* set to non-blocking after bind */
475 } else { 486 socket_setnonblocking(ps);
476 /* remember what we connected to, particularly the family */
477 *bindhints = *iterator;
478 break; 487 break;
479 } 488 }
480 } 489 }
481 /* cleanup and return error */ 490 /* cleanup and return error */
482 freeaddrinfo(resolved); 491 freeaddrinfo(resolved);
483 *ps = sock; 492 /* here, if err is set, we failed */
484 return err; 493 return err;
485} 494}
486 495
487/*-------------------------------------------------------------------------*\ 496/*-------------------------------------------------------------------------*\
488* Some systems do not provide these so that we provide our own. 497* Some systems do not provide these so that we provide our own.
489\*-------------------------------------------------------------------------*/ 498\*-------------------------------------------------------------------------*/
490#ifdef LUASOCKET_INET_ATON 499#ifdef LUASOCKET_INET_ATON
491int inet_aton(const char *cp, struct in_addr *inp) 500int inet_aton(const char *cp, struct in_addr *inp)
@@ -510,7 +519,7 @@ int inet_aton(const char *cp, struct in_addr *inp)
510#endif 519#endif
511 520
512#ifdef LUASOCKET_INET_PTON 521#ifdef LUASOCKET_INET_PTON
513int inet_pton(int af, const char *src, void *dst) 522int inet_pton(int af, const char *src, void *dst)
514{ 523{
515 struct addrinfo hints, *res; 524 struct addrinfo hints, *res;
516 int ret = 1; 525 int ret = 1;
@@ -527,7 +536,7 @@ int inet_pton(int af, const char *src, void *dst)
527 } else { 536 } else {
528 ret = -1; 537 ret = -1;
529 } 538 }
530 freeaddrinfo(res); 539 freeaddrinfo(res);
531 return ret; 540 return ret;
532} 541}
533 542
diff --git a/src/inet.h b/src/inet.h
index 1f1a96a..feb3541 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
@@ -24,11 +24,11 @@
24 24
25int inet_open(lua_State *L); 25int inet_open(lua_State *L);
26 26
27const char *inet_trycreate(p_socket ps, int family, int type); 27const char *inet_trycreate(p_socket ps, int family, int type, int protocol);
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..7bf1af5 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;
@@ -352,37 +355,36 @@ static int meth_settimeout(lua_State *L)
352* Creates a master tcp object 355* Creates a master tcp object
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 p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
356 const char *err = inet_trycreate(&sock, family, SOCK_STREAM); 359 memset(tcp, 0, sizeof(t_tcp));
357 /* try to allocate a system socket */ 360 /* set its type as master object */
358 if (!err) { 361 auxiliar_setclass(L, "tcp{master}", -1);
359 /* allocate tcp object */ 362 /* if family is AF_UNSPEC, we leave the socket invalid and
360 p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp)); 363 * store AF_UNSPEC into family. This will allow it to later be
361 memset(tcp, 0, sizeof(t_tcp)); 364 * replaced with an AF_INET6 or AF_INET socket upon first use. */
362 /* set its type as master object */ 365 tcp->sock = SOCKET_INVALID;
363 auxiliar_setclass(L, "tcp{master}", -1); 366 tcp->family = family;
364 /* initialize remaining structure fields */ 367 io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
365 socket_setnonblocking(&sock); 368 (p_error) socket_ioerror, &tcp->sock);
366 if (family == PF_INET6) { 369 timeout_init(&tcp->tm, -1, -1);
367 int yes = 1; 370 buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
368 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, 371 if (family != AF_UNSPEC) {
369 (void *)&yes, sizeof(yes)); 372 const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0);
373 if (err != NULL) {
374 lua_pushnil(L);
375 lua_pushstring(L, err);
376 return 2;
370 } 377 }
371 tcp->sock = sock; 378 socket_setnonblocking(&tcp->sock);
372 io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
373 (p_error) socket_ioerror, &tcp->sock);
374 timeout_init(&tcp->tm, -1, -1);
375 buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
376 tcp->family = family;
377 return 1;
378 } else {
379 lua_pushnil(L);
380 lua_pushstring(L, err);
381 return 2;
382 } 379 }
380 return 1;
383} 381}
384 382
385static int global_create(lua_State *L) { 383static int global_create(lua_State *L) {
384 return tcp_create(L, AF_UNSPEC);
385}
386
387static int global_create4(lua_State *L) {
386 return tcp_create(L, AF_INET); 388 return tcp_create(L, AF_INET);
387} 389}
388 390
@@ -390,53 +392,6 @@ static int global_create6(lua_State *L) {
390 return tcp_create(L, AF_INET6); 392 return tcp_create(L, AF_INET6);
391} 393}
392 394
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) { 395static int global_connect(lua_State *L) {
441 const char *remoteaddr = luaL_checkstring(L, 1); 396 const char *remoteaddr = luaL_checkstring(L, 1);
442 const char *remoteserv = luaL_checkstring(L, 2); 397 const char *remoteserv = luaL_checkstring(L, 2);
@@ -453,26 +408,26 @@ static int global_connect(lua_State *L) {
453 timeout_init(&tcp->tm, -1, -1); 408 timeout_init(&tcp->tm, -1, -1);
454 buffer_init(&tcp->buf, &tcp->io, &tcp->tm); 409 buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
455 tcp->sock = SOCKET_INVALID; 410 tcp->sock = SOCKET_INVALID;
456 tcp->family = PF_UNSPEC; 411 tcp->family = AF_UNSPEC;
457 /* allow user to pick local address and port */ 412 /* allow user to pick local address and port */
458 memset(&bindhints, 0, sizeof(bindhints)); 413 memset(&bindhints, 0, sizeof(bindhints));
459 bindhints.ai_socktype = SOCK_STREAM; 414 bindhints.ai_socktype = SOCK_STREAM;
460 bindhints.ai_family = family; 415 bindhints.ai_family = family;
461 bindhints.ai_flags = AI_PASSIVE; 416 bindhints.ai_flags = AI_PASSIVE;
462 if (localaddr) { 417 if (localaddr) {
463 err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints); 418 err = inet_trybind(&tcp->sock, &tcp->family, localaddr,
419 localserv, &bindhints);
464 if (err) { 420 if (err) {
465 lua_pushnil(L); 421 lua_pushnil(L);
466 lua_pushstring(L, err); 422 lua_pushstring(L, err);
467 return 2; 423 return 2;
468 } 424 }
469 tcp->family = bindhints.ai_family;
470 } 425 }
471 /* try to connect to remote address and port */ 426 /* try to connect to remote address and port */
472 memset(&connecthints, 0, sizeof(connecthints)); 427 memset(&connecthints, 0, sizeof(connecthints));
473 connecthints.ai_socktype = SOCK_STREAM; 428 connecthints.ai_socktype = SOCK_STREAM;
474 /* make sure we try to connect only to the same family */ 429 /* make sure we try to connect only to the same family */
475 connecthints.ai_family = bindhints.ai_family; 430 connecthints.ai_family = tcp->family;
476 err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv, 431 err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv,
477 &tcp->tm, &connecthints); 432 &tcp->tm, &connecthints);
478 if (err) { 433 if (err) {
diff --git a/src/udp.c b/src/udp.c
index 7ff00f5..17d932a 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};
@@ -183,7 +185,7 @@ static int meth_sendto(lua_State *L) {
183 return 2; 185 return 2;
184 } 186 }
185 timeout_markstart(tm); 187 timeout_markstart(tm);
186 err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, 188 err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr,
187 (socklen_t) ai->ai_addrlen, tm); 189 (socklen_t) ai->ai_addrlen, tm);
188 freeaddrinfo(ai); 190 freeaddrinfo(ai);
189 if (err != IO_DONE) { 191 if (err != IO_DONE) {
@@ -235,7 +237,7 @@ static int meth_receivefrom(lua_State *L)
235 char portstr[6]; 237 char portstr[6];
236 timeout_markstart(tm); 238 timeout_markstart(tm);
237 count = MIN(count, sizeof(buffer)); 239 count = MIN(count, sizeof(buffer));
238 err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, 240 err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr,
239 &addr_len, tm); 241 &addr_len, tm);
240 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */ 242 /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
241 if (err == IO_CLOSED) 243 if (err == IO_CLOSED)
@@ -245,7 +247,7 @@ static int meth_receivefrom(lua_State *L)
245 lua_pushstring(L, udp_strerror(err)); 247 lua_pushstring(L, udp_strerror(err));
246 return 2; 248 return 2;
247 } 249 }
248 err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, 250 err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
249 INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV); 251 INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV);
250 if (err) { 252 if (err) {
251 lua_pushnil(L); 253 lua_pushnil(L);
@@ -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 {
@@ -349,7 +351,7 @@ static int meth_setpeername(lua_State *L) {
349 /* make sure we try to connect only to the same family */ 351 /* make sure we try to connect only to the same family */
350 connecthints.ai_family = udp->family; 352 connecthints.ai_family = udp->family;
351 if (connecting) { 353 if (connecting) {
352 err = inet_tryconnect(&udp->sock, &udp->family, address, 354 err = inet_tryconnect(&udp->sock, &udp->family, address,
353 port, tm, &connecthints); 355 port, tm, &connecthints);
354 if (err) { 356 if (err) {
355 lua_pushnil(L); 357 lua_pushnil(L);
@@ -363,7 +365,6 @@ static int meth_setpeername(lua_State *L) {
363 inet_trydisconnect(&udp->sock, udp->family, tm); 365 inet_trydisconnect(&udp->sock, udp->family, tm);
364 auxiliar_setclass(L, "udp{unconnected}", 1); 366 auxiliar_setclass(L, "udp{unconnected}", 1);
365 } 367 }
366 /* change class to connected or unconnected depending on address */
367 lua_pushnumber(L, 1); 368 lua_pushnumber(L, 1);
368 return 1; 369 return 1;
369} 370}
@@ -391,7 +392,7 @@ static int meth_setsockname(lua_State *L) {
391 bindhints.ai_socktype = SOCK_DGRAM; 392 bindhints.ai_socktype = SOCK_DGRAM;
392 bindhints.ai_family = udp->family; 393 bindhints.ai_family = udp->family;
393 bindhints.ai_flags = AI_PASSIVE; 394 bindhints.ai_flags = AI_PASSIVE;
394 err = inet_trybind(&udp->sock, address, port, &bindhints); 395 err = inet_trybind(&udp->sock, &udp->family, address, port, &bindhints);
395 if (err) { 396 if (err) {
396 lua_pushnil(L); 397 lua_pushnil(L);
397 lua_pushstring(L, err); 398 lua_pushstring(L, err);
@@ -408,32 +409,32 @@ static int meth_setsockname(lua_State *L) {
408* Creates a master udp object 409* Creates a master udp object
409\*-------------------------------------------------------------------------*/ 410\*-------------------------------------------------------------------------*/
410static int udp_create(lua_State *L, int family) { 411static int udp_create(lua_State *L, int family) {
411 t_socket sock; 412 /* allocate udp object */
412 const char *err = inet_trycreate(&sock, family, SOCK_DGRAM); 413 p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
413 /* try to allocate a system socket */ 414 auxiliar_setclass(L, "udp{unconnected}", -1);
414 if (!err) { 415 /* if family is AF_UNSPEC, we leave the socket invalid and
415 /* allocate udp object */ 416 * store AF_UNSPEC into family. This will allow it to later be
416 p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp)); 417 * replaced with an AF_INET6 or AF_INET socket upon first use. */
417 auxiliar_setclass(L, "udp{unconnected}", -1); 418 udp->sock = SOCKET_INVALID;
418 /* initialize remaining structure fields */ 419 timeout_init(&udp->tm, -1, -1);
419 socket_setnonblocking(&sock); 420 udp->family = family;
420 if (family == PF_INET6) { 421 if (family != AF_UNSPEC) {
421 int yes = 1; 422 const char *err = inet_trycreate(&udp->sock, family, SOCK_DGRAM, 0);
422 setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, 423 if (err != NULL) {
423 (void *)&yes, sizeof(yes)); 424 lua_pushnil(L);
425 lua_pushstring(L, err);
426 return 2;
424 } 427 }
425 udp->sock = sock; 428 socket_setnonblocking(&udp->sock);
426 timeout_init(&udp->tm, -1, -1);
427 udp->family = family;
428 return 1;
429 } else {
430 lua_pushnil(L);
431 lua_pushstring(L, err);
432 return 2;
433 } 429 }
430 return 1;
434} 431}
435 432
436static int global_create(lua_State *L) { 433static int global_create(lua_State *L) {
434 return udp_create(L, AF_UNSPEC);
435}
436
437static int global_create4(lua_State *L) {
437 return udp_create(L, AF_INET); 438 return udp_create(L, AF_INET);
438} 439}
439 440
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..ee1201f 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
@@ -304,15 +304,20 @@ function isclosed(c)
304end 304end
305 305
306function active_close() 306function active_close()
307 reconnect() 307 local tcp = socket.tcp4()
308 if isclosed(data) then fail("should not be closed") end 308 if isclosed(tcp) then fail("should not be closed") end
309 data:close() 309 tcp:close()
310 if not isclosed(data) then fail("should be closed") end 310 if not isclosed(tcp) then fail("should be closed") end
311 data = nil 311 tcp = socket.tcp()
312 local udp = socket.udp() 312 if not isclosed(tcp) then fail("should be closed") end
313 tcp = nil
314 local udp = socket.udp4()
313 if isclosed(udp) then fail("should not be closed") end 315 if isclosed(udp) then fail("should not be closed") end
314 udp:close() 316 udp:close()
315 if not isclosed(udp) then fail("should be closed") end 317 if not isclosed(udp) then fail("should be closed") end
318 udp = socket.udp()
319 if not isclosed(udp) then fail("should be closed") end
320 udp = nil
316 pass("ok") 321 pass("ok")
317end 322end
318 323
@@ -327,7 +332,7 @@ function test_closed()
327 data:close() 332 data:close()
328 data = nil 333 data = nil
329 ]], str)) 334 ]], str))
330 -- try to get a line 335 -- try to get a line
331 back, err, partial = data:receive() 336 back, err, partial = data:receive()
332 if not err then fail("should have gotten 'closed'.") 337 if not err then fail("should have gotten 'closed'.")
333 elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.") 338 elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.")
@@ -340,25 +345,25 @@ function test_closed()
340 data = nil 345 data = nil
341 ]] 346 ]]
342 total, err, partial = data:send(string.rep("ugauga", 100000)) 347 total, err, partial = data:send(string.rep("ugauga", 100000))
343 if not err then 348 if not err then
344 pass("failed: output buffer is at least %d bytes long!", total) 349 pass("failed: output buffer is at least %d bytes long!", total)
345 elseif err ~= "closed" then 350 elseif err ~= "closed" then
346 fail("got '"..err.."' instead of 'closed'.") 351 fail("got '"..err.."' instead of 'closed'.")
347 else 352 else
348 pass("graceful 'closed' received after %d bytes were sent", partial) 353 pass("graceful 'closed' received after %d bytes were sent", partial)
349 end 354 end
350end 355end
351 356
352------------------------------------------------------------------------ 357------------------------------------------------------------------------
353function test_selectbugs() 358function test_selectbugs()
354 local r, s, e = socket.select(nil, nil, 0.1) 359 local r, s, e = socket.select(nil, nil, 0.1)
355 assert(type(r) == "table" and type(s) == "table" and 360 assert(type(r) == "table" and type(s) == "table" and
356 (e == "timeout" or e == "error")) 361 (e == "timeout" or e == "error"))
357 pass("both nil: ok") 362 pass("both nil: ok")
358 local udp = socket.udp() 363 local udp = socket.udp()
359 udp:close() 364 udp:close()
360 r, s, e = socket.select({ udp }, { udp }, 0.1) 365 r, s, e = socket.select({ udp }, { udp }, 0.1)
361 assert(type(r) == "table" and type(s) == "table" and 366 assert(type(r) == "table" and type(s) == "table" and
362 (e == "timeout" or e == "error")) 367 (e == "timeout" or e == "error"))
363 pass("closed sockets: ok") 368 pass("closed sockets: ok")
364 e = pcall(socket.select, "wrong", 1, 0.1) 369 e = pcall(socket.select, "wrong", 1, 0.1)
@@ -368,7 +373,7 @@ function test_selectbugs()
368 pass("invalid input: ok") 373 pass("invalid input: ok")
369 local toomany = {} 374 local toomany = {}
370 for i = 1, socket._SETSIZE+1 do 375 for i = 1, socket._SETSIZE+1 do
371 toomany[#toomany+1] = socket.udp() 376 toomany[#toomany+1] = socket.udp4()
372 end 377 end
373 if #toomany > socket._SETSIZE then 378 if #toomany > socket._SETSIZE then
374 local e = pcall(socket.select, toomany, nil, 0.1) 379 local e = pcall(socket.select, toomany, nil, 0.1)
@@ -389,7 +394,7 @@ function accept_timeout()
389 local t = socket.gettime() 394 local t = socket.gettime()
390 s:settimeout(1) 395 s:settimeout(1)
391 local c, e = s:accept() 396 local c, e = s:accept()
392 assert(not c, "should not accept") 397 assert(not c, "should not accept")
393 assert(e == "timeout", string.format("wrong error message (%s)", e)) 398 assert(e == "timeout", string.format("wrong error message (%s)", e))
394 t = socket.gettime() - t 399 t = socket.gettime() - t
395 assert(t < 2, string.format("took to long to give up (%gs)", t)) 400 assert(t < 2, string.format("took to long to give up (%gs)", t))
@@ -407,9 +412,9 @@ function connect_timeout()
407 local t = socket.gettime() 412 local t = socket.gettime()
408 local r, e = c:connect("10.0.0.1", 81) 413 local r, e = c:connect("10.0.0.1", 81)
409 assert(not r, "should not connect") 414 assert(not r, "should not connect")
410 assert(socket.gettime() - t < 2, "took too long to give up.") 415 assert(socket.gettime() - t < 2, "took too long to give up.")
411 c:close() 416 c:close()
412 pass("ok") 417 pass("ok")
413end 418end
414 419
415------------------------------------------------------------------------ 420------------------------------------------------------------------------
@@ -447,16 +452,14 @@ end
447 452
448------------------------------------------------------------------------ 453------------------------------------------------------------------------
449function rebind_test() 454function rebind_test()
450 --local c ,c1 = socket.bind("localhost", 0)
451 local c ,c1 = socket.bind("127.0.0.1", 0) 455 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 456 if not c then pass ("failed to bind! " .. tostring(c) .. ' ' .. tostring(c1)) return end
453 assert(c,c1) 457 assert(c,c1)
454
455 local i, p = c:getsockname() 458 local i, p = c:getsockname()
456 local s, e = socket.tcp() 459 local s, e = socket.tcp()
457 assert(s, e) 460 assert(s, e)
458 s:setoption("reuseaddr", false) 461 s:setoption("reuseaddr", false)
459 r, e = s:bind("localhost", p) 462 r, e = s:bind(i, p)
460 assert(not r, "managed to rebind!") 463 assert(not r, "managed to rebind!")
461 assert(e) 464 assert(e)
462 pass("ok") 465 pass("ok")
@@ -476,9 +479,9 @@ function getstats_test()
476 data:receive(c) 479 data:receive(c)
477 t = t + c 480 t = t + c
478 local r, s, a = data:getstats() 481 local r, s, a = data:getstats()
479 assert(r == t, "received count failed" .. tostring(r) 482 assert(r == t, "received count failed" .. tostring(r)
480 .. "/" .. tostring(t)) 483 .. "/" .. tostring(t))
481 assert(s == t, "sent count failed" .. tostring(s) 484 assert(s == t, "sent count failed" .. tostring(s)
482 .. "/" .. tostring(t)) 485 .. "/" .. tostring(t))
483 end 486 end
484 pass("ok") 487 pass("ok")
@@ -486,7 +489,7 @@ end
486 489
487 490
488------------------------------------------------------------------------ 491------------------------------------------------------------------------
489function test_nonblocking(size) 492function test_nonblocking(size)
490 reconnect() 493 reconnect()
491 printf("testing " .. 2*size .. " bytes: ") 494 printf("testing " .. 2*size .. " bytes: ")
492remote(string.format([[ 495remote(string.format([[
@@ -545,7 +548,7 @@ function test_readafterclose()
545 data:close() 548 data:close()
546 data = nil 549 data = nil
547 ]])) 550 ]]))
548 data:close() 551 data:close()
549 back, err, partial = data:receive("*a") 552 back, err, partial = data:receive("*a")
550 assert(back == nil and err == "closed", "should have returned 'closed'") 553 assert(back == nil and err == "closed", "should have returned 'closed'")
551 pass("ok") 554 pass("ok")
@@ -555,7 +558,7 @@ function test_readafterclose()
555 data:close() 558 data:close()
556 data = nil 559 data = nil
557 ]])) 560 ]]))
558 data:close() 561 data:close()
559 back, err, partial = data:receive() 562 back, err, partial = data:receive()
560 assert(back == nil and err == "closed", "should have returned 'closed'") 563 assert(back == nil and err == "closed", "should have returned 'closed'")
561 pass("ok") 564 pass("ok")
@@ -565,7 +568,7 @@ function test_readafterclose()
565 data:close() 568 data:close()
566 data = nil 569 data = nil
567 ]])) 570 ]]))
568 data:close() 571 data:close()
569 back, err, partial = data:receive(1) 572 back, err, partial = data:receive(1)
570 assert(back == nil and err == "closed", "should have returned 'closed'") 573 assert(back == nil and err == "closed", "should have returned 'closed'")
571 pass("ok") 574 pass("ok")
@@ -575,7 +578,7 @@ function test_readafterclose()
575 data:close() 578 data:close()
576 data = nil 579 data = nil
577 ]])) 580 ]]))
578 data:close() 581 data:close()
579 back, err, partial = data:receive(0) 582 back, err, partial = data:receive(0)
580 assert(back == nil and err == "closed", "should have returned 'closed'") 583 assert(back == nil and err == "closed", "should have returned 'closed'")
581 pass("ok") 584 pass("ok")
@@ -593,7 +596,7 @@ function test_writeafterclose()
593 while not err do 596 while not err do
594 sent, err, errsent, time = data:send(str) 597 sent, err, errsent, time = data:send(str)
595 end 598 end
596 assert(err == "closed", "should have returned 'closed'") 599 assert(err == "closed", "got " .. err .. " instead of 'closed'")
597 pass("ok") 600 pass("ok")
598end 601end
599 602
@@ -648,18 +651,18 @@ else io.stderr:write("Warning! IPv6 does not support!\n") end
648end 651end
649 652
650local udp_methods = { 653local udp_methods = {
651 "close", 654 "close",
652 "dirty", 655 "dirty",
653 "getfamily", 656 "getfamily",
654 "getfd", 657 "getfd",
655 "getoption", 658 "getoption",
656 "getpeername", 659 "getpeername",
657 "getsockname", 660 "getsockname",
658 "receive", 661 "receive",
659 "receivefrom", 662 "receivefrom",
660 "send", 663 "send",
661 "sendto", 664 "sendto",
662 "setfd", 665 "setfd",
663 "setoption", 666 "setoption",
664 "setpeername", 667 "setpeername",
665 "setsockname", 668 "setsockname",
@@ -674,6 +677,9 @@ if sock then test_methods(socket.udp6(), udp_methods)
674else io.stderr:write("Warning! IPv6 does not support!\n") end 677else io.stderr:write("Warning! IPv6 does not support!\n") end
675end 678end
676 679
680test("closed connection detection: ")
681test_closed()
682
677test("partial receive") 683test("partial receive")
678test_partialrecv() 684test_partialrecv()
679 685
@@ -697,9 +703,6 @@ rebind_test()
697test("active close: ") 703test("active close: ")
698active_close() 704active_close()
699 705
700test("closed connection detection: ")
701test_closed()
702
703test("accept function: ") 706test("accept function: ")
704accept_timeout() 707accept_timeout()
705accept_errors() 708accept_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)