Browse Source

Merge a453ccd7e5 into 1158f11cb3

pull/32/merge
alexgor1 6 months ago
committed by GitHub
parent
commit
28fdccfff1
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
5 changed files with 130 additions and 14 deletions
  1. +66
    -13
      dialog/dialog.go
  2. +7
    -1
      dialog/messages.go
  3. +40
    -0
      dialog/receiver.go
  4. +5
    -0
      go.mod
  5. +12
    -0
      go.sum

+ 66
- 13
dialog/dialog.go View File

@ -28,6 +28,8 @@ import (
"github.com/jart/gosip/sdp"
"github.com/jart/gosip/sip"
"github.com/jart/gosip/util"
"github.com/icholy/digest"
)
const (
@ -62,8 +64,12 @@ type dialogState struct {
sendHangupChan <-chan bool
state int // Current state of the dialog.
dest string // Destination hostname (or IP).
destPort uint16 // Destination port
addr string // Destination ip:port.
sock *net.UDPConn // Outbound message socket (connected for ICMP)
username string // Username for authorization
password string // Password for authorization
protocol string // Can be "tcp" or "udp"
sock net.Conn // Outbound message socket (connected for ICMP)
csock *net.UDPConn // Inbound socket for Contact field.
routes *AddressRoute // List of SRV addresses to attempt contacting.
invite *sip.Msg // Our INVITE that established the dialog.
@ -80,7 +86,30 @@ type dialogState struct {
}
// NewDialog creates a phone call.
func NewDialog(invite *sip.Msg) (dl *Dialog, err error) {
func NewDialog(invite *sip.Msg, protocol string) (dl *Dialog, err error) {
errChan := make(chan error)
stateChan := make(chan int)
peerChan := make(chan *net.UDPAddr)
sendHangupChan := make(chan bool, 4)
dls := &dialogState{
errChan: errChan,
stateChan: stateChan,
peerChan: peerChan,
sendHangupChan: sendHangupChan,
invite: invite,
protocol: protocol,
}
go dls.run()
return &Dialog{
OnErr: errChan,
OnState: stateChan,
OnPeer: peerChan,
Hangup: sendHangupChan,
}, nil
}
// NewDialogWithCredentials creates a phone call.
func NewDialogWithCredentials(invite *sip.Msg, protocol string, username string, password string) (dl *Dialog, err error) {
errChan := make(chan error)
stateChan := make(chan int)
peerChan := make(chan *net.UDPAddr)
@ -91,6 +120,9 @@ func NewDialog(invite *sip.Msg) (dl *Dialog, err error) {
peerChan: peerChan,
sendHangupChan: sendHangupChan,
invite: invite,
username: username,
password: password,
protocol: protocol,
}
go dls.run()
return &Dialog{
@ -164,6 +196,7 @@ func (dls *dialogState) sendRequest(request *sip.Msg) bool {
dls.request = request
dls.routes = routes
dls.dest = host
dls.destPort = port
return dls.popRoute()
}
@ -194,17 +227,17 @@ func (dls *dialogState) connect() bool {
// to the remote address so we can receive ICMP unavailable errors. It also
// allows us to discover the appropriate IP address for the local machine.
dls.cleanupSock()
conn, err := net.Dial("udp", dls.addr)
conn, err := net.Dial(dls.protocol, dls.addr)
if err != nil {
log.Printf("net.Dial(udp, %s) failed: %s\r\n", dls.addr, err)
log.Printf("net.Dial(%s, %s) failed: %s\r\n", dls.protocol, dls.addr, err)
return false
}
dls.sock = conn.(*net.UDPConn)
dls.sock = conn
sockMsgs := make(chan *sip.Msg)
sockErrs := make(chan error)
dls.sockMsgs = sockMsgs
dls.sockErrs = sockErrs
go ReceiveMessages(dls.sock, sockMsgs, sockErrs)
go ReceiveMessagesFromAddr(dls.sock, sockMsgs, sockErrs, &net.UDPAddr{IP: net.ParseIP(dls.dest), Port: int(dls.destPort)})
// But a connected UDP socket can only receive packets from a single host.
// SIP signalling paths can change depending on the environment, so we need
@ -227,9 +260,16 @@ func (dls *dialogState) connect() bool {
}
func (dls *dialogState) populate(msg *sip.Msg) {
laddr := dls.sock.LocalAddr().(*net.UDPAddr)
lhost := laddr.IP.String()
lport := uint16(laddr.Port)
var lhost string
var lport uint16
switch laddr := dls.sock.LocalAddr().(type) {
case *net.UDPAddr:
lhost = laddr.IP.String()
lport = uint16(laddr.Port)
case *net.TCPAddr:
lhost = laddr.IP.String()
lport = uint16(laddr.Port)
}
if msg.Via == nil {
msg.Via = &sip.Via{Host: lhost}
@ -303,10 +343,6 @@ func (dls *dialogState) handleResponse(msg *sip.Msg) bool {
return true
}
if msg.Status >= sip.StatusOK && dls.request.Method == sip.MethodInvite {
if msg.Contact == nil {
dls.errChan <- errors.New("Remote UA sent >=200 response w/o Contact")
return false
}
if !dls.send(NewAck(msg, dls.request)) {
return false
}
@ -332,6 +368,23 @@ func (dls *dialogState) handleResponse(msg *sip.Msg) bool {
dls.transition(Hangup)
return false
}
case sip.StatusUnauthorized:
chal, err := digest.ParseChallenge(msg.WWWAuthenticate)
if err != nil {
dls.errChan <- errors.New("Fail to parse WWWAuthenticate challenge")
}
// Reply with digest
cred, _ := digest.Digest(chal, digest.Options{
Method: msg.CSeqMethod,
URI: dls.dest,
Username: dls.username,
Password: dls.password,
})
newReq := dls.invite.Copy()
newReq.Authorization = cred.String()
return dls.send(newReq)
case sip.StatusServiceUnavailable:
if dls.request == dls.invite {
log.Printf("Service unavailable: %s (%s)\r\n", dls.sock.RemoteAddr(), dls.dest)


+ 7
- 1
dialog/messages.go View File

@ -58,9 +58,15 @@ func NewResponse(msg *sip.Msg, status int) *sip.Msg {
// http://tools.ietf.org/html/rfc3261#section-17.1.1.3
func NewAck(msg, invite *sip.Msg) *sip.Msg {
var request *sip.URI
if msg.Contact != nil {
request = msg.Contact.Uri
} else {
request = msg.From.Uri
}
return &sip.Msg{
Method: sip.MethodAck,
Request: msg.Contact.Uri,
Request: request,
From: msg.From,
To: msg.To,
Via: msg.Via.Detach(),


+ 40
- 0
dialog/receiver.go View File

@ -23,6 +23,46 @@ import (
"github.com/jart/gosip/sip"
)
func ReceiveMessagesFromAddr(sock net.Conn, c chan<- *sip.Msg, e chan<- error, addr *net.UDPAddr) {
buf := make([]byte, 2048)
var lhost string
var lport uint16
switch laddr := sock.LocalAddr().(type) {
case *net.UDPAddr:
lhost = laddr.IP.String()
lport = uint16(laddr.Port)
case *net.TCPAddr:
lhost = laddr.IP.String()
lport = uint16(laddr.Port)
}
for {
amt, err := sock.Read(buf)
if err != nil {
e <- err
break
}
ts := time.Now()
packet := buf[0:amt]
if *tracing {
trace("recv", packet, addr)
}
msg, err := sip.ParseMsg(packet)
if err != nil {
log.Printf("Dropping SIP message: %s\r\n", err)
continue
}
addReceived(msg, addr)
addTimestamp(msg, ts)
if msg.Route != nil && msg.Route.Uri.Host == lhost && or5060(msg.Route.Uri.Port) == lport {
msg.Route = msg.Route.Next
}
fixMessagesFromStrictRouters(lhost, lport, msg)
c <- msg
}
close(c)
close(e) // Must be unbuffered!
}
func ReceiveMessages(sock *net.UDPConn, c chan<- *sip.Msg, e chan<- error) {
buf := make([]byte, 2048)
laddr := sock.LocalAddr().(*net.UDPAddr)


+ 5
- 0
go.mod View File

@ -1,3 +1,8 @@
module github.com/jart/gosip
go 1.14
require (
github.com/icholy/digest v0.1.22
)

+ 12
- 0
go.sum View File

@ -0,0 +1,12 @@
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/icholy/digest v0.1.22 h1:dRIwCjtAcXch57ei+F0HSb5hmprL873+q7PoVojdMzM=
github.com/icholy/digest v0.1.22/go.mod h1:uLAeDdWKIWNFMH0wqbwchbTQOmJWhzSnL7zmqSPqEEc=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=

Loading…
Cancel
Save