Posted August 27th 2009
GTH E1/T1 modules are always controlled by a general-purpose server, usually some sort of unix machine. The server and GTH are connected by ethernet and communicate using TCP sockets. Normally, that ethernet connection is chosen to be simple and reliable, for instance by putting the server and the GTH in the same rack, connected to the same ethernet switch.
I experimented a bit to see what happens when that network gets interrupted. I interrupted the network in a reproduceable way by disabling and re-enabling the server's ethernet port for a known length of time while running a <recorder>. (A <recorder> sends all the data, typically someone talking, from an E1 timeslot to the server over a TCP socket, 8000 octets per second.)
Here's what I did to capture traffic and interrupt the ethernet:
tcpdump -w /tmp/capture.pcap -s 0 not port 22 sudo ifconfig eth0 down; sleep 5; sudo ifconfig eth0 up
The GTH buffers about two seconds of timeslot traffic. So a 'sleep' of about a second won't result in an overrun. Here's what it looks like in wireshark:
Packet | Time | Direction | Flags | Seq. # |
133 | 7.596 | GTH -> server | [PSH, ACK] | 59393 |
134 | 7.633 | server -> GTH | [ACK] | 1 |
135 | 7.724 | GTH -> server | [PSH, ACK] | 60417 |
136 | 7.761 | server -> GTH | [ACK] | 1 |
137 | 7.852 | GTH -> server | [PSH, ACK] | 61441 |
138 | 7.889 | server -> GTH | [ACK] | 1 |
139 | 7.980 | GTH -> server | [PSH, ACK] | 62465 |
140 | 8.017 | server -> GTH | [ACK] | 1 |
141 | 8.108 | GTH -> server | [PSH, ACK] | 63489 |
142 | 8.145 | server -> GTH | [ACK] | 1 |
143 | 8.236 | GTH -> server | [PSH, ACK] | 64513 |
144 | 8.273 | server -> GTH | [ACK] | 1 |
145 | 8.364 | GTH -> server | [PSH, ACK] | 65537 |
146 | 8.401 | server -> GTH | [ACK] | 1 |
147 | 10.151 | GTH -> server | [PSH, ACK] | 66561 |
148 | 10.151 | server -> GTH | [ACK] | 1 |
149 | 10.151 | GTH -> server | [ACK] | 67585 |
150 | 10.151 | server -> GTH | [ACK] | 1 |
Everything up to packet 146 is normal: the GTH (172.16.2.5) sends 8000 octets every second and the server (172.16.2.1) acks them. It happens to be in chunks of 1024 octets about eight times per second. After packet 146, about 8.4 seconds after the capture started, the ethernet interface went down and stayed down for 1s. The TCP stream started up again after about 1.5s and then 'caught up' by sending many packets in quick succession.
I took a second trace similar to the first one, except this time, I disabled ethernet for about five seconds:
Packet Time Source IP Dest IP SPort DPort ---------------------------------------------------------------------- 28 1.040083 172.16.2.5 -> 172.16.2.1 54271 > 45195 [PSH, ACK] Seq=7169 29 1.040095 172.16.2.1 -> 172.16.2.5 45195 > 54271 [ACK] Seq=1 30 1.168065 172.16.2.5 -> 172.16.2.1 54271 > 45195 [PSH, ACK] Seq=8193 31 1.168078 172.16.2.1 -> 172.16.2.5 45195 > 54271 [ACK] Seq=1 32 1.296067 172.16.2.5 -> 172.16.2.1 54271 > 45195 [PSH, ACK] Seq=9217 33 1.296079 172.16.2.1 -> 172.16.2.5 45195 > 54271 [ACK] Seq=1 34 1.424068 172.16.2.5 -> 172.16.2.1 54271 > 45195 [PSH, ACK] Seq=10241 35 1.424081 172.16.2.1 -> 172.16.2.5 45195 > 54271 [ACK] Seq=1 36 7.782851 172.16.2.5 -> 172.16.2.1 54271 > 45195 [PSH, ACK] Seq=11265 37 7.782863 172.16.2.1 -> 172.16.2.5 45195 > 54271 [ACK] Seq=1 38 7.783406 172.16.2.5 -> 172.16.2.1 54271 > 45195 [ACK] Seq=12289 39 7.783413 172.16.2.1 -> 172.16.2.5 45195 > 54271 [ACK] Seq=1 40 7.783569 172.16.2.5 -> 172.16.2.1 54271 > 45195 [ACK] Seq=13737 ... 50 7.784962 172.16.2.5 -> 172.16.2.1 54271 > 45195 [FIN, PSH, ACK] Seq=23873 51 7.784972 172.16.2.1 -> 172.16.2.5 45195 > 54271 [ACK] Seq=1 52 7.785026 172.16.2.1 -> 172.16.2.5 45195 > 54271 [FIN, ACK] Seq=1 53 7.785348 172.16.2.5 -> 172.16.2.1 54271 > 45195 [ACK] Seq=25322
Everything is normal up to packet 35. Then, ethernet is suspended for five seconds and TCP takes a further second to recover, which causes a buffer overrun on the GTH (172.16.2.5). The GTH closes the socket at packet 50 and also sends an overrun event to the application so that it knows why the socket was closed.
GTH uses IP for control and traffic. It is important that the IP link between the GTH and the server is simple and reliable. Ideally the GTH and server should be in the same rack and be connected by an ethernet switch.
It's possible for a system to survive a short interruption (less than a second) to the ethernet traffic without pre-recorded calls getting interrupted. For longer interruptions, all bets are off.
(Interruptions aren't the only type of network problem, e.g. radio networks such as 802.11 can suffer significant packet loss, which can trigger TCP congestion avoidance. But that's another topic.)
Permalink | Tags: GTH, questions-from-customers
Posted August 10th 2009
Update 23. January 2014: save_to_pcap now emits Pcap-NG by default, but current versions (1.10.5)of Wireshark don't allow that through pipes. Use the '-c' switch to force classic Pcap.
I often use wireshark to look at SS7 signalling on E1 links. Up until today, I've always done that by capturing the signalling (from a GTH), then converting the captured data to libpcap format and finally loading the file into wireshark.
Someone showed me a better way today: wireshark can read from a pipe or from standard input. That lets me see and filter the packets in wireshark in real time. Here's how to do it, using the save_to_pcap demo program (included in gth_c_examples):
> ./save_to_pcap -c gth21 1A 2A 16 - | wireshark -k -i - capturing packets, press ^C to abort saving capture to stdout
The same thing works for tshark:
>./save_to_pcap -c gth21 1A 2A 16 - | tshark -V -i - capturing packets, press ^C to abort saving capture to stdout Capturing on - Frame 1 (15 bytes on wire, 15 bytes captured) Arrival Time: Aug 10, 2009 20:38:29.388000000 ... Message Transfer Part Level 2 .000 1101 = Backward sequence number: 13 1... .... = Backward indicator bit: 1 .011 1000 = Forward sequence number: 56 1... .... = Forward indicator bit: 1 ..00 0000 = Length Indicator: 0 00.. .... = Spare: 0 ...
Piping standard output to wireshark/tshark works on all the *nixes, i.e. linux, BSD, OSX, Solaris. On Windows, things are a bit different, you have to use 'named pipes' instead, like this:
save_to_pcap -c 172.16.1.10 1A 2A 16 \\.\pipe\ss7.1 wireshark -k -i \\.\pipe\ss7.1
On some older (as of August 2009) versions of wireshark, possibly in combination with older libraries, the "-i -" switch doesn't work, at least according to google, even though the tshark version works.
Posted June 9th 2009
The GTH can transmit in-band signalling tones on a timeslot. That's useful for testing and for building active in-band signalling systems.
The tones transmitted when the subscriber presses a number key on fixed or mobile handset are called DTMF. Wikipedia has an article about it. To generate DTMF, all we really need to know is that there are 16 possible DTMF signals, that each signal is made up of two sine waves of particular frequencies and that sending the signal for 100ms is a reasonable thing to do.
Here's a .zip file with DTMF tones in it. Each file is raw ALAW data, i.e. it's ready for the GTH to play (transmit) on a timeslot.
The GTH has two ways of playing tones. One way is to stream the audio data in over a TCP socket each time we want to play it. I wrote a post about that earlier. The other way is to store the sample data on the GTH and command its playback whenever it's needed. Since there's a small number of different tones (12, or 16 if you want to use the A/B/C/D tones as well) and the tones are short, storing them on the GTH makes sense. To store the tone:
<new><clip name='dtmf5'></new> (and now send the 800 byte file)
to play the tone later on:
<new><player> <clip id='clip dtmf5'/> <pcm_sink span='3A' timeslot='19'/> </player></new>
Sometimes you want to transmit a sequence of DTMF tones, for instance to simulate a subscriber dialling a number. The GTH lets you start a player with a sequence of tones like this:
<new><player> <clip id='clip dtmf5'/><clip id='clip dtmf6'/><clip id='clip dtmf8'/> <pcm_sink span='3A' timeslot='19'/> </player></new>
But that isn't a valid sequence of DTMF tones. Why not? Because DTMF expects a gap between tones. The cleanest way to handle that is to define another clip consisting of just silence and putting it between each tone. A good 'silence' value on E1 lines is 0x54. 60ms (480 samples) is a reasonable length.
DTMF in-band signalling is used in pretty much all handsets (telephones), mostly for dialling, but also to navigate menus in IVR systems. But before SS7 became popular, in-band signalling in the form of CAS and SS5 was even used to communicate call setup information between exchanges. GTH can also generate those tones, but that can be the subject of another post.
Posted March 23rd 2009
When the Corelatus GTH is used to monitor (sniff) signalling, it sends each sniffed packet to your server over a TCP socket, along with a header. For instance, for SS7 MTP-2 the header looks like this:
octet 0x00: Length (16 bits) octet 0x02: Tag (16 bits) octet 0x04: Flags (16 bits) octet 0x06: Timestamp (48 bits)
Every field is big-endian, i.e. the most significant byte comes first. Here's an actual header from a GTH, octet by octet:
00 1c 00 00 00 00 01 20 34 ee fa 61 99 99 99 99 ...
The timestamp is thus 0x012034eefa61, or decimal 1237838658145. For most applications, you just want to know which packet came first, so the interpretation of that number doesn't matter much, though it's useful to know that it's the number of milliseconds since the unix epoch. (wikipedia has a decent article about unix time)
Sometimes, though, you want to represent that as a human-readable time. Unix (and, most likely, Win32) provides functions to do that in the C library, so, after throwing away the last three digits (the milliseconds), this C program does it:
#include <time.h> #include <stdio.h> int main() { const time_t time_stamp = 1237838658; printf("%d corresponds to %s\n", time_stamp, ctime(&time_stamp)); return 0; }
The output agrees with what the clock on my wall says:
1237838658 corresponds to Mon Mar 23 21:04:18 2009
Since I've been messing around with python, the same thing in python:
>>> import time >>> time.ctime(1237838658) 'Mon Mar 23 21:04:18 2009'
Erlang doesn't have an interface to the 'ctime' call, but you can use the gregorian calendar functions:
1> Epoch = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0,0,0}}). 62167219200 2> calendar:gregorian_seconds_to_datetime(1237838658 + Epoch). {{2009,3,23},{20,4,18}}
Why is the GTH timestamp in milliseconds instead of either seconds or a 'timeval'-like seconds + microseconds?
We chose millisecond resolution for several reasons. Firstly, the shortest possible useful packet in SS7 takes a bit more than a millisecond to transmit at 64kbit/s. Secondly, the practical limit of NTP time synchronisation over the internet is about one millisecond at a typical site.
Posted February 19th 2009
A technician working for an operator mailed me a few days ago wondering why the recorded voice clips they use for their IVR sound so bad, "like they're coming from the bottom of a deep well". It turned out that the clips actually sounded OK on a telephone, just not through his laptop's speaker. He asked if I recommend any specific filter parameters when converting audio from 44.1kHz wav to 8kHz Alaw voice clips.
I took this audio snippet from the introduction to an audio book. It was originally a .mp3 file. I converted it to a .wav file with a 44.1kHz sampling rate and 16 bits per sample. For my purposes, artefacts from mp3 are negligible.
1_mono.wav (44.1kHz, 16 bit linear samples)
Next, I converted it to 8kHz Alaw using sox. 8kHz Alaw is what runs on the fixed telephone network in most of the world. (The US uses a minor variant, μlaw):
sox 1_mono.wav --encoding a-law --rate 8000 2_8kHz_alaw.wav
2_8kHz_alaw.wav (8kHz, 8 bit Alaw samples)
That sounds a bit less clear than the original, but it's OK. It's what you'd expect coming out of a telephone. There's some weirdness though. The audible difference between the two files varies from one PC to another and even one playback program to another. Why? Because laptop speakers vary in quality and because playback programs usually quietly convert everything back to 48kHz or 44.1kHz sampling rates, and they do it with different approaches. For fun, I resampled to 44.1kHz:
sox 2_8kHz_alaw.wav --rate 44100 --encoding signed 3_resampled.wav
3_resampled.wav (44.1kHz, 16 bit linear samples)
2_8kHz_alaw.wav and 3_resampled.wav should sound almost the same. But on some PCs they sound markedly different.
The GTH has a simple approach to playing back audio. It just copies the bytes you give it to the destination timeslot. No format or rate conversion happens, though the GTH does make sure the data is played out at the E1's frame rate (8000Hz). The downside of that is that you have to convert all the files for your IVR system before giving them to a GTH, e.g. using sox. The upside is that it's simple. Nothing happens behind your back.
To convert an audio recording to raw a-law for GTH:
sox original.wav --rate 8000 --channels 1 --encoding a-law --type raw gth.raw
To convert a raw recording from a GTH to something most audio programs can play:
sox --type raw --rate 8000 --channels 1 --encoding a-law gth.raw --rate 44100 --encoding signed gth.wav
(May 2016: I updated this section because SOX has changed since I first wrote this in 2009. The options above work for sox 14.4.1.)
There's a certain sound quality level expected in telephone networks, and part of that is that the network carries everything up to about 3500Hz. Analog local loop specifications mention that, and pretty much all digital telephone systems use an 8kHz sampling rate, which is what you need to be able to carry audio up to 3.5kHz. Even the GSM and AMR codecs start off with the assumption that the incoming audio is limited to 3500Hz.
So the bar is set pretty low. I haven't come across any systems which set out to provide higher quality, e.g. even skype compresses the hell out of the audio to save bandwidth. Even when both parties in a conversation have huge amounts of it. Surprising, why not aim for VOIP to sound much better than a regular telephone?
Permalink | Tags: GTH, questions-from-customers