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

net: FileConn() and Dial() only return public net.Conn implementations #27391

Open
dfinkel opened this Issue Aug 30, 2018 · 3 comments

Comments

Projects
None yet
4 participants
@dfinkel

dfinkel commented Aug 30, 2018

In Go 1.11 and 1.10, the documentation does not say anything about which implementations of net.Conn are actually returned by net.Dial() (and friends) and net.FileConn().

The current implementations of net.Dial() and net.FileConn() only return public implementations of net.Conn (or an error). Taking advantage of this by type-asserting to the actual implementation returned by these functions/methods is extremely useful. As such, it would be nice to have this behavior documented so users can rely on it.

I'll send out a CL to extend the documentation and a test or two shortly.

@gopherbot

This comment has been minimized.

gopherbot commented Aug 30, 2018

Change https://golang.org/cl/132437 mentions this issue: net: extend documentation for net.FileConn()

@ianlancetaylor

This comment has been minimized.

Contributor

ianlancetaylor commented Aug 31, 2018

For what kind of code does this matter?

@dfinkel

This comment has been minimized.

dfinkel commented Aug 31, 2018

This is particularly with unix sockets where one might want access to the non-generic Conn methods. (e.g. (*UnixConn).SetWriteBuffer()1 which isn't in the Conn interface)

My specific use-case is that I'm constructing a unix socket with syscall.SocketPair()2 to communicate data with a subprocess that's being spawned with os.Exec, and it's much nicer if my function for creating the socket can return the correct net.Conn implementation.

In this case, I'd like the documentation reflect that this will never return the "failed to type-assert back to a UnixConn" error below (with some error-checking elided for simplicity):

func SocketPair() (*os.File, *net.UnixConn, error)
	fds, _ := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)

	// Convert these into os.files.
	var files [2]*os.File
	for i, fd := range fds {
		files[i] = os.NewFile(uintptr(fd), fmt.Sprintf("anonymous-socket-%d", i))
	}

	conn, _ := net.FileConn(files[1])

	unixConn, ok := conn.(*net.UnixConn)
	if !ok {
		for _, file := range files {
			file.Close()
		}
		return nil, nil, fmt.Errorf("failed to type-assert back to a UnixConn. conn type: %T", conn)
	}

	// Since FileConn dup'd the files[1] FD, we need to close that FD.
	// Since we never wrote to this FD closing should always succeed.
	if err := files[1].Close(); err != nil {
		// We don't want to leak an FD for every process.
		log.Panicf("Failed to close a unix FD: %s", err)
	}
	return files[0], unixConn, nil

The use-case for Dial() is less clear to me due to the presence of DialUnix(), DialTCP, etc, but it seems odd to document that the less-used FileConn won't use a random private type when Dial() doesn't document similar behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment