func (e *attemptEngine) read() error { buf := make([]byte, 512) n, from, err := e.sock.ReadFromUDP(buf) if err != nil { if neterr, ok := err.(net.Error); ok && neterr.Timeout() { return nil } return err } packet, err := stun.ParsePacket(buf[:n], nil) if err != nil { return nil } if packet.Method != stun.MethodBinding { return nil } switch packet.Class { case stun.ClassRequest: response, err := stun.BindResponse(packet.Tid[:], from, nil, false) if err != nil { return nil } e.sock.WriteToUDP(response, from) if packet.UseCandidate { for i := range e.attempts { if from.String() != e.attempts[i].Addr.String() { continue } if !e.attempts[i].success { return errors.New("Initiator told us to use bad link") } e.p2pconn = newConn(e.sock, e.attempts[i].localaddr, e.attempts[i].Addr) return nil } } case stun.ClassSuccess: for i := range e.attempts { if !bytes.Equal(packet.Tid[:], e.attempts[i].tid) { continue } if from.String() != e.attempts[i].Addr.String() { return nil } if e.attempts[i].chosen { e.p2pconn = newConn(e.sock, e.attempts[i].localaddr, e.attempts[i].Addr) return nil } e.attempts[i].success = true e.attempts[i].localaddr = packet.Addr e.attempts[i].timeout = time.Now().Add(probeInterval) return nil } } return nil }
func getReflexive(sock *net.UDPConn) (*net.UDPAddr, error) { serverAddr, err := net.ResolveUDPAddr("udp", *stunserver) if err != nil { return nil, errors.New("Couldn't resolve STUN server") } var tid [12]byte if _, err = rand.Read(tid[:]); err != nil { return nil, err } request, err := stun.BindRequest(tid[:], nil, true, false) if err != nil { return nil, err } n, err := sock.WriteTo(request, serverAddr) if err != nil { return nil, err } if n < len(request) { return nil, err } var buf [1024]byte n, _, err = sock.ReadFromUDP(buf[:]) if err != nil { return nil, err } packet, err := stun.ParsePacket(buf[:n], nil) if err != nil { return nil, err } if packet.Class != stun.ClassSuccess || packet.Method != stun.MethodBinding || packet.Addr == nil || !bytes.Equal(tid[:], packet.Tid[:]) { return nil, errors.New("No address provided by STUN server") } return packet.Addr, nil }