sipgo

package module
v0.27.1 Latest Latest
Warning

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

Go to latest
Published: Dec 22, 2024 License: BSD-2-Clause Imports: 17 Imported by: 26

README

SIPGO

Go Report Card Used By Coverage License GitHub go.mod Go version

SIPGO is library for writing fast SIP services in GO language.
It comes with SIP stack (RFC 3261|RFC3581|RFC6026 optimized for fast parsing.


NOTE: LIBRARY IS IN PROCESS GETTING TO 1.0. THIS MAY TAKE TIME UNTIL WE CLOSE ALL ISSUES. PLEASE OPEN ISSUES FOR DISCUSSION FIRST INSTEAD PULL REQUESTS. OTHER NOTES:

  • dialog managment may be refactored or reduced only to keep some basic functionality handling dialogs per RFC. Rest is moved to diago project
  • only small optimizations/refactoring is considered to happen.
  • if something is missing before 1.0 and it is good to have, it will be moved to sipgox package.

Libs on top of sipgo:

Fetch lib with:

go get github.com/emiago/sipgo

If you like/use project currently and looking for support/sponsoring checkout Support section

You can follow on X/Twitter for more updates.

More on documentation you can find on Go doc

Supported protocols

  • UDP
  • TCP
  • TLS
  • WS
  • WSS

Examples

Also thanks to pion project sharing this example of using SIPgo with webrtc:

Tools developed:

  • CLI softphone for easy testing gophone
  • Simple proxy where NAT is problem psip
  • ... your tool can be here

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

Usage

Lib allows you to write easily sip servers, clients, stateful proxies, registrars 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 for ua
client, _ := sipgo.NewClient(ua) // Creating client handle for ua
srv.OnInvite(inviteHandler)
srv.OnAck(ackHandler)
srv.OnBye(byeHandler)

// For registrars
// srv.OnRegister(registerHandler)
ctx, _ := signal.NotifyContext(ctx, os.Interrupt)
go srv.ListenAndServe(ctx, "udp", "127.0.0.1:5060")
go srv.ListenAndServe(ctx, "tcp", "127.0.0.1:5061")
go srv.ListenAndServe(ctx, "ws", "127.0.0.1:5080")
<-ctx.Done()

TLS transports

// TLS
conf :=  sipgo.GenerateTLSConfig(certFile, keyFile, rootPems)
srv.ListenAndServeTLS(ctx, "tcp", "127.0.0.1:5061", conf)
srv.ListenAndServeTLS(ctx, "ws", "127.0.0.1:5081", conf)

UAC first

If you are acting as client first, you can say to client which host:port to use, and this connection will be reused until closing UA. Any request received can be still processed with server handle.

ua, _ := sipgo.NewUA() // Build user agent
defer ua.Close()

client, _ := sipgo.NewClient(ua, sipgo.WithClientHostname("127.0.0.1"), sipgo.WithClientPort(5060))
server, _ := sipgo.NewServer(ua) 
srv.OnBye(func(req *sip.Request, tx sip.ServerTransaction)) {
    // This will be received on 127.0.0.1:5060
}

tx, err := client.TransactionRequest(ctx, sip.NewRequest(sip.INVITE, recipient)) 

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 for response . ACKs on 2xx are send as different request
        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. 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:

ctx := context.Background()
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(ctx, 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
}

Client Do request

Unless you need more control over Client Transaction you can simply go with client Do request and wait final response.

req := sip.NewRequest(sip.INVITE, sip.Uri{User:"bob", Host: "example.com"})
res, err := client.Do(req)

Client stateless request

client, _ := sipgo.NewClient(ua) // Creating client handle
req := sip.NewRequest(method, recipient)
// Send request and forget
client.WriteRequest(req)

Dialog handling

DialogUA is helper struct to create Dialog. Dialog can be as server or as client created. Later on this provides you RFC way of sending request within dialog Do or TransactionRequest functions.

For basic usage DialogClientCache and DialogServerCache are created to be part of library to manage and cache dialog accross multiple request. They are seperated based on your request context, but they act more like peer.


NOTE: It is recomended that you build your OWN Dialog Server/Client Cache mechanism for dialogs.


For basic control some handling request wrappers like Ack, Bye, ReadAck, ReadBye is provided. Sending any other request should be done with Do or receiving can be validated with ReadRequest

UAC:

ua, _ := sipgo.NewUA() // Build user agent
srv, _ := sipgo.NewServer(ua) // Creating server handle
client, _ := sipgo.NewClient(ua) // Creating client handle

contactHDR := sip.ContactHeader{
    Address: sip.Uri{User: "test", Host: "127.0.0.200", Port: 5088},
}
dialogCli := sipgo.NewDialogClientCache(client, contactHDR)

// Attach Bye handling for dialog
srv.OnBye(func(req *sip.Request, tx sip.ServerTransaction) {
    err := dialogCli.ReadBye(req, tx)
    //handle error
})

// Create dialog session
dialog, err := dialogCli.Invite(ctx, recipientURI, nil)
defer dialog.Close() // Cleans up from dialog pool
// Wait for answer
err = dialog.WaitAnswer(ctx, AnswerOptions{})
// Check dialog response dialog.InviteResponse (SDP) and return ACK
err = dialog.Ack(ctx)
// Send BYE to terminate call
err = dialog.Bye(ctx)

UAS:

ua, _ := sipgo.NewUA() // Build user agent
srv, _ := sipgo.NewServer(ua) // Creating server handle
client, _ := sipgo.NewClient(ua) // Creating client handle

uasContact := sip.ContactHeader{
    Address: sip.Uri{User: "test", Host: "127.0.0.200", Port: 5099},
}
dialogSrv := sipgo.NewDialogServerCache(client, uasContact)

srv.OnInvite(func(req *sip.Request, tx sip.ServerTransaction) {
    dlg, err := dialogSrv.ReadInvite(req, tx)
    if err != nil {
        return err
    }
    defer dlg.Close() // Close for cleanup from cache
    // handle error
    dlg.Respond(sip.StatusTrying, "Trying", nil)
    dlg.Respond(sip.StatusOK, "OK", nil)
    
    // Instead Done also dlg.State() can be used for granular state checking
    <-dlg.Context().Done()
})

srv.OnAck(func(req *sip.Request, tx sip.ServerTransaction) {
    dialogSrv.ReadAck(req, tx)
})

srv.OnBye(func(req *sip.Request, tx sip.ServerTransaction) {
    dialogSrv.ReadBye(req, tx)
})

Dialog Do/Transaction request

For any other request within dialog you should use dialog.Do to send request. Requests withing dialog need more checks to pass and therefore this API helps to keep requests within dialog session.

req := sip.NewRequest(sip.INFO, recipient)
res, err := dialog.Do(ctx, req)

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:

ua, _ := sipgo.NewUA() // Build user agent
srv, _ := sipgo.NewServer(ua) // Creating server handle
client, _ := sipgo.NewClient(ua) // Creating client handle

srv.OnInvite(func(req *sip.Request, tx sip.ServerTransaction) {
    ctx := context.Background()
    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(ctx, req, sipgo.ClientRequestAddVia, sipgo.ClientRequestAddRecordRoute)
    // Send back response
    res := <-cltx.Responses()
    tx.Respond(res)
})

SIP Debug

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

Example:

sip.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

Support

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

For bugs features pls create issue.

Trusted By

babelforce      avero

If you are using in company, your logo can be here.

Extra

E2E/integration testing

If you are interested using lib for your testing services then checkout article on how easy you can make calls and other

Tests

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

go test ./...  

Credits

This project was influenced by gosip, 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.

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrDialogOutsideDialog   = errors.New("Call/Transaction Outside Dialog")
	ErrDialogDoesNotExists   = errors.New("Call/Transaction Does Not Exist")
	ErrDialogInviteNoContact = errors.New("No Contact header")
	ErrDialogCanceled        = errors.New("Dialog canceled")
	ErrDialogInvalidCseq     = errors.New("Invalid CSEQ number")
)
View Source
var (
	// Used only for testing, better way is to pass listener with Serve{Transport}
	ListenReadyCtxKey = "ListenReadyCtxKey"
)
View Source
var (
	WaitAnswerForceCancelErr = errors.New("Context cancel forced")
)

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 ClientRequestBuild added in v0.16.0

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

ClientRequestBuild will build missing fields in request This is by default but can be used to combine with other ClientRequestOptions

func ClientRequestDecreaseMaxForward added in v0.7.0

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 GenerateTLSConfig added in v0.7.0

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 added in v0.7.2

func Init()

Types

type AnswerOptions added in v0.15.1

type AnswerOptions struct {
	OnResponse func(res *sip.Response) error

	// For digest authentication
	Username string
	Password string
}

type Client

type Client struct {
	*UserAgent

	// TxRequester allows you to use your transaction requester instead default from transaction layer
	// Useful only for testing
	//
	// Experimental
	TxRequester ClientTransactionRequester
	// contains filtered or unexported fields
}

func NewClient

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

NewClient creates client handle for user agent

func (*Client) Close added in v0.13.0

func (c *Client) Close() error

Close client handle. UserAgent must be closed for full transaction and transport layer closing.

func (*Client) Do added in v0.22.0

func (c *Client) Do(ctx context.Context, req *sip.Request) (*sip.Response, error)

Do request is HTTP client like Do request/response. It returns on final response. NOTE: Canceling ctx WILL not send Cancel Request which is needed for INVITE. Use dialog API for dealing with dialogs For more lower API use TransactionRequest directly

func (*Client) DoDigestAuth added in v0.19.0

func (c *Client) DoDigestAuth(ctx context.Context, req *sip.Request, res *sip.Response, auth DigestAuth) (sip.ClientTransaction, error)

DoDigestAuth will apply digest authentication if initial request is chalenged by 401 or 407. It returns new transaction that is created for this request

func (*Client) Hostname added in v0.25.0

func (c *Client) Hostname() string

Hostname returns default hostname or what is set WithHostname option

func (*Client) TransactionRequest

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

TransactionRequest uses transaction layer to send request and returns transaction For more correct behavior use client.Do instead which acts same like HTTP req/response

By default request will not be cloned and it will populate request with missing headers unless options are used In most cases you want this as you will retry with additional headers

Following header fields will be added if not exist to have correct SIP request: To, From, CSeq, Call-ID, Max-Forwards, Via Passing options will override this behavior, that is, it is expected that your request is already prebuild This is mostly the case when creating proxy

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 WithClientAddr added in v0.12.0

func WithClientAddr(addr string) ClientOption

WithClientAddr is merge of WithClientHostname and WithClientPort addr is format <host>:<port>

func WithClientHostname added in v0.11.0

func WithClientHostname(hostname string) ClientOption

WithClientHost allows setting default route host or IP on Via in case of IP it will enforce transport layer to create/reuse connection with this IP This is useful when you need to act as client first and avoid creating server handle listeners. NOTE: From header hostname is WithUserAgentHostname option on UA or modify request manually

func WithClientLogger added in v0.7.2

func WithClientLogger(logger zerolog.Logger) ClientOption

WithClientLogger allows customizing client logger

func WithClientNAT added in v0.16.0

func WithClientNAT() ClientOption

WithClientNAT makes client aware that is behind NAT.

func WithClientPort added in v0.11.0

func WithClientPort(port int) ClientOption

WithClientPort allows setting default route Via port it will enforce transport layer to create connection with this port if does NOT exist transport layer will choose existing connection by default unless TransportLayer.ConnectionReuse is set to false default: ephemeral port

type ClientRequestOption

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

type ClientTransactionRequester added in v0.24.1

type ClientTransactionRequester interface {
	Request(ctx context.Context, req *sip.Request) (sip.ClientTransaction, error)
}

type Dialog added in v0.15.0

type Dialog struct {
	ID string

	// InviteRequest is set when dialog is created. It is not thread safe!
	// Use it only as read only and use methods to change headers
	InviteRequest *sip.Request

	// InviteResponse is last response received or sent. It is not thread safe!
	// Use it only as read only and do not change values
	InviteResponse *sip.Response
	// contains filtered or unexported fields
}

func (*Dialog) CSEQ added in v0.23.0

func (d *Dialog) CSEQ() uint32

func (*Dialog) Context added in v0.21.0

func (d *Dialog) Context() context.Context

func (*Dialog) Init added in v0.23.0

func (d *Dialog) Init()

Init setups dialog state

func (*Dialog) InitWithState added in v0.23.0

func (d *Dialog) InitWithState(s sip.DialogState)

func (*Dialog) LoadState added in v0.23.0

func (d *Dialog) LoadState() sip.DialogState

func (*Dialog) OnState added in v0.24.0

func (d *Dialog) OnState(f DialogStateFn)

func (*Dialog) StateRead added in v0.23.0

func (d *Dialog) StateRead() <-chan sip.DialogState

type DialogClientCache added in v0.24.0

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

func NewDialogClientCache added in v0.24.0

func NewDialogClientCache(client *Client, contactHDR sip.ContactHeader) *DialogClientCache

NewDialogClientCache provides simple cache layer for managing UAC dialogs. It is generally recomended to build your own cache layer Contact hdr is default to be provided for correct invite. It is not used if you provided hdr as part of request, but contact hdr must be present so this makes sure correct dialog is established. In case handling different transports you should have multiple instances per transport

func (*DialogClientCache) Invite added in v0.24.0

func (c *DialogClientCache) Invite(ctx context.Context, recipient sip.Uri, body []byte, headers ...sip.Header) (*DialogClientSession, error)

Invite sends INVITE request and creates early dialog session. This is actually not yet dialog (ID is empty) You need to call WaitAnswer after for establishing dialog For passing custom Invite request use WriteInvite

func (*DialogClientCache) MatchRequestDialog added in v0.24.0

func (s *DialogClientCache) MatchRequestDialog(req *sip.Request) (*DialogClientSession, error)

func (*DialogClientCache) ReadBye added in v0.24.0

func (c *DialogClientCache) ReadBye(req *sip.Request, tx sip.ServerTransaction) error

func (*DialogClientCache) WriteInvite added in v0.24.0

func (c *DialogClientCache) WriteInvite(ctx context.Context, inviteRequest *sip.Request) (*DialogClientSession, error)

type DialogClientSession added in v0.15.0

type DialogClientSession struct {
	Dialog
	// contains filtered or unexported fields
}

func (*DialogClientSession) Ack added in v0.15.0

Ack sends ack. Use WriteAck for more customizing

func (*DialogClientSession) Bye added in v0.15.0

Bye sends bye and terminates session. Use WriteBye if you want to customize bye request

func (*DialogClientSession) Close added in v0.15.1

func (s *DialogClientSession) Close() error

Close must be always called in order to cleanup some internal resources Consider that this will not send BYE or CANCEL or change dialog state

func (*DialogClientSession) Do added in v0.23.0

Do sends request and waits final response using Dialog rules For more control use TransactionRequest

NOTE: It does not provide INVITE CANCEL as it could be REINVITE Use WaitAnswer when creating initial INVITE to have CANCEL sending.

func (*DialogClientSession) ReadBye added in v0.23.0

func (*DialogClientSession) ReadRequest added in v0.23.0

func (s *DialogClientSession) ReadRequest(req *sip.Request, tx sip.ServerTransaction) error

ReadRequest is generic func to validate new request in dialog and update seq. Use it if there are no predefined

func (*DialogClientSession) TransactionRequest added in v0.21.0

func (s *DialogClientSession) TransactionRequest(ctx context.Context, req *sip.Request) (sip.ClientTransaction, error)

TransactionRequest is doing client DIALOG request based on RFC https://www.rfc-editor.org/rfc/rfc3261#section-12.2.1 This ensures that you have proper request done within dialog. You should avoid setting any Dialog header (cseq, from, to, callid)

func (*DialogClientSession) WaitAnswer added in v0.15.1

func (s *DialogClientSession) WaitAnswer(ctx context.Context, opts AnswerOptions) error

WaitAnswer waits for success response or returns ErrDialogResponse in case non 2xx Canceling context while waiting 2xx will send Cancel request. It will block until 1xx provisional is not received If Canceling succesfull context.Canceled error is returned Returns errors: - ErrDialogResponse in case non 2xx response - any internal in case waiting answer failed for different reasons

func (*DialogClientSession) WriteAck added in v0.15.0

func (s *DialogClientSession) WriteAck(ctx context.Context, ack *sip.Request) error

func (*DialogClientSession) WriteBye added in v0.15.0

func (s *DialogClientSession) WriteBye(ctx context.Context, bye *sip.Request) error

func (*DialogClientSession) WriteRequest added in v0.21.0

func (s *DialogClientSession) WriteRequest(req *sip.Request) error

type DialogServerCache added in v0.24.0

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

DialogServerCache serves as quick way to start building dialog server It is not optimized version and it is recomended that you build own dialog caching

func NewDialogServerCache added in v0.24.0

func NewDialogServerCache(client *Client, contactHDR sip.ContactHeader) *DialogServerCache

NewDialogServerCache provides simple cache layer for managing UAS dialog Contact hdr is default that is provided for responses. Client is needed for termination dialog session In case handling different transports you should have multiple instances per transport

Using DialogUA is now better way for genereting dialogs without caching and giving you as caller whole control of dialog

func (*DialogServerCache) MatchDialogRequest added in v0.24.0

func (s *DialogServerCache) MatchDialogRequest(req *sip.Request) (*DialogServerSession, error)

func (*DialogServerCache) ReadAck added in v0.24.0

func (s *DialogServerCache) ReadAck(req *sip.Request, tx sip.ServerTransaction) error

ReadAck should read from your OnAck handler

func (*DialogServerCache) ReadBye added in v0.24.0

func (s *DialogServerCache) ReadBye(req *sip.Request, tx sip.ServerTransaction) error

ReadBye should read from your OnBye handler. Returns error if it fails

func (*DialogServerCache) ReadInvite added in v0.24.0

ReadInvite should read from your OnInvite handler for which it creates dialog context You need to use DialogServerSession for all further responses Do not forget to add ReadAck and ReadBye for confirming dialog and terminating

type DialogServerSession added in v0.15.0

type DialogServerSession struct {
	Dialog
	// contains filtered or unexported fields
}

func (*DialogServerSession) Bye added in v0.15.0

func (*DialogServerSession) Close added in v0.15.1

func (s *DialogServerSession) Close() error

Close is always good to call for cleanup or terminating dialog state

func (*DialogServerSession) Do added in v0.23.0

func (*DialogServerSession) ReadAck added in v0.23.0

ReadAck changes dialog state to confiremed

func (*DialogServerSession) ReadBye added in v0.23.0

func (*DialogServerSession) ReadRequest added in v0.23.0

func (s *DialogServerSession) ReadRequest(req *sip.Request, tx sip.ServerTransaction) error

ReadRequest is generic func to validate new request in dialog and update seq. Use it if there are no predefined

func (*DialogServerSession) Respond added in v0.15.0

func (s *DialogServerSession) Respond(statusCode sip.StatusCode, reason string, body []byte, headers ...sip.Header) error

Respond should be called for Invite request, you may want to call this multiple times like 100 Progress or 180 Ringing 2xx for creating dialog or other code in case failure

In case Cancel request received: ErrDialogCanceled is responded

func (*DialogServerSession) RespondSDP added in v0.21.0

func (s *DialogServerSession) RespondSDP(sdp []byte) error

RespondSDP is just wrapper to call 200 with SDP. It is better to use this when answering as it provide correct headers

func (*DialogServerSession) TransactionRequest added in v0.21.0

func (s *DialogServerSession) TransactionRequest(ctx context.Context, req *sip.Request) (sip.ClientTransaction, error)

TransactionRequest is doing client DIALOG request based on RFC https://www.rfc-editor.org/rfc/rfc3261#section-12.2.1 This ensures that you have proper request done within dialog

func (*DialogServerSession) WriteBye added in v0.24.1

func (s *DialogServerSession) WriteBye(ctx context.Context, bye *sip.Request) error

func (*DialogServerSession) WriteRequest added in v0.21.0

func (s *DialogServerSession) WriteRequest(req *sip.Request) error

func (*DialogServerSession) WriteResponse added in v0.15.0

func (s *DialogServerSession) WriteResponse(res *sip.Response) error

WriteResponse allows passing you custom response

type DialogStateFn added in v0.24.0

type DialogStateFn func(s sip.DialogState)

type DialogUA added in v0.23.0

type DialogUA struct {
	// Client (required) is used to build and send subsequent request (CANCEL, BYE)
	Client *Client
	// ContactHDR (required) is used as default one to build request/response.
	// You can pass custom on each request, but in dialog it is required to be present
	ContactHDR sip.ContactHeader

	RewriteContact bool
}

DialogUA defines UserAgent that will be used in controling your dialog. It needs client handle for cancelation or sending more subsequent request during dialog

func (*DialogUA) Invite added in v0.23.0

func (ua *DialogUA) Invite(ctx context.Context, recipient sip.Uri, body []byte, headers ...sip.Header) (*DialogClientSession, error)

func (*DialogUA) ReadInvite added in v0.23.0

func (c *DialogUA) ReadInvite(inviteReq *sip.Request, tx sip.ServerTransaction) (*DialogServerSession, error)

func (*DialogUA) WriteInvite added in v0.23.0

func (c *DialogUA) WriteInvite(ctx context.Context, inviteReq *sip.Request, options ...ClientRequestOption) (*DialogClientSession, error)

type DigestAuth added in v0.19.0

type DigestAuth struct {
	Username string
	Password string
}

type ErrDialogResponse added in v0.15.0

type ErrDialogResponse struct {
	Res *sip.Response
}

func (ErrDialogResponse) Error added in v0.15.0

func (e ErrDialogResponse) Error() string

type ListenReadyCtxValue added in v0.14.0

type ListenReadyCtxValue chan struct{}

type ListenReadyFuncCtxValue added in v0.26.0

type ListenReadyFuncCtxValue func(network string, addr string)

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 added in v0.8.0

func (srv *Server) Close() error

Close server handle. UserAgent must be closed for full transaction and transport layer closing.

func (*Server) ListenAndServe added in v0.7.0

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

Serve will fire all listeners Network supported: udp, tcp, ws

func (*Server) ListenAndServeTLS added in v0.7.0

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

Serve will fire all listeners that are secured. Network supported: tls, wss, tcp, tcp4, tcp6, ws, ws4, ws6

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 added in v0.9.0

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")
	}
})
Output:

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) RegisteredMethods added in v0.12.1

func (srv *Server) RegisteredMethods() []string

RegisteredMethods returns list of registered handlers. Can be used for constructing Allow header

func (*Server) ServeRequest

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

ServeRequest can be used as middleware for preprocessing message

func (*Server) ServeTCP added in v0.10.0

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

ServeTCP starts serving request on TCP type listener.

func (*Server) ServeTLS added in v0.10.0

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

ServeTLS starts serving request on TLS type listener.

func (*Server) ServeUDP added in v0.10.0

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

ServeUDP starts serving request on UDP type listener.

func (*Server) ServeWS added in v0.12.0

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

ServeWS starts serving request on WS type listener.

func (*Server) ServeWSS added in v0.12.0

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

ServeWS starts serving request on WS type listener.

func (*Server) TransportLayer

func (srv *Server) TransportLayer() *sip.TransportLayer

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 ServerOption

type ServerOption func(s *Server) error

func WithServerLogger added in v0.7.2

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) Close added in v0.13.1

func (ua *UserAgent) Close() error

func (*UserAgent) Hostname added in v0.25.0

func (ua *UserAgent) Hostname() string

func (*UserAgent) Name added in v0.14.0

func (ua *UserAgent) Name() string

func (*UserAgent) TransactionLayer added in v0.19.0

func (ua *UserAgent) TransactionLayer() *sip.TransactionLayer

func (*UserAgent) TransportLayer added in v0.10.0

func (ua *UserAgent) TransportLayer() *sip.TransportLayer

type UserAgentOption

type UserAgentOption func(s *UserAgent) error

func WithUserAgenTLSConfig added in v0.12.0

func WithUserAgenTLSConfig(c *tls.Config) UserAgentOption

WithUserAgenTLSConfig allows customizing default tls config.

func WithUserAgent

func WithUserAgent(ua string) UserAgentOption

WithUserAgent changes user agent name Default: sipgo

func WithUserAgentDNSResolver added in v0.7.2

func WithUserAgentDNSResolver(r *net.Resolver) UserAgentOption

WithUserAgentDNSResolver allows customizing default DNS resolver for transport layer

func WithUserAgentHostname added in v0.17.0

func WithUserAgentHostname(hostname string) UserAgentOption

WithUserAgentHostname represents FQDN of user that can be presented in From header

func WithUserAgentParser added in v0.16.1

func WithUserAgentParser(p *sip.Parser) UserAgentOption

WithUserAgentParser allows removing default behavior of parser You can define and remove default headers parser map and pass here. Only use if your benchmarks are better than default

Directories

Path Synopsis
example
proxysip Module
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