Code Monkey home page Code Monkey logo

node-diameter's Introduction

node-diameter

Gitter npm version Build Status Code Climate Test Coverage

node-diameter is node.js implementation of Base Diameter protocol.

Usage

Check client and server in 'examples' directory.

To see it in action:

$ npm install

Start server:

$ npm run-script example-server

Start client:

$ npm run-script example-client

Using custom diameter dictionaries

To use your own diameter dictionary, set the 'DIAMETER_DICTIONARY' environment variable to path of the json file containing your dictionary, or name of node module that provides it. See 'node-diameter-dictionary' module for json file format, and how to create a node module that provides a dictionary.

Note: this module has a dependency on 'node-diameter-dictionary' module, so if you are using your own dictionary, you can optionaly remove the 'node-diameter-dictionary' dependency when doing the npm shrinkwrap of your application.

Complementary library

Makes it easier to work with diameter messages, by converting the arrays to objects:

https://github.com/node-diameter/node-diameter-avp-object

node-diameter's People

Contributors

atesgoral avatar dependabot[bot] avatar rkovacevic avatar shokuie 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

Watchers

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

node-diameter's Issues

3GPP-GGSN-Address AVP - malformed AVP

Hi guys,

I'm seeing a strange issue with the 3GPP-GGSN-Address AVP:

    {
        "code": 7,
        "name": "3GPP-GGSN-Address",
        "vendorId": 10415,
        "type": "IPAddress",
        "flags": {
            "mandatory": true,
            "protected": true,
            "mayEncrypt": true,
            "vendorBit": true
        }
    }

Wireshark is telling me that the AVP is Malformed. But what is strange, is that I've also the SGSN-Address AVP within the same avp-group and this one works fine:

            ['Service-Information', [
                ['PS-Information', [
                    ['Called-Station-Id', 'internet.dhimobile'],
                    ['3GPP-GPRS-Negotiated-QoS-Profile', '08-58090002666700026667'],
                    ['3GPP-GGSN-Address', '1.2.3.4'],
                    ['SGSN-Address', '1.2.3.4'],

Have you seen this before? Again, it only happens with this particular AVP. I can see it correctly on the server side.

Thanks,
Luís

Screenshot 2020-05-07 at 15 18 40

More CPU Consumed with Diameter Server at 100 ACR/ACA call rate/Sec with RF traffic.

Hi rkovacevic,

Thank you very much implementing Diameter Protocol in Node Js with very light weight code( hardly 4 to 5 Files) and It's easily readable. Using this Api, , i developed Diameter CCF server and ran RF traffic around 100 call rate/Sec and the this server consuming 100% Cpu. I feel like diameter-codec.js should be optivmised further to avoid unnecessary CPU consuming.

Please suggest me how to avoid this problem.

Thanks,
Naresh

GroupedAVP

Hi,

I just create nodejs application with your diameter module. When diameter-client-app.js receive GroupedAVP throw error (Error: No handler for type: Grouped)
Full stack error message in the attachment.
dimater_error_groupedAVP.txt

GroupedAVP description in rfc3588. chapter 4.4 Grouped AVP values

The diameter-types.js var types may include Grouped value encode and decode functions.

Closing a client connection right after sending a response produces error

If you close a connection right after sending a response, i.e.:

event.callback(event.response);
socket.diameterConnection.end();

it produces:

Error: write after end
    at writeAfterEnd (_stream_writable.js:193:12)
    at Socket.Writable.write (_stream_writable.js:244:5)
    at Socket.write (net.js:661:40)
    at Immediate.<anonymous> (/Users/robert/dev/node-diameter/lib/diameter-connection.js:61:49)
    at runCallback (timers.js:637:20)
    at tryOnImmediate (timers.js:610:5)
    at processImmediate [as _immediateCallback] (timers.js:582:5)

You can see it in example client, by just uncommenting the relevant line.

This is probably due to this part in diameter-connection.js:

setImmediate(function() {
    self.socket.write(responseBuffer);
});

which is a workaround for another problem.

Will need to do some deep analysis of this whole synchronisation part.

sending Unsigned64 using Long

Hi guys,

Sorry about insisting on this. I'm receiving on my app, a string with the value '53687091200'. What I'm doing is picking this value and add it to the CC-Total-Octets AVP. Example:

reqUnits = ['CC-Total-Octets', new Long.fromString('53687091200',true,10)];

If I print it, I get this:
[
'CC-Total-Octets',
Long { low: -2147483648, high: 12, unsigned: true }
]

I'm seeing that the message has the right data:
CC-Request-Number: 0
Multiple-Services-Credit-Control:
Rating-Group: 12799
Service-Identifier: 16
Requested-Service-Unit:
CC-Total-Octets: 53687091200

However, I get this exception:

RangeError [ERR_OUT_OF_RANGE]: The value of "value" is out of range. It must be >= 0 and <= 4294967295. Received -2147483648
at checkInt (internal/buffer.js:63:11)
at writeU_Int32BE (internal/buffer.js:793:3)
at Buffer.writeUInt32BE (internal/buffer.js:806:10)
at Object.encode (/scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-types.js:50:24)
at Object.exports.encode (/scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-types.js:148:26)
at encodeAvp (/scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-codec.js:327:39)
at /scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-codec.js:280:16
at arrayMap (/scratch/home/brmadmin/lsilva/node-diameter-master/node_modules/lodash/lodash.js:639:23)
at Function.map (/scratch/home/brmadmin/lsilva/node-diameter-master/node_modules/lodash/lodash.js:9554:14)
at encodeAvps (/scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-codec.js:279:24)

Do you know what I'm doing wrong?

Thanks and apologizes for this question!
Luís

Allow usage of custom dictionary

It would be great to have flexibility to let node-diameter use alternative dictionary.json when needed. When given custom/extra args to createServer or client, it would load this alternative file instead.

Handling junk data

Write tests and handle errors when receiving junk data. It should just close the client connection, not kill the server, which I suspect it would do now.

decodeAvp correct?

I was wondering about this code line:

https://github.com/node-diameter/node-diameter/blob/master/lib/diameter-codec.js#L197

The situation is like this:

I receive a packet with the following content:
test

which results in

diameter_server-2 (err): at Socket.Readable.push (_stream_readable.js:126:10)
diameter_server-2 (err): at TCP.onread (net.js:538:20)
diameter_server-2 (err): Error: Unable to find AVP for code 443 for app 16777238
diameter_server-2 (err): at decodeAvp (/var/node/diameter/node_modules/diameter/lib/diameter-codec.js:199:15)
diameter_server-2 (err): at decodeAvps (/var/node/diameter/node_modules/diameter/lib/diameter-codec.js:230:19)
diameter_server-2 (err): at Object.exports.decodeMessage (/var/node/diameter/node_modules/diameter/lib/diameter-codec.js:252:16)
diameter_server-2 (err): at Socket.DiameterSession.self.socketDataHandler (/var/node/diameter/node_modules/diameter/lib/diameter-session.js:49:45)
diameter_server-2 (err): at Socket.emit (events.js:107:17)
diameter_server-2 (err): at readableAddChunk (_stream_readable.js:163:16)
diameter_server-2 (err): at Socket.Readable.push (_stream_readable.js:126:10)
diameter_server-2 (err): at TCP.onread (net.js:538:20)

Is it correct to lookup all avps according based on the application id or should only the vendor specific ids be looked up by the specific application id?

No function named "getCommandById"

I executed client using node-diameter api v0.8 and observed below error.
nodejs diameter-client-example.js
/home/vuser/nodeDiameterUpdated/node-diameter/lib/diameter-codec.js:114
command = dictionary.getCommandById(commandName);
^

TypeError: dictionary.getCommandById is not a function.

It resolved by replacing the line with command = dictionary.getCommandByCode(commandName);

var findCommand = function(commandName) {
var command;
if (!_.isNumber(commandName)) {
command = dictionary.getCommandByName(commandName);
} else {
//command = dictionary.getCommandById(commandName);
command = dictionary.getCommandByCode(commandName);
}
return command;
};

Client: Using an open TCP connection for multiple simultaneous connections

I'm not sure if this is something that is technically possible (js newbie here), if I were to open a new socket and call multiple functions with this connection as argument, for each of them to send different requests simultaneously to same host, I will have Promise errors.

To be able to send requests without waiting for response also is a challenge for me. I'm trying to find a way to bombard an OCS with high amount of requests to see how it fares, it allows only one tcp connection per interface (Gx, Gy) peer.

Please close if this is technically wrong way of thinking.

Travis CI

setup travis CI for tests and npm publish

Index out of range

this is just an example, i can see a lot of places where this will break, depending on the AVP size
diameter-type can also fail. bottom line, there is no sanity check before reading
quesion is: what do you guys think is a good way to handle it? on go-diameter, they actually dropped it and returned. maybe we should do the same?

happy to submit a PR

buffer.readUInt32BE(start + DIAMETER_MESSAGE_AVP_CODE);

RangeError: Index out of range
    at checkOffset (buffer.js:831:11)
    at Buffer.readUInt8 (buffer.js:869:5)
    at decodeAvpHeader (/home/nodeuser/source/node_modules/diameter/lib/diameter-codec.js:185:24)
    at decodeAvp (/home/nodeuser/source/node_modules/diameter/lib/diameter-codec.js:196:15)
    at decodeAvps (/home/nodeuser/source/node_modules/diameter/lib/diameter-codec.js:235:19)
    at Object.exports.decodeMessage (/home/nodeuser/source/node_modules/diameter/lib/diameter-codec.js:257:16)
    at Socket.<anonymous> (/home/nodeuser/source/node_modules/diameter/lib/diameter-connection.js:44:49)
    at emitOne (events.js:96:13)
    at Socket.emit (events.js:188:7)
    at readableAddChunk (_stream_readable.js:176:18)
    at Socket.Readable.push (_stream_readable.js:134:10)
    at TCP.onread (net.js:547:20) 

Problem sending the value 751619276800 in the CC-Total-Octets AVP

Hi guys,

I'm sending a CCR with the CC-Total-Octets AVP with a value of 751619276800 (700GB). What I'm seeing is that the library is considering this AVP Uint32, when in fact, it is supposed to be consider Unsigned64. Because of this, I'm getting an exception when attempting to send it. Do you know why?

Thanks,
Luís

    {
        "code": 421,
        "name": "CC-Total-Octets",
        "vendorId": 0,
        "type": "Unsigned64",
        "flags": {
            "mandatory": true,
            "protected": false,
            "mayEncrypt": false,
            "vendorBit": false
        }
    },

Multiple-Services-Credit-Control:
Rating-Group: 12804
Service-Identifier: 16
Requested-Service-Unit:
CC-Total-Octets: 751619276800


RangeError [ERR_OUT_OF_RANGE]: The value of "value" is out of range. It must be >= 0 and <= 4294967295. Received 751_619_276_800
at checkInt (internal/buffer.js:63:11)
at writeU_Int32BE (internal/buffer.js:793:3)
at Buffer.writeUInt32BE (internal/buffer.js:806:10)
at Object.encode (/scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-types.js:53:24)
at Object.exports.encode (/scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-types.js:148:26)
at encodeAvp (/scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-codec.js:327:39)
at /scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-codec.js:280:16
at arrayMap (/scratch/home/brmadmin/lsilva/node-diameter-master/node_modules/lodash/lodash.js:639:23)
at Function.map (/scratch/home/brmadmin/lsilva/node-diameter-master/node_modules/lodash/lodash.js:9554:14)
at encodeAvps (/scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-codec.js:279:24)
at encodeAvp (/scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-codec.js:298:25)
at /scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-codec.js:280:16
at arrayMap (/scratch/home/brmadmin/lsilva/node-diameter-master/node_modules/lodash/lodash.js:639:23)
at Function.map (/scratch/home/brmadmin/lsilva/node-diameter-master/node_modules/lodash/lodash.js:9554:14)
at encodeAvps (/scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-codec.js:279:24)
at encodeAvp (/scratch/home/brmadmin/lsilva/node-diameter-master/lib/diameter-codec.js:298:25)

3GPP Gx enum is duplicate within dictionary.xml

I know the standard says the same but the way the lookup is performed its never possible to access this enum:

because this one is accessed before

maybe it should also be possible to directly add values by int instead of looking them up in an enum?

CCF Server not able to handle long running traffic at 1000 calls/Sec from PGW

Hi Robert,

I setup CCF server using with this Api. 1000 calls/sec is triggered from PGW using simulator for long time. the CCF server is not able read the Network Recv-q buffer quickly which results into Network Recv-Q keep on heaping up at server side.

Active Internet connections (w/o servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp6 0 73188 x:x:x:x:3868 x:x:x:x:3995 ESTABLISHED
tcp6 3130480 0 x:x:x:x:3995 x:x:x:x:3868 ESTABLISHED

Thanks,
Naresh

AVP encoding/decoding application/vendor-specificity

Take for instance the CC-Request-Type AVP entry in dictionary.json. It's sharing the AVP code 416 with these entries:

{
    "code": 416,
    "name": "Not defined in .xml",
    "vendorId": 13019,
    "type": "OctetString",
    "flags": {
        "mandatory": true,
        "protected": false,
        "mayEncrypt": true,
        "vendorBit": true
    }
},
{
    "code": 416,
    "name": "Private-Identity-Request",
    "vendorId": 10415,
    "type": "Integer32",
    "flags": {
        "mandatory": false,
        "protected": false,
        "mayEncrypt": false,
        "vendorBit": true
    },
    "enums": [
        {
            "code": 0,
            "name": "Private identity requested"
        },
        {
            "code": 1,
            "name": "Private identity not requested"
        }
    ]
},
{
    "code": 416,
    "name": "CC-Request-Type",
    "vendorId": 0,
    "type": "Unsigned32",
    "flags": {
        "mandatory": true,
        "protected": true,
        "mayEncrypt": true,
        "vendorBit": false
    },
    "enums": [
        {
            "code": 1,
            "name": "INITIAL_REQUEST"
        },
        {
            "code": 2,
            "name": "UPDATE_REQUEST"
        },
        {
            "code": 3,
            "name": "TERMINATION_REQUEST"
        },
        {
            "code": 4,
            "name": "EVENT_REQUEST"
        }
    ]
},

This is causing and issue in my application because the CC-Request-Type AVP erroneously gets mapped to the very first entry with code 416.

Shouldn't getAvpByCode() in lib/diameter-dictionary.js be actually something like getAvpByCodeAndVendorId() so that it just returns the AVP with the matching vendor ID? For this, the decodeAvp() function in lib/diameter-codec.js might have to take in a vendorId argument instead of (or in addition to) appId. I'm actually also a bit confused about the whole application ID versus vendor ID thing. Are vendor IDs just vendor-specific application IDs and therefore they're the same thing? (i.e. a vendor ID is an application ID?)

Using Event-Timestamp AVP

Hi guys,

I'm trying to use the Event-Timestamp AVP with the current time.

I was trying to use Math.round(new Date().now()/1000) but it doesn't seem to be working.

Can you tell me how I can pass this value?

Thanks,
Luís

Synchronous socket.write for responses seems to choke event processing loop

(Copied from associated PR)

In my development environment, I've set my Diameter server to act both as an initiator and a responder to connect to itself so that I can test my device watchdog implementation. Even though there's barely any load on the server except for a DWR/DWA exchange every 3 seconds, receipt of DWA tends to randomly fail after a while.

Note that this is all happening on the single thread of a single Node.js process, so one might argue that it's not a realistic scenario that should be worried about, but I think node-diameter should be able to robustly handle loopback connections.

I added a lot of log statements to both my code and within node-diameter's diameter-connection.js to get a sense of the timing of events, and also did some reading into Node.js's event loop internals, but I wasn't able to pinpoint exactly the condition that triggers the missed receipt of DWA.

However, through some experimentation and intuition, I was able to get around the problem by making the response sending asynchronous by wrapping the socket.write call inside a setImmediate. The fact that both the request receipt and the response sending happen entirely synchronously seems to be the culprit. While it is possible to let application writers call the response callback asynchronously, I thought it would be better to make node-diameter's sending of the response asynchronous itself.

I don't see any immediate negative consequences of doing so, and it indeed solved the problem I was having. While I still would love to get an understanding of exactly what is going on with the event processing phases in this particular case, I think we could go ahead with this fix without fully getting down to the bottom of what the issue is.

I also think the synchronous response sending might have something to do with some of the other performance/robustness issues that were mentioned in some of the open issues.

Licensing change

Are there any plans for changing license to something less restrictive like BSD or MIT license?

Node module is still on V0.9.0

Seems CD didn't work properly for the latest release (V0.9.1) and node module is still on V0.9.0. Could you please take a look and update.

how to react on client disconnect

server side re-auth works now, but if the client disconnects during the session, the server crashes with
events.js:85
throw er; // Unhandled 'error' event
^
Error: read ECONNRESET
at exports._errnoException (util.js:746:11)
at TCP.onread (net.js:559:26)

how should disconnecting clients be handled gracefullly?

event data read latency

i am wrestling with an issue where i can see CCR packets come in on time (pcap) but somehow this.socket.on('data',()=>{}) is emitting 2 seconds or more later. (diameter-connection.js)

this happens very often, sometimes even on 5tps. looks like random hiccups, suddenly froze. weird issue.

i am monitoring my event loop lag, and there is no blocking, i can see my app calling callback in a few millis and this.socket.write() is fine inside setImmediate() writing seems to be all good.

anybody experienced same issue?

Unnecessary usage of hex encoding

  1. At https://github.com/node-diameter/node-diameter/blob/master/lib/diameter-session.js#L31:
var buffer = new Buffer(0, 'hex');

The second argument, 'hex' is redundant because when the first argument is a number, the new Buffer(size) overload is used.

  1. In diameter-types.js, there are a bunch instances of the same problem as above: new Buffer(4, 'hex'), new Buffer(8, 'hex')
  2. At https://github.com/node-diameter/node-diameter/blob/master/lib/diameter-session.js#L34:
buffer = Buffer.concat([buffer, new Buffer(data, 'hex')]);

Again, the second argument is probably redundant because data is already a Buffer instance.

The only case where there is an encoding argument that is used is this overload:

new Buffer(str[, encoding])

When the first argument is a string, the second argument determines how bytes are encoded within the string.

Reconnect mechanism

Hi guys,

This is not really a bug, so I'm not sure if I'm using the right tool to raise my question. I'm trying to implement a keep alive mechanism that periodically tests if the diameter connection is up and if it isn't, it attempts to reconnect.
What I was thinking was using the DiameterConnection -> readable and writable flags to understand that the socket is closed and attempt to create a new one. Do you think this can be done or is there a better way of doing this?

Thanks!!
Luís

AVP not found for code 494

Unable to find AVP for code 494 and vendor id 50, for app 16777216.
Also, this AVP is not available on Wireshark and internet.
Any help would be appreciated!

Exception encoding Octet string AVP.

Encoding an octet string AVP, like Proxy-State, raise an exception:


Unhandled rejection TypeError: "list" argument must be an Array of Buffers
-------------------------------------------------------------------------------- at Function.Buffer.concat (buffer.js:314:13)

This is the message body:
request.body = request.body.concat([
['Proxy-Info', [
['Proxy-State', '19']
]]
]);

Looks that the issue is in the diameter-types.js file. OctetString returns the value, instead of a buffer.

var types = {
'OctetString': {
encode: function(value) {
return value;
},

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.