sipgo

package module
v0.0.0-...-4380dcc Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 10, 2023 License: BSD-2-Clause Imports: 12 Imported by: 0

README

SIPGO

Go Report Card License GitHub go.mod Go version

Library for writing fast SIP servers in GO language.
It comes with SIP stack (RFC 3261) optimized for fast parsing.

Fetch lib with:

go get github.com/emiago/sipgo

NOTE: LIB MAY HAVE API CHANGES UNTIL STABLE VERSION.

Performance

As example you can find example/proxysip as simple version of statefull proxy. It is used for stress testing with sipp. To find out more about performance check the latest results:
example/proxysip

(Contributions are welcome, I would place your results here)

Examples

If you use this lib in some way, open issue for more sharing.

Usage

Lib allows you to write easily sip servers(or clients) or to build up stateful proxies, registrar or any sip routing. Writing in GO we are not limited to handle SIP requests/responses in many ways, or to integrate and scale with any external services (databases, caches...).

UAS/UAC build

Using server or client handle for UA you can build incoming or outgoing requests.

ua, _ := sipgo.NewUA() // Build user agent
srv, _ := sipgo.NewServer(ua) // Creating server handle
client, _ := sipgo.NewClient(ua) // Creating client handle
srv.OnInvite(inviteHandler)
srv.OnAck(ackHandler)
srv.OnCancel(cancelHandler)
srv.OnBye(byeHandler)

// For registrars
// srv.OnRegister(registerHandler)
go srv.ListenAndServe(ctx, "tcp", "127.0.0.1:5061")
go srv.ListenAndServe(ctx, "ws", "127.0.0.1:5080")
go srv.ListenAndServe(ctx, "udp", "127.0.0.1:5060")
<-ctx.Done()
TLS transports
// TLS
conf :=  sipgo.GenerateTLSConfig(certFile, keyFile, rootPems)
srv.ListenAndServeTLS(ctx, "tcp", "127.0.0.1:5061", conf)

Stateful Proxy build

Proxy is combination client and server handle that creates server/client transaction. They need to share same ua same like uac/uas build. Forwarding request is done via client handle:


srv.OnInvite(func(req *sip.Request, tx sip.ServerTransaction) {
    req.SetDestination("10.1.2.3") // Change sip.Request destination
    // Start client transaction and relay our request. Add Via and Record-Route header
    clTx, err := client.TransactionRequest(req, sipgo.ClientRequestAddVia, sipgo.ClientRequestAddRecordRoute)
    // Send back response
    res := <-cltx.Responses()
    tx.Respond(res)
})

Checkout /example/proxysip for more how to build simple stateful proxy.

Server Transaction

Server transaction is passed on handler

// Incoming request
srv.OnInvite(func(req *sip.Request, tx sip.ServerTransaction) {
    res := sip.NewResponseFromRequest(req, code, reason, body)
    // Send response
    tx.Respond(res)

    select {
        case m := <-tx.Acks(): // Handle ACK . ACKs on 2xx are send as different request
        case m := <-tx.Cancels(): // Handle Cancel 
        case <-tx.Done():
            // Signal transaction is done. 
            // Check any errors with tx.Err() to have more info why terminated
            return
    }

    // terminating handler terminates Server transaction automaticaly
})

Server stateless response
srv := sipgo.NewServer()
...
func ackHandler(req *sip.Request, tx sip.ServerTransaction) {
    res := sip.NewResponseFromRequest(req, code, reason, body)
    srv.WriteResponse(res)
}
srv.OnACK(ackHandler)
Client Transaction

Using client handle allows easy creating and sending request. All you need is this.

req := sip.NewRequest(sip.INVITE, recipient)
tx, err := client.TransactionRequest(req, opts...) // Send request and get client transaction handle

Unless you customize transaction request with opts by default client.TransactionRequest will build all other headers needed to pass correct sip request.

Here is full example:

client, _ := sipgo.NewClient(ua) // Creating client handle

// Request is either from server request handler or created
req.SetDestination("10.1.2.3") // Change sip.Request destination
tx, err := client.TransactionRequest(req) // Send request and get client transaction handle

defer tx.Terminate() // Client Transaction must be terminated for cleanup
...

select {
    case res := <-tx.Responses():
    // Handle responses
    case <-tx.Done():
    // Wait for termination
    return
}

NOTE: If you are building UA that also has server handle on UDP. UDP listener will be reused to also send packets.

Client stateless request
client, _ := sipgo.NewClient(ua) // Creating client handle
req := sip.NewRequest(method, &recipment)
// Send request and forget
client.WriteRequest(req)
Dialogs (experiment)

NOTE: This may be redesigned to have more control

ServerDialog is extended type of Server with Dialog support. For now this is in experiment.

srv, err := sipgo.NewServerDialog(ua)
...
srv.OnDialog(func(d sip.Dialog) {
    switch d.State {
	case sip.DialogStateEstablished:
		// 200 response
	case sip.DialogStateConfirmed:
		// ACK send
	case sip.DialogStateEnded:
		// BYE send
	}
})

ClientDialog TODO...

SIP Debug

You can have full SIP messages dumped from transport into Debug level message.

Example:

transport.SIPDebug = true
Feb 24 23:32:26.493191 DBG UDP read 10.10.0.10:5060 <- 10.10.0.100:5060:
SIP/2.0 100 Trying
Via: SIP/2.0/UDP 10.10.0.10:5060;rport=5060;received=10.10.0.10;branch=z9hG4bK.G3nCwpXAKJQ0T2oZUII70wuQx9NeXc61;alias
Via: SIP/2.0/UDP 10.10.1.1:5060;branch=z9hG4bK-1-1-0
Record-Route: <sip:10.10.0.10;transport=udp;lr>
Call-ID: 1-1@10.10.1.1
From: "sipp" <sip:sipp@10.10.1.1>;tag=1SIPpTag001
To: "uac" <sip:uac@10.10.0.10>
CSeq: 1 INVITE
Server: Asterisk PBX 18.16.0
Content-Length:  0

Documentation

More on documentation you can find on Go doc

Supported protocols

  • UDP
  • TCP
  • TLS
  • WS
  • WSS

Tests

Library will be covered with more tests. Focus is more on benchmarking currently.

go test ./...  

Credits

This project was based on gosip by project by @ghetovoice, but started as new project to achieve best/better performance and to improve API. This unfortunately required many design changes, therefore this libraries are not compatible.

Support

If you find this project interesting for bigger support or contributing, you can contact me on mail

For bugs features pls create issue.

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func ClientRequestAddRecordRoute

func ClientRequestAddRecordRoute(c *Client, r *sip.Request) error

ClientRequestAddRecordRoute is option for adding record route header Based on proxy setup https://www.rfc-editor.org/rfc/rfc3261#section-16

func ClientRequestAddVia

func ClientRequestAddVia(c *Client, r *sip.Request) error

ClientRequestAddVia is option for adding via header Based on proxy setup https://www.rfc-editor.org/rfc/rfc3261.html#section-16.6

func ClientRequestDecreaseMaxForward

func ClientRequestDecreaseMaxForward(c *Client, r *sip.Request) error

Based on proxy setup https://www.rfc-editor.org/rfc/rfc3261#section-16 ClientRequestDecreaseMaxForward should be used when forwarding request. It decreases max forward in case of 0 it returnes error

func ClientResponseRemoveVia

func ClientResponseRemoveVia(c *Client, r *sip.Response)

ClientResponseRemoveVia is needed when handling client transaction response, where previously used in TransactionRequest with ClientRequestAddVia

func GenerateTLSConfig

func GenerateTLSConfig(certFile string, keyFile string, rootPems []byte) (*tls.Config, error)

GenerateTLSConfig creates basic tls.Config that you can pass for ServerTLS It needs rootPems for client side

func Init

func Init()

Types

type Client

type Client struct {
	*UserAgent
	// contains filtered or unexported fields
}

func NewClient

func NewClient(ua *UserAgent, options ...ClientOption) (*Client, error)

NewClient creates client handle for user agent

func (*Client) GetHostname

func (c *Client) GetHostname() string

func (*Client) TransactionRequest

func (c *Client) TransactionRequest(req *sip.Request, options ...ClientRequestOption) (sip.ClientTransaction, error)

TransactionRequest uses transaction layer to send request and returns transaction By default the following header fields will be added if not exist: To, From, CSeq, Call-ID, Max-Forwards, Via Passing custom options will override this behavior. This is useful when using client handle in proxy building

NOTE: request will not be cloned and header adding will be present after this action

func (*Client) WriteRequest

func (c *Client) WriteRequest(req *sip.Request, options ...ClientRequestOption) error

WriteRequest sends request directly to transport layer Behavior is same as TransactionRequest Non-transaction ACK request should be passed like this

type ClientOption

type ClientOption func(c *Client) error

func WithClientHostname

func WithClientHostname(hostname string) ClientOption

WithClientHost allows setting default route host default it will be used user agent IP

func WithClientLogger

func WithClientLogger(logger zerolog.Logger) ClientOption

WithClientLogger allows customizing client logger

func WithClientPort

func WithClientPort(port int) ClientOption

WithClientPort allows setting default route port

type ClientRequestOption

type ClientRequestOption func(c *Client, req *sip.Request) error

type RequestHandler

type RequestHandler func(req *sip.Request, tx sip.ServerTransaction)

RequestHandler is a callback that will be called on the incoming request

type Server

type Server struct {
	*UserAgent
	// contains filtered or unexported fields
}

Server is a SIP server

func NewServer

func NewServer(ua *UserAgent, options ...ServerOption) (*Server, error)

NewServer creates new instance of SIP server handle. Allows creating server transaction handlers It uses User Agent transport and transaction layer

func (*Server) Close

func (srv *Server) Close()

Shutdown gracefully shutdowns SIP server

func (*Server) ListenAndServe

func (srv *Server) ListenAndServe(ctx context.Context, network string, addr string) error

Serve will fire all listeners. Ctx allows canceling

func (*Server) ListenAndServeTLS

func (srv *Server) ListenAndServeTLS(ctx context.Context, network string, addr string, conf *tls.Config) error

Serve will fire all listeners that are secured. Ctx allows canceling

func (*Server) OnAck

func (srv *Server) OnAck(handler RequestHandler)

OnAck registers Ack request handler

func (*Server) OnBye

func (srv *Server) OnBye(handler RequestHandler)

OnBye registers Bye request handler

func (*Server) OnCancel

func (srv *Server) OnCancel(handler RequestHandler)

OnCancel registers Cancel request handler

func (*Server) OnInfo

func (srv *Server) OnInfo(handler RequestHandler)

OnInfo registers Info request handler

func (*Server) OnInvite

func (srv *Server) OnInvite(handler RequestHandler)

OnInvite registers Invite request handler

func (*Server) OnMessage

func (srv *Server) OnMessage(handler RequestHandler)

OnMessage registers Message request handler

func (*Server) OnNoRoute

func (srv *Server) OnNoRoute(handler RequestHandler)

OnNoRoute registers no route handler default is handling is responding 405 Method Not allowed This allows customizing your response for any non handled message

Example
// Creating no route handler allows you to respond for non handled (non routed) requests
ua, _ := NewUA()
srv, _ := NewServer(ua)

srv.OnNoRoute(func(req *sip.Request, tx sip.ServerTransaction) {
	res := sip.NewResponseFromRequest(req, 405, "Method Not Allowed", nil)
	// Send response directly and let transaction terminate
	if err := srv.WriteResponse(res); err != nil {
		srv.log.Error().Err(err).Msg("respond '405 Method Not Allowed' failed")
	}
})

func (*Server) OnNotify

func (srv *Server) OnNotify(handler RequestHandler)

OnNotify registers Notify request handler

func (*Server) OnOptions

func (srv *Server) OnOptions(handler RequestHandler)

OnOptions registers Options request handler

func (*Server) OnPrack

func (srv *Server) OnPrack(handler RequestHandler)

OnPrack registers Prack request handler

func (*Server) OnPublish

func (srv *Server) OnPublish(handler RequestHandler)

OnPublish registers Publish request handler

func (*Server) OnRefer

func (srv *Server) OnRefer(handler RequestHandler)

OnRefer registers Refer request handler

func (*Server) OnRegister

func (srv *Server) OnRegister(handler RequestHandler)

OnRegister registers Register request handler

func (*Server) OnRequest

func (srv *Server) OnRequest(method sip.RequestMethod, handler RequestHandler)

OnRequest registers new request callback. Can be used as generic way to add handler

func (*Server) OnSubscribe

func (srv *Server) OnSubscribe(handler RequestHandler)

OnSubscribe registers Subscribe request handler

func (*Server) OnUpdate

func (srv *Server) OnUpdate(handler RequestHandler)

OnUpdate registers Update request handler

func (*Server) ServeRequest

func (srv *Server) ServeRequest(f func(r *sip.Request))

ServeRequest can be used as middleware for preprocessing message

func (*Server) ServeTCP

func (srv *Server) ServeTCP(l net.Listener) error

ServeTCP starts serving request on TCP type listener.

func (*Server) ServeTLS

func (srv *Server) ServeTLS(l net.Listener, conf *tls.Config) error

ServeTLS starts serving request on TLS type listener.

func (*Server) ServeUDP

func (srv *Server) ServeUDP(l net.PacketConn) error

ServeUDP starts serving request on UDP type listener.

func (*Server) TransportLayer

func (srv *Server) TransportLayer() *transport.Layer

Transport is function to get transport layer of server Can be used for modifying

func (*Server) WriteResponse

func (srv *Server) WriteResponse(r *sip.Response) error

WriteResponse will proxy message to transport layer. Use it in stateless mode

type ServerDialog

type ServerDialog struct {
	Server
	// contains filtered or unexported fields
}

ServerDialog is extension of Server to support Dialog handling

func NewServerDialog

func NewServerDialog(ua *UserAgent, options ...ServerOption) (*ServerDialog, error)

func (*ServerDialog) OnDialog

func (s *ServerDialog) OnDialog(f func(d sip.Dialog))

OnDialog allows monitoring new dialogs

func (*ServerDialog) OnDialogChan

func (s *ServerDialog) OnDialogChan(ch chan sip.Dialog)

OnDialogChan same as onDialog but we channel instead callback func

type ServerOption

type ServerOption func(s *Server) error

func WithServerLogger

func WithServerLogger(logger zerolog.Logger) ServerOption

WithServerLogger allows customizing server logger

type UserAgent

type UserAgent struct {
	// contains filtered or unexported fields
}

func NewUA

func NewUA(options ...UserAgentOption) (*UserAgent, error)

NewUA creates User Agent User Agent will create transport and transaction layer Check options for customizing user agent

func (*UserAgent) GetIP

func (ua *UserAgent) GetIP() net.IP

func (*UserAgent) TransportLayer

func (ua *UserAgent) TransportLayer() *transport.Layer

type UserAgentOption

type UserAgentOption func(s *UserAgent) error

func WithUserAgent

func WithUserAgent(ua string) UserAgentOption

WithUserAgent changes user agent name Default: sipgo

func WithUserAgentDNSResolver

func WithUserAgentDNSResolver(r *net.Resolver) UserAgentOption

WithUserAgentDNSResolver allows customizing default DNS resolver for transport layer

func WithUserAgentIP

func WithUserAgentIP(ip net.IP) UserAgentOption

WithUserAgentIP sets local IP that will be used in building request If not used IP will be resolved

Directories

Path Synopsis
example
Originally forked from https://github.com/ghettovoice/gosip by @ghetovoice
Originally forked from https://github.com/ghettovoice/gosip by @ghetovoice

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL