Well, i had originally planned to make this a long entry about the history of the OpenZAP ISDN stack, what i’ve changed in the past months and how i think it should look and work like in the future, but…
… life sucks and stupid problems ususally come up at the worst time possible.
Let’s start with a short introduction to OpenZAP’s past:
The original OpenZAP ISDN has been written by Case Labs Ltd. and released under a BSD License. It contains both, Q.921 and Q.931 parts, that are loosely coupled. The Q.931 part has been designed to support multiple dialects (e.g. 5ESS, DMS etc.), which is a good thing, since OpenZAP is used by people in different countries and continents.
The old stack “works”… most of the time… well, unless something slighty unexpected happens…
It lacks proper stateful handling of messages, error handling, timers, the higher level API used in ozmod_isdn.c is message-centric instead of call-centric…. in short:
It’s a big mess.
I started in summer 2008 by rewriting most of the Q.921 layer based on the ITU-T specs (to add BRI support). That work is 80% complete, there are still a couple of things that have to be adressed e.g. error handling (FRMR etc.), resending of frames and sending/receiving events from/to Q.931 (Link activation and deactivation events for example). The initial goal however has been reached, BRI support works (Point-to-Point and Point-to-Multipoint mode) and the Q.921 layer is stateful and has working timers, which is a big improvement compared to what was there before i started.
Of course, if you start working on one part of the stack, you’ll have to touch the other one too…
… so i continued my rampage through the OpenZAP ISDN stack by trying to rewrite the Q.931 stack internals and its API. The current state of that work is available in the so called “api” branch of my private OpenZAP GIT repository on oss.axsentis.de (here is a link to the gitweb running on the server). There are already a lot of changes:
- A ton of the message decoding/encoding functions have been replaced by a pair of generic ones.
- The whole thing is stateful, which solves a lot of problems (like some stupid hacks to create a proper response to STATUS ENQUIRY out of the OpenZAP channel states (urgh)).
- Initial support for timers is in the works (depends on some other bits, but i’ve made some progress this weekend)
- Proper checking of messages: Is this message valid in the current call state? Are those Information Elements (IEs) allowed? Are some mandatory ones missing? - A lot of that has been added (still needs some work though and testing)
- API rework: Slowly making some progress, there’s some initial code to send and queue events to the higher layer now (only for the Q.931 NT dialect right now).
So, where are we heading?
Let’s start with the high-level api part. The current API works by passing Q.931 messages to the API, which is nice and allows for some *cough* flexibility, but makes life harder on the upper level (creating custom messages piece by piece, keeping track of OpenZAP channel <-> Q.931 call pairs via their CRV (Call Reference Value) etc.). We’d like to retain some of that freedom (sending custom messages) but get rid of most of the manual plumbing by replacing it with a call-centric API. The goal here is being abled to do something like:
struct Q931_Call *call = Q931CallNew(trunk); /* Add all the details like, Caller ID, Destination number etc. * (we'd still need to find a sane way to do that...) */ /* Associate the call with our higher level handle */ Q931CallSetPrivate(call, ourhandle); /* Make the call */ Q931CallSend(call); /* or something like that */
If you really want to know what this looks like in the old code, ozmod_isdn.c:isdn_request_channel() has it all (pretty, isn’t it?).
I’m taking a little shortcut for now (it’s getting late).
To understand the codebase a little, the most important names:
- Q931call.c – Call specific functions, timers, lookup by CRV etc.
- Q931mes.c – Message handling functions, generic message unpack / pack functions (Q931Umes_Generic, Q931Pmes_Generic), Table with Message <-> allowed IE lists for the (= base) Q.931 dialect.
- Q931State*.c - Q.931 TE / NT mode Dialect initialization function, Message processing functions and timer callbacks. Either mode is handled as a separate dialect!
- Q931ie.c - Information Element pack / unpack functions (Q931Pie_* and Q931Uie_*).
- Q931api.c – Misc (API) functions
- Q931.c – Input / Output routines (Q931Rx* Q931Tx*, Note: Q931Rx43 means: Message coming from Layer 4 into Layer 3 (this is what gets called to send messages from ozmod_isdn.c to the Q.931 stack); Q931Tx34: Send message to Layer 4), Logging functions, some Dummy functions (that should be moved somewhere else), also things like Q931Umes() : Wrapper functions; Initialization (and tons of other stuff).
- Q931dialect.c – Dialect handling.
- 5ESS/* - 5ESS Dialect (work-in-progress, started porting this one over to find parts of the dialect and message handling stuff that need refinement to support other dialects).
to be continued…