gost_software/vendor/github.com/isofew/go-stun/stun/server.go
2018-05-17 13:14:45 +01:00

127 lines
2.4 KiB
Go

package stun
import (
"net"
"sync"
)
func ListenAndServe(network, laddr string, config *Config) error {
srv := NewServer(config)
return srv.ListenAndServe(network, laddr)
}
type Server struct {
agent *Agent
mu sync.RWMutex
conns []net.PacketConn
}
func NewServer(config *Config) *Server {
srv := &Server{agent: NewAgent(config)}
srv.agent.Handler = srv
return srv
}
func (srv *Server) ListenAndServe(network, laddr string) error {
c, err := net.ListenPacket(network, laddr)
if err != nil {
return err
}
srv.addConn(c)
defer srv.removeConn(c)
// not using stop channel
return srv.agent.ServePacket(c, make(chan struct{}))
}
func (srv *Server) ServeSTUN(msg *Message, from Transport) {
if msg.Type == MethodBinding {
to := from
mapped := from.RemoteAddr()
ip, port := SockAddr(from.LocalAddr())
res := &Message{
Type: MethodBinding | KindResponse,
Transaction: msg.Transaction,
Attributes: []Attr{
Addr(AttrXorMappedAddress, mapped),
Addr(AttrMappedAddress, mapped),
},
}
srv.mu.RLock()
defer srv.mu.RUnlock()
if ch, ok := msg.GetInt(AttrChangeRequest); ok && ch != 0 {
for _, c := range srv.conns {
chip, chport := SockAddr(c.LocalAddr())
if chip.IsUnspecified() {
continue
}
if ch&ChangeIP != 0 {
if !ip.Equal(chip) {
to = &packetConn{c, mapped}
break
}
} else if ch&ChangePort != 0 {
if ip.Equal(chip) && port != chport {
to = &packetConn{c, mapped}
break
}
}
}
}
if len(srv.conns) < 2 {
srv.agent.Send(res, to)
return
}
other:
for _, a := range srv.conns {
aip, aport := SockAddr(a.LocalAddr())
if aip.IsUnspecified() || !ip.Equal(aip) || port == aport {
continue
}
for _, b := range srv.conns {
bip, bport := SockAddr(b.LocalAddr())
if bip.IsUnspecified() || bip.Equal(ip) || aport != bport {
continue
}
res.Set(Addr(AttrOtherAddress, b.LocalAddr()))
break other
}
}
srv.agent.Send(res, to)
}
}
func (srv *Server) addConn(c net.PacketConn) {
srv.mu.Lock()
srv.conns = append(srv.conns, c)
srv.mu.Unlock()
}
func (srv *Server) removeConn(c net.PacketConn) {
srv.mu.Lock()
l := srv.conns
for i, it := range l {
if it == c {
srv.conns = append(l[:i], l[i+1:]...)
break
}
}
srv.mu.Unlock()
}
func (srv *Server) Close() error {
srv.mu.RLock()
defer srv.mu.RUnlock()
for _, it := range srv.conns {
it.Close()
}
srv.conns = nil
return nil
}