From 96965b179c7311f850f72a8629b9ba6d3a31d117 Mon Sep 17 00:00:00 2001
From: Diego Nehab <diego@impa.br>
Date: Sat, 22 Aug 2015 19:52:01 -0300
Subject: New agnostic IPv4 IPv6 functions.

Also dealing with EPROTOTYPE Yosemite seems to be throwing
at us for no reason.
---
 doc/reference.html      |   2 +
 doc/tcp.html            | 193 +++++++++++++++++++++++++++---------------------
 doc/udp.html            | 159 +++++++++++++++++++++++----------------
 src/buffer.c            |  24 +++---
 src/inet.c              | 132 +++++++++++++++++----------------
 src/inet.h              |  10 +--
 src/io.h                |   2 +-
 src/socket.lua          |  10 +--
 src/tcp.c               |  85 +++++++--------------
 src/udp.c               |  19 ++++-
 src/usocket.c           |   9 ++-
 test/testclnt.lua       | 100 ++++++++++++-------------
 test/testsrvr.lua       |   2 +-
 test/udpconnectclnt.lua |   2 +-
 14 files changed, 398 insertions(+), 351 deletions(-)

diff --git a/doc/reference.html b/doc/reference.html
index e9bb5eb..6067ba6 100644
--- a/doc/reference.html
+++ b/doc/reference.html
@@ -160,9 +160,11 @@ Support, Manual">
 <a href="socket.html#setsize">_SETSIZE</a>,
 <a href="socket.html#source">source</a>,
 <a href="tcp.html#socket.tcp">tcp</a>,
+<a href="tcp.html#socket.tcp4">tcp4</a>,
 <a href="tcp.html#socket.tcp6">tcp6</a>,
 <a href="socket.html#try">try</a>,
 <a href="udp.html#socket.udp">udp</a>,
+<a href="udp.html#socket.udp4">udp4</a>,
 <a href="udp.html#socket.udp6">udp6</a>,
 <a href="socket.html#version">_VERSION</a>.
 </blockquote>
diff --git a/doc/tcp.html b/doc/tcp.html
index 4226d78..6fc9900 100644
--- a/doc/tcp.html
+++ b/doc/tcp.html
@@ -1,10 +1,10 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" 
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
     "http://www.w3.org/TR/html4/strict.dtd">
 <html>
 
 <head>
 <meta name="description" content="LuaSocket: The TCP/IP support">
-<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support"> 
+<meta name="keywords" content="Lua, LuaSocket, Socket, TCP, Library, Network, Support">
 <title>LuaSocket: TCP/IP support</title>
 <link rel="stylesheet" href="reference.css" type="text/css">
 </head>
@@ -28,7 +28,7 @@
 <a href="index.html#download">download</a> &middot;
 <a href="installation.html">installation</a> &middot;
 <a href="introduction.html">introduction</a> &middot;
-<a href="reference.html">reference</a> 
+<a href="reference.html">reference</a>
 </p>
 </center>
 <hr>
@@ -36,21 +36,48 @@
 
 <!-- tcp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<h2 id="tcp">TCP</h2> 
+<h2 id="tcp">TCP</h2>
 
 <!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id="socket.tcp"> 
+<p class=name id="socket.tcp">
 socket.<b>tcp()</b>
 </p>
 
-<p class=description> 
+<p class=description>
+Creates and returns an TCP master object. A master object can
+be transformed into a server object with the method
+<a href=#listen><tt>listen</tt></a> (after a call to <a
+href=#bind><tt>bind</tt></a>) or into a client object with
+the method <a href=#connect><tt>connect</tt></a>. The only other
+method supported by a master object is the
+<a href=#close><tt>close</tt></a> method.</p>
+
+<p class=return>
+In case of success, a new master object is returned. In case of error,
+<b><tt>nil</tt></b> is returned, followed by an error message.
+</p>
+
+<p class=note>
+Note: The choice between IPv4 and IPv6 happens during a call to
+<a href=#bind><tt>bind</tt></a> or <a
+href=#bind><tt>connect</tt></a>, depending on the address
+family obtained from the resolver.
+</p>
+
+<!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class=name id="socket.tcp4">
+socket.<b>tcp4()</b>
+</p>
+
+<p class=description>
 Creates and returns an IPv4 TCP master object. A master object can
-be transformed into a server object with the method 
+be transformed into a server object with the method
 <a href=#listen><tt>listen</tt></a> (after a call to <a
-href=#bind><tt>bind</tt></a>) or into a client object with 
-the method <a href=#connect><tt>connect</tt></a>. The only other 
-method supported by a master object is the 
+href=#bind><tt>bind</tt></a>) or into a client object with
+the method <a href=#connect><tt>connect</tt></a>. The only other
+method supported by a master object is the
 <a href=#close><tt>close</tt></a> method.</p>
 
 <p class=return>
@@ -60,17 +87,17 @@ In case of success, a new master object is returned. In case of error,
 
 <!-- socket.tcp6 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id="socket.tcp6"> 
+<p class=name id="socket.tcp6">
 socket.<b>tcp6()</b>
 </p>
 
-<p class=description> 
+<p class=description>
 Creates and returns an IPv6 TCP master object. A master object can
-be transformed into a server object with the method 
+be transformed into a server object with the method
 <a href=#listen><tt>listen</tt></a> (after a call to <a
-href=#bind><tt>bind</tt></a>) or into a client object with 
-the method <a href=#connect><tt>connect</tt></a>. The only other 
-method supported by a master object is the 
+href=#bind><tt>bind</tt></a>) or into a client object with
+the method <a href=#connect><tt>connect</tt></a>. The only other
+method supported by a master object is the
 <a href=#close><tt>close</tt></a> method.</p>
 
 <p class=return>
@@ -85,7 +112,7 @@ Note: The TCP object returned will have the option
 
 <!-- accept +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id="accept"> 
+<p class=name id="accept">
 server:<b>accept()</b>
 </p>
 
@@ -95,9 +122,9 @@ object and returns a client object representing that connection.
 </p>
 
 <p class=return>
-If a connection is successfully initiated, a client object is returned.  
+If a connection is successfully initiated, a client object is returned.
 If a  timeout condition  is  met,  the method  returns <b><tt>nil</tt></b>
-followed by the error string '<tt>timeout</tt>'. Other errors are 
+followed by the error string '<tt>timeout</tt>'. Other errors are
 reported by <b><tt>nil</tt></b> followed by a message describing the error.
 </p>
 
@@ -107,28 +134,28 @@ with   a  server   object   in
 the <tt>recvt</tt>  parameter  before  a   call  to  <tt>accept</tt> does
 <em>not</em> guarantee  <tt>accept</tt> will  return immediately.  Use the <a
 href=#settimeout><tt>settimeout</tt></a> method or <tt>accept</tt>
-might block until <em>another</em> client shows up. 
+might block until <em>another</em> client shows up.
 </p>
 
 <!-- bind +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id="bind"> 
+<p class=name id="bind">
 master:<b>bind(</b>address, port<b>)</b>
 </p>
 
 <p class=description>
 Binds a master object to <tt>address</tt> and <tt>port</tt> on the
-local host. 
+local host.
 
 <p class=parameters>
-<tt>Address</tt> can be an IP address or a host name. 
-<tt>Port</tt> must be an integer number in the range [0..64K). 
+<tt>Address</tt> can be an IP address or a host name.
+<tt>Port</tt> must be an integer number in the range [0..64K).
 If <tt>address</tt>
 is '<tt>*</tt>', the system binds to all local interfaces
 using the <tt>INADDR_ANY</tt> constant or
-<tt>IN6ADDR_ANY_INIT</tt>, according to the family. 
+<tt>IN6ADDR_ANY_INIT</tt>, according to the family.
 If <tt>port</tt> is 0, the system automatically
-chooses an ephemeral port.  
+chooses an ephemeral port.
 </p>
 
 <p class=return>
@@ -137,13 +164,13 @@ method returns <b><tt>nil</tt></b> followed by an error message.
 </p>
 
 <p class=note>
-Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a> 
+Note: The function <a href=socket.html#bind><tt>socket.bind</tt></a>
 is available and is a shortcut for the creation of server sockets.
 </p>
 
 <!-- close ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id="close"> 
+<p class=name id="close">
 master:<b>close()</b><br>
 client:<b>close()</b><br>
 server:<b>close()</b>
@@ -154,14 +181,14 @@ Closes  a TCP object. The internal socket used by the object is closed
 and the local  address   to  which the object was
 bound is made  available to other  applications. No further  operations
 (except  for  further calls  to the <tt>close</tt> method)  are allowed on
-a closed socket. 
+a closed socket.
 </p>
 
 <p class=note>
 Note:  It is  important to  close all  used  sockets once  they are  not
 needed,  since, in  many systems,  each socket  uses a  file descriptor,
 which are limited system resources. Garbage-collected objects are
-automatically closed before destruction, though. 
+automatically closed before destruction, though.
 </p>
 
 <!-- connect ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -172,19 +199,19 @@ master:<b>connect(</b>address, port<b>)</b>
 
 <p class=description>
 Attempts to connect a master object to a remote host, transforming it into a
-client object. 
-Client objects support methods 
+client object.
+Client objects support methods
 <a href=#send><tt>send</tt></a>,
-<a href=#receive><tt>receive</tt></a>, 
-<a href=#getsockname><tt>getsockname</tt></a>, 
+<a href=#receive><tt>receive</tt></a>,
+<a href=#getsockname><tt>getsockname</tt></a>,
 <a href=#getpeername><tt>getpeername</tt></a>,
-<a href=#settimeout><tt>settimeout</tt></a>, 
+<a href=#settimeout><tt>settimeout</tt></a>,
 and <a href=#close><tt>close</tt></a>.
 </p>
 
 <p class=parameters>
-<tt>Address</tt> can be an IP address or a host name. 
-<tt>Port</tt> must be an integer number in the range [1..64K). 
+<tt>Address</tt> can be an IP address or a host name.
+<tt>Port</tt> must be an integer number in the range [1..64K).
 </p>
 
 <p class=return>
@@ -193,14 +220,14 @@ describing the error. In case of success, the method returns 1.
 </p>
 
 <p class=note>
-Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a> 
+Note: The function <a href=socket.html#connect><tt>socket.connect</tt></a>
 is available and is a shortcut for the creation of client sockets.
 </p>
 
 <p class=note>
-Note: Starting with LuaSocket 2.0, 
+Note: Starting with LuaSocket 2.0,
 the <a href=#settimeout><tt>settimeout</tt></a>
-method affects the behavior of <tt>connect</tt>, causing it to return 
+method affects the behavior of <tt>connect</tt>, causing it to return
 with an error in case of a timeout. If that happens, you can still call <a
 href=socket.html#select><tt>socket.select</tt></a> with the socket in the
 <tt>sendt</tt> table. The socket will be writable when the connection is
@@ -227,10 +254,10 @@ Returns information about the remote side of a connected client object.
 </p>
 
 <p class=return>
-Returns a string with the IP address of the peer, the 
-port number that peer is using for the connection, 
-and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 
-In case of error, the method returns <b><tt>nil</tt></b>. 
+Returns a string with the IP address of the peer, the
+port number that peer is using for the connection,
+and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
+In case of error, the method returns <b><tt>nil</tt></b>.
 </p>
 
 <p class=note>
@@ -246,13 +273,13 @@ server:<b>getsockname()</b>
 </p>
 
 <p class=description>
-Returns the local address information associated to the object. 
+Returns the local address information associated to the object.
 </p>
 
 <p class=return>
-The method returns a string with local IP address, a number with 
-the local port, 
-and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 
+The method returns a string with local IP address, a number with
+the local port,
+and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
 In case of error, the method returns <b><tt>nil</tt></b>.
 </p>
 
@@ -266,32 +293,32 @@ server:<b>getstats()</b><br>
 
 <p class=description>
 Returns accounting information on the socket, useful for throttling
-of bandwidth. 
+of bandwidth.
 </p>
 
 <p class=return>
 The method returns the number of bytes received, the number of bytes sent,
-and the age of the socket object in seconds. 
+and the age of the socket object in seconds.
 </p>
 
 <!-- listen ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<p class=name id="listen"> 
+<p class=name id="listen">
 master:<b>listen(</b>backlog<b>)</b>
 </p>
 
 <p class=description>
 Specifies the socket is willing to receive connections, transforming the
-object into a server object.  Server objects support the 
-<a href=#accept><tt>accept</tt></a>,  
-<a href=#getsockname><tt>getsockname</tt></a>, 
-<a href=#setoption><tt>setoption</tt></a>, 
-<a href=#settimeout><tt>settimeout</tt></a>, 
-and <a href=#close><tt>close</tt></a> methods.  
+object into a server object.  Server objects support the
+<a href=#accept><tt>accept</tt></a>,
+<a href=#getsockname><tt>getsockname</tt></a>,
+<a href=#setoption><tt>setoption</tt></a>,
+<a href=#settimeout><tt>settimeout</tt></a>,
+and <a href=#close><tt>close</tt></a> methods.
 </p>
 
 <p class=parameters>
-The parameter <tt>backlog</tt> specifies the  number  of  client 
+The parameter <tt>backlog</tt> specifies the  number  of  client
 connections that can
 be queued waiting for service. If the queue is full and another  client
 attempts connection,  the connection is  refused.
@@ -310,11 +337,11 @@ client:<b>receive(</b>[pattern [, prefix]]<b>)</b>
 
 <p class=description>
 Reads data from a client object, according to the specified <em>read
-pattern</em>.  Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible. 
+pattern</em>.  Patterns follow the Lua file I/O format, and the difference in performance between all patterns is negligible.
 </p>
 
 <p class=parameters>
-<tt>Pattern</tt> can be any of the following: 
+<tt>Pattern</tt> can be any of the following:
 </p>
 
 <ul>
@@ -325,7 +352,7 @@ terminated by a  LF character (ASCII&nbsp;10), optionally  preceded by a
 CR character (ASCII&nbsp;13). The CR and LF characters are not included in
 the returned line. In fact, <em>all</em> CR characters are
 ignored by the pattern. This is the default pattern;
-<li> <tt>number</tt>:  causes the  method to read  a specified <tt>number</tt> 
+<li> <tt>number</tt>:  causes the  method to read  a specified <tt>number</tt>
 of bytes from the socket.
 </ul>
 
@@ -347,10 +374,10 @@ closed  before  the transmission  was completed  or  the string
 <p class=note>
 <b>Important note</b>: This function was changed <em>severely</em>. It used
 to support multiple patterns (but I have never seen this feature used) and
-now it doesn't anymore.  Partial results used to be returned in the same 
+now it doesn't anymore.  Partial results used to be returned in the same
 way as successful results. This last feature violated the idea that all
 functions should return <tt><b>nil</b></tt> on error.  Thus it was changed
-too. 
+too.
 </p>
 
 <!-- send +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -366,7 +393,7 @@ Sends <tt>data</tt> through client object.
 <p class=parameters>
 <tt>Data</tt> is the string to be sent. The optional arguments
 <tt>i</tt> and <tt>j</tt> work exactly like the standard
-<tt>string.sub</tt> Lua function to allow the selection of a 
+<tt>string.sub</tt> Lua function to allow the selection of a
 substring to be sent.
 </p>
 
@@ -385,10 +412,10 @@ there was  a  timeout  during  the operation.
 </p>
 
 <p class=note>
-Note: Output is <em>not</em> buffered. For small strings, 
-it is always better to concatenate them in Lua 
-(with the '<tt>..</tt>' operator) and send the result in one call 
-instead of calling the method several times. 
+Note: Output is <em>not</em> buffered. For small strings,
+it is always better to concatenate them in Lua
+(with the '<tt>..</tt>' operator) and send the result in one call
+instead of calling the method several times.
 </p>
 
 <!-- setoption ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -400,12 +427,12 @@ server:<b>setoption(</b>option [, value]<b>)</b>
 
 <p class=description>
 Sets options for the TCP object. Options are only needed by low-level or
-time-critical applications. You should only modify an option if you 
-are sure you need it. 
+time-critical applications. You should only modify an option if you
+are sure you need it.
 </p>
 
 <p class=parameters>
-<tt>Option</tt> is a string with the option name, and <tt>value</tt> 
+<tt>Option</tt> is a string with the option name, and <tt>value</tt>
 depends on the option being set:
 
 <ul>
@@ -413,7 +440,7 @@ depends on the option being set:
 <li> '<tt>keepalive</tt>':  Setting this option to <tt>true</tt> enables
 the periodic transmission of messages on a connected socket. Should the
 connected party fail to respond to these messages, the connection is
-considered broken and processes using the socket are notified; 
+considered broken and processes using the socket are notified;
 
 <li> '<tt>linger</tt>': Controls the action taken when unsent data are
 queued on a socket and a close is performed.  The value is a table with a
@@ -424,13 +451,13 @@ it is able to transmit the data or until '<tt>timeout</tt>' has passed. If
 '<tt>on</tt>' is <tt>false</tt> and a close is issued, the system will
 process the close in a manner that allows the process to continue as
 quickly as possible. I do not advise you to set this to anything other than
-zero; 
+zero;
 
 <li> '<tt>reuseaddr</tt>': Setting this option indicates that the rules
-used in validating addresses supplied in a call to 
+used in validating addresses supplied in a call to
 <a href=#bind><tt>bind</tt></a> should allow reuse of local addresses;
 
-<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt> 
+<li> '<tt>tcp-nodelay</tt>': Setting this option to <tt>true</tt>
 disables the Nagle's algorithm for the connection;
 
 <li> '<tt>ipv6-v6only</tt>':
@@ -485,7 +512,7 @@ server:<b>setstats(</b>received, sent, age<b>)</b><br>
 
 <p class=description>
 Resets accounting information on the socket, useful for throttling
-of bandwidth. 
+of bandwidth.
 </p>
 
 <p class=parameters>
@@ -495,7 +522,7 @@ of bandwidth.
 </p>
 
 <p class=return>
-The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise. 
+The method returns 1 in case of success and <tt><b>nil</b></tt> otherwise.
 </p>
 
 <!-- settimeout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -509,8 +536,8 @@ server:<b>settimeout(</b>value [, mode]<b>)</b>
 <p class=description>
 Changes the timeout  values for the object. By default,
 all I/O  operations are  blocking. That  is, any  call to  the methods
-<a href=#send><tt>send</tt></a>, 
-<a href=#receive><tt>receive</tt></a>, and 
+<a href=#send><tt>send</tt></a>,
+<a href=#receive><tt>receive</tt></a>, and
 <a href=#accept><tt>accept</tt></a>
 will  block indefinitely,  until the operation completes.  The
 <tt>settimeout</tt>  method defines a  limit on the  amount  of   time  the
@@ -521,7 +548,7 @@ time has elapsed, the affected methods give up and fail with an error code.
 <p class=parameters>
 The amount of time to wait is specified  as  the
 <tt>value</tt> parameter, in seconds. There  are two timeout  modes and
-both can be used together for fine tuning: 
+both can be used together for fine tuning:
 </p>
 
 <ul>
@@ -532,7 +559,7 @@ default mode;</li>
 
 <li> '<tt>t</tt>':  <em>total</em> timeout. Specifies the  upper limit on
 the amount of  time LuaSocket can block a Lua  script before returning from
-a call.</li> 
+a call.</li>
 </ul>
 
 <p class=parameters>
@@ -562,7 +589,7 @@ client:<b>shutdown(</b>mode<b>)</b><br>
 </p>
 
 <p class=description>
-Shuts down part of a full-duplex connection. 
+Shuts down part of a full-duplex connection.
 </p>
 
 <p class=parameters>
@@ -608,7 +635,7 @@ server:<b>getfd()</b>
 </p>
 
 <p class=description>
-Returns the underling socket descriptor or handle associated to the object. 
+Returns the underling socket descriptor or handle associated to the object.
 </p>
 
 <p class=return>
diff --git a/doc/udp.html b/doc/udp.html
index e5b0ad0..e313af4 100644
--- a/doc/udp.html
+++ b/doc/udp.html
@@ -4,7 +4,7 @@
 
 <head>
 <meta name="description" content="LuaSocket: The UDP support">
-<meta name="keywords" content="Lua, LuaSocket, Socket, UDP, Library, Network, Support"> 
+<meta name="keywords" content="Lua, LuaSocket, Socket, UDP, Library, Network, Support">
 <title>LuaSocket: UDP support</title>
 <link rel="stylesheet" href="reference.css" type="text/css">
 </head>
@@ -28,7 +28,7 @@
 <a href="index.html#download">download</a> &middot;
 <a href="installation.html">installation</a> &middot;
 <a href="introduction.html">introduction</a> &middot;
-<a href="reference.html">reference</a> 
+<a href="reference.html">reference</a>
 </p>
 </center>
 <hr>
@@ -37,7 +37,7 @@
 
 <!-- udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
-<h2 id="udp">UDP</h2> 
+<h2 id="udp">UDP</h2>
 
 <!-- socket.udp ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
@@ -46,19 +46,56 @@ socket.<b>udp()</b>
 </p>
 
 <p class="description">
-Creates and returns an unconnected IPv4 UDP object. 
-Unconnected objects support the 
-<a href="#sendto"><tt>sendto</tt></a>, 
-<a href="#receive"><tt>receive</tt></a>, 
-<a href="#receivefrom"><tt>receivefrom</tt></a>, 
-<a href="#getoption"><tt>getoption</tt></a>, 
-<a href="#getsockname"><tt>getsockname</tt></a>, 
-<a href="#setoption"><tt>setoption</tt></a>, 
-<a href="#settimeout"><tt>settimeout</tt></a>, 
-<a href="#setpeername"><tt>setpeername</tt></a>, 
-<a href="#setsockname"><tt>setsockname</tt></a>, and 
-<a href="#close"><tt>close</tt></a>. 
-The <a href="#setpeername"><tt>setpeername</tt></a> 
+Creates and returns an unconnected UDP object.
+Unconnected objects support the
+<a href="#sendto"><tt>sendto</tt></a>,
+<a href="#receive"><tt>receive</tt></a>,
+<a href="#receivefrom"><tt>receivefrom</tt></a>,
+<a href="#getoption"><tt>getoption</tt></a>,
+<a href="#getsockname"><tt>getsockname</tt></a>,
+<a href="#setoption"><tt>setoption</tt></a>,
+<a href="#settimeout"><tt>settimeout</tt></a>,
+<a href="#setpeername"><tt>setpeername</tt></a>,
+<a href="#setsockname"><tt>setsockname</tt></a>, and
+<a href="#close"><tt>close</tt></a>.
+The <a href="#setpeername"><tt>setpeername</tt></a>
+is used to connect the object.
+</p>
+
+<p class="return">
+In case of success, a new unconnected UDP object
+returned. In case of error, <b><tt>nil</tt></b> is returned, followed by
+an error message.
+</p>
+
+<p class=note>
+Note: The choice between IPv4 and IPv6 happens during a call to
+<a href=#sendto><tt>sendto</tt></a>, <a
+href=#setpeername><tt>setpeername</tt></a>, or <a
+href=#setsockname><tt>sockname</tt></a>, depending on the address
+family obtained from the resolver.
+</p>
+
+<!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
+
+<p class="name" id="socket.udp">
+socket.<b>udp4()</b>
+</p>
+
+<p class="description">
+Creates and returns an unconnected IPv4 UDP object.
+Unconnected objects support the
+<a href="#sendto"><tt>sendto</tt></a>,
+<a href="#receive"><tt>receive</tt></a>,
+<a href="#receivefrom"><tt>receivefrom</tt></a>,
+<a href="#getoption"><tt>getoption</tt></a>,
+<a href="#getsockname"><tt>getsockname</tt></a>,
+<a href="#setoption"><tt>setoption</tt></a>,
+<a href="#settimeout"><tt>settimeout</tt></a>,
+<a href="#setpeername"><tt>setpeername</tt></a>,
+<a href="#setsockname"><tt>setsockname</tt></a>, and
+<a href="#close"><tt>close</tt></a>.
+The <a href="#setpeername"><tt>setpeername</tt></a>
 is used to connect the object.
 </p>
 
@@ -75,19 +112,19 @@ socket.<b>udp6()</b>
 </p>
 
 <p class="description">
-Creates and returns an unconnected IPv6 UDP object. 
-Unconnected objects support the 
-<a href="#sendto"><tt>sendto</tt></a>, 
-<a href="#receive"><tt>receive</tt></a>, 
-<a href="#receivefrom"><tt>receivefrom</tt></a>, 
-<a href="#getoption"><tt>getoption</tt></a>, 
-<a href="#getsockname"><tt>getsockname</tt></a>, 
-<a href="#setoption"><tt>setoption</tt></a>, 
-<a href="#settimeout"><tt>settimeout</tt></a>, 
-<a href="#setpeername"><tt>setpeername</tt></a>, 
-<a href="#setsockname"><tt>setsockname</tt></a>, and 
-<a href="#close"><tt>close</tt></a>. 
-The <a href="#setpeername"><tt>setpeername</tt></a> 
+Creates and returns an unconnected IPv6 UDP object.
+Unconnected objects support the
+<a href="#sendto"><tt>sendto</tt></a>,
+<a href="#receive"><tt>receive</tt></a>,
+<a href="#receivefrom"><tt>receivefrom</tt></a>,
+<a href="#getoption"><tt>getoption</tt></a>,
+<a href="#getsockname"><tt>getsockname</tt></a>,
+<a href="#setoption"><tt>setoption</tt></a>,
+<a href="#settimeout"><tt>settimeout</tt></a>,
+<a href="#setpeername"><tt>setpeername</tt></a>,
+<a href="#setsockname"><tt>setsockname</tt></a>, and
+<a href="#close"><tt>close</tt></a>.
+The <a href="#setpeername"><tt>setpeername</tt></a>
 is used to connect the object.
 </p>
 
@@ -102,10 +139,6 @@ Note: The TCP object returned will have the option
 "<tt>ipv6-v6only</tt>" set to <tt><b>true</b></tt>.
 </p>
 
-
-
-<!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
-
 <!-- close +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class="name" id="close">
@@ -142,10 +175,10 @@ associated with a connected UDP object.
 
 
 <p class=return>
-Returns a string with the IP address of the peer, the 
-port number that peer is using for the connection, 
-and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 
-In case of error, the method returns <b><tt>nil</tt></b>. 
+Returns a string with the IP address of the peer, the
+port number that peer is using for the connection,
+and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
+In case of error, the method returns <b><tt>nil</tt></b>.
 </p>
 
 <p class="note">
@@ -165,9 +198,9 @@ Returns the local address information associated to the object.
 
 
 <p class=return>
-The method returns a string with local IP address, a number with 
-the local port, 
-and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>"). 
+The method returns a string with local IP address, a number with
+the local port,
+and a string with the family ("<tt>inet</tt>" or "<tt>inet6</tt>").
 In case of error, the method returns <b><tt>nil</tt></b>.
 </p>
 
@@ -217,7 +250,7 @@ unconnected:<b>receivefrom(</b>[size]<b>)</b>
 </p>
 
 <p class="description">
-Works exactly as the <a href="#receive"><tt>receive</tt></a> 
+Works exactly as the <a href="#receive"><tt>receive</tt></a>
 method, except it returns the IP
 address and port as extra return values (and is therefore slightly less
 efficient).
@@ -236,7 +269,7 @@ See <a href=#setoption><tt>setoption</tt></a> for
 description of the option names and values.
 </p>
 
-<p class="parameters"><tt>Option</tt> is a string with the option name. 
+<p class="parameters"><tt>Option</tt> is a string with the option name.
 <ul>
 <li> '<tt>dontroute</tt>'
 <li> '<tt>broadcast</tt>'
@@ -246,9 +279,9 @@ description of the option names and values.
 <li> '<tt>ipv6-v6only</tt>'
 <li> '<tt>ip-multicast-if</tt>'
 <li> '<tt>ip-multicast-ttl</tt>'
-<li> '<tt>ip-add-membership</tt>' 
+<li> '<tt>ip-add-membership</tt>'
 <li> '<tt>ip-drop-membership</tt>'
-</ul> 
+</ul>
 </p>
 
 <p class=return>
@@ -268,7 +301,7 @@ Sends a datagram to the UDP peer of a connected object.
 </p>
 
 <p class="parameters">
-<tt>Datagram</tt> is a string with the datagram contents. 
+<tt>Datagram</tt> is a string with the datagram contents.
 The maximum datagram size for UDP is 64K minus IP layer overhead.
 However datagrams larger than the link layer packet size will be
 fragmented, which may deteriorate performance and/or reliability.
@@ -298,11 +331,11 @@ Sends a datagram to the specified IP address and port number.
 
 <p class="parameters">
 <tt>Datagram</tt> is a string with the
-datagram contents. 
+datagram contents.
 The maximum datagram size for UDP is 64K minus IP layer overhead.
 However datagrams larger than the link layer packet size will be
 fragmented, which may deteriorate performance and/or reliability.
-<tt>Ip</tt> is the IP address of the recipient. 
+<tt>Ip</tt> is the IP address of the recipient.
 Host names are <em>not</em> allowed for performance reasons.
 
 <tt>Port</tt> is the port number at the recipient.
@@ -337,9 +370,9 @@ object or vice versa.
 For connected objects, outgoing datagrams
 will be sent to the specified peer, and datagrams received from
 other peers will be discarded by the OS. Connected UDP objects must
-use the <a href="#send"><tt>send</tt></a> and 
-<a href="#receive"><tt>receive</tt></a> methods instead of 
-<a href="#sendto"><tt>sendto</tt></a> and 
+use the <a href="#send"><tt>send</tt></a> and
+<a href="#receive"><tt>receive</tt></a> methods instead of
+<a href="#sendto"><tt>sendto</tt></a> and
 <a href="#receivefrom"><tt>receivefrom</tt></a>.
 </p>
 
@@ -421,16 +454,16 @@ only modify an option if you are sure you need it.</p>
 name, and <tt>value</tt> depends on the option being set:
 </p>
 
-<ul> 
+<ul>
 <li> '<tt>dontroute</tt>': Indicates that outgoing
 messages should bypass the standard routing facilities.
 Receives a boolean value;
-<li> '<tt>broadcast</tt>': Requests permission to send 
+<li> '<tt>broadcast</tt>': Requests permission to send
 broadcast datagrams on the socket.
 Receives a boolean value;
 <li> '<tt>reuseaddr</tt>': Indicates that the rules used in
-validating addresses supplied in a <tt>bind()</tt> call 
-should allow reuse of local addresses. 
+validating addresses supplied in a <tt>bind()</tt> call
+should allow reuse of local addresses.
 Receives a boolean value;
 <li> '<tt>reuseport</tt>': Allows completely duplicate
 bindings by multiple processes if they all set
@@ -442,7 +475,7 @@ datagram is delivered to the sending host as long as it is a
 member of the multicast group.
 Receives a boolean value;
 <li> '<tt>ipv6-v6only</tt>':
-Specifies whether to restrict <tt>inet6</tt> sockets to 
+Specifies whether to restrict <tt>inet6</tt> sockets to
 sending and receiving only IPv6 packets.
 Receive a boolean value;
 <li> '<tt>ip-multicast-if</tt>':
@@ -451,9 +484,9 @@ are sent.
 Receives an IP address;
 <li> '<tt>ip-multicast-ttl</tt>':
 Sets the Time To Live in the IP header for outgoing
-multicast datagrams. 
+multicast datagrams.
 Receives a number;
-<li> '<tt>ip-add-membership</tt>': 
+<li> '<tt>ip-add-membership</tt>':
 Joins the multicast group specified.
 Receives a table with fields
 <tt>multiaddr</tt> and <tt>interface</tt>, each containing an
@@ -463,7 +496,7 @@ group specified.
 Receives a table with fields
 <tt>multiaddr</tt> and <tt>interface</tt>, each containing an
 IP address.
-</ul> 
+</ul>
 
 <p class="return">
 The method returns 1 in case of success, or
@@ -482,14 +515,14 @@ unconnected:<b>settimeout(</b>value<b>)</b>
 </p>
 
 <p class="description">
-Changes the timeout values for the object.  By default, the 
-<a href="#receive"><tt>receive</tt></a> and 
-<a href="#receivefrom"><tt>receivefrom</tt></a> 
+Changes the timeout values for the object.  By default, the
+<a href="#receive"><tt>receive</tt></a> and
+<a href="#receivefrom"><tt>receivefrom</tt></a>
 operations are blocking. That is, any call to the methods will block
 indefinitely, until data arrives.  The <tt>settimeout</tt> function defines
 a limit on the amount of time the functions can block. When a timeout is
 set and the specified amount of time has elapsed, the affected methods
-give up and fail with an error code.  
+give up and fail with an error code.
 </p>
 
 <p class="parameters">
@@ -524,7 +557,7 @@ imperative nature obvious.
 <a href="index.html#download">download</a> &middot;
 <a href="installation.html">installation</a> &middot;
 <a href="introduction.html">introduction</a> &middot;
-<a href="reference.html">reference</a> 
+<a href="reference.html">reference</a>
 </p>
 <p>
 <small>
diff --git a/src/buffer.c b/src/buffer.c
index 8fc1166..fff1634 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -38,7 +38,7 @@ int buffer_open(lua_State *L) {
 }
 
 /*-------------------------------------------------------------------------*\
-* Initializes C structure 
+* Initializes C structure
 \*-------------------------------------------------------------------------*/
 void buffer_init(p_buffer buf, p_io io, p_timeout tm) {
     buf->first = buf->last = 0;
@@ -62,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;
@@ -88,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));
@@ -111,7 +111,7 @@ int buffer_meth_receive(lua_State *L, p_buffer buf) {
     size_t size;
     const char *part = luaL_optlstring(L, 3, "", &size);
     timeout_markstart(buf->tm);
-    /* initialize buffer with optional extra prefix 
+    /* initialize buffer with optional extra prefix
      * (useful for concatenating previous partial results) */
     luaL_buffinit(L, &b);
     luaL_addlstring(&b, part, size);
@@ -119,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)
@@ -135,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 {
@@ -219,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) {
@@ -249,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/inet.c b/src/inet.c
index 68087db..8f0fac2 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -94,7 +94,7 @@ static int inet_global_getnameinfo(lua_State *L) {
 
     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) {
@@ -105,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);
@@ -146,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)];
 }
@@ -167,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);
@@ -177,7 +177,7 @@ 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);
@@ -198,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);
@@ -254,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;
 }
@@ -279,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);
@@ -288,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;
 }
@@ -354,21 +362,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));
         }
     }
@@ -383,6 +391,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));
@@ -397,23 +406,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, 
+            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 */
+            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 (err == NULL) {
+            *family = current_family;
+            break;
+        }
     }
     freeaddrinfo(resolved);
     /* here, if err is set, we failed */
@@ -423,29 +432,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";
@@ -457,35 +464,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,
+        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)
-                continue;
+            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)
@@ -510,7 +514,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;
@@ -527,7 +531,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..b85c20e 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
@@ -27,8 +27,8 @@ int inet_open(lua_State *L);
 const char *inet_trycreate(p_socket ps, int family, int type);
 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.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/socket.lua b/src/socket.lua
index 3913e6f..d1c0b16 100644
--- a/src/socket.lua
+++ b/src/socket.lua
@@ -32,23 +32,23 @@ function _M.bind(host, port, backlog)
     err = "no info on address"
     for i, alt in base.ipairs(addrinfo) do
         if alt.family == "inet" then
-            sock, err = socket.tcp()
+            sock, err = socket.tcp4()
         else
             sock, err = socket.tcp6()
         end
         if not sock then return nil, err end
         sock:setoption("reuseaddr", true)
         res, err = sock:bind(alt.addr, port)
-        if not res then 
+        if not res then
             sock:close()
-        else 
+        else
             res, err = sock:listen(backlog)
-            if not res then 
+            if not res then
                 sock:close()
             else
                 return sock
             end
-        end 
+        end
     end
     return nil, err
 end
diff --git a/src/tcp.c b/src/tcp.c
index dcac0c8..4d12f08 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -18,6 +18,7 @@
 * Internal function prototypes
 \*=========================================================================*/
 static int global_create(lua_State *L);
+static int global_create4(lua_State *L);
 static int global_create6(lua_State *L);
 static int global_connect(lua_State *L);
 static int meth_connect(lua_State *L);
@@ -90,6 +91,7 @@ static t_opt optset[] = {
 /* functions in library namespace */
 static luaL_Reg func[] = {
     {"tcp", global_create},
+    {"tcp4", global_create4},
     {"tcp6", global_create6},
     {"connect", global_connect},
     {NULL, NULL}
@@ -213,8 +215,7 @@ static int meth_accept(lua_State *L)
 /*-------------------------------------------------------------------------*\
 * Binds an object to an address
 \*-------------------------------------------------------------------------*/
-static int meth_bind(lua_State *L)
-{
+static int meth_bind(lua_State *L) {
     p_tcp tcp = (p_tcp) auxiliar_checkclass(L, "tcp{master}", 1);
     const char *address =  luaL_checkstring(L, 2);
     const char *port = luaL_checkstring(L, 3);
@@ -224,7 +225,7 @@ static int meth_bind(lua_State *L)
     bindhints.ai_socktype = SOCK_STREAM;
     bindhints.ai_family = tcp->family;
     bindhints.ai_flags = AI_PASSIVE;
-    err = inet_trybind(&tcp->sock, address, port, &bindhints);
+    err = inet_trybind(&tcp->sock, &tcp->family, address, port, &bindhints);
     if (err) {
         lua_pushnil(L);
         lua_pushstring(L, err);
@@ -237,8 +238,7 @@ static int meth_bind(lua_State *L)
 /*-------------------------------------------------------------------------*\
 * Turns a master tcp object into a client object.
 \*-------------------------------------------------------------------------*/
-static int meth_connect(lua_State *L)
-{
+static int meth_connect(lua_State *L) {
     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
     const char *address =  luaL_checkstring(L, 2);
     const char *port = luaL_checkstring(L, 3);
@@ -249,7 +249,7 @@ static int meth_connect(lua_State *L)
     /* make sure we try to connect only to the same family */
     connecthints.ai_family = tcp->family;
     timeout_markstart(&tcp->tm);
-    err = inet_tryconnect(&tcp->sock, &tcp->family, address, port, 
+    err = inet_tryconnect(&tcp->sock, &tcp->family, address, port,
         &tcp->tm, &connecthints);
     /* have to set the class even if it failed due to non-blocking connects */
     auxiliar_setclass(L, "tcp{client}", 1);
@@ -279,9 +279,12 @@ static int meth_close(lua_State *L)
 static int meth_getfamily(lua_State *L)
 {
     p_tcp tcp = (p_tcp) auxiliar_checkgroup(L, "tcp{any}", 1);
-    if (tcp->family == PF_INET6) {
+    if (tcp->family == AF_INET6) {
         lua_pushliteral(L, "inet6");
         return 1;
+    } else if (tcp->family == AF_INET) {
+        lua_pushliteral(L, "inet4");
+        return 1;
     } else {
         lua_pushliteral(L, "inet4");
         return 1;
@@ -353,7 +356,12 @@ static int meth_settimeout(lua_State *L)
 \*-------------------------------------------------------------------------*/
 static int tcp_create(lua_State *L, int family) {
     t_socket sock;
-    const char *err = inet_trycreate(&sock, family, SOCK_STREAM);
+    /* if family is AF_UNSPEC, we create an AF_INET socket
+     * but store AF_UNSPEC into tcp-family. This will allow it
+     * later be replaced with an AF_INET6 socket if
+     * trybind or tryconnect prefer it instead. */
+    const char *err = inet_trycreate(&sock, family == AF_UNSPEC?
+        AF_INET: family, SOCK_STREAM);
     /* try to allocate a system socket */
     if (!err) {
         /* allocate tcp object */
@@ -363,7 +371,7 @@ static int tcp_create(lua_State *L, int family) {
         auxiliar_setclass(L, "tcp{master}", -1);
         /* initialize remaining structure fields */
         socket_setnonblocking(&sock);
-        if (family == PF_INET6) {
+        if (family == AF_INET6) {
             int yes = 1;
             setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
                 (void *)&yes, sizeof(yes));
@@ -383,6 +391,10 @@ static int tcp_create(lua_State *L, int family) {
 }
 
 static int global_create(lua_State *L) {
+    return tcp_create(L, AF_UNSPEC);
+}
+
+static int global_create4(lua_State *L) {
     return tcp_create(L, AF_INET);
 }
 
@@ -390,53 +402,6 @@ static int global_create6(lua_State *L) {
     return tcp_create(L, AF_INET6);
 }
 
-#if 0
-static const char *tryconnect6(const char *remoteaddr, const char *remoteserv,
-    struct addrinfo *connecthints, p_tcp tcp) {
-    struct addrinfo *iterator = NULL, *resolved = NULL;
-    const char *err = NULL;
-    /* try resolving */
-    err = socket_gaistrerror(getaddrinfo(remoteaddr, remoteserv,
-                connecthints, &resolved));
-    if (err != NULL) {
-        if (resolved) freeaddrinfo(resolved);
-        return err;
-    }
-    /* iterate over all returned addresses trying to connect */
-    for (iterator = resolved; iterator; iterator = iterator->ai_next) {
-        p_timeout tm = timeout_markstart(&tcp->tm);
-        /* create new socket if necessary. if there was no
-         * bind, we need to create one for every new family
-         * that shows up while iterating. if there was a
-         * bind, all families will be the same and we will
-         * not enter this branch. */
-        if (tcp->family != iterator->ai_family) {
-            socket_destroy(&tcp->sock);
-            err = socket_strerror(socket_create(&tcp->sock,
-                iterator->ai_family, iterator->ai_socktype,
-                iterator->ai_protocol));
-            if (err != NULL) {
-                freeaddrinfo(resolved);
-                return err;
-            }
-            tcp->family = iterator->ai_family;
-            /* all sockets initially non-blocking */
-            socket_setnonblocking(&tcp->sock);
-        }
-        /* finally try connecting to remote address */
-        err = socket_strerror(socket_connect(&tcp->sock,
-            (SA *) iterator->ai_addr,
-            (socklen_t) iterator->ai_addrlen, tm));
-        /* if success, break out of loop */
-        if (err == NULL) break;
-    }
-
-    freeaddrinfo(resolved);
-    /* here, if err is set, we failed */
-    return err;
-}
-#endif
-
 static int global_connect(lua_State *L) {
     const char *remoteaddr = luaL_checkstring(L, 1);
     const char *remoteserv = luaL_checkstring(L, 2);
@@ -453,26 +418,26 @@ static int global_connect(lua_State *L) {
     timeout_init(&tcp->tm, -1, -1);
     buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
     tcp->sock = SOCKET_INVALID;
-    tcp->family = PF_UNSPEC;
+    tcp->family = AF_UNSPEC;
     /* allow user to pick local address and port */
     memset(&bindhints, 0, sizeof(bindhints));
     bindhints.ai_socktype = SOCK_STREAM;
     bindhints.ai_family = family;
     bindhints.ai_flags = AI_PASSIVE;
     if (localaddr) {
-        err = inet_trybind(&tcp->sock, localaddr, localserv, &bindhints);
+        err = inet_trybind(&tcp->sock, &tcp->family, localaddr, 
+            localserv, &bindhints);
         if (err) {
             lua_pushnil(L);
             lua_pushstring(L, err);
             return 2;
         }
-        tcp->family = bindhints.ai_family;
     }
     /* try to connect to remote address and port */
     memset(&connecthints, 0, sizeof(connecthints));
     connecthints.ai_socktype = SOCK_STREAM;
     /* make sure we try to connect only to the same family */
-    connecthints.ai_family = bindhints.ai_family;
+    connecthints.ai_family = tcp->family; 
     err = inet_tryconnect(&tcp->sock, &tcp->family, remoteaddr, remoteserv,
          &tcp->tm, &connecthints);
     if (err) {
diff --git a/src/udp.c b/src/udp.c
index 7ff00f5..6600859 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -27,6 +27,7 @@
 * Internal function prototypes
 \*=========================================================================*/
 static int global_create(lua_State *L);
+static int global_create4(lua_State *L);
 static int global_create6(lua_State *L);
 static int meth_send(lua_State *L);
 static int meth_sendto(lua_State *L);
@@ -107,6 +108,7 @@ static t_opt optget[] = {
 /* functions in library namespace */
 static luaL_Reg func[] = {
     {"udp", global_create},
+    {"udp4", global_create4},
     {"udp6", global_create6},
     {NULL, NULL}
 };
@@ -264,7 +266,7 @@ static int meth_receivefrom(lua_State *L)
 static int meth_getfamily(lua_State *L)
 {
     p_udp udp = (p_udp) auxiliar_checkgroup(L, "udp{any}", 1);
-    if (udp->family == PF_INET6) {
+    if (udp->family == AF_INET6) {
         lua_pushliteral(L, "inet6");
         return 1;
     } else {
@@ -391,7 +393,7 @@ static int meth_setsockname(lua_State *L) {
     bindhints.ai_socktype = SOCK_DGRAM;
     bindhints.ai_family = udp->family;
     bindhints.ai_flags = AI_PASSIVE;
-    err = inet_trybind(&udp->sock, address, port, &bindhints);
+    err = inet_trybind(&udp->sock, &udp->family, address, port, &bindhints);
     if (err) {
         lua_pushnil(L);
         lua_pushstring(L, err);
@@ -409,7 +411,12 @@ static int meth_setsockname(lua_State *L) {
 \*-------------------------------------------------------------------------*/
 static int udp_create(lua_State *L, int family) {
     t_socket sock;
-    const char *err = inet_trycreate(&sock, family, SOCK_DGRAM);
+    /* if family is AF_UNSPEC, we create an AF_INET socket
+     * but store AF_UNSPEC into tcp-family. This will allow it
+     * later be replaced with an AF_INET6 socket if
+     * trybind or tryconnect prefer it instead. */
+    const char *err = inet_trycreate(&sock, family == AF_UNSPEC?
+        AF_INET: family, SOCK_DGRAM);
     /* try to allocate a system socket */
     if (!err) {
         /* allocate udp object */
@@ -417,7 +424,7 @@ static int udp_create(lua_State *L, int family) {
         auxiliar_setclass(L, "udp{unconnected}", -1);
         /* initialize remaining structure fields */
         socket_setnonblocking(&sock);
-        if (family == PF_INET6) {
+        if (family == AF_INET6) {
             int yes = 1;
             setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
                 (void *)&yes, sizeof(yes));
@@ -434,6 +441,10 @@ static int udp_create(lua_State *L, int family) {
 }
 
 static int global_create(lua_State *L) {
+    return udp_create(L, AF_UNSPEC);
+}
+
+static int global_create4(lua_State *L) {
     return udp_create(L, AF_INET);
 }
 
diff --git a/src/usocket.c b/src/usocket.c
index 99e551b..8adc573 100644
--- a/src/usocket.c
+++ b/src/usocket.c
@@ -211,6 +211,8 @@ int socket_send(p_socket ps, const char *data, size_t count,
         err = errno;
         /* EPIPE means the connection was closed */
         if (err == EPIPE) return IO_CLOSED;
+        /* EPROTOTYPE means the connection is being closed (on Yosemite!)*/
+        if (err == EPROTOTYPE) continue;
         /* we call was interrupted, just try again */
         if (err == EINTR) continue;
         /* if failed fatal reason, report error */
@@ -239,6 +241,7 @@ int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent,
         }
         err = errno;
         if (err == EPIPE) return IO_CLOSED;
+        if (err == EPROTOTYPE) continue;
         if (err == EINTR) continue;
         if (err != EAGAIN) return err;
         if ((err = socket_waitfd(ps, WAITFD_W, tm)) != IO_DONE) return err;
@@ -317,6 +320,8 @@ int socket_write(p_socket ps, const char *data, size_t count,
         err = errno;
         /* EPIPE means the connection was closed */
         if (err == EPIPE) return IO_CLOSED;
+        /* EPROTOTYPE means the connection is being closed (on Yosemite!)*/
+        if (err == EPROTOTYPE) continue;
         /* we call was interrupted, just try again */
         if (err == EINTR) continue;
         /* if failed fatal reason, report error */
@@ -410,7 +415,9 @@ const char *socket_strerror(int err) {
         case ECONNABORTED: return PIE_CONNABORTED;
         case ECONNRESET: return PIE_CONNRESET;
         case ETIMEDOUT: return PIE_TIMEDOUT;
-        default: return strerror(err);
+        default: {
+            return strerror(err);
+        }
     }
 }
 
diff --git a/test/testclnt.lua b/test/testclnt.lua
index 0014781..abf9608 100644
--- a/test/testclnt.lua
+++ b/test/testclnt.lua
@@ -8,7 +8,7 @@ function printf(...)
 end
 
 function pass(...)
-    printf(...) 
+    printf(...)
     io.stderr:write("\n")
 end
 
@@ -45,30 +45,30 @@ function check_timeout(tm, sl, elapsed, err, opp, mode, alldone)
             if not err then warn("must be buffered")
             elseif err == "timeout" then pass("proper timeout")
             else fail("unexpected error '%s'", err) end
-        else 
-            if err ~= "timeout" then fail("should have timed out") 
+        else
+            if err ~= "timeout" then fail("should have timed out")
             else pass("proper timeout") end
         end
     else
         if mode == "total" then
-            if elapsed > tm then 
+            if elapsed > tm then
                 if err ~= "timeout" then fail("should have timed out")
                 else pass("proper timeout") end
             elseif elapsed < tm then
-                if err then fail(err) 
+                if err then fail(err)
                 else pass("ok") end
-            else 
-                if alldone then 
-                    if err then fail("unexpected error '%s'", err) 
+            else
+                if alldone then
+                    if err then fail("unexpected error '%s'", err)
                     else pass("ok") end
                 else
-                    if err ~= "timeout" then fail(err) 
+                    if err ~= "timeout" then fail(err)
                     else pass("proper timeoutk") end
                 end
             end
-        else 
-            if err then fail(err) 
-            else pass("ok") end 
+        else
+            if err then fail(err)
+            else pass("ok") end
         end
     end
 end
@@ -104,8 +104,8 @@ control:setoption("tcp-nodelay", true)
 ------------------------------------------------------------------------
 function test_methods(sock, methods)
     for _, v in pairs(methods) do
-        if type(sock[v]) ~= "function" then 
-            fail(sock.class .. " method '" .. v .. "' not registered") 
+        if type(sock[v]) ~= "function" then
+            fail(sock.class .. " method '" .. v .. "' not registered")
         end
     end
     pass(sock.class .. " methods are ok")
@@ -121,7 +121,7 @@ function test_mixed(len)
     local p3 = "raw " .. string.rep("z", inter) .. "bytes"
     local p4 = "end" .. string.rep("w", inter) .. "bytes"
     local bp1, bp2, bp3, bp4
-remote (string.format("str = data:receive(%d)", 
+remote (string.format("str = data:receive(%d)",
             string.len(p1)+string.len(p2)+string.len(p3)+string.len(p4)))
     sent, err = data:send(p1..p2..p3..p4)
     if err then fail(err) end
@@ -166,7 +166,7 @@ function test_rawline(len)
     io.stderr:write("length " .. len .. ": ")
     local str, str10, back, err
     str = string.rep(string.char(47), math.mod(len, 10))
-    str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100), 
+    str10 = string.rep(string.char(120,21,77,4,5,0,7,36,44,100),
             math.floor(len/10))
     str = str .. str10
 remote "str = data:receive()"
@@ -216,7 +216,7 @@ function test_totaltimeoutreceive(len, tm, sl)
     data:settimeout(tm, "total")
 local t = socket.gettime()
     str, err, partial, elapsed = data:receive(2*len)
-    check_timeout(tm, sl, elapsed, err, "receive", "total", 
+    check_timeout(tm, sl, elapsed, err, "receive", "total",
         string.len(str or partial) == 2*len)
 end
 
@@ -236,7 +236,7 @@ function test_totaltimeoutsend(len, tm, sl)
     data:settimeout(tm, "total")
     str = string.rep("a", 2*len)
     total, err, partial, elapsed = data:send(str)
-    check_timeout(tm, sl, elapsed, err, "send", "total", 
+    check_timeout(tm, sl, elapsed, err, "send", "total",
         total == 2*len)
 end
 
@@ -256,7 +256,7 @@ function test_blockingtimeoutreceive(len, tm, sl)
     ]], 2*tm, len, sl, sl))
     data:settimeout(tm)
     str, err, partial, elapsed = data:receive(2*len)
-    check_timeout(tm, sl, elapsed, err, "receive", "blocking", 
+    check_timeout(tm, sl, elapsed, err, "receive", "blocking",
         string.len(str or partial) == 2*len)
 end
 
@@ -290,10 +290,10 @@ function empty_connect()
         data = server:accept()
     ]]
     data, err = socket.connect("", port)
-    if not data then 
+    if not data then
         pass("ok")
         data = socket.connect(host, port)
-    else 
+    else
         pass("gethostbyname returns localhost on empty string...")
     end
 end
@@ -327,7 +327,7 @@ function test_closed()
         data:close()
         data = nil
     ]], str))
-    -- try to get a line 
+    -- try to get a line
     back, err, partial = data:receive()
     if not err then fail("should have gotten 'closed'.")
     elseif err ~= "closed" then fail("got '"..err.."' instead of 'closed'.")
@@ -340,25 +340,25 @@ function test_closed()
         data = nil
     ]]
     total, err, partial = data:send(string.rep("ugauga", 100000))
-    if not err then 
+    if not err then
         pass("failed: output buffer is at least %d bytes long!", total)
-    elseif err ~= "closed" then 
+    elseif err ~= "closed" then
         fail("got '"..err.."' instead of 'closed'.")
-    else 
-        pass("graceful 'closed' received after %d bytes were sent", partial) 
+    else
+        pass("graceful 'closed' received after %d bytes were sent", partial)
     end
 end
 
 ------------------------------------------------------------------------
 function test_selectbugs()
     local r, s, e = socket.select(nil, nil, 0.1)
-    assert(type(r) == "table" and type(s) == "table" and 
+    assert(type(r) == "table" and type(s) == "table" and
         (e == "timeout" or e == "error"))
     pass("both nil: ok")
     local udp = socket.udp()
     udp:close()
     r, s, e = socket.select({ udp }, { udp }, 0.1)
-    assert(type(r) == "table" and type(s) == "table" and 
+    assert(type(r) == "table" and type(s) == "table" and
         (e == "timeout" or e == "error"))
     pass("closed sockets: ok")
     e = pcall(socket.select, "wrong", 1, 0.1)
@@ -389,7 +389,7 @@ function accept_timeout()
     local t = socket.gettime()
     s:settimeout(1)
     local c, e = s:accept()
-    assert(not c, "should not accept") 
+    assert(not c, "should not accept")
     assert(e == "timeout", string.format("wrong error message (%s)", e))
     t = socket.gettime() - t
     assert(t < 2, string.format("took to long to give up (%gs)", t))
@@ -407,9 +407,9 @@ function connect_timeout()
     local t = socket.gettime()
     local r, e = c:connect("10.0.0.1", 81)
     assert(not r, "should not connect")
-    assert(socket.gettime() - t < 2, "took too long to give up.") 
+    assert(socket.gettime() - t < 2, "took too long to give up.")
     c:close()
-    pass("ok") 
+    pass("ok")
 end
 
 ------------------------------------------------------------------------
@@ -447,16 +447,14 @@ end
 
 ------------------------------------------------------------------------
 function rebind_test()
-    --local c ,c1 = socket.bind("localhost", 0)
    local c ,c1 = socket.bind("127.0.0.1", 0)
     if not c then pass ("failed to bind! " .. tostring(c) .. ' ' .. tostring(c1))  return end
 	assert(c,c1)
- 
     local i, p = c:getsockname()
     local s, e = socket.tcp()
     assert(s, e)
     s:setoption("reuseaddr", false)
-    r, e = s:bind("localhost", p)
+    r, e = s:bind(i, p)
     assert(not r, "managed to rebind!")
     assert(e)
     pass("ok")
@@ -476,9 +474,9 @@ function getstats_test()
         data:receive(c)
         t = t + c
         local r, s, a = data:getstats()
-        assert(r == t, "received count failed" .. tostring(r) 
+        assert(r == t, "received count failed" .. tostring(r)
             .. "/" .. tostring(t))
-        assert(s == t, "sent count failed" .. tostring(s) 
+        assert(s == t, "sent count failed" .. tostring(s)
             .. "/" .. tostring(t))
     end
     pass("ok")
@@ -486,7 +484,7 @@ end
 
 
 ------------------------------------------------------------------------
-function test_nonblocking(size) 
+function test_nonblocking(size)
     reconnect()
     printf("testing "  .. 2*size .. " bytes: ")
 remote(string.format([[
@@ -545,7 +543,7 @@ function test_readafterclose()
         data:close()
         data = nil
     ]]))
-    data:close() 
+    data:close()
     back, err, partial = data:receive("*a")
     assert(back == nil and err == "closed", "should have returned 'closed'")
     pass("ok")
@@ -555,7 +553,7 @@ function test_readafterclose()
         data:close()
         data = nil
     ]]))
-    data:close() 
+    data:close()
     back, err, partial = data:receive()
     assert(back == nil and err == "closed", "should have returned 'closed'")
     pass("ok")
@@ -565,7 +563,7 @@ function test_readafterclose()
         data:close()
         data = nil
     ]]))
-    data:close() 
+    data:close()
     back, err, partial = data:receive(1)
     assert(back == nil and err == "closed", "should have returned 'closed'")
     pass("ok")
@@ -575,7 +573,7 @@ function test_readafterclose()
         data:close()
         data = nil
     ]]))
-    data:close() 
+    data:close()
     back, err, partial = data:receive(0)
     assert(back == nil and err == "closed", "should have returned 'closed'")
     pass("ok")
@@ -593,7 +591,7 @@ function test_writeafterclose()
     while not err do
         sent, err, errsent, time = data:send(str)
     end
-    assert(err == "closed", "should have returned 'closed'")
+    assert(err == "closed", "got " .. err .. " instead of 'closed'")
     pass("ok")
 end
 
@@ -648,18 +646,18 @@ else io.stderr:write("Warning! IPv6 does not support!\n") end
 end
 
 local udp_methods = {
-    "close", 
+    "close",
     "dirty",
     "getfamily",
     "getfd",
     "getoption",
     "getpeername",
     "getsockname",
-    "receive", 
-    "receivefrom", 
-    "send", 
-    "sendto", 
-    "setfd", 
+    "receive",
+    "receivefrom",
+    "send",
+    "sendto",
+    "setfd",
     "setoption",
     "setpeername",
     "setsockname",
@@ -674,6 +672,9 @@ if sock then test_methods(socket.udp6(), udp_methods)
 else io.stderr:write("Warning! IPv6 does not support!\n") end
 end
 
+test("closed connection detection: ")
+test_closed()
+
 test("partial receive")
 test_partialrecv()
 
@@ -697,9 +698,6 @@ rebind_test()
 test("active close: ")
 active_close()
 
-test("closed connection detection: ")
-test_closed()
-
 test("accept function: ")
 accept_timeout()
 accept_errors()
diff --git a/test/testsrvr.lua b/test/testsrvr.lua
index 72b93ab..1eb2d5b 100644
--- a/test/testsrvr.lua
+++ b/test/testsrvr.lua
@@ -6,7 +6,7 @@ ack = "\n";
 while 1 do
     print("server: waiting for client connection...");
     control = assert(server:accept());
-    while 1 do 
+    while 1 do
         command, emsg = control:receive();
         if emsg == "closed" then
             control:close()
diff --git a/test/udpconnectclnt.lua b/test/udpconnectclnt.lua
index effe13a..ad6ab6a 100644
--- a/test/udpconnectclnt.lua
+++ b/test/udpconnectclnt.lua
@@ -1,7 +1,7 @@
 local socket = require"socket"
 local udp = socket.udp
 local localhost = "127.0.0.1"
-local port = arg[1]
+local port = assert(arg[1], "missing port argument")
 
 se = udp(); se:setoption("reuseaddr", true)
 se:setsockname(localhost, 5062)
-- 
cgit v1.2.3-55-g6feb


From 77bba625d7aaa0f9e118879163687fcbcb0b5a7b Mon Sep 17 00:00:00 2001
From: Diego Nehab <diego.nehab@gmail.com>
Date: Tue, 25 Aug 2015 15:41:40 -0300
Subject: Fixes suggested by @Florob in #147.

---
 doc/tcp.html      |  6 ++++++
 doc/udp.html      |  6 ++++++
 src/inet.c        | 17 +++++++++++------
 src/inet.h        |  2 +-
 src/tcp.c         | 52 +++++++++++++++++++++-------------------------------
 src/udp.c         | 52 +++++++++++++++++++++-------------------------------
 test/testclnt.lua | 19 ++++++++++++-------
 7 files changed, 78 insertions(+), 76 deletions(-)

diff --git a/doc/tcp.html b/doc/tcp.html
index 6fc9900..fb627a1 100644
--- a/doc/tcp.html
+++ b/doc/tcp.html
@@ -65,6 +65,12 @@ href=#bind><tt>connect</tt></a>, depending on the address
 family obtained from the resolver.
 </p>
 
+<p class=note>
+Note: Before the choice between IPv4 and IPv6 happens,
+the internal socket object is invalid and therefore <a
+href=#setoption><tt>setoption</tt></a> will fail.
+</p>
+
 <!-- socket.tcp +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class=name id="socket.tcp4">
diff --git a/doc/udp.html b/doc/udp.html
index e313af4..a300f2f 100644
--- a/doc/udp.html
+++ b/doc/udp.html
@@ -76,6 +76,12 @@ href=#setsockname><tt>sockname</tt></a>, depending on the address
 family obtained from the resolver.
 </p>
 
+<p class=note>
+Note: Before the choice between IPv4 and IPv6 happens,
+the internal socket object is invalid and therefore <a
+href=#setoption><tt>setoption</tt></a> will fail.
+</p>
+
 <!-- socket.udp4 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
 
 <p class="name" id="socket.udp">
diff --git a/src/inet.c b/src/inet.c
index 8f0fac2..331b800 100644
--- a/src/inet.c
+++ b/src/inet.c
@@ -352,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;
 }
 
 /*-------------------------------------------------------------------------*\
@@ -408,8 +413,8 @@ const char *inet_tryconnect(p_socket ps, int *family, const char *address,
          * not enter this branch. */
         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));
+            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 */
@@ -466,8 +471,8 @@ const char *inet_trybind(p_socket ps, int *family, const char *address,
     for (iterator = resolved; iterator; iterator = iterator->ai_next) {
         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));
+            err = inet_trycreate(ps, iterator->ai_family,
+                        iterator->ai_socktype, iterator->ai_protocol);
             if (err) continue;
             current_family = iterator->ai_family;
         }
diff --git a/src/inet.h b/src/inet.h
index b85c20e..feb3541 100644
--- a/src/inet.h
+++ b/src/inet.h
@@ -24,7 +24,7 @@
 
 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, int *family, const char *address,
diff --git a/src/tcp.c b/src/tcp.c
index 4d12f08..7bf1af5 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -355,39 +355,29 @@ static int meth_settimeout(lua_State *L)
 * Creates a master tcp object
 \*-------------------------------------------------------------------------*/
 static int tcp_create(lua_State *L, int family) {
-    t_socket sock;
-    /* if family is AF_UNSPEC, we create an AF_INET socket
-     * but store AF_UNSPEC into tcp-family. This will allow it
-     * later be replaced with an AF_INET6 socket if
-     * trybind or tryconnect prefer it instead. */
-    const char *err = inet_trycreate(&sock, family == AF_UNSPEC?
-        AF_INET: family, SOCK_STREAM);
-    /* try to allocate a system socket */
-    if (!err) {
-        /* allocate tcp object */
-        p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
-        memset(tcp, 0, sizeof(t_tcp));
-        /* set its type as master object */
-        auxiliar_setclass(L, "tcp{master}", -1);
-        /* initialize remaining structure fields */
-        socket_setnonblocking(&sock);
-        if (family == AF_INET6) {
-            int yes = 1;
-            setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
-                (void *)&yes, sizeof(yes));
+    p_tcp tcp = (p_tcp) lua_newuserdata(L, sizeof(t_tcp));
+    memset(tcp, 0, sizeof(t_tcp));
+    /* set its type as master object */
+    auxiliar_setclass(L, "tcp{master}", -1);
+    /* if family is AF_UNSPEC, we leave the socket invalid and
+     * store AF_UNSPEC into family. This will allow it to later be
+     * replaced with an AF_INET6 or AF_INET socket upon first use. */
+    tcp->sock = SOCKET_INVALID;
+    tcp->family = family;
+    io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
+            (p_error) socket_ioerror, &tcp->sock);
+    timeout_init(&tcp->tm, -1, -1);
+    buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
+    if (family != AF_UNSPEC) {
+        const char *err = inet_trycreate(&tcp->sock, family, SOCK_STREAM, 0);
+        if (err != NULL) {
+            lua_pushnil(L);
+            lua_pushstring(L, err);
+            return 2;
         }
-        tcp->sock = sock;
-        io_init(&tcp->io, (p_send) socket_send, (p_recv) socket_recv,
-                (p_error) socket_ioerror, &tcp->sock);
-        timeout_init(&tcp->tm, -1, -1);
-        buffer_init(&tcp->buf, &tcp->io, &tcp->tm);
-        tcp->family = family;
-        return 1;
-    } else {
-        lua_pushnil(L);
-        lua_pushstring(L, err);
-        return 2;
+        socket_setnonblocking(&tcp->sock);
     }
+    return 1;
 }
 
 static int global_create(lua_State *L) {
diff --git a/src/udp.c b/src/udp.c
index 6600859..17d932a 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -185,7 +185,7 @@ static int meth_sendto(lua_State *L) {
         return 2;
     }
     timeout_markstart(tm);
-    err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr, 
+    err = socket_sendto(&udp->sock, data, count, &sent, ai->ai_addr,
         (socklen_t) ai->ai_addrlen, tm);
     freeaddrinfo(ai);
     if (err != IO_DONE) {
@@ -237,7 +237,7 @@ static int meth_receivefrom(lua_State *L)
     char portstr[6];
     timeout_markstart(tm);
     count = MIN(count, sizeof(buffer));
-    err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr, 
+    err = socket_recvfrom(&udp->sock, buffer, count, &got, (SA *) &addr,
             &addr_len, tm);
     /* Unlike TCP, recv() of zero is not closed, but a zero-length packet. */
     if (err == IO_CLOSED)
@@ -247,7 +247,7 @@ static int meth_receivefrom(lua_State *L)
         lua_pushstring(L, udp_strerror(err));
         return 2;
     }
-    err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr, 
+    err = getnameinfo((struct sockaddr *)&addr, addr_len, addrstr,
         INET6_ADDRSTRLEN, portstr, 6, NI_NUMERICHOST | NI_NUMERICSERV);
 	if (err) {
         lua_pushnil(L);
@@ -351,7 +351,7 @@ static int meth_setpeername(lua_State *L) {
     /* make sure we try to connect only to the same family */
     connecthints.ai_family = udp->family;
     if (connecting) {
-        err = inet_tryconnect(&udp->sock, &udp->family, address, 
+        err = inet_tryconnect(&udp->sock, &udp->family, address,
             port, tm, &connecthints);
         if (err) {
             lua_pushnil(L);
@@ -365,7 +365,6 @@ static int meth_setpeername(lua_State *L) {
         inet_trydisconnect(&udp->sock, udp->family, tm);
         auxiliar_setclass(L, "udp{unconnected}", 1);
     }
-    /* change class to connected or unconnected depending on address */
     lua_pushnumber(L, 1);
     return 1;
 }
@@ -410,34 +409,25 @@ static int meth_setsockname(lua_State *L) {
 * Creates a master udp object
 \*-------------------------------------------------------------------------*/
 static int udp_create(lua_State *L, int family) {
-    t_socket sock;
-    /* if family is AF_UNSPEC, we create an AF_INET socket
-     * but store AF_UNSPEC into tcp-family. This will allow it
-     * later be replaced with an AF_INET6 socket if
-     * trybind or tryconnect prefer it instead. */
-    const char *err = inet_trycreate(&sock, family == AF_UNSPEC?
-        AF_INET: family, SOCK_DGRAM);
-    /* try to allocate a system socket */
-    if (!err) {
-        /* allocate udp object */
-        p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
-        auxiliar_setclass(L, "udp{unconnected}", -1);
-        /* initialize remaining structure fields */
-        socket_setnonblocking(&sock);
-        if (family == AF_INET6) {
-            int yes = 1;
-            setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
-                (void *)&yes, sizeof(yes));
+    /* allocate udp object */
+    p_udp udp = (p_udp) lua_newuserdata(L, sizeof(t_udp));
+    auxiliar_setclass(L, "udp{unconnected}", -1);
+    /* if family is AF_UNSPEC, we leave the socket invalid and
+     * store AF_UNSPEC into family. This will allow it to later be
+     * replaced with an AF_INET6 or AF_INET socket upon first use. */
+    udp->sock = SOCKET_INVALID;
+    timeout_init(&udp->tm, -1, -1);
+    udp->family = family;
+    if (family != AF_UNSPEC) {
+        const char *err = inet_trycreate(&udp->sock, family, SOCK_DGRAM, 0);
+        if (err != NULL) {
+            lua_pushnil(L);
+            lua_pushstring(L, err);
+            return 2;
         }
-        udp->sock = sock;
-        timeout_init(&udp->tm, -1, -1);
-        udp->family = family;
-        return 1;
-    } else {
-        lua_pushnil(L);
-        lua_pushstring(L, err);
-        return 2;
+        socket_setnonblocking(&udp->sock);
     }
+    return 1;
 }
 
 static int global_create(lua_State *L) {
diff --git a/test/testclnt.lua b/test/testclnt.lua
index abf9608..ee1201f 100644
--- a/test/testclnt.lua
+++ b/test/testclnt.lua
@@ -304,15 +304,20 @@ function isclosed(c)
 end
 
 function active_close()
-    reconnect()
-    if isclosed(data) then fail("should not be closed") end
-    data:close()
-    if not isclosed(data) then fail("should be closed") end
-    data = nil
-    local udp = socket.udp()
+    local tcp = socket.tcp4()
+    if isclosed(tcp) then fail("should not be closed") end
+    tcp:close()
+    if not isclosed(tcp) then fail("should be closed") end
+    tcp = socket.tcp()
+    if not isclosed(tcp) then fail("should be closed") end
+    tcp = nil
+    local udp = socket.udp4()
     if isclosed(udp) then fail("should not be closed") end
     udp:close()
     if not isclosed(udp) then fail("should be closed") end
+    udp = socket.udp()
+    if not isclosed(udp) then fail("should be closed") end
+    udp = nil
     pass("ok")
 end
 
@@ -368,7 +373,7 @@ function test_selectbugs()
     pass("invalid input: ok")
     local toomany = {}
     for i = 1, socket._SETSIZE+1 do
-        toomany[#toomany+1] = socket.udp()
+        toomany[#toomany+1] = socket.udp4()
     end
     if #toomany > socket._SETSIZE then
         local e = pcall(socket.select, toomany, nil, 0.1)
-- 
cgit v1.2.3-55-g6feb