diff options
Diffstat (limited to 'user')
-rw-r--r-- | user/lua-socket/0001-Create-socket-on-first-sendto-if-family-agnostic-udp.patch | 49 | ||||
-rw-r--r-- | user/lua-socket/APKBUILD | 35 | ||||
-rw-r--r-- | user/lua-socket/git.patch | 6609 | ||||
-rw-r--r-- | user/lua-socket/lua-cflags.patch | 22 |
4 files changed, 15 insertions, 6700 deletions
diff --git a/user/lua-socket/0001-Create-socket-on-first-sendto-if-family-agnostic-udp.patch b/user/lua-socket/0001-Create-socket-on-first-sendto-if-family-agnostic-udp.patch deleted file mode 100644 index 61bae6fbf..000000000 --- a/user/lua-socket/0001-Create-socket-on-first-sendto-if-family-agnostic-udp.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 3041a808c3797e3c87272d71666e7b2f7c7a9f46 Mon Sep 17 00:00:00 2001 -From: Natanael Copa <ncopa@alpinelinux.org> -Date: Wed, 25 Jan 2017 12:43:29 +0100 -Subject: [PATCH] Create socket on first sendto if family agnostic udp() was - used - -Create socket and set family on first sendto() if udp() was created -without address family. - -Signed-off-by: Natanael Copa <ncopa@alpinelinux.org> ---- - src/udp.c | 21 +++++++++++++++++++++ - 1 file changed, 21 insertions(+) - -diff --git a/src/udp.c b/src/udp.c -index ec97252..605c195 100644 ---- a/src/udp.c -+++ b/src/udp.c -@@ -189,6 +189,27 @@ static int meth_sendto(lua_State *L) { - lua_pushstring(L, gai_strerror(err)); - return 2; - } -+ -+ /* create socket if on first sendto if AF_UNSPEC was set */ -+ if (udp->family == AF_UNSPEC && udp->sock == SOCKET_INVALID) { -+ struct addrinfo *ap; -+ const char *errstr = NULL; -+ for (ap = ai; ap != NULL; ap = ap->ai_next) { -+ errstr = inet_trycreate(&udp->sock, ap->ai_family, SOCK_DGRAM, 0); -+ if (errstr == NULL) { -+ socket_setnonblocking(&udp->sock); -+ udp->family = ap->ai_family; -+ break; -+ } -+ } -+ if (errstr != NULL) { -+ lua_pushnil(L); -+ lua_pushstring(L, errstr); -+ freeaddrinfo(ai); -+ return 2; -+ } -+ } -+ - timeout_markstart(tm); - err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, - (socklen_t) ai->ai_addrlen, tm); --- -2.11.0 - diff --git a/user/lua-socket/APKBUILD b/user/lua-socket/APKBUILD index e2235310d..a9c0f7af0 100644 --- a/user/lua-socket/APKBUILD +++ b/user/lua-socket/APKBUILD @@ -1,38 +1,33 @@ # Contributor: Mika Havela <mika.havela@gmail.com> # Maintainer: Síle Ekaterin Liszka <sheila@vulpine.house> pkgname=lua-socket -_name=luasocket -pkgver=3.0_rc1_git20160306 +_pkgname=luasocket +pkgver=3.1.0 pkgrel=0 -_ver=${pkgver%_git*} -_ver=$(printf '%s' "$_ver" | sed 's/_rc/-rc/') +_luaver=5.3 +_socketver=3.0.0 +_mimever=1.0.3 pkgdesc="Networking library for Lua" -url="http://luaforge.net/projects/luasocket/" +url="https://lunarmodules.github.io/luasocket/" arch="all" license="MIT" -depends="lua5.3" -makedepends="lua5.3-dev" -source="luasocket-$_ver.tar.gz::https://github.com/diegonehab/luasocket/archive/v$_ver.tar.gz - git.patch - lua-cflags.patch - 0001-Create-socket-on-first-sendto-if-family-agnostic-udp.patch" -builddir="$srcdir/$_name-$_ver" +depends="lua$_luaver" +makedepends="lua$_luaver-dev" +source="$pkgname-$pkgver.tar.gz::https://github.com/lunarmodules/luasocket/archive/refs/tags/v$pkgver.tar.gz" +builddir="$srcdir/$_pkgname-$pkgver" build() { - make LUAV="" + make linux prefix=/usr LUAV="$_luaver" } check() { - mkdir -p src/socket && cp src/socket-$_ver.so src/socket/core.so - mkdir -p src/mime && cp src/mime-1.0.3.so src/mime/core.so + cp src/socket-$_socketver.so src/socket.so + cp src/mime-$_mimever.so src/mime.so LUA_CPATH=./src/?.so LUA_PATH="./src/?.lua;;" lua test/hello.lua } package() { - make prefix=/usr DESTDIR="$pkgdir" LUAV="5.3" install-unix + make prefix=/usr DESTDIR="$pkgdir" LUAV="$_luaver" install-unix } -sha512sums="f6efce259aaacaa11472911471f8a13b118fe009b8953a82c6aa18b9ec829cd1293180904e56935cb130d36d267e3f27c91db2d78e03f7488f3e100571ed0540 luasocket-3.0-rc1.tar.gz -45c80e488fedc879f0217bc8a654d80da003039f5d1ff21b0dea0eb769151787dbe793e44a3dfd72cb07ff2697eceaf4fc7b55b4634cd170fa71281f19f025a5 git.patch -61c15238a2f116b7239fdbdb8f617c82dbbecd0117c6e8389b12015bf07f3978299a8e8995e93a45a23530c747662b08d161073cdb6a8e07c4f449e45856e8cb lua-cflags.patch -c45a12e17771a1b3b71154b5415421f524cd10b7969b4649a5f37b652cdc826721e117edb8fe64758d3520e59946e2f755b814f72cbb39ff42bf59bbcf9a64e9 0001-Create-socket-on-first-sendto-if-family-agnostic-udp.patch" +sha512sums="1e9e98484740ec6538fe3d2b0dab74d31f052956ecf9ee3b60e229f2d0b13fcc6d4aaf74cd2a3e2ee330333dabb316fe6a43c60baaea26f0cc01069b6aa4519b lua-socket-3.1.0.tar.gz" diff --git a/user/lua-socket/git.patch b/user/lua-socket/git.patch deleted file mode 100644 index d665fc232..000000000 --- a/user/lua-socket/git.patch +++ /dev/null @@ -1,6609 +0,0 @@ -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> -+ headers = <i>header-table</i>,<br> -+ body = <i>LTN12 source</i> or <i>string</i> or -+<i>multipart-mesgt</i><br> -+}<br> -+ <br> -+multipart-mesgt = {<br> -+ [preamble = <i>string</i>,]<br> -+ [1] = <i>mesgt</i>,<br> -+ [2] = <i>mesgt</i>,<br> -+ ...<br> -+ [<i>n</i>] = <i>mesgt</i>,<br> -+ [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 <sicrano@example.com>", -+ to = "Fulano da Silva <fulano@example.com>", -+ 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 = "<sicrano@example.com>", -+ rcpt = "<fulano@example.com>", -+ 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> -- headers = <i>header-table</i>,<br> -- body = <i>LTN12 source</i> or <i>string</i> or --<i>multipart-mesgt</i><br> --}<br> -- <br> --multipart-mesgt = {<br> -- [preamble = <i>string</i>,]<br> -- [1] = <i>mesgt</i>,<br> -- [2] = <i>mesgt</i>,<br> -- ...<br> -- [<i>n</i>] = <i>mesgt</i>,<br> -- [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 <sicrano@example.com>", -- to = "Fulano da Silva <fulano@example.com>", -- 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 = "<sicrano@example.com>", -- rcpt = "<fulano@example.com>", -- 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> · - <a href="installation.html">installation</a> · - <a href="introduction.html">introduction</a> · --<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 10), optionally preceded by a - CR character (ASCII 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> · - <a href="installation.html">installation</a> · - <a href="introduction.html">introduction</a> · --<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> · - <a href="installation.html">installation</a> · - <a href="introduction.html">introduction</a> · --<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 diff --git a/user/lua-socket/lua-cflags.patch b/user/lua-socket/lua-cflags.patch deleted file mode 100644 index c1da89644..000000000 --- a/user/lua-socket/lua-cflags.patch +++ /dev/null @@ -1,22 +0,0 @@ -diff --git a/src/makefile b/src/makefile -index adf687f..c2abddc 100644 ---- a/src/makefile -+++ b/src/makefile -@@ -160,6 +160,8 @@ SOCKET_macosx=usocket.o - #------ - # Compiler and linker settings - # for Linux -+LUAPC=lua -+LUA_CFLAGS=$(shell pkg-config --cflags $(LUAPC)) - SO_linux=so - O_linux=o - CC_linux=gcc -@@ -167,7 +169,7 @@ DEF_linux=-DLUASOCKET_$(DEBUG) \ - -DLUASOCKET_API='__attribute__((visibility("default")))' \ - -DUNIX_API='__attribute__((visibility("default")))' \ - -DMIME_API='__attribute__((visibility("default")))' --CFLAGS_linux= -I$(LUAINC) $(DEF) -Wall -Wshadow -Wextra \ -+CFLAGS_linux= $(LUA_CFLAGS) -I$(LUAINC) $(DEF) -Wall -Wshadow -Wextra \ - -Wimplicit -O2 -ggdb3 -fpic -fvisibility=hidden - LDFLAGS_linux=-O -shared -fpic -o - LD_linux=gcc |