binrpc

package module
v3.2.0 Latest Latest
Warning

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

Go to latest
Published: May 24, 2022 License: MIT Imports: 7 Imported by: 3

README

go-kamailio-binrpc

Go Report Card CircleCI GoDoc License

Zero dependency Go implementation of Kamailio BINRPC protocol, for invoking RPC functions.

This library works with any Kamailio version.

go-kamailio-binrpc requires at least Go 1.18.

Usage

import binrpc "github.com/florentchauveau/go-kamailio-binrpc/v3"
Full Example
package main

import (
	"fmt"
	"net"

	binrpc "github.com/florentchauveau/go-kamailio-binrpc/v3"
)

func main() {
	// establish connection to Kamailio server
	conn, err := net.Dial("tcp", "localhost:2049")

	if err != nil {
		panic(err)
	}

	// WritePacket returns the cookie generated
	cookie, err := binrpc.WritePacket(conn, "tm.stats")
	
	// for commands that require args, add them as function args
	// like this: binrpc.WritePacket(conn, "stats.fetch", "all")

	if err != nil {
		panic(err)
	}

	// the cookie is passed again for verification
	// we receive records in response
	records, err := binrpc.ReadPacket(conn, cookie)

	if err != nil {
		panic(err)
	}

	// "tm.stats" returns one record that is a struct
	// and all items are int values
	items, _ := records[0].StructItems()

	for _, item := range items {
		value, _ := item.Value.Int()

		fmt.Printf("%s = %d\n",
			item.Key,
			value,
		)
	}
}
Kamailio Config

The ctl module must be loaded:

loadmodule "ctl.so"

If you are using kamcmd (and you most probably are), the module is already loaded.

In order to connect remotely, you must listen on TCP or UDP (defaults to local unix socket):

modparam("ctl", "binrpc", "tcp:2049")

WARNING: this will open your Kamailio to the world. Make sure you have a firewall in place, or listen on an internal interface.

Limits

For now, only int double string and structs are implemented. Other types will return an error.

Contributing

Contributions are welcome.

License

This library is distributed under the MIT license.

Documentation

Overview

Package binrpc implements the BINRPC protocol of Kamailio for invoking RPC functions. This package lets you talk to a Kamailio instance from Go code.

The ctl module must be loaded: https://www.kamailio.org/docs/modules/stable/modules/ctl.html

The BINRPC protocol is described in "src/modules/ctl/binrpc.h": https://github.com/kamailio/kamailio/blob/master/src/modules/ctl/binrpc.h

Limits

The current implementation handles only int, string, and structs containing int or string values. Other types will return an error.

Usage

High level functions:

- WritePacket to call an RPC function (a string like "tm.stats")

- ReadPacket to read the response

package main

import (
	"fmt"
	"net"

	binrpc "github.com/florentchauveau/go-kamailio-binrpc/v3"
)

func main() {
	conn, err := net.Dial("tcp", "localhost:2049")

	if err != nil {
		panic(err)
	}

	cookie, err := binrpc.WritePacket(conn, "tm.stats")

	if err != nil {
		panic(err)
	}

	records, err := binrpc.ReadPacket(conn, cookie)

	if err != nil {
		panic(err)
	}

	fmt.Printf("records = %v", records)
}

Index

Examples

Constants

View Source
const (
	BinRPCMagic   uint8 = 0xA
	BinRPCVersion uint8 = 0x1

	TypeInt    uint8 = 0x0
	TypeString uint8 = 0x1
	TypeDouble uint8 = 0x2
	TypeStruct uint8 = 0x3
	TypeArray  uint8 = 0x4
	TypeAVP    uint8 = 0x5
	TypeBytes  uint8 = 0x6

	// the totalLength cannot be larger than 4 bytes
	// because we have 2 bits to write its "length-1"
	// so "4" is the largest length that we can write
	MaxSizeOfLength = 4
)

BinRPCMagic is a magic value at the start of every BINRPC packet. BinRPCVersion is the version implemented (currently 1).

Variables

This section is empty.

Functions

func WritePacket

func WritePacket[T ValidTypes](w io.Writer, values ...T) (uint32, error)

WritePacket creates a BINRPC packet (header and payload) containing values v, and writes it to w. It returns the cookie generated, or an error if one occurred.

Example
// establish connection to Kamailio server
conn, err := net.Dial("tcp", "localhost:2049")

if err != nil {
	panic(err)
}

cookie, err := WritePacket(conn, "core.echo", "bonjours")

if err != nil {
	panic(err)
}

records, err := ReadPacket(conn, cookie)

if err != nil {
	panic(err)
}

// based on records[0].Type, records[0].Value is either:
// an int (TypeInt)
// a string (TypeString)
// a []StructItem (TypeStruct)

response, _ := records[0].String()

fmt.Printf("response = %s", response)
Output:

Example (Scan)
// establish connection to Kamailio server
conn, err := net.Dial("tcp", "localhost:2049")

if err != nil {
	panic(err)
}

cookie, err := WritePacket(conn, "core.echo", "bonjours")

if err != nil {
	panic(err)
}

records, err := ReadPacket(conn, cookie)

if err != nil {
	panic(err)
}

// based on records[0].Type, records[0].Value is either:
// an int (TypeInt)
// a string (TypeString)
// a []StructItem (TypeStruct)

var response string

if err = records[0].Scan(&response); err != nil {
	panic(err)
}

fmt.Printf("response = %s", response)
Output:

Example (StructResponse)
// establish connection to Kamailio server
conn, err := net.Dial("tcp", "localhost:2049")

if err != nil {
	panic(err)
}

// WritePacket returns the cookie generated
cookie, err := WritePacket(conn, "tm.stats")

if err != nil {
	panic(err)
}

// the cookie is passed again for verification
// we receive records in response
records, err := ReadPacket(conn, cookie)

if err != nil {
	panic(err)
}

// "tm.stats" returns one record that is a struct
// and all items are int values
items, _ := records[0].StructItems()

for _, item := range items {
	value, _ := item.Value.Int()

	fmt.Printf("%s = %d\n",
		item.Key,
		value,
	)
}
Output:

Example (StructResponseScan)
// establish connection to Kamailio server
conn, err := net.Dial("tcp", "localhost:2049")

if err != nil {
	panic(err)
}

// WritePacket returns the cookie generated
cookie, err := WritePacket(conn, "tm.stats")

if err != nil {
	panic(err)
}

// the cookie is passed again for verification
// we receive records in response
records, err := ReadPacket(conn, cookie)

if err != nil {
	panic(err)
}

// "tm.stats" returns one record that is a struct
// and all items are int values
var items []StructItem

if err = records[0].Scan(&items); err != nil {
	panic(err)
}

for _, item := range items {
	value, _ := item.Value.Int()

	fmt.Printf("%s = %d\n",
		item.Key,
		value,
	)
}
Output:

Types

type Header struct {
	PayloadLength int
	Cookie        uint32
}

Header is a struct containing values needed for parsing the payload and replying. It is not a binary representation of the actual header.

func ReadHeader

func ReadHeader(r io.Reader) (*Header, error)

ReadHeader is a low level function that reads from r and returns a Header.

type Record

type Record struct {
	Type  uint8
	Value any
	// contains filtered or unexported fields
}

Record represents a BINRPC type+size, and Go value. It is not a binary representation of a record. Type is the BINRPC type.

func CreateRecord

func CreateRecord[T ValidTypes](v T) (*Record, error)

CreateRecord is a low level function that creates a Record from value v and fills the Type property automatically.

func ReadPacket

func ReadPacket(r io.Reader, expectedCookie uint32) ([]Record, error)

ReadPacket reads from r and returns records, or an error if one occurred. If expectedCookie is not zero, it verifies the cookie.

func ReadRecord

func ReadRecord(r io.Reader) (*Record, error)

ReadRecord is a low level function that reads from r and returns a Record or an error if one occurred.

func (Record) Double added in v3.1.0

func (record Record) Double() (float64, error)

Double returns the double value as a float64, or an error if the type is not a double

func (*Record) Encode

func (record *Record) Encode(w io.Writer) error

Encode is a low level function that encodes a record and writes it to w.

func (Record) Int

func (record Record) Int() (int, error)

Int returns the int value, or an error if the type is not a int.

func (*Record) Scan

func (record *Record) Scan(dest any) error

Scan copies the value in the Record into the values pointed at by dest. Valid dest type are *int, *string, and *[]StructItem

func (Record) String

func (record Record) String() (string, error)

String returns the string value, or an error if the type is not a string.

func (*Record) StructItems

func (record *Record) StructItems() ([]StructItem, error)

StructItems returns items for a struct value, or an error if not a struct.

type StructItem

type StructItem struct {
	Key   string
	Value Record
}

StructItem represents an item in a BINRPC struct. Because BINRPC structs may contain the same key multiple times, structs are handled with arrays of StructItem.

type ValidTypes added in v3.2.0

type ValidTypes interface {
	int | string | float64
}

ValidTypes is an interface of types that can be used in a Record.

Jump to

Keyboard shortcuts

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