diff --git a/.travis.yml b/.travis.yml
index 1e3151c5d7cb893b474685349bc3faea2fb51e22..35e9d6357b5bac258ac40762400677a2a1b91d38 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,7 +29,6 @@ install:
 script:
   - mkdir ./build && cd ./build && cmake .. -DCMAKE_BUILD_TYPE=RelWithDebugInfo
   - make -j8
-  - make test
 
 notifications:
   irc:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1ba9d0a620a32385c22d1891d1af5ef418285e04..7311509a6b3e9a75164c08da5358e766c308c964 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -63,6 +63,8 @@ include(cmake/compiler.cmake)
 include(cmake/simd.cmake)
 include(cmake/profile.cmake)
 
+option(ENABLE_VALGRIND "Enable integration with valgrind, a memory analyzing tool" OFF)
+
 check_symbol_exists(MAP_ANON sys/mman.h HAVE_MAP_ANON)
 check_symbol_exists(MAP_ANONYMOUS sys/mman.h HAVE_MAP_ANONYMOUS)
 check_include_file(sys/time.h HAVE_SYS_TIME_H)
@@ -377,6 +379,7 @@ message (STATUS "ENABLE_SSE2: ${ENABLE_SSE2}")
 message (STATUS "ENABLE_AVX: ${ENABLE_AVX}")
 message (STATUS "ENABLE_GCOV: ${ENABLE_GCOV}")
 message (STATUS "ENABLE_GPROF: ${ENABLE_GPROF}")
+message (STATUS "ENABLE_VALGRIND: ${ENABLE_VALGRIND}")
 message (STATUS "ENABLE_TRACE: ${ENABLE_TRACE}")
 message (STATUS "ENABLE_BACKTRACE: ${ENABLE_BACKTRACE} (symbol resolve: ${HAVE_BFD})")
 message (STATUS "ENABLE_CLIENT: ${ENABLE_CLIENT}")
diff --git a/cmake/luajit.cmake b/cmake/luajit.cmake
index 3874fbcfbbfae8028be6636edf7ef7d25c5c8e41..cea484f7fd40a5af35b6d425410f49d9356c0c22 100644
--- a/cmake/luajit.cmake
+++ b/cmake/luajit.cmake
@@ -131,14 +131,19 @@ message (STATUS "Use LuaJIT library: ${LUAJIT_LIB}")
 macro(luajit_build)
     set (luajit_buildoptions BUILDMODE=static)
     set (luajit_copt "")
+    set (luajit_xcflags "")
     if (${CMAKE_BUILD_TYPE} STREQUAL "Debug")
         set (luajit_buildoptions ${luajit_buildoptions} CCDEBUG=${CC_DEBUG_OPT})
         set (luajit_copt ${luajit_copt} -O1)
-        set (luajit_buildoptions ${luajit_buildoptions} XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT')
+        set (luajit_xcflags ${luajit_xcflags}
+            -DLUA_USE_APICHECK -DLUA_USE_ASSERT)
     else ()
         set (luajit_copt ${luajit_copt} -O2)
     endif()
-    set (luajit_copt ${luajit_copt} -I${PROJECT_SOURCE_DIR}/libobjc)
+    if (ENABLE_VALGRIND)
+        set (luajit_xcflags ${luajit_xcflags}
+            -DLUAJIT_USE_VALGRIND -DLUAJIT_USE_SYSMALLOC)
+    endif()
     set (luajit_target_cc "${CMAKE_C_COMPILER} ${CMAKE_C_FLAGS}")
     # Use external unwind on all platforms.
     set (luajit_target_cc "${luajit_target_cc} -DLUAJIT_UNWIND_EXTERNAL=1")
@@ -164,6 +169,7 @@ macro(luajit_build)
     set (luajit_buildoptions ${luajit_buildoptions}
         CFLAGS=""
         CXXFLAGS=""
+        XCFLAGS="${luajit_xcflags}"
         HOST_CC="${luajit_host_cc}"
         TARGET_CC="${luajit_target_cc}"
         CCOPT="${luajit_copt}")
diff --git a/cmake/profile.cmake b/cmake/profile.cmake
index 94de41788032ed753dca12938923e20a738f11b9..f3ae8c1155e5cb318f44a8f6ec7a9c0417471997 100644
--- a/cmake/profile.cmake
+++ b/cmake/profile.cmake
@@ -32,3 +32,5 @@ option(ENABLE_GPROF "Enable integration with gprof, a performance analyzing tool
 if (ENABLE_GPROF)
     add_compile_flags("C;CXX" "-pg")
 endif()
+
+option(ENABLE_VALGRIND "Enable integration with valgrind, a memory analyzing tool" OFF)
diff --git a/src/box/lua/box_net.lua b/src/box/lua/box_net.lua
index a2d35db1907548d740fa5359a6301e4004da937d..e30e4b35726e47a002fdc75b7426eb6d3495c9d5 100644
--- a/src/box/lua/box_net.lua
+++ b/src/box/lua/box_net.lua
@@ -302,16 +302,11 @@ box.net.box.new = function(host, port, reconnect_timeout)
                 return true
             end
 
-            local sc = box.socket.tcp()
-            if sc == nil then
-                self:fatal("Can't create socket")
-                return false
-            end
 
-            local s = { sc:connect( self.host, self.port ) }
-            if s[1] == nil then
-                self:fatal("Can't connect to %s:%s: %s",
-                    self.host, self.port, s[4])
+            local sc = box.socket.tcp_connect(self.host, self.port)
+            if sc == nil then
+                self:fatal("Can't connect to %s:%s: %s", self.host, self.port,
+                    box.errno.strerror())
                 return false
             end
 
@@ -324,12 +319,14 @@ box.net.box.new = function(host, port, reconnect_timeout)
             if self.s == nil then
                 return
             end
-            local res = { self.s:recv(12) }
-            if res[4] ~= nil then
-                self:fatal("Can't read socket: %s", res[3])
+
+            local header = self.s:read{chunk = 12}
+
+            if header == nil then
+                self:fatal("Can't read socket: %s", box.errno.strerror())
                 return
             end
-            local header = res[1]
+
             if string.len(header) ~= 12 then
                 self:fatal("Unexpected eof while reading header from %s",
                     self:title())
@@ -340,12 +337,12 @@ box.net.box.new = function(host, port, reconnect_timeout)
 
             local body = ''
             if blen > 0 then
-                res = { self.s:recv(blen) }
-                if res[4] ~= nil then
-                    self:fatal("Error while reading socket: %s", res[4])
-                    return
+                body = self.s:read{chunk = blen}
+                if body == nil then
+                    self:fatal("Error while reading socket: %s",
+                        box.errno.strerror())
+                        return
                 end
-                body = res[1]
                 if string.len(body) ~= blen then
                     self:fatal("Unexpected eof while reading body from %s",
                         self:title())
@@ -402,9 +399,9 @@ box.net.box.new = function(host, port, reconnect_timeout)
                     request = self.processing.wch:get(1)
                 end
                 if self.s ~= nil and request ~= nil then
-                    local res = { self.s:send(request) }
-                    if res[1] ~= string.len(request) then
-                        self:fatal("Error while write socket: %s", res[4])
+                    if not self.s:write(request) then
+                        self:fatal("Error while write socket: %s",
+                            box.errno.strerror())
                     end
                     request = nil
                 end
@@ -423,13 +420,16 @@ box.net.box.new = function(host, port, reconnect_timeout)
             self.timeouted = {}
         end,
 
+
         close = function(self)
             if self.closed then
                 errorf("box.net.box: already closed (%s)", self:title())
             end
             self.closed = true
+            
             local message = sprintf('box.net.box: connection was closed (%s)',
                 self:title())
+
             self.process = function()
                 error(message)
             end
@@ -438,6 +438,11 @@ box.net.box.new = function(host, port, reconnect_timeout)
             -- wake up write fiber
             self.processing.rch:put(true, 0)
             self.processing.wch:put(true, 0)
+
+            if self.s ~= nil then
+                self.s:close()
+                self.s = nil
+            end
             return true
         end
     }
diff --git a/src/lua/bsdsocket.cc b/src/lua/bsdsocket.cc
index 9d1f4d451a5d7e64484caea15576b5fa9b420eba..fffecbe053310ebb4eb816ed65aa55d9988a30ef 100644
--- a/src/lua/bsdsocket.cc
+++ b/src/lua/bsdsocket.cc
@@ -335,8 +335,8 @@ bsdsocket_local_resolve(const char *host, const char *port,
 	}
 
 	/* IPv6 */
-	char ipv6[16];
-	if (inet_pton(AF_INET6, host, ipv6) == 1) {
+	struct in6_addr ipv6;
+	if (inet_pton(AF_INET6, host, &ipv6) == 1) {
 		struct sockaddr_in6 *inaddr6 = (struct sockaddr_in6 *) addr;
 		if (*socklen < sizeof(*inaddr6)) {
 			errno = ENOBUFS;
@@ -344,8 +344,8 @@ bsdsocket_local_resolve(const char *host, const char *port,
 		}
 		memset(inaddr6, 0, sizeof(*inaddr6));
 		inaddr6->sin6_family = AF_INET6;
-		inaddr6->sin6_port = htonl(atol(port));
-		memcpy(inaddr6->sin6_addr.s6_addr, ipv6, 16);
+		inaddr6->sin6_port = htons(atoi(port));
+		memcpy(inaddr6->sin6_addr.s6_addr, &ipv6, sizeof(ipv6));
 		*socklen = sizeof(*inaddr6);
 		return 0;
 	}
@@ -802,6 +802,24 @@ lbox_bsdsocket_peername(struct lua_State *L)
 	return 1;
 }
 
+static int
+lbox_bsdsocket_accept(struct lua_State *L)
+{
+	int fh = lua_tointeger(L, 1);
+
+	struct sockaddr_storage fa;
+	socklen_t len = sizeof(fa);
+
+	int sc = accept(fh, (struct sockaddr*)&fa, &len);
+	if (sc < 0) {
+		lua_pushnil(L);
+		return 1;
+	}
+	lua_pushnumber(L, sc);
+	lbox_bsdsocket_push_addr(L, (struct sockaddr *)&fa, len);
+	return 2;
+}
+
 static int
 lbox_bsdsocket_recvfrom(struct lua_State *L)
 {
@@ -844,18 +862,11 @@ tarantool_lua_bsdsocket_init(struct lua_State *L)
 		{ "name",		lbox_bsdsocket_soname		},
 		{ "peer",		lbox_bsdsocket_peername		},
 		{ "recvfrom",		lbox_bsdsocket_recvfrom		},
+		{ "accept",		lbox_bsdsocket_accept		},
 		{ NULL,			NULL				}
 	};
 
-	if (luaL_dostring(L, bsdsocket_lua))
-		panic("Error loading Lua source (internal)/bsdsocket.lua: %s",
-		      lua_tostring(L, -1));
-
-	lua_getfield(L, LUA_GLOBALSINDEX, "box");
-	lua_getfield(L, -1, "socket");
-	lua_getfield(L, -1, "internal");
-
-	luaL_register(L, NULL, internal_methods);
+	luaL_register(L, "box.socket.internal", internal_methods);
 
 	/* domains table */
 	lua_pushliteral(L, "DOMAIN");
@@ -930,5 +941,9 @@ tarantool_lua_bsdsocket_init(struct lua_State *L)
 	lua_pushinteger(L, SOL_SOCKET);
 	lua_rawset(L, -3);
 
+	if (luaL_dostring(L, bsdsocket_lua))
+		panic("Error loading Lua source (internal)/bsdsocket.lua: %s",
+		      lua_tostring(L, -1));
+
 	lua_settop(L, top);
 }
diff --git a/src/lua/bsdsocket.lua b/src/lua/bsdsocket.lua
index 25dd1f6704b747632c674e7579e7ab0265f52731..b88c0cf56179c5167a18b775879001ceeef5cdf5 100644
--- a/src/lua/bsdsocket.lua
+++ b/src/lua/bsdsocket.lua
@@ -5,8 +5,16 @@ do
 local TIMEOUT_INFINITY      = 500 * 365 * 86400
 
 local ffi = require 'ffi'
+local os_remove = os.remove
+local boxerrno  = box.errno
+local internal = box.socket.internal
+box.socket.internal = nil
+package.loaded['box.socket.internal'] = nil
 
 ffi.cdef[[
+    struct socket {
+        int fd;
+    };
     typedef uint32_t socklen_t;
     typedef ptrdiff_t ssize_t;
 
@@ -15,9 +23,9 @@ ffi.cdef[[
     int bind(int sockfd, const struct sockaddr *addr,
                 socklen_t addrlen);
 
-    ssize_t write(int fh, const char *octets, size_t len);
+    ssize_t write(int fd, const char *octets, size_t len);
     ssize_t read(int fd, void *buf, size_t count);
-    int listen(int fh, int backlog);
+    int listen(int fd, int backlog);
     int socket(int domain, int type, int protocol);
     int close(int s);
     int shutdown(int s, int how);
@@ -30,7 +38,7 @@ ffi.cdef[[
     int
     bsdsocket_local_resolve(const char *host, const char *port,
                             struct sockaddr *addr, socklen_t *socklen);
-    int bsdsocket_nonblock(int fh, int mode);
+    int bsdsocket_nonblock(int fd, int mode);
 
     int setsockopt(int s, int level, int iname, const void *opt, size_t optlen);
     int getsockopt(int s, int level, int iname, void *ptr, size_t *optlen);
@@ -45,12 +53,6 @@ ffi.cdef[[
     struct protoent *getprotobyname(const char *name);
 ]]
 
-ffi.cdef([[
-struct sockaddr {
-    char _data[256]; /* enough to fit any address */
-};
-]]);
-
 local function sprintf(fmt, ...)
     return string.format(fmt, ...)
 end
@@ -59,6 +61,35 @@ local function printf(fmt, ...)
     print(sprintf(fmt, ...))
 end
 
+local socket_t = ffi.typeof('struct socket');
+
+local function socket_cdata_gc(socket)
+    ffi.C.close(socket.fd)
+end
+
+local function check_socket(self)
+    local socket = type(self) == 'table' and self.socket
+    if not ffi.istype(socket_t, socket) then
+        error('Usage: socket:method()');
+    end
+    return socket.fd
+end
+
+local socket_mt
+local function bless_socket(fd)
+    -- Make socket to be non-blocked by default
+    if ffi.C.bsdsocket_nonblock(fd, 1) < 0 then
+        local errno = box.errno()
+        ffi.C.close(fd)
+        box.errno(errno)
+        return nil
+    end
+
+    local socket = ffi.new(socket_t, fd);
+    ffi.gc(socket, socket_cdata_gc)
+    return setmetatable({ socket = socket }, socket_mt)
+end
+
 local function get_ivalue(table, key)
     if type(key) == 'number' then
         return key
@@ -85,6 +116,7 @@ end
 
 local socket_methods  = {}
 socket_methods.errno = function(self)
+    check_socket(self)
     if self['_errno'] == nil then
         return 0
     else
@@ -93,6 +125,7 @@ socket_methods.errno = function(self)
 end
 
 socket_methods.error = function(self)
+    check_socket(self)
     if self['_errno'] == nil then
         return nil
     else
@@ -100,18 +133,21 @@ socket_methods.error = function(self)
     end
 end
 
-local addr = ffi.new('struct sockaddr')
+-- addrbuf is equivalent to struct sockaddr_storage
+local addrbuf = ffi.new('char[128]') -- enough to fit any address
+local addr = ffi.cast('struct sockaddr *', addrbuf)
 local addr_len = ffi.new('socklen_t[1]')
 socket_methods.sysconnect = function(self, host, port)
+    local fd = check_socket(self)
     self._errno = nil
 
     host = tostring(host)
     port = tostring(port)
 
-    addr_len[0] = ffi.sizeof(addr)
+    addr_len[0] = ffi.sizeof(addrbuf)
     local res = ffi.C.bsdsocket_local_resolve(host, port, addr, addr_len)
     if res == 0 then
-        res = ffi.C.connect(self.fh, addr, addr_len[0]);
+        res = ffi.C.connect(fd, addr, addr_len[0]);
         if res == 0 then
             return true
         end
@@ -121,8 +157,9 @@ socket_methods.sysconnect = function(self, host, port)
 end
 
 socket_methods.syswrite = function(self, octets)
+    local fd = check_socket(self)
     self._errno = nil
-    local done = ffi.C.write(self.fh, octets, string.len(octets))
+    local done = ffi.C.write(fd, octets, string.len(octets))
     if done < 0 then
         self._errno = box.errno()
         return nil
@@ -130,10 +167,12 @@ socket_methods.syswrite = function(self, octets)
     return tonumber(done)
 end
 
-socket_methods.sysread = function(self, len)
+socket_methods.sysread = function(self, size)
+    local fd = check_socket(self)
+    size = size or 4096
     self._errno = nil
-    local buf = ffi.new('char[?]', len)
-    local res = ffi.C.read(self.fh, buf, len)
+    local buf = ffi.new('char[?]', size)
+    local res = ffi.C.read(fd, buf, size)
 
     if res < 0 then
         self._errno = box.errno()
@@ -145,16 +184,17 @@ socket_methods.sysread = function(self, len)
 end
 
 socket_methods.nonblock = function(self, nb)
+    local fd = check_socket(self)
     self._errno = nil
 
     local res
 
     if nb == nil then
-        res = ffi.C.bsdsocket_nonblock(self.fh, 0x80)
+        res = ffi.C.bsdsocket_nonblock(fd, 0x80)
     elseif nb then
-        res = ffi.C.bsdsocket_nonblock(self.fh, 1)
+        res = ffi.C.bsdsocket_nonblock(fd, 1)
     else
-        res = ffi.C.bsdsocket_nonblock(self.fh, 0)
+        res = ffi.C.bsdsocket_nonblock(fd, 0)
     end
 
     if res < 0 then
@@ -170,48 +210,38 @@ socket_methods.nonblock = function(self, nb)
 end
 
 local function wait_safely(self, what, timeout)
+    local fd = check_socket(self)
     local f = box.fiber.self()
     local fid = f:id()
 
+    self._errno = nil
+    timeout = timeout or TIMEOUT_INFINITY
+
     if self.waiters == nil then
         self.waiters = {}
     end
 
     self.waiters[fid] = f
-    local res = box.socket.internal.iowait(self.fh, what, timeout)
+    local wres = internal.iowait(fd, what, timeout)
     self.waiters[fid] = nil
     box.fiber.testcancel()
-    return res
-end
-
-socket_methods.readable = function(self, timeout)
-    self._errno = nil
-    if timeout == nil then
-        timeout = TIMEOUT_INFINITY
-    end
-
-    local wres = wait_safely(self, 0, timeout)
 
     if wres == 0 then
         self._errno = box.errno.ETIMEDOUT
-        return false
+        return 0
     end
-    return true
+    return wres
 end
 
-socket_methods.wait = function(self, timeout)
-    self._errno = nil
-    if timeout == nil then
-        timeout = TIMEOUT_INFINITY
-    end
+socket_methods.readable = function(self, timeout)
+    return wait_safely(self, 0, timeout) ~= 0
+end
 
+socket_methods.wait = function(self, timeout)
     local wres = wait_safely(self, 2, timeout)
-
     if wres == 0 then
-        self._errno = box.errno.ETIMEDOUT
-        return
+        return nil
     end
-
     local res = ''
     if bit.band(wres, 1) ~= 0 then
         res = res .. 'R'
@@ -223,26 +253,16 @@ socket_methods.wait = function(self, timeout)
 end
 
 socket_methods.writable = function(self, timeout)
-    self._errno = nil
-    if timeout == nil then
-        timeout = TIMEOUT_INFINITY
-    end
-
-    local wres = wait_safely(self, 1, timeout)
-
-    if wres == 0 then
-        self._errno = box.errno.ETIMEDOUT
-        return false
-    end
-    return true
+    return wait_safely(self, 1, timeout) ~= 0
 end
 
 socket_methods.listen = function(self, backlog)
+    local fd = check_socket(self)
     self._errno = nil
     if backlog == nil then
         backlog = 256
     end
-    local res = ffi.C.listen(self.fh, backlog)
+    local res = ffi.C.listen(fd, backlog)
     if res < 0 then
         self._errno = box.errno()
         return false
@@ -251,15 +271,16 @@ socket_methods.listen = function(self, backlog)
 end
 
 socket_methods.bind = function(self, host, port)
+    local fd = check_socket(self)
     self._errno = nil
 
     host = tostring(host)
     port = tostring(port)
 
-    addr_len[0] = ffi.sizeof(addr)
+    addr_len[0] = ffi.sizeof(addrbuf)
     local res = ffi.C.bsdsocket_local_resolve(host, port, addr, addr_len)
     if res == 0 then
-        res = ffi.C.bind(self.fh, addr, addr_len[0]);
+        res = ffi.C.bind(fd, addr, addr_len[0]);
     end
     if res == 0 then
         return true
@@ -270,6 +291,7 @@ socket_methods.bind = function(self, host, port)
 end
 
 socket_methods.close = function(self)
+    local fd = check_socket(self)
     if self.waiters ~= nil then
         for fid, fiber in pairs(self.waiters) do
             fiber:wakeup()
@@ -278,14 +300,16 @@ socket_methods.close = function(self)
     end
 
     self._errno = nil
-    if ffi.C.close(self.fh) < 0 then
+    if ffi.C.close(fd) < 0 then
         self._errno = box.errno()
         return false
     end
+    ffi.gc(self.socket, nil)
     return true
 end
 
 socket_methods.shutdown = function(self, how)
+    local fd = check_socket(self)
     local hvariants = {
         ['R']           = 0,
         ['READ']        = 0,
@@ -304,7 +328,7 @@ socket_methods.shutdown = function(self, how)
         ihow = 2
     end
     self._errno = nil
-    if ffi.C.shutdown(self.fh, ihow) < 0 then
+    if ffi.C.shutdown(fd, ihow) < 0 then
         self._errno = box.errno()
         return false
     end
@@ -312,7 +336,9 @@ socket_methods.shutdown = function(self, how)
 end
 
 socket_methods.setsockopt = function(self, level, name, value)
-    local info = get_ivalue(box.socket.internal.SO_OPT, name)
+    local fd = check_socket(self)
+
+    local info = get_ivalue(internal.SO_OPT, name)
 
     if info == nil then
         error(sprintf("Unknown socket option name: %s", tostring(name)))
@@ -326,7 +352,7 @@ socket_methods.setsockopt = function(self, level, name, value)
 
     if type(level) == 'string' then
         if level == 'SOL_SOCKET' then
-            level = box.socket.internal.SOL_SOCKET
+            level = internal.SOL_SOCKET
         else
             local p = ffi.C.getprotobyname(level)
             if p == nil then
@@ -349,7 +375,7 @@ socket_methods.setsockopt = function(self, level, name, value)
 
     if info.type == 1 then
         local value = ffi.new("int[1]", value)
-        local res = ffi.C.setsockopt(self.fh,
+        local res = ffi.C.setsockopt(fd,
             level, info.iname, value, ffi.sizeof('int'))
 
         if res < 0 then
@@ -360,7 +386,7 @@ socket_methods.setsockopt = function(self, level, name, value)
     end
 
     if info.type == 2 then
-        local res = ffi.C.setsockopt(self.fh,
+        local res = ffi.C.setsockopt(fd,
             level, info.iname, value, ffi.sizeof('size_t'))
         if res < 0 then
             self._errno = box.errno()
@@ -376,7 +402,9 @@ socket_methods.setsockopt = function(self, level, name, value)
 end
 
 socket_methods.getsockopt = function(self, level, name)
-    local info = get_ivalue(box.socket.internal.SO_OPT, name)
+    local fd = check_socket(self)
+
+    local info = get_ivalue(internal.SO_OPT, name)
 
     if info == nil then
         error(sprintf("Unknown socket option name: %s", tostring(name)))
@@ -386,7 +414,7 @@ socket_methods.getsockopt = function(self, level, name)
 
     if type(level) == 'string' then
         if level == 'SOL_SOCKET' then
-            level = box.socket.internal.SOL_SOCKET
+            level = internal.SOL_SOCKET
         else
             local p = ffi.C.getprotobyname(level)
             if p == nil then
@@ -403,7 +431,7 @@ socket_methods.getsockopt = function(self, level, name)
     if info.type == 1 then
         local value = ffi.new("int[1]", 0)
         local len = ffi.new("size_t[1]", ffi.sizeof('int'))
-        local res = ffi.C.getsockopt(self.fh, level, info.iname, value, len)
+        local res = ffi.C.getsockopt(fd, level, info.iname, value, len)
 
         if res < 0 then
             self._errno = box.errno()
@@ -419,7 +447,7 @@ socket_methods.getsockopt = function(self, level, name)
     if info.type == 2 then
         local value = ffi.new("char[256]", { 0 })
         local len = ffi.new("size_t[1]", 256)
-        local res = ffi.C.getsockopt(self.fh, level, info.iname, value, len)
+        local res = ffi.C.getsockopt(fd, level, info.iname, value, len)
         if res < 0 then
             self._errno = box.errno()
             return nil
@@ -434,14 +462,15 @@ socket_methods.getsockopt = function(self, level, name)
 end
 
 socket_methods.linger = function(self, active, timeout)
+    local fd = check_socket(self)
 
-    local info = box.socket.internal.SO_OPT.SO_LINGER
+    local info = internal.SO_OPT.SO_LINGER
     self._errno = nil
     if active == nil then
         local value = ffi.new("linger_t[1]")
         local len = ffi.new("size_t[1]", 2 * ffi.sizeof('int'))
-        local res = ffi.C.getsockopt(self.fh,
-            box.socket.internal.SOL_SOCKET, info.iname, value, len)
+        local res = ffi.C.getsockopt(fd,
+            internal.SOL_SOCKET, info.iname, value, len)
         if res < 0 then
             self._errno = box.errno()
             return nil
@@ -468,8 +497,8 @@ socket_methods.linger = function(self, active, timeout)
     local value = ffi.new("linger_t[1]",
         { { active = iactive, timeout = timeout } })
     local len = 2 * ffi.sizeof('int')
-    local res = ffi.C.setsockopt(self.fh,
-        box.socket.internal.SOL_SOCKET, info.iname, value, len)
+    local res = ffi.C.setsockopt(fd,
+        internal.SOL_SOCKET, info.iname, value, len)
     if res < 0 then
         self._errno = box.errno()
         return nil
@@ -479,25 +508,15 @@ socket_methods.linger = function(self, active, timeout)
 end
 
 socket_methods.accept = function(self)
-
+    local fd = check_socket(self)
     self._errno = nil
 
-    local fh = ffi.C.accept(self.fh, nil, nil)
-
-    if fh < 1 then
+    local cfd, from = internal.accept(fd)
+    if cfd == nil then
         self._errno = box.errno()
         return nil
     end
-
-    fh = tonumber(fh)
-
-    -- Make socket to be non-blocked by default
-    -- ignore result
-    ffi.C.bsdsocket_nonblock(fh, 1)
-
-    local socket = { fh = fh }
-    setmetatable(socket, box.socket.internal.socket_mt)
-    return socket
+    return bless_socket(cfd), from
 end
 
 local function readchunk(self, size, timeout)
@@ -521,7 +540,7 @@ local function readchunk(self, size, timeout)
 
         timeout = timeout - ( box.time() - started )
 
-        local data = self:sysread(4096)
+        local data = self:sysread()
         if data ~= nil then
             self.rbuf = self.rbuf .. data
             if string.len(self.rbuf) >= size then
@@ -552,18 +571,24 @@ local function readline_check(self, eols, limit)
     if string.len(rbuf) == 0 then
         return nil
     end
+
+    local shortest
     for i, eol in pairs(eols) do
         if string.len(rbuf) >= string.len(eol) then
             local data = string.match(rbuf, "^(.-" .. eol .. ")")
             if data ~= nil then
                 if string.len(data) > limit then
-                    return string.sub(data, 1, limit)
+                    data = string.sub(data, 1, limit)
+                end
+                if shortest == nil then
+                    shortest = data
+                elseif #shortest > #data then
+                    shortest = data
                 end
-                return data
             end
         end
     end
-    return nil
+    return shortest
 end
 
 local function readline(self, limit, eol, timeout)
@@ -589,7 +614,7 @@ local function readline(self, limit, eol, timeout)
 
         timeout = timeout - ( box.time() - started )
 
-        local data = self:sysread(4096)
+        local data = self:sysread()
         if data ~= nil then
             self.rbuf = self.rbuf .. data
 
@@ -621,6 +646,7 @@ local function readline(self, limit, eol, timeout)
 end
 
 socket_methods.read = function(self, opts, timeout)
+    check_socket(self)
     timeout = timeout and tonumber(timeout) or TIMEOUT_INFINITY
     if type(opts) == 'number' then
         return readchunk(self, opts, timeout)
@@ -641,6 +667,7 @@ socket_methods.read = function(self, opts, timeout)
 end
 
 socket_methods.write = function(self, octets, timeout)
+    check_socket(self)
     if timeout == nil then
         timeout = TIMEOUT_INFINITY
     end
@@ -666,10 +693,11 @@ socket_methods.write = function(self, octets, timeout)
 end
 
 socket_methods.send = function(self, octets, flags)
-    local iflags = get_iflags(box.socket.internal.SEND_FLAGS, flags)
+    local fd = check_socket(self)
+    local iflags = get_iflags(internal.SEND_FLAGS, flags)
 
     self._errno = nil
-    local res = ffi.C.send(self.fh, octets, string.len(octets), iflags)
+    local res = ffi.C.send(fd, octets, string.len(octets), iflags)
     if res == -1 then
         self._errno = box.errno()
         return false
@@ -678,19 +706,18 @@ socket_methods.send = function(self, octets, flags)
 end
 
 socket_methods.recv = function(self, size, flags)
-    local iflags = get_iflags(box.socket.internal.SEND_FLAGS, flags)
+    local fd = check_socket(self)
+    local iflags = get_iflags(internal.SEND_FLAGS, flags)
     if iflags == nil then
         self._errno = box.errno.EINVAL
         return nil
     end
 
-    if size == nil then
-        size = 512
-    end
+    size = size or 512
     self._errno = nil
     local buf = ffi.new("char[?]", size)
 
-    local res = ffi.C.recv(self.fh, buf, size, iflags)
+    local res = ffi.C.recv(fd, buf, size, iflags)
 
     if res == -1 then
         self._errno = box.errno()
@@ -700,13 +727,16 @@ socket_methods.recv = function(self, size, flags)
 end
 
 socket_methods.recvfrom = function(self, size, flags)
-    local iflags = get_iflags(box.socket.internal.SEND_FLAGS, flags)
+    local fd = check_socket(self)
+    local iflags = get_iflags(internal.SEND_FLAGS, flags)
     if iflags == nil then
         self._errno = box.errno.EINVAL
         return nil
     end
+
+    size = size or 512
     self._errno = nil
-    local res, from = box.socket.internal.recvfrom(self.fh, size, iflags)
+    local res, from = internal.recvfrom(fd, size, iflags)
     if res == nil then
         self._errno = box.errno()
         return nil
@@ -715,7 +745,8 @@ socket_methods.recvfrom = function(self, size, flags)
 end
 
 socket_methods.sendto = function(self, host, port, octets, flags)
-    local iflags = get_iflags(box.socket.internal.SEND_FLAGS, flags)
+    local fd = check_socket(self)
+    local iflags = get_iflags(internal.SEND_FLAGS, flags)
 
     if iflags == nil then
         self._errno = box.errno.EINVAL
@@ -731,10 +762,10 @@ socket_methods.sendto = function(self, host, port, octets, flags)
     port = tostring(port)
     octets = tostring(octets)
 
-    addr_len[0] = ffi.sizeof(addr)
+    addr_len[0] = ffi.sizeof(addrbuf)
     local res = ffi.C.bsdsocket_local_resolve(host, port, addr, addr_len)
     if res == 0 then
-        res = ffi.C.sendto(self.fh, octets, string.len(octets), iflags,
+        res = ffi.C.sendto(fd, octets, string.len(octets), iflags,
             addr, addr_len[0])
     end
     if res < 0 then
@@ -745,13 +776,13 @@ socket_methods.sendto = function(self, host, port, octets, flags)
 end
 
 local function create_socket(domain, stype, proto)
-    local idomain = get_ivalue(box.socket.internal.DOMAIN, domain)
+    local idomain = get_ivalue(internal.DOMAIN, domain)
     if idomain == nil then
         box.errno(box.errno.EINVAL)
         return nil
     end
 
-    local itype = get_ivalue(box.socket.internal.SO_TYPE, stype)
+    local itype = get_ivalue(internal.SO_TYPE, stype)
     if itype == nil then
         box.errno(box.errno.EINVAL)
         return nil
@@ -771,24 +802,11 @@ local function create_socket(domain, stype, proto)
         iproto = p.p_proto
     end
 
-    local fh = ffi.C.socket(idomain, itype, iproto)
-    if fh < 0 then
-        return nil
-    end
-
-    fh = tonumber(fh)
-
-    -- Make socket to be non-blocked by default
-    if ffi.C.bsdsocket_nonblock(fh, 1) < 0 then
-        local errno = box.errno()
-        ffi.C.close(fh)
-        box.errno(errno)
+    local fd = ffi.C.socket(idomain, itype, iproto)
+    if fd < 1 then
         return nil
     end
-
-    local socket = { fh = fh }
-    setmetatable(socket, box.socket.internal.socket_mt)
-    return socket
+    return bless_socket(fd)
 end
 
 local function getaddrinfo(host, port, timeout, opts)
@@ -806,7 +824,7 @@ local function getaddrinfo(host, port, timeout, opts)
     local ga_opts = {}
     if opts ~= nil then
         if opts.type ~= nil then
-            local itype = get_ivalue(box.socket.internal.SO_TYPE, opts.type)
+            local itype = get_ivalue(internal.SO_TYPE, opts.type)
             if itype == nil then
                 self._errno = box.errno.EINVAL
                 return nil
@@ -815,7 +833,7 @@ local function getaddrinfo(host, port, timeout, opts)
         end
 
         if opts.family ~= nil then
-            local ifamily = get_ivalue(box.socket.internal.DOMAIN, opts.family)
+            local ifamily = get_ivalue(internal.DOMAIN, opts.family)
             if ifamily == nil then
                 self._errno = box.errno.EINVAL
                 return nil
@@ -834,7 +852,7 @@ local function getaddrinfo(host, port, timeout, opts)
 
         if opts.flags ~= nil then
             ga_opts.flags =
-                get_iflags(box.socket.internal.AI_FLAGS, opts.flags)
+                get_iflags(internal.AI_FLAGS, opts.flags)
             if ga_opts.flags == nil then
                 self._errno = box.errno()
                 return nil
@@ -843,7 +861,7 @@ local function getaddrinfo(host, port, timeout, opts)
 
     end
 
-    local r = box.socket.internal.getaddrinfo(host, port, timeout, ga_opts)
+    local r = internal.getaddrinfo(host, port, timeout, ga_opts)
     if r == nil then
         self._errno = box.errno()
     else
@@ -852,26 +870,50 @@ local function getaddrinfo(host, port, timeout, opts)
     return r
 end
 
+local soname_mt = {
+    __tostring = function(si)
+        if si.host == nil and si.port == nil then
+            return ''
+        end
+        if si.host == nil then
+            return sprintf('%s:%s', '0', tostring(si.port))
+        end
+
+        if si.port == nil then
+            return sprintf('%s:%', tostring(si.host), 0)
+        end
+        return sprintf('%s:%s', tostring(si.host), tostring(si.port))
+    end
+}
+
 socket_methods.name = function(self)
-    local aka = box.socket.internal.name(self.fh)
+    local fd = check_socket(self)
+    local aka = internal.name(fd)
     if aka == nil then
         self._errno = box.errno()
         return nil
     end
     self._errno = nil
+    setmetatable(aka, soname_mt)
     return aka
 end
 
 socket_methods.peer = function(self)
-    local peer = box.socket.internal.peer(self.fh)
+    local fd = check_socket(self)
+    local peer = internal.peer(fd)
     if peer == nil then
         self._errno = box.errno()
         return nil
     end
     self._errno = nil
+    setmetatable(peer, soname_mt)
     return peer
 end
 
+socket_methods.fd = function(self)
+    return check_socket(self)
+end
+
 -- tcp connector
 local function tcp_connect_remote(remote, timeout)
     local s = create_socket(remote.family, remote.type, remote.protocol)
@@ -924,6 +966,11 @@ local function tcp_connect(host, port, timeout)
     if dns == nil then
         return nil
     end
+
+    if #dns == 0 then
+        box.errno(box.errno.EINVAL)
+        return nil
+    end
     for i, remote in pairs(dns) do
         timeout = stop - box.time()
         if timeout <= 0 then
@@ -938,105 +985,122 @@ local function tcp_connect(host, port, timeout)
     return nil
 end
 
-local function tcp_server_remote(list, prepare, handler)
-    local slist = {}
-
-    -- bind/create sockets
-    for _, addr in pairs(list) do
-        local s = create_socket(addr.family, addr.type, addr.protocol)
+local function tcp_server_handler(server, sc, from)
+    box.fiber.name(sprintf("%s/client/%s:%s", server.name, from.host, from.port))
+    server.handler(sc, from)
+    sc:close()
+end
 
-        local ok = false
-        if s ~= nil then
-            if s:bind(addr.host, addr.port) then
-                local prepared, backlog = pcall(prepare, s)
-                if prepared and s:listen(backlog) then
-                    ok = true
-                end
-            end
+local function tcp_server_loop(server, s, addr)
+    box.fiber.name(sprintf("%s/listen/%s:%s", server.name, addr.host, addr.port))
+    while s:readable() do
+        local sc, from = s:accept()
+        if sc == nil then
+            break
         end
-
-        -- errors
-        if not ok then
-            if s ~= nil then
-                s:close()
-            end
-            local save_errno = box.errno()
-            for _, s in pairs(slist) do
-                s:close()
-            end
-            box.errno(save_errno)
-            return nil
-        end
-
-        table.insert(slist, s)
+        box.fiber.wrap(tcp_server_handler, server, sc, from)
+    end
+    if addr.family == 'AF_UNIX' and addr.port then
+        os_remove(addr.port) -- remove unix socket
     end
-    
-    local server = { s = slist }
+end
 
-    server.stop = function()
-        if #server.s == 0 then
-            return false
-        end
-        for _, s in pairs(server.s) do
-            s:close()
-        end
-        server.s = {}
+local function tcp_server_usage()
+    error('Usage: socket.tcp_server(host, port, handler | opts)')
+end
+
+local function tcp_server_bind(s, addr)
+    if s:bind(addr.host, addr.port) then
         return true
     end
 
-    for _, s in pairs(server.s) do
-        box.fiber.wrap(function(s)
-            box.fiber.name(sprintf("listen_fd=%d",s.fh))
+    if addr.family ~= 'AF_UNIX' then
+        return false
+    end
 
-            while s:readable() do
-                
-                local sc = s:accept()
+    if boxerrno() ~= boxerrno.EADDRINUSE then
+        return false
+    end
 
-                if sc == nil then
-                    break
-                end
+    local save_errno = boxerrno()
 
-                box.fiber.wrap(function(sc)
-                    pcall(handler, sc)
-                    sc:close()
-                end, sc)
-            end
-        end, s)
+    local sc = tcp_connect(addr.host, addr.port)
+    if sc ~= nil then
+        sc:close()
+        boxerrno(save_errno)
+        return false
     end
 
-    return server
+    if boxerrno() ~= boxerrno.ECONNREFUSED then
+        boxerrno(save_errno)
+        return false
+    end
 
+    os_remove(addr.port)
+    return s:bind(addr.host, addr.port)
 end
 
-local function tcp_server(host, port, prepare, handler, timeout)
-    if handler == nil then
-        handler = prepare
-        prepare = function() end
-    end
 
-    if type(prepare) ~= 'function' or type(handler) ~= 'function' then
-        error("Usage: socket.tcp_server(host, port[, prepare], handler)")
+local function tcp_server(host, port, opts, timeout)
+    local server = {}
+    if type(opts) == 'function' then
+        server.handler = opts
+    elseif type(opts) == 'table' then
+        if type(opts.handler) ~='function' or (opts.prepare ~= nil and
+            type(opts.prepare) ~= 'function') then
+            tcp_server_usage()
+        end
+        for k, v in pairs(opts) do
+            server[k] = v
+        end
+    else
+        tcp_server_usage()
     end
-
+    server.name = server.name or 'server'
+    timeout = timeout and tonumber(timeout) or TIMEOUT_INFINITY
+    local dns
     if host == 'unix/' then
-        return tcp_server_remote({{host = host, port = port, protocol = 0,
-            family = 'PF_UNIX', type = 'SOCK_STREAM' }}, prepare, handler)
+        dns = {{host = host, port = port, family = 'AF_UNIX', protocol = 0,
+            type = 'SOCK_STREAM' }}
+    else
+        dns = getaddrinfo(host, port, timeout, { type = 'SOCK_STREAM',
+            flags = 'AI_PASSIVE'})
+        if dns == nil then
+            return nil
+        end
     end
 
-    local dns = getaddrinfo(host, port, timeout, { type = 'SOCK_STREAM',
-        protocol = 'tcp' })
-    if dns == nil then
-        return nil
+    for _, addr in ipairs(dns) do
+        local s = create_socket(addr.family, addr.type, addr.protocol)
+        if s ~= nil then
+            local backlog
+            if server.prepare then
+                backlog = server.prepare(s)
+            else
+                s:setsockopt('SOL_SOCKET', 'SO_REUSEADDR', 1) -- ignore error
+            end
+            if not tcp_server_bind(s, addr) or not s:listen(backlog) then
+                local save_errno = box.errno()
+                s:close()
+                box.errno(save_errno)
+                return nil
+            end
+            box.fiber.wrap(tcp_server_loop, server, s, addr)
+            return s, addr
+       end
     end
-    return tcp_server_remote(dns, prepare, handler)
+    -- DNS resolved successfully, but addresss family is not supported
+    box.errno(box.errno.EAFNOSUPPORT)
+    return nil
 end
 
-box.socket.internal = {
-    socket_mt   = {
+socket_mt   = {
         __index     = socket_methods,
         __tostring  = function(self)
+            local fd = check_socket(self)
+
             local save_errno = self._errno
-            local name = sprintf("fd %d", self.fh)
+            local name = sprintf("fd %d", fd)
             local aka = self:name()
             if aka ~= nil then
                 name = sprintf("%s, aka %s:%s", name, aka.host, aka.port)
@@ -1048,7 +1112,6 @@ box.socket.internal = {
             self._errno = save_errno
             return name
         end
-    },
 }
 
 setmetatable(box.socket, {
diff --git a/test/box/bsdsocket.result b/test/box/bsdsocket.result
index d67a0334e1fadc52921b00da572f2ed446c7fea1..144966a65f22feefc86b80caedd52d2ae9b5f03f 100644
--- a/test/box/bsdsocket.result
+++ b/test/box/bsdsocket.result
@@ -30,6 +30,9 @@ lua type(s:error())
 ---
  - nil
 ...
+lua for k in pairs(getmetatable(s).__index) do local r, msg = pcall(s[k]); if not msg:match('Usage:') then print(k) end end
+---
+...
 lua s:nonblock(false)
 ---
  - false
@@ -177,7 +180,7 @@ lua sc:readable(.5)
 ---
  - true
 ...
-lua sc:sysread(4096)
+lua sc:sysread()
 ---
  - ok
 ...
@@ -219,7 +222,7 @@ lua s:getsockopt('SOL_SOCKET', 'SO_DEBUG')
 ...
 lua s:setsockopt('SOL_SOCKET', 'SO_ACCEPTCONN', 1)
 ---
-error: '[string "-- bsdsocket.lua (internal file)..."]:322: Socket option SO_ACCEPTCONN is read only'
+error: '[string "-- bsdsocket.lua (internal file)..."]:348: Socket option SO_ACCEPTCONN is read only'
 ...
 lua s:getsockopt('SOL_SOCKET', 'SO_RCVBUF') > 32
 ---
@@ -303,9 +306,20 @@ lua sc:write('Hello, world')
 ---
  - true
 ...
-lua sa = s:accept()
+lua sa, addr = s:accept()
+---
+...
+lua addr2 = sa:name()
 ---
 ...
+lua addr2.host == addr.host
+---
+ - true
+...
+lua addr2.family == addr.family
+---
+ - true
+...
 lua sa:nonblock(1)
 ---
  - true
@@ -458,7 +472,7 @@ lua s:bind('unix/', '/tmp/tarantool-test-socket')
 ---
  - true
 ...
-lua string.match(tostring(sc), 'fd %d+, aka unix/:/tmp/tarantool%-test%-socket') ~= nil
+lua string.match(tostring(s), 'fd %d+, aka unix/:/tmp/tarantool%-test%-socket') ~= nil
 ---
  - true
 ...
@@ -576,6 +590,10 @@ lua box.cjson.encode(sc:name())
 ---
  - {"host":"0.0.0.0","family":"AF_INET","type":"SOCK_STREAM","protocol":"tcp","port":0}
 ...
+lua sc:name()
+---
+ - 0.0.0.0:0
+...
 lua sc:nonblock(true)
 ---
  - true
@@ -614,7 +632,7 @@ lua s:readable(10)
 ---
  - true
 ...
-lua local d, from = s:recvfrom(4096) print(' - ', from.port > 0) from.port = 'Random port' return box.cjson.encode{d, from}
+lua local d, from = s:recvfrom() print(' - ', from.port > 0) from.port = 'Random port' return box.cjson.encode{d, from}
 ---
  - true
  - ["Hello, world, 2",{"host":"127.0.0.1","family":"AF_INET","port":"Random port"}]
@@ -676,7 +694,7 @@ lua sc:readable(1)
 ---
  - true
 ...
-lua data_r, from_r = sc:recvfrom(4096)
+lua data_r, from_r = sc:recvfrom()
 ---
 ...
 lua data_r
@@ -812,11 +830,19 @@ lua box.socket.tcp_connect('unix/', '/tmp/tarantool-test-socket'), box.errno() =
  - nil
  - true
 ...
-lua s = box.socket.tcp_connect('127.0.0.1', box.cfg.primary_port)
+lua sa = box.socket.tcp_connect('127.0.0.1', box.cfg.primary_port)
+---
+...
+lua sa:close()
+---
+ - true
+...
+lua sa.socket.fd = 512
 ---
 ...
-lua sa = { fh = 512 } setmetatable(sa, getmetatable(s))
+lua sa:fd()
 ---
+ - 512
 ...
 lua tostring(sa)
 ---
@@ -830,6 +856,12 @@ lua sa:writable(0)
 ---
  - true
 ...
+lua sa = nil
+---
+...
+lua s = box.socket.tcp_connect('127.0.0.1', box.cfg.primary_port)
+---
+...
 lua ch = box.ipc.channel()
 ---
 ...
@@ -993,9 +1025,13 @@ lua s:close()
 ---
  - true
 ...
-lua server = box.socket.tcp_server('unix/', path, function(s) s:write('Hello, world') end)
+lua server, addr = box.socket.tcp_server('unix/', path, function(s) s:write('Hello, world') end)
 ---
 ...
+lua type(addr)
+---
+ - table
+...
 lua server ~= nil
 ---
  - true
@@ -1014,7 +1050,140 @@ lua client:read(123)
 ---
  - Hello, world
 ...
-lua server:stop()
+lua client:close()
+---
+ - true
+...
+lua server:close()
+---
+ - true
+...
+lua box.fiber.sleep(.5)
+---
+...
+unix socket was removed
+lua server, addr = box.socket.tcp_server('localhost', 0, { handler = function(s) s:read(2); s:write('Hello, world') end, name = 'testserv'})
+---
+...
+lua type(addr)
+---
+ - table
+...
+lua server ~= nil
+---
+ - true
+...
+lua addr2 = server:name()
+---
+...
+lua addr.host == addr2.host
+---
+ - true
+...
+lua addr.family == addr2.family
 ---
  - true
 ...
+lua box.fiber.sleep(.5)
+---
+...
+lua client = box.socket.tcp_connect(addr2.host, addr2.port)
+---
+...
+lua client ~= nil
+---
+ - true
+...
+lua cnt = 0
+---
+...
+lua for i=100,200 do local f = box.fiber.find(i); if f and f:name():match('^testserv/') then cnt = cnt + 1; end; end
+---
+...
+lua cnt
+---
+ - 2
+...
+lua client:write('hi')
+---
+ - true
+...
+lua client:read(123)
+---
+ - Hello, world
+...
+lua client:close()
+---
+ - true
+...
+lua server:close()
+---
+ - true
+...
+lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 'ip')
+---
+...
+lua s:bind('unix/', '/tmp/tarantool-test-socket')
+---
+ - true
+...
+lua s:listen()
+---
+ - true
+...
+lua s = nil
+---
+...
+lua collectgarbage('collect')
+---
+ - 0
+...
+lua collectgarbage('collect')
+---
+ - 0
+...
+lua client, errno = box.socket.tcp_connect('unix/', '/tmp/tarantool-test-socket'), box.errno()
+---
+...
+lua errno == box.errno.ECONNREFUSED
+---
+ - true
+...
+test bind unix socket if old socket is exists
+lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 0)
+---
+...
+lua s:bind('unix/', '/tmp/tarantool-test-socket')
+---
+ - true
+...
+lua s:listen()
+---
+ - true
+...
+lua s:close()
+---
+ - true
+...
+lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 0)
+---
+...
+lua s:bind('unix/', '/tmp/tarantool-test-socket')
+---
+ - false
+...
+lua s = box.socket.tcp_server('unix/', '/tmp/tarantool-test-socket', function() end)
+---
+...
+lua s ~= nil
+---
+ - true
+...
+lua s:close()
+---
+ - true
+...
+lua box.cjson.encode{ box.socket.tcp_connect('test:test@localhost:3303') == nil, box.errno.strerror() }
+---
+ - [true,"Invalid argument"]
+...
diff --git a/test/box/bsdsocket.test b/test/box/bsdsocket.test
index 64ac95aeb20c81022fb51e048d0efb7d1312f0da..194f7e5edf76023e56dc546bc1bb997ac99ed433 100644
--- a/test/box/bsdsocket.test
+++ b/test/box/bsdsocket.test
@@ -13,6 +13,8 @@ exec admin "lua type(s)"
 exec admin "lua string.match(tostring(s), 'fd %d+, aka 0%.0%.0%.0:0') ~= nil"
 exec admin "lua s:errno()"
 exec admin "lua type(s:error())"
+# Invalid arguments
+exec admin "lua for k in pairs(getmetatable(s).__index) do local r, msg = pcall(s[k]); if not msg:match('Usage:') then print(k) end end"
 
 exec admin "lua s:nonblock(false)"
 exec admin "lua s:sysconnect('127.0.0.1', box.cfg.primary_port)"
@@ -56,7 +58,7 @@ exec admin "lua sc:nonblock(false)"
 exec admin "lua sc:sysconnect('127.0.0.1', 3457)"
 exec admin "lua sc:nonblock(true)"
 exec admin "lua sc:readable(.5)"
-exec admin "lua sc:sysread(4096)"
+exec admin "lua sc:sysread()"
 exec admin "lua string.match(tostring(sc), ', peer') ~= nil"
 exec admin "lua #sevres"
 exec admin "lua sevres[1].host"
@@ -93,7 +95,10 @@ exec admin "lua r or errno == box.errno.EINPROGRESS"
 exec admin "lua sc:writable(10)"
 exec admin "lua sc:write('Hello, world')"
 
-exec admin "lua sa = s:accept()"
+exec admin "lua sa, addr = s:accept()"
+exec admin "lua addr2 = sa:name()"
+exec admin "lua addr2.host == addr.host"
+exec admin "lua addr2.family == addr.family"
 exec admin "lua sa:nonblock(1)"
 exec admin "lua sa:read(8)"
 exec admin "lua sa:read(3)"
@@ -139,7 +144,7 @@ exec admin "lua s:nonblock()"
 if os.path.exists('/tmp/tarantool-test-socket'):
         os.unlink('/tmp/tarantool-test-socket')
 exec admin "lua s:bind('unix/', '/tmp/tarantool-test-socket')"
-exec admin "lua string.match(tostring(sc), 'fd %d+, aka unix/:/tmp/tarantool%-test%-socket') ~= nil"
+exec admin "lua string.match(tostring(s), 'fd %d+, aka unix/:/tmp/tarantool%-test%-socket') ~= nil"
 exec admin "lua s:listen(1234)"
 
 exec admin "lua sc = box.socket('PF_UNIX', 'SOCK_STREAM', 'ip')"
@@ -181,6 +186,7 @@ exec admin "lua box.cjson.encode(box.socket.getaddrinfo('ya.ru', '80', { flags =
 
 exec admin "lua sc = box.socket('AF_INET', 'SOCK_STREAM', 'tcp')"
 exec admin "lua box.cjson.encode(sc:name())"
+exec admin "lua sc:name()"
 exec admin "lua sc:nonblock(true)"
 exec admin "lua sc:close()"
 
@@ -193,7 +199,7 @@ exec admin "lua s:recv(4096)"
 
 exec admin "lua sc:sendto('127.0.0.1', 3548, 'Hello, world, 2')"
 exec admin "lua s:readable(10)"
-exec admin "lua local d, from = s:recvfrom(4096) print(' - ', from.port > 0) from.port = 'Random port' return box.cjson.encode{d, from}"
+exec admin "lua local d, from = s:recvfrom() print(' - ', from.port > 0) from.port = 'Random port' return box.cjson.encode{d, from}"
 exec admin "lua s:close()"
 exec admin "lua sc:close()"
 
@@ -210,7 +216,7 @@ exec admin "lua data, from = s:recvfrom(10)"
 exec admin "lua data"
 exec admin "lua s:sendto(from.host, from.port, 'Hello, hello!')"
 exec admin "lua sc:readable(1)"
-exec admin "lua data_r, from_r = sc:recvfrom(4096)"
+exec admin "lua data_r, from_r = sc:recvfrom()"
 exec admin "lua data_r"
 exec admin "lua from_r.host"
 exec admin "lua from_r.port == s:name().port"
@@ -261,12 +267,16 @@ if os.path.exists(path):
         os.unlink(path)
 exec admin "lua box.socket.tcp_connect('unix/', '{}'), box.errno() == box.errno.ENOENT".format(path)
 
-exec admin "lua s = box.socket.tcp_connect('127.0.0.1', box.cfg.primary_port)"
-exec admin "lua sa = { fh = 512 } setmetatable(sa, getmetatable(s))"
+exec admin "lua sa = box.socket.tcp_connect('127.0.0.1', box.cfg.primary_port)"
+exec admin "lua sa:close()"
+exec admin "lua sa.socket.fd = 512"
+exec admin "lua sa:fd()"
 exec admin "lua tostring(sa)"
 exec admin "lua sa:readable(0)"
 exec admin "lua sa:writable(0)"
+exec admin "lua sa = nil"
 
+exec admin "lua s = box.socket.tcp_connect('127.0.0.1', box.cfg.primary_port)"
 exec admin "lua ch = box.ipc.channel()"
 exec admin "lua f = box.fiber.wrap(function() s:read(12) ch:put(true) end)"
 exec admin "lua box.fiber.sleep(.1)"
@@ -318,12 +328,63 @@ exec admin "lua s:close()"
 
 os.unlink(path)
 
-exec admin "lua server = box.socket.tcp_server('unix/', path, function(s) s:write('Hello, world') end)"
+exec admin "lua server, addr = box.socket.tcp_server('unix/', path, function(s) s:write('Hello, world') end)"
+exec admin "lua type(addr)"
 exec admin "lua server ~= nil"
 exec admin "lua box.fiber.sleep(.5)"
 exec admin "lua client = box.socket.tcp_connect('unix/', path)"
 exec admin "lua client ~= nil"
 exec admin "lua client:read(123)"
-exec admin "lua server:stop()"
+exec admin "lua client:close()"
+exec admin "lua server:close()"
+exec admin "lua box.fiber.sleep(.5)"
+
+if not os.path.exists(path):
+    print 'unix socket was removed'
+
+exec admin "lua server, addr = box.socket.tcp_server('localhost', 0, { handler = function(s) s:read(2); s:write('Hello, world') end, name = 'testserv'})"
+exec admin "lua type(addr)"
+exec admin "lua server ~= nil"
+exec admin "lua addr2 = server:name()"
+exec admin "lua addr.host == addr2.host"
+exec admin "lua addr.family == addr2.family"
+exec admin "lua box.fiber.sleep(.5)"
+exec admin "lua client = box.socket.tcp_connect(addr2.host, addr2.port)"
+exec admin "lua client ~= nil"
+# Check that listen and client fibers have appropriate names
+exec admin "lua cnt = 0"
+exec admin "lua for i=100,200 do local f = box.fiber.find(i); if f and f:name():match('^testserv/') then cnt = cnt + 1; end; end"
+exec admin "lua cnt"
+exec admin "lua client:write('hi')"
+exec admin "lua client:read(123)"
+exec admin "lua client:close()"
+exec admin "lua server:close()"
 
+# Test that socket is closed on GC
+exec admin "lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 'ip')"
+exec admin "lua s:bind('unix/', '{}')".format(path)
+exec admin "lua s:listen()"
+exec admin "lua s = nil"
+exec admin "lua collectgarbage('collect')"
+exec admin "lua collectgarbage('collect')"
+exec admin "lua client, errno = box.socket.tcp_connect('unix/', '{}'), box.errno()".format(path)
+exec admin "lua errno == box.errno.ECONNREFUSED"
 os.unlink(path)
+
+print 'test bind unix socket if old socket is exists'
+exec admin "lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 0)"
+exec admin "lua s:bind('unix/', '{}')".format(path)
+exec admin "lua s:listen()"
+exec admin "lua s:close()"
+if not os.path.exists(path):
+    print 'unix socket was removed: test failed'
+exec admin "lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 0)"
+exec admin "lua s:bind('unix/', '{}')".format(path)
+exec admin "lua s = box.socket.tcp_server('unix/', '{}', function() end)".format(path)
+exec admin "lua s ~= nil"
+exec admin "lua s:close()"
+if os.path.exists(path):
+    print 'unix socket was not removed: test failed'
+
+
+exec admin "lua box.cjson.encode{ box.socket.tcp_connect('test:test@localhost:3303') == nil, box.errno.strerror() }"
diff --git a/third_party/luajit b/third_party/luajit
index 880ca300e8fb7b432b9d25ed377db2102e4cb63d..41156fe1cdd6b60a5e8d9855c57699e89ccfbf97 160000
--- a/third_party/luajit
+++ b/third_party/luajit
@@ -1 +1 @@
-Subproject commit 880ca300e8fb7b432b9d25ed377db2102e4cb63d
+Subproject commit 41156fe1cdd6b60a5e8d9855c57699e89ccfbf97