Skip to content

Basic Diameter Examples

This document provides fundamental examples of implementing Diameter protocol interfaces.

Client Setup

from diameter.client import DiameterClient
from diameter.avp import AVP
import asyncio
import uuid

class BasicDiameterClient:
    def __init__(self, host, port, realm):
        self.host = host
        self.port = port
        self.realm = realm
        self.client = DiameterClient()

    async def connect(self):
        """Establish connection and perform CER/CEA"""
        await self.client.connect(self.host, self.port)
        await self.capability_exchange()

    async def capability_exchange(self):
        """Perform Capabilities-Exchange"""
        avps = [
            AVP('Origin-Host', self.host),
            AVP('Origin-Realm', self.realm),
            AVP('Host-IP-Address', self.host),
            AVP('Vendor-Id', 0),
            AVP('Product-Name', 'Example Client'),
            AVP('Auth-Application-Id', 4)  # Credit Control
        ]

        request = self.client.create_request('CER', avps)
        response = await self.client.send_request(request)
        return response.result_code == 2001

async def main():
    client = BasicDiameterClient(
        host='client.example.com',
        port=3868,
        realm='example.com'
    )

    try:
        await client.connect()
        print("Connected successfully")

    except Exception as e:
        print(f"Connection failed: {e}")

if __name__ == '__main__':
    asyncio.run(main())

Authentication Request

async def send_auth_request(client, username):
    """Send AA-Request for user authentication"""
    session_id = str(uuid.uuid4())

    avps = [
        AVP('Session-Id', session_id),
        AVP('Origin-Host', client.host),
        AVP('Origin-Realm', client.realm),
        AVP('Destination-Realm', 'auth.example.com'),
        AVP('Auth-Application-Id', 1),
        AVP('User-Name', username),
        AVP('Auth-Request-Type', 1)  # AUTHENTICATE_ONLY
    ]

    request = client.create_request('AAR', avps)
    return await client.send_request(request)

# Usage example
async def authenticate_user(client, username):
    try:
        response = await send_auth_request(client, username)

        if response.result_code == 2001:
            print(f"Authentication successful for {username}")
            return True
        else:
            print(f"Authentication failed: {response.error_message}")
            return False

    except Exception as e:
        print(f"Error during authentication: {e}")
        return False

Credit Control Request

async def send_credit_control_request(client, subscription_id, requested_units):
    """Send Credit-Control-Request for real-time charging"""
    session_id = str(uuid.uuid4())

    avps = [
        AVP('Session-Id', session_id),
        AVP('Origin-Host', client.host),
        AVP('Origin-Realm', client.realm),
        AVP('Destination-Realm', 'charging.example.com'),
        AVP('Auth-Application-Id', 4),
        AVP('CC-Request-Type', 1),  # INITIAL_REQUEST
        AVP('CC-Request-Number', 0),
        AVP('Subscription-Id', [
            AVP('Subscription-Id-Type', 0),  # END_USER_E164
            AVP('Subscription-Id-Data', subscription_id)
        ]),
        AVP('Requested-Service-Unit', [
            AVP('CC-Time', requested_units)
        ])
    ]

    request = client.create_request('CCR', avps)
    return await client.send_request(request)

# Usage example
async def request_credit(client, subscription_id):
    try:
        response = await send_credit_control_request(
            client,
            subscription_id,
            requested_units=600  # 10 minutes
        )

        if response.result_code == 2001:
            granted_units = response.get_avp('Granted-Service-Unit')
            print(f"Granted {granted_units} units")
            return granted_units
        else:
            print(f"Credit request failed: {response.error_message}")
            return 0

    except Exception as e:
        print(f"Error during credit request: {e}")
        return 0

Error Handling

class DiameterError(Exception):
    def __init__(self, result_code, message=None):
        self.result_code = result_code
        self.message = message or self._get_error_message()
        super().__init__(self.message)

    def _get_error_message(self):
        error_messages = {
            3001: "DIAMETER_COMMAND_UNSUPPORTED",
            3002: "DIAMETER_UNABLE_TO_DELIVER",
            3004: "DIAMETER_TOO_BUSY",
            4001: "DIAMETER_AUTHENTICATION_REJECTED",
            4010: "DIAMETER_END_USER_SERVICE_DENIED",
            4012: "DIAMETER_CREDIT_LIMIT_REACHED",
            5001: "DIAMETER_AVP_UNSUPPORTED",
            5004: "DIAMETER_INVALID_AVP_VALUE",
            5012: "DIAMETER_UNABLE_TO_COMPLY"
        }
        return error_messages.get(
            self.result_code,
            f"Unknown error: {self.result_code}"
        )

async def send_request_with_retry(client, request, max_retries=3):
    """Send request with retry mechanism"""
    for attempt in range(max_retries):
        try:
            response = await client.send_request(request)

            if response.result_code == 2001:
                return response

            if response.result_code >= 3000:
                raise DiameterError(response.result_code)

        except Exception as e:
            if attempt == max_retries - 1:
                raise

            await asyncio.sleep(2 ** attempt)  # Exponential backoff
            continue

Configuration Example

# config.yaml
diameter:
  client:
    host: client.example.com
    port: 3868
    realm: example.com

  connection:
    retry_count: 3
    timeout: 5
    keepalive: 30

  security:
    tls_enabled: true
    cert_file: /etc/diameter/client.pem
    key_file: /etc/diameter/client.key

  logging:
    level: INFO
    file: /var/log/diameter.log

Loading Configuration

import yaml

def load_config(config_file):
    """Load diameter configuration from YAML file"""
    with open(config_file, 'r') as f:
        return yaml.safe_load(f)

def create_client_from_config(config_file):
    """Create Diameter client from configuration"""
    config = load_config(config_file)

    client = BasicDiameterClient(
        host=config['diameter']['client']['host'],
        port=config['diameter']['client']['port'],
        realm=config['diameter']['client']['realm']
    )

    if config['diameter']['security']['tls_enabled']:
        client.set_tls_config(
            cert_file=config['diameter']['security']['cert_file'],
            key_file=config['diameter']['security']['key_file']
        )

    return client