Categorygithub.com/emiago/sipgo
modulepackage
0.24.1
Repository: https://github.com/emiago/sipgo.git
Documentation: pkg.go.dev

# 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

Used By

babelforce

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

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)
})

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: [email protected]
From: "sipp" <sip:[email protected]>;tag=1SIPpTag001
To: "uac" <sip:[email protected]>
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.

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.

# Packages

No description provided by the author
No description provided by the author
Originally forked from https://github.com/ghettovoice/gosip by @ghetovoice.
No description provided by the author

# Functions

ClientRequestAddRecordRoute is option for adding record route header Based on proxy setup https://www.rfc-editor.org/rfc/rfc3261#section-16.
ClientRequestAddVia is option for adding via header Based on proxy setup https://www.rfc-editor.org/rfc/rfc3261.html#section-16.6.
ClientRequestBuild will build missing fields in request This is by default but can be used to combine with other ClientRequestOptions.
Based on proxy setup https://www.rfc-editor.org/rfc/rfc3261#section-16 ClientRequestDecreaseMaxForward should be used when forwarding request.
GenerateTLSConfig creates basic tls.Config that you can pass for ServerTLS It needs rootPems for client side.
No description provided by the author
NewClient creates client handle for user agent.
NewDialogClientCache provides simple cache layer for managing UAC dialogs.
NewDialogServerCache provides simple cache layer for managing UAS dialog Contact hdr is default that is provided for responses.
NewServer creates new instance of SIP server handle.
NewUA creates User Agent User Agent will create transport and transaction layer Check options for customizing user agent.
WithClientAddr is merge of WithClientHostname and WithClientPort addr is format <host>:<port>.
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.
WithClientLogger allows customizing client logger.
WithClientNAT makes client aware that is behind NAT.
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.
WithServerLogger allows customizing server logger.
WithUserAgent changes user agent name Default: sipgo.
WithUserAgentDNSResolver allows customizing default DNS resolver for transport layer.
WithUserAgentHostname represents FQDN of user that can be presented in From header.
WithUserAgenTLSConfig allows customizing default tls config.
WithUserAgentParser allows removing default behavior of parser You can define and remove default headers parser map and pass here.

# Variables

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
Used only for testing, better way is to pass listener with Serve{Transport}.
No description provided by the author

# Structs

No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
No description provided by the author
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.
No description provided by the author
DialogUA defines UserAgent that will be used in controling your dialog.
No description provided by the author
No description provided by the author
Server is a SIP server.
No description provided by the author

# Interfaces

No description provided by the author

# Type aliases

No description provided by the author
No description provided by the author
No description provided by the author
RequestHandler is a callback that will be called on the incoming request.
No description provided by the author
No description provided by the author