JAIN SLEE Powered | jSS7-NG 9.2.10 | 10k TPS Load Tested | Multi-Protocol
7.2.1 β gRPC Application Server integration Β· Adaptive gate timeout Β· Virtual Session Bridge
Design RFC for unified late-response reconciliation:docs/design/bridge-unified-reconciliation-rfc.md
|
Connect the AS over gRPC (HTTP/2) with the same pull/push semantics as HTTP β no XML glue, no extra sidecar.
|
Stop losing subscribers when the AS or the network is slow.
|
Subscriber dials *101#. Gateway forwards to the AS over gRPC; the menu returns while the MO dialogue is still open.
sequenceDiagram
autonumber
participant U as π± Subscriber
participant GW as USSD Gateway
participant AS as gRPC AS
participant SS7 as MSC / MAP
U->>SS7: *101# (MO)
SS7->>GW: ProcessUnstructuredSSRequest
GW->>AS: gRPC Process(sessionId, payload)
Note over GW,AS: within adaptive gate (~7s)
AS-->>GW: menu XmlMAPDialog
GW->>SS7: UnstructuredSSRequest
SS7->>U: Show menu (S1)
AS needs longer than the network allows. Gateway releases S1 with a friendly wait message, keeps state in Infinispan, and delivers the result on a new NI push dialogue (S2).
sequenceDiagram
autonumber
participant U as π± Subscriber
participant GW as USSD Gateway
participant Store as Infinispan
participant AS as Application Server
participant SS7 as MSC / MAP
U->>SS7: menu input
SS7->>GW: MO dialogue S1
GW->>Store: WAIT_AS + requestId
GW->>AS: HTTP / gRPC / SIP + X-Ussd-Request-Id
Note over GW: adaptive gate fires (~EWMA Γ headroom)
GW->>U: "Δang xα» lΓ½, sαΊ½ cαΊp nhαΊt ngay"
GW->>SS7: close S1
GW->>Store: BRIDGED
Note over AS: processing 10β30sβ¦
AS-->>GW: late response (sync or push URL)
GW->>SS7: NI Push S2
SS7->>U: menu result
Note over GW: CDR S1 + S2 share correlationId
After gate, the AS may answer on the same sync connection (preferred) or on the existing USSD Push URL if the transport already closed β one contract, no separate /async-response endpoint.
flowchart LR
subgraph S1["MO dialogue S1"]
MO[User input]
end
subgraph Gate["Adaptive gate"]
G[Release S1 Β· BRIDGED]
end
subgraph Channels["Late response β pick one"]
A["Channel A<br/>Sync HTTP / gRPC / SIP"]
B["Channel B<br/>POST push servlet<br/>+ X-Ussd-Request-Id"]
end
subgraph S2["NI Push S2"]
P[Menu to subscriber]
end
MO --> G
G --> A
G --> B
A --> P
B --> P
| Scenario | What happens | AS action |
|---|---|---|
| AS fast | Menu on S1, no bridge | Normal sync response |
| AS slow, sync alive | Gate β reconcile on same HTTP/gRPC/SIP | Return menu on original request |
| AS slow, sync dead | Gate β NI Push S2 | POST existing push URL + X-Ussd-Request-Id |
| Duplicate delivery | Idempotent per requestId |
Safe to retry |
π Full bridge spec: docs/design/virtual-session-bridge.md Β· RFC: bridge-unified-reconciliation-rfc.md
USSD Gateway is the bridge between modern application servers and legacy SS7 telecom networks, enabling Unstructured Supplementary Service Data (USSD) services for mobile subscribers across all network generations β from 2G GSM to 5G NR.
Unlike SMS, USSD creates a real-time interactive session between subscriber and application, making it ideal for:
- Mobile banking (
*100#) - Balance inquiry & top-up
- SIM toolkit menus
- Emergency alerts
- Voting & surveys
- Self-care portals
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β USSD Gateway 7.2.1 Architecture β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ β
β β HTTP β β SIP β β HTTP β β SS7/ β β
β β Client β β Client β β Push β β MAP β β
β ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ β
β β β β β β
β ββββββ΄βββββββββββββββ΄βββββββββββββββ΄βββββββββββββββ΄βββββ β
β β JAIN SLEE 1.1 Container β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β β β SBB - Service Building Blocks β β β
β β β ββββββββββββ ββββββββββββ ββββββββββββ β β β
β β β β HTTP β β SIP β β MAP-RA β β β β
β β β β SBB β β SBB β β Events β β β β
β β β ββββββ¬ββββββ ββββββ¬ββββββ ββββββ¬ββββββ β β β
β β β ββββββββββββββ΄βββββββββββββ β β β
β β β USSD Routing Logic β β β
β β ββββββββββββββββββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββ β
β β jSS7-NG 9.2.10 Stack β β
β β (JCTools + Jackson XML + Zero-GC SCTP) β β
β ββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ β
β β β
β ββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββ β
β β SCTP-NG 2.0.13 Transport β β
β β (500K+ msg/s | Object Pooling) β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ β
β β HLR βββββ€ STP βββββ€ SIGTRAN βββββ€ M3UA/ β β
β β β β β β SCTP β β SCCP β β
β ββββββββββββ ββββββββββββ ββββββββββββ ββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
| Protocol | Interface | Use Case | Latency |
|---|---|---|---|
| HTTP | POST /ussdhttpdemo/ |
Web apps, modern services | < 10ms |
| SIP | INVITE |
VoIP integration, IMS | < 15ms |
| HTTP Push | Callback URL | Async notifications | < 5ms |
| SS7/MAP | ProcessUnstructuredSSRequest |
Legacy network | < 50ms |
// ProcessUnstructuredSSRequest - Mobile Originated
MAPDialogSupplementary dialog = mapProvider.getMAPServiceSupplementary()
.createNewDialog(appContext, origAddress, origRef, destAddress, destRef);
dialog.addProcessUnstructuredSSRequest(dcs, ussdString, alertingPattern, msisdn);
dialog.send();
// UnstructuredSSRequest - Network Initiated
dialog.addUnstructuredSSRequest(dcs, ussdString, alertingPattern);
// UnstructuredSSNotify - One-way notification
dialog.addUnstructuredSSNotify(dcs, ussdString, alertingPattern, msisdn);| Component | Legacy (Javolution) | NG (JCTools) | Improvement |
|---|---|---|---|
| Dialog Queue | FastList (synchronized) |
MpscArrayQueue (lock-free) |
13x faster |
| Subscriber Cache | FastMap (lock per op) |
NonBlockingHashMap (wait-free reads) |
5x faster |
| Event Buffer | FastList |
MpscArrayQueue |
Zero contention |
| Module | XMLFormat Lines | Jackson XML Lines | Reduction |
|---|---|---|---|
| USSD XML | 200+ | 15 | 93% |
| MAP Dialog | 280 | 20 | 93% |
| TCAP Events | 150 | 10 | 93% |
Benchmark: USSD Dialogs/sec (100 concurrent clients)
ββββββββββββββββββββββββββ¬βββββββββββββ¬βββββββββββ¬ββββββββββββββ
β Scenario β Classic β NG β Improvement β
ββββββββββββββββββββββββββΌβββββββββββββΌβββββββββββΌββββββββββββββ€
β HTTP β MAP β 2,100 TPS β 10,500 β β
5x β
β SIP β MAP β 1,800 TPS β 9,200 β β
5.1x β
β MAP β MAP (load test) β 3,500 TPS β 12,000+ β β
3.4x β
β Memory allocations β 450 MB/s β < 50 MB/sβ β
9x β
ββββββββββββββββββββββββββ΄βββββββββββββ΄βββββββββββ΄ββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β USSD SBB Lifecycle β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β [HTTP Request] βββΊ HTTP SBB βββΊ XmlMAPDialog βββΊ β
β [SIP INVITE] βββΊ SIP SBB βββΊ XmlMAPDialog βββΊ β
β β β
β βΌ β
β ββββββββββββββββββββββββ β
β β Routing Logic β β
β β - Rule matching β β
β β - URL resolution β β
β β - Dialog mapping β β
β ββββββββββββ¬ββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββ β
β β MAP-RA Events β β
β β ProcessUnstructuredSSβ β
β β UnstructuredSSRequestβ β
β ββββββββββββ¬ββββββββββββ β
β β β
β βΌ β
β ββββββββββββββββββββββββ β
β β jSS7-NG Stack β β
β β TCAP βββΊ SCCP βββΊ β β
β β M3UA βββΊ SCTP β β
β ββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// 1. HTTP Client sends XML
POST /ussdhttpdemo/ HTTP/1.1
Content-Type: application/xml
<dialog appCntx="networkUnstructuredSsContext" version="2">
<processUnstructuredSSRequest_Request>
<dataCodingScheme>15</dataCodingScheme>
<ussdString>*100#</ussdString>
<msisdn>1234567890</msisdn>
</processUnstructuredSSRequest_Request>
</dialog>
// 2. USSD Gateway converts to MAP Dialog
// 3. Routes through SS7 stack to HLR/MSC
// 4. Returns XML response to HTTP client| Component | Version | Notes |
|---|---|---|
| Java | JDK 8+ | Zulu JDK 8.84.0.15 recommended |
| Maven | 3.6+ | 3.9.12 tested |
| WildFly | 10.0.0.Final | JBoss-based JAIN SLEE container |
| OS | Linux | Ubuntu 20.04/22.04 recommended |
# Clone repository
git clone https://github.com/nhanth87/ussdgw.git
cd ussdgw
# Build core modules
cd core
mvn clean install -DskipTests
# Build examples
cd ../examples
mvn clean install -DskipTests
# Build tools
cd ../tools
mvn clean install -DskipTests
# Build test & load test
cd ../test
mvn clean install -DskipTests# Start WildFly in standalone mode
$WILDFLY_HOME/bin/standalone.sh -c standalone-slee.xml
# Deploy USSD Gateway SLEE Deployable Unit
cp core/slee/services-du/target/ussd-gateway-du-*.jar \
$WILDFLY_HOME/standalone/deployments/
# Deploy HTTP Example WAR
cp examples/http/target/http-example-*.war \
$WILDFLY_HOME/standalone/deployments/USSD Gateway ships with a comprehensive load testing toolkit capable of validating 10,000 transactions per second.
| Approach | Protocol | Stack Required | Use Case |
|---|---|---|---|
| MAP-Level | SS7/MAP | Full SCTPβM3UAβSCCPβTCAPβMAP | Core SS7 performance |
| HTTP-Level | HTTP/XML | None (client-side) | HTTPβSBBβXML path |
cd test/loadtest
# Build load test JAR with all dependencies
mvn clean install -Passemble -DskipTests
# Start MAP Load Server (Terminal 1)
cd target/load
java -cp "*" org.mobicents.protocols.ss7.map.load.ussd.Server \
100000 50000 SCTP 192.168.1.10 192.168.1.11 8011 IPSP 101 1 2 147 101 8
# Start MAP Load Client (Terminal 2)
cd target/load
java -cp "*" org.mobicents.protocols.ss7.map.load.ussd.Client \
100000 50000 SCTP 192.168.1.11 192.168.1.10 8011 IPSP 101 2 1 147 101 8 \
"*100#" "UTF-8" 60000 10000 10000 2000cd test/loadtest
# Build HTTP load test
mvn clean package -DskipTests
# Run HTTP load generator
java -cp "target/loadtest-7.2.1-SNAPSHOT.jar:target/dependency/*" \
org.mobicents.ussd.loadtest.UssdHttpLoadGenerator \
http://localhost:8080/ussdhttpdemo/ \
10000 # target TPS \
32 # worker threads \
50000 # max concurrent dialogs \
300 # test duration (seconds) \
"*100#" # USSD stringJAVA_OPTS="-Xms4g -Xmx4g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=10 \
-XX:+UnlockExperimentalVMOptions \
-XX:+UseStringDeduplication \
-XX:+HeapDumpOnOutOfMemoryError \
-Djava.net.preferIPv4Stack=true \
-Dorg.jboss.resolver.warning=true \
-Dsun.rmi.dgc.client.gcInterval=3600000 \
-Dsun.rmi.dgc.server.gcInterval=3600000"# /etc/sysctl.conf
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.core.netdev_max_backlog = 65535
fs.file-max = 2097152
fs.nr_open = 2097152
# /etc/security/limits.conf
* soft nofile 1048576
* hard nofile 1048576ussdgateway/
βββ core/ # Core modules
β βββ domain/ # Domain model & entities
β βββ xml/ # XML serialization (Jackson)
β βββ session-bridge/ # Virtual Session Bridge (FSM, Infinispan store)
β βββ slee/ # JAIN SLEE SBBs
β β βββ library/ # SBB library
β β βββ sbbs/ # Service Building Blocks
β β βββ services-du/ # Deployable Unit
β βββ oam/cli/ # Operations & Management CLI
β βββ bootstrap-wildfly/ # WildFly bootstrap
βββ examples/ # Sample applications
β βββ http/ # HTTP interface example
β βββ http-push/ # HTTP Push example
β βββ sip/ # SIP interface example
βββ management/ # Management interfaces
β βββ ussd-management/ # JMX / CLI management
βββ test/ # Test suite
β βββ mapmodule/ # MAP module tests
β βββ bootstrap/ # Bootstrap tests
β βββ loadtest/ # 10k TPS load test tools
β βββ UssdLoadGenerator.java # MAP-level
β βββ UssdHttpLoadGenerator.java # HTTP-level
β βββ LoadTestMetrics.java # Metrics
βββ tools/ # Utilities
β βββ http-simulator/ # HTTP simulator for testing
βββ docs/ # Documentation
βββ adminguide/
βββ installationguide/
βββ releasenotes/
curl -X POST http://ussd-gateway:8080/ussdhttpdemo/ \
-H "Content-Type: application/xml" \
-d '<?xml version="1.0"?>
<dialog appCntx="networkUnstructuredSsContext" version="2">
<processUnstructuredSSRequest_Request>
<dataCodingScheme>15</dataCodingScheme>
<ussdString>*100#</ussdString>
</processUnstructuredSSRequest_Request>
</dialog>'INVITE sip:*100#@ussd-gateway SIP/2.0
Via: SIP/2.0/UDP 192.168.1.100:5060
From: <sip:subscriber@operator.com>
To: <sip:*100#@ussd-gateway>
Content-Type: application/vnd.3gpp.ussd+xml
<?xml version="1.0"?>
<ussd-data>
<ussd-string>*100#</ussd-string>
<any-ext>
<data-coding-scheme>15</data-coding-scheme>
</any-ext>
</ussd-data>
| Component | Version | Description |
|---|---|---|
| USSD Gateway | 7.2.1-SNAPSHOT | This project |
| jSS7-NG | 9.2.10 | SS7 protocol stack |
| SCTP-NG | 2.0.13 | Transport layer |
| JAIN SLEE | 1.1 | Container specification |
| WildFly | 10.0.0.Final | Application server |
| Netty | 4.2.11.Final | Network framework |
| JCTools | 4.0.3 | Lock-free collections |
| Jackson XML | 2.15.2 | XML serialization |
| Guava | 18.0 | Utility library |
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Restcomm Telecom Stack β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β ββββββββββββββββ ββββββββββββββββ ββββββββββββββββ β
β β jSS7-NG β β GMLC β β Diameter β β
β β SS7 Stack β β Location β β Gateway β β
β β v9.2.10 β β v6.0.1 β β v7.4.5 β β
β ββββββββ¬ββββββββ ββββββββ¬ββββββββ ββββββββ¬ββββββββ β
β β β β β
β βββββββββββββββββββ΄βββββββββββββββββββ β
β β β
β βββββββββΌββββββββ β
β β USSD Gateway β β
β β v7.2.1 β β
β βββββββββ¬ββββββββ β
β β β
β βββββββββββββββββββΌββββββββββββββββββ β
β β β β β
β ββββββββΌβββββββ ββββββββΌβββββββ ββββββββΌβββββββ β
β β HTTP β β SIP β β SS7 β β
β β Apps β β Clients β β Network β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
This project is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0).
- TeleStax β Original Mobicents USSD Gateway
- JCTools β Lock-free concurrent collections
- Netty Project β High-performance network framework
- 3GPP β SS7 / MAP / USSD specifications
When an Application Server takes longer than the network USSD timer allows, the session is normally dropped. The Virtual Session Bridge turns the gateway into a session orchestration layer that recovers these slow transactions and raises the session success rate.
How it works (feature-flagged, sessionBridgeEnabled, default false):
- On a Mobile-Originated (pull) request the gateway tracks the interaction with a gateway-owned
correlationIdand persists state to Infinispan (cache-container "ussd"). - If the AS does not reply before the async gate timeout, the gateway releases the MO dialogue
early with a friendly message ("Hα» thα»ng Δang bαΊn, sαΊ½ update lαΊ‘i cho bαΊ‘n ngay") and writes CDR
record S1 (
bridgePhase=S1_RELEASED). - When the late AS reply arrives it is delivered as a Network-Initiated push (S2). Both CDR
records share the same
correlationIdso reporting counts one successful transaction. - Idempotency lock per MSISDN, active-session priority/queue-back, push retry queue (JCTools) and a
NotificationFallbackSPI (SMS hook) protect against double submits and undeliverable pushes. - Adaptive timeout keeps a per-operator EWMA of AS latency and shortens/lengthens the gate within the configured ceiling.
Configuration (MBean UssdPropertiesManagement, editable in the Server Settings β Session
Bridge tab of ussd-management):
| Property | Meaning | Default |
|---|---|---|
sessionBridgeEnabled |
master feature flag | false |
asyncGateTimeoutMs |
release MO dialogue before network timeout | 7000 |
asyncWaitUserMessage |
message shown while bridging | VN string |
asyncHardFailMessage |
message shown on AS hard-fail / overload | VN string |
bridgeStateTtlSec |
Infinispan TTL | 180 |
pushRetryDelaysMs |
push retry back-off | 3000,8000,15000 |
Design spec (Vietnamese, with FSM + sequence diagrams + scenario catalog P1βP15 / U1βU10 / H7βH9):
docs/design/virtual-session-bridge.md.
The AS only needs one stable identifier. In the bridged case the MO (S1) and NI push (S2)
dialogues are different network dialogues but the same business session, so the gateway keeps the
id stable (sessionId := correlationId) across S1βS2. Internally the gateway uses correlationId
as the Infinispan/CDR key; on the wire there is a single id. See section 12 of the design doc.
In addition to HTTP, the gateway can talk to the AS over gRPC (HTTP/2) β the gateway is the gRPC client, the AS is the gRPC server, mirroring the HTTP client RA.
- Routing: set
ScRoutingRuleType.GRPCon the routing rule;ruleUrl=host:portof the AS. - The gRPC RA (
core/slee/resources/grpc-as) is non-blocking and publishes the reply to aGrpcResponseRegistry;GrpcClientSbbcollects it on a short SLEE poll timer and drives the MAP dialogue β the sameXmlMAPDialogpayload as HTTP. - The session id (unified with the bridge correlation id) is sent to the AS so it can keep per-session menu state, exactly like the HTTP session id.
- Wire format: unary method
ussd.UssdApplicationService/Processcarrying a JSON envelope (sessionId,correlationId,push,networkId,payloadB64). No protobuf code generation is required on the Java side; swap the marshaller if you prefer protobuf.
Deploy: the ussd-grpc-as-ra-DU is copied by release-wildfly/build.xml and the GrpcAsRA entity
is activated by the services DU deploy-config.xml.
tools/grpc-as-tester ships a configurable test AS and a load generator:
cd tools/grpc-as-tester
python3 -m venv .venv && ./.venv/bin/pip install -r requirements.txt
# multi-menu USSD AS with adaptive (random 1-100ms) processing delay
./.venv/bin/python ussd_as_server.py --port 8443 --min-delay 1 --max-delay 100 \
--menu-config menu_config.json
# load test from 1,000 up to 100,000+ TPS (fan out across processes for high TPS)
./.venv/bin/python loadtest_client.py --target localhost:8443 --tps 1000 --duration 10
./.venv/bin/python loadtest_client.py --target localhost:8443 --tps 100000 --duration 20 --processes 8The AS implements a configurable multi-menu pull/push flow, applies the adaptive delay to exercise the bridge + adaptive timeout, and keeps per-session menu state keyed by the (unified) session id. The load client reports achieved TPS and p50/p95/p99 latency.
β Star this repo if it powers your telecom infrastructure! β
Built with β€οΈ for the global telecom community