81 lines
1.5 KiB
Go
81 lines
1.5 KiB
Go
package packets
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"packets/internal/consts"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"golang.org/x/net/ipv4"
|
|
)
|
|
|
|
type Peer struct {
|
|
IP net.IP
|
|
Port int
|
|
}
|
|
|
|
func BroadcastAddr(ip net.IP, mask net.IPMask) net.IP {
|
|
b := make(net.IP, len(ip))
|
|
for i := range ip {
|
|
b[i] = ip[i] | ^mask[i]
|
|
}
|
|
return b
|
|
}
|
|
|
|
func AskLAN(filename string) ([]Peer, error) {
|
|
var peers []Peer
|
|
query := []byte("Q:" + filename)
|
|
|
|
pc, err := net.ListenPacket("udp", ":0")
|
|
if err != nil {
|
|
return []Peer{}, err
|
|
}
|
|
defer pc.Close()
|
|
|
|
if pconn := ipv4.NewPacketConn(pc); pconn != nil {
|
|
_ = pconn.SetTTL(1)
|
|
}
|
|
|
|
ifaces, _ := net.Interfaces()
|
|
for _, ifc := range ifaces {
|
|
if ifc.Flags&net.FlagUp == 0 || ifc.Flags&net.FlagLoopback != 0 {
|
|
continue
|
|
}
|
|
|
|
addrs, _ := ifc.Addrs()
|
|
for _, a := range addrs {
|
|
ipnet, ok := a.(*net.IPNet)
|
|
if !ok || ipnet.IP.To4() == nil {
|
|
continue
|
|
}
|
|
|
|
bcast := BroadcastAddr(ipnet.IP.To4(), ipnet.Mask)
|
|
dst := &net.UDPAddr{IP: bcast, Port: 1333}
|
|
|
|
_, err = pc.WriteTo(query, dst)
|
|
if err != nil {
|
|
fmt.Printf(":: (%s) can't send to %s: %s\n", ifc.Name, bcast, err.Error())
|
|
}
|
|
}
|
|
}
|
|
_ = pc.SetDeadline(time.Now().Add(consts.LANDeadline))
|
|
buf := make([]byte, 1500)
|
|
|
|
for {
|
|
n, addr, err := pc.ReadFrom(buf)
|
|
if err != nil {
|
|
break
|
|
}
|
|
msg := string(buf[:n])
|
|
|
|
if strings.HasPrefix(msg, "H:"+filename) {
|
|
parts := strings.Split(msg, ":")
|
|
port, _ := strconv.Atoi(parts[2])
|
|
peers = append(peers, Peer{IP: addr.(*net.UDPAddr).IP, Port: port})
|
|
}
|
|
}
|
|
return peers, nil
|
|
}
|