1// 2// UDP ping command 3// Model 1, does UDP work inline 4// 5 6// this doesn't use ZeroMQ at all 7 8package main 9 10import ( 11 "fmt" 12 "log" 13 "syscall" 14 "time" 15) 16 17const ( 18 PING_PORT_NUMBER = 9999 19 PING_MSG_SIZE = 1 20 PING_INTERVAL = 1000 * time.Millisecond // Once per second 21) 22 23func main() { 24 25 log.SetFlags(log.Lshortfile) 26 27 // Create UDP socket 28 fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) 29 if err != nil { 30 log.Fatalln(err) 31 } 32 33 // Ask operating system to let us do broadcasts from socket 34 if err := syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1); err != nil { 35 log.Fatalln(err) 36 } 37 38 // Bind UDP socket to local port so we can receive pings 39 if err := syscall.Bind(fd, &syscall.SockaddrInet4{Port: PING_PORT_NUMBER, Addr: [4]byte{0, 0, 0, 0}}); err != nil { 40 log.Fatalln(err) 41 } 42 43 buffer := make([]byte, PING_MSG_SIZE) 44 45 // We use syscall.Select to wait for activity on the UDP socket. 46 // We send a beacon once a second, and we collect and report 47 // beacons that come in from other nodes: 48 49 rfds := &syscall.FdSet{} 50 timeout := &syscall.Timeval{} 51 52 // Send first ping right away 53 ping_at := time.Now() 54 55 bcast := &syscall.SockaddrInet4{Port: PING_PORT_NUMBER, Addr: [4]byte{255, 255, 255, 255}} 56 for { 57 dur := int64(ping_at.Sub(time.Now()) / time.Microsecond) 58 if dur < 0 { 59 dur = 0 60 } 61 timeout.Sec, timeout.Usec = dur/1000000, dur%1000000 62 FD_ZERO(rfds) 63 FD_SET(rfds, fd) 64 _, err := syscall.Select(fd+1, rfds, nil, nil, timeout) 65 if err != nil { 66 log.Fatalln(err) 67 } 68 69 // Someone answered our ping 70 if FD_ISSET(rfds, fd) { 71 _, addr, err := syscall.Recvfrom(fd, buffer, 0) 72 if err != nil { 73 log.Fatalln(err) 74 } 75 a := addr.(*syscall.SockaddrInet4) 76 fmt.Printf("Found peer %v.%v.%v.%v:%v\n", a.Addr[0], a.Addr[1], a.Addr[2], a.Addr[3], a.Port) 77 } 78 if time.Now().After(ping_at) { 79 // Broadcast our beacon 80 fmt.Println("Pinging peers...") 81 buffer[0] = '!' 82 if err := syscall.Sendto(fd, buffer, 0, bcast); err != nil { 83 log.Fatalln(err) 84 } 85 ping_at = time.Now().Add(PING_INTERVAL) 86 } 87 } 88 89} 90 91func FD_SET(p *syscall.FdSet, i int) { 92 p.Bits[i/64] |= 1 << uint(i) % 64 93} 94 95func FD_ISSET(p *syscall.FdSet, i int) bool { 96 return (p.Bits[i/64] & (1 << uint(i) % 64)) != 0 97} 98 99func FD_ZERO(p *syscall.FdSet) { 100 for i := range p.Bits { 101 p.Bits[i] = 0 102 } 103} 104