You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

117 lines
3.0 KiB

// SIP Transport Layer. Responsible for serializing messages to/from
// your network.
package sip
import (
"bytes"
"errors"
"flag"
"net"
"time"
)
var (
tracing = flag.Bool("tracing", true, "Enable SIP message tracing")
timestampTagging = flag.Bool("timestampTagging", false, "Add microsecond timestamps to Via tags")
)
// Transport sends and receives SIP messages over UDP with stateless routing.
type Transport struct {
// Channel to which received SIP messages and errors are published.
C chan *Msg
E chan error
// Underlying UDP socket.
Sock *net.UDPConn
// When you send an outbound request (not a response) you have to set the via
// tag: ``msg.Via = tp.Via.Copy().Branch().SetNext(msg.Via)``. The details of
// the branch parameter... are tricky.
Via *Via
// Contact that gets put in outbound SIP messages.
Contact *Addr
}
// Creates a new stateless network mechanism for transmitting and receiving SIP
// signalling messages.
//
// contact is a SIP address, e.g. "<sip:1.2.3.4>", that tells how to bind
// sockets. If contact.Uri.Port is 0, it'll be mutated with a randomly selected
// port. This value is also used for contact headers which tell other
// user-agents where to send responses and hence should only contain an IP or
// canonical address.
func NewTransport(contact *Addr) (tp *Transport, err error) {
saddr := net.JoinHostPort(contact.Uri.Host, portstr(contact.Uri.Port))
c, err := net.ListenPacket("udp", saddr)
if err != nil {
return nil, err
}
sock := c.(*net.UDPConn)
addr := c.LocalAddr().(*net.UDPAddr)
contact = contact.Copy()
contact.Next = nil
contact.Uri.Port = uint16(addr.Port)
contact.Uri.Params["transport"] = "udp"
tp = &Transport{
C: make(chan *Msg, 32),
E: make(chan error, 1),
Sock: sock,
Contact: contact,
Via: &Via{
Host: addr.IP.String(),
Port: uint16(addr.Port),
},
}
go ReceiveMessages(contact, sock, tp.C, tp.E)
return
}
// Sends a SIP message.
func (tp *Transport) Send(msg *Msg) error {
msg, hostport, err := RouteMessage(tp.Via, tp.Contact, msg)
if err != nil {
return err
}
addr, err := net.ResolveUDPAddr("udp", hostport)
if err != nil {
return err
}
if msg.MaxForwards > 0 {
msg.MaxForwards--
}
ts := time.Now()
addTimestamp(msg, ts)
var b bytes.Buffer
msg.Append(&b)
if *tracing {
trace("send", b.String(), addr, ts)
}
_, err = tp.Sock.WriteTo(b.Bytes(), addr)
if err != nil {
return err
}
return nil
}
// Checks if message is acceptable, otherwise sets msg.Error and returns false.
func (tp *Transport) sanityCheck(msg *Msg) error {
if msg.MaxForwards <= 0 {
tp.Send(NewResponse(msg, StatusTooManyHops))
return errors.New("Froot loop detected")
}
if msg.IsResponse {
if msg.Status >= 700 {
tp.Send(NewResponse(msg, StatusBadRequest))
return errors.New("Crazy status number")
}
} else {
if msg.CSeqMethod == "" || msg.CSeqMethod != msg.Method {
tp.Send(NewResponse(msg, StatusBadRequest))
return errors.New("Bad CSeq")
}
}
return nil
}