Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(globalpathces) ngx socket connect to unix domain socket #3633

Merged
merged 6 commits into from
Jul 19, 2018

Conversation

rucciva
Copy link
Contributor

@rucciva rucciva commented Jul 19, 2018

Summary

When connecting to unix domain socket, port parameter should not
be passed to tcpsock:connect or udpsock:connect

Full changelog

  • globalpatches of ngx.socket to connect to unix domain socket

Issues resolved

Fix #3626

rucciva added 2 commits July 19, 2018 09:17
When connecting to unix domain socket, port parameter should not
be passed to tcpsock:connect or udpsock:connect

Fix Kong#3626
When connecting to unix domain socket, port parameter should not
be passed to tcpsock:connect or udpsock:connect

Patch of the previous commit
@rucciva
Copy link
Contributor Author

rucciva commented Jul 19, 2018

Weird, the test succeded on the forked repository

screen shot 2018-07-19 at 12 48 31

@Tieske
Copy link
Member

Tieske commented Jul 19, 2018

@rucciva one testsuite (PDK) failed. It ran fine after restarting.

Copy link
Member

@Tieske Tieske left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Problem solved, but the code is a mess this way (not your fault, but because of all the branches/if-then).

I think it would be cleaner to implement a helper function to strip the trailing nils. Something like:

    -- need to do the extra check here: https://github.com/openresty/lua-nginx-module/issues/860
    local function strip_nils(f, sock, host, port, opts)
      if opts then
        return f(sock, host, port, opts)
      elseif port then
        return f(sock, host, port)
      end
      return f(sock, host)
    end

This can then be used from both the TCP as well as the UDP functions, which would only have to do the unix: check, and then simply call the helper function

@Tieske
Copy link
Member

Tieske commented Jul 19, 2018

actually this would be better:

    -- need to do the extra check here: https://github.com/openresty/lua-nginx-module/issues/860
    local function strip_nils(port, opts)
      if opts then
        return port, opts
      elseif port then
        return port
      end
    end

    -- to be called as:
    old_tcp_connect(sock, target_ip, strip_nils(port, opts))

@rucciva
Copy link
Contributor Author

rucciva commented Jul 19, 2018

this failed when opts is not nil but the port is nil

   -- need to do the extra check here: https://github.com/openresty/lua-nginx-module/issues/860
    local function strip_nils(port, opts)
      if opts then
        return port, opts
      elseif port then
        return port
      end
    end

    -- to be called as:
    old_tcp_connect(sock, target_ip, strip_nils(port, opts))

i think it should be

local function strip_nils(port, opts)
      if opts and port then
        return port, opts
      elseif opts then
        return opts
      elseif port then
        return port
      end
    end

and the caller will be like this

    local function tcp_resolve_connect(sock, host, port, sock_opts)
      local target_ip, target_port
      if sub(host, 1, 5) == "unix:" then
        target_ip = host
      else
        target_ip, target_port = toip(host, port)
      end
      if not target_ip then
        return nil, "[toip() name lookup failed]: " .. tostring(target_port)
      end

      return old_tcp_connect(sock, target_ip, strip_nils(target_port, sock_opts))
    end

    local function udp_resolve_setpeername(sock, host, port)
      local target_ip, target_port
      if sub(host, 1, 5) == "unix:" then
        target_ip = host
      else
        target_ip, target_port = toip(host, port)
      end
      if not target_ip then
        return nil, "[toip() name lookup failed]: " .. tostring(target_port) -- err
      end

      return old_udp_setpeername(sock, target_ip, strip_nils(target_port))
    end

is this fine @Tieske ?

@rucciva
Copy link
Contributor Author

rucciva commented Jul 19, 2018

or refactor further?

  -- need to do the extra check here: https://github.com/openresty/lua-nginx-module/issues/860
    local function strip_nils(port, opts)
      if opts and port then
        return port, opts
      elseif opts then
        return opts
      elseif port then
        return port
      end
    end

    local function resolve_connect(f, sock, host, port, sock_opts)
      local target_ip, target_port
      if sub(host, 1, 5) == "unix:" then
        target_ip = host
      else
        target_ip, target_port = toip(host, port)
      end
      if not target_ip then
        return nil, "[toip() name lookup failed]: " .. tostring(target_port)
      end
      return f(sock, target_ip, strip_nils(target_port, sock_opts))
    end

    local function tcp_resolve_connect(sock, host, port, sock_opts)
      return resolve_connect(old_tcp_connect, sock, host, port, sock_opts)
    end

    local function udp_resolve_setpeername(sock, host, port)
      return resolve_connect(old_udp_setpeername, sock, host, port)
    end

@Tieske
Copy link
Member

Tieske commented Jul 19, 2018

@rucciva that's looking great (the last version). Thx. please adjust the PR. I'l comment on the update in line

if port and opts then
return port, opts
elseif opts then
return opts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here you are "shifting" a parameter? is that what's intended? So in case of a unix socket, the proper call would be tcp_connect(sock, name, opts) instead of tcp_connect(sock, name, nil, opts)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and you are correct, sorry for the noise. https://github.com/openresty/lua-nginx-module#tcpsockconnect

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eh, no, you are not correct.

Since the function should be compatible with the ngx.socket.tcp calls, in the case of a unix socket, the caller would do connect(sock, name, opts), so in the code, the opts table would ba carried in the port variable actually.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the function should be compatible with the ngx.socket.tcp calls, in the case of a unix socket, the caller would do connect(sock, name, opts), so in the code, the opts table would ba carried in the port variable actually.

isn't that what will happens? if the port is nil then strip_nils will return only the opts,
so return f(sock, target_ip, strip_nils(target_port, sock_opts)) equals return f(sock, target_ip, sock_opts) when target_port is nil

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh i got what you means, sorry

Copy link
Contributor Author

@rucciva rucciva Jul 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the third argument can be port or opts (and will be confusing), can i do it like this?

    local function strip_nils(first, second)
      if second then
        return first, second
      elseif first then
        return first
      end
    end

    local function resolve_connect(f, sock, host, port_or_opts, opts)
      if sub(host, 1, 5) == "unix:" then
        opts = port_or_opts 
        return f(sock, host, strip_nils(opts))
      end

      local port = port_or_opts
      local target_ip, target_port = toip(host, port)
      if not target_ip then
        return nil, "[toip() name lookup failed]: " .. tostring(target_port)
      end
      return f(sock, target_ip, strip_nils(target_port, opts))
    end

    local function tcp_resolve_connect(sock, host, port_or_opts, opts)
      return resolve_connect(old_tcp_connect, sock, host, port_or_opts, opts)
    end

    local function udp_resolve_setpeername(sock, host, port)
      return resolve_connect(old_udp_setpeername, sock, host, port)
    end

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, seems appropriate

end
if not target_ip then
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this check can be moved in the else block above, since it doesn't apply to unix sockets

if sub(host, 1, 5) == "unix:" then
target_ip = host -- unix domain socket, so just maintain the named values

target_ip = host
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please do not remove the vertical whitspace, see also style guide

Copy link
Contributor Author

@rucciva rucciva Jul 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

like this one right?

    local function resolve_connect(f, sock, host, port, sock_opts)
      local target_ip, target_port
      if sub(host, 1, 5) == "unix:" then
        target_ip = host
        
      else
        target_ip, target_port = toip(host, port)
        if not target_ip then
          return nil, "[toip() name lookup failed]: " .. tostring(target_port)
        end

      end

      return f(sock, target_ip, strip_nils(target_port, sock_opts))
    end

i removed the blank line in the last commit since in the style guide, it says For one-line blocks, blank lines are not necessary:

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine, no need for the blank line between the two end statements. In general, check the rest of the code.

@rucciva
Copy link
Contributor Author

rucciva commented Jul 19, 2018

btw, the test result are not the same again

screen shot 2018-07-19 at 17 41 24

- tcpsock:connect(host, port, options_table?)
- tcpsock:connect("unix:/path/to/unix-domain.socket", options_table?)
- udpsock:setpeername(host, port)
- udpsock:setpeername("unix:/path/to/unix-domain.socket")
end

return old_tcp_connect(sock, target_ip, target_port, sock_opts)
return f(sock, target_ip, strip_nils(target_port, opts))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the code is correct, but I think you're overdoing the variable naming to explain some intricate details of how the socket functions work, which complicates the code and reduces code readability. Can't we just drop the local variables and stick to:

    local function resolve_connect(f, sock, host, port, opts)
      if sub(host, 1, 5) ~= "unix:" then
        host, port = toip(host, port)
        if not host then
          return nil, "[toip() name lookup failed]: " .. tostring(port)
        end
      end

      return f(sock, host, strip_nils(port, opts))
    end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems ok for me too. in the end, this is a patch and users might not expect that the original ngx.socket.* are modified by kong, thus they will probably lookup the original ngx lua to find the definition.

end
end

-- need to do the extra check here: https://github.com/openresty/lua-nginx-module/issues/860
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment belongs to the function above: strip_nils

@Tieske Tieske merged commit d895296 into Kong:master Jul 19, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

connect to unix socked failed
2 participants