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

111 lines
2.0 KiB
Go

package stun
import (
"github.com/pkg/errors"
"net"
)
type Conn struct {
net.Conn
agent *Agent
sess *Session
}
func NewConn(conn net.Conn, config *Config, stop chan struct{}) *Conn {
a := NewAgent(config)
go a.ServeConn(conn, stop)
return &Conn{conn, a, nil}
}
func (c *Conn) Network() string {
return c.LocalAddr().Network()
}
func (c *Conn) Discover() (net.Addr, error) {
res, err := c.Request(&Message{Type: MethodBinding})
if err != nil {
return nil, err
}
mapped := res.GetAddr(c.Network(), AttrXorMappedAddress, AttrMappedAddress)
if mapped != nil {
return mapped, nil
}
return nil, errors.New("stun: bad response, no mapped address")
}
func (c *Conn) Request(req *Message) (res *Message, err error) {
res, _, err = c.RequestTransport(req, c.Conn)
return
}
func (c *Conn) RequestTransport(req *Message, to Transport) (res *Message, from Transport, err error) {
sess := c.sess
auth := c.agent.config.AuthMethod
if to == nil {
to = c.Conn
}
for {
msg := &Message{
req.Type,
NewTransaction(),
append(sess.attrs(), req.Attributes...),
}
res, from, err = c.agent.RoundTrip(msg, to)
if err != nil {
return
}
code := res.GetError()
if code == nil {
// FIXME: authorize response...
if sess != nil {
c.sess = sess
}
return
}
err = code
switch code.Code {
case CodeUnauthorized, CodeStaleNonce:
if auth == nil {
return
}
sess = &Session{
Realm: res.GetString(AttrRealm),
Nonce: res.GetString(AttrNonce),
}
if err = auth(sess); err != nil {
return
}
auth = nil
default:
return
}
}
}
type Session struct {
Realm string
Nonce string
Username string
Key []byte
}
func (s *Session) attrs() []Attr {
if s == nil {
return nil
}
var a []Attr
if s.Realm != "" {
a = append(a, String(AttrRealm, s.Realm))
}
if s.Nonce != "" {
a = append(a, String(AttrNonce, s.Nonce))
}
if s.Username != "" {
a = append(a, String(AttrUsername, s.Username))
}
if s.Key != nil {
a = append(a, MessageIntegrity(s.Key))
}
return a
}