// Chtimes changes the access and modification times of the named // file, similar to the Unix utime() or utimes() functions. // // The argument times are in nanoseconds, although the underlying // filesystem may truncate or round the values to a more // coarse time unit. func Chtimes(name string, atime_ns int64, mtime_ns int64) Error { var utimes [2]syscall.Timeval utimes[0] = syscall.NsecToTimeval(atime_ns) utimes[1] = syscall.NsecToTimeval(mtime_ns) if e := syscall.Utimes(name, utimes[0:]); e != 0 { return &PathError{"chtimes", name, Errno(e)} } return nil }
// Chtimes changes the access and modification times of the named // file, similar to the Unix utime() or utimes() functions. // // The underlying filesystem may truncate or round the values to a // less precise time unit. func Chtimes(name string, atime time.Time, mtime time.Time) error { var utimes [2]syscall.Timeval atime_ns := atime.Unix()*1e9 + int64(atime.Nanosecond()) mtime_ns := mtime.Unix()*1e9 + int64(mtime.Nanosecond()) utimes[0] = syscall.NsecToTimeval(atime_ns) utimes[1] = syscall.NsecToTimeval(mtime_ns) if e := syscall.Utimes(name, utimes[0:]); e != nil { return &PathError{"chtimes", name, e} } return nil }
func setClock(t time.Time) error { tv := syscall.NsecToTimeval(t.UnixNano()) if err := syscall.Settimeofday(&tv); err != nil { return errors.New("settimeofday: " + err.Error()) } return nil }
// WaitEvent can return dvb.ErrOverflow. If deadline is non zero time WaitEvent // returns true if it doesn't receive any event up to deatline. func (f API3) WaitEvent(ev *Event, deadline time.Time) (bool, error) { fd := f.Fd() if !deadline.IsZero() { timeout := deadline.Sub(time.Now()) if timeout <= 0 { return true, nil } var r syscall.FdSet r.Bits[fd/64] = 1 << (fd % 64) tv := syscall.NsecToTimeval(int64(timeout)) n, err := syscall.Select(int(fd+1), &r, nil, nil, &tv) if err != nil { return false, Error{"get", "event (select)", err} } if n == 0 { return true, nil } } _, _, e := syscall.Syscall( syscall.SYS_IOCTL, fd, _FE_GET_EVENT, uintptr(unsafe.Pointer(ev)), ) if e != 0 { if e == syscall.EOVERFLOW { return false, dvb.ErrOverflow } return false, Error{"get", "event", e} } return false, nil }
func (p *pollster) WaitFD(nsec int64) (fd int, mode int, err os.Error) { if p.nReady == 0 { var timeout *syscall.Timeval var tv syscall.Timeval timeout = nil if nsec > 0 { tv = syscall.NsecToTimeval(nsec) timeout = &tv } var n, e int var tmpReadFds, tmpWriteFds syscall.FdSet_t for { // Temporary syscall.FdSet_ts into which the values are copied // because select mutates the values. tmpReadFds = *p.readFds tmpWriteFds = *p.writeFds n, e = syscall.Select(p.maxFd+1, &tmpReadFds, &tmpWriteFds, nil, timeout) if e != syscall.EINTR { break } } if e != 0 { return -1, 0, os.NewSyscallError("select", e) } if n == 0 { return -1, 0, nil } p.nReady = n *p.readyReadFds = tmpReadFds *p.readyWriteFds = tmpWriteFds p.lastFd = 0 } flag := false for i := p.lastFd; i < p.maxFd+1; i++ { if syscall.FDIsSet(i, p.readyReadFds) { flag = true mode = 'r' syscall.FDClr(i, p.readyReadFds) } else if syscall.FDIsSet(i, p.readyWriteFds) { flag = true mode = 'w' syscall.FDClr(i, p.readyWriteFds) } if flag { if !syscall.FDIsSet(i, p.repeatFds) { p.DelFD(i, mode) } p.nReady-- p.lastFd = i return i, mode, nil } } // Will not reach here. Just to shut up the compiler. return -1, 0, nil }
func traceOne(addr *syscall.SockaddrInet4, ttl int) *ReturnArgs { cli, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { exitWithError(err) } srv, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP) if err != nil { exitWithError(err) } defer syscall.Close(cli) defer syscall.Close(srv) // set ttl, stolen from somewhere else... // https://github.com/aeden/traceroute/blob/master/traceroute.go#L195 if err := syscall.SetsockoptInt(cli, syscall.SOL_IP, syscall.IP_TTL, ttl); err != nil { exitWithError(err) } // set timeout, stolen from somewhere else... // https://github.com/aeden/traceroute/blob/master/traceroute.go#L197 tv := syscall.NsecToTimeval(1e6 * TIMEOUT) if err := syscall.SetsockoptTimeval(srv, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv); err != nil { exitWithError(err) } if err := syscall.Bind(srv, toAddr(HOST, RECV_PORT)); err != nil { exitWithError(err) } rr := &ReturnArgs{} start := time.Now() if err := syscall.Sendto(cli, makeICMP(), 0, addr); err != nil { return rr } buf := make([]byte, 512) _, from, err := syscall.Recvfrom(srv, buf, 0) if err != nil { return rr } rr.elapsed = float64(time.Since(start).Nanoseconds()) / 1e6 t, c := parseICMP(buf) if t == 3 && c == 3 { // Destination port unreachable, type==3 && code==3 rr.done = true } else if t != 11 { // Time Exceeded, type==11 && code in (0,1) return rr } rr.ok = true rr.ip = toStr(from) addrs, err := net.LookupAddr(rr.ip) if err != nil { rr.addr = rr.ip } else { rr.addr = addrs[0] } return rr }
// Select wraps syscall.Select with Go types func Select(n int, r, w, e *FDSet, timeout time.Duration) error { var timeval *syscall.Timeval if timeout >= 0 { t := syscall.NsecToTimeval(timeout.Nanoseconds()) timeval = &t } return sysSelect(n, r, w, e, timeval) }
// Traceroute executes traceroute to given destination, using options from TracerouteOptions // and sending updates to chan c // // Outbound packets are UDP packets and inbound packets are ICMP. // // Returns an error or nil if no error occurred func Traceroute(dest *net.IPAddr, options *TracerouteOptions, c chan TraceUpdate) (err error) { var destAddr [4]byte copy(destAddr[:], dest.IP.To4()) socketAddr, err := getSocketAddr() if err != nil { return } timeoutMs := (int64)(options.TimeoutMs) tv := syscall.NsecToTimeval(1000 * 1000 * timeoutMs) ttl := 1 for { // Set up receiving socket recvSocket, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP) if err != nil { log.Fatal("Cannot setup receive socket, please run as root or with CAP_NET_RAW permissions") return err } // Set up sending socket sendSocket, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { log.Fatal("Cannot setup sending socket") return err } start := time.Now() syscall.SetsockoptInt(sendSocket, 0x0, syscall.IP_TTL, ttl) syscall.SetsockoptTimeval(recvSocket, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv) syscall.Bind(recvSocket, &syscall.SockaddrInet4{Port: options.Port, Addr: socketAddr}) syscall.Sendto(sendSocket, []byte{0x0}, 0, &syscall.SockaddrInet4{Port: options.Port, Addr: destAddr}) var p = make([]byte, options.PacketSize) n, from, err := syscall.Recvfrom(recvSocket, p, 0) elapsed := time.Since(start) if err == nil { currAddr := from.(*syscall.SockaddrInet4).Addr hop := TraceUpdate{Success: true, Address: currAddr, N: n, ElapsedTime: elapsed, TTL: ttl} currHost, err := net.LookupAddr(hop.addressString()) if err == nil { hop.Host = currHost[0] } // Send update c <- hop ttl += 1 // We reached the destination if ttl > options.MaxTTL || currAddr == destAddr { ttl = 1 } } else { c <- TraceUpdate{Success: false, TTL: ttl} ttl += 1 } syscall.Close(recvSocket) syscall.Close(sendSocket) } }
// setSocketTimeout sets the receive and send timeouts on the given socket. func setSocketTimeout(fd int, timeout time.Duration) error { tv := syscall.NsecToTimeval(timeout.Nanoseconds()) for _, opt := range []int{syscall.SO_RCVTIMEO, syscall.SO_SNDTIMEO} { if err := syscall.SetsockoptTimeval(fd, syscall.SOL_SOCKET, opt, &tv); err != nil { return os.NewSyscallError("setsockopt", err) } } return nil }
func (f *AzukiFile) Utimens(a *time.Time, m *time.Time) fuse.Status { tv := make([]syscall.Timeval, 2) if a == nil { tv[0].Usec = _UTIME_OMIT } else { n := a.UnixNano() tv[0] = syscall.NsecToTimeval(n) } if m == nil { tv[1].Usec = _UTIME_OMIT } else { n := a.UnixNano() tv[1] = syscall.NsecToTimeval(n) } err := syscall.Futimes(int(f.File.Fd()), tv) return fuse.ToStatus(err) }
func Hop(port, ttl int, IP_addr net.IP) (*Hop_ret, error) { ret_addr := net.IPv4(0, 0, 0, 0) success := false // make sockets send_udp_s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { return nil, err } recv_icmp_s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP) if err != nil { return nil, err } //editing TTL value for outgoing IPv4 packets if err := syscall.SetsockoptInt(send_udp_s, syscall.SOL_IP, syscall.IP_TTL, ttl); err != nil { return nil, err } tv := syscall.NsecToTimeval(1000 * 1000 * TIME_OUT_MS) syscall.SetsockoptTimeval(recv_icmp_s, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv) defer syscall.Close(send_udp_s) defer syscall.Close(recv_icmp_s) //connect sockets if err := syscall.Bind(recv_icmp_s, &syscall.SockaddrInet4{Port: port, Addr: [4]byte{137, 224, 226, 47}}); err != nil { return nil, err } //send udp-packet var IP [4]byte copy(IP[:], IP_addr.To4()) if err := syscall.Sendto(send_udp_s, []byte{0x42, 0x42}, 0, &syscall.SockaddrInet4{Port: 1337, Addr: IP}); err != nil { return nil, err } //receive ICMP recv_buffer := make([]byte, 4096) _, _, err = syscall.Recvfrom(recv_icmp_s, recv_buffer, 0) if err == nil { header, err := ipv4.ParseHeader(recv_buffer) if err != nil { log.Errorf("%q", err) } success = true ret_addr = header.Src } else { //time out success = false ret_addr = net.IPv4(0, 0, 0, 0) //log.Errorf("%q", err) } //resolve (timeout) errors, retry or return false... return &Hop_ret{Addr: ret_addr, TTL: ttl, success: success}, nil }
// This implementation should work for all systems that implement the utimes syscall func (e *entry) SetMtime(mtime time.Time) error { tvMtime := syscall.NsecToTimeval(mtime.UnixNano()) tvAtime := syscall.NsecToTimeval(time.Now().UnixNano()) resolvedPath := resolveSymlink(e.realPath()) err := syscall.Utimes(resolvedPath, []syscall.Timeval{tvAtime, tvMtime}) if err != nil { return err } e.fileInfo, err = os.Stat(resolvedPath) if err != nil { return err } return nil }
// Take a shared lock on an object. func (ioctx *IOContext) LockShared(oid, name, cookie, tag, desc string, duration time.Duration, flags *byte) (int, error) { c_oid := C.CString(oid) c_name := C.CString(name) c_cookie := C.CString(cookie) c_tag := C.CString(tag) c_desc := C.CString(desc) var c_duration C.struct_timeval if duration != 0 { tv := syscall.NsecToTimeval(time.Now().Add(duration).UnixNano()) c_duration = C.struct_timeval{tv_sec: C.__time_t(tv.Sec), tv_usec: C.__suseconds_t(tv.Usec)} } var c_flags C.uint8_t if flags != nil { c_flags = C.uint8_t(*flags) } defer C.free(unsafe.Pointer(c_oid)) defer C.free(unsafe.Pointer(c_name)) defer C.free(unsafe.Pointer(c_cookie)) defer C.free(unsafe.Pointer(c_tag)) defer C.free(unsafe.Pointer(c_desc)) ret := C.rados_lock_shared( ioctx.ioctx, c_oid, c_name, c_cookie, c_tag, c_desc, &c_duration, c_flags) // 0 on success, negative error code on failure // -EBUSY if the lock is already held by another (client, cookie) pair // -EEXIST if the lock is already held by the same (client, cookie) pair switch ret { case 0: return int(ret), nil case -16: // EBUSY return int(ret), nil case -17: // EEXIST return int(ret), nil default: return int(ret), RadosError(int(ret)) } }
// SetSocketTimeout sets the send and receive timeout for each socket in the // netlink handle. Although the socket timeout has granularity of one // microsecond, the effective granularity is floored by the kernel timer tick, // which default value is four milliseconds. func (h *Handle) SetSocketTimeout(to time.Duration) error { if to < time.Microsecond { return fmt.Errorf("invalid timeout, minimul value is %s", time.Microsecond) } tv := syscall.NsecToTimeval(to.Nanoseconds()) for _, sh := range h.sockets { fd := sh.Socket.GetFd() err := syscall.SetsockoptTimeval(fd, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv) if err != nil { return err } err = syscall.SetsockoptTimeval(fd, syscall.SOL_SOCKET, syscall.SO_SNDTIMEO, &tv) if err != nil { return err } } return nil }
func main() { lsFiles := exec.Command("git", "ls-files", "-z") out, err := lsFiles.Output() if err != nil { fmt.Fprint(os.Stderr, err) os.Exit(1) } files := strings.Split(strings.TrimRight(string(out), "\x00"), "\x00") for _, file := range files { gitLog := exec.Command( "/bin/sh", "-c", fmt.Sprintf(`git log -n 1 --date=rfc2822 "%s" | head -n 3 | tail -n 1`, file), ) out, err := gitLog.Output() if err != nil { fmt.Fprint(os.Stderr, err) os.Exit(1) } mStr := strings.TrimSpace(strings.TrimLeft(string(out), "Date:")) mTime, err := time.Parse(rfc2822, mStr) if err != nil { fmt.Fprintf(os.Stderr, "%s on %s", err, file) os.Exit(1) } mTimeval := syscall.NsecToTimeval(mTime.UnixNano()) times := []syscall.Timeval{ mTimeval, mTimeval, } syscall.Utimes(file, times) fmt.Printf("%s: %s\n", file, mTime) } }
func waitWithTimeout(socket int, timeout time.Duration) (state SocketState, err error) { wfdset := &syscall.FdSet{} FD_ZERO(wfdset) FD_SET(wfdset, socket) timeval := syscall.NsecToTimeval(int64(timeout)) syscall.Select(socket+1, nil, wfdset, nil, &timeval) errcode, err := syscall.GetsockoptInt(socket, syscall.SOL_SOCKET, syscall.SO_ERROR) if err != nil { state = SocketError return } if errcode == int(syscall.EHOSTUNREACH) { state = SocketNotReached return } if errcode == int(syscall.ECONNREFUSED) { state = SocketPortClosed return } if errcode != 0 { state = SocketError err = fmt.Errorf("Connect Error: %v", errcode) return } if FD_ISSET(wfdset, socket) { state = SocketConnected } else { state = SocketTimedOut } return }
func main() { switch len(flag.Args()) { case 0: fmt.Printf("%v\n", date(z)) case 1: argv0 := flag.Args()[0] if argv0[0] == '+' { fmt.Printf("%v\n", dateMap(argv0[1:])) } else { t, err := getTime(argv0) if err != nil { log.Fatalf("%v: %v", argv0, err) } tv := syscall.NsecToTimeval(t.UnixNano()) if err := syscall.Settimeofday(&tv); err != nil { log.Fatalf("%v: %v", argv0, err) } } default: usage() } }
// Read reads from serial port. Port must be opened before calling this method. // It is blocked until all data received or timeout after p.timeout. func (p *port) Read(b []byte) (n int, err error) { var rfds syscall.FdSet fd := int(p.file.Fd()) fdSet(fd, &rfds) var tv *syscall.Timeval if p.timeout > 0 { timeout := syscall.NsecToTimeval(p.timeout.Nanoseconds()) tv = &timeout } if err = syscall.Select(fd+1, &rfds, nil, nil, tv); err != nil { err = fmt.Errorf("serial: could not select: %v", err) return } if !fdIsSet(fd, &rfds) { // Timeout err = ErrTimeout return } n, err = p.file.Read(b) return }
// Traceroute uses the given dest (hostname) and options to execute a traceroute // from your machine to the remote host. // // Outbound packets are UDP packets and inbound packets are ICMP. // // Returns a TracerouteResult which contains an array of hops. Each hop includes // the elapsed time and its IP address. func Traceroute(dest string, options *TracerouteOptions, c ...chan TracerouteHop) (result TracerouteResult, err error) { result.Hops = []TracerouteHop{} destAddr, err := destAddr(dest) result.DestinationAddress = destAddr socketAddr, err := socketAddr() if err != nil { return } timeoutMs := (int64)(options.TimeoutMs()) tv := syscall.NsecToTimeval(1000 * 1000 * timeoutMs) ttl := 1 retry := 0 for { //log.Println("TTL: ", ttl) start := time.Now() // Set up the socket to receive inbound packets recvSocket, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP) if err != nil { return result, err } // Set up the socket to send packets out. sendSocket, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { return result, err } // This sets the current hop TTL syscall.SetsockoptInt(sendSocket, 0x0, syscall.IP_TTL, ttl) // This sets the timeout to wait for a response from the remote host syscall.SetsockoptTimeval(recvSocket, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv) defer syscall.Close(recvSocket) defer syscall.Close(sendSocket) // Bind to the local socket to listen for ICMP packets syscall.Bind(recvSocket, &syscall.SockaddrInet4{Port: options.Port(), Addr: socketAddr}) // Send a single null byte UDP packet syscall.Sendto(sendSocket, []byte{0x0}, 0, &syscall.SockaddrInet4{Port: options.Port(), Addr: destAddr}) var p = make([]byte, options.PacketSize()) n, from, err := syscall.Recvfrom(recvSocket, p, 0) elapsed := time.Since(start) if err == nil { currAddr := from.(*syscall.SockaddrInet4).Addr hop := TracerouteHop{Success: true, Address: currAddr, N: n, ElapsedTime: elapsed, TTL: ttl} // TODO: this reverse lookup appears to have some standard timeout that is relatively // high. Consider switching to something where there is greater control. currHost, err := net.LookupAddr(hop.AddressString()) if err == nil { hop.Host = currHost[0] } notify(hop, c) result.Hops = append(result.Hops, hop) ttl += 1 retry = 0 if ttl > options.MaxHops() || currAddr == destAddr { closeNotify(c) return result, nil } } else { retry += 1 if retry > options.Retries() { notify(TracerouteHop{Success: false, TTL: ttl}, c) ttl += 1 retry = 0 } } } }
func (self *Syncer) copyRegularFile(srcName string, stat *os.FileInfo, dstName string, out chan SyncStats) { stats := new(SyncStats) defer func() { out <- *stats }() outfd, err := os.Open(dstName, os.O_CREATE|os.O_EXCL|os.O_WRONLY, stat.Permission()) if err != nil { fmt.Fprintf(self.ErrorWriter, "Error opening copy output file %s: %s\n", dstName, err) stats.ErrorCount++ return } defer outfd.Close() infd, err := os.Open(srcName, os.O_RDONLY, 0) if err != nil { fmt.Fprintf(self.ErrorWriter, "Error opening copy source file %s: %s\n", srcName, err) stats.ErrorCount++ return } defer infd.Close() const BUF_SIZE = 1024 * 256 buf := make([]byte, BUF_SIZE) bytesRemain := stat.Size for bytesRemain > 0 { n, err := infd.Read(buf) switch { case n == 0: break case n < 0: stats.ErrorCount++ fmt.Fprintf(self.ErrorWriter, "Error copying file %s in read: %s", srcName, err) return default: outN, err := outfd.Write(buf[0:n]) if err != nil || outN != n { fmt.Fprintf(self.ErrorWriter, "Error copying file %s in write: %s", srcName, err) return } bytesRemain -= int64(outN) } } // Close it explicitly before we syscall.Utime() it, even // though the precautionary defer'd Close() above will close // it again later. That's harmless. err = outfd.Close() if err != nil { stats.ErrorCount++ return } // When the Chtimes patch is merged upstream... // err = os.Chtimes(dstName, stat.Atime_ns, stat.Mtime_ns) var tv []syscall.Timeval = make([]syscall.Timeval, 2) tv[0] = syscall.NsecToTimeval(stat.Atime_ns) tv[1] = syscall.NsecToTimeval(stat.Mtime_ns) errno := syscall.Utimes(dstName, tv) if errno != 0 { fmt.Fprintf(self.ErrorWriter, "Error modifying utimes on %s: %v", dstName, errno) stats.ErrorCount++ return } stats.FilesCreated++ if self.Verbose { fmt.Fprintln(self.VerboseWriter, dstName) } }
func setsockoptNsec(fd, level, opt int, nsec int64) os.Error { var tv = syscall.NsecToTimeval(nsec) return os.NewSyscallError("setsockopt", syscall.SetsockoptTimeval(fd, level, opt, &tv)) }
func (sock fd) connectTimeout(addr ax25Addr, timeout time.Duration) (err error) { if timeout == 0 { return sock.connect(addr) } if err = syscall.SetNonblock(int(sock), true); err != nil { return err } err = sock.connect(addr) if err == nil { return nil // Connected } else if err != syscall.EINPROGRESS { return fmt.Errorf("Unable to connect: %s", err) } // Shamelessly stolen from src/pkg/exp/inotify/inotify_linux.go: // // Create fdSet, taking into consideration that // 64-bit OS uses Bits: [16]int64, while 32-bit OS uses Bits: [32]int32. // This only support File Descriptors up to 1024 // if sock > 1024 { panic(fmt.Errorf("connectTimeout: File Descriptor >= 1024: %v", sock)) } fdset := new(syscall.FdSet) fElemSize := 32 * 32 / len(fdset.Bits) fdset.Bits[int(sock)/fElemSize] |= 1 << uint(int(sock)%fElemSize) // // Thanks! // // Wait or timeout var n int var tv syscall.Timeval for { tv = syscall.NsecToTimeval(int64(timeout)) n, err = syscall.Select(int(sock)+1, nil, fdset, nil, &tv) if n < 0 && err != syscall.EINTR { return fmt.Errorf("Unable to connect: %s", err) } else if n > 0 { /* TODO: verify that connection is OK * lon = sizeof(int); * if (getsockopt(soc, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &lon) < 0) { * fprintf(stderr, "Error in getsockopt() %d - %s\n", errno, strerror(errno)); * exit(0); * } * // Check the value returned... * if (valopt) { * fprintf(stderr, "Error in delayed connection() %d - %s\n", valopt, strerror(valopt)); * exit(0); * } */ break } else { return fmt.Errorf("Unable to connect: timeout") } } syscall.SetNonblock(int(sock), false) return }
func toTimeval(d time.Duration) syscall.Timeval { return syscall.NsecToTimeval(int64(d)) }
func Traceroute(dest string, options *TracerouteOptions, c ...chan TracerouteHop) (result TracerouteResult, err error) { result.Hops = []TracerouteHop{} destAddr, err := destAddr(dest) result.DestinationAddress = destAddr sockAddr, err := socketAddr() if err != nil { return } timeoutMs := (int64)(options.TimeoutMs()) tv := syscall.NsecToTimeval(1000 * 1000 * timeoutMs) ttl := 1 retry := 0 for { start := time.Now() recvSock, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_ICMP) if err != nil { return result, err } sendSock, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { return result, err } syscall.SetsockoptInt(sendSock, 0x0, syscall.IP_TTL, ttl) syscall.SetsockoptTimeval(recvSock, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv) defer syscall.Close(sendSock) defer syscall.Close(recvSock) syscall.Bind(recvSock, &syscall.SockaddrInet4{Port: options.Port(), Addr: sockAddr}) syscall.Sendto(sendSock, []byte{0x0}, 0, &syscall.SockaddrInet4{Port: options.Port(), Addr: destAddr}) var p = make([]byte, options.PacketSize()) n, form, err := syscall.Recvfrom(recvSock, p, 0) elapsed := time.Since(start) if err == nil { currAddr := form.(*syscall.SockaddrInet4).Addr hop := TracerouteHop{Success: true, Address: currAddr, N: n, ElapsedTime: elapsed, TTL: ttl} currHost, err := net.LookupAddr(hop.AddressString()) if err == nil { hop.Host = currHost[0] } notify(hop, c) result.Hops = append(result.Hops, hop) ttl += 1 retry = 0 if ttl > options.MaxHops() || currAddr == destAddr { closeNotify(c) return result, nil } } else { retry += 1 if retry > options.Retries() { notify(TracerouteHop{Success: false, TTL: ttl}, c) ttl += 1 retry = 0 } } } return }
// readEvents reads from the inotify file descriptor, converts the // received events into Event objects and sends them via the Event channel func (w *Watcher) readEvents() { var buf [syscall.SizeofInotifyEvent * 4096]byte // Timeout after 500 milliseconds when waiting for events // so we can reliably close the Watcher timeout := int64(500e6) readFds := newFdSet(w.fd) for { var n int var err error select { // See if there is a message on the "done" channel case <-w.done: // Otherwise select fd with timeout default: tmpSet := *readFds timeval := syscall.NsecToTimeval(timeout) n, err = syscall.Select(w.fd+1, &tmpSet, nil, nil, &timeval) if n == 1 { n, err = syscall.Read(w.fd, buf[0:]) } else if err != nil { w.Error <- err } else { continue } } // If EOF or a "done" message is received if n == 0 { goto done } if n < 0 { w.Error <- os.NewSyscallError("read", err) continue } if n < syscall.SizeofInotifyEvent { w.Error <- errors.New("inotify: short read in readEvents()") continue } var offset uint32 = 0 // 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-syscall.SizeofInotifyEvent) { // Point "raw" to the event in the buffer raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset])) event := new(Event) event.Mask = uint32(raw.Mask) event.Cookie = uint32(raw.Cookie) 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() event.Name = w.paths[int(raw.Wd)] // Check if the the watch was removed if event.Mask&IN_IGNORED != 0 { // remove stale watch delete(w.watches, event.Name) delete(w.paths, int(raw.Wd)) } w.mu.Unlock() if nameLen > 0 { // Point "bytes" at the first byte of the filename bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent])) // The filename is padded with NUL bytes. TrimRight() gets rid of those. event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") } // Send the event on the events channel w.Event <- event // Move to the next event in the buffer offset += syscall.SizeofInotifyEvent + nameLen } } done: w.isClosed = true // keep API behaviour consistent when EOF was read err := syscall.Close(w.fd) if err != nil { w.Error <- os.NewSyscallError("close", err) } close(w.Event) close(w.Error) for path, watch := range w.watches { delete(w.watches, path) delete(w.paths, int(watch.wd)) } }
func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) { if p.nReady == 0 { var timeout *syscall.Timeval var tv syscall.Timeval timeout = nil if nsec > 0 { tv = syscall.NsecToTimeval(nsec) timeout = &tv } var n int var e error var tmpReadFds, tmpWriteFds syscall.FdSet for { if p.closed { return -1, 0, errors.New("pollster closed") } // Temporary syscall.FdSet's into which the values are copied // because select mutates the values. tmpReadFds = *p.readFds tmpWriteFds = *p.writeFds s.Unlock() n, e = syscall.Select(p.maxFd+1, &tmpReadFds, &tmpWriteFds, nil, timeout) s.Lock() if e != syscall.EINTR { break } } if e == syscall.EBADF { // Some file descriptor has been closed. tmpReadFds = syscall.FdSet{} tmpWriteFds = syscall.FdSet{} n = 0 for i := 0; i < p.maxFd+1; i++ { if syscall.FDIsSet(i, p.readFds) { var s syscall.Stat_t if syscall.Fstat(i, &s) == syscall.EBADF { syscall.FDSet(i, &tmpReadFds) n++ } } else if syscall.FDIsSet(i, p.writeFds) { var s syscall.Stat_t if syscall.Fstat(i, &s) == syscall.EBADF { syscall.FDSet(i, &tmpWriteFds) n++ } } } } else if e != nil { return -1, 0, os.NewSyscallError("select", e) } if n == 0 { return -1, 0, nil } p.nReady = n *p.readyReadFds = tmpReadFds *p.readyWriteFds = tmpWriteFds p.lastFd = 0 } flag := false for i := p.lastFd; i < p.maxFd+1; i++ { if syscall.FDIsSet(i, p.readyReadFds) { flag = true mode = 'r' syscall.FDClr(i, p.readyReadFds) } else if syscall.FDIsSet(i, p.readyWriteFds) { flag = true mode = 'w' syscall.FDClr(i, p.readyWriteFds) } if flag { if !syscall.FDIsSet(i, p.repeatFds) { p.DelFD(i, mode) } p.nReady-- p.lastFd = i return i, mode, nil } } // Will not reach here. Just to shut up the compiler. return -1, 0, nil }
func MakeTimeval(t time.Duration) syscall.Timeval { return syscall.NsecToTimeval(int64(t)) }
// readEvents reads from the inotify file descriptor, converts the // received events into Event objects and sends them via the Event channel func (w *Watcher) readEvents() { var ( buf [syscall.SizeofInotifyEvent * 4096]byte // Buffer for a maximum of 4096 raw events n int // Number of bytes read with read() errno error // Syscall errno ) rfds := &syscall.FdSet{} timeout := &syscall.Timeval{} for { // Select to see if data available *timeout = syscall.NsecToTimeval(selectWaitTime) FD_ZERO(rfds) FD_SET(rfds, w.fd) if _, errno = syscall.Select(w.fd+1, rfds, nil, nil, timeout); errno != nil { w.Error <- os.NewSyscallError("select", errno) } // See if there is a message on the "done" channel select { case <-w.done: syscall.Close(w.fd) close(w.internalEvent) close(w.Error) return default: } // Check select result to see if Read will block, only read if no blocking. if FD_ISSET(rfds, w.fd) { n, errno = syscall.Read(w.fd, buf[0:]) } else { continue } // If EOF is received if n == 0 { syscall.Close(w.fd) close(w.internalEvent) close(w.Error) return } if n < 0 { w.Error <- os.NewSyscallError("read", errno) continue } if n < syscall.SizeofInotifyEvent { w.Error <- errors.New("inotify: short read in readEvents()") continue } var offset uint32 = 0 // 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-syscall.SizeofInotifyEvent) { // Point "raw" to the event in the buffer raw := (*syscall.InotifyEvent)(unsafe.Pointer(&buf[offset])) event := new(FileEvent) event.mask = uint32(raw.Mask) event.cookie = uint32(raw.Cookie) 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() event.Name = w.paths[int(raw.Wd)] w.mu.Unlock() watchedName := event.Name if nameLen > 0 { // Point "bytes" at the first byte of the filename bytes := (*[syscall.PathMax]byte)(unsafe.Pointer(&buf[offset+syscall.SizeofInotifyEvent])) // The filename is padded with NUL bytes. TrimRight() gets rid of those. event.Name += "/" + strings.TrimRight(string(bytes[0:nameLen]), "\000") } // Send the events that are not ignored on the events channel if !event.ignoreLinux() { // Setup FSNotify flags (inherit from directory watch) w.fsnmut.Lock() if _, fsnFound := w.fsnFlags[event.Name]; !fsnFound { if fsnFlags, watchFound := w.fsnFlags[watchedName]; watchFound { w.fsnFlags[event.Name] = fsnFlags } else { w.fsnFlags[event.Name] = FSN_ALL } } w.fsnmut.Unlock() w.internalEvent <- event } // Move to the next event in the buffer offset += syscall.SizeofInotifyEvent + nameLen } } }