From f5df416fd9b9d428aaf8c997e50b89c2710a010f Mon Sep 17 00:00:00 2001
From: Kiyoshi Aman
++Note: These constants are global. Changing them will also ++change the behavior other code that might be using LuaSocket. ++
+ + + +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") + ++-mime.normalize([marker]) +-
+- +-+-Converts most common end-of-line markers to a specific given marker. +-
+- +-+-Marker is the new marker. It defaults to CRLF, the canonic +-end-of-line marker defined by the MIME standard. +-
+- +-+-The function returns a filter that performs the conversion. +-
+- +-+-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. +-
+ + + +@@ -159,6 +131,35 @@ base64 = ltn12.filter.chain( + ) + + ++ ++ ++++mime.normalize([marker]) ++
++ ++++Converts most common end-of-line markers to a specific given marker. ++
++ ++++Marker is the new marker. It defaults to CRLF, the canonic ++end-of-line marker defined by the MIME standard. ++
++ ++++The function returns a filter that performs the conversion. ++
++ ++++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. ++
++ + + ++@@ -466,7 +467,7 @@ marker. +
+
+ Last modified by Diego Nehab on
+-Thu Apr 20 00:25:44 EDT 2006
++Fri Mar 4 15:19:17 BRT 2016
+
+
++smtp.message(mesgt) ++
++ ++++Returns a simple ++LTN12 source that sends an SMTP message body, possibly multipart (arbitrarily deep). ++
++ ++++The only parameter of the function is a table describing the message. ++Mesgt has the following form (notice the recursive structure): ++
++ ++++++ ++++
++++ ++mesgt = {
++ headers = header-table,
++ body = LTN12 source or string or ++multipart-mesgt
++}
++
++multipart-mesgt = {
++ [preamble = string,]
++ [1] = mesgt,
++ [2] = mesgt,
++ ...
++ [n] = mesgt,
++ [epilogue = string,]
++}
++
++For a simple message, all that is needed is a set of headers ++and the body. The message body can be given as a string ++or as a simple ++LTN12 ++source. For multipart messages, the body is a table that ++recursively defines each part as an independent message, plus an optional ++preamble and epilogue. ++
++ ++++The function returns a simple ++LTN12 ++source that produces the ++message contents as defined by mesgt, chunk by chunk. ++Hopefully, the following ++example will make things clear. When in doubt, refer to the appropriate RFC ++as listed in the introduction.
++ ++++-- 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, ++} ++++ ++ + + +
+@@ -275,123 +393,6 @@ r, e = smtp.send{ + } + + +- +- +-
+-smtp.message(mesgt) +-
+- +-+-Returns a simple +-LTN12 source that sends an SMTP message body, possibly multipart (arbitrarily deep). +-
+- +-+-The only parameter of the function is a table describing the message. +-Mesgt has the following form (notice the recursive structure): +-
+- +-+-+- +-+-
+-+- +-mesgt = {
+- headers = header-table,
+- body = LTN12 source or string or +-multipart-mesgt
+-}
+-
+-multipart-mesgt = {
+- [preamble = string,]
+- [1] = mesgt,
+- [2] = mesgt,
+- ...
+- [n] = mesgt,
+- [epilogue = string,]
+-}
+-
+-For a simple message, all that is needed is a set of headers +-and the body. The message body can be given as a string +-or as a simple +-LTN12 +-source. For multipart messages, the body is a table that +-recursively defines each part as an independent message, plus an optional +-preamble and epilogue. +-
+- +-+-The function returns a simple +-LTN12 +-source that produces the +-message contents as defined by mesgt, chunk by chunk. +-Hopefully, the following +-example will make things clear. When in doubt, refer to the appropriate RFC +-as listed in the introduction.
+- +-+--- 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, +-} +-+- + + +
++socket.headers.canonic
++ ++The socket.headers.canonic 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. ++
++ ++++You can obtain the headers namespace if case run-time ++modifications are required by running: ++
++ ++++-- loads the headers module ++local headers = require("headers") ++++ ++ + + +
+@@ -90,7 +114,7 @@ of connect are defined as simple helper functions that restrict the + + + +-
++
+ socket._DEBUG +
+ +@@ -99,6 +123,19 @@ This constant is set to true if the library was compiled + with debug support. + + ++ ++ ++++socket._DATAGRAMSIZE ++
++ ++++Default datagram size used by calls to ++receive and ++receivefrom. ++(Unless changed in compile time, the value is 8192.) ++
++ + + ++@@ -106,8 +143,7 @@ socket.gettime() +
+ ++-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. +
+ +@@ -117,29 +153,6 @@ t = socket.gettime() + print(socket.gettime() - t .. " seconds elapsed") + + +- +- +-+-socket.headers.canonic
+- +-The socket.headers.canonic 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. +-
+- +-+-You can obtain the headers namespace if case run-time +-modifications are required by running: +-
+- +-+--- loads the headers module +-local headers = require("headers") +-+- + + +
+@@ -155,8 +168,7 @@ is raised. + +
+ Finalizer is a function that will be called before +-try throws the exception. It will be called +-in protected mode. ++try throws the exception. +
+ ++@@ -204,15 +216,9 @@ to throw exceptions. +
+ ++-Returns an equivalent function that instead of throwing exceptions, +-returns nil followed by an error message. +-
+- +-+-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 try function +-uses errors as the mechanism to throw exceptions. ++Returns an equivalent function that instead of throwing exceptions in case of ++a failed try call, returns nil ++followed by an error message. +
+ + +@@ -238,7 +244,9 @@ non-numeric indices) in the arrays will be silently ignored. + +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 "timeout" if a timeout condition was met and ++The error message is "timeout" if a timeout ++condition was met, "select failed" if the call ++to select failed, and + nil 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. +
+ ++-Note: : select can monitor a limited number ++Note: select can monitor a limited number + of sockets, as defined by the constant socket._SETSIZE. 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 select, it will be ignored. + Using select with non-socket objects: Any object that implements getfd and dirty can be used with select, allowing objects from other libraries to be used within a socket.select driven loop. +
+ ++ ++ ++++socket._SETSIZE ++
++ ++++The maximum number of sockets that the select function can handle. ++
++ ++ + + ++@@ -383,15 +403,14 @@ side closes the connection. + The function returns a source with the appropriate behavior. +
+ +- ++ + +-+-socket._SETSIZE ++
++socket._SOCKETINVALID +
+ ++-The maximum number of sockets that the select function can handle. ++The OS value for an invalid socket. +
+ + +@@ -401,9 +420,9 @@ socket.try(ret1 [, ret2 ... retN]) + ++-Throws an exception in case of error. The exception can only be caught +-by the protect function. It does not explode +-into an error message. ++Throws an exception in case ret1 is falsy, using ++ret2 as the error message. The exception is supposed to be caught ++by a protected function only. +
+ ++@@ -414,7 +433,10 @@ nested with try. + +
+ The function returns ret1 to retN if +-ret1 is not nil. Otherwise, it calls error passing ret2. ++ret1 is not nil or false. ++Otherwise, it calls error passing ret2 wrapped ++in a table with metatable used by protect to ++distinguish exceptions from runtime errors. +
+ ++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 @@ +- + + + + +- ++ +LuaSocket: TCP/IP support + + +@@ -28,7 +28,7 @@ + download · + installation · + introduction · +-reference ++reference + + +
+@@ -36,56 +36,11 @@ + + + +-TCP
+- +- +- +-+-socket.tcp() +-
+- +-+-Creates and returns an IPv4 TCP master object. A master object can +-be transformed into a server object with the method +-listen (after a call to bind) or into a client object with +-the method connect. The only other +-method supported by a master object is the +-close method.
+- +-+-In case of success, a new master object is returned. In case of error, +-nil is returned, followed by an error message. +-
+- +- +- +-+-socket.tcp6() +-
+- +-+-Creates and returns an IPv6 TCP master object. A master object can +-be transformed into a server object with the method +-listen (after a call to bind) or into a client object with +-the method connect. The only other +-method supported by a master object is the +-close method.
+- +-+-In case of success, a new master object is returned. In case of error, +-nil is returned, followed by an error message. +-
+- +-+-Note: The TCP object returned will have the option +-"ipv6-v6only" set to true. +-
++TCP
+ + + +-++
+ server:accept() +
+ +@@ -95,9 +50,9 @@ object and returns a client object representing that connection. + + ++-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 nil +-followed by the error string 'timeout'. Other errors are ++followed by the error string 'timeout'. Other errors are + reported by nil followed by a message describing the error. +
+ +@@ -107,28 +62,28 @@ with a server object in + the recvt parameter before a call to accept does + not guarantee accept will return immediately. Use the settimeout method or accept +-might block until another client shows up. ++might block until another client shows up. + + + + +-++
+ master:bind(address, port) +
+ ++ Binds a master object to address and port on the +-local host. ++local host. + +
+-Address can be an IP address or a host name. +-Port must be an integer number in the range [0..64K). ++Address can be an IP address or a host name. ++Port must be an integer number in the range [0..64K). + If address + is '*', the system binds to all local interfaces + using the INADDR_ANY constant or +-IN6ADDR_ANY_INIT, according to the family. ++IN6ADDR_ANY_INIT, according to the family. + If port is 0, the system automatically +-chooses an ephemeral port. ++chooses an ephemeral port. +
+ ++@@ -137,13 +92,13 @@ method returns nil followed by an error message. +
+ ++-Note: The function socket.bind ++Note: The function socket.bind + is available and is a shortcut for the creation of server sockets. +
+ + + +-++
+ master:close()
+ +
+ client:close()
+ server:close() +@@ -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 close method) are allowed on +-a closed socket. ++a closed socket. ++ 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. +
+ + +@@ -172,19 +127,19 @@ master:connect(address, port) + ++ 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 + send, +-receive, +-getsockname, ++receive, ++getsockname, + getpeername, +-settimeout, ++settimeout, + and close. +
+ ++-Address can be an IP address or a host name. +-Port must be an integer number in the range [1..64K). ++Address can be an IP address or a host name. ++Port must be an integer number in the range [1..64K). +
+ ++@@ -193,14 +148,14 @@ describing the error. In case of success, the method returns 1. +
+ ++-Note: The function socket.connect ++Note: The function socket.connect + is available and is a shortcut for the creation of client sockets. +
+ ++-Note: Starting with LuaSocket 2.0, ++Note: Starting with LuaSocket 2.0, + the settimeout +-method affects the behavior of connect, causing it to return ++method affects the behavior of connect, causing it to return + with an error in case of a timeout. If that happens, you can still call socket.select with the socket in the + sendt table. The socket will be writable when the connection is +@@ -209,13 +164,88 @@ established. + +
+ Note: Starting with LuaSocket 3.0, the host name resolution +-depends on whether the socket was created by socket.tcp or socket.tcp6. 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 ++socket.tcp, ++socket.tcp4 or ++socket.tcp6. 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. ++
++ ++ ++ ++++master:dirty()
++ ++
++client:dirty()
++server:dirty() ++++Check the read buffer status. ++
++ ++++Returns true if there is any data in the read buffer, false otherwise. ++
++ ++++Note: This is an internal method, use at your own risk. ++
++ ++ ++ ++ ++++master:getfd()
++ ++
++client:getfd()
++server:getfd() ++++Returns the underling socket descriptor or handle associated to the object. ++
++ ++++The descriptor or handle. In case the object has been closed, the return will be -1. ++
++ ++++Note: This is an internal method. Unlikely to be ++portable. Use at your own risk. ++
++ ++ ++ ++ ++++client:getoption(option)
++ ++
++server:getoption(option) ++++Gets options for the TCP object. ++See setoption for description of the ++option names and values. ++
++ ++++Option is a string with the option name. ++
++The method returns the option value in case of success, or ++nil followed by an error message otherwise. +
+ ++ + + ++@@ -227,10 +257,10 @@ Returns information about the remote side of a connected client object. +
+ ++-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 ("inet" or "inet6"). +-In case of error, the method returns nil. ++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 ("inet" or "inet6"). ++In case of error, the method returns nil. +
+ ++@@ -246,13 +276,13 @@ server:getsockname() +
+ ++-Returns the local address information associated to the object. ++Returns the local address information associated to the object. +
+ ++-The method returns a string with local IP address, a number with +-the local port, +-and a string with the family ("inet" or "inet6"). ++The method returns a string with local IP address, a number with ++the local port, ++and a string with the family ("inet" or "inet6"). + In case of error, the method returns nil. +
+ +@@ -266,32 +296,46 @@ server:getstats()+ Returns accounting information on the socket, useful for throttling +-of bandwidth. ++of bandwidth. +
+ ++ 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. +
+ ++ ++ ++
++master:gettimeout()
++client:gettimeout()
++server:gettimeout()
++
++Returns the current block timeout followed by the curent ++total timeout. ++
++ ++ + + +-++
+ master:listen(backlog) +
+ ++ Specifies the socket is willing to receive connections, transforming the +-object into a server object. Server objects support the +-accept, +-getsockname, +-setoption, +-settimeout, +-and close methods. ++object into a server object. Server objects support the ++accept, ++getsockname, ++setoption, ++settimeout, ++and close methods. +
+ ++-The parameter backlog specifies the number of client ++The parameter backlog 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:receive([pattern [, prefix]]) + +
+ Reads data from a client object, according to the specified read +-pattern. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible. ++pattern. Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible. +
+ ++-Pattern can be any of the following: ++Pattern can be any of the following: +
+ ++ Important note: This function was changed severely. 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 nil on error. Thus it was changed +-too. ++too. +
+ + +@@ -366,7 +410,7 @@ Sends data through client object. ++ Data is the string to be sent. The optional arguments + i and j work exactly like the standard +-string.sub Lua function to allow the selection of a ++string.sub Lua function to allow the selection of a + substring to be sent. +
+ +@@ -385,10 +429,10 @@ there was a timeout during the operation. + + ++-Note: Output is not buffered. For small strings, +-it is always better to concatenate them in Lua +-(with the '..' operator) and send the result in one call +-instead of calling the method several times. ++Note: Output is not buffered. For small strings, ++it is always better to concatenate them in Lua ++(with the '..' operator) and send the result in one call ++instead of calling the method several times. +
+ + +@@ -400,12 +444,12 @@ server:setoption(option [, value]) + ++ 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. +
+ ++-Option is a string with the option name, and value ++Option is a string with the option name, and value + depends on the option being set: + +
+-client:getoption(option)
+-server:getoption(option)
+-
+-Gets options for the TCP object. +-See setoption for description of the +-option names and values. +-
+- +-+-Option is a string with the option name. +-
+-The method returns the option value in case of success, or +-nil followed by an error message otherwise. +-
+- + + +
+@@ -485,7 +501,7 @@ server:setstats(received, sent, age)
+
+
+ Resets accounting information on the socket, useful for throttling +-of bandwidth. ++of bandwidth. +
+ ++@@ -495,7 +511,7 @@ of bandwidth. +
+ ++-The method returns 1 in case of success and nil otherwise. ++The method returns 1 in case of success and nil otherwise. +
+ + +@@ -509,8 +525,8 @@ server:settimeout(value [, mode]) ++ Changes the timeout values for the object. By default, + all I/O operations are blocking. That is, any call to the methods +-send, +-receive, and ++send, ++receive, and + accept + will block indefinitely, until the operation completes. The + settimeout 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. +
+ The amount of time to wait is specified as the + value 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: +
+ +
+@@ -562,7 +578,7 @@ client:shutdown(mode)
+
+-Shuts down part of a full-duplex connection. ++Shuts down part of a full-duplex connection. +
+ ++@@ -579,66 +595,107 @@ This is the default mode; + This function returns 1. +
+ +- ++ + +-
+-master:dirty()
+-client:dirty()
+-server:dirty()
++
++master:setfd(fd)
++client:setfd(fd)
++server:setfd(fd)
+
+-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. +
+ ++-Returns true if there is any data in the read buffer, false otherwise. ++No return value. +
+ ++-Note: This is an internal method, any use is unlikely to be portable. ++Note: This is an internal method. Unlikely to be ++portable. Use at your own risk. +
+ +- ++ + +-
+-master:getfd()
+-client:getfd()
+-server:getfd()
++
++socket.tcp() +
+ ++-Returns the underling socket descriptor or handle associated to the object. +-
++Creates and returns an TCP master object. A master object can ++be transformed into a server object with the method ++listen (after a call to bind) or into a client object with ++the method connect. The only other ++method supported by a master object is the ++close method. + ++-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, ++nil is returned, followed by an error message. +
+ ++-Note: This is an internal method, any use is unlikely to be portable. ++Note: The choice between IPv4 and IPv6 happens during a call to ++bind or connect, depending on the address ++family obtained from the resolver. +
+ +- ++++Note: Before the choice between IPv4 and IPv6 happens, ++the internal socket object is invalid and therefore setoption will fail. ++
+ +-
+-master:setfd(fd)
+-client:setfd(fd)
+-server:setfd(fd)
++
++
++
++socket.tcp4() +
+ ++-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 ++listen (after a call to bind) or into a client object with ++the method connect. The only other ++method supported by a master object is the ++close method.
++ ++++In case of success, a new master object is returned. In case of error, ++nil is returned, followed by an error message. ++
++ ++ ++ ++++socket.tcp6() +
+ ++++Creates and returns an IPv6 TCP master object. A master object can ++be transformed into a server object with the method ++listen (after a call to bind) or into a client object with ++the method connect. The only other ++method supported by a master object is the ++close method.
++ ++-No return value. ++In case of success, a new master object is returned. In case of error, ++nil is returned, followed by an error message. +
+ ++-Note: This is an internal method, any use is unlikely to be portable. ++Note: The TCP object returned will have the option ++"ipv6-v6only" set to true. +
+ ++ ++ + + ++-socket.udp() +-
+- +-+-Creates and returns an unconnected IPv4 UDP object. +-Unconnected objects support the +-sendto, +-receive, +-receivefrom, +-getoption, +-getsockname, +-setoption, +-settimeout, +-setpeername, +-setsockname, and +-close. +-The setpeername +-is used to connect the object. +-
+- +-+-In case of success, a new unconnected UDP object +-returned. In case of error, nil is returned, followed by +-an error message. +-
+- +- +- +-+-socket.udp6() +-
+- +-+-Creates and returns an unconnected IPv6 UDP object. +-Unconnected objects support the +-sendto, +-receive, +-receivefrom, +-getoption, +-getsockname, +-setoption, +-settimeout, +-setpeername, +-setsockname, and +-close. +-The setpeername +-is used to connect the object. +-
+- +-+-In case of success, a new unconnected UDP object +-returned. In case of error, nil is returned, followed by +-an error message. +-
+- +-+-Note: The TCP object returned will have the option +-"ipv6-v6only" set to true. +-
+- +- +- +- ++
++connected:getoption()
++unconnected:getoption()
++
++Gets an option value from the UDP object. ++See setoption for ++description of the option names and values. ++
++ ++Option is a string with the option name. ++
++The method returns the option value in case of ++success, or ++nil followed by an error message otherwise. ++
++ + + ++@@ -142,10 +109,10 @@ associated with a connected UDP object. + + +
+-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 ("inet" or "inet6"). +-In case of error, the method returns nil. ++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 ("inet" or "inet6"). ++In case of error, the method returns nil. +
+ ++@@ -165,9 +132,9 @@ Returns the local address information associated to the object. + + +
+-The method returns a string with local IP address, a number with +-the local port, +-and a string with the family ("inet" or "inet6"). ++The method returns a string with local IP address, a number with ++the local port, ++and a string with the family ("inet" or "inet6"). + In case of error, the method returns nil. +
+ +@@ -179,6 +146,18 @@ first time (in which case it is bound to an ephemeral port and the + wild-card address). + + ++ ++ ++
++connected:settimeout(value)
++unconnected:settimeout(value)
++
++Returns the current timeout value. ++
++ ++ + + ++@@ -199,9 +178,12 @@ specifies the maximum size of the datagram to be retrieved. If + there are more than size bytes available in the datagram, + the excess bytes are discarded. If there are less then + size bytes available in the current datagram, the +-available bytes are returned. If size is omitted, the +-maximum datagram size is used (which is currently limited by the +-implementation to 8192 bytes). ++available bytes are returned. ++If size is omitted, the ++compile-time constant socket._DATAGRAMSIZE is used ++(it defaults to 8192 bytes). Larger sizes will cause a ++temporary buffer to be allocated for the operation. +
+ ++@@ -217,46 +199,12 @@ unconnected:receivefrom([size]) +
+ ++-Works exactly as the receive ++Works exactly as the receive + method, except it returns the IP + address and port as extra return values (and is therefore slightly less + efficient). +
+ +- +- +-
+-connected:getoption()
+-unconnected:getoption()
+-
+-Gets an option value from the UDP object. +-See setoption for +-description of the option names and values. +-
+- +-Option is a string with the option name. +-
+-The method returns the option value in case of +-success, or +-nil followed by an error message otherwise. +-
+- + + ++@@ -268,7 +216,7 @@ Sends a datagram to the UDP peer of a connected object. +
+ ++-Datagram is a string with the datagram contents. ++Datagram 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. + +
+ Datagram 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. +-Ip is the IP address of the recipient. ++Ip is the IP address of the recipient. + Host names are not allowed for performance reasons. + + Port 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). +
+ ++ ++ ++
++connected:setoption(option [, value])
++unconnected:setoption(option [, value])
++
++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.
++Option is a string with the option ++name, and value depends on the option being set: ++
++ ++++The method returns 1 in case of success, or ++nil followed by an error message otherwise. ++
++ ++++Note: The descriptions above come from the man pages. ++
++ ++ + + ++@@ -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 send and +-receive methods instead of +-sendto and ++use the send and ++receive methods instead of ++sendto and + receivefrom. +
+ +@@ -406,74 +423,6 @@ system or explicitly by setsockname, it cannot be + changed. + + +- +- +-
+-connected:setoption(option [, value])
+-unconnected:setoption(option [, value])
+-
+-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.
+-Option is a string with the option +-name, and value depends on the option being set: +-
+- +-+-The method returns 1 in case of success, or +-nil followed by an error message otherwise. +-
+- +-+-Note: The descriptions above come from the man pages. +-
+- + + ++@@ -482,14 +431,14 @@ unconnected:settimeout(value) +
+ ++-Changes the timeout values for the object. By default, the +-receive and +-receivefrom ++Changes the timeout values for the object. By default, the ++receive and ++receivefrom + operations are blocking. That is, any call to the methods will block + indefinitely, until data arrives. The settimeout 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. +
+ ++@@ -514,6 +463,114 @@ all other method names already contained verbs making their + imperative nature obvious. +
+ ++ ++ ++++socket.udp() ++
++ ++++Creates and returns an unconnected UDP object. ++Unconnected objects support the ++sendto, ++receive, ++receivefrom, ++getoption, ++getsockname, ++setoption, ++settimeout, ++setpeername, ++setsockname, and ++close. ++The setpeername ++is used to connect the object. ++
++ ++++In case of success, a new unconnected UDP object ++returned. In case of error, nil is returned, followed by ++an error message. ++
++ ++++Note: The choice between IPv4 and IPv6 happens during a call to ++sendto, setpeername, or sockname, depending on the address ++family obtained from the resolver. ++
++ ++++Note: Before the choice between IPv4 and IPv6 happens, ++the internal socket object is invalid and therefore setoption will fail. ++
++ ++ ++ ++++socket.udp4() ++
++ ++++Creates and returns an unconnected IPv4 UDP object. ++Unconnected objects support the ++sendto, ++receive, ++receivefrom, ++getoption, ++getsockname, ++setoption, ++settimeout, ++setpeername, ++setsockname, and ++close. ++The setpeername ++is used to connect the object. ++
++ ++++In case of success, a new unconnected UDP object ++returned. In case of error, nil is returned, followed by ++an error message. ++
++ ++ ++ ++++socket.udp6() ++
++ ++++Creates and returns an unconnected IPv6 UDP object. ++Unconnected objects support the ++sendto, ++receive, ++receivefrom, ++getoption, ++getsockname, ++setoption, ++settimeout, ++setpeername, ++setsockname, and ++close. ++The setpeername ++is used to connect the object. ++
++ ++++In case of success, a new unconnected UDP object ++returned. In case of error, nil is returned, followed by ++an error message. ++
++ ++++Note: The TCP object returned will have the option ++"ipv6-v6only" set to true. ++
++ ++ ++ + + +
+
+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