Updated test templates for SIPAgent

This commit is contained in:
Trial97
2020-05-13 18:06:22 +03:00
committed by Dan Christian Bogos
parent 5bbd39a3b2
commit 2161cda746
12 changed files with 257 additions and 128 deletions

View File

@@ -19,19 +19,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package agents
import (
"context"
"fmt"
"net"
"strings"
"syscall"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
"github.com/cgrates/sipd"
"golang.org/x/sys/unix"
)
// updateDiamMsgFromNavMap will update the diameter message with items from navigable map
// updateSIPMsgFromNavMap will update the diameter message with items from navigable map
func updateSIPMsgFromNavMap(m sipd.Message, navMp *utils.OrderedNavigableMap) (err error) {
// write reply into message
for el := navMp.GetFirstElement(); el != nil; el = el.Next() {
@@ -51,27 +47,3 @@ func updateSIPMsgFromNavMap(m sipd.Message, navMp *utils.OrderedNavigableMap) (e
}
return
}
func reuseportControl(network, address string, c syscall.RawConn) error {
var opErr error
err := c.Control(func(fd uintptr) {
opErr = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1)
})
if err != nil {
return err
}
return opErr
}
func listenTCPWithReuseablePort(network, addr string) (net.Listener, error) {
var lc net.ListenConfig
lc.Control = reuseportControl
return lc.Listen(context.Background(), network, addr)
}
func listenUDPWithReuseablePort(network, addr string) (net.PacketConn, error) {
var lc net.ListenConfig
lc.Control = reuseportControl
return lc.ListenPacket(context.Background(), network, addr)
}

View File

@@ -21,6 +21,8 @@ package agents
import (
"fmt"
"net"
"sync"
"time"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
@@ -45,28 +47,34 @@ func NewSIPAgent(connMgr *engine.ConnManager, cfg *config.CGRConfig,
// SIPAgent is a handler for HTTP requests
type SIPAgent struct {
connMgr *engine.ConnManager
filterS *engine.FilterS
cfg *config.CGRConfig
connMgr *engine.ConnManager
filterS *engine.FilterS
cfg *config.CGRConfig
stopChan chan struct{}
}
// Shutdown will stop the SIPAgent server
func (sa *SIPAgent) Shutdown() {
close(sa.stopChan)
}
// ListenAndServe will run the DNS handler doing also the connection to listen address
func (sa *SIPAgent) ListenAndServe() (err error) {
sa.stopChan = make(chan struct{})
utils.Logger.Info(fmt.Sprintf("<%s> start listening on <%s:%s>",
utils.SIPAgent, sa.cfg.SIPAgentCfg().ListenNet, sa.cfg.SIPAgentCfg().Listen))
switch sa.cfg.SIPAgentCfg().ListenNet {
case utils.TCP:
sa.serveTCP()
return sa.serveTCP(sa.stopChan)
case utils.UDP:
sa.serveUDP()
return sa.serveUDP(sa.stopChan)
default:
return fmt.Errorf("Unecepected protocol %s", sa.cfg.SIPAgentCfg().ListenNet)
}
return nil //da.server.ListenAndServe()
}
func (sa *SIPAgent) serveUDP() {
conn, err := listenUDPWithReuseablePort(utils.UDP, sa.cfg.SIPAgentCfg().Listen)
if err != nil {
func (sa *SIPAgent) serveUDP(stop chan struct{}) (err error) {
var conn net.PacketConn
if conn, err = net.ListenPacket(utils.UDP, sa.cfg.SIPAgentCfg().Listen); err != nil {
utils.Logger.Err(
fmt.Sprintf("<%s> error: %s unable to listen to: %s",
utils.SIPAgent, err.Error(), sa.cfg.SIPAgentCfg().Listen))
@@ -76,36 +84,63 @@ func (sa *SIPAgent) serveUDP() {
defer conn.Close()
buf := make([]byte, bufferSize)
wg := sync.WaitGroup{}
for {
n, saddr, err := conn.ReadFrom(buf)
if err != nil {
continue
select {
case <-stop:
wg.Wait()
return
default:
}
conn.SetDeadline(time.Now().Add(time.Second))
var n int
var saddr net.Addr
if n, saddr, err = conn.ReadFrom(buf); err != nil {
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
continue
}
utils.Logger.Err(
fmt.Sprintf("<%s> error: %s unable to read from: %s",
utils.SIPAgent, err.Error(), saddr))
return
}
// echo response
if n < 50 {
conn.WriteTo(buf[:n], saddr)
continue
}
sipMessage := make(sipd.Message) // recreate map SIP
sipMessage.Parse(string(buf[:n]))
var sipAnswer sipd.Message
if sipAnswer, err = sa.handleMessage(sipMessage, saddr.String()); err != nil {
continue
}
if _, err = conn.WriteTo([]byte(sipAnswer.String()), saddr); err != nil {
utils.Logger.Warning(
fmt.Sprintf("<%s> error: %s sending message: %s",
utils.SIPAgent, err.Error(), sipAnswer))
continue
}
wg.Add(1)
go func(message string, conn net.PacketConn) {
sipMessage := make(sipd.Message)
sipMessage.Parse(message)
var sipAnswer sipd.Message
var err error
if sipAnswer, err = sa.handleMessage(sipMessage, saddr.String()); err != nil {
wg.Done()
return
}
if _, err = conn.WriteTo([]byte(sipAnswer.String()), saddr); err != nil {
utils.Logger.Warning(
fmt.Sprintf("<%s> error: %s sending message: %s",
utils.SIPAgent, err.Error(), sipAnswer))
wg.Done()
return
}
wg.Done()
}(string(buf[:n]), conn)
}
}
func (sa *SIPAgent) serveTCP() {
l, err := listenTCPWithReuseablePort(utils.TCP, sa.cfg.SIPAgentCfg().Listen)
if err != nil {
func (sa *SIPAgent) serveTCP(stop chan struct{}) (err error) {
var l *net.TCPListener
var addr *net.TCPAddr
if addr, err = net.ResolveTCPAddr("tcp", sa.cfg.SIPAgentCfg().Listen); err != nil {
utils.Logger.Err(
fmt.Sprintf("<%s> unable to rezolve TCP Address <%s> because: %s",
utils.SIPAgent, sa.cfg.SIPAgentCfg().Listen, err.Error()))
return
}
if l, err = net.ListenTCP(utils.TCP, addr); err != nil {
utils.Logger.Err(
fmt.Sprintf("<%s> error: %s unable to listen to: %s",
utils.SIPAgent, err.Error(), sa.cfg.SIPAgentCfg().Listen))
@@ -114,14 +149,35 @@ func (sa *SIPAgent) serveTCP() {
defer l.Close()
wg := sync.WaitGroup{}
for {
conn, err := l.Accept()
if err != nil {
continue
select {
case <-stop:
wg.Wait()
return
default:
}
l.SetDeadline(time.Now().Add(time.Second))
var conn net.Conn
if conn, err = l.Accept(); err != nil {
if opErr, ok := err.(*net.OpError); ok && opErr.Timeout() {
continue
}
utils.Logger.Err(
fmt.Sprintf("<%s> unable to accept connection because of error %s",
utils.SIPAgent, err.Error()))
return
}
go func(conn net.Conn) {
buf := make([]byte, bufferSize)
for {
select {
case <-stop:
conn.Close()
return
default:
}
conn.SetReadDeadline(time.Now().Add(time.Second))
n, err := conn.Read(buf)
if err != nil {
continue
@@ -162,7 +218,10 @@ func (sa *SIPAgent) handleMessage(sipMessage sipd.Message, remoteHost string) (s
cgrRplyNM := utils.NavigableMap2{}
rplyNM := utils.NewOrderedNavigableMap()
opts := utils.NewOrderedNavigableMap()
reqVars := utils.NavigableMap2{utils.RemoteHost: utils.NewNMData(remoteHost)}
reqVars := utils.NavigableMap2{
utils.RemoteHost: utils.NewNMData(remoteHost),
"Method": utils.NewNMData(sipMessage.MethodFrom("Request")),
}
for _, reqProcessor := range sa.cfg.SIPAgentCfg().RequestProcessors {
agReq := NewAgentRequest(dp, reqVars, &cgrRplyNM, rplyNM,
opts, reqProcessor.Tenant, sa.cfg.GeneralCfg().DefaultTenant,
@@ -218,10 +277,10 @@ func (sa *SIPAgent) processRequest(reqProcessor *config.RequestProcessor,
opts := config.NMAsMapInterface(agReq.Opts, utils.NestingSep)
var reqType string
for _, typ := range []string{
utils.MetaDryRun, /* utils.MetaAuthorize,
utils.MetaInitiate, utils.MetaUpdate,
utils.MetaTerminate, utils.MetaMessage,
utils.MetaCDRs, */utils.MetaEvent, utils.META_NONE} {
utils.MetaDryRun, utils.MetaAuthorize, /*
utils.MetaInitiate, utils.MetaUpdate,
utils.MetaTerminate, utils.MetaMessage,
utils.MetaCDRs, */utils.MetaEvent, utils.META_NONE} {
if reqProcessor.Flags.HasKey(typ) { // request type is identified through flags
reqType = typ
break
@@ -247,29 +306,29 @@ func (sa *SIPAgent) processRequest(reqProcessor *config.RequestProcessor,
utils.Logger.Info(
fmt.Sprintf("<%s> DRY_RUN, processorID: %s, CGREvent: %s",
utils.SIPAgent, reqProcessor.ID, utils.ToJSON(cgrEv)))
// case utils.MetaAuthorize:
// authArgs := sessions.NewV1AuthorizeArgs(
// reqProcessor.Flags.HasKey(utils.MetaAttributes),
// reqProcessor.Flags.ParamsSlice(utils.MetaAttributes),
// reqProcessor.Flags.HasKey(utils.MetaThresholds),
// reqProcessor.Flags.ParamsSlice(utils.MetaThresholds),
// reqProcessor.Flags.HasKey(utils.MetaStats),
// reqProcessor.Flags.ParamsSlice(utils.MetaStats),
// reqProcessor.Flags.HasKey(utils.MetaResources),
// reqProcessor.Flags.HasKey(utils.MetaAccounts),
// reqProcessor.Flags.HasKey(utils.MetaRoutes),
// reqProcessor.Flags.HasKey(utils.MetaRoutesIgnoreErrors),
// reqProcessor.Flags.HasKey(utils.MetaRoutesEventCost),
// cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.RoutePaginator,
// reqProcessor.Flags.HasKey(utils.MetaFD),
// opts,
// )
// rply := new(sessions.V1AuthorizeReply)
// err = sa.connMgr.Call(sa.cfg.SIPAgentCfg().SessionSConns, nil, utils.SessionSv1AuthorizeEvent,
// authArgs, rply)
// if err = agReq.setCGRReply(rply, err); err != nil {
// return
// }
case utils.MetaAuthorize:
authArgs := sessions.NewV1AuthorizeArgs(
reqProcessor.Flags.HasKey(utils.MetaAttributes),
reqProcessor.Flags.ParamsSlice(utils.MetaAttributes),
reqProcessor.Flags.HasKey(utils.MetaThresholds),
reqProcessor.Flags.ParamsSlice(utils.MetaThresholds),
reqProcessor.Flags.HasKey(utils.MetaStats),
reqProcessor.Flags.ParamsSlice(utils.MetaStats),
reqProcessor.Flags.HasKey(utils.MetaResources),
reqProcessor.Flags.HasKey(utils.MetaAccounts),
reqProcessor.Flags.HasKey(utils.MetaRoutes),
reqProcessor.Flags.HasKey(utils.MetaRoutesIgnoreErrors),
reqProcessor.Flags.HasKey(utils.MetaRoutesEventCost),
cgrEv, cgrArgs.ArgDispatcher, *cgrArgs.RoutePaginator,
reqProcessor.Flags.HasKey(utils.MetaFD),
opts,
)
rply := new(sessions.V1AuthorizeReply)
err = sa.connMgr.Call(sa.cfg.SIPAgentCfg().SessionSConns, nil, utils.SessionSv1AuthorizeEvent,
authArgs, rply)
if err = agReq.setCGRReply(rply, err); err != nil {
return
}
// case utils.MetaInitiate:
// initArgs := sessions.NewV1InitSessionArgs(
// reqProcessor.Flags.HasKey(utils.MetaAttributes),

View File

@@ -150,7 +150,7 @@ func testSAitSetAttributeProfile(t *testing.T) {
Tenant: "cgrates.org",
ID: "ChangeDestination",
Contexts: []string{utils.ANY},
FilterIDs: []string{"*prefix:~*req.Account:\"1001\""},
FilterIDs: []string{"*string:~*req.Account:1001"},
Attributes: []*engine.ExternalAttribute{{
Path: utils.MetaReq + utils.NestingSep + "Destination",
Value: "sip:1003@192.168.53.203:5060",
@@ -184,7 +184,7 @@ func testSAitSIPRegister(t *testing.T) {
t.Fatal(err)
}
if expected := "SIP/2.0 200 OK"; recived["Request"] != expected {
if expected := "SIP/2.0 405 Method Not Allowed"; recived["Request"] != expected {
t.Errorf("Expected %q, received: %q", expected, recived["Request"])
}
}

View File

@@ -9,8 +9,7 @@
"request_fields":[],
"reply_fields":[
{"tag": "Request", "path": "*rep.Request", "type": "*constant",
"value": "SIP/2.0 200 OK"},
{"tag": "Authorization", "path": "*rep.Authorization", "type": "*remove"}
"value": "SIP/2.0 405 Method Not Allowed"},
]
},
{
@@ -19,9 +18,9 @@
"flags": ["*attributes","*event"],
"request_fields":[
{"tag": "Account", "path": "*cgreq.Account", "type": "*variable",
"value": "~*req.From", "mandatory": true},
"value": "~*req.From{*sipuri_user}", "mandatory": true},
{"tag": "Destination", "path": "*cgreq.Destination", "type": "*variable",
"value": "~*req.To", "mandatory": true}
"value": "~*req.To{*sipuri_user}", "mandatory": true}
],
"reply_fields":[
{"tag": "Request", "path": "*rep.Request", "type": "*constant",

View File

@@ -9,8 +9,7 @@
"request_fields":[],
"reply_fields":[
{"tag": "Request", "path": "*rep.Request", "type": "*constant",
"value": "SIP/2.0 200 OK"},
{"tag": "Authorization", "path": "*rep.Authorization", "type": "*remove"}
"value": "SIP/2.0 405 Method Not Allowed"},
]
},
{
@@ -19,9 +18,9 @@
"flags": ["*attributes","*event"],
"request_fields":[
{"tag": "Account", "path": "*cgreq.Account", "type": "*variable",
"value": "~*req.From", "mandatory": true},
"value": "~*req.From{*sipuri_user}", "mandatory": true},
{"tag": "Destination", "path": "*cgreq.Destination", "type": "*variable",
"value": "~*req.To", "mandatory": true}
"value": "~*req.To{*sipuri_user}", "mandatory": true}
],
"reply_fields":[
{"tag": "Request", "path": "*rep.Request", "type": "*constant",

View File

@@ -4,24 +4,23 @@
"request_processors": [
{
"id": "Register",
"filters": ["*prefix:~*req.Request:REGISTER"],
"filters": ["*notprefix:~*vars.Method:INVITE"],
"flags": ["*none"],
"request_fields":[],
"reply_fields":[
{"tag": "Request", "path": "*rep.Request", "type": "*constant",
"value": "SIP/2.0 200 OK"},
{"tag": "Authorization", "path": "*rep.Authorization", "type": "*remove"}
"value": "SIP/2.0 405 Method Not Allowed"},
]
},
{
"id": "InviteRedirect",
"filters": ["*prefix:~*req.Request:INVITE"],
"filters": ["*prefix:~*vars.Method:INVITE"],
"flags": ["*attributes","*event"],
"request_fields":[
{"tag": "Account", "path": "*cgreq.Account", "type": "*variable",
"value": "~*req.From", "mandatory": true},
"value": "~*req.From{*sipuri_user}", "mandatory": true},
{"tag": "Destination", "path": "*cgreq.Destination", "type": "*variable",
"value": "~*req.To", "mandatory": true}
"value": "~*req.To{*sipuri_user}", "mandatory": true}
],
"reply_fields":[
{"tag": "Request", "path": "*rep.Request", "type": "*constant",

View File

@@ -0,0 +1,68 @@
{
"sip_agent": {
"request_processors": [
{
"id": "NAPTRRoutesQuery",
"filters": ["*string:~*vars.Method:INVITE"],
"flags": ["*event", "*routes","*continue"],
"request_fields":[
{"tag": "Account", "path": "*cgreq.Account", "type": "*variable",
"value": "~*req.From{*sipuri_user}", "mandatory": true},
{"tag": "Destination", "path": "*cgreq.Destination", "type": "*variable",
"value": "~*req.To{*sipuri_user}", "mandatory": true}
],
"reply_fields":[
],
},
{
"id": "NAPTRSuppliersOneSupplier",
"filters": ["*string:~*vars.Method:INVITE",
"*gte:~*cgrep.Routes.Count:1"],
"flags": ["*none","*continue"], // do not send request to CGRateS
"reply_fields":[
{"tag": "Request", "path": "*rep.Request", "type": "*constant",
"value": "SIP/2.0 302 Moved Temporarily"},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value":"\""},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value":"~*cgreq.Destination"},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value":"\" <sip:"},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value":"~*cgreq.Destination"},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value":"@"},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value": "~*cgrep.Routes.SortedRoutes[0].RouteParameters"},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value":">;q=0.7; expires=3600"},
],
},
{
"id": "NAPTRSuppliersTwoSuppliers",
"filters": ["*string:~*vars.Method:INVITE",
"*gte:~*cgrep.Routes.Count:2"],
"flags": ["*none","*continue"],
"reply_fields":[
{"tag": "Request", "path": "*rep.Request", "type": "*constant",
"value": "SIP/2.0 302 Moved Temporarily"},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value":"\""},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value":"~*cgreq.Destination"},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value":"\" <sip:"},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value":"~*cgreq.Destination"},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value":"@"},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value": "~*cgrep.Routes.SortedRoutes[1].RouteParameters"},
{"tag": "Contact", "path": "*rep.Contact", "type": "*composed",
"value":">;q=0.1"},
],
},
],
},
}

2
go.mod
View File

@@ -25,7 +25,7 @@ require (
github.com/cgrates/ltcache v0.0.0-20181016092649-92fb7fa77cca
github.com/cgrates/radigo v0.0.0-20200324152710-35e651804ad1
github.com/cgrates/rpcclient v0.0.0-20200326100105-a579e2c47453
github.com/cgrates/sipd v1.0.0
github.com/cgrates/sipd v1.0.1-0.20200513092040-728b130a73d6
github.com/creack/pty v1.1.7
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/fiorix/go-diameter v3.0.3-0.20190716165154-f4823472d0e0+incompatible

3
go.sum
View File

@@ -63,8 +63,9 @@ github.com/cgrates/radigo v0.0.0-20200324152710-35e651804ad1 h1:QvA6Nbwq9kTd7hsv
github.com/cgrates/radigo v0.0.0-20200324152710-35e651804ad1/go.mod h1:HZbsg3Y+xw4lsfCqX9rzj429wrg0XOug6pFT3B6VHZY=
github.com/cgrates/rpcclient v0.0.0-20200326100105-a579e2c47453 h1:kgIdi3qR/meiWILdmDRuDi1fFgd6A3lutGV6HLiTDyc=
github.com/cgrates/rpcclient v0.0.0-20200326100105-a579e2c47453/go.mod h1:xXLqAKVvcdWeDYwHJYwDgAI3ZOg5LZYxzb72kLjsLZU=
github.com/cgrates/sipd v1.0.0 h1:9CPVaWCYBAWGVyzsEtv+VbG6kMk+sHml6kx3OvYQnkc=
github.com/cgrates/sipd v1.0.0/go.mod h1:Itz4HoJHqckX9XAbGRanB1PvXfKrIO/UtMB8JwCFsT4=
github.com/cgrates/sipd v1.0.1-0.20200513092040-728b130a73d6 h1:yKEwGpD79Pbss7/03mwPh9MvbBXmttiUX+iyA67PRA8=
github.com/cgrates/sipd v1.0.1-0.20200513092040-728b130a73d6/go.mod h1:yAWcE5qt60PMrWME9Ijp6IWlWwL5d+/VflUYudO1Xm0=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/creack/pty v1.1.7 h1:6pwm8kMQKCmgUg0ZHTm5+/YvRK0s3THD/28+T6/kk4A=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=

View File

@@ -84,24 +84,21 @@ func (sip *SIPAgent) GetIntenternalChan() (conn chan rpcclient.ClientConnector)
// Reload handles the change of config
func (sip *SIPAgent) Reload() (err error) {
// if sip.oldListen == sip.cfg.SIPAgentCfg().Listen {
// return
// }
// if err = sip.Shutdown(); err != nil {
// return
// }
// sip.Lock()
// sip.oldListen = sip.cfg.SIPAgentCfg().Listen
// defer sip.Unlock()
// if err = sip.sip.Reload(); err != nil {
// return
// }
// go func() {
// if err := sip.sip.ListenAndServe(); err != nil {
// utils.Logger.Err(fmt.Sprintf("<%s> error: <%s>", utils.SIPAgent, err.Error()))
// sip.exitChan <- true // stop the engine here
// }
// }()
if sip.oldListen == sip.cfg.SIPAgentCfg().Listen {
return
}
if err = sip.Shutdown(); err != nil {
return
}
sip.Lock()
sip.oldListen = sip.cfg.SIPAgentCfg().Listen
sip.Unlock()
go func() {
if err := sip.sip.ListenAndServe(); err != nil {
utils.Logger.Err(fmt.Sprintf("<%s> error: <%s>", utils.SIPAgent, err.Error()))
sip.exitChan <- true // stop the engine here
}
}()
return
}
@@ -109,9 +106,7 @@ func (sip *SIPAgent) Reload() (err error) {
func (sip *SIPAgent) Shutdown() (err error) {
sip.Lock()
defer sip.Unlock()
// if err = sip.sip.Shutdown(); err != nil {
// return
// }
sip.sip.Shutdown()
sip.sip = nil
return
}

View File

@@ -644,6 +644,9 @@ const (
MetaDuration = "*duration"
MetaLibPhoneNumber = "*libphonenumber"
MetaIP2Hex = "*ip2hex"
MetaSIPURIMethod = "*sipuri_method"
MetaSIPURIHost = "*sipuri_host"
MetaSIPURIUser = "*sipuri_user"
MetaReload = "*reload"
MetaLoad = "*load"
MetaRemove = "*remove"

View File

@@ -26,6 +26,7 @@ import (
"strings"
"time"
"github.com/cgrates/sipd"
"github.com/nyaruka/phonenumbers"
)
@@ -75,6 +76,12 @@ func NewDataConverter(params string) (conv DataConverter, err error) {
return NewDurationConverter("")
case params == MetaIP2Hex:
return new(IP2HexConverter), nil
case params == MetaSIPURIHost:
return new(SIPURIHostConverter), nil
case params == MetaSIPURIUser:
return new(SIPURIUserConverter), nil
case params == MetaSIPURIMethod:
return new(SIPURIMethodConverter), nil
case strings.HasPrefix(params, MetaLibPhoneNumber):
if len(params) == len(MetaLibPhoneNumber) {
return NewPhoneNumberConverter("")
@@ -300,3 +307,30 @@ func (*IP2HexConverter) Convert(in interface{}) (out interface{}, err error) {
}
return "0x" + string([]byte(hx)[len(hx)-8:]), nil
}
// SIPURIHostConverter will return the
type SIPURIHostConverter struct{}
// Convert implements DataConverter interface
func (*SIPURIHostConverter) Convert(in interface{}) (out interface{}, err error) {
val := IfaceAsString(in)
return sipd.HostFrom(val), nil
}
// SIPURIUserConverter will return the
type SIPURIUserConverter struct{}
// Convert implements DataConverter interface
func (*SIPURIUserConverter) Convert(in interface{}) (out interface{}, err error) {
val := IfaceAsString(in)
return sipd.NameFrom(val), nil
}
// SIPURIMethodConverter will return the
type SIPURIMethodConverter struct{}
// Convert implements DataConverter interface
func (*SIPURIMethodConverter) Convert(in interface{}) (out interface{}, err error) {
val := IfaceAsString(in)
return sipd.MethodFrom(val), nil
}