This tutorial introduces the bases of T3DevKit through two examples.
The first one (DNSTester) is taken from the book An Introduction to TTCN-3 [1], it implements a simple DNS client for resolving an IP address. While the book focuses only on the abstract side (TTCN-3 sources) we cover the full process to make the test executable. This especially includes: writing the system adapter and the codec.
The second example (DNSTester2) is advanced version of the dns client. The TTCN-3 type definitions have been rewritten so as to provide a more accurate description of DNS messages and demonstrate the capabilities of the codec generator.
Sources files for both examples are provided in the T3DevKit package.
DNSTester is described in details in Chapter 2 of An Introduction of TTCN-3[1]. This example is fully functional, however you will not be able to execute it if you do not provide a codec (for representing abstract TTCN-3 values in “real world” data, i.e. bits) and a system adapter (for communicating with the DNS server).
The syntax used for representing DNS messages is the following:
Examples of encoded DNS query and DNS answer are shown in Figures 6.1 and 6.2. They map to the following two messages used in the example.
As we can see, transforming a DNS message between our TTCN-3 model and the “real” encoded message is not a so trivial task. The DNSMessage record is a very simplified representation of the message: several fields were removed (eg. flags, authority records...) and also the remote server may perform compression of DNS names.
The task is not impossible however since all important information is available. Implementing the CoDec will mostly consist of adding extra fields when encoding and remove them when decoding.
Let us start with the definition of DNS messages given in Rfc 1035[2]. The record DNSMessage has to be mapped to a message containing 5 sections.
[ 4.1. Format ]
+---------------------+ | Header | +---------------------+ | Question | the question for the name server +---------------------+ | Answer | RRs answering the question +---------------------+ | Authority | RRs pointing toward an authority +---------------------+ | Additional | RRs holding additional information +---------------------+ |
The first section is the header. It contains two fields that can directly be mapped to the fields of DNSMessage. ID is mapped to Identification and the QR flag is mapped to messageKind. Every other field has to be filled on the fly by the codec so as to produce a valid message when encoding. The same applies for when decoding these fields must be processed.
[ 4.1.1. Header section format ]
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ID | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |QR| Opcode |AA|TC|RD|RA| Z | RCODE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QDCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ANCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | NSCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | ARCOUNT | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
Once the codec generator is lauched, the record DNSMessage is mapped to the following class:
This class...
The default behaviour of the encoder is to call successively the Encode() function of each field. In our case we will need to do some additional processing for inserting missing fields in the header (Opcode, AA, TC, RD, RA, RCODE, ...). These fields have to be inserted after the second field (messageKind).
This operation is done by defining a PostEncodeField() member function. This function is called by the decoder after having decoded any field.
This function takes two parameters: the identifier of the field that has just been encoded and a reference to the buffer we are working with.
For each field that is to be added a Unsigned class is instantiated. The first parameter is the size of the integer in bits and the second is the initial value. Then the Encode() method is called to encode the integer into the buffer.
There is a similar work to be done in the decoder, but it is a bit more complex since the number of questions and answers is not known in advance.
In addition to processing the missing header fields this functions performs three operations:
Unfortunately the definition of a codec for the four other types present in the test (Identification, MessageKind, Question and Answer) cannot be done automatically by codec generator since primitive types are not yet supported. The class declarations have to be done manually.
The integer subtype Identification in declared with the macro INTEGER_DEFINITION().
DNSTester is the defining module, Unsigned is the parent class (the other valid value is Signed) and 16 is the size of the integer in bits.
The enumeration MessageKind is defined as follows:
This field is mapped to the QR flag (one bit) in the DNS Header. It can be encoded and decoded with a Boolean variable.
The second section contains question records which are mapped to the question field. There may be several records while only one character string is present in DNSMessage, others will be ignored. The field QNAME is not encoded directly as a string, the name is split into labels which are encoded separately (possibly with compression).
[ 4.1.2. Question section format ]
1 1 1 1 1 1 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | | / QNAME / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QTYPE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | QCLASS | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
The section is mapped to the following class.
Encoding and decoding DNS names is a bit too complicated to be presented in this document. For this purpose we wrote two separate functions: encode_dns_name() and decode_dns_name(). When performing compression these functions need to know where is the starting position of the DNS message in the buffer, so a third function (set_dns_message_origin()) has been written for this purpose.
set_dns_message_origin() is called before encoding and before decoding the DNS message.
The two other functions are used in Encode() and Decode().
The third section contains resource records describing the answers. Whereas we generate queries with only one question we can get several answers in the reply, typically when the name queried is an alias (CNAME). The codec has to process every resource record and select the one that contains the final answer, i.e. the IP address of the host.
The IP address is binary encoded on 32-bit, it has to be converted into the dot notation to be presented to the test.
Also we may get answers of an unknown type. In that case the record must be skipped, knowing that the length of the resource data is given by the field RDLENGTH.
[ 4.1.3. Resource record format ]
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | | / / / NAME / | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | TYPE | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | CLASS | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | TTL | | | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ | RDLENGTH | +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--| / RDATA / / / +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
Class Answer is similar to Question. Also two functions were written for converting the IP address from and into the dot notation.
To encode the answer we need to get the dns name of the query which is present in the question. This is done by accessing the parent which is supposed to be a DNSMessage.
Decoding the answer is less straightforward. Several answers may be present and we have to select the right one (whose class is IN and type is A).
The system adapter is needed for exchanging messages between the test and the system under test by implementing the communication ports.
In TTCN-3 the port for interfacing with the recursive DNS server is defined as follows:
TODO
TODO