Giter VIP home page Giter VIP logo

routr's Introduction

Contribute with Gitpod Sponsor this Discord GitHub Twitter Follow

Routr is a lightweight sip proxy, location server, and registrar that provides a reliable and scalable SIP infrastructure for telephony carriers, communication service providers, and integrators.

Table of content

Community

We are building Routr in the open. The best to communicate with us is via GitHub Discussions.


Special Announcement:

We now have a Discord Channel
There we plan to discuss roadmaps, feature requests, and more
Join us today


Should you try Routr?

Routr's architecture and design is fantastic. A breath of fresh air. Being Docker and Kubernetes ready is a huge win over a more traditional SIP server setup.

Phil Jones, VP of Web Architecture at VQ Communications

I came across Routr, which seems to be the one and only cloud-first Kubernetes-ready SIP server on the planet!

Jessie Wadman, Cloud Architect @ Camanio AB

Awesome and one of the best open-source software in 2023.

no-championship-s368, Check conversation @ Reddit

I think this project has a great promise to become a transformative technology.

jbwill36, Check conversation @ GitHub

Contact us

Meet our sales team for any commercial inquiries.

Book us with Cal.com

Features

Routr's main features are:

  • Common SIP Server functions; Proxy, Registrar, Location Service
  • Programmable routing
  • Load balancing strategies against Media Servers like Asterisk and FreeSWITCH
  • Session Affinity
  • Multi-Tenant/Multi-Domain with Domain level Access Control List
  • Region-based routing
  • Configurable routing strategies; Intra-Domain, Domain Ingress, Domain Egress, and Peer Egress
  • No single point of failure
  • Transport: TCP, UDP, TLS, WS, WSS
  • In-memory and Redis Location Service
  • JSON and YAML files as a data source
  • Postgres as a data source
  • Server management with the gRPC API
  • NodeSDK
  • Command-Line Tool
  • RTPEngine Middleware
  • Helm Chart for Kubernetes Deployments
  • Endpoint Authentication with JWT (For web phones)
  • Support for STIR/SHAKEN
  • Web Application

To learn more, read the documentation 📚

The official handbook

This handbook offers a detailed information about of the innovative features, challenges, and opportunities associated with using Routr.

Get the eBook.

Give a star! ⭐

If you want to support this project, please give it a star. Thanks 🙏

Deployment

Instant server deployment with Docker and Compose

First, create a directory named "routr". Navigate into the new folder, and then copy the content below:

Filename: compose.yaml

version: "3"

services:
  routr:
    image: fonoster/routr-one:latest
    environment:
      EXTERNAL_ADDRS: ${DOCKER_HOST_ADDRESS}
    ports:
      - 51908:51908
      - 5060:5060/udp
    volumes:
      - shared:/var/lib/postgresql/data

volumes:
  shared:

Then, start the server with:

# Be sure to replace with your IP address
DOCKER_HOST_ADDRESS=192.168.1.3 docker-compose up

Alternatively, you can use the following command:

# Be sure to replace with your IP address
docker run \
  -p 51908:51908 \
  -p 5060:5060/udp \
  -e EXTERNAL_ADDRS=192.168.1.3 \
  fonoster/routr-one:latest

Wait a few seconds for the containers to initialize. Afterward, you can verify the status of the containers using:

docker ps -a --format 'table {{.ID}}\t{{.Image}}\t{{.Status}}'

You should see a container with the status "Up." It should look like the one below:

CONTAINER ID  IMAGE                                     STATUS
6c63fd573768  fonoster/routr-one:latest                 Up About a minute

If the status of your services is "Up," you are ready to go.

Kubernetes

Routr can be installed in Kubernetes using Helm. The following instructions assume that you have a Kubernetes cluster up and running.

You can use Minikube or Docker Desktop to create a local Kubernetes cluster.

First, add the Helm repository:

helm repo add routr https://routr.io/charts
helm repo update

Then, create a namespace for Routr:

kubectl create namespace routr

Next, install Routr with the following command:

helm install my-release routr/routr-connect --namespace routr

Finally, wait a few minutes for the pods to start. You can check the status of the pods with the following command:

kubectl get pods -n routr

You should see a list of pods and their status. If the status is Running, then you are ready to go.

For more details, please refer to the chart's README.

Development mode with Gitpod

Routr's one-click interactive deployment will familiarize you with the server in development mode.

Open in Gitpod

To connect to your instance, follow these steps:

First, add your public SSH keys to your Gitpod account by going to Gitpod account keys and adding your public key.

Next, find your Gitpod workspace and click on the "More" button. Then, select "Connect via SSH."

Finally, copy the SSH Command and run it in your terminal by pasting it and pressing Enter. The command should look like this:

ssh -L 5060:localhost:5060 <workspace-ssh-connection>

Replace with your own workspace SSH connection.

For example, your command might look like this:

ssh -L 5060:localhost:5060 fonoster-routr-mn8nsx0d9px@fonoster-routr-mn8nsx0d9px.ssh.ws-us90.gitpod.io

This command forwards traffic from your local port 5060 to your Gitpod workspace's port 5060, allowing you to access your instance.

Getting started with the CTL

Regadles of the deployment method, you can use the command-line tool to manage your server.

To install the command-line tool, run the following command:

npm install --location=global @routr/ctl

We are using the flag --location=global to tell npm to install the command-line tool globally. If you don't have npm installed, you can follow the instructions here: https://nodejs.org/en/download/.

Here is an example of how to create a domain:

rctl domains create --insecure

The --insecure flag, in the last example, is required because no certificate was provided to secure the API.

Follow the prompts to create the domain.

The output should look like this:

This utility will help you create a new Domain.
Press ^C at any time to quit.
? Friendly Name Local Domain
? SIP URI sip.local
? IP Access Control List None
? Ready? Yes
Creating Domain Local Domain... a27e9fb2-a71a-4cf3-9b1d-dccf373f9777

For additional examples, refer to the command line documentation.

First steps with the NodeSDK

To begin using the Node.js SDK, first make sure you have Node and NPM installed. Then, start by creating a new project and installing the Routr Connect SDK.

mkdir my-project
cd my-project
npm init -y

Next, install the SDK:

npm install --save @routr/sdk

Now, create a new file called index.js and add the following code:

const SDK = require("@routr/sdk");

const domains = new SDK.Domains();

const request = {
  name: "Local domain",
  domainUri: "sip.local",
  accessControlListRef: "4671371b-ff5d-48b1-aabe-d3c5ca5317a3", 
  egressPolicies: [{
    rule: ".*",
    numberRef: "4671371b-ff5d-48b1-aabe-d3c5ca5317a3"
  }],
  extended: {
    "key": "value"
  } 
};

domains.createDomain(request) 
  .then(console.log)
  .catch(console.error); // an error occurred

In the example above, we assume that the ACL and Number already exist.

Now, go ahead and run the code:

node index.js

For complete documentation, please visit the npm page for @routr/sdk at https://www.npmjs.com/package/@routr/sdk

Building custom Processors and Middleware

One of Routr's most significant advantages is that it is highly extensible. It enables you to create new Processors and Middleware to extend the functionality of your server.

Processors and Middleware services are responsible for modifying the SIP messages as they pass through the server. However, while both share the same interface, they serve different purposes.

Processors hold feature logic; Middlewares addresses cross-cutting concerns like authentication, authorization, rate limiting, etc.

The simplest possible Processor looks like this:

const Processor = require("@routr/processor").default
const { MessageRequest, Response } = require("@routr/processor")

new Processor({ bindAddr: "0.0.0.0:51904", name: "echo" }).listen(
  (req: MessageRequest, res: Response) => {
    console.log("got new request: ")
    console.log(JSON.stringify(req, null, " "))
    res.sendOk()
  }
)

The previous example is for a Processor that waits for a SIP message and then sends a 200 OK response. You can find the complete code here.

In addition to the previous example, you can check the following modules:

For more information about building Processors and Middleware, please refer to the documentation.

Bugs and feedback

For bugs, questions, and discussions, please use the Github Issues

Contributing

For contributing, please see the following links:

Pedro
Pedro Sanders
Hannarong
Hannarong Klinjan
Efrain
Efrain Peralta
vitalyster/
vitalyster
Kani/
Kani
Timmy/
Timmy
luzpaz/
luzpaz

Sponsors

We're glad to be supported by respected companies and individuals from several industries.

Find all our supporters here

Become a Github Sponsor

Authors

License

Copyright (C) 2024 by Fonoster Inc. MIT License (see LICENSE for details).

routr's People

Contributors

browt190 avatar dependabot[bot] avatar efraa avatar github-actions[bot] avatar hannarong98 avatar kanimaru avatar luzpaz avatar psanders avatar vitalyster avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

routr's Issues

Call forking not working

The server is not forking the calls for location entries with several contact. The first client to acknowledge the invite is the only one that starts ringing.

Realm and Domain should be a parameter

The challenge response generated by the Proxy currently has "sipio" hardcode as the realm. This should be a parameter. Perhaps in the general configuration(i.e: for example, metadata.realm.).

This can be done at the Domain level as well.

WebSocket problem

Hi before start... thanks very nice project.

I have some question about configuration your service, I need use WebSocket but I don't found any configuration for this.

RC4 roadmap

The areas of focus for RC4 are:

  • Freeze changes in the public API(apiVersion == v1beta1)
  • Replace the testing tool with Mocha and Istanbul to allow for test coverage
  • Bring GraalJS as the default JS engine
  • Re-write the Location module to improve performance
  • Review the architecture to allow for better decoupling and scalability
  • Work on bringing the server to the following platforms:
    • Ubuntu Snaps
    • DigitalOcean droplet
    • Docker
    • Kubernetes
    • Google Cloud Shell
    • Custom
  • Bring the routr-ui to a beta version
  • Add experimental support for IPv6

Multi threaded access requested by thread Thread

This issue is likely caused by the host language attempting to access nodejs event loop while the server is busy.

Exception in thread "Timer-0" java.lang.IllegalStateException: Multi threaded access requested by thread Thread[Timer-0,5,main] but is not allowed for language(s) js.
        at com.oracle.truffle.polyglot.PolyglotContextImpl.throwDeniedThreadAccess(PolyglotContextImpl.java:649)
        at com.oracle.truffle.polyglot.PolyglotContextImpl.checkAllThreadAccesses(PolyglotContextImpl.java:567)
        at com.oracle.truffle.polyglot.PolyglotContextImpl.enterThreadChanged(PolyglotContextImpl.java:486)
        at com.oracle.truffle.polyglot.PolyglotContextImpl.enter(PolyglotContextImpl.java:447)
        at com.oracle.truffle.polyglot.HostToGuestRootNode.execute(HostToGuestRootNode.java:82)
        at com.oracle.truffle.api.impl.DefaultCallTarget.call(DefaultCallTarget.java:102)
        at com.oracle.truffle.polyglot.PolyglotMap.entrySet(PolyglotMap.java:117)
        at com.oracle.truffle.js.scriptengine.GraalJSBindings.entrySet(GraalJSBindings.java:152)
        at java.base/java.util.AbstractMap.containsKey(Unknown Source)
        at java.scripting/javax.script.SimpleScriptContext.getAttribute(Unknown Source)
        at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.getScriptName(GraalJSScriptEngine.java:331)
        at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.createSource(GraalJSScriptEngine.java:327)
        at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.eval(GraalJSScriptEngine.java:323)
        at java.scripting/javax.script.AbstractScriptEngine.eval(Unknown Source)
        at io.routr.core.Launcher$2.run(Launcher.java:90)
        at java.base/java.util.TimerThread.mainLoop(Unknown Source)
        at java.base/java.util.TimerThread.run(Unknown Source)
[WARN ] Unable to connect to host -> `x.x.x.x`.(Verify your network status)

Remove agents from the location service after the "Expires" time has elapsed

  • Devices that did not send a REGISTER before their expiration time should be removed from the Location Service.

  • If an agent sends a REGISTER message with expires = 0 it should be removed from the Location Service. Often the "expires" is a property of the Contact Header it should be handled as if it was the header expires.

Routr does not provide with a re-register interval parameter

Currently Router does not provide with a re-register interval parameter for the Gateway resources. This causes Router to re-register using a hard coded value( 300 seconds.)

We will need to provider and parameter spec on the Gateway resource to cover this situation.

Cannot find module utils/acl_helper

Cannot find module utils/acl_helper
Cannot load module utils/test LOAD_ERROR
./node_modules/jvm-npm/src/main/javascript/jvm-npm.js:109:8 Error: Cannot find module utils/acl_helper

Allow to add gateway without registration

My SIP provider does not provide credentials and works for example with freeswitch and <param name="register" value="false"/>, while your gateway spec requires it.

Parameter .spec.host in peers is not working

The parameter .spec.host in peers is not working as expected. When this parameter is present in the configuration this value is to replace the proxy IP/Host. The purpose of this to facilitate the query of a peer in the LocationService.

Deprecate endpoint `/credentials`

RC3 will deprecate endpoint /credentials in favor of \token. This new method will return a json message instead of only the JWT string. A successful response can look like this:

{
   "status": "200",
   "message": "Successful request",
   "result": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhZG1pbiJ9.O7hC-ta225epRQlJZO44WC-l2cWohKnJ8lkmlOQpw8Z_xYiwJ6-qDUhHeJEZH9DmwIwz_jD77sj1kQUkXHsbOg"
}

Memory usage growth

We are seeing an increase in memory usage from 70 mb to 356 mb in 9 hours.
Centos 7.

routr.service - Routr
   Loaded: loaded (/etc/systemd/system/routr.service; enabled; vendor preset: disabled)
   Active: active (running) since Wed 2019-09-11 23:21:56 MSK; 9h ago
 Main PID: 5497 (sh)
    Tasks: 72
   Memory: 356.8M
   CGroup: /system.slice/routr.service
           ├─5497 sh /usr/local/routr/routr
           └─5501 /usr/local/routr/jre/bin/java -Dlog4j.configurationFile=config/log4j2.xml -Dnashorn.args=--no-deprecation-warning -classpath libs/* com.fonoster.routr.core.Launcher

Performance issues while using ROUTR_JS_ENGINE=graal.js

Routr is showing degraded performance while using Graal.js as the JS engine. Something is causing a deadlock, perhaps due to Graal.js approach to Multithreading. I believe the issue is related to the following code:

        const requestProcessor = this.requestProcessor
        const responseProcessor = this.responseProcessor

        return new SipListener({
            processRequest: function(event) {
                try {
                    requestProcessor.process(event)
                } catch(e) {
                    LOG.error(e)
                }
            },
...

So the fact the processRequest function is sharing Javascript objects. The degraded performance is noticeable while looking in VisualVM:

Running with Graal.js

Screen Shot 2019-06-08 at 13 26 45

Running with Nashorn

Screen Shot 2019-06-08 at 13 28 07

I compared both engines in a recent benchmark and noticed that Routr performs 92% faster in Nashorn.

More follow on this issue.

Spec: Peer Egress Routing

Peers are very similar to Agents but are not bound to any Domain, and they are usually in the same or near network with Sip I/O. A common case will be peering with Asterisk, where Asterisk acts as a Media Server and Sip I/O is used for signaling.

Peers can perform inbound/outbound signaling within the network without any especial consideration since they exist inside the Location Service just like Agents. So it is possible to perform signaling from Peer to Peer, Peer to Agent, and Agent to Peer.

The same is true for Inbound from the PSTN. For example, we can redirect incoming calls from the PSTN using the spec.location settings in the dids.yml configuration file.

Outbound routing to the PSTN requires of having the Gateway and DID's information beforehand. Sip I/O expects to receive the following information:

From -> with the Peer’s username@host
To -> The endpoint the Peer is attempting to reach
Reference to the DID and the Gateway

A use case for this routing traffic originated by the Asterisk Manager.

WebRTC problem

Hi i want to call from WebRTC client ( SIP.js sample ) to regular tcp client ( like telephone app ).

INVITE sip:[email protected] SIP/2.0
Via: SIP/2.0/WS 192.0.2.141;branch=z9hG4bK9974885
Max-Forwards: 70
To: sip:[email protected]
From: "john" sip:[email protected];tag=ti72bitt27
Call-ID: scjcl34f5tk1bv3f4k76
CSeq: 117 INVITE
Contact: sip:[email protected];transport=ws;ob
Allow: ACK,CANCEL,INVITE,MESSAGE,BYE,OPTIONS,INFO,NOTIFY,REFER
Supported: outbound
User-Agent: SIP.js/0.7.0 BB
Content-Type: application/sdp
Content-Length: 4716


SIP/2.0 100 Trying
CSeq: 117 INVITE
Call-ID: scjcl34f5tk1bv3f4k76
From: "john" sip:[email protected];tag=ti72bitt27
To: sip:[email protected]
Via: SIP/2.0/WS 192.0.2.141;branch=z9hG4bK9974885;received=192.168.1.188;rport=54594
Content-Length: 0

I don't give any other response. and no ringing ...

Peer Routing is not working as expected

Calls originated from a Peer to an Agent are being dropped because the Peer's domain does not match with the Agents domains. Please investigate for a potential bug.

Use routr for a close group

Guys, I am so happy I have found your project that I cannot express in words. 👏
I just need some hand-holding and maybe a help with config files, etc.
We have a close group of users (6 people) and we would like to be able to communicate using VoIP. We do not need conference calls or calls outside of the group. We have a mixture of VoIP devices ranges from SoftPhones (LinPhone, CSIPSimple) to Yealink VoIP devices.
I would like to host routr.io on my Docker server.
Can you guys give me some suggestions on how to configure routr to cater to what we are looking for? What ports should I open on the firewall? Any help would be highly appreciated.

Provide examples of the env variables

The environmental variables should have their own space in the configuration section of routr.io, with examples of each one. The variable ROUTR_JS_ENGINE should be added until support for Nashorn is removed and Graal.js becomes the default Javascript engine.

Locator reports thruGw==true for Agents

The location module is reporting thruGw == true for Agents which is never a valid value. This happens when the endpoint is not on the location table. A possible fix for this is to pre-load all routes in the location module for DOMAIN_INGRESS_ROUTING and DOMAIN_EGRESS_ROUTING.

rctl commands with '?' formatting

Hi All. I've started recently playing around with Routr and I'm having a particular issue probably related with the Java that I have installed on Debian. Every time I run a rctl command, the formatting is not as it should be. This didn't happen when I was running CentOS. Can you please provide me more information about what ideal Java packages are required? Here is how it looks:
image

Another useless exception

This doesn't tell much about the problem...

{"status":500,"message":"The execution of the service failed","result":"java.lang.IllegalArgumentException: path can not be null or empty"}

It is cause by not appending the token at the end of the URL

Exceptions incoming call

Hi I'm create gateway to my provider. All config files write as you tutorial. But if I make incoming call. In terminal have exceptions. That me this exception?

[DEBUG] advertised addr: {"host":"192.168.0.2","port":5060}
[DEBUG] flow: {"isLinkAOR":false,"thruGw":false}
[ERROR] javax.sip.TransactionUnavailableException: Could not resolve next hop or listening point unavailable!

Confirm/refine schema definitions (v1beta1)

This issue is aimed to refine/refactor the schema definitions. This will help clarify some of the features and capabilities of the server. It will also help identify the best place to define certain parameters(i.e global or domain level)

ACL rules not working

Sip I/O's current implementation is not using the last-hop to check if isIpAllowed.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.