// Close all poller file descriptors, but not the one passed to it. func (poller *fdPoller) close() { if poller.pipe[1] != -1 { unix.Close(poller.pipe[1]) } if poller.pipe[0] != -1 { unix.Close(poller.pipe[0]) } if poller.epfd != -1 { unix.Close(poller.epfd) } }
func (c conn) Close() (err error) { err = unix.Close(c.fd) if err != nil { err = Err{err} } return }
// TcpListen is listening for incoming IP packets which are being intercepted. // In conflict to regular Listen mehtod the socket destination and source addresses // are of the intercepted connection. // Else then that it works exactly like net package net.Listen. func TcpListen(listenAddr string) (listener net.Listener, err error) { s, err := unix.Socket(unix.AF_INET6, unix.SOCK_STREAM, 0) if err != nil { return nil, err } defer unix.Close(s) err = unix.SetsockoptInt(s, unix.SOL_IP, unix.IP_TRANSPARENT, 1) if err != nil { return nil, err } sa, err := IPv6TcpAddrToUnixSocksAddr(listenAddr) if err != nil { return nil, err } err = unix.Bind(s, sa) if err != nil { return nil, err } err = unix.Listen(s, unix.SOMAXCONN) if err != nil { return nil, err } f := os.NewFile(uintptr(s), "TProxy") defer f.Close() return net.FileListener(f) }
// dial tcp with tcp fastopen // 第一个包体积不要太大,需要小于一定数量,否则会被吃掉(正确性问题), // 如果过大,此处会在连接时发送前一部分,连接后又发送一部分 func TfoDial(nextAddr string, data []byte) (conn net.Conn, err error) { s, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0) if err != nil { return nil, err } defer unix.Close(s) sa, err := kmgUnix.IPv4TcpAddrToUnixSocksAddr(nextAddr) if err != nil { return nil, err } if len(data) <= tfoFirstSize { err = unix.Sendto(s, data, unix.MSG_FASTOPEN, sa) if err != nil { return } } else { err = unix.Sendto(s, data[:tfoFirstSize], unix.MSG_FASTOPEN, sa) if err != nil { return } } f := os.NewFile(uintptr(s), "TFODial") defer f.Close() conn, err = net.FileConn(f) if err != nil { return } if len(data) > tfoFirstSize { _, err = conn.Write(data[tfoFirstSize:]) if err != nil { return nil, err } } return conn, nil }
//network is useless ,it will always use tcp4 func TfoListen(network string, listenAddr string) (listener net.Listener, err error) { s, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM|unix.SOCK_NONBLOCK|unix.SOCK_CLOEXEC, 0) if err != nil { return nil, err } defer unix.Close(s) err = unix.SetsockoptInt(s, unix.SOL_TCP, 23, 10) if err != nil { return nil, err } err = unix.SetsockoptInt(s, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) if err != nil { return nil, err } sa, err := kmgUnix.IPv4TcpAddrToUnixSocksAddr(listenAddr) if err != nil { return nil, err } err = unix.Bind(s, sa) if err != nil { return nil, err } err = unix.Listen(s, 10) if err != nil { return nil, err } f := os.NewFile(uintptr(s), "TFOListen") defer f.Close() return net.FileListener(f) }
// NewWatcher establishes a new watcher with the underlying OS and begins waiting for events. func NewWatcher() (*Watcher, error) { // Create inotify fd fd, errno := unix.InotifyInit() if fd == -1 { return nil, errno } // Create epoll poller, err := newFdPoller(fd) if err != nil { unix.Close(fd) return nil, err } w := &Watcher{ fd: fd, poller: poller, watches: make(map[string]*watch), paths: make(map[int]string), Events: make(chan Event), Errors: make(chan error), done: make(chan struct{}), doneResp: make(chan struct{}), } w.cv = sync.NewCond(&w.mu) go w.readEvents() return w, nil }
// TfoListen announces on the local network address laddr using tcp protocol and fast open option. // laddr must be in the form of "host:port". // It returns a tfo-enabled listener and an error if any. func tfoListen(laddr string) (lst net.Listener, err error) { s, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM|unix.SOCK_NONBLOCK|unix.SOCK_CLOEXEC, 0) if err != nil { return } defer unix.Close(s) sa, err := tcpAddrToSockaddr(laddr) if err != nil { return } err = unix.Bind(s, sa) if err != nil { return } // set the socket to fast open mode err = unix.SetsockoptInt(s, unix.SOL_TCP, 23, TCP_FASTOPEN_VAL) if err != nil { return } err = unix.Listen(s, 10) if err != nil { return } f := os.NewFile(uintptr(s), "TFOListen") defer f.Close() return net.FileListener(f) }
func stop() { if cxt != nil { // notify HandleRequest() that we're done if _, err := unix.Write(pipeFds[1], []byte{0}); err != nil { log.Errorln("Fail to notify poll for finishing: ", err) } close(done) C.tcmulib_close(cxt) if err := unix.Close(pipeFds[0]); err != nil { log.Errorln("Fail to close pipeFds[0]: ", err) } if err := unix.Close(pipeFds[1]); err != nil { log.Errorln("Fail to close pipeFds[1]: ", err) } cxt = nil } }
// hackDump returns the value dump as a string. func hackDump(v llvm.Value) (string, error) { // Open temp file. // TODO: Use an in-memory file instead of /tmp/x. fd, err := unix.Open("/tmp/x", unix.O_WRONLY|unix.O_TRUNC|unix.O_CREAT, 0644) if err != nil { return "", errutil.Err(err) } // Store original stderr. stderr, err := unix.Dup(2) if err != nil { return "", errutil.Err(err) } // Capture stderr and redirect its output to the temp file. err = unix.Dup2(fd, 2) if err != nil { return "", errutil.Err(err) } err = unix.Close(fd) if err != nil { return "", errutil.Err(err) } // Dump value. v.Dump() C.fflush_stderr() // Restore stderr. err = unix.Dup2(stderr, 2) if err != nil { return "", errutil.Err(err) } err = unix.Close(stderr) if err != nil { return "", errutil.Err(err) } // Return content of temp file. buf, err := ioutil.ReadFile("/tmp/x") if err != nil { return "", errutil.Err(err) } return string(buf), nil }
func UdpTProxyConn(listenAddr string) (udp *net.UDPConn, err error) { var c net.Conn s, err := unix.Socket(unix.AF_INET6, unix.SOCK_DGRAM, 0) if err != nil { return nil, err } //Why close here ??? defer unix.Close(s) err = unix.SetsockoptInt(s, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) if err != nil { return nil, err } err = unix.SetsockoptInt(s, unix.SOL_SOCKET, unix.SO_BROADCAST, 1) if err != nil { return nil, err } err = unix.SetsockoptInt(s, unix.SOL_IP, unix.IP_TRANSPARENT, 1) if err != nil { return nil, err } err = unix.SetsockoptInt(s, unix.IPPROTO_IP, unix.IP_RECVORIGDSTADDR, 1) if err != nil { return nil, err } sa, err := IPv6TcpAddrToUnixSocksAddr(listenAddr) if err != nil { return nil, err } err = unix.Bind(s, sa) if err != nil { return nil, err } f := os.NewFile(uintptr(s), "TProxy") defer f.Close() c, err = net.FileConn(f) if err != nil { return nil, err } var ok bool if udp, ok = c.(*net.UDPConn); ok { return } else { c.Close() return nil, errors.New("type error") } }
func MakeNetworkNS(containerID string) string { namespace := "/var/run/netns/" + containerID err := os.MkdirAll("/var/run/netns", 0600) Expect(err).NotTo(HaveOccurred()) // create an empty file at the mount point mountPointFd, err := os.Create(namespace) Expect(err).NotTo(HaveOccurred()) mountPointFd.Close() var wg sync.WaitGroup wg.Add(1) // do namespace work in a dedicated goroutine, so that we can safely // Lock/Unlock OSThread without upsetting the lock/unlock state of // the caller of this function. See block comment above. go (func() { defer wg.Done() runtime.LockOSThread() defer runtime.UnlockOSThread() defer GinkgoRecover() // capture current thread's original netns currentThreadNetNSPath := getCurrentThreadNetNSPath() originalNetNS, err := unix.Open(currentThreadNetNSPath, unix.O_RDONLY, 0) Expect(err).NotTo(HaveOccurred()) defer unix.Close(originalNetNS) // create a new netns on the current thread err = unix.Unshare(unix.CLONE_NEWNET) Expect(err).NotTo(HaveOccurred()) // bind mount the new netns from the current thread onto the mount point err = unix.Mount(currentThreadNetNSPath, namespace, "none", unix.MS_BIND, "") Expect(err).NotTo(HaveOccurred()) // reset current thread's netns to the original _, _, e1 := unix.Syscall(unix.SYS_SETNS, uintptr(originalNetNS), uintptr(unix.CLONE_NEWNET), 0) Expect(e1).To(BeZero()) })() wg.Wait() return namespace }
// TestFcntlFlock tests whether the file locking structure matches // the calling convention of each kernel. func TestFcntlFlock(t *testing.T) { name := filepath.Join(os.TempDir(), "TestFcntlFlock") fd, err := unix.Open(name, unix.O_CREAT|unix.O_RDWR|unix.O_CLOEXEC, 0) if err != nil { t.Fatalf("Open failed: %v", err) } defer unix.Unlink(name) defer unix.Close(fd) flock := unix.Flock_t{ Type: unix.F_RDLCK, Start: 0, Len: 0, Whence: 1, } if err := unix.FcntlFlock(uintptr(fd), unix.F_GETLK, &flock); err != nil { t.Fatalf("FcntlFlock failed: %v", err) } }
// Remove stops watching the named file or directory (non-recursively). func (w *Watcher) Remove(name string) error { name = filepath.Clean(name) w.mu.Lock() watchfd, ok := w.watches[name] w.mu.Unlock() if !ok { return fmt.Errorf("can't remove non-existent kevent watch for: %s", name) } const registerRemove = unix.EV_DELETE if err := register(w.kq, []int{watchfd}, registerRemove, 0); err != nil { return err } unix.Close(watchfd) w.mu.Lock() isDir := w.paths[watchfd].isDir delete(w.watches, name) delete(w.paths, watchfd) delete(w.dirFlags, name) w.mu.Unlock() // Find all watched paths that are in this directory that are not external. if isDir { var pathsToRemove []string w.mu.Lock() for _, path := range w.paths { wdir, _ := filepath.Split(path.name) if filepath.Clean(wdir) == name { if !w.externalWatches[path.name] { pathsToRemove = append(pathsToRemove, path.name) } } } w.mu.Unlock() for _, name := range pathsToRemove { // Since these are internal, not much sense in propagating error // to the user, as that will just confuse them with an error about // a path they did not explicitly watch themselves. w.Remove(name) } } return nil }
// TfoDial dials to addr using tcp protocol with fast open option set, // addr should be in the form of "addr:port", // the data is sent along with the first syn packet of tcp handshake. // It returns a established connection and an error if any. func tfoDial(addr string, data []byte) (conn net.Conn, err error) { fd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0) if err != nil { return } defer unix.Close(fd) sa, err := tcpAddrToSockaddr(addr) if err != nil { return } err = unix.Sendto(fd, data, unix.MSG_FASTOPEN, sa) if err != nil { return } f := os.NewFile(uintptr(fd), "TFODial") defer f.Close() return net.FileConn(f) }
func makeNetworkNS(containerID string) string { namespace := "/var/run/netns/" + containerID pid := unix.Getpid() tid := unix.Gettid() err := os.MkdirAll("/var/run/netns", 0600) Expect(err).NotTo(HaveOccurred()) runtime.LockOSThread() defer runtime.UnlockOSThread() go (func() { defer GinkgoRecover() err = unix.Unshare(unix.CLONE_NEWNET) Expect(err).NotTo(HaveOccurred()) fd, err := os.Create(namespace) Expect(err).NotTo(HaveOccurred()) defer fd.Close() err = unix.Mount("/proc/self/ns/net", namespace, "none", unix.MS_BIND, "") Expect(err).NotTo(HaveOccurred()) })() Eventually(namespace).Should(BeAnExistingFile()) fd, err := unix.Open(fmt.Sprintf("/proc/%d/task/%d/ns/net", pid, tid), unix.O_RDONLY, 0) Expect(err).NotTo(HaveOccurred()) defer unix.Close(fd) _, _, e1 := unix.Syscall(unix.SYS_SETNS, uintptr(fd), uintptr(unix.CLONE_NEWNET), 0) Expect(e1).To(BeZero()) return namespace }
func (s *Socket) Close() error { return errors.Wrap(unix.Close(s.fd), "can't close hci socket") }
// TestSCMCredentials tests the sending and receiving of credentials // (PID, UID, GID) in an ancillary message between two UNIX // sockets. The SO_PASSCRED socket option is enabled on the sending // socket for this to work. func TestSCMCredentials(t *testing.T) { fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0) if err != nil { t.Fatalf("Socketpair: %v", err) } defer unix.Close(fds[0]) defer unix.Close(fds[1]) err = unix.SetsockoptInt(fds[0], unix.SOL_SOCKET, unix.SO_PASSCRED, 1) if err != nil { t.Fatalf("SetsockoptInt: %v", err) } srvFile := os.NewFile(uintptr(fds[0]), "server") defer srvFile.Close() srv, err := net.FileConn(srvFile) if err != nil { t.Errorf("FileConn: %v", err) return } defer srv.Close() cliFile := os.NewFile(uintptr(fds[1]), "client") defer cliFile.Close() cli, err := net.FileConn(cliFile) if err != nil { t.Errorf("FileConn: %v", err) return } defer cli.Close() var ucred unix.Ucred if os.Getuid() != 0 { ucred.Pid = int32(os.Getpid()) ucred.Uid = 0 ucred.Gid = 0 oob := unix.UnixCredentials(&ucred) _, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) if err.(*net.OpError).Err != syscall.EPERM { t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err) } } ucred.Pid = int32(os.Getpid()) ucred.Uid = uint32(os.Getuid()) ucred.Gid = uint32(os.Getgid()) oob := unix.UnixCredentials(&ucred) // this is going to send a dummy byte n, oobn, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) if err != nil { t.Fatalf("WriteMsgUnix: %v", err) } if n != 0 { t.Fatalf("WriteMsgUnix n = %d, want 0", n) } if oobn != len(oob) { t.Fatalf("WriteMsgUnix oobn = %d, want %d", oobn, len(oob)) } oob2 := make([]byte, 10*len(oob)) n, oobn2, flags, _, err := srv.(*net.UnixConn).ReadMsgUnix(nil, oob2) if err != nil { t.Fatalf("ReadMsgUnix: %v", err) } if flags != 0 { t.Fatalf("ReadMsgUnix flags = 0x%x, want 0", flags) } if n != 1 { t.Fatalf("ReadMsgUnix n = %d, want 1 (dummy byte)", n) } if oobn2 != oobn { // without SO_PASSCRED set on the socket, ReadMsgUnix will // return zero oob bytes t.Fatalf("ReadMsgUnix oobn = %d, want %d", oobn2, oobn) } oob2 = oob2[:oobn2] if !bytes.Equal(oob, oob2) { t.Fatal("ReadMsgUnix oob bytes don't match") } scm, err := unix.ParseSocketControlMessage(oob2) if err != nil { t.Fatalf("ParseSocketControlMessage: %v", err) } newUcred, err := unix.ParseUnixCredentials(&scm[0]) if err != nil { t.Fatalf("ParseUnixCredentials: %v", err) } if *newUcred != ucred { t.Fatalf("ParseUnixCredentials = %+v, want %+v", newUcred, ucred) } }
func cl(fd int) (err error) { return unix.Close(fd) }
func xserverInit(display *C.struct_wl_display) { // Fetch a valid lock file and DISPLAY number displayNum, _ := TryLock() numStr := strconv.Itoa(displayNum) // Set DISPLAY number displayName := ":" + numStr os.Setenv("DISPLAY", displayName) println(displayName) // Open a socket for the Wayland connection from Xwayland. wls, _ := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0) wms, _ := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0) initXwm((uintptr)(wms[0])) client := C.wl_client_create(display, (C.int)(wls[0])) println(client) unixFd := listen2(SOCKET_FMT + numStr) abstructFd := listen2("@" + SOCKET_FMT + numStr) unsetCloseOnExec(unixFd) unsetCloseOnExec(abstructFd) pid := forkXWayland() if pid == 0 { // child unix.Close(wls[0]) unix.Close(wms[0]) // init DISPLAY unix socket // do not close the listener(Close them will remove the file in filesystem). // unixListener, _ := listen(SOCKET_FMT + numStr) // abstructListener, _ := listen("@" + SOCKET_FMT + numStr) // unixFile, _ := unixListener.File() // abstructFile, _ := abstructListener.File() // unixFd := unixFile.Fd() // abstructFd := abstructFile.Fd() C.signal_ignore((C.int)(syscall.SIGUSR1)) os.Setenv("WAYLAND_SOCKET", strconv.Itoa(wls[1])) args := []string{ "Xwayland", displayName, "-rootless", "-terminate", "-listen", strconv.Itoa((int)(unixFd)), "-listen", strconv.Itoa((int)(abstructFd)), "-wm", strconv.Itoa(wms[1]), } binary, lookErr := exec.LookPath("Xwayland") // binary, lookErr := exec.LookPath("strace") if lookErr != nil { panic(lookErr) } env := os.Environ() execErr := syscall.Exec(binary, args, env) if execErr != nil { panic(lookErr) } } else { // parent unix.Close(wls[1]) unix.Close(wms[1]) } }
func main() { fmt.Println("Listening on port :", port) counter := new(connCounter) // create socket fd, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0) if err != nil { log.Fatal("socket-error: ", err) } // sa struct sa := new(unix.SockaddrInet4) sa.Port = 9090 // bind err = unix.Bind(fd, sa) if err != nil { log.Fatal("bind: ", err) } // listen err = unix.Listen(fd, 3) if err != nil { log.Fatal("listen: ", err) } for { connInfo := new(connection) // accept connection, discard SA struct newFd, _, err := unix.Accept(fd) connInfo.fd = newFd if err != nil { log.Fatal("accept: ", err) } // client reads until closes, adding // a gorutine allows dealing with more // requests. counter.mu.Lock() counter.num += 1 counter.mu.Unlock() fmt.Println("Number of connections: ", counter.num) go func(c *connection, counter *connCounter) { fmt.Printf("Conn.fd=%d\n", c.fd) for { // read c.buf = make([]byte, 50) n, err := unix.Read(c.fd, c.buf) if err != nil { log.Fatal("read: ", err) } fmt.Printf("Read: %d Value: %s\n", n, string(c.buf[0:n])) // close if string(c.buf[0:5]) == "close" { _, err = unix.Write(c.fd, []byte(`Bye bye buddy`)) if err != nil { log.Fatal("close: ", err) } err = unix.Close(c.fd) if err != nil { log.Fatal("close: ", err) } counter.mu.Lock() counter.num = counter.num - 1 counter.mu.Unlock() return } } }(connInfo, counter) } }
// readEvents reads from the inotify file descriptor, converts the // received events into Event objects and sends them via the Events channel func (w *Watcher) readEvents() { var ( buf [unix.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events n int // Number of bytes read with read() errno error // Syscall errno ok bool // For poller.wait ) defer close(w.doneResp) defer close(w.Errors) defer close(w.Events) defer unix.Close(w.fd) defer w.poller.close() for { // See if we have been closed. if w.isClosed() { return } ok, errno = w.poller.wait() if errno != nil { select { case w.Errors <- errno: case <-w.done: return } continue } if !ok { continue } n, errno = unix.Read(w.fd, buf[:]) // If a signal interrupted execution, see if we've been asked to close, and try again. // http://man7.org/linux/man-pages/man7/signal.7.html : // "Before Linux 3.8, reads from an inotify(7) file descriptor were not restartable" if errno == unix.EINTR { continue } // unix.Read might have been woken up by Close. If so, we're done. if w.isClosed() { return } if n < unix.SizeofInotifyEvent { var err error if n == 0 { // If EOF is received. This should really never happen. err = io.EOF } else if n < 0 { // If an error occurred while reading. err = errno } else { // Read was too short. err = errors.New("notify: short read in readEvents()") } select { case w.Errors <- err: case <-w.done: return } continue } var offset uint32 // We don't know how many events we just read into the buffer // While the offset points to at least one whole event... for offset <= uint32(n-unix.SizeofInotifyEvent) { // Point "raw" to the event in the buffer raw := (*unix.InotifyEvent)(unsafe.Pointer(&buf[offset])) mask := uint32(raw.Mask) nameLen := uint32(raw.Len) // If the event happened to the watched directory or the watched file, the kernel // doesn't append the filename to the event, but we would like to always fill the // the "Name" field with a valid filename. We retrieve the path of the watch from // the "paths" map. w.mu.Lock() name := w.paths[int(raw.Wd)] w.mu.Unlock() if nameLen > 0 { // Point "bytes" at the first byte of the filename bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent])) // The filename is padded with NULL bytes. TrimRight() gets rid of those. name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") } event := newEvent(name, mask) // Send the events that are not ignored on the events channel if !event.ignoreLinux(w, raw.Wd, mask) { select { case w.Events <- event: case <-w.done: return } } // Move to the next event in the buffer offset += unix.SizeofInotifyEvent + nameLen } } }
// TcpDial is a special tcp connection which binds a non local address as the source. // Except then the option to bind to a specific local address which the machine doesn't posses // it is exactly like any other net.Conn connection. // It is advised to use port numbered 0 in the localAddr and leave the kernel to choose which // Local port to use in order to avoid errors and binding conflicts. func TcpDial(localAddr, remoteAddr string) (conn net.Conn, err error) { fmt.Println(localAddr) fmt.Println(remoteAddr) s, err := unix.Socket(unix.AF_INET6, unix.SOCK_STREAM, 0) //In a case there was a need for a non-blocking socket an example //s, err := unix.Socket(unix.AF_INET6, unix.SOCK_STREAM |unix.SOCK_NONBLOCK, 0) if err != nil { fmt.Println(err) return nil, err } defer unix.Close(s) err = unix.SetsockoptInt(s, unix.SOL_IP, unix.IP_TRANSPARENT, 1) if err != nil { fmt.Println(err) return nil, err } err = unix.SetsockoptInt(s, unix.SOL_SOCKET, unix.SO_REUSEADDR, 1) if err != nil { fmt.Println(err) return nil, err } rhost, rport, err := net.SplitHostPort(localAddr) _ = rport if err != nil { fmt.Fprintln(os.Stderr, err) } sa, err := IPv6TcpAddrToUnixSocksAddr(rhost + ":0") if err != nil { fmt.Println(err) return nil, err } remoteSocket, err := IPv6TcpAddrToUnixSocksAddr(remoteAddr) if err != nil { fmt.Println(err) return nil, err } err = unix.Bind(s, sa) if err != nil { fmt.Println(err) return nil, err } err = unix.Connect(s, remoteSocket) if err != nil { fmt.Println(err) return nil, err } f := os.NewFile(uintptr(s), "TProxyTcpClient") client, err := net.FileConn(f) if err != nil { fmt.Println(err) return nil, err } fmt.Println(client.LocalAddr()) fmt.Println(client.RemoteAddr()) return client, err }
func (pc *packetSock) Close() error { return unix.Close(pc.fd) }
// addWatch adds name to the watched file set. // The flags are interpreted as described in kevent(2). // Returns the real path to the file which was added, if any, which may be different from the one passed in the case of symlinks. func (w *Watcher) addWatch(name string, flags uint32) (string, error) { var isDir bool // Make ./name and name equivalent name = filepath.Clean(name) w.mu.Lock() if w.isClosed { w.mu.Unlock() return "", errors.New("kevent instance already closed") } watchfd, alreadyWatching := w.watches[name] // We already have a watch, but we can still override flags. if alreadyWatching { isDir = w.paths[watchfd].isDir } w.mu.Unlock() if !alreadyWatching { fi, err := os.Lstat(name) if err != nil { return "", err } // Don't watch sockets. if fi.Mode()&os.ModeSocket == os.ModeSocket { return "", nil } // Don't watch named pipes. if fi.Mode()&os.ModeNamedPipe == os.ModeNamedPipe { return "", nil } // Follow Symlinks // Unfortunately, Linux can add bogus symlinks to watch list without // issue, and Windows can't do symlinks period (AFAIK). To maintain // consistency, we will act like everything is fine. There will simply // be no file events for broken symlinks. // Hence the returns of nil on errors. if fi.Mode()&os.ModeSymlink == os.ModeSymlink { name, err = filepath.EvalSymlinks(name) if err != nil { return "", nil } w.mu.Lock() _, alreadyWatching = w.watches[name] w.mu.Unlock() if alreadyWatching { return name, nil } fi, err = os.Lstat(name) if err != nil { return "", nil } } watchfd, err = unix.Open(name, openMode, 0700) if watchfd == -1 { return "", err } isDir = fi.IsDir() } const registerAdd = unix.EV_ADD | unix.EV_CLEAR | unix.EV_ENABLE if err := register(w.kq, []int{watchfd}, registerAdd, flags); err != nil { unix.Close(watchfd) return "", err } if !alreadyWatching { w.mu.Lock() w.watches[name] = watchfd w.paths[watchfd] = pathInfo{name: name, isDir: isDir} w.mu.Unlock() } if isDir { // Watch the directory if it has not been watched before, // or if it was watched before, but perhaps only a NOTE_DELETE (watchDirectoryFiles) w.mu.Lock() watchDir := (flags&unix.NOTE_WRITE) == unix.NOTE_WRITE && (!alreadyWatching || (w.dirFlags[name]&unix.NOTE_WRITE) != unix.NOTE_WRITE) // Store flags so this watch can be updated later w.dirFlags[name] = flags w.mu.Unlock() if watchDir { if err := w.watchDirectoryFiles(name); err != nil { return "", err } } } return name, nil }
// DeviceChan binds the udev_monitor socket to the event source and spawns a // goroutine. The goroutine efficiently waits on the monitor socket using epoll. // Data is received from the udev monitor socket and a new Device is created // with the data received. Pointers to the device are sent on the returned channel. // The function takes a done signalling channel as a parameter, which when // triggered will stop the goroutine and close the device channel. // Only socket connections with uid=0 are accepted. func (m *Monitor) DeviceChan(done <-chan struct{}) (<-chan *Device, error) { var event unix.EpollEvent var events [maxEpollEvents]unix.EpollEvent // Lock the context m.lock() defer m.unlock() // Enable receiving if C.udev_monitor_enable_receiving(m.ptr) != 0 { return nil, errors.New("udev: udev_monitor_enable_receiving failed") } // Set the fd to non-blocking fd := C.udev_monitor_get_fd(m.ptr) if e := unix.SetNonblock(int(fd), true); e != nil { return nil, errors.New("udev: unix.SetNonblock failed") } // Create an epoll fd epfd, e := unix.EpollCreate1(0) if e != nil { return nil, errors.New("udev: unix.EpollCreate1 failed") } // Add the fd to the epoll fd event.Events = unix.EPOLLIN | unix.EPOLLET event.Fd = int32(fd) if e = unix.EpollCtl(epfd, unix.EPOLL_CTL_ADD, int(fd), &event); e != nil { return nil, errors.New("udev: unix.EpollCtl failed") } // Create the channel ch := make(chan *Device) // Create goroutine to epoll the fd go func(done <-chan struct{}, fd int32) { // Close the epoll fd when goroutine exits defer unix.Close(epfd) // Close the channel when goroutine exits defer close(ch) // Loop forever for { // Poll the file descriptor nevents, e := unix.EpollWait(epfd, events[:], epollTimeout) if e != nil { return } // Process events for ev := 0; ev < nevents; ev++ { if events[ev].Fd == fd { if (events[ev].Events & unix.EPOLLIN) != 0 { for d := m.receiveDevice(); d != nil; d = m.receiveDevice() { ch <- d } } } } // Check for done signal select { case <-done: return default: } } }(done, int32(fd)) return ch, nil }
func (tfd testFd) close() { unix.Close(tfd[1]) unix.Close(tfd[0]) }
func (tfd testFd) closeWrite(t *testing.T) { errno := unix.Close(tfd[1]) if errno != nil { t.Fatalf("Failed to close write end of pipe: %v", errno) } }
// readEvents reads from kqueue and converts the received kevents into // Event values that it sends down the Events channel. func (w *Watcher) readEvents() { eventBuffer := make([]unix.Kevent_t, 10) for { // See if there is a message on the "done" channel select { case <-w.done: err := unix.Close(w.kq) if err != nil { w.Errors <- err } close(w.Events) close(w.Errors) return default: } // Get new events kevents, err := read(w.kq, eventBuffer, &keventWaitTime) // EINTR is okay, the syscall was interrupted before timeout expired. if err != nil && err != unix.EINTR { w.Errors <- err continue } // Flush the events we received to the Events channel for len(kevents) > 0 { kevent := &kevents[0] watchfd := int(kevent.Ident) mask := uint32(kevent.Fflags) w.mu.Lock() path := w.paths[watchfd] w.mu.Unlock() event := newEvent(path.name, mask) if path.isDir && !(event.Op&Remove == Remove) { // Double check to make sure the directory exists. This can happen when // we do a rm -fr on a recursively watched folders and we receive a // modification event first but the folder has been deleted and later // receive the delete event if _, err := os.Lstat(event.Name); os.IsNotExist(err) { // mark is as delete event event.Op |= Remove } } if event.Op&Rename == Rename || event.Op&Remove == Remove { w.Remove(event.Name) w.mu.Lock() delete(w.fileExists, event.Name) w.mu.Unlock() } if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) { w.sendDirectoryChangeEvents(event.Name) } else { // Send the event on the Events channel w.Events <- event } if event.Op&Remove == Remove { // Look for a file that may have overwritten this. // For example, mv f1 f2 will delete f2, then create f2. if path.isDir { fileDir := filepath.Clean(event.Name) w.mu.Lock() _, found := w.watches[fileDir] w.mu.Unlock() if found { // make sure the directory exists before we watch for changes. When we // do a recursive watch and perform rm -fr, the parent directory might // have gone missing, ignore the missing directory and let the // upcoming delete event remove the watch from the parent directory. if _, err := os.Lstat(fileDir); err == nil { w.sendDirectoryChangeEvents(fileDir) } } } else { filePath := filepath.Clean(event.Name) if fileInfo, err := os.Lstat(filePath); err == nil { w.sendFileCreatedEventIfNew(filePath, fileInfo) } } } // Move to next event kevents = kevents[1:] } } }
// TestPassFD tests passing a file descriptor over a Unix socket. // // This test involved both a parent and child process. The parent // process is invoked as a normal test, with "go test", which then // runs the child process by running the current test binary with args // "-test.run=^TestPassFD$" and an environment variable used to signal // that the test should become the child process instead. func TestPassFD(t *testing.T) { switch runtime.GOOS { case "dragonfly": // TODO(jsing): Figure out why sendmsg is returning EINVAL. t.Skip("skipping test on dragonfly") case "solaris": // TODO(aram): Figure out why ReadMsgUnix is returning empty message. t.Skip("skipping test on solaris, see issue 7402") } if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { passFDChild() return } tempDir, err := ioutil.TempDir("", "TestPassFD") if err != nil { t.Fatal(err) } defer os.RemoveAll(tempDir) fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0) if err != nil { t.Fatalf("Socketpair: %v", err) } defer unix.Close(fds[0]) defer unix.Close(fds[1]) writeFile := os.NewFile(uintptr(fds[0]), "child-writes") readFile := os.NewFile(uintptr(fds[1]), "parent-reads") defer writeFile.Close() defer readFile.Close() cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir) cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} if lp := os.Getenv("LD_LIBRARY_PATH"); lp != "" { cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+lp) } cmd.ExtraFiles = []*os.File{writeFile} out, err := cmd.CombinedOutput() if len(out) > 0 || err != nil { t.Fatalf("child process: %q, %v", out, err) } c, err := net.FileConn(readFile) if err != nil { t.Fatalf("FileConn: %v", err) } defer c.Close() uc, ok := c.(*net.UnixConn) if !ok { t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c) } buf := make([]byte, 32) // expect 1 byte oob := make([]byte, 32) // expect 24 bytes closeUnix := time.AfterFunc(5*time.Second, func() { t.Logf("timeout reading from unix socket") uc.Close() }) _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) closeUnix.Stop() scms, err := unix.ParseSocketControlMessage(oob[:oobn]) if err != nil { t.Fatalf("ParseSocketControlMessage: %v", err) } if len(scms) != 1 { t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms) } scm := scms[0] gotFds, err := unix.ParseUnixRights(&scm) if err != nil { t.Fatalf("unix.ParseUnixRights: %v", err) } if len(gotFds) != 1 { t.Fatalf("wanted 1 fd; got %#v", gotFds) } f := os.NewFile(uintptr(gotFds[0]), "fd-from-child") defer f.Close() got, err := ioutil.ReadAll(f) want := "Hello from child process!\n" if string(got) != want { t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want) } }
// close closes the file descriptor mapped to a network namespace func (h nsHandle) close() error { return unix.Close(int(h)) }