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

net: File method of Conn on Windows #10350

Open
vyrus001 opened this issue Apr 5, 2015 · 17 comments

Comments

Projects
None yet
8 participants
@vyrus001
Copy link

commented Apr 5, 2015

I am writing something that requires access to the file descriptor of a socket created by net.Dial (which returns a net.conn) and then recast as net.TCPConn so that I can use net.TCPConn.File().Fd().

However, (as the error message says), "dup is not supported on windows". for my purposes, I don't "need" the dup() and would love to settle for just getting the raw file descriptor, but sadly the code within conn.File() appears as follows.

https://golang.org/src/net/net.go?s=5510:5555#L195

func (c *conn) File() (f *os.File, err error) { return c.fd.dup() }

Is there any way I could ask for an "if windows then just return c.fd" option? Hopefully this request isn't a waste of time, I am far from an expert on go.

@mikioh mikioh changed the title net.Conn File Descriptor on Windows net: File method of Conn on Windows Apr 5, 2015

@mikioh

This comment has been minimized.

Copy link
Contributor

commented Apr 5, 2015

See #9503. We need a good compromise for both issues, and so need Windows experts.

@alexbrainman

This comment has been minimized.

Copy link
Member

commented Apr 7, 2015

I don't think you can have "if windows then just return c.fd" option, because it is not what (*conn).File documented to do. Why do you need access to Windows socket handle?

Alex

@mattn

This comment has been minimized.

Copy link
Member

commented Apr 7, 2015

Excuse me for discuss, because we want to pass socket handle into external process for listening. For example, to implement graceful server, we often use fork/exec model.

@vyrus001

This comment has been minimized.

Copy link
Author

commented Apr 7, 2015

In my case, I am passing it to some c compiled with cgo for additional
functionality
On Apr 7, 2015 12:36 AM, "mattn" notifications@github.com wrote:

Excuse me for discuss, because we want to pass socket handle into external
process for listening. For example, to implement graceful server, we often
use fork/exec model.


Reply to this email directly or view it on GitHub
#10350 (comment).

@alexbrainman

This comment has been minimized.

Copy link
Member

commented Apr 8, 2015

@vyrus001 there is no way to access original socket. If you need that functionality, you have to make copy of main Go repo and make whatever changes you want to net package.

@mattn I am not sure what you require, but have you tried implementing windows version of (*netFD).dup? Just use syscall.DuplicateHandle. Would that work for you?

Alex

@mattn

This comment has been minimized.

Copy link
Member

commented Apr 8, 2015

@alexbrainman

https://msdn.microsoft.com/ja-jp/library/windows/desktop/ms724251%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396

You should not use DuplicateHandle to duplicate handles to the following objects:

  • I/O completion ports. No error is returned, but the duplicate handle cannot be used.
  • Sockets. No error is returned, but the duplicate handle may not be recognized by Winsock at the target process. Also, using DuplicateHandle interferes with internal reference counting on the underlying object. To duplicate a socket handle, use the WSADuplicateSocket function.
@alexbrainman

This comment has been minimized.

Copy link
Member

commented Apr 9, 2015

Fair enough. Use WSADuplicateSocket instead. Would that work for you?

Alex

@mattn

This comment has been minimized.

Copy link
Member

commented Apr 9, 2015

Works fine. (But not enough to do that I want)

Look this: https://github.com/mattn/gospel/blob/master/example/echo-server.go

This is not possible to build currently. For building, it need https://codereview.appspot.com/177590043/

This is fork/exec model server. This can replace executable without stop server with SIGHUP. This package is passing socket handle into child process on windows.

@alexbrainman

This comment has been minimized.

Copy link
Member

commented Apr 9, 2015

@mattn your old CL needs to be moved into Gerrit and made work on tip before we can discuss it.

Alex

@mattn

This comment has been minimized.

Copy link
Member

commented Apr 9, 2015

@rsc rsc removed the os-windows label Apr 10, 2015

@rsc rsc added this to the Unplanned milestone Apr 10, 2015

@rsc rsc added the OS-Windows label Apr 15, 2015

@gopherbot

This comment has been minimized.

Copy link

commented Apr 25, 2015

CL https://golang.org/cl/8683 mentions this issue.

mattn added a commit to mattn/go that referenced this issue Apr 24, 2018

net, syscall, internal/syscall/windows: implement FileConn, FilePacke…
…tConn, FileListener

DO NOT REVIEW

Fixes golang#9503.
Fixes golang#10350.

Change-Id: If0851cb3340281cc1ea523cd0ddf48fc7f87c775
@NuSkooler

This comment has been minimized.

Copy link

commented Dec 6, 2018

Gah, I just ran into this as well:
I actually need to do exactly what MSDN says not to do (DuplidateHandle) so I can pass the fd to an "dumb" process. Unfortunately WSADuplicateSocket requires both processes to be in cooperation in order to pass off a special structure. Basically, I want to do this: https://github.com/vrcsix/synchronet/blob/93b01c55b3102ebc3c4f4793c3a45b8c13d0dc2a/src/sbbs3/main.cpp#L3085

If there is no way to get a underlying socket fd, I'm probably at a dead end golang-wise :(

@mikioh

This comment has been minimized.

Copy link
Contributor

commented Dec 28, 2018

This issue might be unfixable because of the architectural differences between Unix-variants and Windows. One good news is that Go 1.12 supports #24331; you may use os.File.SyscallConn instead of File method of net.{TCP,UDP,IP}Conn.

@crvv

This comment has been minimized.

Copy link
Contributor

commented Dec 28, 2018

The purpose of this issue is to get the handle of a *net.TCPConn.
I think this issue was already fixed by (*net.TCPConn).SyscallConn
https://golang.org/pkg/net/#TCPConn.SyscallConn

The FileConn and (*os.File).Fd methods have other side effects(dup, blocking mode), so I think it's hardly useful now.

@mikioh

This comment has been minimized.

Copy link
Contributor

commented Jan 17, 2019

@crvv,

The purpose of the File method is not only for tweaking/crafting the underlying socket but for passing a cloned descriptor pointing to the same underlying socket to external processes.

@NuSkooler

This comment has been minimized.

Copy link

commented Jan 17, 2019

I can see that it would not be fixable with the current API (due to dupe guarantees/etc.), but certainly would be nice and useful for many reasons. It's a bit of a shame that the API kind of tosses Windows out the the uh... window here.

@crvv

This comment has been minimized.

Copy link
Contributor

commented Jan 17, 2019

@mikioh
The purpose of @vyrus001 is to pass the handle to C code.
That can be done via SyscallConn, like

package main

/*
#cgo LDFLAGS: -lWs2_32
#include <stdio.h>
#include <Winsock.h>

void get_listen_addr(SOCKET s) {
    struct sockaddr_in name;
    int namelen = sizeof(name);

    if (getsockname(s, (struct sockaddr*)&name, &namelen)) {
        printf("failed %d\n", WSAGetLastError());
        return;
    }
    printf("%hhu.%hhu.%hhu.%hhu:%hu\n",
        name.sin_addr.S_un.S_un_b.s_b1,
        name.sin_addr.S_un.S_un_b.s_b2,
        name.sin_addr.S_un.S_un_b.s_b3,
        name.sin_addr.S_un.S_un_b.s_b4,
        ntohs(name.sin_port));
}
*/
import "C"
import "net"

func main() {
        listener, err := net.Listen("tcp4", "127.0.0.88:0")
        if err != nil {
                panic(err)
        }
        defer listener.Close()
        rawConn, err := listener.(*net.TCPListener).SyscallConn()
        if err != nil {
                panic(err)
        }
        fdCh := make(chan uintptr, 1)
        err = rawConn.Control(func(fd uintptr) {
                fdCh <- fd
        })
        if err != nil {
                panic(err)
        }
        fd := <-fdCh
        // You can do anything with the fd now
        println(listener.Addr().String())
        C.get_listen_addr(C.SOCKET(fd))
}

The handle can also be passed to external processes with os.NewFile and os.ProcAttr.Files.
The document of syscall.RawConn says

The file descriptor fd is guaranteed to remain valid while f executes but not after f returns.

But this approach is not worse than (*os.File).Fd() method.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.