diff --git a/doc/http.html b/doc/http.html
index cd41c0d..3b7a8b1 100644
--- a/doc/http.html
+++ b/doc/http.html
@@ -112,12 +112,15 @@ the HTTP module:
 </p>
 
 <ul>
-<li> <tt>PORT</tt>: default port used for connections; 
-<li> <tt>PROXY</tt>: default proxy used for connections; 
+<li> <tt>PROXY</tt>: default proxy used for connections;
 <li> <tt>TIMEOUT</tt>: sets the timeout for all I/O operations;
 <li> <tt>USERAGENT</tt>: default user agent reported to server.
 </ul>
 
+<p class=note id="post">
+Note: These constants are global. Changing them will also
+change the behavior other code that might be using LuaSocket.
+</p>
 
 <!-- http.request ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
diff --git a/doc/mime.html b/doc/mime.html
index ae136fd..8cb3507 100644
--- a/doc/mime.html
+++ b/doc/mime.html
@@ -72,34 +72,6 @@ local mime = require("mime")
 
 <h3 id=high>High-level filters</h3>
 
-<!-- normalize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
-
-<p class=name id="normalize">
-mime.<b>normalize(</b>[marker]<b>)</b>
-</p>
-
-<p class=description>
-Converts most common end-of-line markers to a specific given marker. 
-</p>
-
-<p class=parameters>
-<tt>Marker</tt> is the new marker. It defaults to CRLF, the canonic 
-end-of-line marker defined by the MIME standard.
-</p>
-
-<p class=return>
-The function returns a filter that performs the conversion. 
-</p>
-
-<p class=note>
-Note: There is no perfect solution to this problem. Different end-of-line
-markers are an evil that will probably plague developers forever. 
-This function, however, will work perfectly for text created with any of
-the most common end-of-line markers, i.e. the Mac OS (CR), the Unix (LF), 
-or the DOS (CRLF) conventions. Even if the data has mixed end-of-line
-markers, the function will still work well, although it doesn't 
-guarantee that the number of empty lines will be correct.
-</p>
 
 <!-- decode +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
@@ -159,6 +131,35 @@ base64 = ltn12.filter.chain(
 )
 </pre>
 
+<!-- normalize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id="normalize">
+mime.<b>normalize(</b>[marker]<b>)</b>
+</p>
+
+<p class=description>
+Converts most common end-of-line markers to a specific given marker. 
+</p>
+
+<p class=parameters>
+<tt>Marker</tt> is the new marker. It defaults to CRLF, the canonic 
+end-of-line marker defined by the MIME standard.
+</p>
+
+<p class=return>
+The function returns a filter that performs the conversion. 
+</p>
+
+<p class=note>
+Note: There is no perfect solution to this problem. Different end-of-line
+markers are an evil that will probably plague developers forever. 
+This function, however, will work perfectly for text created with any of
+the most common end-of-line markers, i.e. the Mac OS (CR), the Unix (LF), 
+or the DOS (CRLF) conventions. Even if the data has mixed end-of-line
+markers, the function will still work well, although it doesn't 
+guarantee that the number of empty lines will be correct.
+</p>
+
 <!-- stuff +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class=name id="stuff">
@@ -466,7 +467,7 @@ marker.
 <p>
 <small>
 Last modified by Diego Nehab on <br>
-Thu Apr 20 00:25:44 EDT 2006
+Fri Mar  4 15:19:17 BRT 2016
 </small>
 </p>
 </center>
diff --git a/doc/reference.css b/doc/reference.css
index b1dd25d..04e38cf 100644
--- a/doc/reference.css
+++ b/doc/reference.css
@@ -2,6 +2,7 @@ body {
     margin-left: 1em; 
     margin-right: 1em; 
     font-family: "Verdana", sans-serif; 
+    background: #ffffff;
 }
 
 tt {
diff --git a/doc/reference.html b/doc/reference.html
index e9bb5eb..287dc19 100644
--- a/doc/reference.html
+++ b/doc/reference.html
@@ -147,6 +147,7 @@ Support, Manual">
 <a href="socket.html#connect">connect</a>,
 <a href="socket.html#connect">connect4</a>,
 <a href="socket.html#connect">connect6</a>,
+<a href="socket.html#datagramsize">_DATAGRAMSIZE</a>,
 <a href="socket.html#debug">_DEBUG</a>,
 <a href="dns.html#dns">dns</a>,
 <a href="socket.html#gettime">gettime</a>,
@@ -158,11 +159,14 @@ Support, Manual">
 <a href="socket.html#skip">skip</a>,
 <a href="socket.html#sleep">sleep</a>,
 <a href="socket.html#setsize">_SETSIZE</a>,
+<a href="socket.html#socketinvalid">_SOCKETINVALID</a>,
 <a href="socket.html#source">source</a>,
 <a href="tcp.html#socket.tcp">tcp</a>,
+<a href="tcp.html#socket.tcp4">tcp4</a>,
 <a href="tcp.html#socket.tcp6">tcp6</a>,
 <a href="socket.html#try">try</a>,
 <a href="udp.html#socket.udp">udp</a>,
+<a href="udp.html#socket.udp4">udp4</a>,
 <a href="udp.html#socket.udp6">udp6</a>,
 <a href="socket.html#version">_VERSION</a>.
 </blockquote>
@@ -183,6 +187,7 @@ Support, Manual">
 <a href="tcp.html#getpeername">getpeername</a>,
 <a href="tcp.html#getsockname">getsockname</a>,
 <a href="tcp.html#getstats">getstats</a>,
+<a href="tcp.html#gettimeout">gettimeout</a>,
 <a href="tcp.html#listen">listen</a>,
 <a href="tcp.html#receive">receive</a>,
 <a href="tcp.html#send">send</a>,
@@ -203,6 +208,7 @@ Support, Manual">
 <a href="udp.html#getoption">getoption</a>,
 <a href="udp.html#getpeername">getpeername</a>,
 <a href="udp.html#getsockname">getsockname</a>,
+<a href="udp.html#gettimeout">gettimeout</a>,
 <a href="udp.html#receive">receive</a>,
 <a href="udp.html#receivefrom">receivefrom</a>,
 <a href="udp.html#send">send</a>,
diff --git a/doc/smtp.html b/doc/smtp.html
index bbbff80..600ec37 100644
--- a/doc/smtp.html
+++ b/doc/smtp.html
@@ -114,6 +114,124 @@ the SMTP module:
 <li> <tt>ZONE</tt>: default time zone.
 </ul>
 
+<!-- message ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id=message> 
+smtp.<b>message(</b>mesgt<b>)</b>
+</p>
+
+<p class=description>
+Returns a <em>simple</em>
+<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> source that sends an SMTP message body, possibly multipart (arbitrarily deep). 
+</p>
+
+<p class=parameters>
+The only parameter of the function is a table describing the message.
+<tt>Mesgt</tt> has the following form (notice the recursive structure):
+</p>
+
+<blockquote>
+<table summary="Mesgt table structure">
+<tr><td><tt>
+mesgt = {<br>
+&nbsp;&nbsp;headers = <i>header-table</i>,<br>
+&nbsp;&nbsp;body = <i>LTN12 source</i> or <i>string</i> or 
+<i>multipart-mesgt</i><br>
+}<br>
+&nbsp;<br>
+multipart-mesgt = {<br>
+&nbsp;&nbsp;[preamble = <i>string</i>,]<br>
+&nbsp;&nbsp;[1] = <i>mesgt</i>,<br>
+&nbsp;&nbsp;[2] = <i>mesgt</i>,<br>
+&nbsp;&nbsp;...<br>
+&nbsp;&nbsp;[<i>n</i>] = <i>mesgt</i>,<br>
+&nbsp;&nbsp;[epilogue = <i>string</i>,]<br>
+}<br>
+</tt></td></tr>
+</table>
+</blockquote>
+
+<p class=parameters>
+For a simple message, all that is needed is a set of <tt>headers</tt>
+and the <tt>body</tt>. The message <tt>body</tt> can be given as a string
+or as a <em>simple</em> 
+<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 
+source. For multipart messages, the body is a table that
+recursively defines each part as an independent message, plus an optional
+<tt>preamble</tt> and <tt>epilogue</tt>.
+</p>
+
+<p class=return> 
+The function returns a <em>simple</em> 
+<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 
+source that produces the
+message contents as defined by <tt>mesgt</tt>, chunk by chunk. 
+Hopefully, the following
+example will make things clear. When in doubt, refer to the appropriate RFC
+as listed in the introduction.  </p>
+
+<pre class=example>
+-- load the smtp support and its friends
+local smtp = require("socket.smtp")
+local mime = require("mime")
+local ltn12 = require("ltn12")
+
+-- creates a source to send a message with two parts. The first part is 
+-- plain text, the second part is a PNG image, encoded as base64.
+source = smtp.message{
+  headers = {
+     -- Remember that headers are *ignored* by smtp.send. 
+     from = "Sicrano de Oliveira &lt;sicrano@example.com&gt;",
+     to = "Fulano da Silva &lt;fulano@example.com&gt;",
+     subject = "Here is a message with attachments"
+  },
+  body = {
+    preamble = "If your client doesn't understand attachments, \r\n" ..
+               "it will still display the preamble and the epilogue.\r\n" ..
+               "Preamble will probably appear even in a MIME enabled client.",
+    -- first part: no headers means plain text, us-ascii.
+    -- The mime.eol low-level filter normalizes end-of-line markers.
+    [1] = { 
+      body = mime.eol(0, [[
+        Lines in a message body should always end with CRLF. 
+        The smtp module will *NOT* perform translation. However, the 
+        send function *DOES* perform SMTP stuffing, whereas the message
+        function does *NOT*.
+      ]])
+    },
+    -- second part: headers describe content to be a png image, 
+    -- sent under the base64 transfer content encoding.
+    -- notice that nothing happens until the message is actually sent. 
+    -- small chunks are loaded into memory right before transmission and 
+    -- translation happens on the fly.
+    [2] = { 
+      headers = {
+        ["content-type"] = 'image/png; name="image.png"',
+        ["content-disposition"] = 'attachment; filename="image.png"',
+        ["content-description"] = 'a beautiful image',
+        ["content-transfer-encoding"] = "BASE64"
+      },
+      body = ltn12.source.chain(
+        ltn12.source.file(io.open("image.png", "rb")),
+        ltn12.filter.chain(
+          mime.encode("base64"),
+          mime.wrap()
+        )
+      )
+    },
+    epilogue = "This might also show up, but after the attachments"
+  }
+}
+
+-- finally send it
+r, e = smtp.send{
+    from = "&lt;sicrano@example.com&gt;",
+    rcpt = "&lt;fulano@example.com&gt;",
+    source = source,
+}
+</pre>
+
+
 <!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class=name id=send> 
@@ -275,123 +393,6 @@ r, e = smtp.send{
 }
 </pre>
 
-<!-- message ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
-
-<p class=name id=message> 
-smtp.<b>message(</b>mesgt<b>)</b>
-</p>
-
-<p class=description>
-Returns a <em>simple</em>
-<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> source that sends an SMTP message body, possibly multipart (arbitrarily deep). 
-</p>
-
-<p class=parameters>
-The only parameter of the function is a table describing the message.
-<tt>Mesgt</tt> has the following form (notice the recursive structure):
-</p>
-
-<blockquote>
-<table summary="Mesgt table structure">
-<tr><td><tt>
-mesgt = {<br>
-&nbsp;&nbsp;headers = <i>header-table</i>,<br>
-&nbsp;&nbsp;body = <i>LTN12 source</i> or <i>string</i> or 
-<i>multipart-mesgt</i><br>
-}<br>
-&nbsp;<br>
-multipart-mesgt = {<br>
-&nbsp;&nbsp;[preamble = <i>string</i>,]<br>
-&nbsp;&nbsp;[1] = <i>mesgt</i>,<br>
-&nbsp;&nbsp;[2] = <i>mesgt</i>,<br>
-&nbsp;&nbsp;...<br>
-&nbsp;&nbsp;[<i>n</i>] = <i>mesgt</i>,<br>
-&nbsp;&nbsp;[epilogue = <i>string</i>,]<br>
-}<br>
-</tt></td></tr>
-</table>
-</blockquote>
-
-<p class=parameters>
-For a simple message, all that is needed is a set of <tt>headers</tt>
-and the <tt>body</tt>. The message <tt>body</tt> can be given as a string
-or as a <em>simple</em> 
-<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 
-source. For multipart messages, the body is a table that
-recursively defines each part as an independent message, plus an optional
-<tt>preamble</tt> and <tt>epilogue</tt>.
-</p>
-
-<p class=return> 
-The function returns a <em>simple</em> 
-<a href="http://lua-users.org/wiki/FiltersSourcesAndSinks">LTN12</a> 
-source that produces the
-message contents as defined by <tt>mesgt</tt>, chunk by chunk. 
-Hopefully, the following
-example will make things clear. When in doubt, refer to the appropriate RFC
-as listed in the introduction.  </p>
-
-<pre class=example>
--- load the smtp support and its friends
-local smtp = require("socket.smtp")
-local mime = require("mime")
-local ltn12 = require("ltn12")
-
--- creates a source to send a message with two parts. The first part is 
--- plain text, the second part is a PNG image, encoded as base64.
-source = smtp.message{
-  headers = {
-     -- Remember that headers are *ignored* by smtp.send. 
-     from = "Sicrano de Oliveira &lt;sicrano@example.com&gt;",
-     to = "Fulano da Silva &lt;fulano@example.com&gt;",
-     subject = "Here is a message with attachments"
-  },
-  body = {
-    preamble = "If your client doesn't understand attachments, \r\n" ..
-               "it will still display the preamble and the epilogue.\r\n" ..
-               "Preamble will probably appear even in a MIME enabled client.",
-    -- first part: no headers means plain text, us-ascii.
-    -- The mime.eol low-level filter normalizes end-of-line markers.
-    [1] = { 
-      body = mime.eol(0, [[
-        Lines in a message body should always end with CRLF. 
-        The smtp module will *NOT* perform translation. However, the 
-        send function *DOES* perform SMTP stuffing, whereas the message
-        function does *NOT*.
-      ]])
-    },
-    -- second part: headers describe content to be a png image, 
-    -- sent under the base64 transfer content encoding.
-    -- notice that nothing happens until the message is actually sent. 
-    -- small chunks are loaded into memory right before transmission and 
-    -- translation happens on the fly.
-    [2] = { 
-      headers = {
-        ["content-type"] = 'image/png; name="image.png"',
-        ["content-disposition"] = 'attachment; filename="image.png"',
-        ["content-description"] = 'a beautiful image',
-        ["content-transfer-encoding"] = "BASE64"
-      },
-      body = ltn12.source.chain(
-        ltn12.source.file(io.open("image.png", "rb")),
-        ltn12.filter.chain(
-          mime.encode("base64"),
-          mime.wrap()
-        )
-      )
-    },
-    epilogue = "This might also show up, but after the attachments"
-  }
-}
-
--- finally send it
-r, e = smtp.send{
-    from = "&lt;sicrano@example.com&gt;",
-    rcpt = "&lt;fulano@example.com&gt;",
-    source = source,
-}
-</pre>
-
 <!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <div class=footer>
diff --git a/doc/socket.html b/doc/socket.html
index b9303cb..35f8391 100644
--- a/doc/socket.html
+++ b/doc/socket.html
@@ -51,6 +51,30 @@ To obtain the <tt>socket</tt> namespace, run:
 local socket = require("socket")
 </pre>
 
+<!-- headers.canonic ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id="headers.canonic">
+socket.headers.<b>canonic</b></p>
+
+<p> The <tt>socket.headers.canonic</tt> table 
+is used by the HTTP and SMTP modules to translate from 
+lowercase field names back into their canonic 
+capitalization. When a lowercase field name exists as a key
+in this table, the associated value is substituted in
+whenever the field name is sent out.
+</p>
+
+<p> 
+You can obtain the <tt>headers</tt> namespace if case run-time
+modifications are required by running:
+</p>
+
+<pre class=example>
+-- loads the headers module 
+local headers = require("headers")
+</pre>
+
+
 <!-- bind ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class=name id=bind> 
@@ -90,7 +114,7 @@ of connect are defined as simple helper functions that restrict the
 
 <!-- debug ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id=debug> 
+<p class=name id=debug>
 socket.<b>_DEBUG</b>
 </p>
 
@@ -99,6 +123,19 @@ This constant is set to <tt><b>true</b></tt> if the library was compiled
 with debug support.
 </p>
 
+<!-- datagramsize +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id=debug>
+socket.<b>_DATAGRAMSIZE</b>
+</p>
+
+<p class=description>
+Default datagram size used by calls to
+<a href="udp.html#receive"<tt>receive</tt></a> and
+<a href="udp.html#receivefrom"><tt>receivefrom</tt></a>.
+(Unless changed in compile time, the value is 8192.)
+</p>
+
 <!-- get time +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class=name id=gettime> 
@@ -106,8 +143,7 @@ socket.<b>gettime()</b>
 </p>
 
 <p class=description>
-Returns the time in seconds, relative to the origin of the 
-universe. You should subtract the values returned by this function
+Returns the UNIX time in seconds. You should subtract the values returned by this function
 to get meaningful values. 
 </p>
 
@@ -117,29 +153,6 @@ t = socket.gettime()
 print(socket.gettime() - t .. " seconds elapsed")
 </pre>
 
-<!-- socket.headers ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
-
-<p class=name id="headers.canonic">
-socket.headers.<b>canonic</b></p>
-
-<p> The <tt>socket.headers.canonic</tt> table 
-is used by the HTTP and SMTP modules to translate from 
-lowercase field names back into their canonic 
-capitalization. When a lowercase field name exists as a key
-in this table, the associated value is substituted in
-whenever the field name is sent out.
-</p>
-
-<p> 
-You can obtain the <tt>headers</tt> namespace if case run-time
-modifications are required by running:
-</p>
-
-<pre class=example>
--- loads the headers module 
-local headers = require("headers")
-</pre>
-
 <!-- newtry +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class=name id=newtry> 
@@ -155,8 +168,7 @@ is  raised.
 
 <p class=parameters> 
 <tt>Finalizer</tt> is a function that will be called before
-<tt>try</tt> throws the exception. It will be called 
-in <em>protected</em> mode.
+<tt>try</tt> throws the exception.
 </p>
 
 <p class=return> 
@@ -204,15 +216,9 @@ to throw exceptions.
 </p>
 
 <p class=return>
-Returns an equivalent function that instead of throwing exceptions,
-returns <tt><b>nil</b></tt> followed by an error message. 
-</p>
-
-<p class=note>
-Note: Beware that if your function performs some illegal operation that
-raises an error, the protected function will catch the error and return it
-as a string. This is because the <a href=#try><tt>try</tt></a> function
-uses errors as the mechanism to throw exceptions.  
+Returns an equivalent function that instead of throwing exceptions in case of
+a failed <a href=#try><tt>try</tt></a> call, returns <tt><b>nil</b></tt>
+followed by an error message.
 </p>
 
 <!-- select +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -238,7 +244,9 @@ non-numeric indices) in the arrays will be silently ignored.
 
 <p class=return> The function returns a list with the sockets ready for
 reading, a list with the sockets ready for writing and an error message.
-The error message is "<tt>timeout</tt>" if a timeout condition was met and
+The error message is "<tt>timeout</tt>" if a timeout
+condition was met, "<tt>select failed</tt>" if the call
+to <tt>select</tt> failed, and
 <tt><b>nil</b></tt> otherwise. The returned tables are
 doubly keyed both by integers and also by the sockets
 themselves, to simplify the test if a specific socket has
@@ -246,7 +254,7 @@ changed status.
 </p>
 
 <p class=note>
-<b>Note: </b>: <tt>select</tt> can monitor a limited number
+<b>Note:</b> <tt>select</tt> can monitor a limited number
 of sockets, as defined by the constant <tt>socket._SETSIZE</tt>. This
 number may be as high as 1024 or as low as 64 by default,
 depending on the system. It is usually possible to change this
@@ -276,6 +284,18 @@ it to <tt>select</tt>, it will be ignored.
 <b>Using select with non-socket objects</b>: Any object that implements <tt>getfd</tt> and <tt>dirty</tt> can be used with <tt>select</tt>, allowing objects from other libraries to be used within a <tt>socket.select</tt> driven loop.
 </p>
 
+<!-- setsize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id=setsize> 
+socket.<b>_SETSIZE</b>
+</p>
+
+<p class=description>
+The maximum number of sockets that the <a
+href=#select><tt>select</tt></a> function can handle. 
+</p>
+
+
 <!-- sink ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class=name id=sink> 
@@ -383,15 +403,14 @@ side closes the connection.
 The function returns a source with the appropriate behavior. 
 </p>
 
-<!-- setsize ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+<!-- socketinvalid ++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id=setsize> 
-socket.<b>_SETSIZE</b>
+<p class=name id=socketinvalid>
+socket.<b>_SOCKETINVALID</b>
 </p>
 
 <p class=description>
-The maximum number of sockets that the <a
-href=#select><tt>select</tt></a> function can handle. 
+The OS value for an invalid socket.
 </p>
 
 <!-- try ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -401,9 +420,9 @@ socket.<b>try(</b>ret<sub>1</sub> [, ret<sub>2</sub> ... ret<sub>N</sub>]<b>)</b
 </p>
 
 <p class=description>
-Throws an exception in case of error. The exception can only be caught 
-by the <a href=#protect><tt>protect</tt></a> function. It does not explode
-into an error message.
+Throws an exception in case <tt>ret<sub>1</sub></tt> is falsy, using
+<tt>ret<sub>2</sub></tt> as the error message. The exception is supposed to be caught 
+by a <a href=#protect><tt>protect</tt></a>ed function only.
 </p>
 
 <p class=parameters>
@@ -414,7 +433,10 @@ nested with <tt>try</tt>.
 
 <p class=return> 
 The function returns <tt>ret</tt><sub>1</sub> to <tt>ret</tt><sub>N</sub> if
-<tt>ret</tt><sub>1</sub> is not <tt><b>nil</b></tt>. Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub>.
+<tt>ret</tt><sub>1</sub> is not <tt><b>nil</b></tt> or <tt><b>false</b></tt>.
+Otherwise, it calls <tt>error</tt> passing <tt>ret</tt><sub>2</sub> wrapped
+in a table with metatable used by <a href=#protect><tt>protect</tt></a> to
+distinguish exceptions from runtime errors.
 </p>
 
 <pre class=example>
diff --git a/doc/tcp.html b/doc/tcp.html
index 4226d78..c6c6eb2 100644
--- a/doc/tcp.html
+++ b/doc/tcp.html
@@ -1,10 +1,10 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
     "http://www.w3.org/TR/html4/strict.dtd">
 <html>
 
 <head>
 <meta name="description" content="LuaSocket: The TCP/IP support">
-<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support"> 
+<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support">
 <title>LuaSocket: TCP/IP support</title>
 <link rel="stylesheet" href="reference.css" type="text/css">
 </head>
@@ -28,7 +28,7 @@
 <a href="index.html#download">download</a> &middot;
 <a href="installation.html">installation</a> &middot;
 <a href="introduction.html">introduction</a> &middot;
-<a href="reference.html">reference</a> 
+<a href="reference.html">reference</a>
 </p>
 </center>
 <hr>
@@ -36,56 +36,11 @@
 
 <!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<h2 id="tcp">TCP</h2> 
-
-<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
-
-<p class=name id="socket.tcp"> 
-socket.<b>tcp()</b>
-</p>
-
-<p class=description> 
-Creates and returns an IPv4 TCP master object. A master object can
-be transformed into a server object with the method 
-<a href=#listen><tt>listen</tt></a> (after a call to <a
-href=#bind><tt>bind</tt></a>) or into a client object with 
-the method <a href=#connect><tt>connect</tt></a>. The only other 
-method supported by a master object is the 
-<a href=#close><tt>close</tt></a> method.</p>
-
-<p class=return>
-In case of success, a new master object is returned. In case of error,
-<b><tt>nil</tt></b> is returned, followed by an error message.
-</p>
-
-<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
-
-<p class=name id="socket.tcp6"> 
-socket.<b>tcp6()</b>
-</p>
-
-<p class=description> 
-Creates and returns an IPv6 TCP master object. A master object can
-be transformed into a server object with the method 
-<a href=#listen><tt>listen</tt></a> (after a call to <a
-href=#bind><tt>bind</tt></a>) or into a client object with 
-the method <a href=#connect><tt>connect</tt></a>. The only other 
-method supported by a master object is the 
-<a href=#close><tt>close</tt></a> method.</p>
-
-<p class=return>
-In case of success, a new master object is returned. In case of error,
-<b><tt>nil</tt></b> is returned, followed by an error message.
-</p>
-
-<p class=note>
-Note: The TCP object returned will have the option
-"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
-</p>
+<h2 id="tcp">TCP</h2>
 
 <!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id="accept"> 
+<p class=name id="accept">
 server:<b>accept()</b>
 </p>
 
@@ -95,9 +50,9 @@ object and returns a client object representing that connection.
 </p>
 
 <p class=return>
-If a connection is successfully initiated, a client object is returned.  
+If a connection is successfully initiated, a client object is returned.
 If a  timeout condition  is  met,  the method  returns <b><tt>nil</tt></b>
-followed by the error string '<tt>timeout</tt>'. Other errors are 
+followed by the error string '<tt>timeout</tt>'. Other errors are
 reported by <b><tt>nil</tt></b> followed by a message describing the error.
 </p>
 
@@ -107,28 +62,28 @@ with   a  server   object   in
 the <tt>recvt</tt>  parameter  before  a   call  to  <tt>accept</tt> does
 <em>not</em> guarantee  <tt>accept</tt> will  return immediately.  Use the <a
 href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt>
-might block until <em>another</em> client shows up. 
+might block until <em>another</em> client shows up.
 </p>
 
 <!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id="bind"> 
+<p class=name id="bind">
 master:<b>bind(</b>address, port<b>)</b>
 </p>
 
 <p class=description>
 Binds a master object to <tt>address</tt> and <tt>port</tt> on the
-local host. 
+local host.
 
 <p class=parameters>
-<tt>Address</tt> can be an IP address or a host name. 
-<tt>Port</tt> must be an integer number in the range [0..64K). 
+<tt>Address</tt> can be an IP address or a host name.
+<tt>Port</tt> must be an integer number in the range [0..64K).
 If <tt>address</tt>
 is '<tt>*</tt>', the system binds to all local interfaces
 using the <tt>INADDR_ANY</tt> constant or
-<tt>IN6ADDR_ANY_INIT</tt>, according to the family. 
+<tt>IN6ADDR_ANY_INIT</tt>, according to the family.
 If <tt>port</tt> is 0, the system automatically
-chooses an ephemeral port.  
+chooses an ephemeral port.
 </p>
 
 <p class=return>
@@ -137,13 +92,13 @@ method returns <b><tt>nil</tt></b> followed by an error message.
 </p>
 
 <p class=note>
-Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a> 
+Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a>
 is available and is a shortcut for the creation of server sockets.
 </p>
 
 <!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id="close"> 
+<p class=name id="close">
 master:<b>close()</b><br>
 client:<b>close()</b><br>
 server:<b>close()</b>
@@ -154,14 +109,14 @@ Closes  a TCP object. The internal socket used by the object is closed
 and the local  address   to  which the object was
 bound is made  available to other  applications. No further  operations
 (except  for  further calls  to the <tt>close</tt> method)  are allowed on
-a closed socket. 
+a closed socket.
 </p>
 
 <p class=note>
 Note:  It is  important to  close all  used  sockets once  they are  not
 needed,  since, in  many systems,  each socket  uses a  file descriptor,
 which are limited system resources. Garbage-collected objects are
-automatically closed before destruction, though. 
+automatically closed before destruction, though.
 </p>
 
 <!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -172,19 +127,19 @@ master:<b>connect(</b>address, port<b>)</b>
 
 <p class=description>
 Attempts to connect a master object to a remote host, transforming it into a
-client object. 
-Client objects support methods 
+client object.
+Client objects support methods
 <a href=#send><tt>send</tt></a>,
-<a href=#receive><tt>receive</tt></a>, 
-<a href=#getsockname><tt>getsockname</tt></a>, 
+<a href=#receive><tt>receive</tt></a>,
+<a href=#getsockname><tt>getsockname</tt></a>,
 <a href=#getpeername><tt>getpeername</tt></a>,
-<a href=#settimeout><tt>settimeout</tt></a>, 
+<a href=#settimeout><tt>settimeout</tt></a>,
 and <a href=#close><tt>close</tt></a>.
 </p>
 
 <p class=parameters>
-<tt>Address</tt> can be an IP address or a host name. 
-<tt>Port</tt> must be an integer number in the range [1..64K). 
+<tt>Address</tt> can be an IP address or a host name.
+<tt>Port</tt> must be an integer number in the range [1..64K).
 </p>
 
 <p class=return>
@@ -193,14 +148,14 @@ describing the error. In case of success, the method returns 1.
 </p>
 
 <p class=note>
-Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a> 
+Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a>
 is available and is a shortcut for the creation of client sockets.
 </p>
 
 <p class=note>
-Note: Starting with LuaSocket 2.0, 
+Note: Starting with LuaSocket 2.0,
 the <a href=#settimeout><tt>settimeout</tt></a>
-method affects the behavior of <tt>connect</tt>, causing it to return 
+method affects the behavior of <tt>connect</tt>, causing it to return
 with an error in case of a timeout. If that happens, you can still call <a
 href=socket.html#select><tt>socket.select</tt></a> with the socket in the
 <tt>sendt</tt> table. The socket will be writable when the connection is
@@ -209,13 +164,88 @@ established.
 
 <p class=note>
 Note: Starting with LuaSocket 3.0, the host name resolution
-depends on whether the socket was created by <a
-href=#socket.tcp><tt>socket.tcp</tt></a> or <a
-href=#socket.tcp6><tt>socket.tcp6</tt></a>. Addresses from
-the appropriate family are tried in succession until the
-first success or until the last failure.
+depends on whether the socket was created by
+<a href=#socket.tcp><tt>socket.tcp</tt></a>,
+<a href=#socket.tcp4><tt>socket.tcp4</tt></a> or
+<a href=#socket.tcp6><tt>socket.tcp6</tt></a>. Addresses from
+the appropriate family (or both) are tried in the order
+returned by the resolver until the
+first success or until the last failure. If the timeout was
+set to zero, only the first address is tried.
+</p>
+
+<!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id="dirty">
+master:<b>dirty()</b><br>
+client:<b>dirty()</b><br>
+server:<b>dirty()</b>
+</p>
+
+<p class=description>
+Check the read buffer status.
+</p>
+
+<p class=return>
+Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise.
+</p>
+
+<p class=note>
+Note: <b>This is an internal method, use at your own risk.</b>
+</p>
+
+
+<!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id="getfd">
+master:<b>getfd()</b><br>
+client:<b>getfd()</b><br>
+server:<b>getfd()</b>
+</p>
+
+<p class=description>
+Returns the underling socket descriptor or handle associated to the object.
+</p>
+
+<p class=return>
+The descriptor or handle. In case the object has been closed, the return will be -1.
+</p>
+
+<p class=note>
+Note: <b>This is an internal method. Unlikely to be
+portable. Use at your own risk. </b>
+</p>
+
+
+<!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id="getoption">
+client:<b>getoption(</b>option)</b><br>
+server:<b>getoption(</b>option)</b>
+</p>
+
+<p class=description>
+Gets options for the TCP object.
+See <a href=#setoption><tt>setoption</tt></a> for description of the
+option names and values.
+</p>
+
+<p class=parameters>
+<tt>Option</tt> is a string with the option name.
+<ul>
+
+<li> '<tt>keepalive</tt>'
+<li> '<tt>linger</tt>'
+<li> '<tt>reuseaddr</tt>'
+<li> '<tt>tcp-nodelay</tt>'
+</ul>
+
+<p class=return>
+The method returns the option <tt>value</tt> in case of success, or
+<b><tt>nil</tt></b> followed by an error message otherwise.
 </p>
 
+
 <!-- getpeername ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class=name id="getpeername">
@@ -227,10 +257,10 @@ Returns information about the remote side of a connected client object.
 </p>
 
 <p class=return>
-Returns a string with the IP address of the peer, the 
-port number that peer is using for the connection, 
-and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 
-In case of error, the method returns <b><tt>nil</tt></b>. 
+Returns a string with the IP address of the peer, the
+port number that peer is using for the connection,
+and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
+In case of error, the method returns <b><tt>nil</tt></b>.
 </p>
 
 <p class=note>
@@ -246,13 +276,13 @@ server:<b>getsockname()</b>
 </p>
 
 <p class=description>
-Returns the local address information associated to the object. 
+Returns the local address information associated to the object.
 </p>
 
 <p class=return>
-The method returns a string with local IP address, a number with 
-the local port, 
-and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 
+The method returns a string with local IP address, a number with
+the local port,
+and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
 In case of error, the method returns <b><tt>nil</tt></b>.
 </p>
 
@@ -266,32 +296,46 @@ server:<b>getstats()</b><br>
 
 <p class=description>
 Returns accounting information on the socket, useful for throttling
-of bandwidth. 
+of bandwidth.
 </p>
 
 <p class=return>
 The method returns the number of bytes received, the number of bytes sent,
-and the age of the socket object in seconds. 
+and the age of the socket object in seconds.
 </p>
 
+<!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id="gettimeout">
+master:<b>gettimeout()</b><br>
+client:<b>gettimeout()</b><br>
+server:<b>gettimeout()</b>
+</p>
+
+<p class=description>
+Returns the current block timeout followed by the curent
+total timeout.
+</p>
+
+
 <!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id="listen"> 
+<p class=name id="listen">
 master:<b>listen(</b>backlog<b>)</b>
 </p>
 
 <p class=description>
 Specifies the socket is willing to receive connections, transforming the
-object into a server object.  Server objects support the 
-<a href=#accept><tt>accept</tt></a>,  
-<a href=#getsockname><tt>getsockname</tt></a>, 
-<a href=#setoption><tt>setoption</tt></a>, 
-<a href=#settimeout><tt>settimeout</tt></a>, 
-and <a href=#close><tt>close</tt></a> methods.  
+object into a server object.  Server objects support the
+<a href=#accept><tt>accept</tt></a>,
+<a href=#getsockname><tt>getsockname</tt></a>,
+<a href=#setoption><tt>setoption</tt></a>,
+<a href=#settimeout><tt>settimeout</tt></a>,
+and <a href=#close><tt>close</tt></a> methods.
 </p>
 
 <p class=parameters>
-The parameter <tt>backlog</tt> specifies the  number  of  client 
+The parameter <tt>backlog</tt> specifies the  number  of  client
 connections that can
 be queued waiting for service. If the queue is full and another  client
 attempts connection,  the connection is  refused.
@@ -310,11 +354,11 @@ client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
 
 <p class=description>
 Reads data from a client object, according to the specified <em>read
-pattern</em>.  Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible. 
+pattern</em>.  Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible.
 </p>
 
 <p class=parameters>
-<tt>Pattern</tt> can be any of the following: 
+<tt>Pattern</tt> can be any of the following:
 </p>
 
 <ul>
@@ -325,7 +369,7 @@ terminated by a  LF character (ASCII&nbsp;10), optionally  preceded by a
 CR character (ASCII&nbsp;13). The CR and LF characters are not included in
 the returned line. In fact, <em>all</em> CR characters are
 ignored by the pattern. This is the default pattern;
-<li> <tt>number</tt>:  causes the  method to read  a specified <tt>number</tt> 
+<li> <tt>number</tt>:  causes the  method to read  a specified <tt>number</tt>
 of bytes from the socket.
 </ul>
 
@@ -347,10 +391,10 @@ closed  before  the transmission  was completed  or  the string
 <p class=note>
 <b>Important note</b>: This function was changed <em>severely</em>. It used
 to support multiple patterns (but I have never seen this feature used) and
-now it doesn't anymore.  Partial results used to be returned in the same 
+now it doesn't anymore.  Partial results used to be returned in the same
 way as successful results. This last feature violated the idea that all
 functions should return <tt><b>nil</b></tt> on error.  Thus it was changed
-too. 
+too.
 </p>
 
 <!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -366,7 +410,7 @@ Sends <tt>data</tt> through client object.
 <p class=parameters>
 <tt>Data</tt> is the string to be sent. The optional arguments
 <tt>i</tt> and <tt>j</tt> work exactly like the standard
-<tt>string.sub</tt> Lua function to allow the selection of a 
+<tt>string.sub</tt> Lua function to allow the selection of a
 substring to be sent.
 </p>
 
@@ -385,10 +429,10 @@ there was  a  timeout  during  the operation.
 </p>
 
 <p class=note>
-Note: Output is <em>not</em> buffered. For small strings, 
-it is always better to concatenate them in Lua 
-(with the '<tt>..</tt>' operator) and send the result in one call 
-instead of calling the method several times. 
+Note: Output is <em>not</em> buffered. For small strings,
+it is always better to concatenate them in Lua
+(with the '<tt>..</tt>' operator) and send the result in one call
+instead of calling the method several times.
 </p>
 
 <!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -400,12 +444,12 @@ server:<b>setoption(</b>option [, value]<b>)</b>
 
 <p class=description>
 Sets options for the TCP object. Options are only needed by low-level or
-time-critical applications. You should only modify an option if you 
-are sure you need it. 
+time-critical applications. You should only modify an option if you
+are sure you need it.
 </p>
 
 <p class=parameters>
-<tt>Option</tt> is a string with the option name, and <tt>value</tt> 
+<tt>Option</tt> is a string with the option name, and <tt>value</tt>
 depends on the option being set:
 
 <ul>
@@ -413,7 +457,7 @@ depends on the option being set:
 <li> '<tt>keepalive</tt>':  Setting this option to <tt>true</tt> enables
 the periodic transmission of messages on a connected socket. Should the
 connected party fail to respond to these messages, the connection is
-considered broken and processes using the socket are notified; 
+considered broken and processes using the socket are notified;
 
 <li> '<tt>linger</tt>': Controls the action taken when unsent data are
 queued on a socket and a close is performed.  The value is a table with a
@@ -424,13 +468,13 @@ it is able to transmit the data or until '<tt>timeout</tt>' has passed. If
 '<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will
 process the close in a manner that allows the process to continue as
 quickly as possible. I do not advise you to set this to anything other than
-zero; 
+zero;
 
 <li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules
-used in validating addresses supplied in a call to 
+used in validating addresses supplied in a call to
 <a href=#bind><tt>bind</tt></a> should allow reuse of local addresses;
 
-<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt> 
+<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt>
 disables the Nagle's algorithm for the connection;
 
 <li> '<tt>ipv6-v6only</tt>':
@@ -447,34 +491,6 @@ followed by an error message otherwise.
 Note: The descriptions above come from the man pages.
 </p>
 
-<!-- getoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
-
-<p class=name id="getoption">
-client:<b>getoption(</b>option)</b><br>
-server:<b>getoption(</b>option)</b>
-</p>
-
-<p class=description>
-Gets options for the TCP object.
-See <a href=#setoption><tt>setoption</tt></a> for description of the
-option names and values.
-</p>
-
-<p class=parameters>
-<tt>Option</tt> is a string with the option name.
-<ul>
-
-<li> '<tt>keepalive</tt>'
-<li> '<tt>linger</tt>'
-<li> '<tt>reuseaddr</tt>'
-<li> '<tt>tcp-nodelay</tt>'
-</ul>
-
-<p class=return>
-The method returns the option <tt>value</tt> in case of success, or
-<b><tt>nil</tt></b> followed by an error message otherwise.
-</p>
-
 <!-- setstats +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class=name id="setstats">
@@ -485,7 +501,7 @@ server:<b>setstats(</b>received, sent, age<b>)</b><br>
 
 <p class=description>
 Resets accounting information on the socket, useful for throttling
-of bandwidth. 
+of bandwidth.
 </p>
 
 <p class=parameters>
@@ -495,7 +511,7 @@ of bandwidth.
 </p>
 
 <p class=return>
-The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise. 
+The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
 </p>
 
 <!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -509,8 +525,8 @@ server:<b>settimeout(</b>value [, mode]<b>)</b>
 <p class=description>
 Changes the timeout  values for the object. By default,
 all I/O  operations are  blocking. That  is, any  call to  the methods
-<a href=#send><tt>send</tt></a>, 
-<a href=#receive><tt>receive</tt></a>, and 
+<a href=#send><tt>send</tt></a>,
+<a href=#receive><tt>receive</tt></a>, and
 <a href=#accept><tt>accept</tt></a>
 will  block indefinitely,  until the operation completes.  The
 <tt>settimeout</tt>  method defines a  limit on the  amount  of   time  the
@@ -521,7 +537,7 @@ time has elapsed, the affected methods give up and fail with an error code.
 <p class=parameters>
 The amount of time to wait is specified  as  the
 <tt>value</tt> parameter, in seconds. There  are two timeout  modes and
-both can be used together for fine tuning: 
+both can be used together for fine tuning:
 </p>
 
 <ul>
@@ -532,7 +548,7 @@ default mode;</li>
 
 <li> '<tt>t</tt>':  <em>total</em> timeout. Specifies the  upper limit on
 the amount of  time LuaSocket can block a Lua  script before returning from
-a call.</li> 
+a call.</li>
 </ul>
 
 <p class=parameters>
@@ -562,7 +578,7 @@ client:<b>shutdown(</b>mode<b>)</b><br>
 </p>
 
 <p class=description>
-Shuts down part of a full-duplex connection. 
+Shuts down part of a full-duplex connection.
 </p>
 
 <p class=parameters>
@@ -579,66 +595,107 @@ This is the default mode;
 This function returns 1.
 </p>
 
-<!-- dirty +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+<!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id="dirty">
-master:<b>dirty()</b><br>
-client:<b>dirty()</b><br>
-server:<b>dirty()</b>
+<p class=name id="setfd">
+master:<b>setfd(</b>fd<b>)</b><br>
+client:<b>setfd(</b>fd<b>)</b><br>
+server:<b>setfd(</b>fd<b>)</b>
 </p>
 
 <p class=description>
-Check the read buffer status.
+Sets the underling socket descriptor or handle associated to the object. The current one is simply replaced, not closed, and no other change to the object state is made.
 </p>
 
 <p class=return>
-Returns <tt>true</tt> if there is any data in the read buffer, <tt>false</tt> otherwise.
+No return value.
 </p>
 
 <p class=note>
-Note: <b>This is an internal method, any use is unlikely to be portable.</b>
+Note: <b>This is an internal method. Unlikely to be
+portable. Use at your own risk. </b>
 </p>
 
-<!-- getfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id="getfd">
-master:<b>getfd()</b><br>
-client:<b>getfd()</b><br>
-server:<b>getfd()</b>
+<p class=name id="socket.tcp">
+socket.<b>tcp()</b>
 </p>
 
 <p class=description>
-Returns the underling socket descriptor or handle associated to the object. 
-</p>
+Creates and returns an TCP master object. A master object can
+be transformed into a server object with the method
+<a href=#listen><tt>listen</tt></a> (after a call to <a
+href=#bind><tt>bind</tt></a>) or into a client object with
+the method <a href=#connect><tt>connect</tt></a>. The only other
+method supported by a master object is the
+<a href=#close><tt>close</tt></a> method.</p>
 
 <p class=return>
-The descriptor or handle. In case the object has been closed, the return will be -1.
+In case of success, a new master object is returned. In case of error,
+<b><tt>nil</tt></b> is returned, followed by an error message.
 </p>
 
 <p class=note>
-Note: <b>This is an internal method, any use is unlikely to be portable.</b>
+Note: The choice between IPv4 and IPv6 happens during a call to
+<a href=#bind><tt>bind</tt></a> or <a
+href=#bind><tt>connect</tt></a>, depending on the address
+family obtained from the resolver.
 </p>
 
-<!-- setfd +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+<p class=note>
+Note: Before the choice between IPv4 and IPv6 happens,
+the internal socket object is invalid and therefore <a
+href=#setoption><tt>setoption</tt></a> will fail.
+</p>
 
-<p class=name id="setfd">
-master:<b>setfd(</b>fd<b>)</b><br>
-client:<b>setfd(</b>fd<b>)</b><br>
-server:<b>setfd(</b>fd<b>)</b>
+<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id="socket.tcp4">
+socket.<b>tcp4()</b>
 </p>
 
 <p class=description>
-Sets the underling socket descriptor or handle associated to the object. The current one is simply replaced, not closed, and no other change to the object state is made.
+Creates and returns an IPv4 TCP master object. A master object can
+be transformed into a server object with the method
+<a href=#listen><tt>listen</tt></a> (after a call to <a
+href=#bind><tt>bind</tt></a>) or into a client object with
+the method <a href=#connect><tt>connect</tt></a>. The only other
+method supported by a master object is the
+<a href=#close><tt>close</tt></a> method.</p>
+
+<p class=return>
+In case of success, a new master object is returned. In case of error,
+<b><tt>nil</tt></b> is returned, followed by an error message.
+</p>
+
+<!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id="socket.tcp6">
+socket.<b>tcp6()</b>
 </p>
 
+<p class=description>
+Creates and returns an IPv6 TCP master object. A master object can
+be transformed into a server object with the method
+<a href=#listen><tt>listen</tt></a> (after a call to <a
+href=#bind><tt>bind</tt></a>) or into a client object with
+the method <a href=#connect><tt>connect</tt></a>. The only other
+method supported by a master object is the
+<a href=#close><tt>close</tt></a> method.</p>
+
 <p class=return>
-No return value.
+In case of success, a new master object is returned. In case of error,
+<b><tt>nil</tt></b> is returned, followed by an error message.
 </p>
 
 <p class=note>
-Note: <b>This is an internal method, any use is unlikely to be portable.</b>
+Note: The TCP object returned will have the option
+"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
 </p>
 
+
+
 <!-- footer +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <div class=footer>
diff --git a/doc/udp.html b/doc/udp.html
index e5b0ad0..4618aad 100644
--- a/doc/udp.html
+++ b/doc/udp.html
@@ -4,7 +4,7 @@
 
 <head>
 <meta name="description" content="LuaSocket: The UDP support">
-<meta name="keywords" content="Lua, LuaSocket, Socket, UDP, Library, Network, Support"> 
+<meta name="keywords" content="Lua, LuaSocket, Socket, UDP, Library, Network, Support">
 <title>LuaSocket: UDP support</title>
 <link rel="stylesheet" href="reference.css" type="text/css">
 </head>
@@ -28,7 +28,7 @@
 <a href="index.html#download">download</a> &middot;
 <a href="installation.html">installation</a> &middot;
 <a href="introduction.html">introduction</a> &middot;
-<a href="reference.html">reference</a> 
+<a href="reference.html">reference</a>
 </p>
 </center>
 <hr>
@@ -37,74 +37,7 @@
 
 <!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<h2 id="udp">UDP</h2> 
-
-<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
-
-<p class="name" id="socket.udp">
-socket.<b>udp()</b>
-</p>
-
-<p class="description">
-Creates and returns an unconnected IPv4 UDP object. 
-Unconnected objects support the 
-<a href="#sendto"><tt>sendto</tt></a>, 
-<a href="#receive"><tt>receive</tt></a>, 
-<a href="#receivefrom"><tt>receivefrom</tt></a>, 
-<a href="#getoption"><tt>getoption</tt></a>, 
-<a href="#getsockname"><tt>getsockname</tt></a>, 
-<a href="#setoption"><tt>setoption</tt></a>, 
-<a href="#settimeout"><tt>settimeout</tt></a>, 
-<a href="#setpeername"><tt>setpeername</tt></a>, 
-<a href="#setsockname"><tt>setsockname</tt></a>, and 
-<a href="#close"><tt>close</tt></a>. 
-The <a href="#setpeername"><tt>setpeername</tt></a> 
-is used to connect the object.
-</p>
-
-<p class="return">
-In case of success, a new unconnected UDP object
-returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
-an error message.
-</p>
-
-<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
-
-<p class="name" id="socket.udp6">
-socket.<b>udp6()</b>
-</p>
-
-<p class="description">
-Creates and returns an unconnected IPv6 UDP object. 
-Unconnected objects support the 
-<a href="#sendto"><tt>sendto</tt></a>, 
-<a href="#receive"><tt>receive</tt></a>, 
-<a href="#receivefrom"><tt>receivefrom</tt></a>, 
-<a href="#getoption"><tt>getoption</tt></a>, 
-<a href="#getsockname"><tt>getsockname</tt></a>, 
-<a href="#setoption"><tt>setoption</tt></a>, 
-<a href="#settimeout"><tt>settimeout</tt></a>, 
-<a href="#setpeername"><tt>setpeername</tt></a>, 
-<a href="#setsockname"><tt>setsockname</tt></a>, and 
-<a href="#close"><tt>close</tt></a>. 
-The <a href="#setpeername"><tt>setpeername</tt></a> 
-is used to connect the object.
-</p>
-
-<p class="return">
-In case of success, a new unconnected UDP object
-returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
-an error message.
-</p>
-
-<p class=note>
-Note: The TCP object returned will have the option
-"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
-</p>
-
-
-
-<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+<h2 id="udp">UDP</h2>
 
 <!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
@@ -129,6 +62,40 @@ Garbage-collected objects are automatically closed before
 destruction, though.
 </p>
 
+<!-- getoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class="name" id="getoption">
+connected:<b>getoption()</b><br>
+unconnected:<b>getoption()</b>
+</p>
+
+<p class="description">
+Gets an option value from the UDP object.
+See <a href=#setoption><tt>setoption</tt></a> for
+description of the option names and values.
+</p>
+
+<p class="parameters"><tt>Option</tt> is a string with the option name.
+<ul>
+<li> '<tt>dontroute</tt>'
+<li> '<tt>broadcast</tt>'
+<li> '<tt>reuseaddr</tt>'
+<li> '<tt>reuseport</tt>'
+<li> '<tt>ip-multicast-loop</tt>'
+<li> '<tt>ipv6-v6only</tt>'
+<li> '<tt>ip-multicast-if</tt>'
+<li> '<tt>ip-multicast-ttl</tt>'
+<li> '<tt>ip-add-membership</tt>'
+<li> '<tt>ip-drop-membership</tt>'
+</ul>
+</p>
+
+<p class=return>
+The method returns the option <tt>value</tt> in case of
+success, or
+<b><tt>nil</tt></b> followed by an error message otherwise.
+</p>
+
 <!-- getpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class="name" id="getpeername">
@@ -142,10 +109,10 @@ associated with a connected UDP object.
 
 
 <p class=return>
-Returns a string with the IP address of the peer, the 
-port number that peer is using for the connection, 
-and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 
-In case of error, the method returns <b><tt>nil</tt></b>. 
+Returns a string with the IP address of the peer, the
+port number that peer is using for the connection,
+and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
+In case of error, the method returns <b><tt>nil</tt></b>.
 </p>
 
 <p class="note">
@@ -165,9 +132,9 @@ Returns the local address information associated to the object.
 
 
 <p class=return>
-The method returns a string with local IP address, a number with 
-the local port, 
-and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 
+The method returns a string with local IP address, a number with
+the local port,
+and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
 In case of error, the method returns <b><tt>nil</tt></b>.
 </p>
 
@@ -179,6 +146,18 @@ first time (in which case it is bound to an ephemeral port and the
 wild-card address).
 </p>
 
+<!-- gettimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id="gettimeout">
+connected:<b>settimeout(</b>value<b>)</b><br>
+unconnected:<b>settimeout(</b>value<b>)</b>
+</p>
+
+<p class=description>
+Returns the current timeout value.
+</p>
+
+
 <!-- receive +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class="name" id="receive">
@@ -199,9 +178,12 @@ specifies the maximum size of the datagram to be retrieved. If
 there are more than <tt>size</tt> bytes available in the datagram,
 the excess bytes are discarded. If there are less then
 <tt>size</tt> bytes available in the current datagram, the
-available bytes are returned. If <tt>size</tt> is omitted, the
-maximum datagram size is used (which is currently limited by the
-implementation to 8192 bytes).
+available bytes are returned.
+If <tt>size</tt> is omitted, the
+compile-time constant <a
+href=socket.html#datagramsize><tt>socket._DATAGRAMSIZE</tt></a> is used
+(it defaults to 8192 bytes). Larger sizes will cause a
+temporary buffer to be allocated for the operation.
 </p>
 
 <p class="return">
@@ -217,46 +199,12 @@ unconnected:<b>receivefrom(</b>[size]<b>)</b>
 </p>
 
 <p class="description">
-Works exactly as the <a href="#receive"><tt>receive</tt></a> 
+Works exactly as the <a href="#receive"><tt>receive</tt></a>
 method, except it returns the IP
 address and port as extra return values (and is therefore slightly less
 efficient).
 </p>
 
-<!-- getoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
-
-<p class="name" id="getoption">
-connected:<b>getoption()</b><br>
-unconnected:<b>getoption()</b>
-</p>
-
-<p class="description">
-Gets an option value from the UDP object.
-See <a href=#setoption><tt>setoption</tt></a> for
-description of the option names and values.
-</p>
-
-<p class="parameters"><tt>Option</tt> is a string with the option name. 
-<ul>
-<li> '<tt>dontroute</tt>'
-<li> '<tt>broadcast</tt>'
-<li> '<tt>reuseaddr</tt>'
-<li> '<tt>reuseport</tt>'
-<li> '<tt>ip-multicast-loop</tt>'
-<li> '<tt>ipv6-v6only</tt>'
-<li> '<tt>ip-multicast-if</tt>'
-<li> '<tt>ip-multicast-ttl</tt>'
-<li> '<tt>ip-add-membership</tt>' 
-<li> '<tt>ip-drop-membership</tt>'
-</ul> 
-</p>
-
-<p class=return>
-The method returns the option <tt>value</tt> in case of
-success, or
-<b><tt>nil</tt></b> followed by an error message otherwise.
-</p>
-
 <!-- send ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class="name" id="send">
@@ -268,7 +216,7 @@ Sends a datagram to the UDP peer of a connected object.
 </p>
 
 <p class="parameters">
-<tt>Datagram</tt> is a string with the datagram contents. 
+<tt>Datagram</tt> is a string with the datagram contents.
 The maximum datagram size for UDP is 64K minus IP layer overhead.
 However datagrams larger than the link layer packet size will be
 fragmented, which may deteriorate performance and/or reliability.
@@ -298,11 +246,11 @@ Sends a datagram to the specified IP address and port number.
 
 <p class="parameters">
 <tt>Datagram</tt> is a string with the
-datagram contents. 
+datagram contents.
 The maximum datagram size for UDP is 64K minus IP layer overhead.
 However datagrams larger than the link layer packet size will be
 fragmented, which may deteriorate performance and/or reliability.
-<tt>Ip</tt> is the IP address of the recipient. 
+<tt>Ip</tt> is the IP address of the recipient.
 Host names are <em>not</em> allowed for performance reasons.
 
 <tt>Port</tt> is the port number at the recipient.
@@ -320,6 +268,75 @@ refuses to send a message to the specified address (i.e. no
 interface accepts the address).
 </p>
 
+<!-- setoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class="name" id="setoption">
+connected:<b>setoption(</b>option [, value]<b>)</b><br>
+unconnected:<b>setoption(</b>option [, value]<b>)</b>
+</p>
+
+<p class="description">
+Sets options for the UDP object. Options are
+only needed by low-level or time-critical applications. You should
+only modify an option if you are sure you need it.</p>
+<p class="parameters"><tt>Option</tt> is a string with the option
+name, and <tt>value</tt> depends on the option being set:
+</p>
+
+<ul>
+<li> '<tt>dontroute</tt>': Indicates that outgoing
+messages should bypass the standard routing facilities.
+Receives a boolean value;
+<li> '<tt>broadcast</tt>': Requests permission to send
+broadcast datagrams on the socket.
+Receives a boolean value;
+<li> '<tt>reuseaddr</tt>': Indicates that the rules used in
+validating addresses supplied in a <tt>bind()</tt> call
+should allow reuse of local addresses.
+Receives a boolean value;
+<li> '<tt>reuseport</tt>': Allows completely duplicate
+bindings by multiple processes if they all set
+'<tt>reuseport</tt>' before binding the port.
+Receives a boolean value;
+<li> '<tt>ip-multicast-loop</tt>':
+Specifies whether or not a copy of an outgoing multicast
+datagram is delivered to the sending host as long as it is a
+member of the multicast group.
+Receives a boolean value;
+<li> '<tt>ipv6-v6only</tt>':
+Specifies whether to restrict <tt>inet6</tt> sockets to
+sending and receiving only IPv6 packets.
+Receive a boolean value;
+<li> '<tt>ip-multicast-if</tt>':
+Sets the interface over which outgoing multicast datagrams
+are sent.
+Receives an IP address;
+<li> '<tt>ip-multicast-ttl</tt>':
+Sets the Time To Live in the IP header for outgoing
+multicast datagrams.
+Receives a number;
+<li> '<tt>ip-add-membership</tt>':
+Joins the multicast group specified.
+Receives a table with fields
+<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
+IP address;
+<li> '<tt>ip-drop-membership</tt>': Leaves the multicast
+group specified.
+Receives a table with fields
+<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
+IP address.
+</ul>
+
+<p class="return">
+The method returns 1 in case of success, or
+<b><tt>nil</tt></b> followed by an error message otherwise.
+</p>
+
+<p class=note>
+Note: The descriptions above come from the man pages.
+</p>
+
+
 <!-- setpeername +++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class="name" id="setpeername">
@@ -337,9 +354,9 @@ object or vice versa.
 For connected objects, outgoing datagrams
 will be sent to the specified peer, and datagrams received from
 other peers will be discarded by the OS. Connected UDP objects must
-use the <a href="#send"><tt>send</tt></a> and 
-<a href="#receive"><tt>receive</tt></a> methods instead of 
-<a href="#sendto"><tt>sendto</tt></a> and 
+use the <a href="#send"><tt>send</tt></a> and
+<a href="#receive"><tt>receive</tt></a> methods instead of
+<a href="#sendto"><tt>sendto</tt></a> and
 <a href="#receivefrom"><tt>receivefrom</tt></a>.
 </p>
 
@@ -406,74 +423,6 @@ system or explicitly by <tt>setsockname</tt>, it cannot be
 changed.
 </p>
 
-<!-- setoption +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
-
-<p class="name" id="setoption">
-connected:<b>setoption(</b>option [, value]<b>)</b><br>
-unconnected:<b>setoption(</b>option [, value]<b>)</b>
-</p>
-
-<p class="description">
-Sets options for the UDP object. Options are
-only needed by low-level or time-critical applications. You should
-only modify an option if you are sure you need it.</p>
-<p class="parameters"><tt>Option</tt> is a string with the option
-name, and <tt>value</tt> depends on the option being set:
-</p>
-
-<ul> 
-<li> '<tt>dontroute</tt>': Indicates that outgoing
-messages should bypass the standard routing facilities.
-Receives a boolean value;
-<li> '<tt>broadcast</tt>': Requests permission to send 
-broadcast datagrams on the socket.
-Receives a boolean value;
-<li> '<tt>reuseaddr</tt>': Indicates that the rules used in
-validating addresses supplied in a <tt>bind()</tt> call 
-should allow reuse of local addresses. 
-Receives a boolean value;
-<li> '<tt>reuseport</tt>': Allows completely duplicate
-bindings by multiple processes if they all set
-'<tt>reuseport</tt>' before binding the port.
-Receives a boolean value;
-<li> '<tt>ip-multicast-loop</tt>':
-Specifies whether or not a copy of an outgoing multicast
-datagram is delivered to the sending host as long as it is a
-member of the multicast group.
-Receives a boolean value;
-<li> '<tt>ipv6-v6only</tt>':
-Specifies whether to restrict <tt>inet6</tt> sockets to 
-sending and receiving only IPv6 packets.
-Receive a boolean value;
-<li> '<tt>ip-multicast-if</tt>':
-Sets the interface over which outgoing multicast datagrams
-are sent.
-Receives an IP address;
-<li> '<tt>ip-multicast-ttl</tt>':
-Sets the Time To Live in the IP header for outgoing
-multicast datagrams. 
-Receives a number;
-<li> '<tt>ip-add-membership</tt>': 
-Joins the multicast group specified.
-Receives a table with fields
-<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
-IP address;
-<li> '<tt>ip-drop-membership</tt>': Leaves the multicast
-group specified.
-Receives a table with fields
-<tt>multiaddr</tt> and <tt>interface</tt>, each containing an
-IP address.
-</ul> 
-
-<p class="return">
-The method returns 1 in case of success, or
-<b><tt>nil</tt></b> followed by an error message otherwise.
-</p>
-
-<p class=note>
-Note: The descriptions above come from the man pages.
-</p>
-
 <!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class="name" id="settimeout">
@@ -482,14 +431,14 @@ unconnected:<b>settimeout(</b>value<b>)</b>
 </p>
 
 <p class="description">
-Changes the timeout values for the object.  By default, the 
-<a href="#receive"><tt>receive</tt></a> and 
-<a href="#receivefrom"><tt>receivefrom</tt></a> 
+Changes the timeout values for the object.  By default, the
+<a href="#receive"><tt>receive</tt></a> and
+<a href="#receivefrom"><tt>receivefrom</tt></a>
 operations are blocking. That is, any call to the methods will block
 indefinitely, until data arrives.  The <tt>settimeout</tt> function defines
 a limit on the amount of time the functions can block. When a timeout is
 set and the specified amount of time has elapsed, the affected methods
-give up and fail with an error code.  
+give up and fail with an error code.
 </p>
 
 <p class="parameters">
@@ -514,6 +463,114 @@ all other method names already contained verbs making their
 imperative nature obvious.
 </p>
 
+<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class="name" id="socket.udp">
+socket.<b>udp()</b>
+</p>
+
+<p class="description">
+Creates and returns an unconnected UDP object.
+Unconnected objects support the
+<a href="#sendto"><tt>sendto</tt></a>,
+<a href="#receive"><tt>receive</tt></a>,
+<a href="#receivefrom"><tt>receivefrom</tt></a>,
+<a href="#getoption"><tt>getoption</tt></a>,
+<a href="#getsockname"><tt>getsockname</tt></a>,
+<a href="#setoption"><tt>setoption</tt></a>,
+<a href="#settimeout"><tt>settimeout</tt></a>,
+<a href="#setpeername"><tt>setpeername</tt></a>,
+<a href="#setsockname"><tt>setsockname</tt></a>, and
+<a href="#close"><tt>close</tt></a>.
+The <a href="#setpeername"><tt>setpeername</tt></a>
+is used to connect the object.
+</p>
+
+<p class="return">
+In case of success, a new unconnected UDP object
+returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
+an error message.
+</p>
+
+<p class=note>
+Note: The choice between IPv4 and IPv6 happens during a call to
+<a href=#sendto><tt>sendto</tt></a>, <a
+href=#setpeername><tt>setpeername</tt></a>, or <a
+href=#setsockname><tt>sockname</tt></a>, depending on the address
+family obtained from the resolver.
+</p>
+
+<p class=note>
+Note: Before the choice between IPv4 and IPv6 happens,
+the internal socket object is invalid and therefore <a
+href=#setoption><tt>setoption</tt></a> will fail.
+</p>
+
+<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class="name" id="socket.udp">
+socket.<b>udp4()</b>
+</p>
+
+<p class="description">
+Creates and returns an unconnected IPv4 UDP object.
+Unconnected objects support the
+<a href="#sendto"><tt>sendto</tt></a>,
+<a href="#receive"><tt>receive</tt></a>,
+<a href="#receivefrom"><tt>receivefrom</tt></a>,
+<a href="#getoption"><tt>getoption</tt></a>,
+<a href="#getsockname"><tt>getsockname</tt></a>,
+<a href="#setoption"><tt>setoption</tt></a>,
+<a href="#settimeout"><tt>settimeout</tt></a>,
+<a href="#setpeername"><tt>setpeername</tt></a>,
+<a href="#setsockname"><tt>setsockname</tt></a>, and
+<a href="#close"><tt>close</tt></a>.
+The <a href="#setpeername"><tt>setpeername</tt></a>
+is used to connect the object.
+</p>
+
+<p class="return">
+In case of success, a new unconnected UDP object
+returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
+an error message.
+</p>
+
+<!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class="name" id="socket.udp6">
+socket.<b>udp6()</b>
+</p>
+
+<p class="description">
+Creates and returns an unconnected IPv6 UDP object.
+Unconnected objects support the
+<a href="#sendto"><tt>sendto</tt></a>,
+<a href="#receive"><tt>receive</tt></a>,
+<a href="#receivefrom"><tt>receivefrom</tt></a>,
+<a href="#getoption"><tt>getoption</tt></a>,
+<a href="#getsockname"><tt>getsockname</tt></a>,
+<a href="#setoption"><tt>setoption</tt></a>,
+<a href="#settimeout"><tt>settimeout</tt></a>,
+<a href="#setpeername"><tt>setpeername</tt></a>,
+<a href="#setsockname"><tt>setsockname</tt></a>, and
+<a href="#close"><tt>close</tt></a>.
+The <a href="#setpeername"><tt>setpeername</tt></a>
+is used to connect the object.
+</p>
+
+<p class="return">
+In case of success, a new unconnected UDP object
+returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
+an error message.
+</p>
+
+<p class=note>
+Note: The TCP object returned will have the option
+"<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
+</p>
+
+
+
 <!-- footer ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <div class=footer>
@@ -524,7 +581,7 @@ imperative nature obvious.
 <a href="index.html#download">download</a> &middot;
 <a href="installation.html">installation</a> &middot;
 <a href="introduction.html">introduction</a> &middot;
-<a href="reference.html">reference</a> 
+<a href="reference.html">reference</a>
 </p>
 <p>
 <small>
diff --git a/etc/dispatch.lua b/etc/dispatch.lua
index cab7f59..2485415 100644
--- a/etc/dispatch.lua
+++ b/etc/dispatch.lua
@@ -5,6 +5,7 @@
 -----------------------------------------------------------------------------
 local base = _G
 local table = require("table")
+local string = require("string")
 local socket = require("socket")
 local coroutine = require("coroutine")
 module("dispatch")
@@ -43,26 +44,32 @@ end
 -----------------------------------------------------------------------------
 -- Mega hack. Don't try to do this at home.
 -----------------------------------------------------------------------------
--- we can't yield across calls to protect, so we rewrite it with coxpcall
+-- we can't yield across calls to protect on Lua 5.1, so we rewrite it with
+-- coroutines
 -- make sure you don't require any module that uses socket.protect before
 -- loading our hack
-function socket.protect(f)
-  return function(...)
-    local co = coroutine.create(f)
-    while true do
-      local results = {coroutine.resume(co, ...)}
-      local status = table.remove(results, 1)
-      if not status then
-        if base.type(results[1]) == 'table' then
-          return nil, results[1][1]
-        else base.error(results[1]) end
-      end
-      if coroutine.status(co) == "suspended" then
-        arg = {coroutine.yield(base.unpack(results))}
+if string.sub(base._VERSION, -3) == "5.1" then
+  local function _protect(co, status, ...)
+    if not status then
+      local msg = ...
+      if base.type(msg) == 'table' then
+        return nil, msg[1]
       else
-        return base.unpack(results)
+        base.error(msg, 0)
       end
     end
+    if coroutine.status(co) == "suspended" then
+      return _protect(co, coroutine.resume(co, coroutine.yield(...)))
+    else
+      return ...
+    end
+  end
+
+  function socket.protect(f)
+    return function(...)
+      local co = coroutine.create(f)
+      return _protect(co, coroutine.resume(co, ...))
+    end
   end
 end
 
diff --git a/linux.cmd b/linux.cmd
index bd59adc..6c6636b 100644
--- a/linux.cmd
+++ b/linux.cmd
@@ -1 +1 @@
-make PLAT=linux DEBUG=DEBUG LUAINC_linux_base=/home/diego/build/linux/include LUAPREFIX_linux=/home/diego/build/linux
+make PLAT=linux DEBUG=DEBUG LUAINC_linux_base=/home/diego/build/ubuntu/include LUAPREFIX_linux=/home/diego/build/ubuntu
diff --git a/luasocket-scm-0.rockspec b/luasocket-scm-0.rockspec
index f86567b..352a497 100644
--- a/luasocket-scm-0.rockspec
+++ b/luasocket-scm-0.rockspec
@@ -50,13 +50,12 @@ local function make_plat(plat)
 	}
 	local modules = {
 		["socket.core"] = {
-			sources = { "src/luasocket.c", "src/timeout.c", "src/buffer.c", "src/io.c", "src/auxiliar.c",
-						"src/options.c", "src/inet.c", "src/except.c", "src/select.c", "src/tcp.c", "src/udp.c" },
+			sources = { "src/luasocket.c", "src/timeout.c", "src/buffer.c", "src/io.c", "src/auxiliar.c", "src/options.c", "src/inet.c", "src/except.c", "src/select.c", "src/tcp.c", "src/udp.c", "src/compat.c" },
 			defines = defines[plat],
 			incdir = "/src"
 		},
-		["mime.core"] = { 
-			sources = { "src/mime.c" },
+		["mime.core"] = {
+			sources = { "src/mime.c", "src/compat.c" },
 			defines = defines[plat],
 			incdir = "/src"
 		},
@@ -73,14 +72,12 @@ local function make_plat(plat)
 	if plat == "unix" or plat == "macosx" then
 	    modules["socket.core"].sources[#modules["socket.core"].sources+1] = "src/usocket.c"
 		modules["socket.unix"] = {
-		  sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c", "src/io.c", 
-					  "src/usocket.c", "src/unix.c" },
+		  sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c", "src/io.c", "src/usocket.c", "src/unix.c" },
 		  defines = defines[plat],
 		  incdir = "/src"
 		}
 		modules["socket.serial"] = {
-		  sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c",
-					  "src/io.c", "src/usocket.c", "src/serial.c" },
+		  sources = { "src/buffer.c", "src/auxiliar.c", "src/options.c", "src/timeout.c", "src/io.c", "src/usocket.c", "src/serial.c" },
 		  defines = defines[plat],
 		  incdir = "/src"
 		}
diff --git a/makefile b/makefile
index 04cd894..cc15b4e 100644
--- a/makefile
+++ b/makefile
@@ -5,12 +5,12 @@
 # Targets:
 #   install            install system independent support
 #   install-unix           also install unix-only support
-#   install-both       install for both lua5.1 and lua5.2 
-#   install-both-unix      also install unix-only 
+#   install-both       install for lua51 lua52 lua53
+#   install-both-unix      also install unix-only
 #   print	           print the build settings
 
 PLAT?= linux
-PLATS= macosx linux win32 mingw
+PLATS= macosx linux win32 mingw freebsd solaris
 
 all: $(PLAT)
 
@@ -24,20 +24,26 @@ test:
 	lua test/hello.lua
 
 install-both:
-	$(MAKE) clean 
+	$(MAKE) clean
 	@cd src; $(MAKE) $(PLAT) LUAV=5.1
 	@cd src; $(MAKE) install LUAV=5.1
-	$(MAKE) clean 
+	$(MAKE) clean
 	@cd src; $(MAKE) $(PLAT) LUAV=5.2
 	@cd src; $(MAKE) install LUAV=5.2
+	$(MAKE) clean
+	@cd src; $(MAKE) $(PLAT) LUAV=5.3
+	@cd src; $(MAKE) install LUAV=5.3
 
 install-both-unix:
-	$(MAKE) clean 
+	$(MAKE) clean
 	@cd src; $(MAKE) $(PLAT) LUAV=5.1
 	@cd src; $(MAKE) install-unix LUAV=5.1
-	$(MAKE) clean 
+	$(MAKE) clean
 	@cd src; $(MAKE) $(PLAT) LUAV=5.2
 	@cd src; $(MAKE) install-unix LUAV=5.2
+	$(MAKE) clean
+	@cd src; $(MAKE) $(PLAT) LUAV=5.3
+	@cd src; $(MAKE) install-unix LUAV=5.3
 
 .PHONY: test
 
diff --git a/src/auxiliar.c b/src/auxiliar.c
index de625e9..18fa8e4 100644
--- a/src/auxiliar.c
+++ b/src/auxiliar.c
@@ -26,7 +26,7 @@ void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) {
     luaL_newmetatable(L, classname); /* mt */
     /* create __index table to place methods */
     lua_pushstring(L, "__index");    /* mt,"__index" */
-    lua_newtable(L);                 /* mt,"__index",it */ 
+    lua_newtable(L);                 /* mt,"__index",it */
     /* put class name into class metatable */
     lua_pushstring(L, "class");      /* mt,"__index",it,"class" */
     lua_pushstring(L, classname);    /* mt,"__index",it,"class",classname */
@@ -84,7 +84,7 @@ int auxiliar_checkboolean(lua_State *L, int objidx) {
 }
 
 /*-------------------------------------------------------------------------*\
-* Return userdata pointer if object belongs to a given class, abort with 
+* Return userdata pointer if object belongs to a given class, abort with
 * error otherwise
 \*-------------------------------------------------------------------------*/
 void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) {
@@ -98,7 +98,7 @@ void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) {
 }
 
 /*-------------------------------------------------------------------------*\
-* Return userdata pointer if object belongs to a given group, abort with 
+* Return userdata pointer if object belongs to a given group, abort with
 * error otherwise
 \*-------------------------------------------------------------------------*/
 void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) {
@@ -121,7 +121,7 @@ void auxiliar_setclass(lua_State *L, const char *classname, int objidx) {
 }
 
 /*-------------------------------------------------------------------------*\
-* Get a userdata pointer if object belongs to a given group. Return NULL 
+* Get a userdata pointer if object belongs to a given group. Return NULL
 * otherwise
 \*-------------------------------------------------------------------------*/
 void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
@@ -139,7 +139,7 @@ void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) {
 }
 
 /*-------------------------------------------------------------------------*\
-* Get a userdata pointer if object belongs to a given class. Return NULL 
+* Get a userdata pointer if object belongs to a given class. Return NULL
 * otherwise
 \*-------------------------------------------------------------------------*/
 void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
@@ -151,7 +151,7 @@ void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) {
 * Used to be part of lauxlib in Lua 5.1, was dropped from 5.2.
 \*-------------------------------------------------------------------------*/
 int auxiliar_typeerror (lua_State *L, int narg, const char *tname) {
-  const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, 
+  const char *msg = lua_pushfstring(L, "%s expected, got %s", tname,
       luaL_typename(L, narg));
   return luaL_argerror(L, narg, msg);
 }
diff --git a/src/auxiliar.h b/src/auxiliar.h
index ea99013..65511d4 100644
--- a/src/auxiliar.h
+++ b/src/auxiliar.h
@@ -4,12 +4,12 @@
 * Auxiliar routines for class hierarchy manipulation
 * LuaSocket toolkit (but completely independent of other LuaSocket modules)
 *
-* A LuaSocket class is a name associated with Lua metatables. A LuaSocket 
-* group is a name associated with a class. A class can belong to any number 
+* A LuaSocket class is a name associated with Lua metatables. A LuaSocket
+* group is a name associated with a class. A class can belong to any number
 * of groups. This module provides the functionality to:
 *
-*   - create new classes 
-*   - add classes to groups 
+*   - create new classes
+*   - add classes to groups
 *   - set the class of objects
 *   - check if an object belongs to a given class or group
 *   - get the userdata associated to objects
@@ -26,11 +26,12 @@
 * "class" with the class name.
 *
 * The mapping from class name to the corresponding metatable and the
-* reverse mapping are done using lauxlib. 
+* reverse mapping are done using lauxlib.
 \*=========================================================================*/
 
 #include "lua.h"
 #include "lauxlib.h"
+#include "compat.h"
 
 int auxiliar_open(lua_State *L);
 void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func);
diff --git a/src/buffer.c b/src/buffer.c
index 4ef4e8e..fff1634 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -4,6 +4,7 @@
 \*=========================================================================*/
 #include "lua.h"
 #include "lauxlib.h"
+#include "compat.h"
 
 #include "buffer.h"
 
@@ -37,7 +38,7 @@ int buffer_open(lua_State *L) {
 }
 
 /*-------------------------------------------------------------------------*\
-* Initializes C structure 
+* Initializes C structure
 \*-------------------------------------------------------------------------*/
 void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
     buf->first = buf->last = 0;
@@ -61,8 +62,8 @@ int buffer_meth_getstats(lua_State *L, p_buffer buf) {
 * object:setstats() interface
 \*-------------------------------------------------------------------------*/
 int buffer_meth_setstats(lua_State *L, p_buffer buf) {
-    buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received); 
-    buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent); 
+    buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received);
+    buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent);
     if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4);
     lua_pushnumber(L, 1);
     return 1;
@@ -78,9 +79,7 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
     const char *data = luaL_checklstring(L, 2, &size);
     long start = (long) luaL_optnumber(L, 3, 1);
     long end = (long) luaL_optnumber(L, 4, -1);
-#ifdef LUASOCKET_DEBUG
-    p_timeout tm = timeout_markstart(buf->tm);
-#endif
+    timeout_markstart(buf->tm);
     if (start < 0) start = (long) (size+start+1);
     if (end < 0) end = (long) (size+end+1);
     if (start < 1) start = (long) 1;
@@ -89,7 +88,7 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
     /* check if there was an error */
     if (err != IO_DONE) {
         lua_pushnil(L);
-        lua_pushstring(L, buf->io->error(buf->io->ctx, err)); 
+        lua_pushstring(L, buf->io->error(buf->io->ctx, err));
         lua_pushnumber(L, (lua_Number) (sent+start-1));
     } else {
         lua_pushnumber(L, (lua_Number) (sent+start-1));
@@ -98,7 +97,7 @@ int buffer_meth_send(lua_State *L, p_buffer buf) {
     }
 #ifdef LUASOCKET_DEBUG
     /* push time elapsed during operation as the last return value */
-    lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
+    lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm));
 #endif
     return lua_gettop(L) - top;
 }
@@ -111,10 +110,8 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
     luaL_Buffer b;
     size_t size;
     const char *part = luaL_optlstring(L, 3, "", &size);
-#ifdef LUASOCKET_DEBUG
-    p_timeout tm = timeout_markstart(buf->tm);
-#endif
-    /* initialize buffer with optional extra prefix 
+    timeout_markstart(buf->tm);
+    /* initialize buffer with optional extra prefix
      * (useful for concatenating previous partial results) */
     luaL_buffinit(L, &b);
     luaL_addlstring(&b, part, size);
@@ -122,12 +119,12 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
     if (!lua_isnumber(L, 2)) {
         const char *p= luaL_optstring(L, 2, "*l");
         if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b);
-        else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); 
+        else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b);
         else luaL_argcheck(L, 0, 2, "invalid receive pattern");
-    /* get a fixed number of bytes (minus what was already partially 
+    /* get a fixed number of bytes (minus what was already partially
      * received) */
     } else {
-        double n = lua_tonumber(L, 2); 
+        double n = lua_tonumber(L, 2);
         size_t wanted = (size_t) n;
         luaL_argcheck(L, n >= 0, 2, "invalid receive pattern");
         if (size == 0 || wanted > size)
@@ -138,8 +135,8 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
         /* we can't push anyting in the stack before pushing the
          * contents of the buffer. this is the reason for the complication */
         luaL_pushresult(&b);
-        lua_pushstring(L, buf->io->error(buf->io->ctx, err)); 
-        lua_pushvalue(L, -2); 
+        lua_pushstring(L, buf->io->error(buf->io->ctx, err));
+        lua_pushvalue(L, -2);
         lua_pushnil(L);
         lua_replace(L, -4);
     } else {
@@ -149,7 +146,7 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
     }
 #ifdef LUASOCKET_DEBUG
     /* push time elapsed during operation as the last return value */
-    lua_pushnumber(L, timeout_gettime() - timeout_getstart(tm));
+    lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm));
 #endif
     return lua_gettop(L) - top;
 }
@@ -222,7 +219,7 @@ static int recvall(p_buffer buf, luaL_Buffer *b) {
 }
 
 /*-------------------------------------------------------------------------*\
-* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF 
+* Reads a line terminated by a CR LF pair or just by a LF. The CR and LF
 * are not returned by the function and are discarded from the buffer
 \*-------------------------------------------------------------------------*/
 static int recvline(p_buffer buf, luaL_Buffer *b) {
@@ -252,7 +249,7 @@ static int recvline(p_buffer buf, luaL_Buffer *b) {
 static void buffer_skip(p_buffer buf, size_t count) {
     buf->received += count;
     buf->first += count;
-    if (buffer_isempty(buf)) 
+    if (buffer_isempty(buf))
         buf->first = buf->last = 0;
 }
 
diff --git a/src/compat.c b/src/compat.c
new file mode 100644
index 0000000..c2d99cb
--- /dev/null
+++ b/src/compat.c
@@ -0,0 +1,19 @@
+#include "compat.h"
+
+#if LUA_VERSION_NUM==501
+/*
+** Adapted from Lua 5.2
+*/
+void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
+  luaL_checkstack(L, nup+1, "too many upvalues");
+  for (; l->name != NULL; l++) {  /* fill the table with given functions */
+    int i;
+    lua_pushstring(L, l->name);
+    for (i = 0; i < nup; i++)  /* copy upvalues to the top */
+      lua_pushvalue(L, -(nup+1));
+    lua_pushcclosure(L, l->func, nup);  /* closure with those upvalues */
+    lua_settable(L, -(nup + 3));
+  }
+  lua_pop(L, nup);  /* remove upvalues */
+}
+#endif
diff --git a/src/compat.h b/src/compat.h
new file mode 100644
index 0000000..7bf8010
--- /dev/null
+++ b/src/compat.h
@@ -0,0 +1,11 @@
+#ifndef COMPAT_H
+#define COMPAT_H
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#if LUA_VERSION_NUM==501
+void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup);
+#endif
+
+#endif
diff --git a/src/except.c b/src/except.c
index 002e701..60b5005 100644
--- a/src/except.c
+++ b/src/except.c
@@ -6,9 +6,19 @@
 
 #include "lua.h"
 #include "lauxlib.h"
+#include "compat.h"
 
 #include "except.h"
 
+#if LUA_VERSION_NUM < 502
+#define lua_pcallk(L, na, nr, err, ctx, cont) \
+    (((void)ctx),((void)cont),lua_pcall(L, na, nr, err))
+#endif
+
+#if LUA_VERSION_NUM < 503
+typedef int lua_KContext;
+#endif
+
 /*=========================================================================*\
 * Internal function prototypes.
 \*=========================================================================*/
@@ -29,18 +39,17 @@ static luaL_Reg func[] = {
 * Try factory
 \*-------------------------------------------------------------------------*/
 static void wrap(lua_State *L) {
-    lua_newtable(L);
-    lua_pushnumber(L, 1);
-    lua_pushvalue(L, -3);
-    lua_settable(L, -3);
-    lua_insert(L, -2);
-    lua_pop(L, 1);
+    lua_createtable(L, 1, 0);
+    lua_pushvalue(L, -2);
+    lua_rawseti(L, -2, 1);
+    lua_pushvalue(L, lua_upvalueindex(1));
+    lua_setmetatable(L, -2);
 }
 
 static int finalize(lua_State *L) {
     if (!lua_toboolean(L, 1)) {
-        lua_pushvalue(L, lua_upvalueindex(1));
-        lua_pcall(L, 0, 0, 0);
+        lua_pushvalue(L, lua_upvalueindex(2));
+        lua_call(L, 0, 0);
         lua_settop(L, 2);
         wrap(L);
         lua_error(L);
@@ -48,15 +57,17 @@ static int finalize(lua_State *L) {
     } else return lua_gettop(L);
 }
 
-static int do_nothing(lua_State *L) { 
+static int do_nothing(lua_State *L) {
     (void) L;
-    return 0; 
+    return 0;
 }
 
 static int global_newtry(lua_State *L) {
     lua_settop(L, 1);
     if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing);
-    lua_pushcclosure(L, finalize, 1);
+    lua_pushvalue(L, lua_upvalueindex(1));
+    lua_insert(L, -2);
+    lua_pushcclosure(L, finalize, 2);
     return 1;
 }
 
@@ -64,27 +75,49 @@ static int global_newtry(lua_State *L) {
 * Protect factory
 \*-------------------------------------------------------------------------*/
 static int unwrap(lua_State *L) {
-    if (lua_istable(L, -1)) {
-        lua_pushnumber(L, 1);
-        lua_gettable(L, -2);
-        lua_pushnil(L);
-        lua_insert(L, -2);
-        return 1;
-    } else return 0;
+    if (lua_istable(L, -1) && lua_getmetatable(L, -1)) {
+        int r = lua_rawequal(L, -1, lua_upvalueindex(1));
+        lua_pop(L, 1);
+        if (r) {
+            lua_pushnil(L);
+            lua_rawgeti(L, -2, 1);
+            return 1;
+        }
+    }
+    return 0;
 }
 
-static int protected_(lua_State *L) {
-    lua_pushvalue(L, lua_upvalueindex(1));
-    lua_insert(L, 1);
-    if (lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0) != 0) {
+static int protected_finish(lua_State *L, int status, lua_KContext ctx) {
+    (void)ctx;
+    if (status != 0 && status != LUA_YIELD) {
         if (unwrap(L)) return 2;
-        else lua_error(L);
-        return 0;
+        else return lua_error(L);
     } else return lua_gettop(L);
 }
 
+#if LUA_VERSION_NUM == 502
+static int protected_cont(lua_State *L) {
+    int ctx = 0;
+    int status = lua_getctx(L, &ctx);
+    return protected_finish(L, status, ctx);
+}
+#else
+#define protected_cont protected_finish
+#endif
+
+static int protected_(lua_State *L) {
+    int status;
+    lua_pushvalue(L, lua_upvalueindex(2));
+    lua_insert(L, 1);
+    status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont);
+    return protected_finish(L, status, 0);
+}
+
 static int global_protect(lua_State *L) {
-    lua_pushcclosure(L, protected_, 1);
+    lua_settop(L, 1);
+    lua_pushvalue(L, lua_upvalueindex(1));
+    lua_insert(L, 1);
+    lua_pushcclosure(L, protected_, 2);
     return 1;
 }
 
@@ -92,10 +125,9 @@ static int global_protect(lua_State *L) {
 * Init module
 \*-------------------------------------------------------------------------*/
 int except_open(lua_State *L) {
-#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
-    luaL_setfuncs(L, func, 0);
-#else
-    luaL_openlib(L, NULL, func, 0);
-#endif
+    lua_newtable(L); /* metatable for wrapped exceptions */
+    lua_pushboolean(L, 0);
+    lua_setfield(L, -2, "__metatable");
+    luaL_setfuncs(L, func, 1);
     return 0;
 }
diff --git a/src/except.h b/src/except.h
index 1e7a245..2497c05 100644
--- a/src/except.h
+++ b/src/except.h
@@ -9,21 +9,26 @@
 * error checking was taking a substantial amount of the coding. These
 * function greatly simplify the task of checking errors.
 *
-* The main idea is that functions should return nil as its first return
-* value when it finds an error, and return an error message (or value)
+* The main idea is that functions should return nil as their first return
+* values when they find an error, and return an error message (or value)
 * following nil. In case of success, as long as the first value is not nil,
 * the other values don't matter.
 *
 * The idea is to nest function calls with the "try" function. This function
-* checks the first value, and calls "error" on the second if the first is
-* nil. Otherwise, it returns all values it received. 
+* checks the first value, and, if it's falsy, wraps the second value in a
+* table with metatable and calls "error" on it. Otherwise, it returns all
+* values it received. Basically, it works like the Lua "assert" function,
+* but it creates errors targeted specifically at "protect".
 *
-* The protect function returns a new function that behaves exactly like the
-* function it receives, but the new function doesn't throw exceptions: it
-* returns nil followed by the error message instead.
+* The "newtry" function is a factory for "try" functions that call a
+* finalizer in protected mode before calling "error".
 *
-* With these two function, it's easy to write functions that throw
-* exceptions on error, but that don't interrupt the user script. 
+* The "protect" function returns a new function that behaves exactly like
+* the function it receives, but the new function catches exceptions thrown
+* by "try" functions and returns nil followed by the error message instead.
+*
+* With these three functions, it's easy to write functions that throw
+* exceptions on error, but that don't interrupt the user script.
 \*=========================================================================*/
 
 #include "lua.h"
diff --git a/src/ftp.lua b/src/ftp.lua
index ea1145b..e0c3cae 100644
--- a/src/ftp.lua
+++ b/src/ftp.lua
@@ -268,11 +268,20 @@ _M.command = socket.protect(function(cmdt)
     cmdt = override(cmdt)
     socket.try(cmdt.host, "missing hostname")
     socket.try(cmdt.command, "missing command")
-    local f = open(cmdt.host, cmdt.port, cmdt.create)
+    local f = _M.open(cmdt.host, cmdt.port, cmdt.create)
     f:greet()
     f:login(cmdt.user, cmdt.password)
-    f.try(f.tp:command(cmdt.command, cmdt.argument))
-    if cmdt.check then f.try(f.tp:check(cmdt.check)) end
+    if type(cmdt.command) == "table" then
+        local argument = cmdt.argument or {}
+        local check = cmdt.check or {}
+        for i,cmd in ipairs(cmdt.command) do
+            f.try(f.tp:command(cmd, argument[i]))
+            if check[i] then f.try(f.tp:check(check[i])) end
+        end
+    else
+        f.try(f.tp:command(cmdt.command, cmdt.argument))
+        if cmdt.check then f.try(f.tp:check(cmdt.check)) end
+    end
     f:quit()
     return f:close()
 end)
@@ -282,4 +291,4 @@ _M.get = socket.protect(function(gett)
     else return tget(gett) end
 end)
 
-return _M
\ No newline at end of file
+return _M
diff --git a/src/http.lua b/src/http.lua
index ac4b2d6..d6bcc91 100644
--- a/src/http.lua
+++ b/src/http.lua
@@ -22,12 +22,15 @@ local _M = socket.http
 -- Program constants
 -----------------------------------------------------------------------------
 -- connection timeout in seconds
-TIMEOUT = 60
--- default port for document retrieval
-_M.PORT = 80
+_M.TIMEOUT = 60
 -- user agent field sent in request
 _M.USERAGENT = socket._VERSION
 
+-- supported schemes
+local SCHEMES = { ["http"] = true }
+-- default port for document retrieval
+local PORT = 80
+
 -----------------------------------------------------------------------------
 -- Reads MIME headers from a connection, unfolding where needed
 -----------------------------------------------------------------------------
@@ -114,7 +117,7 @@ function _M.open(host, port, create)
     h.try = socket.newtry(function() h:close() end)
     -- set timeout before connecting
     h.try(c:settimeout(_M.TIMEOUT))
-    h.try(c:connect(host, port or _M.PORT))
+    h.try(c:connect(host, port or PORT))
     -- here everything worked
     return h
 end
@@ -186,7 +189,7 @@ end
 local function adjusturi(reqt)
     local u = reqt
     -- if there is a proxy, we need the full url. otherwise, just a part.
-    if not reqt.proxy and not PROXY then
+    if not reqt.proxy and not _M.PROXY then
         u = {
            path = socket.try(reqt.path, "invalid path 'nil'"),
            params = reqt.params,
@@ -198,7 +201,7 @@ local function adjusturi(reqt)
 end
 
 local function adjustproxy(reqt)
-    local proxy = reqt.proxy or PROXY
+    local proxy = reqt.proxy or _M.PROXY
     if proxy then
         proxy = url.parse(proxy)
         return proxy.host, proxy.port or 3128
@@ -209,17 +212,27 @@ end
 
 local function adjustheaders(reqt)
     -- default headers
+    local host = string.gsub(reqt.authority, "^.-@", "")
     local lower = {
         ["user-agent"] = _M.USERAGENT,
-        ["host"] = reqt.host,
+        ["host"] = host,
         ["connection"] = "close, TE",
         ["te"] = "trailers"
     }
     -- if we have authentication information, pass it along
     if reqt.user and reqt.password then
-        lower["authorization"] = 
+        lower["authorization"] =
             "Basic " ..  (mime.b64(reqt.user .. ":" .. reqt.password))
     end
+    -- if we have proxy authentication information, pass it along
+    local proxy = reqt.proxy or _M.PROXY
+    if proxy then
+        proxy = url.parse(proxy)
+        if proxy.user and proxy.password then
+            lower["proxy-authorization"] =
+                "Basic " ..  (mime.b64(proxy.user .. ":" .. proxy.password))
+        end
+    end
     -- override with user headers
     for i,v in base.pairs(reqt.headers or lower) do
         lower[string.lower(i)] = v
@@ -230,7 +243,7 @@ end
 -- default url parts
 local default = {
     host = "",
-    port = _M.PORT,
+    port = PORT,
     path ="/",
     scheme = "http"
 }
@@ -240,22 +253,27 @@ local function adjustrequest(reqt)
     local nreqt = reqt.url and url.parse(reqt.url, default) or {}
     -- explicit components override url
     for i,v in base.pairs(reqt) do nreqt[i] = v end
-    if nreqt.port == "" then nreqt.port = 80 end
-    socket.try(nreqt.host and nreqt.host ~= "", 
-        "invalid host '" .. base.tostring(nreqt.host) .. "'")
+    if nreqt.port == "" then nreqt.port = PORT end
+    if not (nreqt.host and nreqt.host ~= "") then
+        socket.try(nil, "invalid host '" .. base.tostring(nreqt.host) .. "'")
+    end
     -- compute uri if user hasn't overriden
     nreqt.uri = reqt.uri or adjusturi(nreqt)
-    -- ajust host and port if there is a proxy
-    nreqt.host, nreqt.port = adjustproxy(nreqt)
     -- adjust headers in request
     nreqt.headers = adjustheaders(nreqt)
+    -- ajust host and port if there is a proxy
+    nreqt.host, nreqt.port = adjustproxy(nreqt)
     return nreqt
 end
 
 local function shouldredirect(reqt, code, headers)
-    return headers.location and
-           string.gsub(headers.location, "%s", "") ~= "" and
-           (reqt.redirect ~= false) and
+    local location = headers.location
+    if not location then return false end
+    location = string.gsub(location, "%s", "")
+    if location == "" then return false end
+    local scheme = string.match(location, "^([%w][%w%+%-%.]*)%:")
+    if scheme and not SCHEMES[scheme] then return false end
+    return (reqt.redirect ~= false) and
            (code == 301 or code == 302 or code == 303 or code == 307) and
            (not reqt.method or reqt.method == "GET" or reqt.method == "HEAD")
            and (not reqt.nredirects or reqt.nredirects < 5)
@@ -279,10 +297,10 @@ local trequest, tredirect
         source = reqt.source,
         sink = reqt.sink,
         headers = reqt.headers,
-        proxy = reqt.proxy, 
+        proxy = reqt.proxy,
         nredirects = (reqt.nredirects or 0) + 1,
         create = reqt.create
-    }   
+    }
     -- pass location header back as a hint we redirected
     headers = headers or {}
     headers.location = headers.location or location
@@ -299,7 +317,7 @@ end
     h:sendheaders(nreqt.headers)
     -- if there is a body, send it
     if nreqt.source then
-        h:sendbody(nreqt.headers, nreqt.source, nreqt.step) 
+        h:sendbody(nreqt.headers, nreqt.source, nreqt.step)
     end
     local code, status = h:receivestatusline()
     -- if it is an HTTP/0.9 server, simply get the body and we are done
@@ -309,13 +327,13 @@ end
     end
     local headers
     -- ignore any 100-continue messages
-    while code == 100 do 
+    while code == 100 do
         headers = h:receiveheaders()
         code, status = h:receivestatusline()
     end
     headers = h:receiveheaders()
     -- at this point we should have a honest reply from the server
-    -- we can't redirect if we already used the source, so we report the error 
+    -- we can't redirect if we already used the source, so we report the error
     if shouldredirect(nreqt, code, headers) and not nreqt.source then
         h:close()
         return tredirect(reqt, headers.location)
@@ -351,4 +369,4 @@ _M.request = socket.protect(function(reqt, body)
     else return trequest(reqt) end
 end)
 
-return _M
\ No newline at end of file
+return _M
diff --git a/src/inet.c b/src/inet.c
index 1a411f6..f4c8404 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -8,6 +8,7 @@
 
 #include "lua.h"
 #include "lauxlib.h"
+#include "compat.h"
 
 #include "inet.h"
 
@@ -41,11 +42,7 @@ int inet_open(lua_State *L)
 {
     lua_pushstring(L, "dns");
     lua_newtable(L);
-#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
     luaL_setfuncs(L, func, 0);
-#else
-    luaL_openlib(L, NULL, func, 0);
-#endif
     lua_settable(L, -3);
     return 0;
 }
@@ -97,7 +94,7 @@ static int inet_global_getnameinfo(lua_State *L) {
 
     memset(&hints, 0, sizeof(hints));
     hints.ai_socktype = SOCK_STREAM;
-    hints.ai_family = PF_UNSPEC;
+    hints.ai_family = AF_UNSPEC;
 
     ret = getaddrinfo(host, serv, &hints, &resolved);
     if (ret != 0) {
@@ -108,8 +105,8 @@ static int inet_global_getnameinfo(lua_State *L) {
 
     lua_newtable(L);
     for (i = 1, iter = resolved; iter; i++, iter = iter->ai_next) {
-        getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen, 
-            hbuf, host? (socklen_t) sizeof(hbuf): 0, 
+        getnameinfo(iter->ai_addr, (socklen_t) iter->ai_addrlen,
+            hbuf, host? (socklen_t) sizeof(hbuf): 0,
             sbuf, serv? (socklen_t) sizeof(sbuf): 0, 0);
         if (host) {
             lua_pushnumber(L, i);
@@ -149,7 +146,7 @@ static int inet_global_toip(lua_State *L)
 int inet_optfamily(lua_State* L, int narg, const char* def)
 {
     static const char* optname[] = { "unspec", "inet", "inet6", NULL };
-    static int optvalue[] = { PF_UNSPEC, PF_INET, PF_INET6, 0 };
+    static int optvalue[] = { AF_UNSPEC, AF_INET, AF_INET6, 0 };
 
     return optvalue[luaL_checkoption(L, narg, def, optname)];
 }
@@ -170,7 +167,7 @@ static int inet_global_getaddrinfo(lua_State *L)
     int i = 1, ret = 0;
     memset(&hints, 0, sizeof(hints));
     hints.ai_socktype = SOCK_STREAM;
-    hints.ai_family = PF_UNSPEC;
+    hints.ai_family = AF_UNSPEC;
     ret = getaddrinfo(hostname, NULL, &hints, &resolved);
     if (ret != 0) {
         lua_pushnil(L);
@@ -180,9 +177,10 @@ static int inet_global_getaddrinfo(lua_State *L)
     lua_newtable(L);
     for (iterator = resolved; iterator; iterator = iterator->ai_next) {
         char hbuf[NI_MAXHOST];
-        ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen, 
+        ret = getnameinfo(iterator->ai_addr, (socklen_t) iterator->ai_addrlen,
             hbuf, (socklen_t) sizeof(hbuf), NULL, 0, NI_NUMERICHOST);
         if (ret){
+          freeaddrinfo(resolved);
           lua_pushnil(L);
           lua_pushstring(L, socket_gaistrerror(ret));
           return 2;
@@ -200,6 +198,16 @@ static int inet_global_getaddrinfo(lua_State *L)
                 lua_pushliteral(L, "inet6");
                 lua_settable(L, -3);
                 break;
+            case AF_UNSPEC:
+                lua_pushliteral(L, "family");
+                lua_pushliteral(L, "unspec");
+                lua_settable(L, -3);
+                break;
+            default:
+                lua_pushliteral(L, "family");
+                lua_pushliteral(L, "unknown");
+                lua_settable(L, -3);
+                break;
         }
         lua_pushliteral(L, "addr");
         lua_pushstring(L, hbuf);
@@ -256,12 +264,11 @@ int inet_meth_getpeername(lua_State *L, p_socket ps, int family)
     }
     lua_pushstring(L, name);
     lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10));
-    if (family == PF_INET) {
-        lua_pushliteral(L, "inet");
-    } else if (family == PF_INET6) {
-        lua_pushliteral(L, "inet6");
-    } else {
-        lua_pushliteral(L, "uknown family");
+    switch (family) {
+        case AF_INET: lua_pushliteral(L, "inet"); break;
+        case AF_INET6: lua_pushliteral(L, "inet6"); break;
+        case AF_UNSPEC: lua_pushliteral(L, "unspec"); break;
+        default: lua_pushliteral(L, "unknown"); break;
     }
     return 3;
 }
@@ -281,7 +288,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
         lua_pushstring(L, socket_strerror(errno));
         return 2;
     }
-	err=getnameinfo((struct sockaddr *)&peer, peer_len, 
+	err=getnameinfo((struct sockaddr *)&peer, peer_len,
 		name, INET6_ADDRSTRLEN, port, 6, NI_NUMERICHOST | NI_NUMERICSERV);
     if (err) {
         lua_pushnil(L);
@@ -290,12 +297,11 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family)
     }
     lua_pushstring(L, name);
     lua_pushstring(L, port);
-    if (family == PF_INET) {
-        lua_pushliteral(L, "inet");
-    } else if (family == PF_INET6) {
-        lua_pushliteral(L, "inet6");
-    } else {
-        lua_pushliteral(L, "uknown family");
+    switch (family) {
+        case AF_INET: lua_pushliteral(L, "inet"); break;
+        case AF_INET6: lua_pushliteral(L, "inet6"); break;
+        case AF_UNSPEC: lua_pushliteral(L, "unspec"); break;
+        default: lua_pushliteral(L, "unknown"); break;
     }
     return 3;
 }
@@ -346,8 +352,13 @@ static void inet_pushresolved(lua_State *L, struct hostent *hp)
 /*-------------------------------------------------------------------------*\
 * Tries to create a new inet socket
 \*-------------------------------------------------------------------------*/
-const char *inet_trycreate(p_socket ps, int family, int type) {
-    return socket_strerror(socket_create(ps, family, type, 0));
+const char *inet_trycreate(p_socket ps, int family, int type, int protocol) {
+    const char *err = socket_strerror(socket_create(ps, family, type, protocol));
+    if (err == NULL && family == AF_INET6) {
+        int yes = 1;
+        setsockopt(*ps, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes));
+    }
+    return err;
 }
 
 /*-------------------------------------------------------------------------*\
@@ -356,21 +367,21 @@ const char *inet_trycreate(p_socket ps, int family, int type) {
 const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm)
 {
     switch (family) {
-        case PF_INET: {
+        case AF_INET: {
             struct sockaddr_in sin;
             memset((char *) &sin, 0, sizeof(sin));
             sin.sin_family = AF_UNSPEC;
             sin.sin_addr.s_addr = INADDR_ANY;
-            return socket_strerror(socket_connect(ps, (SA *) &sin, 
+            return socket_strerror(socket_connect(ps, (SA *) &sin,
                 sizeof(sin), tm));
         }
-        case PF_INET6: {
+        case AF_INET6: {
             struct sockaddr_in6 sin6;
-            struct in6_addr addrany = IN6ADDR_ANY_INIT; 
+            struct in6_addr addrany = IN6ADDR_ANY_INIT;
             memset((char *) &sin6, 0, sizeof(sin6));
             sin6.sin6_family = AF_UNSPEC;
             sin6.sin6_addr = addrany;
-            return socket_strerror(socket_connect(ps, (SA *) &sin6, 
+            return socket_strerror(socket_connect(ps, (SA *) &sin6,
                 sizeof(sin6), tm));
         }
     }
@@ -385,6 +396,7 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
 {
     struct addrinfo *iterator = NULL, *resolved = NULL;
     const char *err = NULL;
+    int current_family = *family;
     /* try resolving */
     err = socket_gaistrerror(getaddrinfo(address, serv,
                 connecthints, &resolved));
@@ -399,23 +411,23 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
          * that shows up while iterating. if there was a
          * bind, all families will be the same and we will
          * not enter this branch. */
-        if (*family != iterator->ai_family) {
+        if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
             socket_destroy(ps);
-            err = socket_strerror(socket_create(ps, iterator->ai_family, 
-                iterator->ai_socktype, iterator->ai_protocol));
-            if (err != NULL) {
-                freeaddrinfo(resolved);
-                return err;
-            }
-            *family = iterator->ai_family;
-            /* all sockets initially non-blocking */
+            err = inet_trycreate(ps, iterator->ai_family,
+                iterator->ai_socktype, iterator->ai_protocol);
+            if (err) continue;
+            current_family = iterator->ai_family;
+            /* set non-blocking before connect */
             socket_setnonblocking(ps);
         }
         /* try connecting to remote address */
-        err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr, 
+        err = socket_strerror(socket_connect(ps, (SA *) iterator->ai_addr,
             (socklen_t) iterator->ai_addrlen, tm));
-        /* if success, break out of loop */
-        if (err == NULL) break;
+        /* if success or timeout is zero, break out of loop */
+        if (err == NULL || timeout_iszero(tm)) {
+            *family = current_family;
+            break;
+        }
     }
     freeaddrinfo(resolved);
     /* here, if err is set, we failed */
@@ -425,29 +437,27 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
 /*-------------------------------------------------------------------------*\
 * Tries to accept a socket
 \*-------------------------------------------------------------------------*/
-const char *inet_tryaccept(p_socket server, int family, p_socket client, 
-    p_timeout tm)
-{
+const char *inet_tryaccept(p_socket server, int family, p_socket client,
+    p_timeout tm) {
 	socklen_t len;
 	t_sockaddr_storage addr;
-	if (family == PF_INET6) {
-		len = sizeof(struct sockaddr_in6);
-	} else {
-		len = sizeof(struct sockaddr_in);
-	}
-	return socket_strerror(socket_accept(server, client, (SA *) &addr, 
+    switch (family) {
+        case AF_INET6: len = sizeof(struct sockaddr_in6); break;
+        case AF_INET: len = sizeof(struct sockaddr_in); break;
+        default: len = sizeof(addr); break;
+    }
+	return socket_strerror(socket_accept(server, client, (SA *) &addr,
         &len, tm));
 }
 
 /*-------------------------------------------------------------------------*\
 * Tries to bind socket to (address, port)
 \*-------------------------------------------------------------------------*/
-const char *inet_trybind(p_socket ps, const char *address, const char *serv,
-        struct addrinfo *bindhints)
-{
+const char *inet_trybind(p_socket ps, int *family, const char *address,
+    const char *serv, struct addrinfo *bindhints) {
     struct addrinfo *iterator = NULL, *resolved = NULL;
     const char *err = NULL;
-    t_socket sock = *ps;
+    int current_family = *family;
     /* translate luasocket special values to C */
     if (strcmp(address, "*") == 0) address = NULL;
     if (!serv) serv = "0";
@@ -459,35 +469,32 @@ const char *inet_trybind(p_socket ps, const char *address, const char *serv,
     }
     /* iterate over resolved addresses until one is good */
     for (iterator = resolved; iterator; iterator = iterator->ai_next) {
-        if(sock == SOCKET_INVALID) {
-            err = socket_strerror(socket_create(&sock, iterator->ai_family,
-                        iterator->ai_socktype, iterator->ai_protocol));
-            if(err)
-                continue;
+        if (current_family != iterator->ai_family || *ps == SOCKET_INVALID) {
+            socket_destroy(ps);
+            err = inet_trycreate(ps, iterator->ai_family,
+                        iterator->ai_socktype, iterator->ai_protocol);
+            if (err) continue;
+            current_family = iterator->ai_family;
         }
         /* try binding to local address */
-        err = socket_strerror(socket_bind(&sock,
-            (SA *) iterator->ai_addr,
+        err = socket_strerror(socket_bind(ps, (SA *) iterator->ai_addr,
             (socklen_t) iterator->ai_addrlen));
-
         /* keep trying unless bind succeeded */
-        if (err) {
-            if(sock != *ps)
-                socket_destroy(&sock);
-        } else {
-            /* remember what we connected to, particularly the family */
-            *bindhints = *iterator;
+        if (err == NULL) {
+            *family = current_family;
+            /* set to non-blocking after bind */
+            socket_setnonblocking(ps);
             break;
         }
     }
     /* cleanup and return error */
     freeaddrinfo(resolved);
-    *ps = sock;
+    /* here, if err is set, we failed */
     return err;
 }
 
 /*-------------------------------------------------------------------------*\
-* Some systems do not provide these so that we provide our own. 
+* Some systems do not provide these so that we provide our own.
 \*-------------------------------------------------------------------------*/
 #ifdef LUASOCKET_INET_ATON
 int inet_aton(const char *cp, struct in_addr *inp)
@@ -512,7 +519,7 @@ int inet_aton(const char *cp, struct in_addr *inp)
 #endif
 
 #ifdef LUASOCKET_INET_PTON
-int inet_pton(int af, const char *src, void *dst) 
+int inet_pton(int af, const char *src, void *dst)
 {
     struct addrinfo hints, *res;
     int ret = 1;
@@ -529,7 +536,7 @@ int inet_pton(int af, const char *src, void *dst)
     } else {
         ret = -1;
     }
-    freeaddrinfo(res); 
+    freeaddrinfo(res);
     return ret;
 }
 
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 @@
-#ifndef INET_H 
-#define INET_H 
+#ifndef INET_H
+#define INET_H
 /*=========================================================================*\
 * Internet domain functions
 * LuaSocket toolkit
 *
 * This module implements the creation and connection of internet domain
 * sockets, on top of the socket.h interface, and the interface of with the
-* resolver. 
+* resolver.
 *
 * The function inet_aton is provided for the platforms where it is not
 * available. The module also implements the interface of the internet
@@ -24,11 +24,11 @@
 
 int inet_open(lua_State *L);
 
-const char *inet_trycreate(p_socket ps, int family, int type);
+const char *inet_trycreate(p_socket ps, int family, int type, int protocol);
 const char *inet_tryconnect(p_socket ps, int *family, const char *address,
         const char *serv, p_timeout tm, struct addrinfo *connecthints);
-const char *inet_trybind(p_socket ps, const char *address, const char *serv,
-        struct addrinfo *bindhints);
+const char *inet_trybind(p_socket ps, int *family, const char *address,
+        const char *serv, struct addrinfo *bindhints);
 const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm);
 const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm);
 
diff --git a/src/io.c b/src/io.c
index 35f46f7..a4230ce 100644
--- a/src/io.c
+++ b/src/io.c
@@ -25,6 +25,6 @@ const char *io_strerror(int err) {
         case IO_DONE: return NULL;
         case IO_CLOSED: return "closed";
         case IO_TIMEOUT: return "timeout";
-        default: return "unknown error"; 
+        default: return "unknown error";
     }
 }
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 {
     IO_DONE = 0,        /* operation completed successfully */
     IO_TIMEOUT = -1,    /* operation timed out */
     IO_CLOSED = -2,     /* the connection has been closed */
-	IO_UNKNOWN = -3     
+	IO_UNKNOWN = -3
 };
 
 /* interface to error message function */
diff --git a/src/ltn12.lua b/src/ltn12.lua
index 5b10f56..575c5a7 100644
--- a/src/ltn12.lua
+++ b/src/ltn12.lua
@@ -9,6 +9,7 @@
 -----------------------------------------------------------------------------
 local string = require("string")
 local table = require("table")
+local unpack = unpack or table.unpack
 local base = _G
 local _M = {}
 if module then -- heuristic for exporting a global package table
@@ -21,6 +22,9 @@ _M.source = source
 _M.sink = sink
 _M.pump = pump
 
+local unpack = unpack or table.unpack
+local select = base.select
+
 -- 2048 seems to be better in windows...
 _M.BLOCKSIZE = 2048
 _M._VERSION = "LTN12 1.0.3"
@@ -42,7 +46,7 @@ end
 -- (thanks to Wim Couwenberg)
 function filter.chain(...)
     local arg = {...}
-    local n = select('#',...)
+    local n = base.select('#',...)
     local top, index = 1, 1
     local retry = ""
     return function(chunk)
@@ -139,7 +143,9 @@ function source.rewind(src)
     end
 end
 
-function source.chain(src, f)
+-- chains a source with one or several filter(s)
+function source.chain(src, f, ...)
+    if ... then f=filter.chain(f, ...) end
     base.assert(src and f)
     local last_in, last_out = "", ""
     local state = "feeding"
@@ -254,8 +260,13 @@ function sink.error(err)
     end
 end
 
--- chains a sink with a filter
-function sink.chain(f, snk)
+-- chains a sink with one or several filter(s)
+function sink.chain(f, snk, ...)
+    if ... then
+        local args = { f, snk, ... }
+        snk = table.remove(args, #args)
+        f = filter.chain(unpack(args))
+    end
     base.assert(f and snk)
     return function(chunk, err)
         if chunk ~= "" then
diff --git a/src/luasocket.c b/src/luasocket.c
index e6ee747..7d9c802 100644
--- a/src/luasocket.c
+++ b/src/luasocket.c
@@ -17,7 +17,7 @@
 \*=========================================================================*/
 #include "lua.h"
 #include "lauxlib.h"
-
+#include "compat.h"
 
 /*=========================================================================*\
 * LuaSocket includes
@@ -64,7 +64,7 @@ static luaL_Reg func[] = {
 * Skip a few arguments
 \*-------------------------------------------------------------------------*/
 static int global_skip(lua_State *L) {
-    int amount = luaL_checkint(L, 1);
+    int amount = luaL_checkinteger(L, 1);
     int ret = lua_gettop(L) - amount - 1;
     return ret >= 0 ? ret : 0;
 }
@@ -78,26 +78,14 @@ static int global_unload(lua_State *L) {
     return 0;
 }
 
-#if LUA_VERSION_NUM > 501
-int luaL_typerror (lua_State *L, int narg, const char *tname) {
-  const char *msg = lua_pushfstring(L, "%s expected, got %s",
-                                    tname, luaL_typename(L, narg));
-  return luaL_argerror(L, narg, msg);
-}
-#endif
-
 /*-------------------------------------------------------------------------*\
 * Setup basic stuff.
 \*-------------------------------------------------------------------------*/
 static int base_open(lua_State *L) {
     if (socket_open()) {
         /* export functions (and leave namespace table on top of stack) */
-#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
         lua_newtable(L);
         luaL_setfuncs(L, func, 0);
-#else
-        luaL_openlib(L, "socket", func, 0);
-#endif
 #ifdef LUASOCKET_DEBUG
         lua_pushstring(L, "_DEBUG");
         lua_pushboolean(L, 1);
diff --git a/src/makefile b/src/makefile
index c24e61b..adf687f 100644
--- a/src/makefile
+++ b/src/makefile
@@ -20,15 +20,17 @@ PLAT?=linux
 # lua version to build against
 LUAV?=5.1
 
+# MYCFLAGS: to be set by user if needed
+MYCFLAGS=
+
+# MYLDFLAGS: to be set by user if needed
+MYLDFLAGS=
+
 # DEBUG: NODEBUG DEBUG
 # debug mode causes luasocket to collect and returns timing information useful
 # for testing and debugging luasocket itself
 DEBUG?=NODEBUG
 
-# COMPAT: COMPAT NOCOMPAT
-# when compiling for 5.2, use LUA_COMPAT_MODULE
-COMPAT?=NOCOMPAT
-
 # where lua headers are found for macosx builds
 # LUAINC_macosx:
 # /opt/local/include
@@ -40,7 +42,6 @@ LUAPREFIX_macosx?=/opt/local
 CDIR_macosx?=lib/lua/$(LUAV)
 LDIR_macosx?=share/lua/$(LUAV)
 
-
 # LUAINC_linux:
 # /usr/include/lua$(LUAV)
 # /usr/local/include
@@ -52,8 +53,17 @@ LUAPREFIX_linux?=/usr/local
 CDIR_linux?=lib/lua/$(LUAV)
 LDIR_linux?=share/lua/$(LUAV)
 
+# LUAINC_freebsd:
+# /usr/local/include/lua$(LUAV)
+# where lua headers are found for freebsd builds
+LUAINC_freebsd_base?=/usr/local/include/
+LUAINC_freebsd?=$(LUAINC_freebsd_base)/lua$(LUAV)
+LUAPREFIX_freebsd?=/usr/local/
+CDIR_freebsd?=lib/lua/$(LUAV)
+LDIR_freebsd?=share/lua/$(LUAV)
+
 # where lua headers are found for mingw builds
-# LUAINC_mingw: 
+# LUAINC_mingw:
 # /opt/local/include
 LUAINC_mingw_base?=/usr/include
 LUAINC_mingw?=$(LUAINC_mingw_base)/lua/$(LUAV)
@@ -67,13 +77,21 @@ LDIR_mingw?=lua/$(LUAV)/lua
 # LUAINC_win32:
 # LUALIB_win32:
 # where lua headers and libraries are found for win32 builds
-LUAINC_win32_base?=
-LUAINC_win32?=$(LUAINC_win32_base)/lua/$(LUAV)
-PLATFORM_win32?=Release
 LUAPREFIX_win32?=
-CDIR_win32?=lua/$(LUAV)/$(PLATFORM_win32)
-LDIR_win32?=lua/$(LUAV)/$(PLATFORM_win32)/lua
-LUALIB_win32?=$(LUAPREFIX_win32)/lua/$(LUAV)/$(PLATFORM_win32)
+LUAINC_win32?=$(LUAPREFIX_win32)/include/lua/$(LUAV)
+PLATFORM_win32?=Release
+CDIR_win32?=bin/lua/$(LUAV)/$(PLATFORM_win32)
+LDIR_win32?=bin/lua/$(LUAV)/$(PLATFORM_win32)/lua
+LUALIB_win32?=$(LUAPREFIX_win32)/lib/lua/$(LUAV)/$(PLATFORM_win32)
+LUALIBNAME_win32?=lua$(subst .,,$(LUAV)).lib 
+
+
+# LUAINC_solaris:
+LUAINC_solaris_base?=/usr/include
+LUAINC_solaris?=$(LUAINC_solaris_base)/lua/$(LUAV)
+LUAPREFIX_solaris?=/usr/local
+CDIR_solaris?=lib/lua/$(LUAV)
+LDIR_solaris?=share/lua/$(LUAV)
 
 # prefix: /usr/local /usr /opt/local /sw
 # the top of the default install tree
@@ -121,7 +139,7 @@ print:
 #------
 # Supported platforms
 #
-PLATS= macosx linux win32 mingw
+PLATS= macosx linux win32 mingw solaris
 
 #------
 # Compiler and linker settings
@@ -129,11 +147,11 @@ PLATS= macosx linux win32 mingw
 SO_macosx=so
 O_macosx=o
 CC_macosx=gcc
-DEF_macosx= -DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN -DLUA_$(COMPAT)_MODULE \
+DEF_macosx= -DLUASOCKET_$(DEBUG) -DUNIX_HAS_SUN_LEN \
 	-DLUASOCKET_API='__attribute__((visibility("default")))' \
 	-DUNIX_API='__attribute__((visibility("default")))' \
 	-DMIME_API='__attribute__((visibility("default")))'
-CFLAGS_macosx= -I$(LUAINC) $(DEF) -pedantic -Wall -O2 -fno-common \
+CFLAGS_macosx= -I$(LUAINC) $(DEF) -Wall -O2 -fno-common \
 	-fvisibility=hidden
 LDFLAGS_macosx= -bundle -undefined dynamic_lookup -o 
 LD_macosx= export MACOSX_DEPLOYMENT_TARGET="10.3"; gcc
@@ -145,11 +163,11 @@ SOCKET_macosx=usocket.o
 SO_linux=so
 O_linux=o
 CC_linux=gcc
-DEF_linux=-DLUASOCKET_$(DEBUG) -DLUA_$(COMPAT)_MODULE \
+DEF_linux=-DLUASOCKET_$(DEBUG) \
 	-DLUASOCKET_API='__attribute__((visibility("default")))' \
 	-DUNIX_API='__attribute__((visibility("default")))' \
 	-DMIME_API='__attribute__((visibility("default")))'
-CFLAGS_linux= -I$(LUAINC) $(DEF) -pedantic -Wall -Wshadow -Wextra \
+CFLAGS_linux= -I$(LUAINC) $(DEF) -Wall -Wshadow -Wextra \
 	-Wimplicit -O2 -ggdb3 -fpic -fvisibility=hidden
 LDFLAGS_linux=-O -shared -fpic -o 
 LD_linux=gcc
@@ -157,14 +175,46 @@ SOCKET_linux=usocket.o
 
 #------
 # Compiler and linker settings
+# for FreeBSD
+SO_freebsd=so
+O_freebsd=o
+CC_freebsd=gcc
+DEF_freebsd=-DLUASOCKET_$(DEBUG) \
+	-DLUASOCKET_API='__attribute__((visibility("default")))' \
+	-DUNIX_API='__attribute__((visibility("default")))' \
+	-DMIME_API='__attribute__((visibility("default")))'
+CFLAGS_freebsd= -I$(LUAINC) $(DEF) -Wall -Wshadow -Wextra \
+	-Wimplicit -O2 -ggdb3 -fpic -fvisibility=hidden
+LDFLAGS_freebsd=-O -shared -fpic -o 
+LD_freebsd=gcc
+SOCKET_freebsd=usocket.o
+
+#------
+# Compiler and linker settings
+# for Solaris
+SO_solaris=so
+O_solaris=o
+CC_solaris=gcc
+DEF_solaris=-DLUASOCKET_$(DEBUG) \
+	-DLUASOCKET_API='__attribute__((visibility("default")))' \
+	-DUNIX_API='__attribute__((visibility("default")))' \
+	-DMIME_API='__attribute__((visibility("default")))'
+CFLAGS_solaris=-I$(LUAINC) $(DEF) -Wall -Wshadow -Wextra \
+	-Wimplicit -O2 -ggdb3 -fpic -fvisibility=hidden   
+LDFLAGS_solaris=-lnsl -lsocket -lresolv -O -shared -fpic -o 
+LD_solaris=gcc
+SOCKET_solaris=usocket.o
+
+#------
+# Compiler and linker settings
 # for MingW
 SO_mingw=dll
 O_mingw=o
 CC_mingw=gcc
-DEF_mingw= -DLUASOCKET_INET_PTON -DLUASOCKET_$(DEBUG) -DLUA_$(COMPAT)_MODULE \
+DEF_mingw= -DLUASOCKET_INET_PTON -DLUASOCKET_$(DEBUG) \
 	-DWINVER=0x0501 -DLUASOCKET_API='__declspec(dllexport)' \
 	-DMIME_API='__declspec(dllexport)'
-CFLAGS_mingw= -I$(LUAINC) $(DEF) -pedantic -Wall -O2 -fno-common \
+CFLAGS_mingw= -I$(LUAINC) $(DEF) -Wall -O2 -fno-common \
 	-fvisibility=hidden
 LDFLAGS_mingw= $(LUALIB) -shared -Wl,-s -lws2_32 -o 
 LD_mingw=gcc
@@ -179,8 +229,7 @@ O_win32=obj
 CC_win32=cl
 DEF_win32= //D "WIN32" //D "NDEBUG" //D "_WINDOWS" //D "_USRDLL" \
      //D "LUASOCKET_API=__declspec(dllexport)" //D "_CRT_SECURE_NO_WARNINGS" \
-     //D "_WINDLL" //D "LUA_$(COMPAT)_MODULE" \
-	 //D "MIME_API=__declspec(dllexport)" \
+     //D "_WINDLL" //D "MIME_API=__declspec(dllexport)" \
      //D "LUASOCKET_$(DEBUG)" 
 CFLAGS_win32=//I "$(LUAINC)" $(DEF) //O2 //Ot //MD //W3 //nologo
 LDFLAGS_win32= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \
@@ -188,7 +237,7 @@ LDFLAGS_win32= //nologo //link //NOLOGO //DLL //INCREMENTAL:NO \
     //MANIFESTUAC:"level='asInvoker' uiAccess='false'" \
 	//SUBSYSTEM:WINDOWS //OPT:REF //OPT:ICF //DYNAMICBASE:NO \
     //MACHINE:X86 /LIBPATH:"$(shell cmd //c echo $(LUALIB))" \
-	lua$(subst .,,$(LUAV)).lib ws2_32.lib //OUT:
+	$(LUALIBNAME_win32) ws2_32.lib //OUT:
 LD_win32=cl
 SOCKET_win32=wsocket.obj
 
@@ -204,8 +253,8 @@ SO=$(SO_$(PLAT))
 O=$(O_$(PLAT))
 SOCKET_V=3.0-rc1
 MIME_V=1.0.3
-SOCKET_SO=socket.$(SO).$(SOCKET_V)
-MIME_SO=mime.$(SO).$(MIME_V)
+SOCKET_SO=socket-$(SOCKET_V).$(SO)
+MIME_SO=mime-$(MIME_V).$(SO)
 UNIX_SO=unix.$(SO)
 SERIAL_SO=serial.$(SO)
 SOCKET=$(SOCKET_$(PLAT))
@@ -215,8 +264,8 @@ SOCKET=$(SOCKET_$(PLAT))
 #
 CC=$(CC_$(PLAT))
 DEF=$(DEF_$(PLAT))
-CFLAGS=$(CFLAGS_$(PLAT))
-LDFLAGS=$(LDFLAGS_$(PLAT))
+CFLAGS=$(MYCFLAGS) $(CFLAGS_$(PLAT))
+LDFLAGS=$(MYLDFLAGS) $(LDFLAGS_$(PLAT))
 LD=$(LD_$(PLAT))
 LUAINC= $(LUAINC_$(PLAT))
 LUALIB= $(LUALIB_$(PLAT))
@@ -230,6 +279,7 @@ SOCKET_OBJS= \
 	buffer.$(O) \
 	io.$(O) \
 	auxiliar.$(O) \
+	compat.$(O) \
 	options.$(O) \
 	inet.$(O) \
 	$(SOCKET) \
@@ -242,7 +292,8 @@ SOCKET_OBJS= \
 # Modules belonging mime-core
 #
 MIME_OBJS= \
-	mime.$(O)
+	mime.$(O) \
+	compat.$(O)
 
 #------
 # Modules belonging unix (local domain sockets)
@@ -259,7 +310,7 @@ UNIX_OBJS=\
 #------
 # Modules belonging to serial (device streams)
 #
-SERIAL_OBJS:=\
+SERIAL_OBJS=\
 	buffer.$(O) \
 	auxiliar.$(O) \
 	options.$(O) \
@@ -289,6 +340,10 @@ TO_TOP_LDIR= \
 #
 default: $(PLAT)
 
+
+freebsd:
+	$(MAKE) all-unix PLAT=freebsd
+
 macosx:
 	$(MAKE) all-unix PLAT=macosx
 
@@ -300,6 +355,9 @@ linux:
 
 mingw:
 	$(MAKE) all PLAT=mingw
+	
+solaris:
+	$(MAKE) all-unix PLAT=solaris
 
 none:
 	@echo "Please run"
@@ -349,6 +407,7 @@ clean:
 #------
 # List of dependencies
 #
+compat.$(O): compat.c compat.h
 auxiliar.$(O): auxiliar.c auxiliar.h
 buffer.$(O): buffer.c buffer.h io.h timeout.h
 except.$(O): except.c except.h
diff --git a/src/mbox.lua b/src/mbox.lua
index 7724ae2..ed9e781 100644
--- a/src/mbox.lua
+++ b/src/mbox.lua
@@ -61,7 +61,7 @@ function _M.parse_from(from)
 end
 
 function _M.split_mbox(mbox_s)
-    mbox = {}
+    local mbox = {}
     mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n"
     local nj, i, j = 1, 1, 1
     while 1 do
diff --git a/src/mime.c b/src/mime.c
index dd37dcf..ed44104 100644
--- a/src/mime.c
+++ b/src/mime.c
@@ -6,10 +6,7 @@
 
 #include "lua.h"
 #include "lauxlib.h"
-
-#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
-#include "compat-5.1.h"
-#endif
+#include "compat.h"
 
 #include "mime.h"
 
@@ -41,7 +38,7 @@ static size_t b64decode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
 static void qpsetup(UC *class, UC *unbase);
 static void qpquote(UC c, luaL_Buffer *buffer);
 static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer);
-static size_t qpencode(UC c, UC *input, size_t size, 
+static size_t qpencode(UC c, UC *input, size_t size,
         const char *marker, luaL_Buffer *buffer);
 static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer);
 
@@ -81,12 +78,8 @@ static UC b64unbase[256];
 \*-------------------------------------------------------------------------*/
 MIME_API int luaopen_mime_core(lua_State *L)
 {
-#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
     lua_newtable(L);
     luaL_setfuncs(L, func, 0);
-#else
-    luaL_openlib(L, "mime", func, 0);
-#endif
     /* make version string available to scripts */
     lua_pushstring(L, "_VERSION");
     lua_pushstring(L, MIME_VERSION);
@@ -103,15 +96,15 @@ MIME_API int luaopen_mime_core(lua_State *L)
 /*-------------------------------------------------------------------------*\
 * Incrementaly breaks a string into lines. The string can have CRLF breaks.
 * A, n = wrp(l, B, length)
-* A is a copy of B, broken into lines of at most 'length' bytes. 
-* 'l' is how many bytes are left for the first line of B. 
-* 'n' is the number of bytes left in the last line of A. 
+* A is a copy of B, broken into lines of at most 'length' bytes.
+* 'l' is how many bytes are left for the first line of B.
+* 'n' is the number of bytes left in the last line of A.
 \*-------------------------------------------------------------------------*/
 static int mime_global_wrp(lua_State *L)
 {
     size_t size = 0;
     int left = (int) luaL_checknumber(L, 1);
-    const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size);
+    const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size);
     const UC *last = input + size;
     int length = (int) luaL_optnumber(L, 3, 76);
     luaL_Buffer buffer;
@@ -123,7 +116,7 @@ static int mime_global_wrp(lua_State *L)
         else lua_pushnil(L);
         lua_pushnumber(L, length);
         return 2;
-    } 
+    }
     luaL_buffinit(L, &buffer);
     while (input < last) {
         switch (*input) {
@@ -150,9 +143,9 @@ static int mime_global_wrp(lua_State *L)
 }
 
 /*-------------------------------------------------------------------------*\
-* Fill base64 decode map. 
+* Fill base64 decode map.
 \*-------------------------------------------------------------------------*/
-static void b64setup(UC *unbase) 
+static void b64setup(UC *unbase)
 {
     int i;
     for (i = 0; i <= 255; i++) unbase[i] = (UC) 255;
@@ -161,11 +154,11 @@ static void b64setup(UC *unbase)
 }
 
 /*-------------------------------------------------------------------------*\
-* Acumulates bytes in input buffer until 3 bytes are available. 
+* Acumulates bytes in input buffer until 3 bytes are available.
 * Translate the 3 bytes into Base64 form and append to buffer.
 * Returns new number of bytes in buffer.
 \*-------------------------------------------------------------------------*/
-static size_t b64encode(UC c, UC *input, size_t size, 
+static size_t b64encode(UC c, UC *input, size_t size,
         luaL_Buffer *buffer)
 {
     input[size++] = c;
@@ -174,7 +167,7 @@ static size_t b64encode(UC c, UC *input, size_t size,
         unsigned long value = 0;
         value += input[0]; value <<= 8;
         value += input[1]; value <<= 8;
-        value += input[2]; 
+        value += input[2];
         code[3] = b64base[value & 0x3f]; value >>= 6;
         code[2] = b64base[value & 0x3f]; value >>= 6;
         code[1] = b64base[value & 0x3f]; value >>= 6;
@@ -186,11 +179,11 @@ static size_t b64encode(UC c, UC *input, size_t size,
 }
 
 /*-------------------------------------------------------------------------*\
-* Encodes the Base64 last 1 or 2 bytes and adds padding '=' 
+* Encodes the Base64 last 1 or 2 bytes and adds padding '='
 * Result, if any, is appended to buffer.
 * Returns 0.
 \*-------------------------------------------------------------------------*/
-static size_t b64pad(const UC *input, size_t size, 
+static size_t b64pad(const UC *input, size_t size,
         luaL_Buffer *buffer)
 {
     unsigned long value = 0;
@@ -203,7 +196,7 @@ static size_t b64pad(const UC *input, size_t size,
             luaL_addlstring(buffer, (char *) code, 4);
             break;
         case 2:
-            value = input[0]; value <<= 8; 
+            value = input[0]; value <<= 8;
             value |= input[1]; value <<= 2;
             code[2] = b64base[value & 0x3f]; value >>= 6;
             code[1] = b64base[value & 0x3f]; value >>= 6;
@@ -217,11 +210,11 @@ static size_t b64pad(const UC *input, size_t size,
 }
 
 /*-------------------------------------------------------------------------*\
-* Acumulates bytes in input buffer until 4 bytes are available. 
+* Acumulates bytes in input buffer until 4 bytes are available.
 * Translate the 4 bytes from Base64 form and append to buffer.
 * Returns new number of bytes in buffer.
 \*-------------------------------------------------------------------------*/
-static size_t b64decode(UC c, UC *input, size_t size, 
+static size_t b64decode(UC c, UC *input, size_t size,
         luaL_Buffer *buffer)
 {
     /* ignore invalid characters */
@@ -239,7 +232,7 @@ static size_t b64decode(UC c, UC *input, size_t size,
         decoded[1] = (UC) (value & 0xff); value >>= 8;
         decoded[0] = (UC) value;
         /* take care of paddding */
-        valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3; 
+        valid = (input[2] == '=') ? 1 : (input[3] == '=') ? 2 : 3;
         luaL_addlstring(buffer, (char *) decoded, valid);
         return 0;
     /* need more data */
@@ -251,7 +244,7 @@ static size_t b64decode(UC c, UC *input, size_t size,
 * A, B = b64(C, D)
 * A is the encoded version of the largest prefix of C .. D that is
 * divisible by 3. B has the remaining bytes of C .. D, *without* encoding.
-* The easiest thing would be to concatenate the two strings and 
+* The easiest thing would be to concatenate the two strings and
 * encode the result, but we can't afford that or Lua would dupplicate
 * every chunk we received.
 \*-------------------------------------------------------------------------*/
@@ -259,7 +252,7 @@ static int mime_global_b64(lua_State *L)
 {
     UC atom[3];
     size_t isize = 0, asize = 0;
-    const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
+    const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
     const UC *last = input + isize;
     luaL_Buffer buffer;
     /* end-of-input blackhole */
@@ -272,9 +265,9 @@ static int mime_global_b64(lua_State *L)
     lua_settop(L, 2);
     /* process first part of the input */
     luaL_buffinit(L, &buffer);
-    while (input < last) 
+    while (input < last)
         asize = b64encode(*input++, atom, asize, &buffer);
-    input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
+    input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
     /* if second part is nil, we are done */
     if (!input) {
         size_t osize = 0;
@@ -288,7 +281,7 @@ static int mime_global_b64(lua_State *L)
     }
     /* otherwise process the second part */
     last = input + isize;
-    while (input < last) 
+    while (input < last)
         asize = b64encode(*input++, atom, asize, &buffer);
     luaL_pushresult(&buffer);
     lua_pushlstring(L, (char *) atom, asize);
@@ -305,7 +298,7 @@ static int mime_global_unb64(lua_State *L)
 {
     UC atom[4];
     size_t isize = 0, asize = 0;
-    const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
+    const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
     const UC *last = input + isize;
     luaL_Buffer buffer;
     /* end-of-input blackhole */
@@ -318,9 +311,9 @@ static int mime_global_unb64(lua_State *L)
     lua_settop(L, 2);
     /* process first part of the input */
     luaL_buffinit(L, &buffer);
-    while (input < last) 
+    while (input < last)
         asize = b64decode(*input++, atom, asize, &buffer);
-    input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
+    input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
     /* if second is nil, we are done */
     if (!input) {
         size_t osize = 0;
@@ -333,7 +326,7 @@ static int mime_global_unb64(lua_State *L)
     }
     /* otherwise, process the rest of the input */
     last = input + isize;
-    while (input < last) 
+    while (input < last)
         asize = b64decode(*input++, atom, asize, &buffer);
     luaL_pushresult(&buffer);
     lua_pushlstring(L, (char *) atom, asize);
@@ -349,7 +342,7 @@ static int mime_global_unb64(lua_State *L)
 * 9 and 32 can be plain, unless in the end of a line, where must be =XX
 * encoded lines must be no longer than 76 not counting CRLF
 * soft line-break are =CRLF
-* To encode one byte, we need to see the next two. 
+* To encode one byte, we need to see the next two.
 * Worst case is when we see a space, and wonder if a CRLF is comming
 \*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*\
@@ -362,7 +355,7 @@ static void qpsetup(UC *cl, UC *unbase)
     for (i = 0; i < 256; i++) cl[i] = QP_QUOTED;
     for (i = 33; i <= 60; i++) cl[i] = QP_PLAIN;
     for (i = 62; i <= 126; i++) cl[i] = QP_PLAIN;
-    cl['\t'] = QP_IF_LAST; 
+    cl['\t'] = QP_IF_LAST;
     cl[' '] = QP_IF_LAST;
     cl['\r'] = QP_CR;
     for (i = 0; i < 256; i++) unbase[i] = 255;
@@ -388,9 +381,9 @@ static void qpquote(UC c, luaL_Buffer *buffer)
 
 /*-------------------------------------------------------------------------*\
 * Accumulate characters until we are sure about how to deal with them.
-* Once we are sure, output to the buffer, in the correct form. 
+* Once we are sure, output to the buffer, in the correct form.
 \*-------------------------------------------------------------------------*/
-static size_t qpencode(UC c, UC *input, size_t size, 
+static size_t qpencode(UC c, UC *input, size_t size,
         const char *marker, luaL_Buffer *buffer)
 {
     input[size++] = c;
@@ -431,7 +424,7 @@ static size_t qpencode(UC c, UC *input, size_t size,
 }
 
 /*-------------------------------------------------------------------------*\
-* Deal with the final characters 
+* Deal with the final characters
 \*-------------------------------------------------------------------------*/
 static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
 {
@@ -448,8 +441,8 @@ static size_t qppad(UC *input, size_t size, luaL_Buffer *buffer)
 * Incrementally converts a string to quoted-printable
 * A, B = qp(C, D, marker)
 * Marker is the text to be used to replace CRLF sequences found in A.
-* A is the encoded version of the largest prefix of C .. D that 
-* can be encoded without doubts. 
+* A is the encoded version of the largest prefix of C .. D that
+* can be encoded without doubts.
 * B has the remaining bytes of C .. D, *without* encoding.
 \*-------------------------------------------------------------------------*/
 static int mime_global_qp(lua_State *L)
@@ -457,7 +450,7 @@ static int mime_global_qp(lua_State *L)
 
     size_t asize = 0, isize = 0;
     UC atom[3];
-    const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
+    const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
     const UC *last = input + isize;
     const char *marker = luaL_optstring(L, 3, CRLF);
     luaL_Buffer buffer;
@@ -473,7 +466,7 @@ static int mime_global_qp(lua_State *L)
     luaL_buffinit(L, &buffer);
     while (input < last)
         asize = qpencode(*input++, atom, asize, marker, &buffer);
-    input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
+    input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
     /* if second part is nil, we are done */
     if (!input) {
         asize = qppad(atom, asize, &buffer);
@@ -493,7 +486,7 @@ static int mime_global_qp(lua_State *L)
 
 /*-------------------------------------------------------------------------*\
 * Accumulate characters until we are sure about how to deal with them.
-* Once we are sure, output the to the buffer, in the correct form. 
+* Once we are sure, output the to the buffer, in the correct form.
 \*-------------------------------------------------------------------------*/
 static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
     int d;
@@ -501,8 +494,8 @@ static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
     /* deal with all characters we can deal */
     switch (input[0]) {
         /* if we have an escape character */
-        case '=': 
-            if (size < 3) return size; 
+        case '=':
+            if (size < 3) return size;
             /* eliminate soft line break */
             if (input[1] == '\r' && input[2] == '\n') return 0;
             /* decode quoted representation */
@@ -512,7 +505,7 @@ static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
             else luaL_addchar(buffer, (char) ((c << 4) + d));
             return 0;
         case '\r':
-            if (size < 2) return size; 
+            if (size < 2) return size;
             if (input[1] == '\n') luaL_addlstring(buffer, (char *)input, 2);
             return 0;
         default:
@@ -525,15 +518,15 @@ static size_t qpdecode(UC c, UC *input, size_t size, luaL_Buffer *buffer) {
 /*-------------------------------------------------------------------------*\
 * Incrementally decodes a string in quoted-printable
 * A, B = qp(C, D)
-* A is the decoded version of the largest prefix of C .. D that 
-* can be decoded without doubts. 
+* A is the decoded version of the largest prefix of C .. D that
+* can be decoded without doubts.
 * B has the remaining bytes of C .. D, *without* decoding.
 \*-------------------------------------------------------------------------*/
 static int mime_global_unqp(lua_State *L)
 {
     size_t asize = 0, isize = 0;
     UC atom[3];
-    const UC *input = (UC *) luaL_optlstring(L, 1, NULL, &isize);
+    const UC *input = (const UC *) luaL_optlstring(L, 1, NULL, &isize);
     const UC *last = input + isize;
     luaL_Buffer buffer;
     /* end-of-input blackhole */
@@ -548,14 +541,14 @@ static int mime_global_unqp(lua_State *L)
     luaL_buffinit(L, &buffer);
     while (input < last)
         asize = qpdecode(*input++, atom, asize, &buffer);
-    input = (UC *) luaL_optlstring(L, 2, NULL, &isize);
+    input = (const UC *) luaL_optlstring(L, 2, NULL, &isize);
     /* if second part is nil, we are done */
     if (!input) {
         luaL_pushresult(&buffer);
         if (!(*lua_tostring(L, -1))) lua_pushnil(L);
         lua_pushnil(L);
         return 2;
-    } 
+    }
     /* otherwise process rest of input */
     last = input + isize;
     while (input < last)
@@ -568,9 +561,9 @@ static int mime_global_unqp(lua_State *L)
 /*-------------------------------------------------------------------------*\
 * Incrementally breaks a quoted-printed string into lines
 * A, n = qpwrp(l, B, length)
-* A is a copy of B, broken into lines of at most 'length' bytes. 
-* 'l' is how many bytes are left for the first line of B. 
-* 'n' is the number of bytes left in the last line of A. 
+* A is a copy of B, broken into lines of at most 'length' bytes.
+* 'l' is how many bytes are left for the first line of B.
+* 'n' is the number of bytes left in the last line of A.
 * There are two complications: lines can't be broken in the middle
 * of an encoded =XX, and there might be line breaks already
 \*-------------------------------------------------------------------------*/
@@ -578,7 +571,7 @@ static int mime_global_qpwrp(lua_State *L)
 {
     size_t size = 0;
     int left = (int) luaL_checknumber(L, 1);
-    const UC *input = (UC *) luaL_optlstring(L, 2, NULL, &size);
+    const UC *input = (const UC *) luaL_optlstring(L, 2, NULL, &size);
     const UC *last = input + size;
     int length = (int) luaL_optnumber(L, 3, 76);
     luaL_Buffer buffer;
@@ -603,11 +596,11 @@ static int mime_global_qpwrp(lua_State *L)
                 if (left <= 3) {
                     left = length;
                     luaL_addstring(&buffer, EQCRLF);
-                } 
+                }
                 luaL_addchar(&buffer, *input);
                 left--;
                 break;
-            default: 
+            default:
                 if (left <= 1) {
                     left = length;
                     luaL_addstring(&buffer, EQCRLF);
@@ -635,7 +628,7 @@ static int mime_global_qpwrp(lua_State *L)
 * last is the previous character
 \*-------------------------------------------------------------------------*/
 #define eolcandidate(c) (c == '\r' || c == '\n')
-static int eolprocess(int c, int last, const char *marker, 
+static int eolprocess(int c, int last, const char *marker,
         luaL_Buffer *buffer)
 {
     if (eolcandidate(c)) {
@@ -653,15 +646,15 @@ static int eolprocess(int c, int last, const char *marker,
 }
 
 /*-------------------------------------------------------------------------*\
-* Converts a string to uniform EOL convention. 
+* Converts a string to uniform EOL convention.
 * A, n = eol(o, B, marker)
 * A is the converted version of the largest prefix of B that can be
-* converted unambiguously. 'o' is the context returned by the previous 
+* converted unambiguously. 'o' is the context returned by the previous
 * call. 'n' is the new context.
 \*-------------------------------------------------------------------------*/
 static int mime_global_eol(lua_State *L)
 {
-    int ctx = luaL_checkint(L, 1);
+    int ctx = luaL_checkinteger(L, 1);
     size_t isize = 0;
     const char *input = luaL_optlstring(L, 2, NULL, &isize);
     const char *last = input + isize;
@@ -683,18 +676,18 @@ static int mime_global_eol(lua_State *L)
 }
 
 /*-------------------------------------------------------------------------*\
-* Takes one byte and stuff it if needed. 
+* Takes one byte and stuff it if needed.
 \*-------------------------------------------------------------------------*/
 static size_t dot(int c, size_t state, luaL_Buffer *buffer)
 {
     luaL_addchar(buffer, (char) c);
     switch (c) {
-        case '\r': 
+        case '\r':
             return 1;
-        case '\n': 
-            return (state == 1)? 2: 0; 
-        case '.':  
-            if (state == 2) 
+        case '\n':
+            return (state == 1)? 2: 0;
+        case '.':
+            if (state == 2)
                 luaL_addchar(buffer, '.');
         default:
             return 0;
@@ -719,7 +712,7 @@ static int mime_global_dot(lua_State *L)
     }
     /* process all input */
     luaL_buffinit(L, &buffer);
-    while (input < last) 
+    while (input < last)
         state = dot(*input++, state, &buffer);
     luaL_pushresult(&buffer);
     lua_pushnumber(L, (lua_Number) state);
diff --git a/src/options.c b/src/options.c
index 8ac2a14..20f4c28 100644
--- a/src/options.c
+++ b/src/options.c
@@ -1,8 +1,8 @@
 /*=========================================================================*\
-* Common option interface 
+* Common option interface
 * LuaSocket toolkit
 \*=========================================================================*/
-#include <string.h> 
+#include <string.h>
 
 #include "lauxlib.h"
 
@@ -20,9 +20,9 @@ static int opt_setboolean(lua_State *L, p_socket ps, int level, int name);
 static int opt_getboolean(lua_State *L, p_socket ps, int level, int name);
 static int opt_setint(lua_State *L, p_socket ps, int level, int name);
 static int opt_getint(lua_State *L, p_socket ps, int level, int name);
-static int opt_set(lua_State *L, p_socket ps, int level, int name, 
+static int opt_set(lua_State *L, p_socket ps, int level, int name,
         void *val, int len);
-static int opt_get(lua_State *L, p_socket ps, int level, int name, 
+static int opt_get(lua_State *L, p_socket ps, int level, int name,
         void *val, int* len);
 
 /*=========================================================================*\
@@ -60,29 +60,29 @@ int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps)
 /* enables reuse of local address */
 int opt_set_reuseaddr(lua_State *L, p_socket ps)
 {
-    return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); 
+    return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
 }
 
 int opt_get_reuseaddr(lua_State *L, p_socket ps)
 {
-    return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR); 
+    return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEADDR);
 }
 
 /* enables reuse of local port */
 int opt_set_reuseport(lua_State *L, p_socket ps)
 {
-    return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); 
+    return opt_setboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
 }
 
 int opt_get_reuseport(lua_State *L, p_socket ps)
 {
-    return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT); 
+    return opt_getboolean(L, ps, SOL_SOCKET, SO_REUSEPORT);
 }
 
 /* disables the Naggle algorithm */
 int opt_set_tcp_nodelay(lua_State *L, p_socket ps)
 {
-    return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY); 
+    return opt_setboolean(L, ps, IPPROTO_TCP, TCP_NODELAY);
 }
 
 int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
@@ -92,12 +92,12 @@ int opt_get_tcp_nodelay(lua_State *L, p_socket ps)
 
 int opt_set_keepalive(lua_State *L, p_socket ps)
 {
-    return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); 
+    return opt_setboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
 }
 
 int opt_get_keepalive(lua_State *L, p_socket ps)
 {
-    return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE); 
+    return opt_getboolean(L, ps, SOL_SOCKET, SO_KEEPALIVE);
 }
 
 int opt_set_dontroute(lua_State *L, p_socket ps)
@@ -105,11 +105,21 @@ int opt_set_dontroute(lua_State *L, p_socket ps)
     return opt_setboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
 }
 
+int opt_get_dontroute(lua_State *L, p_socket ps)
+{
+    return opt_getboolean(L, ps, SOL_SOCKET, SO_DONTROUTE);
+}
+
 int opt_set_broadcast(lua_State *L, p_socket ps)
 {
     return opt_setboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
 }
 
+int opt_get_broadcast(lua_State *L, p_socket ps)
+{
+    return opt_getboolean(L, ps, SOL_SOCKET, SO_BROADCAST);
+}
+
 int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps)
 {
   return opt_setint(L, ps, IPPROTO_IPV6, IPV6_UNICAST_HOPS);
@@ -156,12 +166,12 @@ int opt_set_linger(lua_State *L, p_socket ps)
     if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
     lua_pushstring(L, "on");
     lua_gettable(L, 3);
-    if (!lua_isboolean(L, -1)) 
+    if (!lua_isboolean(L, -1))
         luaL_argerror(L, 3, "boolean 'on' field expected");
     li.l_onoff = (u_short) lua_toboolean(L, -1);
     lua_pushstring(L, "timeout");
     lua_gettable(L, 3);
-    if (!lua_isnumber(L, -1)) 
+    if (!lua_isnumber(L, -1))
         luaL_argerror(L, 3, "number 'timeout' field expected");
     li.l_linger = (u_short) lua_tonumber(L, -1);
     return opt_set(L, ps, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof(li));
@@ -194,7 +204,7 @@ int opt_set_ip_multicast_if(lua_State *L, p_socket ps)
     val.s_addr = htonl(INADDR_ANY);
     if (strcmp(address, "*") && !inet_aton(address, &val))
         luaL_argerror(L, 3, "ip expected");
-    return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF, 
+    return opt_set(L, ps, IPPROTO_IP, IP_MULTICAST_IF,
         (char *) &val, sizeof(val));
 }
 
@@ -250,17 +260,17 @@ static int opt_setmembership(lua_State *L, p_socket ps, int level, int name)
     if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
     lua_pushstring(L, "multiaddr");
     lua_gettable(L, 3);
-    if (!lua_isstring(L, -1)) 
+    if (!lua_isstring(L, -1))
         luaL_argerror(L, 3, "string 'multiaddr' field expected");
-    if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr)) 
+    if (!inet_aton(lua_tostring(L, -1), &val.imr_multiaddr))
         luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
     lua_pushstring(L, "interface");
     lua_gettable(L, 3);
-    if (!lua_isstring(L, -1)) 
+    if (!lua_isstring(L, -1))
         luaL_argerror(L, 3, "string 'interface' field expected");
     val.imr_interface.s_addr = htonl(INADDR_ANY);
     if (strcmp(lua_tostring(L, -1), "*") &&
-            !inet_aton(lua_tostring(L, -1), &val.imr_interface)) 
+            !inet_aton(lua_tostring(L, -1), &val.imr_interface))
         luaL_argerror(L, 3, "invalid 'interface' ip address");
     return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
 }
@@ -272,14 +282,14 @@ static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name)
     if (!lua_istable(L, 3)) auxiliar_typeerror(L,3,lua_typename(L, LUA_TTABLE));
     lua_pushstring(L, "multiaddr");
     lua_gettable(L, 3);
-    if (!lua_isstring(L, -1)) 
+    if (!lua_isstring(L, -1))
         luaL_argerror(L, 3, "string 'multiaddr' field expected");
-    if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr)) 
+    if (!inet_pton(AF_INET6, lua_tostring(L, -1), &val.ipv6mr_multiaddr))
         luaL_argerror(L, 3, "invalid 'multiaddr' ip address");
     lua_pushstring(L, "interface");
     lua_gettable(L, 3);
     /* By default we listen to interface on default route
-     * (sigh). However, interface= can override it. We should 
+     * (sigh). However, interface= can override it. We should
      * support either number, or name for it. Waiting for
      * windows port of if_nametoindex */
     if (!lua_isnil(L, -1)) {
@@ -291,7 +301,7 @@ static int opt_ip6_setmembership(lua_State *L, p_socket ps, int level, int name)
     return opt_set(L, ps, level, name, (char *) &val, sizeof(val));
 }
 
-static 
+static
 int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
 {
     socklen_t socklen = *len;
@@ -304,7 +314,7 @@ int opt_get(lua_State *L, p_socket ps, int level, int name, void *val, int* len)
     return 0;
 }
 
-static 
+static
 int opt_set(lua_State *L, p_socket ps, int level, int name, void *val, int len)
 {
     if (setsockopt(*ps, level, name, (char *) val, len) < 0) {
diff --git a/src/options.h b/src/options.h
index 5657a06..19ba0df 100644
--- a/src/options.h
+++ b/src/options.h
@@ -21,7 +21,6 @@ typedef t_opt *p_opt;
 /* supported options for setoption */
 int opt_set_dontroute(lua_State *L, p_socket ps);
 int opt_set_broadcast(lua_State *L, p_socket ps);
-int opt_set_reuseaddr(lua_State *L, p_socket ps);
 int opt_set_tcp_nodelay(lua_State *L, p_socket ps);
 int opt_set_keepalive(lua_State *L, p_socket ps);
 int opt_set_linger(lua_State *L, p_socket ps);
@@ -40,18 +39,21 @@ int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps);
 int opt_set_ip6_v6only(lua_State *L, p_socket ps);
 
 /* supported options for getoption */
+int opt_get_dontroute(lua_State *L, p_socket ps);
+int opt_get_broadcast(lua_State *L, p_socket ps);
 int opt_get_reuseaddr(lua_State *L, p_socket ps);
+int opt_get_reuseport(lua_State *L, p_socket ps);
 int opt_get_tcp_nodelay(lua_State *L, p_socket ps);
 int opt_get_keepalive(lua_State *L, p_socket ps);
 int opt_get_linger(lua_State *L, p_socket ps);
-int opt_get_reuseaddr(lua_State *L, p_socket ps);
 int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
 int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
 int opt_get_error(lua_State *L, p_socket ps);
 int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps);
 int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps);
 int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps);
-int opt_get_ip6_v6only(lua_State *L, p_socket ps); 
+int opt_get_ip6_v6only(lua_State *L, p_socket ps);
+int opt_get_reuseport(lua_State *L, p_socket ps);
 
 /* invokes the appropriate option handler */
 int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
diff --git a/src/pierror.h b/src/pierror.h
new file mode 100644
index 0000000..cb773ab
--- /dev/null
+++ b/src/pierror.h
@@ -0,0 +1,28 @@
+#ifndef PIERROR_H
+#define PIERROR_H
+/*=========================================================================*\
+* Error messages
+* Defines platform independent error messages
+\*=========================================================================*/
+
+#define PIE_HOST_NOT_FOUND "host not found"
+#define PIE_ADDRINUSE      "address already in use"
+#define PIE_ISCONN         "already connected"
+#define PIE_ACCESS         "permission denied"
+#define PIE_CONNREFUSED    "connection refused"
+#define PIE_CONNABORTED    "closed"
+#define PIE_CONNRESET      "closed"
+#define PIE_TIMEDOUT       "timeout"
+#define PIE_AGAIN          "temporary failure in name resolution"
+#define PIE_BADFLAGS       "invalid value for ai_flags"
+#define PIE_BADHINTS       "invalid value for hints"
+#define PIE_FAIL           "non-recoverable failure in name resolution"
+#define PIE_FAMILY         "ai_family not supported"
+#define PIE_MEMORY         "memory allocation failure"
+#define PIE_NONAME         "host or service not provided, or not known"
+#define PIE_OVERFLOW       "argument buffer overflow"
+#define PIE_PROTOCOL       "resolved protocol is unknown"
+#define PIE_SERVICE        "service not supported for socket type"
+#define PIE_SOCKTYPE       "ai_socktype not supported"
+
+#endif
diff --git a/src/select.c b/src/select.c
index fafaa62..9d133b7 100644
--- a/src/select.c
+++ b/src/select.c
@@ -6,6 +6,7 @@
 
 #include "lua.h"
 #include "lauxlib.h"
+#include "compat.h"
 
 #include "socket.h"
 #include "timeout.h"
@@ -16,10 +17,10 @@
 \*=========================================================================*/
 static t_socket getfd(lua_State *L);
 static int dirty(lua_State *L);
-static void collect_fd(lua_State *L, int tab, int itab, 
+static void collect_fd(lua_State *L, int tab, int itab,
         fd_set *set, t_socket *max_fd);
 static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set);
-static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, 
+static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
         int itab, int tab, int start);
 static void make_assoc(lua_State *L, int tab);
 static int global_select(lua_State *L);
@@ -38,13 +39,12 @@ static luaL_Reg func[] = {
 \*-------------------------------------------------------------------------*/
 int select_open(lua_State *L) {
     lua_pushstring(L, "_SETSIZE");
-    lua_pushnumber(L, FD_SETSIZE);
+    lua_pushinteger(L, FD_SETSIZE);
+    lua_rawset(L, -3);
+    lua_pushstring(L, "_SOCKETINVALID");
+    lua_pushinteger(L, SOCKET_INVALID);
     lua_rawset(L, -3);
-#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
     luaL_setfuncs(L, func, 0);
-#else
-    luaL_openlib(L, NULL, func, 0);
-#endif
     return 0;
 }
 
@@ -98,10 +98,10 @@ static t_socket getfd(lua_State *L) {
         lua_pushvalue(L, -2);
         lua_call(L, 1, 1);
         if (lua_isnumber(L, -1)) {
-            double numfd = lua_tonumber(L, -1); 
+            double numfd = lua_tonumber(L, -1);
             fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID;
         }
-    } 
+    }
     lua_pop(L, 1);
     return fd;
 }
@@ -114,12 +114,12 @@ static int dirty(lua_State *L) {
         lua_pushvalue(L, -2);
         lua_call(L, 1, 1);
         is = lua_toboolean(L, -1);
-    } 
+    }
     lua_pop(L, 1);
     return is;
 }
 
-static void collect_fd(lua_State *L, int tab, int itab, 
+static void collect_fd(lua_State *L, int tab, int itab,
         fd_set *set, t_socket *max_fd) {
     int i = 1, n = 0;
     /* nil is the same as an empty table */
@@ -139,16 +139,16 @@ static void collect_fd(lua_State *L, int tab, int itab,
         if (fd != SOCKET_INVALID) {
             /* make sure we don't overflow the fd_set */
 #ifdef _WIN32
-            if (n >= FD_SETSIZE) 
+            if (n >= FD_SETSIZE)
                 luaL_argerror(L, tab, "too many sockets");
 #else
-            if (fd >= FD_SETSIZE) 
+            if (fd >= FD_SETSIZE)
                 luaL_argerror(L, tab, "descriptor too large for set size");
 #endif
             FD_SET(fd, set);
             n++;
             /* keep track of the largest descriptor so far */
-            if (*max_fd == SOCKET_INVALID || *max_fd < fd) 
+            if (*max_fd == SOCKET_INVALID || *max_fd < fd)
                 *max_fd = fd;
             /* make sure we can map back from descriptor to the object */
             lua_pushnumber(L, (lua_Number) fd);
@@ -162,9 +162,9 @@ static void collect_fd(lua_State *L, int tab, int itab,
 
 static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
     int ndirty = 0, i = 1;
-    if (lua_isnil(L, tab)) 
+    if (lua_isnil(L, tab))
         return 0;
-    for ( ;; ) { 
+    for ( ;; ) {
         t_socket fd;
         lua_pushnumber(L, i);
         lua_gettable(L, tab);
@@ -185,7 +185,7 @@ static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) {
     return ndirty;
 }
 
-static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, 
+static void return_fd(lua_State *L, fd_set *set, t_socket max_fd,
         int itab, int tab, int start) {
     t_socket fd;
     for (fd = 0; fd < max_fd; fd++) {
diff --git a/src/serial.c b/src/serial.c
index 583d4e5..7bdb21c 100644
--- a/src/serial.c
+++ b/src/serial.c
@@ -2,7 +2,7 @@
 * Serial stream
 * LuaSocket toolkit
 \*=========================================================================*/
-#include <string.h> 
+#include <string.h>
 
 #include "lua.h"
 #include "lauxlib.h"
@@ -11,7 +11,7 @@
 #include "socket.h"
 #include "options.h"
 #include "unix.h"
-#include <sys/un.h> 
+#include <sys/un.h>
 
 /*
 Reuses userdata definition from unix.h, since it is useful for all
@@ -54,15 +54,6 @@ static luaL_Reg serial_methods[] = {
     {NULL,          NULL}
 };
 
-/* our socket creation function */
-/* this is an ad-hoc module that returns a single function 
- * as such, do not include other functions in this array. */
-static luaL_Reg func[] = {
-    {"serial", global_create},
-    {NULL,          NULL}
-};
-
-
 /*-------------------------------------------------------------------------*\
 * Initializes module
 \*-------------------------------------------------------------------------*/
@@ -71,14 +62,7 @@ LUASOCKET_API int luaopen_socket_serial(lua_State *L) {
     auxiliar_newclass(L, "serial{client}", serial_methods);
     /* create class groups */
     auxiliar_add2group(L, "serial{client}", "serial{any}");
-#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
-    lua_pushcfunction(L, global_create);
-    (void) func;
-#else
-    /* set function into socket namespace */
-    luaL_openlib(L, "socket", func, 0);
     lua_pushcfunction(L, global_create);
-#endif
     return 1;
 }
 
@@ -120,7 +104,7 @@ static int meth_getfd(lua_State *L) {
 /* this is very dangerous, but can be handy for those that are brave enough */
 static int meth_setfd(lua_State *L) {
     p_unix un = (p_unix) auxiliar_checkgroup(L, "serial{any}", 1);
-    un->sock = (t_socket) luaL_checknumber(L, 2); 
+    un->sock = (t_socket) luaL_checknumber(L, 2);
     return 0;
 }
 
@@ -131,7 +115,7 @@ static int meth_dirty(lua_State *L) {
 }
 
 /*-------------------------------------------------------------------------*\
-* Closes socket used by object 
+* Closes socket used by object
 \*-------------------------------------------------------------------------*/
 static int meth_close(lua_State *L)
 {
@@ -156,7 +140,7 @@ static int meth_settimeout(lua_State *L) {
 
 
 /*-------------------------------------------------------------------------*\
-* Creates a serial object 
+* Creates a serial object
 \*-------------------------------------------------------------------------*/
 static int global_create(lua_State *L) {
     const char* path = luaL_checkstring(L, 1);
@@ -180,7 +164,7 @@ static int global_create(lua_State *L) {
     /* initialize remaining structure fields */
     socket_setnonblocking(&sock);
     un->sock = sock;
-    io_init(&un->io, (p_send) socket_write, (p_recv) socket_read, 
+    io_init(&un->io, (p_send) socket_write, (p_recv) socket_read,
             (p_error) socket_ioerror, &un->sock);
     timeout_init(&un->tm, -1, -1);
     buffer_init(&un->buf, &un->io, &un->tm);
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)
     err = "no info on address"
     for i, alt in base.ipairs(addrinfo) do
         if alt.family == "inet" then
-            sock, err = socket.tcp()
+            sock, err = socket.tcp4()
         else
             sock, err = socket.tcp6()
         end
         if not sock then return nil, err end
         sock:setoption("reuseaddr", true)
         res, err = sock:bind(alt.addr, port)
-        if not res then 
+        if not res then
             sock:close()
-        else 
+        else
             res, err = sock:listen(backlog)
-            if not res then 
+            if not res then
                 sock:close()
             else
                 return sock
             end
-        end 
+        end
     end
     return nil, err
 end
diff --git a/src/tcp.c b/src/tcp.c
index 6594bda..ef9ee6f 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -6,6 +6,7 @@
 
 #include "lua.h"
 #include "lauxlib.h"
+#include "compat.h"
 
 #include "auxiliar.h"
 #include "socket.h"
@@ -17,6 +18,7 @@
 * Internal function prototypes
 \*=========================================================================*/
 static int global_create(lua_State *L);
+static int global_create4(lua_State *L);
 static int global_create6(lua_State *L);
 static int global_connect(lua_State *L);
 static int meth_connect(lua_State *L);
@@ -34,6 +36,7 @@ static int meth_accept(lua_State *L);
 static int meth_close(lua_State *L);
 static int meth_getoption(lua_State *L);
 static int meth_setoption(lua_State *L);
+static int meth_gettimeout(lua_State *L);
 static int meth_settimeout(lua_State *L);
 static int meth_getfd(lua_State *L);
 static int meth_setfd(lua_State *L);
@@ -63,6 +66,7 @@ static luaL_Reg tcp_methods[] = {
     {"setpeername", meth_connect},
     {"setsockname", meth_bind},
     {"settimeout",  meth_settimeout},
+    {"gettimeout",  meth_gettimeout},
     {"shutdown",    meth_shutdown},
     {NULL,          NULL}
 };
@@ -71,6 +75,7 @@ static luaL_Reg tcp_methods[] = {
 static t_opt optget[] = {
     {"keepalive",   opt_get_keepalive},
     {"reuseaddr",   opt_get_reuseaddr},
+    {"reuseport",   opt_get_reuseport},
     {"tcp-nodelay", opt_get_tcp_nodelay},
     {"linger",      opt_get_linger},
     {"error",       opt_get_error},
@@ -80,6 +85,7 @@ static t_opt optget[] = {
 static t_opt optset[] = {
     {"keepalive",   opt_set_keepalive},
     {"reuseaddr",   opt_set_reuseaddr},
+    {"reuseport",   opt_set_reuseport},
     {"tcp-nodelay", opt_set_tcp_nodelay},
     {"ipv6-v6only", opt_set_ip6_v6only},
     {"linger",      opt_set_linger},
@@ -89,6 +95,7 @@ static t_opt optset[] = {
 /* functions in library namespace */
 static luaL_Reg func[] = {
     {"tcp", global_create},
+    {"tcp4", global_create4},
     {"tcp6", global_create6},
     {"connect", global_connect},
     {NULL, NULL}
@@ -108,11 +115,7 @@ int tcp_open(lua_State *L)
     auxiliar_add2group(L, "tcp{client}", "tcp{any}");
     auxiliar_add2group(L, "tcp{server}", "tcp{any}");
     /* define library functions */
-#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
     luaL_setfuncs(L, func, 0);
-#else
-    luaL_openlib(L, NULL, func, 0);
-#endif
     return 0;
 }
 
@@ -216,8 +219,7 @@ static int meth_accept(lua_State *L)
 /*-------------------------------------------------------------------------*\
 * Binds an object to an address
 \*-------------------------------------------------------------------------*/
-static int meth_bind(lua_State *L)
-{
+static int meth_bind(lua_State *L) {
     p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
     const char *address =  luaL_checkstring(L, 2);
     const char *port = luaL_checkstring(L, 3);
@@ -227,7 +229,7 @@ static int meth_bind(lua_State *L)
     bindhints.ai_socktype = SOCK_STREAM;
     bindhints.ai_family = tcp->family;
     bindhints.ai_flags = AI_PASSIVE;
-    err = inet_trybind(&tcp->sock, address, port, &bindhints);
+    err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints);
     if (err) {
         lua_pushnil(L);
         lua_pushstring(L, err);
@@ -240,8 +242,7 @@ static int meth_bind(lua_State *L)
 /*-------------------------------------------------------------------------*\
 * Turns a master tcp object into a client object.
 \*-------------------------------------------------------------------------*/
-static int meth_connect(lua_State *L)
-{
+static int meth_connect(lua_State *L) {
     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
     const char *address =  luaL_checkstring(L, 2);
     const char *port = luaL_checkstring(L, 3);
@@ -252,7 +253,7 @@ static int meth_connect(lua_State *L)
     /* make sure we try to connect only to the same family */
     connecthints.ai_family = tcp->family;
     timeout_markstart(&tcp->tm);
-    err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, 
+    err = inet_tryconnect(&tcp->sock, &tcp->family, address, port,
         &tcp->tm, &connecthints);
     /* have to set the class even if it failed due to non-blocking connects */
     auxiliar_setclass(L, "tcp{client}", 1);
@@ -282,9 +283,12 @@ static int meth_close(lua_State *L)
 static int meth_getfamily(lua_State *L)
 {
     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
-    if (tcp->family == PF_INET6) {
+    if (tcp->family == AF_INET6) {
         lua_pushliteral(L, "inet6");
         return 1;
+    } else if (tcp->family == AF_INET) {
+        lua_pushliteral(L, "inet4");
+        return 1;
     } else {
         lua_pushliteral(L, "inet4");
         return 1;
@@ -348,6 +352,12 @@ static int meth_settimeout(lua_State *L)
     return timeout_meth_settimeout(L, &tcp->tm);
 }
 
+static int meth_gettimeout(lua_State *L)
+{
+    p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
+    return timeout_meth_gettimeout(L, &tcp->tm);
+}
+
 /*=========================================================================*\
 * Library functions
 \*=========================================================================*/
@@ -355,37 +365,36 @@ static int meth_settimeout(lua_State *L)
 * Creates a master tcp object
 \*-------------------------------------------------------------------------*/
 static int tcp_create(lua_State *L, int family) {
-    t_socket sock;
-    const char *err = inet_trycreate(&sock, family, SOCK_STREAM);
-    /* try to allocate a system socket */
-    if (!err) {
-        /* allocate tcp object */
-        p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
-        memset(tcp, 0, sizeof(t_tcp));
-        /* set its type as master object */
-        auxiliar_setclass(L, "tcp{master}", -1);
-        /* initialize remaining structure fields */
-        socket_setnonblocking(&sock);
-        if (family == PF_INET6) {
-            int yes = 1;
-            setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
-                (void *)&yes, sizeof(yes));
+    p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
+    memset(tcp, 0, sizeof(t_tcp));
+    /* set its type as master object */
+    auxiliar_setclass(L, "tcp{master}", -1);
+    /* if family is AF_UNSPEC, we leave the socket invalid and
+     * store AF_UNSPEC into family. This will allow it to later be
+     * replaced with an AF_INET6 or AF_INET socket upon first use. */
+    tcp->sock = SOCKET_INVALID;
+    tcp->family = family;
+    io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
+            (p_error) socket_ioerror, &tcp->sock);
+    timeout_init(&tcp->tm, -1, -1);
+    buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
+    if (family != AF_UNSPEC) {
+        const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0);
+        if (err != NULL) {
+            lua_pushnil(L);
+            lua_pushstring(L, err);
+            return 2;
         }
-        tcp->sock = sock;
-        io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
-                (p_error) socket_ioerror, &tcp->sock);
-        timeout_init(&tcp->tm, -1, -1);
-        buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
-        tcp->family = family;
-        return 1;
-    } else {
-        lua_pushnil(L);
-        lua_pushstring(L, err);
-        return 2;
+        socket_setnonblocking(&tcp->sock);
     }
+    return 1;
 }
 
 static int global_create(lua_State *L) {
+    return tcp_create(L, AF_UNSPEC);
+}
+
+static int global_create4(lua_State *L) {
     return tcp_create(L, AF_INET);
 }
 
@@ -393,53 +402,6 @@ static int global_create6(lua_State *L) {
     return tcp_create(L, AF_INET6);
 }
 
-#if 0
-static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
-    struct addrinfo *connecthints, p_tcp tcp) {
-    struct addrinfo *iterator = NULL, *resolved = NULL;
-    const char *err = NULL;
-    /* try resolving */
-    err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv,
-                connecthints, &resolved));
-    if (err != NULL) {
-        if (resolved) freeaddrinfo(resolved);
-        return err;
-    }
-    /* iterate over all returned addresses trying to connect */
-    for (iterator = resolved; iterator; iterator = iterator->ai_next) {
-        p_timeout tm = timeout_markstart(&tcp->tm);
-        /* create new socket if necessary. if there was no
-         * bind, we need to create one for every new family
-         * that shows up while iterating. if there was a
-         * bind, all families will be the same and we will
-         * not enter this branch. */
-        if (tcp->family != iterator->ai_family) {
-            socket_destroy(&tcp->sock);
-            err = socket_strerror(socket_create(&tcp->sock,
-                iterator->ai_family, iterator->ai_socktype,
-                iterator->ai_protocol));
-            if (err != NULL) {
-                freeaddrinfo(resolved);
-                return err;
-            }
-            tcp->family = iterator->ai_family;
-            /* all sockets initially non-blocking */
-            socket_setnonblocking(&tcp->sock);
-        }
-        /* finally try connecting to remote address */
-        err = socket_strerror(socket_connect(&tcp->sock,
-            (SA *) iterator->ai_addr,
-            (socklen_t) iterator->ai_addrlen, tm));
-        /* if success, break out of loop */
-        if (err == NULL) break;
-    }
-
-    freeaddrinfo(resolved);
-    /* here, if err is set, we failed */
-    return err;
-}
-#endif
-
 static int global_connect(lua_State *L) {
     const char *remoteaddr = luaL_checkstring(L, 1);
     const char *remoteserv = luaL_checkstring(L, 2);
@@ -456,26 +418,26 @@ static int global_connect(lua_State *L) {
     timeout_init(&tcp->tm, -1, -1);
     buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
     tcp->sock = SOCKET_INVALID;
-    tcp->family = PF_UNSPEC;
+    tcp->family = AF_UNSPEC;
     /* allow user to pick local address and port */
     memset(&bindhints, 0, sizeof(bindhints));
     bindhints.ai_socktype = SOCK_STREAM;
     bindhints.ai_family = family;
     bindhints.ai_flags = AI_PASSIVE;
     if (localaddr) {
-        err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
+        err = inet_trybind(&tcp->sock, &tcp->family, localaddr,
+            localserv, &bindhints);
         if (err) {
             lua_pushnil(L);
             lua_pushstring(L, err);
             return 2;
         }
-        tcp->family = bindhints.ai_family;
     }
     /* try to connect to remote address and port */
     memset(&connecthints, 0, sizeof(connecthints));
     connecthints.ai_socktype = SOCK_STREAM;
     /* make sure we try to connect only to the same family */
-    connecthints.ai_family = bindhints.ai_family;
+    connecthints.ai_family = tcp->family;
     err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv,
          &tcp->tm, &connecthints);
     if (err) {
diff --git a/src/timeout.c b/src/timeout.c
index bdd5e1c..5a601d5 100644
--- a/src/timeout.c
+++ b/src/timeout.c
@@ -8,6 +8,7 @@
 
 #include "lua.h"
 #include "lauxlib.h"
+#include "compat.h"
 
 #include "auxiliar.h"
 #include "timeout.h"
@@ -52,7 +53,7 @@ void timeout_init(p_timeout tm, double block, double total) {
 
 /*-------------------------------------------------------------------------*\
 * Determines how much time we have left for the next system call,
-* if the previous call was successful 
+* if the previous call was successful
 * Input
 *   tm: timeout control structure
 * Returns
@@ -107,7 +108,7 @@ double timeout_getretry(p_timeout tm) {
 }
 
 /*-------------------------------------------------------------------------*\
-* Marks the operation start time in structure 
+* Marks the operation start time in structure
 * Input
 *   tm: timeout control structure
 \*-------------------------------------------------------------------------*/
@@ -117,7 +118,7 @@ p_timeout timeout_markstart(p_timeout tm) {
 }
 
 /*-------------------------------------------------------------------------*\
-* Gets time in s, relative to January 1, 1970 (UTC) 
+* Gets time in s, relative to January 1, 1970 (UTC)
 * Returns
 *   time in s.
 \*-------------------------------------------------------------------------*/
@@ -144,11 +145,7 @@ double timeout_gettime(void) {
 * Initializes module
 \*-------------------------------------------------------------------------*/
 int timeout_open(lua_State *L) {
-#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
     luaL_setfuncs(L, func, 0);
-#else
-    luaL_openlib(L, NULL, func, 0);
-#endif
     return 0;
 }
 
@@ -163,7 +160,7 @@ int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
     const char *mode = luaL_optstring(L, 3, "b");
     switch (*mode) {
         case 'b':
-            tm->block = t; 
+            tm->block = t;
             break;
         case 'r': case 't':
             tm->total = t;
@@ -176,6 +173,16 @@ int timeout_meth_settimeout(lua_State *L, p_timeout tm) {
     return 1;
 }
 
+/*-------------------------------------------------------------------------*\
+* Gets timeout values for IO operations
+* Lua Output: block, total
+\*-------------------------------------------------------------------------*/
+int timeout_meth_gettimeout(lua_State *L, p_timeout tm) {
+    lua_pushnumber(L, tm->block);
+    lua_pushnumber(L, tm->total);
+    return 2;
+}
+
 /*=========================================================================*\
 * Test support functions
 \*=========================================================================*/
diff --git a/src/timeout.h b/src/timeout.h
index 6715ca7..af90231 100644
--- a/src/timeout.h
+++ b/src/timeout.h
@@ -22,6 +22,7 @@ p_timeout timeout_markstart(p_timeout tm);
 double timeout_getstart(p_timeout tm);
 double timeout_gettime(void);
 int timeout_meth_settimeout(lua_State *L, p_timeout tm);
+int timeout_meth_gettimeout(lua_State *L, p_timeout tm);
 
 #define timeout_iszero(tm)   ((tm)->block == 0.0)
 
diff --git a/src/tp.lua b/src/tp.lua
index cbeff56..328cbab 100644
--- a/src/tp.lua
+++ b/src/tp.lua
@@ -74,7 +74,7 @@ function metat.__index:command(cmd, arg)
 end
 
 function metat.__index:sink(snk, pat)
-    local chunk, err = c:receive(pat)
+    local chunk, err = self.c:receive(pat)
     return snk(chunk, err)
 end
 
diff --git a/src/udp.c b/src/udp.c
index a9f2393..ec97252 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -7,6 +7,7 @@
 
 #include "lua.h"
 #include "lauxlib.h"
+#include "compat.h"
 
 #include "auxiliar.h"
 #include "socket.h"
@@ -26,6 +27,7 @@
 * Internal function prototypes
 \*=========================================================================*/
 static int global_create(lua_State *L);
+static int global_create4(lua_State *L);
 static int global_create6(lua_State *L);
 static int meth_send(lua_State *L);
 static int meth_sendto(lua_State *L);
@@ -34,6 +36,7 @@ static int meth_receivefrom(lua_State *L);
 static int meth_getfamily(lua_State *L);
 static int meth_getsockname(lua_State *L);
 static int meth_getpeername(lua_State *L);
+static int meth_gettimeout(lua_State *L);
 static int meth_setsockname(lua_State *L);
 static int meth_setpeername(lua_State *L);
 static int meth_close(lua_State *L);
@@ -64,6 +67,7 @@ static luaL_Reg udp_methods[] = {
     {"setpeername", meth_setpeername},
     {"setsockname", meth_setsockname},
     {"settimeout",  meth_settimeout},
+    {"gettimeout",  meth_gettimeout},
     {NULL,          NULL}
 };
 
@@ -89,6 +93,10 @@ static t_opt optset[] = {
 
 /* socket options for getoption */
 static t_opt optget[] = {
+    {"dontroute",            opt_get_dontroute},
+    {"broadcast",            opt_get_broadcast},
+    {"reuseaddr",            opt_get_reuseaddr},
+    {"reuseport",            opt_get_reuseport},
     {"ip-multicast-if",      opt_get_ip_multicast_if},
     {"ip-multicast-loop",    opt_get_ip_multicast_loop},
     {"error",                opt_get_error},
@@ -102,6 +110,7 @@ static t_opt optget[] = {
 /* functions in library namespace */
 static luaL_Reg func[] = {
     {"udp", global_create},
+    {"udp4", global_create4},
     {"udp6", global_create6},
     {NULL, NULL}
 };
@@ -109,8 +118,7 @@ static luaL_Reg func[] = {
 /*-------------------------------------------------------------------------*\
 * Initializes module
 \*-------------------------------------------------------------------------*/
-int udp_open(lua_State *L)
-{
+int udp_open(lua_State *L) {
     /* create classes */
     auxiliar_newclass(L, "udp{connected}", udp_methods);
     auxiliar_newclass(L, "udp{unconnected}", udp_methods);
@@ -120,18 +128,18 @@ int udp_open(lua_State *L)
     auxiliar_add2group(L, "udp{connected}",   "select{able}");
     auxiliar_add2group(L, "udp{unconnected}", "select{able}");
     /* define library functions */
-#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
     luaL_setfuncs(L, func, 0);
-#else
-    luaL_openlib(L, NULL, func, 0);
-#endif
+    /* export default UDP size */
+    lua_pushliteral(L, "_DATAGRAMSIZE");
+    lua_pushinteger(L, UDP_DATAGRAMSIZE);
+    lua_rawset(L, -3);
     return 0;
 }
 
 /*=========================================================================*\
 * Lua methods
 \*=========================================================================*/
-const char *udp_strerror(int err) {
+static const char *udp_strerror(int err) {
     /* a 'closed' error on an unconnected means the target address was not
      * accepted by the transport layer */
     if (err == IO_CLOSED) return "refused";
@@ -182,7 +190,7 @@ static int meth_sendto(lua_State *L) {
         return 2;
     }
     timeout_markstart(tm);
-    err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, 
+    err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr,
         (socklen_t) ai->ai_addrlen, tm);
     freeaddrinfo(ai);
     if (err != IO_DONE) {
@@ -199,71 +207,80 @@ static int meth_sendto(lua_State *L) {
 \*-------------------------------------------------------------------------*/
 static int meth_receive(lua_State *L) {
     p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
-    char buffer[UDP_DATAGRAMSIZE];
-    size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
+    char buf[UDP_DATAGRAMSIZE];
+    size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
+    char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
     int err;
     p_timeout tm = &udp->tm;
-    count = MIN(count, sizeof(buffer));
     timeout_markstart(tm);
-    err = socket_recv(&udp->sock, buffer, count, &got, tm);
+    if (!dgram) {
+        lua_pushnil(L);
+        lua_pushliteral(L, "out of memory");
+        return 2;
+    }
+    err = socket_recv(&udp->sock, dgram, wanted, &got, tm);
     /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
-    if (err == IO_CLOSED)
-        err = IO_DONE;
-    if (err != IO_DONE) {
+    if (err != IO_DONE && err != IO_CLOSED) {
         lua_pushnil(L);
         lua_pushstring(L, udp_strerror(err));
+        if (wanted > sizeof(buf)) free(dgram);
         return 2;
     }
-    lua_pushlstring(L, buffer, got);
+    lua_pushlstring(L, dgram, got);
+    if (wanted > sizeof(buf)) free(dgram);
     return 1;
 }
 
 /*-------------------------------------------------------------------------*\
 * Receives data and sender from a UDP socket
 \*-------------------------------------------------------------------------*/
-static int meth_receivefrom(lua_State *L)
-{
+static int meth_receivefrom(lua_State *L) {
     p_udp udp = (p_udp) auxiliar_checkclass(L, "udp{unconnected}", 1);
-    char buffer[UDP_DATAGRAMSIZE];
-    size_t got, count = (size_t) luaL_optnumber(L, 2, sizeof(buffer));
-    int err;
-    p_timeout tm = &udp->tm;
+    char buf[UDP_DATAGRAMSIZE];
+    size_t got, wanted = (size_t) luaL_optnumber(L, 2, sizeof(buf));
+    char *dgram = wanted > sizeof(buf)? (char *) malloc(wanted): buf;
     struct sockaddr_storage addr;
     socklen_t addr_len = sizeof(addr);
     char addrstr[INET6_ADDRSTRLEN];
     char portstr[6];
+    int err;
+    p_timeout tm = &udp->tm;
     timeout_markstart(tm);
-    count = MIN(count, sizeof(buffer));
-    err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, 
+    if (!dgram) {
+        lua_pushnil(L);
+        lua_pushliteral(L, "out of memory");
+        return 2;
+    }
+    err = socket_recvfrom(&udp->sock, dgram, wanted, &got, (SA *) &addr,
             &addr_len, tm);
     /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
-    if (err == IO_CLOSED)
-        err = IO_DONE;
-    if (err != IO_DONE) {
+    if (err != IO_DONE && err != IO_CLOSED) {
         lua_pushnil(L);
         lua_pushstring(L, udp_strerror(err));
+        if (wanted > sizeof(buf)) free(dgram);
         return 2;
     }
-    err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, 
+    err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
         INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV);
 	if (err) {
         lua_pushnil(L);
         lua_pushstring(L, gai_strerror(err));
+        if (wanted > sizeof(buf)) free(dgram);
         return 2;
     }
-    lua_pushlstring(L, buffer, got);
+    lua_pushlstring(L, dgram, got);
     lua_pushstring(L, addrstr);
     lua_pushinteger(L, (int) strtol(portstr, (char **) NULL, 10));
+    if (wanted > sizeof(buf)) free(dgram);
     return 3;
 }
 
 /*-------------------------------------------------------------------------*\
 * Returns family as string
 \*-------------------------------------------------------------------------*/
-static int meth_getfamily(lua_State *L)
-{
+static int meth_getfamily(lua_State *L) {
     p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
-    if (udp->family == PF_INET6) {
+    if (udp->family == AF_INET6) {
         lua_pushliteral(L, "inet6");
         return 1;
     } else {
@@ -332,6 +349,11 @@ static int meth_settimeout(lua_State *L) {
     return timeout_meth_settimeout(L, &udp->tm);
 }
 
+static int meth_gettimeout(lua_State *L) {
+    p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
+    return timeout_meth_gettimeout(L, &udp->tm);
+}
+
 /*-------------------------------------------------------------------------*\
 * Turns a master udp object into a client object.
 \*-------------------------------------------------------------------------*/
@@ -348,7 +370,7 @@ static int meth_setpeername(lua_State *L) {
     /* make sure we try to connect only to the same family */
     connecthints.ai_family = udp->family;
     if (connecting) {
-        err = inet_tryconnect(&udp->sock, &udp->family, address, 
+        err = inet_tryconnect(&udp->sock, &udp->family, address,
             port, tm, &connecthints);
         if (err) {
             lua_pushnil(L);
@@ -362,7 +384,6 @@ static int meth_setpeername(lua_State *L) {
         inet_trydisconnect(&udp->sock, udp->family, tm);
         auxiliar_setclass(L, "udp{unconnected}", 1);
     }
-    /* change class to connected or unconnected depending on address */
     lua_pushnumber(L, 1);
     return 1;
 }
@@ -390,7 +411,7 @@ static int meth_setsockname(lua_State *L) {
     bindhints.ai_socktype = SOCK_DGRAM;
     bindhints.ai_family = udp->family;
     bindhints.ai_flags = AI_PASSIVE;
-    err = inet_trybind(&udp->sock, address, port, &bindhints);
+    err = inet_trybind(&udp->sock, &udp->family, address, port, &bindhints);
     if (err) {
         lua_pushnil(L);
         lua_pushstring(L, err);
@@ -407,32 +428,32 @@ static int meth_setsockname(lua_State *L) {
 * Creates a master udp object
 \*-------------------------------------------------------------------------*/
 static int udp_create(lua_State *L, int family) {
-    t_socket sock;
-    const char *err = inet_trycreate(&sock, family, SOCK_DGRAM);
-    /* try to allocate a system socket */
-    if (!err) {
-        /* allocate udp object */
-        p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
-        auxiliar_setclass(L, "udp{unconnected}", -1);
-        /* initialize remaining structure fields */
-        socket_setnonblocking(&sock);
-        if (family == PF_INET6) {
-            int yes = 1;
-            setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
-                (void *)&yes, sizeof(yes));
+    /* allocate udp object */
+    p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
+    auxiliar_setclass(L, "udp{unconnected}", -1);
+    /* if family is AF_UNSPEC, we leave the socket invalid and
+     * store AF_UNSPEC into family. This will allow it to later be
+     * replaced with an AF_INET6 or AF_INET socket upon first use. */
+    udp->sock = SOCKET_INVALID;
+    timeout_init(&udp->tm, -1, -1);
+    udp->family = family;
+    if (family != AF_UNSPEC) {
+        const char *err = inet_trycreate(&udp->sock, family, SOCK_DGRAM, 0);
+        if (err != NULL) {
+            lua_pushnil(L);
+            lua_pushstring(L, err);
+            return 2;
         }
-        udp->sock = sock;
-        timeout_init(&udp->tm, -1, -1);
-        udp->family = family;
-        return 1;
-    } else {
-        lua_pushnil(L);
-        lua_pushstring(L, err);
-        return 2;
+        socket_setnonblocking(&udp->sock);
     }
+    return 1;
 }
 
 static int global_create(lua_State *L) {
+    return udp_create(L, AF_UNSPEC);
+}
+
+static int global_create4(lua_State *L) {
     return udp_create(L, AF_INET);
 }
 
diff --git a/src/udp.h b/src/udp.h
index 2b831a5..be9b6a5 100644
--- a/src/udp.h
+++ b/src/udp.h
@@ -8,7 +8,7 @@
 * (AF_INET, SOCK_DGRAM).
 *
 * Two classes are defined: connected and unconnected. UDP objects are
-* originally unconnected. They can be "connected" to a given address 
+* originally unconnected. They can be "connected" to a given address
 * with a call to the setpeername function. The same function can be used to
 * break the connection.
 \*=========================================================================*/
@@ -17,7 +17,6 @@
 #include "timeout.h"
 #include "socket.h"
 
-/* can't be larger than wsocket.c MAXCHUNK!!! */
 #define UDP_DATAGRAMSIZE 8192
 
 typedef struct t_udp_ {
diff --git a/src/unix.c b/src/unix.c
index 91aaaf8..5bc3148 100644
--- a/src/unix.c
+++ b/src/unix.c
@@ -1,8 +1,8 @@
 /*=========================================================================*\
-* Unix domain socket 
+* Unix domain socket
 * LuaSocket toolkit
 \*=========================================================================*/
-#include <string.h> 
+#include <string.h>
 
 #include "lua.h"
 #include "lauxlib.h"
@@ -11,7 +11,7 @@
 #include "socket.h"
 #include "options.h"
 #include "unix.h"
-#include <sys/un.h> 
+#include <sys/un.h>
 
 /*=========================================================================*\
 * Internal function prototypes
@@ -68,15 +68,6 @@ static t_opt optset[] = {
     {NULL,          NULL}
 };
 
-/* our socket creation function */
-/* this is an ad-hoc module that returns a single function 
- * as such, do not include other functions in this array. */
-static luaL_Reg func[] = {
-    {"unix", global_create},
-    {NULL,          NULL}
-};
-
-
 /*-------------------------------------------------------------------------*\
 * Initializes module
 \*-------------------------------------------------------------------------*/
@@ -89,15 +80,8 @@ int luaopen_socket_unix(lua_State *L) {
     auxiliar_add2group(L, "unix{master}", "unix{any}");
     auxiliar_add2group(L, "unix{client}", "unix{any}");
     auxiliar_add2group(L, "unix{server}", "unix{any}");
-#if LUA_VERSION_NUM > 501 && !defined(LUA_COMPAT_MODULE)
-    lua_pushcfunction(L, global_create);
-    (void) func;
-#else
-    /* set function into socket namespace */
-    luaL_openlib(L, "socket", func, 0);
-    lua_pushcfunction(L, global_create);
-#endif
     /* return the function instead of the 'socket' table */
+    lua_pushcfunction(L, global_create);
     return 1;
 }
 
@@ -147,7 +131,7 @@ static int meth_getfd(lua_State *L) {
 /* this is very dangerous, but can be handy for those that are brave enough */
 static int meth_setfd(lua_State *L) {
     p_unix un = (p_unix) auxiliar_checkgroup(L, "unix{any}", 1);
-    un->sock = (t_socket) luaL_checknumber(L, 2); 
+    un->sock = (t_socket) luaL_checknumber(L, 2);
     return 0;
 }
 
@@ -158,8 +142,8 @@ static int meth_dirty(lua_State *L) {
 }
 
 /*-------------------------------------------------------------------------*\
-* Waits for and returns a client object attempting connection to the 
-* server object 
+* Waits for and returns a client object attempting connection to the
+* server object
 \*-------------------------------------------------------------------------*/
 static int meth_accept(lua_State *L) {
     p_unix server = (p_unix) auxiliar_checkclass(L, "unix{server}", 1);
@@ -173,20 +157,20 @@ static int meth_accept(lua_State *L) {
         /* initialize structure fields */
         socket_setnonblocking(&sock);
         clnt->sock = sock;
-        io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv, 
+        io_init(&clnt->io, (p_send)socket_send, (p_recv)socket_recv,
                 (p_error) socket_ioerror, &clnt->sock);
         timeout_init(&clnt->tm, -1, -1);
         buffer_init(&clnt->buf, &clnt->io, &clnt->tm);
         return 1;
     } else {
-        lua_pushnil(L); 
+        lua_pushnil(L);
         lua_pushstring(L, socket_strerror(err));
         return 2;
     }
 }
 
 /*-------------------------------------------------------------------------*\
-* Binds an object to an address 
+* Binds an object to an address
 \*-------------------------------------------------------------------------*/
 static const char *unix_trybind(p_unix un, const char *path) {
     struct sockaddr_un local;
@@ -197,16 +181,16 @@ static const char *unix_trybind(p_unix un, const char *path) {
     strcpy(local.sun_path, path);
     local.sun_family = AF_UNIX;
 #ifdef UNIX_HAS_SUN_LEN
-    local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len) 
+    local.sun_len = sizeof(local.sun_family) + sizeof(local.sun_len)
         + len + 1;
     err = socket_bind(&un->sock, (SA *) &local, local.sun_len);
 
-#else 
-    err = socket_bind(&un->sock, (SA *) &local, 
+#else
+    err = socket_bind(&un->sock, (SA *) &local,
             sizeof(local.sun_family) + len);
 #endif
     if (err != IO_DONE) socket_destroy(&un->sock);
-    return socket_strerror(err); 
+    return socket_strerror(err);
 }
 
 static int meth_bind(lua_State *L) {
@@ -236,11 +220,11 @@ static const char *unix_tryconnect(p_unix un, const char *path)
     remote.sun_family = AF_UNIX;
     timeout_markstart(&un->tm);
 #ifdef UNIX_HAS_SUN_LEN
-    remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len) 
+    remote.sun_len = sizeof(remote.sun_family) + sizeof(remote.sun_len)
         + len + 1;
     err = socket_connect(&un->sock, (SA *) &remote, remote.sun_len, &un->tm);
 #else
-    err = socket_connect(&un->sock, (SA *) &remote, 
+    err = socket_connect(&un->sock, (SA *) &remote,
             sizeof(remote.sun_family) + len, &un->tm);
 #endif
     if (err != IO_DONE) socket_destroy(&un->sock);
@@ -264,7 +248,7 @@ static int meth_connect(lua_State *L)
 }
 
 /*-------------------------------------------------------------------------*\
-* Closes socket used by object 
+* Closes socket used by object
 \*-------------------------------------------------------------------------*/
 static int meth_close(lua_State *L)
 {
@@ -319,13 +303,13 @@ static int meth_settimeout(lua_State *L) {
 * Library functions
 \*=========================================================================*/
 /*-------------------------------------------------------------------------*\
-* Creates a master unix object 
+* Creates a master unix object
 \*-------------------------------------------------------------------------*/
 static int global_create(lua_State *L) {
     t_socket sock;
     int err = socket_create(&sock, AF_UNIX, SOCK_STREAM, 0);
     /* try to allocate a system socket */
-    if (err == IO_DONE) { 
+    if (err == IO_DONE) {
         /* allocate unix object */
         p_unix un = (p_unix) lua_newuserdata(L, sizeof(t_unix));
         /* set its type as master object */
@@ -333,7 +317,7 @@ static int global_create(lua_State *L) {
         /* initialize remaining structure fields */
         socket_setnonblocking(&sock);
         un->sock = sock;
-        io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv, 
+        io_init(&un->io, (p_send) socket_send, (p_recv) socket_recv,
                 (p_error) socket_ioerror, &un->sock);
         timeout_init(&un->tm, -1, -1);
         buffer_init(&un->buf, &un->io, &un->tm);
diff --git a/src/url.lua b/src/url.lua
index 7809535..fbd93d1 100644
--- a/src/url.lua
+++ b/src/url.lua
@@ -219,6 +219,7 @@ end
 --   corresponding absolute url
 -----------------------------------------------------------------------------
 function _M.absolute(base_url, relative_url)
+    local base_parsed
     if base.type(base_url) == "table" then
         base_parsed = base_url
         base_url = _M.build(base_parsed)
diff --git a/src/usocket.c b/src/usocket.c
index 096ecd0..8adc573 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -4,12 +4,13 @@
 *
 * The code is now interrupt-safe.
 * The penalty of calling select to avoid busy-wait is only paid when
-* the I/O call fail in the first place. 
+* the I/O call fail in the first place.
 \*=========================================================================*/
-#include <string.h> 
+#include <string.h>
 #include <signal.h>
 
 #include "socket.h"
+#include "pierror.h"
 
 /*-------------------------------------------------------------------------*\
 * Wait for readable/writable/connected socket with timeout
@@ -72,7 +73,7 @@ int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
 
 
 /*-------------------------------------------------------------------------*\
-* Initializes module 
+* Initializes module
 \*-------------------------------------------------------------------------*/
 int socket_open(void) {
     /* instals a handler to ignore sigpipe or it will crash us */
@@ -81,7 +82,7 @@ int socket_open(void) {
 }
 
 /*-------------------------------------------------------------------------*\
-* Close module 
+* Close module
 \*-------------------------------------------------------------------------*/
 int socket_close(void) {
     return 1;
@@ -92,7 +93,6 @@ int socket_close(void) {
 \*-------------------------------------------------------------------------*/
 void socket_destroy(p_socket ps) {
     if (*ps != SOCKET_INVALID) {
-        socket_setblocking(ps);
         close(*ps);
         *ps = SOCKET_INVALID;
     }
@@ -101,7 +101,7 @@ void socket_destroy(p_socket ps) {
 /*-------------------------------------------------------------------------*\
 * Select with timeout control
 \*-------------------------------------------------------------------------*/
-int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, 
+int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
         p_timeout tm) {
     int ret;
     do {
@@ -120,8 +120,8 @@ int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
 \*-------------------------------------------------------------------------*/
 int socket_create(p_socket ps, int domain, int type, int protocol) {
     *ps = socket(domain, type, protocol);
-    if (*ps != SOCKET_INVALID) return IO_DONE; 
-    else return errno; 
+    if (*ps != SOCKET_INVALID) return IO_DONE;
+    else return errno;
 }
 
 /*-------------------------------------------------------------------------*\
@@ -130,29 +130,25 @@ int socket_create(p_socket ps, int domain, int type, int protocol) {
 int socket_bind(p_socket ps, SA *addr, socklen_t len) {
     int err = IO_DONE;
     socket_setblocking(ps);
-    if (bind(*ps, addr, len) < 0) err = errno; 
+    if (bind(*ps, addr, len) < 0) err = errno;
     socket_setnonblocking(ps);
     return err;
 }
 
 /*-------------------------------------------------------------------------*\
-* 
+*
 \*-------------------------------------------------------------------------*/
 int socket_listen(p_socket ps, int backlog) {
-    int err = IO_DONE; 
-    socket_setblocking(ps);
-    if (listen(*ps, backlog)) err = errno; 
-    socket_setnonblocking(ps);
+    int err = IO_DONE;
+    if (listen(*ps, backlog)) err = errno;
     return err;
 }
 
 /*-------------------------------------------------------------------------*\
-* 
+*
 \*-------------------------------------------------------------------------*/
 void socket_shutdown(p_socket ps, int how) {
-    socket_setblocking(ps);
     shutdown(*ps, how);
-    socket_setnonblocking(ps);
 }
 
 /*-------------------------------------------------------------------------*\
@@ -166,7 +162,7 @@ int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
     do if (connect(*ps, addr, len) == 0) return IO_DONE;
     while ((err = errno) == EINTR);
     /* if connection failed immediately, return error code */
-    if (err != EINPROGRESS && err != EAGAIN) return err; 
+    if (err != EINPROGRESS && err != EAGAIN) return err;
     /* zero timeout case optimization */
     if (timeout_iszero(tm)) return IO_TIMEOUT;
     /* wait until we have the result of the connection attempt or timeout */
@@ -181,7 +177,7 @@ int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
 * Accept with timeout
 \*-------------------------------------------------------------------------*/
 int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout tm) {
-    if (*ps == SOCKET_INVALID) return IO_CLOSED; 
+    if (*ps == SOCKET_INVALID) return IO_CLOSED;
     for ( ;; ) {
         int err;
         if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
@@ -197,7 +193,7 @@ int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, p_timeout
 /*-------------------------------------------------------------------------*\
 * Send with timeout
 \*-------------------------------------------------------------------------*/
-int socket_send(p_socket ps, const char *data, size_t count, 
+int socket_send(p_socket ps, const char *data, size_t count,
         size_t *sent, p_timeout tm)
 {
     int err;
@@ -215,6 +211,8 @@ int socket_send(p_socket ps, const char *data, size_t count,
         err = errno;
         /* EPIPE means the connection was closed */
         if (err == EPIPE) return IO_CLOSED;
+        /* EPROTOTYPE means the connection is being closed (on Yosemite!)*/
+        if (err == EPROTOTYPE) continue;
         /* we call was interrupted, just try again */
         if (err == EINTR) continue;
         /* if failed fatal reason, report error */
@@ -229,20 +227,21 @@ int socket_send(p_socket ps, const char *data, size_t count,
 /*-------------------------------------------------------------------------*\
 * Sendto with timeout
 \*-------------------------------------------------------------------------*/
-int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, 
+int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
         SA *addr, socklen_t len, p_timeout tm)
 {
     int err;
     *sent = 0;
     if (*ps == SOCKET_INVALID) return IO_CLOSED;
     for ( ;; ) {
-        long put = (long) sendto(*ps, data, count, 0, addr, len);  
+        long put = (long) sendto(*ps, data, count, 0, addr, len); 
         if (put >= 0) {
             *sent = put;
             return IO_DONE;
         }
         err = errno;
         if (err == EPIPE) return IO_CLOSED;
+        if (err == EPROTOTYPE) continue;
         if (err == EINTR) continue;
         if (err != EAGAIN) return err;
         if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
@@ -266,8 +265,8 @@ int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm
         err = errno;
         if (taken == 0) return IO_CLOSED;
         if (err == EINTR) continue;
-        if (err != EAGAIN) return err; 
-        if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; 
+        if (err != EAGAIN) return err;
+        if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
     }
     return IO_UNKNOWN;
 }
@@ -275,7 +274,7 @@ int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm
 /*-------------------------------------------------------------------------*\
 * Recvfrom with timeout
 \*-------------------------------------------------------------------------*/
-int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, 
+int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
         SA *addr, socklen_t *len, p_timeout tm) {
     int err;
     *got = 0;
@@ -289,8 +288,8 @@ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
         err = errno;
         if (taken == 0) return IO_CLOSED;
         if (err == EINTR) continue;
-        if (err != EAGAIN) return err; 
-        if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; 
+        if (err != EAGAIN) return err;
+        if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
     }
     return IO_UNKNOWN;
 }
@@ -303,7 +302,7 @@ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
 * with send/recv replaced with write/read. We can't just use write/read
 * in the socket version, because behaviour when size is zero is different.
 \*-------------------------------------------------------------------------*/
-int socket_write(p_socket ps, const char *data, size_t count, 
+int socket_write(p_socket ps, const char *data, size_t count,
         size_t *sent, p_timeout tm)
 {
     int err;
@@ -321,6 +320,8 @@ int socket_write(p_socket ps, const char *data, size_t count,
         err = errno;
         /* EPIPE means the connection was closed */
         if (err == EPIPE) return IO_CLOSED;
+        /* EPROTOTYPE means the connection is being closed (on Yosemite!)*/
+        if (err == EPROTOTYPE) continue;
         /* we call was interrupted, just try again */
         if (err == EINTR) continue;
         /* if failed fatal reason, report error */
@@ -349,8 +350,8 @@ int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm
         err = errno;
         if (taken == 0) return IO_CLOSED;
         if (err == EINTR) continue;
-        if (err != EAGAIN) return err; 
-        if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; 
+        if (err != EAGAIN) return err;
+        if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
     }
     return IO_UNKNOWN;
 }
@@ -374,7 +375,7 @@ void socket_setnonblocking(p_socket ps) {
 }
 
 /*-------------------------------------------------------------------------*\
-* DNS helpers 
+* DNS helpers
 \*-------------------------------------------------------------------------*/
 int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
     *hp = gethostbyaddr(addr, len, AF_INET);
@@ -399,7 +400,7 @@ int socket_gethostbyname(const char *addr, struct hostent **hp) {
 const char *socket_hoststrerror(int err) {
     if (err <= 0) return io_strerror(err);
     switch (err) {
-        case HOST_NOT_FOUND: return "host not found";
+        case HOST_NOT_FOUND: return PIE_HOST_NOT_FOUND;
         default: return hstrerror(err);
     }
 }
@@ -407,42 +408,43 @@ const char *socket_hoststrerror(int err) {
 const char *socket_strerror(int err) {
     if (err <= 0) return io_strerror(err);
     switch (err) {
-        case EADDRINUSE: return "address already in use";
-        case EISCONN: return "already connected";
-        case EACCES: return "permission denied";
-        case ECONNREFUSED: return "connection refused";
-        case ECONNABORTED: return "closed";
-        case ECONNRESET: return "closed";
-        case ETIMEDOUT: return "timeout";
-        default: return strerror(err);
+        case EADDRINUSE: return PIE_ADDRINUSE;
+        case EISCONN: return PIE_ISCONN;
+        case EACCES: return PIE_ACCESS;
+        case ECONNREFUSED: return PIE_CONNREFUSED;
+        case ECONNABORTED: return PIE_CONNABORTED;
+        case ECONNRESET: return PIE_CONNRESET;
+        case ETIMEDOUT: return PIE_TIMEDOUT;
+        default: {
+            return strerror(err);
+        }
     }
 }
 
 const char *socket_ioerror(p_socket ps, int err) {
     (void) ps;
     return socket_strerror(err);
-} 
+}
 
 const char *socket_gaistrerror(int err) {
-    if (err == 0) return NULL; 
+    if (err == 0) return NULL;
     switch (err) {
-        case EAI_AGAIN: return "temporary failure in name resolution";
-        case EAI_BADFLAGS: return "invalid value for ai_flags";
+        case EAI_AGAIN: return PIE_AGAIN;
+        case EAI_BADFLAGS: return PIE_BADFLAGS;
 #ifdef EAI_BADHINTS
-        case EAI_BADHINTS: return "invalid value for hints";
+        case EAI_BADHINTS: return PIE_BADHINTS;
 #endif
-        case EAI_FAIL: return "non-recoverable failure in name resolution";
-        case EAI_FAMILY: return "ai_family not supported";
-        case EAI_MEMORY: return "memory allocation failure";
-        case EAI_NONAME: 
-            return "host or service not provided, or not known";
-        case EAI_OVERFLOW: return "argument buffer overflow";
+        case EAI_FAIL: return PIE_FAIL;
+        case EAI_FAMILY: return PIE_FAMILY;
+        case EAI_MEMORY: return PIE_MEMORY;
+        case EAI_NONAME: return PIE_NONAME;
+        case EAI_OVERFLOW: return PIE_OVERFLOW;
 #ifdef EAI_PROTOCOL
-        case EAI_PROTOCOL: return "resolved protocol is unknown";
+        case EAI_PROTOCOL: return PIE_PROTOCOL;
 #endif
-        case EAI_SERVICE: return "service not supported for socket type";
-        case EAI_SOCKTYPE: return "ai_socktype not supported";
-        case EAI_SYSTEM: return strerror(errno); 
+        case EAI_SERVICE: return PIE_SERVICE;
+        case EAI_SOCKTYPE: return PIE_SOCKTYPE;
+        case EAI_SYSTEM: return strerror(errno);
         default: return gai_strerror(err);
     }
 }
diff --git a/src/wsocket.c b/src/wsocket.c
index b4a4384..8ecb0fc 100644
--- a/src/wsocket.c
+++ b/src/wsocket.c
@@ -3,33 +3,34 @@
 * LuaSocket toolkit
 *
 * The penalty of calling select to avoid busy-wait is only paid when
-* the I/O call fail in the first place. 
+* the I/O call fail in the first place.
 \*=========================================================================*/
 #include <string.h>
 
 #include "socket.h"
+#include "pierror.h"
 
 /* WinSock doesn't have a strerror... */
 static const char *wstrerror(int err);
 
 /*-------------------------------------------------------------------------*\
-* Initializes module 
+* Initializes module
 \*-------------------------------------------------------------------------*/
 int socket_open(void) {
     WSADATA wsaData;
-    WORD wVersionRequested = MAKEWORD(2, 0); 
+    WORD wVersionRequested = MAKEWORD(2, 0);
     int err = WSAStartup(wVersionRequested, &wsaData );
     if (err != 0) return 0;
     if ((LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) &&
         (LOBYTE(wsaData.wVersion) != 1 || HIBYTE(wsaData.wVersion) != 1)) {
         WSACleanup();
-        return 0; 
+        return 0;
     }
     return 1;
 }
 
 /*-------------------------------------------------------------------------*\
-* Close module 
+* Close module
 \*-------------------------------------------------------------------------*/
 int socket_close(void) {
     WSACleanup();
@@ -50,10 +51,10 @@ int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
     struct timeval tv, *tp = NULL;
     double t;
     if (timeout_iszero(tm)) return IO_TIMEOUT;  /* optimize timeout == 0 case */
-    if (sw & WAITFD_R) { 
-        FD_ZERO(&rfds); 
+    if (sw & WAITFD_R) {
+        FD_ZERO(&rfds);
         FD_SET(*ps, &rfds);
-        rp = &rfds; 
+        rp = &rfds;
     }
     if (sw & WAITFD_W) { FD_ZERO(&wfds); FD_SET(*ps, &wfds); wp = &wfds; }
     if (sw & WAITFD_C) { FD_ZERO(&efds); FD_SET(*ps, &efds); ep = &efds; }
@@ -72,9 +73,9 @@ int socket_waitfd(p_socket ps, int sw, p_timeout tm) {
 /*-------------------------------------------------------------------------*\
 * Select with int timeout in ms
 \*-------------------------------------------------------------------------*/
-int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, 
+int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds,
         p_timeout tm) {
-    struct timeval tv; 
+    struct timeval tv;
     double t = timeout_get(tm);
     tv.tv_sec = (int) t;
     tv.tv_usec = (int) ((t - tv.tv_sec) * 1.0e6);
@@ -96,7 +97,7 @@ void socket_destroy(p_socket ps) {
 }
 
 /*-------------------------------------------------------------------------*\
-* 
+*
 \*-------------------------------------------------------------------------*/
 void socket_shutdown(p_socket ps, int how) {
     socket_setblocking(ps);
@@ -134,10 +135,10 @@ int socket_connect(p_socket ps, SA *addr, socklen_t len, p_timeout tm) {
         /* give windows time to set the error (yes, disgusting) */
         Sleep(10);
         /* find out why we failed */
-        getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len); 
+        getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *)&err, &len);
         /* we KNOW there was an error. if 'why' is 0, we will return
         * "unknown error", but it's not really our fault */
-        return err > 0? err: IO_UNKNOWN; 
+        return err > 0? err: IO_UNKNOWN;
     } else return err;
 
 }
@@ -154,7 +155,7 @@ int socket_bind(p_socket ps, SA *addr, socklen_t len) {
 }
 
 /*-------------------------------------------------------------------------*\
-* 
+*
 \*-------------------------------------------------------------------------*/
 int socket_listen(p_socket ps, int backlog) {
     int err = IO_DONE;
@@ -167,7 +168,7 @@ int socket_listen(p_socket ps, int backlog) {
 /*-------------------------------------------------------------------------*\
 * Accept with timeout
 \*-------------------------------------------------------------------------*/
-int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len, 
+int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len,
         p_timeout tm) {
     if (*ps == SOCKET_INVALID) return IO_CLOSED;
     for ( ;; ) {
@@ -175,21 +176,21 @@ int socket_accept(p_socket ps, p_socket pa, SA *addr, socklen_t *len,
         /* try to get client socket */
         if ((*pa = accept(*ps, addr, len)) != SOCKET_INVALID) return IO_DONE;
         /* find out why we failed */
-        err = WSAGetLastError(); 
+        err = WSAGetLastError();
         /* if we failed because there was no connectoin, keep trying */
         if (err != WSAEWOULDBLOCK && err != WSAECONNABORTED) return err;
         /* call select to avoid busy wait */
         if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err;
-    } 
+    }
 }
 
 /*-------------------------------------------------------------------------*\
 * Send with timeout
-* On windows, if you try to send 10MB, the OS will buffer EVERYTHING 
-* this can take an awful lot of time and we will end up blocked. 
+* On windows, if you try to send 10MB, the OS will buffer EVERYTHING
+* this can take an awful lot of time and we will end up blocked.
 * Therefore, whoever calls this function should not pass a huge buffer.
 \*-------------------------------------------------------------------------*/
-int socket_send(p_socket ps, const char *data, size_t count, 
+int socket_send(p_socket ps, const char *data, size_t count,
         size_t *sent, p_timeout tm)
 {
     int err;
@@ -206,18 +207,18 @@ int socket_send(p_socket ps, const char *data, size_t count,
             return IO_DONE;
         }
         /* deal with failure */
-        err = WSAGetLastError(); 
+        err = WSAGetLastError();
         /* we can only proceed if there was no serious error */
         if (err != WSAEWOULDBLOCK) return err;
         /* avoid busy wait */
         if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
-    } 
+    }
 }
 
 /*-------------------------------------------------------------------------*\
 * Sendto with timeout
 \*-------------------------------------------------------------------------*/
-int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, 
+int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
         SA *addr, socklen_t len, p_timeout tm)
 {
     int err;
@@ -229,17 +230,17 @@ int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
             *sent = put;
             return IO_DONE;
         }
-        err = WSAGetLastError(); 
+        err = WSAGetLastError();
         if (err != WSAEWOULDBLOCK) return err;
         if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
-    } 
+    }
 }
 
 /*-------------------------------------------------------------------------*\
 * Receive with timeout
 \*-------------------------------------------------------------------------*/
-int socket_recv(p_socket ps, char *data, size_t count, size_t *got, 
-        p_timeout tm) 
+int socket_recv(p_socket ps, char *data, size_t count, size_t *got,
+        p_timeout tm)
 {
     int err, prev = IO_DONE;
     *got = 0;
@@ -252,9 +253,9 @@ int socket_recv(p_socket ps, char *data, size_t count, size_t *got,
         }
         if (taken == 0) return IO_CLOSED;
         err = WSAGetLastError();
-        /* On UDP, a connreset simply means the previous send failed. 
-         * So we try again. 
-         * On TCP, it means our socket is now useless, so the error passes. 
+        /* On UDP, a connreset simply means the previous send failed.
+         * So we try again.
+         * On TCP, it means our socket is now useless, so the error passes.
          * (We will loop again, exiting because the same error will happen) */
         if (err != WSAEWOULDBLOCK) {
             if (err != WSAECONNRESET || prev == WSAECONNRESET) return err;
@@ -267,8 +268,8 @@ int socket_recv(p_socket ps, char *data, size_t count, size_t *got,
 /*-------------------------------------------------------------------------*\
 * Recvfrom with timeout
 \*-------------------------------------------------------------------------*/
-int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, 
-        SA *addr, socklen_t *len, p_timeout tm) 
+int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
+        SA *addr, socklen_t *len, p_timeout tm)
 {
     int err, prev = IO_DONE;
     *got = 0;
@@ -281,8 +282,8 @@ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got,
         }
         if (taken == 0) return IO_CLOSED;
         err = WSAGetLastError();
-        /* On UDP, a connreset simply means the previous send failed. 
-         * So we try again. 
+        /* On UDP, a connreset simply means the previous send failed.
+         * So we try again.
          * On TCP, it means our socket is now useless, so the error passes.
          * (We will loop again, exiting because the same error will happen) */
         if (err != WSAEWOULDBLOCK) {
@@ -310,7 +311,7 @@ void socket_setnonblocking(p_socket ps) {
 }
 
 /*-------------------------------------------------------------------------*\
-* DNS helpers 
+* DNS helpers
 \*-------------------------------------------------------------------------*/
 int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp) {
     *hp = gethostbyaddr(addr, len, AF_INET);
@@ -330,21 +331,21 @@ int socket_gethostbyname(const char *addr, struct hostent **hp) {
 const char *socket_hoststrerror(int err) {
     if (err <= 0) return io_strerror(err);
     switch (err) {
-        case WSAHOST_NOT_FOUND: return "host not found";
-        default: return wstrerror(err); 
+        case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND;
+        default: return wstrerror(err);
     }
 }
 
 const char *socket_strerror(int err) {
     if (err <= 0) return io_strerror(err);
     switch (err) {
-        case WSAEADDRINUSE: return "address already in use";
-        case WSAECONNREFUSED: return "connection refused";
-        case WSAEISCONN: return "already connected";
-        case WSAEACCES: return "permission denied";
-        case WSAECONNABORTED: return "closed";
-        case WSAECONNRESET: return "closed";
-        case WSAETIMEDOUT: return "timeout";
+        case WSAEADDRINUSE: return PIE_ADDRINUSE;
+        case WSAECONNREFUSED : return PIE_CONNREFUSED;
+        case WSAEISCONN: return PIE_ISCONN;
+        case WSAEACCES: return PIE_ACCESS;
+        case WSAECONNABORTED: return PIE_CONNABORTED;
+        case WSAECONNRESET: return PIE_CONNRESET;
+        case WSAETIMEDOUT: return PIE_TIMEDOUT;
         default: return wstrerror(err);
     }
 }
@@ -357,7 +358,7 @@ const char *socket_ioerror(p_socket ps, int err) {
 static const char *wstrerror(int err) {
     switch (err) {
         case WSAEINTR: return "Interrupted function call";
-        case WSAEACCES: return "Permission denied";
+        case WSAEACCES: return PIE_ACCESS; // "Permission denied";
         case WSAEFAULT: return "Bad address";
         case WSAEINVAL: return "Invalid argument";
         case WSAEMFILE: return "Too many open files";
@@ -370,63 +371,61 @@ static const char *wstrerror(int err) {
         case WSAEPROTOTYPE: return "Protocol wrong type for socket";
         case WSAENOPROTOOPT: return "Bad protocol option";
         case WSAEPROTONOSUPPORT: return "Protocol not supported";
-        case WSAESOCKTNOSUPPORT: return "Socket type not supported";
+        case WSAESOCKTNOSUPPORT: return PIE_SOCKTYPE; // "Socket type not supported";
         case WSAEOPNOTSUPP: return "Operation not supported";
         case WSAEPFNOSUPPORT: return "Protocol family not supported";
-        case WSAEAFNOSUPPORT: 
-            return "Address family not supported by protocol family"; 
-        case WSAEADDRINUSE: return "Address already in use";
+        case WSAEAFNOSUPPORT: return PIE_FAMILY; // "Address family not supported by protocol family";
+        case WSAEADDRINUSE: return PIE_ADDRINUSE; // "Address already in use";
         case WSAEADDRNOTAVAIL: return "Cannot assign requested address";
         case WSAENETDOWN: return "Network is down";
         case WSAENETUNREACH: return "Network is unreachable";
         case WSAENETRESET: return "Network dropped connection on reset";
         case WSAECONNABORTED: return "Software caused connection abort";
-        case WSAECONNRESET: return "Connection reset by peer";
+        case WSAECONNRESET: return PIE_CONNRESET; // "Connection reset by peer";
         case WSAENOBUFS: return "No buffer space available";
-        case WSAEISCONN: return "Socket is already connected";
+        case WSAEISCONN: return PIE_ISCONN; // "Socket is already connected";
         case WSAENOTCONN: return "Socket is not connected";
         case WSAESHUTDOWN: return "Cannot send after socket shutdown";
-        case WSAETIMEDOUT: return "Connection timed out";
-        case WSAECONNREFUSED: return "Connection refused";
+        case WSAETIMEDOUT: return PIE_TIMEDOUT; // "Connection timed out";
+        case WSAECONNREFUSED: return PIE_CONNREFUSED; // "Connection refused";
         case WSAEHOSTDOWN: return "Host is down";
         case WSAEHOSTUNREACH: return "No route to host";
         case WSAEPROCLIM: return "Too many processes";
         case WSASYSNOTREADY: return "Network subsystem is unavailable";
         case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range";
-        case WSANOTINITIALISED: 
+        case WSANOTINITIALISED:
             return "Successful WSAStartup not yet performed";
         case WSAEDISCON: return "Graceful shutdown in progress";
-        case WSAHOST_NOT_FOUND: return "Host not found";
+        case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; // "Host not found";
         case WSATRY_AGAIN: return "Nonauthoritative host not found";
-        case WSANO_RECOVERY: return "Nonrecoverable name lookup error"; 
+        case WSANO_RECOVERY: return PIE_FAIL; // "Nonrecoverable name lookup error";
         case WSANO_DATA: return "Valid name, no data record of requested type";
         default: return "Unknown error";
     }
 }
 
 const char *socket_gaistrerror(int err) {
-    if (err == 0) return NULL; 
+    if (err == 0) return NULL;
     switch (err) {
-        case EAI_AGAIN: return "temporary failure in name resolution";
-        case EAI_BADFLAGS: return "invalid value for ai_flags";
+        case EAI_AGAIN: return PIE_AGAIN;
+        case EAI_BADFLAGS: return PIE_BADFLAGS;
 #ifdef EAI_BADHINTS
-        case EAI_BADHINTS: return "invalid value for hints";
+        case EAI_BADHINTS: return PIE_BADHINTS;
 #endif
-        case EAI_FAIL: return "non-recoverable failure in name resolution";
-        case EAI_FAMILY: return "ai_family not supported";
-        case EAI_MEMORY: return "memory allocation failure";
-        case EAI_NONAME: 
-            return "host or service not provided, or not known";
+        case EAI_FAIL: return PIE_FAIL;
+        case EAI_FAMILY: return PIE_FAMILY;
+        case EAI_MEMORY: return PIE_MEMORY;
+        case EAI_NONAME: return PIE_NONAME;
 #ifdef EAI_OVERFLOW
-        case EAI_OVERFLOW: return "argument buffer overflow";
+        case EAI_OVERFLOW: return PIE_OVERFLOW;
 #endif
 #ifdef EAI_PROTOCOL
-        case EAI_PROTOCOL: return "resolved protocol is unknown";
+        case EAI_PROTOCOL: return PIE_PROTOCOL;
 #endif
-        case EAI_SERVICE: return "service not supported for socket type";
-        case EAI_SOCKTYPE: return "ai_socktype not supported";
+        case EAI_SERVICE: return PIE_SERVICE;
+        case EAI_SOCKTYPE: return PIE_SOCKTYPE;
 #ifdef EAI_SYSTEM
-        case EAI_SYSTEM: return strerror(errno); 
+        case EAI_SYSTEM: return strerror(errno);
 #endif
         default: return gai_strerror(err);
     }
diff --git a/test/auth/.htaccess b/test/auth/.htaccess
new file mode 100644
index 0000000..bb2794a
--- /dev/null
+++ b/test/auth/.htaccess
@@ -0,0 +1,4 @@
+AuthName "test-auth"
+    AuthType Basic
+    AuthUserFile /Users/diego/impa/luasocket/test/auth/.htpasswd
+    Require valid-user
diff --git a/test/auth/.htpasswd b/test/auth/.htpasswd
index fd9002b..cfb2603 100644
--- a/test/auth/.htpasswd
+++ b/test/auth/.htpasswd
@@ -1 +1 @@
-luasocket:l8n2npozPB.sQ
+luasocket:$apr1$47u2O.Me$.m/5BWAtt7GVoxsouIPBR1
diff --git a/test/excepttest.lua b/test/excepttest.lua
index ce9f197..80c9cb8 100644
--- a/test/excepttest.lua
+++ b/test/excepttest.lua
@@ -1,6 +1,30 @@
 local socket = require("socket")
-try = socket.newtry(function()
-    print("finalized!!!")
+
+local finalizer_called
+
+local func = socket.protect(function(err, ...)
+    local try = socket.newtry(function()
+        finalizer_called = true
+    end)
+
+    if err then
+        return error(err, 0)
+    else
+        return try(...)
+    end
 end)
-try = socket.protect(try)
-print(try(nil, "it works"))
+
+local ret1, ret2, ret3 = func(false, 1, 2, 3)
+assert(not finalizer_called, "unexpected finalizer call")
+assert(ret1 == 1 and ret2 == 2 and ret3 == 3, "incorrect return values")
+
+ret1, ret2, ret3 = func(false, false, "error message")
+assert(finalizer_called, "finalizer not called")
+assert(ret1 == nil and ret2 == "error message" and ret3 == nil, "incorrect return values")
+
+local err = {key = "value"}
+ret1, ret2 = pcall(func, err)
+assert(not ret1, "error not rethrown")
+assert(ret2 == err, "incorrect error rethrown")
+
+print("OK")
diff --git a/test/httptest.lua b/test/httptest.lua
index d5fbb37..63ff921 100644
--- a/test/httptest.lua
+++ b/test/httptest.lua
@@ -1,4 +1,4 @@
--- needs Alias from /home/c/diego/tec/luasocket/test to 
+-- needs Alias from /home/c/diego/tec/luasocket/test to
 -- "/luasocket-test" and "/luasocket-test/"
 -- needs ScriptAlias from /home/c/diego/tec/luasocket/test/cgi
 -- to "/luasocket-test-cgi" and "/luasocket-test-cgi/"
@@ -36,22 +36,22 @@ index = readfile(index_file)
 local check_result = function(response, expect, ignore)
     for i,v in pairs(response) do
         if not ignore[i] then
-            if v ~= expect[i] then 
+            if v ~= expect[i] then
                 local f = io.open("err", "w")
                 f:write(tostring(v), "\n\n versus\n\n", tostring(expect[i]))
                 f:close()
-                fail(i .. " differs!") 
+                fail(i .. " differs!")
             end
         end
     end
     for i,v in pairs(expect) do
         if not ignore[i] then
-            if v ~= response[i] then 
+            if v ~= response[i] then
                 local f = io.open("err", "w")
                 f:write(tostring(response[i]), "\n\n versus\n\n", tostring(v))
                 v = string.sub(type(v) == "string" and v or "", 1, 70)
                 f:close()
-                fail(i .. " differs!") 
+                fail(i .. " differs!")
             end
         end
     end
@@ -61,10 +61,10 @@ end
 local check_request = function(request, expect, ignore)
     local t
     if not request.sink then request.sink, t = ltn12.sink.table() end
-    request.source = request.source or 
+    request.source = request.source or
         (request.body and ltn12.source.string(request.body))
     local response = {}
-    response.code, response.headers, response.status = 
+    response.code, response.headers, response.status =
         socket.skip(1, http.request(request))
     if t and #t > 0 then response.body = table.concat(t) end
     check_result(response, expect, ignore)
@@ -82,7 +82,7 @@ else fail(back.query) end
 ------------------------------------------------------------------------
 io.write("testing query string correctness: ")
 forth = "this+is+the+query+string"
-back = http.request("http://" .. host .. cgiprefix .. 
+back = http.request("http://" .. host .. cgiprefix ..
     "/query-string?" .. forth)
 if similar(back, forth) then print("ok")
 else fail("failed!") end
@@ -120,10 +120,10 @@ check_request(request, expect, ignore)
 ------------------------------------------------------------------------
 io.write("testing invalid url: ")
 local r, e = http.request{url = host .. prefix}
-assert(r == nil and e == "invalid host ''") 
+assert(r == nil and e == "invalid host ''")
 r, re = http.request(host .. prefix)
-assert(r == nil and e == re, tostring(r) ..", " .. tostring(re) .. 
-    " vs " .. tostring(e)) 
+assert(r == nil and e == re, tostring(r) ..", " .. tostring(re) ..
+    " vs " .. tostring(e))
 print("ok")
 
 io.write("testing invalid empty port: ")
@@ -212,7 +212,7 @@ os.remove(index_file .. "-back")
 io.write("testing ltn12.(sink|source).chain and mime.(encode|decode): ")
 
 local function b64length(len)
-    local a = math.ceil(len/3)*4 
+    local a = math.ceil(len/3)*4
     local l = math.ceil(a/76)
     return a + l*2
 end
@@ -313,7 +313,7 @@ ignore = {
     headers = 1
 }
 check_request(request, expect, ignore)
-    
+
 ------------------------------------------------------------------------
 io.write("testing document not found: ")
 request = {
@@ -429,9 +429,9 @@ print("ok")
 io.write("testing host not found: ")
 local c, e = socket.connect("example.invalid", 80)
 local r, re = http.request{url = "http://example.invalid/does/not/exist"}
-assert(r == nil and e == re, tostring(r) .. " " .. tostring(re)) 
+assert(r == nil and e == re, tostring(r) .. " " .. tostring(re))
 r, re = http.request("http://example.invalid/does/not/exist")
-assert(r == nil and e == re) 
+assert(r == nil and e == re)
 print("ok")
 
 ------------------------------------------------------------------------
diff --git a/test/ltn12test.lua b/test/ltn12test.lua
index 74a45e8..e3f85fb 100644
--- a/test/ltn12test.lua
+++ b/test/ltn12test.lua
@@ -192,6 +192,21 @@ assert(filter(nil, 1), "filter not empty")
 print("ok")
 
 --------------------------------
+io.write("testing source.chain (with several filters): ")
+local function double(x) -- filter turning "ABC" into "AABBCC"
+    if not x then return end
+    local b={}
+    for k in x:gmatch'.' do table.insert(b, k..k) end
+    return table.concat(b)
+end
+source = ltn12.source.string(s)
+source = ltn12.source.chain(source, double, double, double)
+sink, t = ltn12.sink.table()
+assert(ltn12.pump.all(source, sink), "returned error")
+assert(table.concat(t) == double(double(double(s))), "mismatch")
+print("ok")
+
+--------------------------------
 io.write("testing source.chain (with split) and sink.chain (with merge): ")
 source = ltn12.source.string(s)
 filter = split(5)
@@ -206,6 +221,15 @@ assert(filter2(nil, 1), "filter2 not empty")
 print("ok")
 
 --------------------------------
+io.write("testing sink.chain (with several filters): ")
+source = ltn12.source.string(s)
+sink, t = ltn12.sink.table()
+sink = ltn12.sink.chain(double, double, double, sink)
+assert(ltn12.pump.all(source, sink), "returned error")
+assert(table.concat(t) == double(double(double(s))), "mismatch")
+print("ok")
+
+--------------------------------
 io.write("testing filter.chain (and sink.chain, with split, merge): ")
 source = ltn12.source.string(s)
 filter = split(5)
@@ -272,3 +296,4 @@ assert(filter3(nil, 1), "filter3 not empty")
 assert(filter4(nil, 1), "filter4 not empty")
 assert(filter5(nil, 1), "filter5 not empty")
 print("ok")
+
diff --git a/test/testclnt.lua b/test/testclnt.lua
index 315783b..170e187 100644
--- a/test/testclnt.lua
+++ b/test/testclnt.lua
@@ -8,7 +8,7 @@ function printf(...)
 end
 
 function pass(...)
-    printf(...) 
+    printf(...)
     io.stderr:write("\n")
 end
 
@@ -45,30 +45,30 @@ function check_timeout(tm, sl, elapsed, err, opp, mode, alldone)
             if not err then warn("must be buffered")
             elseif err == "timeout" then pass("proper timeout")
             else fail("unexpected error '%s'", err) end
-        else 
-            if err ~= "timeout" then fail("should have timed out") 
+        else
+            if err ~= "timeout" then fail("should have timed out")
             else pass("proper timeout") end
         end
     else
         if mode == "total" then
-            if elapsed > tm then 
+            if elapsed > tm then
                 if err ~= "timeout" then fail("should have timed out")
                 else pass("proper timeout") end
             elseif elapsed < tm then
-                if err then fail(err) 
+                if err then fail(err)
                 else pass("ok") end
-            else 
-                if alldone then 
-                    if err then fail("unexpected error '%s'", err) 
+            else
+                if alldone then
+                    if err then fail("unexpected error '%s'", err)
                     else pass("ok") end
                 else
-                    if err ~= "timeout" then fail(err) 
+                    if err ~= "timeout" then fail(err)
                     else pass("proper timeoutk") end
                 end
             end
-        else 
-            if err then fail(err) 
-            else pass("ok") end 
+        else
+            if err then fail(err)
+            else pass("ok") end
         end
     end
 end
@@ -104,8 +104,8 @@ control:setoption("tcp-nodelay", true)
 ------------------------------------------------------------------------
 function test_methods(sock, methods)
     for _, v in pairs(methods) do
-        if type(sock[v]) ~= "function" then 
-            fail(sock.class .. " method '" .. v .. "' not registered") 
+        if type(sock[v]) ~= "function" then
+            fail(sock.class .. " method '" .. v .. "' not registered")
         end
     end
     pass(sock.class .. " methods are ok")
@@ -121,7 +121,7 @@ function test_mixed(len)
     local p3 = "raw " .. string.rep("z", inter) .. "bytes"
     local p4 = "end" .. string.rep("w", inter) .. "bytes"
     local bp1, bp2, bp3, bp4
-remote (string.format("str = data:receive(%d)", 
+remote (string.format("str = data:receive(%d)",
             string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4)))
     sent, err = data:send(p1..p2..p3..p4)
     if err then fail(err) end
@@ -166,7 +166,7 @@ function test_rawline(len)
     io.stderr:write("length " .. len .. ": ")
     local str, str10, back, err
     str = string.rep(string.char(47), math.mod(len, 10))
-    str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100), 
+    str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100),
             math.floor(len/10))
     str = str .. str10
 remote "str = data:receive()"
@@ -216,7 +216,7 @@ function test_totaltimeoutreceive(len, tm, sl)
     data:settimeout(tm, "total")
 local t = socket.gettime()
     str, err, partial, elapsed = data:receive(2*len)
-    check_timeout(tm, sl, elapsed, err, "receive", "total", 
+    check_timeout(tm, sl, elapsed, err, "receive", "total",
         string.len(str or partial) == 2*len)
 end
 
@@ -236,7 +236,7 @@ function test_totaltimeoutsend(len, tm, sl)
     data:settimeout(tm, "total")
     str = string.rep("a", 2*len)
     total, err, partial, elapsed = data:send(str)
-    check_timeout(tm, sl, elapsed, err, "send", "total", 
+    check_timeout(tm, sl, elapsed, err, "send", "total",
         total == 2*len)
 end
 
@@ -256,7 +256,7 @@ function test_blockingtimeoutreceive(len, tm, sl)
     ]], 2*tm, len, sl, sl))
     data:settimeout(tm)
     str, err, partial, elapsed = data:receive(2*len)
-    check_timeout(tm, sl, elapsed, err, "receive", "blocking", 
+    check_timeout(tm, sl, elapsed, err, "receive", "blocking",
         string.len(str or partial) == 2*len)
 end
 
@@ -290,10 +290,10 @@ function empty_connect()
         data = server:accept()
     ]]
     data, err = socket.connect("", port)
-    if not data then 
+    if not data then
         pass("ok")
         data = socket.connect(host, port)
-    else 
+    else
         pass("gethostbyname returns localhost on empty string...")
     end
 end
@@ -304,15 +304,20 @@ function isclosed(c)
 end
 
 function active_close()
-    reconnect()
-    if isclosed(data) then fail("should not be closed") end
-    data:close()
-    if not isclosed(data) then fail("should be closed") end
-    data = nil
-    local udp = socket.udp()
+    local tcp = socket.tcp4()
+    if isclosed(tcp) then fail("should not be closed") end
+    tcp:close()
+    if not isclosed(tcp) then fail("should be closed") end
+    tcp = socket.tcp()
+    if not isclosed(tcp) then fail("should be closed") end
+    tcp = nil
+    local udp = socket.udp4()
     if isclosed(udp) then fail("should not be closed") end
     udp:close()
     if not isclosed(udp) then fail("should be closed") end
+    udp = socket.udp()
+    if not isclosed(udp) then fail("should be closed") end
+    udp = nil
     pass("ok")
 end
 
@@ -327,7 +332,7 @@ function test_closed()
         data:close()
         data = nil
     ]], str))
-    -- try to get a line 
+    -- try to get a line
     back, err, partial = data:receive()
     if not err then fail("should have gotten 'closed'.")
     elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.")
@@ -340,25 +345,25 @@ function test_closed()
         data = nil
     ]]
     total, err, partial = data:send(string.rep("ugauga", 100000))
-    if not err then 
+    if not err then
         pass("failed: output buffer is at least %d bytes long!", total)
-    elseif err ~= "closed" then 
+    elseif err ~= "closed" then
         fail("got '"..err.."' instead of 'closed'.")
-    else 
-        pass("graceful 'closed' received after %d bytes were sent", partial) 
+    else
+        pass("graceful 'closed' received after %d bytes were sent", partial)
     end
 end
 
 ------------------------------------------------------------------------
 function test_selectbugs()
     local r, s, e = socket.select(nil, nil, 0.1)
-    assert(type(r) == "table" and type(s) == "table" and 
+    assert(type(r) == "table" and type(s) == "table" and
         (e == "timeout" or e == "error"))
     pass("both nil: ok")
     local udp = socket.udp()
     udp:close()
     r, s, e = socket.select({ udp }, { udp }, 0.1)
-    assert(type(r) == "table" and type(s) == "table" and 
+    assert(type(r) == "table" and type(s) == "table" and
         (e == "timeout" or e == "error"))
     pass("closed sockets: ok")
     e = pcall(socket.select, "wrong", 1, 0.1)
@@ -368,7 +373,7 @@ function test_selectbugs()
     pass("invalid input: ok")
     local toomany = {}
     for i = 1, socket._SETSIZE+1 do
-        toomany[#toomany+1] = socket.udp()
+        toomany[#toomany+1] = socket.udp4()
     end
     if #toomany > socket._SETSIZE then
         local e = pcall(socket.select, toomany, nil, 0.1)
@@ -389,7 +394,7 @@ function accept_timeout()
     local t = socket.gettime()
     s:settimeout(1)
     local c, e = s:accept()
-    assert(not c, "should not accept") 
+    assert(not c, "should not accept")
     assert(e == "timeout", string.format("wrong error message (%s)", e))
     t = socket.gettime() - t
     assert(t < 2, string.format("took to long to give up (%gs)", t))
@@ -407,9 +412,9 @@ function connect_timeout()
     local t = socket.gettime()
     local r, e = c:connect("10.0.0.1", 81)
     assert(not r, "should not connect")
-    assert(socket.gettime() - t < 2, "took too long to give up.") 
+    assert(socket.gettime() - t < 2, "took too long to give up.")
     c:close()
-    pass("ok") 
+    pass("ok")
 end
 
 ------------------------------------------------------------------------
@@ -447,16 +452,14 @@ end
 
 ------------------------------------------------------------------------
 function rebind_test()
-    --local c ,c1 = socket.bind("localhost", 0)
    local c ,c1 = socket.bind("127.0.0.1", 0)
     if not c then pass ("failed to bind! " .. tostring(c) .. ' ' .. tostring(c1))  return end
 	assert(c,c1)
- 
     local i, p = c:getsockname()
     local s, e = socket.tcp()
     assert(s, e)
     s:setoption("reuseaddr", false)
-    r, e = s:bind("localhost", p)
+    r, e = s:bind(i, p)
     assert(not r, "managed to rebind!")
     assert(e)
     pass("ok")
@@ -476,9 +479,9 @@ function getstats_test()
         data:receive(c)
         t = t + c
         local r, s, a = data:getstats()
-        assert(r == t, "received count failed" .. tostring(r) 
+        assert(r == t, "received count failed" .. tostring(r)
             .. "/" .. tostring(t))
-        assert(s == t, "sent count failed" .. tostring(s) 
+        assert(s == t, "sent count failed" .. tostring(s)
             .. "/" .. tostring(t))
     end
     pass("ok")
@@ -486,7 +489,7 @@ end
 
 
 ------------------------------------------------------------------------
-function test_nonblocking(size) 
+function test_nonblocking(size)
     reconnect()
     printf("testing "  .. 2*size .. " bytes: ")
 remote(string.format([[
@@ -545,7 +548,7 @@ function test_readafterclose()
         data:close()
         data = nil
     ]]))
-    data:close() 
+    data:close()
     back, err, partial = data:receive("*a")
     assert(back == nil and err == "closed", "should have returned 'closed'")
     pass("ok")
@@ -555,7 +558,7 @@ function test_readafterclose()
         data:close()
         data = nil
     ]]))
-    data:close() 
+    data:close()
     back, err, partial = data:receive()
     assert(back == nil and err == "closed", "should have returned 'closed'")
     pass("ok")
@@ -565,7 +568,7 @@ function test_readafterclose()
         data:close()
         data = nil
     ]]))
-    data:close() 
+    data:close()
     back, err, partial = data:receive(1)
     assert(back == nil and err == "closed", "should have returned 'closed'")
     pass("ok")
@@ -575,7 +578,7 @@ function test_readafterclose()
         data:close()
         data = nil
     ]]))
-    data:close() 
+    data:close()
     back, err, partial = data:receive(0)
     assert(back == nil and err == "closed", "should have returned 'closed'")
     pass("ok")
@@ -590,10 +593,10 @@ function test_writeafterclose()
         data = nil
     ]]))
     local sent, err, errsent
-    while not err do 
+    while not err do
         sent, err, errsent, time = data:send(str)
     end
-    assert(err == "closed", "should have returned 'closed'")
+    assert(err == "closed", "got " .. err .. " instead of 'closed'")
     pass("ok")
 end
 
@@ -648,25 +651,24 @@ else io.stderr:write("Warning! IPv6 does not support!\n") end
 end
 
 local udp_methods = {
-    "close", 
+    "close",
     "dirty",
     "getfamily",
     "getfd",
     "getoption",
     "getpeername",
     "getsockname",
-    "receive", 
-    "receivefrom", 
-    "send", 
-    "sendto", 
-    "setfd", 
+    "receive",
+    "receivefrom",
+    "send",
+    "sendto",
+    "setfd",
     "setoption",
     "setpeername",
     "setsockname",
     "settimeout"
 }
 
-
 ------------------------------------------------------------------------
 test_methods(socket.udp(), udp_methods)
 do local sock = socket.tcp6()
@@ -674,6 +676,9 @@ if sock then test_methods(socket.udp6(), udp_methods)
 else io.stderr:write("Warning! IPv6 does not support!\n") end
 end
 
+test("closed connection detection: ")
+test_closed()
+
 test("partial receive")
 test_partialrecv()
 
@@ -697,9 +702,6 @@ rebind_test()
 test("active close: ")
 active_close()
 
-test("closed connection detection: ")
-test_closed()
-
 test("accept function: ")
 accept_timeout()
 accept_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";
 while 1 do
     print("server: waiting for client connection...");
     control = assert(server:accept());
-    while 1 do 
+    while 1 do
         command, emsg = control:receive();
         if emsg == "closed" then
             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 @@
 local socket = require"socket"
 local udp = socket.udp
 local localhost = "127.0.0.1"
-local port = arg[1]
+local port = assert(arg[1], "missing port argument")
 
 se = udp(); se:setoption("reuseaddr", true)
 se:setsockname(localhost, 5062)
diff --git a/win32.cmd b/win32.cmd
index 48522f0..3045721 100644
--- a/win32.cmd
+++ b/win32.cmd
@@ -1,12 +1 @@
-make PLAT=win32 LUAV=5.2 LUAINC_win32='c:\cygwin\home\diego\build\include' LUALIB_win32='c:\cygwin\home\diego\build\bin\release'
-
-#!/bin/sh
-for p in Release Debug x64/Release x64/Debug; do
-    for el in mime socket; do
-        for e in dll lib; do
-            cp $p/$el/core.$e ../bin/$p/$el/
-        done;
-    done;
-    cp src/ltn12.lua src/socket.lua src/mime.lua ../bin/$p/
-    cp src/http.lua src/url.lua src/tp.lua src/ftp.lua src/headers.lua src/smtp.lua ../bin/$p/socket/
-done;
+make LUAPREFIX_win32='c:\cygwin\home\diego\vc12' LUAV=5.1 PLAT=win32 LUALIBNAME_win32=lualib.lib PLATFORM_win32=Debug install-both