From 1de617e3550366076737e804f1e28891605db89c Mon Sep 17 00:00:00 2001
From: moteus <mimir@newmail.ru>
Date: Wed, 29 May 2013 14:33:27 +0400
Subject: Add. Allow get `error` option to socket.

---
 src/options.c              | 13 +++++++++++++
 src/options.h              |  1 +
 src/tcp.c                  |  1 +
 src/udp.c                  |  1 +
 test/test_socket_error.lua | 27 +++++++++++++++++++++++++++
 5 files changed, 43 insertions(+)
 create mode 100644 test/test_socket_error.lua

diff --git a/src/options.c b/src/options.c
index 6cae7ee..6f36ba4 100644
--- a/src/options.c
+++ b/src/options.c
@@ -254,6 +254,19 @@ static int opt_getboolean(lua_State *L, p_socket ps, int level, int name)
     return 1;
 }
 
+int opt_get_error(lua_State *L, p_socket ps)
+{
+  int val = 0;
+  socklen_t len = sizeof(val);
+  if (getsockopt(*ps, SOL_SOCKET, SO_ERROR, (char *) &val, &len) < 0) {
+    lua_pushnil(L);
+    lua_pushstring(L, "getsockopt failed");
+    return 2;
+  }
+  lua_pushstring(L, socket_strerror(val));
+  return 1;
+}
+
 static int opt_setboolean(lua_State *L, p_socket ps, int level, int name)
 {
     int val = auxiliar_checkboolean(L, 3);             /* obj, name, bool */
diff --git a/src/options.h b/src/options.h
index 55447f7..1cabd7d 100644
--- a/src/options.h
+++ b/src/options.h
@@ -42,6 +42,7 @@ int opt_get_linger(lua_State *L, p_socket ps);
 int opt_get_reuseaddr(lua_State *L, p_socket ps);
 int opt_get_ip_multicast_loop(lua_State *L, p_socket ps);
 int opt_get_ip_multicast_if(lua_State *L, p_socket ps);
+int opt_get_error(lua_State *L, p_socket ps);
 
 /* invokes the appropriate option handler */
 int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps);
diff --git a/src/tcp.c b/src/tcp.c
index efb92c9..6594bda 100644
--- a/src/tcp.c
+++ b/src/tcp.c
@@ -73,6 +73,7 @@ static t_opt optget[] = {
     {"reuseaddr",   opt_get_reuseaddr},
     {"tcp-nodelay", opt_get_tcp_nodelay},
     {"linger",      opt_get_linger},
+    {"error",       opt_get_error},
     {NULL,          NULL}
 };
 
diff --git a/src/udp.c b/src/udp.c
index ec805b6..5945dca 100644
--- a/src/udp.c
+++ b/src/udp.c
@@ -85,6 +85,7 @@ static t_opt optset[] = {
 static t_opt optget[] = {
     {"ip-multicast-if",    opt_get_ip_multicast_if},
     {"ip-multicast-loop",  opt_get_ip_multicast_loop},
+    {"error",              opt_get_error},
     {NULL,                 NULL}
 };
 
diff --git a/test/test_socket_error.lua b/test/test_socket_error.lua
new file mode 100644
index 0000000..9bd0bc7
--- /dev/null
+++ b/test/test_socket_error.lua
@@ -0,0 +1,27 @@
+local socket = require "socket"
+
+local host, port = "127.0.0.1", "5462"
+
+assert(socket.bind(host, port)):close()
+
+local sock = socket.tcp()
+sock:settimeout(0)
+
+local ok, err = sock:connect(host, port)
+assert(not ok)
+assert('timeout' == err)
+
+for i = 1, 10 do
+  -- select pass even if socket has error
+  local _, rec, err = socket.select(nil, {sock}, 1)
+  assert('timeout' == err)
+  assert(not next(rec))
+  err = sock:getoption("error") -- i get 'connection refused' on WinXP
+  if err then
+    print("Passed! Error is '" .. err .. "'.")
+    os.exit(0)
+  end
+end
+
+print("Fail! No error detected!")
+os.exit(1)
-- 
cgit v1.2.3-55-g6feb