diff --git a/src/lua/bsdsocket.lua b/src/lua/bsdsocket.lua
index ca7c1be90de9886db6e9dc64d4a47a43d2db5fda..e811602687972d093838b0ac4a6ead0dc5ddd0fc 100644
--- a/src/lua/bsdsocket.lua
+++ b/src/lua/bsdsocket.lua
@@ -546,7 +546,7 @@ local function readline_check(self, eols, limit)
     end
     for i, eol in pairs(eols) do
         if string.len(rbuf) >= string.len(eol) then
-            local data = string.match(rbuf, "^(.*" .. eol .. ")")
+            local data = string.match(rbuf, "^(.-" .. eol .. ")")
             if data ~= nil then
                 if string.len(data) > limit then
                     return string.sub(data, 1, limit)
@@ -607,12 +607,8 @@ socket_methods.readline = function(self, limit, eol, timeout)
         local data = self:sysread(4096)
         if data ~= nil then
             self.rbuf = self.rbuf .. data
-            if string.len(self.rbuf) >= limit then
-               data = string.sub(self.rbuf, 1, limit)
-               self.rbuf = string.sub(self.rbuf, limit + 1)
-               return data
-            end
 
+            -- eof
             if string.len(data) == 0 then
                 data = self.rbuf
                 self.rbuf = nil
@@ -624,6 +620,14 @@ socket_methods.readline = function(self, limit, eol, timeout)
                 self.rbuf = string.sub(self.rbuf, string.len(data) + 1)
                 return data
             end
+           
+            -- limit
+            if string.len(self.rbuf) >= limit then
+               data = string.sub(self.rbuf, 1, limit)
+               self.rbuf = string.sub(self.rbuf, limit + 1)
+               return data
+            end
+
         elseif self:errno() ~= box.errno.EAGAIN then
             self._errno = box.errno()
             return nil
@@ -840,36 +844,113 @@ socket_methods.name = function(self)
         self._errno = box.errno()
         return nil
     end
+    self._errno = nil
     return aka
 end
 
-if type(box.socket) == nil then
-    box.socket = {}
+socket_methods.peer = function(self)
+    local peer = box.socket.internal.peer(self.fh)
+    if peer == nil then
+        self._errno = box.errno()
+        return nil
+    end
+    self._errno = nil
+    return peer
+end
+
+-- tcp connector
+local function tcp_connect(host, port, timeout)
+    if host == 'unix/' and port ~= nil then
+        local s = package.loaded.socket('AF_UNIX', 'SOCK_STREAM', 'ip')
+        if s == nil then
+            return nil
+        end
+        if s:sysconnect(host, port) then
+            return s
+        else
+            local errno = box.errno()
+            s:close()
+            box.errno(errno)
+            return nil
+        end
+    end
+
+    if timeout == nil then
+        timeout = TIMEOUT_INFINITY
+    end
+    local started = box.time()
+    local dns = box.socket.getaddrinfo(host, port, timeout,
+                                    { type = 'SOCK_STREAM', protocol = 'tcp' })
+    if dns == nil then
+        return nil
+    end
+
+
+
+    for i, remote in pairs(dns) do
+        
+        timeout = timeout - (box.time() - started)
+        if timeout <= 0 then
+            box.errno(box.errno.ETIMEDOUT)
+            return nil
+        end
+
+        started = box.time()
+
+        local s = box.socket(remote.family, remote.type, 'tcp')
+        if s == nil then
+            return nil
+        end
+
+        if s:sysconnect(remote.host, remote.port) then
+
+            timeout = timeout - (box.time() - started)
+            if timeout <= 0 then
+                s:close()
+                break
+            end
+
+            if s:writable(timeout) then
+                return s
+            end
+        end
+
+        local save_errno = box.errno()
+        s:close()
+        box.errno(save_errno)
+    end
+   
+    if timeout <= 0 then
+        box.errno(box.errno.ETIMEDOUT)
+    end 
+    return nil
 end
 
 box.socket.internal = {
     socket_mt   = {
         __index     = socket_methods,
         __tostring  = function(self)
+            local save_errno = self._errno
             local name = sprintf("fd %d", self.fh)
-            local aka = box.socket.internal.name(self.fh)
+            local aka = self:name()
             if aka ~= nil then
                 name = sprintf("%s, aka %s:%s", name, aka.host, aka.port)
             end
-            local peer = box.socket.internal.peer(self.fh)
+            local peer = self:peer(self)
             if peer ~= nil then
                 name = sprintf("%s, peer %s:%s", name, peer.host, peer.port)
             end
+            self._errno = save_errno
             return name
         end
     },
-    
 }
 
 setmetatable(box.socket, {
     __call = create_socket,
     __index = {
         getaddrinfo = getaddrinfo,
+        tcp_connect = tcp_connect
     }
 })
 
diff --git a/test/box/bsdsocket.result b/test/box/bsdsocket.result
index 16456488203c374f4e955939ee3feb91658b9e1f..0417e31db8fe963e39caeac316f41cb47755fbe6 100644
--- a/test/box/bsdsocket.result
+++ b/test/box/bsdsocket.result
@@ -693,3 +693,38 @@ lua sc:close()
 ---
  - true
 ...
+tcp_connect
+lua s = box.socket.tcp_connect('mail.ru', 80)
+---
+...
+lua string.match(tostring(s), ', aka') ~= nil
+---
+ - true
+...
+lua string.match(tostring(s), ', peer') ~= nil
+---
+ - true
+...
+lua s:write('GET / HTTP/1.0\r\nHost: mail.ru\r\n\r\n')
+---
+ - true
+...
+lua header = s:readline(4000, { '\n\n', '\r\n\r\n' }, 1)
+---
+...
+lua string.match(header, '\r\n\r\n$') ~= nil
+---
+ - true
+...
+lua string.match(header, '200 [Oo][Kk]') ~= nil
+---
+ - true
+...
+lua s:close()
+---
+ - true
+...
+lua box.socket.tcp_connect('mail.ru', 80, 0.00000000001)
+---
+ - nil
+...
diff --git a/test/box/bsdsocket.test b/test/box/bsdsocket.test
index 8b69dbbc5adceb8ba67e3ee43823b98b04861e3e..5d9b94f2bd9eecbbd9bddbf0bef47708a054b054 100644
--- a/test/box/bsdsocket.test
+++ b/test/box/bsdsocket.test
@@ -214,3 +214,16 @@ exec admin "lua from_r.host"
 exec admin "lua from_r.port == s:name().port"
 exec admin "lua s:close()"
 exec admin "lua sc:close()"
+
+print("tcp_connect")
+
+exec admin "lua s = box.socket.tcp_connect('mail.ru', 80)"
+exec admin "lua string.match(tostring(s), ', aka') ~= nil"
+exec admin "lua string.match(tostring(s), ', peer') ~= nil"
+exec admin "lua s:write('GET / HTTP/1.0\\r\\nHost: mail.ru\\r\\n\\r\\n')"
+exec admin "lua header = s:readline(4000, { '\\n\\n', '\\r\\n\\r\\n' }, 1)"
+exec admin "lua string.match(header, '\\r\\n\\r\\n$') ~= nil"
+exec admin "lua string.match(header, '200 [Oo][Kk]') ~= nil"
+exec admin "lua s:close()"
+
+exec admin "lua box.socket.tcp_connect('mail.ru', 80, 0.00000000001)"