mirror of https://gerrit.osmocom.org/asn1c
2174 lines
77 KiB
TeX
2174 lines
77 KiB
TeX
\batchmode
|
|
\documentclass[english,oneside,12pt]{book}
|
|
\usepackage[no-math]{fontspec}
|
|
\usepackage{MnSymbol}
|
|
\usepackage{xunicode}
|
|
\usepackage{xltxtra}
|
|
|
|
\usepackage[hmargin={1in,1in},vmargin={1.5in,1.5in}]{geometry}
|
|
|
|
\defaultfontfeatures{Mapping=tex-text}
|
|
\setmainfont{PT Sans}
|
|
\setsansfont{PT Sans}
|
|
\setmonofont{Consolas}
|
|
|
|
\usepackage{fancyhdr}
|
|
\usepackage{fancyref}
|
|
\usepackage{longtable}
|
|
\usepackage{array}
|
|
\usepackage{enumitem}
|
|
\usepackage{booktabs}
|
|
\usepackage{url}
|
|
\usepackage{xcolor}
|
|
\usepackage{listings}
|
|
\usepackage{setspace}
|
|
\usepackage{unicode-math}
|
|
\usepackage{perpage}
|
|
\MakePerPage{footnote}
|
|
|
|
\setstretch{1.1}
|
|
|
|
% Courier 10 Pitch
|
|
\def\courierFont{Courier10 BT WGL4}
|
|
%\def\courierFont{Consolas}
|
|
\setmonofont[Scale=1.05]{\courierFont}
|
|
\setmathfont[Scale=1.05]{Cambria Math}
|
|
|
|
\makeatletter
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Textclass specific LaTeX commands.
|
|
\lstloadlanguages{C,bash}
|
|
\newfontfamily\listingfont[Scale=1.05]{\courierFont}
|
|
\newfontfamily\inlinelistingfont[Scale=1.05]{\courierFont}
|
|
\definecolor{clrlcomment}{gray}{0.3}
|
|
\definecolor{clrlkeyword}{rgb}{0.588,0.145,0.18}
|
|
\newcommand{\listingkeyword}[1]{\color{clrlkeyword}{#1}}
|
|
\newcommand{\listingstring}[1]{\color{clrlcomment}{#1}}
|
|
\newcommand{\listingcomment}[1]{\color{clrlcomment}{#1}}
|
|
\lstset{tabsize=4,
|
|
showstringspaces=false,
|
|
showtabs=false,
|
|
showspaces=false,
|
|
keywordstyle=\listingkeyword,
|
|
stringstyle=\listingstring,
|
|
commentstyle=\listingcomment,
|
|
xleftmargin=\parindent,
|
|
columns=fixed,
|
|
escapechar=\%,
|
|
texcl
|
|
}
|
|
\lstdefinestyle{listingStyle}{
|
|
basicstyle=\small\listingfont,
|
|
stringstyle=\listingstring,
|
|
breaklines=true,
|
|
breakatwhitespace=true,
|
|
flexiblecolumns=false
|
|
}
|
|
\lstdefinelanguage{asn1}{
|
|
morekeywords={DEFINITIONS,BEGIN,END,AUTOMATIC,TAGS,SEQUENCE,SET,OF,CHOICE,OPTIONAL,INTEGER,MAX},
|
|
morecomment=[l]{--},
|
|
morecomment=[n]{/*}{*/}
|
|
}
|
|
|
|
\lstnewenvironment{signature}[1][]{\lstset{style=listingStyle,language=C,xleftmargin=0pt,#1}}{}
|
|
\lstnewenvironment{example}[1][]{\lstset{style=listingStyle,language=C,basicstyle=\scriptsize\listingfont,#1}}{}
|
|
\lstnewenvironment{codesample}[1][]{\lstset{style=listingStyle,language=C,#1}}{}
|
|
\lstnewenvironment{bash}[1][]{\lstset{style=listingStyle,language=bash,#1}}{}
|
|
\lstnewenvironment{asn}[1][]{\lstset{style=listingStyle,language=asn1,#1}}{}
|
|
|
|
\newcommand{\apisection}[2]{\clearpage\section{\label{#1}#2}}
|
|
\newcommand{\api}[2]{\hyperref[#1]{\code{#2}}}
|
|
\newcommand{\seealso}[2]{\api{#1}{#2} at page \pageref{#1}}
|
|
\newcommand{\code}[1]{\texttt{\textbf{\lstinline{#1}}}}
|
|
\newcommand{\cmd}[1]{\texttt{#1}}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% User specified LaTeX commands.
|
|
\usepackage{extramarks}
|
|
\lhead{\firstxmark}
|
|
\rfoot{\lastxmark}
|
|
\definecolor{clrlink}{rgb}{0,0.4,0}
|
|
\definecolor{clrurl}{rgb}{0,0,.6}
|
|
\usepackage[colorlinks=true,
|
|
linkcolor={clrlink},
|
|
citecolor={clrlink},
|
|
urlcolor={clrurl},
|
|
pdfauthor={Lev Walkin},
|
|
pdftitle={Using the Open Source ASN.1 Compiler},
|
|
pdfkeywords={ASN.1,asn1c,compiler},
|
|
bookmarksopen,bookmarksopenlevel=1,
|
|
pdffitwindow,
|
|
xetex
|
|
]{hyperref}
|
|
|
|
|
|
\makeatother
|
|
|
|
\usepackage{babel}
|
|
|
|
\begin{document}
|
|
|
|
\title{Using the Open Source ASN.1 Compiler\\
|
|
\vspace*{0.4cm}
|
|
\Large Documentation for asn1c version \asnver{}}
|
|
\author{Lev Walkin <\href{mailto:vlm@lionet.info?Subject=asn1c}{vlm@lionet.info}>}
|
|
|
|
\pagestyle{fancy}
|
|
\fancyhead[L]{\leftmark}
|
|
\fancyhead[R]{\href{http://lionet.info/asn1c}{asn1c-\asnver}}
|
|
\maketitle
|
|
|
|
\tableofcontents{}
|
|
|
|
\chapter{\label{chap:Quick-start-examples}Quick start examples}
|
|
|
|
\section{A “Rectangle” converter and debugger}
|
|
|
|
One of the most common need is to create some sort of analysis tool
|
|
for the existing ASN.1 data files. Let's build a converter for existing
|
|
Rectangle binary files between BER, OER, PER, and XER (XML).
|
|
|
|
\begin{enumerate}
|
|
\item Create a file named \textbf{rectangle.asn} with the following contents:
|
|
\begin{asn}
|
|
RectangleModule DEFINITIONS ::= BEGIN
|
|
|
|
Rectangle ::= SEQUENCE {
|
|
height INTEGER,
|
|
width INTEGER
|
|
}
|
|
|
|
END
|
|
\end{asn}
|
|
|
|
\item Compile it into the set of .c and .h files using \cmd{asn1c} compiler:
|
|
|
|
\begin{bash}
|
|
asn1c -no-gen-example %\textbf{rectangle.asn}%
|
|
\end{bash}
|
|
|
|
\item Create the converter and dumper:
|
|
|
|
\begin{bash}
|
|
make -f converter-example.mk
|
|
\end{bash}
|
|
|
|
\item Done. The binary file converter is ready:
|
|
|
|
\begin{bash}
|
|
./converter-example -h
|
|
\end{bash}
|
|
\end{enumerate}
|
|
|
|
\section{A “Rectangle” Encoder}
|
|
|
|
This example will help you create a simple BER and XER encoder of
|
|
a ``Rectangle'' type used throughout this document.
|
|
\begin{enumerate}
|
|
\item Create a file named \textbf{rectangle.asn} with the following contents:
|
|
|
|
\begin{asn}
|
|
RectangleModule DEFINITIONS ::= BEGIN
|
|
|
|
Rectangle ::= SEQUENCE {
|
|
height INTEGER,
|
|
width INTEGER
|
|
}
|
|
|
|
END
|
|
\end{asn}
|
|
\item Compile it into the set of .c and .h files using asn1c compiler \cite{ASN1C}:
|
|
|
|
\begin{bash}
|
|
asn1c -no-gen-example %\textbf{rectangle.asn}%
|
|
\end{bash}
|
|
\item Alternatively, use the Online ASN.1 compiler \cite{AONL} by uploading
|
|
the \textbf{rectangle.asn} file into the Web form and unpacking the
|
|
produced archive on your computer.
|
|
\item By this time, you should have gotten multiple files in the current
|
|
directory, including the \textbf{Rectangle.c} and \textbf{Rectangle.h}.
|
|
\item Create a main() routine which creates the Rectangle\_t structure in
|
|
memory and encodes it using BER and XER encoding rules. Let's name
|
|
the file \textbf{main.c}:
|
|
|
|
\begin{example}
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <Rectangle.h> /* Rectangle ASN.1 type */
|
|
|
|
/* Write the encoded output into some FILE stream. */
|
|
static int write_out(const void *buffer, size_t size, void *app_key) {
|
|
FILE *out_fp = app_key;
|
|
size_t wrote = fwrite(buffer, 1, size, out_fp);
|
|
return (wrote == size) ? 0 : -1;
|
|
}
|
|
|
|
int main(int ac, char **av) {
|
|
Rectangle_t *rectangle; /* Type to encode */
|
|
asn_enc_rval_t ec; /* Encoder return value */
|
|
|
|
/* Allocate the Rectangle_t */
|
|
rectangle = calloc(1, sizeof(Rectangle_t)); /* must initialize to zero, not malloc! */
|
|
if(!rectangle) {
|
|
perror("calloc() failed");
|
|
exit(1);
|
|
}
|
|
|
|
/* Initialize the Rectangle members */
|
|
rectangle->height = 42; /* any random value */
|
|
rectangle->width = 23; /* any random value */
|
|
|
|
/* BER encode the data if filename is given */
|
|
if(ac < 2) {
|
|
fprintf(stderr, "Specify filename for BER output\n");
|
|
} else {
|
|
const char *filename = av[1];
|
|
FILE *fp = fopen(filename, "wb"); /* for BER output */
|
|
|
|
if(!fp) {
|
|
perror(filename);
|
|
exit(1);
|
|
}
|
|
|
|
/* Encode the Rectangle type as BER (DER) */
|
|
ec = der_encode(&asn_DEF_Rectangle, rectangle, write_out, fp);
|
|
fclose(fp);
|
|
if(ec.encoded == -1) {
|
|
fprintf(stderr, "Could not encode Rectangle (at %\%%s)\n",
|
|
ec.failed_type ? ec.failed_type->name : "unknown");
|
|
exit(1);
|
|
} else {
|
|
fprintf(stderr, "Created %\%%s with BER encoded Rectangle\n", filename);
|
|
}
|
|
}
|
|
|
|
/* Also print the constructed Rectangle XER encoded (XML) */
|
|
xer_fprint(stdout, &asn_DEF_Rectangle, rectangle);
|
|
|
|
return 0; /* Encoding finished successfully */
|
|
}
|
|
\end{example}
|
|
\item Compile all files together using C compiler (varies by platform):
|
|
|
|
\begin{bash}
|
|
cc -I. -o %\textbf{\emph{rencode}} \emph{*.c}%
|
|
\end{bash}
|
|
\item Done. You have just created the BER and XER encoder of a Rectangle
|
|
type, named \textbf{rencode}!
|
|
\end{enumerate}
|
|
|
|
\section{\label{sec:A-Rectangle-Decoder}A “Rectangle” Decoder}
|
|
|
|
This example will help you to create a simple BER decoder of a simple
|
|
``Rectangle'' type used throughout this document.
|
|
\begin{enumerate}
|
|
\item Create a file named \textbf{rectangle.asn} with the following contents:
|
|
|
|
\begin{asn}
|
|
RectangleModule DEFINITIONS ::= BEGIN
|
|
|
|
Rectangle ::= SEQUENCE {
|
|
height INTEGER,
|
|
width INTEGER
|
|
}
|
|
|
|
END
|
|
\end{asn}
|
|
\item Compile it into the set of .c and .h files using asn1c compiler \cite{ASN1C}:
|
|
|
|
\begin{bash}
|
|
asn1c -no-gen-example %\textbf{rectangle.asn}%
|
|
\end{bash}
|
|
\item Alternatively, use the Online ASN.1 compiler \cite{AONL} by uploading
|
|
the \textbf{rectangle.asn} file into the Web form and unpacking the
|
|
produced archive on your computer.
|
|
\item By this time, you should have gotten multiple files in the current
|
|
directory, including the \textbf{Rectangle.c} and \textbf{Rectangle.h}.
|
|
\item Create a main() routine which takes the binary input file, decodes
|
|
it as it were a BER-encoded Rectangle type, and prints out the text
|
|
(XML) representation of the Rectangle type. Let's name the file \textbf{main.c}:
|
|
|
|
\begin{example}
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <Rectangle.h> /* Rectangle ASN.1 type */
|
|
|
|
int main(int ac, char **av) {
|
|
char buf[1024]; /* Temporary buffer */
|
|
asn_dec_rval_t rval; /* Decoder return value */
|
|
Rectangle_t *%$\underbracket{\textrm{\listingfont rectangle = 0}}$%; /* Type to decode. %\textbf{\color{red}Note this 0\footnote{Forgetting to properly initialize the pointer to a destination structure is a major source of support requests.}!}% */
|
|
FILE *fp; /* Input file handler */
|
|
size_t size; /* Number of bytes read */
|
|
char *filename; /* Input file name */
|
|
|
|
/* Require a single filename argument */
|
|
if(ac != 2) {
|
|
fprintf(stderr, "Usage: %\%%s <file.ber>\n", av[0]);
|
|
exit(1);
|
|
} else {
|
|
filename = av[1];
|
|
}
|
|
|
|
/* Open input file as read-only binary */
|
|
fp = fopen(filename, "rb");
|
|
if(!fp) {
|
|
perror(filename);
|
|
exit(1);
|
|
}
|
|
|
|
/* Read up to the buffer size */
|
|
size = fread(buf, 1, sizeof(buf), fp);
|
|
fclose(fp);
|
|
if(!size) {
|
|
fprintf(stderr, "%\%%s: Empty or broken\n", filename);
|
|
exit(1);
|
|
}
|
|
|
|
/* Decode the input buffer as Rectangle type */
|
|
rval = ber_decode(0, &asn_DEF_Rectangle, (void **)&rectangle, buf, size);
|
|
if(rval.code != RC_OK) {
|
|
fprintf(stderr, "%\%%s: Broken Rectangle encoding at byte %\%%ld\n", filename, (long)rval.consumed);
|
|
exit(1);
|
|
}
|
|
|
|
/* Print the decoded Rectangle type as XML */
|
|
xer_fprint(stdout, &asn_DEF_Rectangle, rectangle);
|
|
|
|
return 0; /* Decoding finished successfully */
|
|
}
|
|
\end{example}
|
|
\item Compile all files together using C compiler (varies by platform):
|
|
|
|
\begin{bash}
|
|
cc -I. -o %\textbf{\emph{rdecode}} \emph{*.c}%
|
|
\end{bash}
|
|
\item Done. You have just created the BER decoder of a Rectangle type,
|
|
named \textbf{rdecode}!
|
|
\end{enumerate}
|
|
|
|
\section{Adding constraints to a “Rectangle”}
|
|
|
|
This example shows how to add basic constraints to the ASN.1 specification
|
|
and how to invoke the constraints validation code in your application.
|
|
\begin{enumerate}
|
|
|
|
\item Create a file named \textbf{rectangle.asn} with the following contents:
|
|
|
|
\begin{asn}
|
|
RectangleModuleWithConstraints DEFINITIONS ::= BEGIN
|
|
|
|
Rectangle ::= SEQUENCE {
|
|
height INTEGER (0..100), -- Value range constraint
|
|
width INTEGER (0..MAX) -- Makes width non-negative
|
|
}
|
|
|
|
END
|
|
\end{asn}
|
|
|
|
\item Compile the file according to procedures shown in \fref{sec:A-Rectangle-Decoder}.
|
|
\item Modify the Rectangle type processing routine (you can start with the
|
|
main() routine shown in the \fref{sec:A-Rectangle-Decoder})
|
|
by placing the following snippet of code \emph{before} encoding and/or
|
|
\emph{after} decoding the Rectangle type:
|
|
|
|
\begin{example}
|
|
int ret; /* Return value */
|
|
char errbuf[128]; /* Buffer for error message */
|
|
size_t errlen = sizeof(errbuf); /* Size of the buffer */
|
|
|
|
/* ... here goes the Rectangle %\emph{decoding}% code ... */
|
|
|
|
ret = asn_check_constraints(&asn_DEF_Rectangle, rectangle, errbuf, &errlen);
|
|
/* assert(errlen < sizeof(errbuf)); // you may rely on that */
|
|
if(ret) {
|
|
fprintf(stderr, "Constraint validation failed: %\%%s\n", errbuf);
|
|
/* exit(...); // Replace with appropriate action */
|
|
}
|
|
|
|
/* ... here goes the Rectangle %\emph{encoding}% code ... */
|
|
\end{example}
|
|
\item Compile the resulting C code as shown in the previous chapters.
|
|
\item Test the constraints checking code by assigning integer value
|
|
101 to the \textbf{.height} member of the Rectangle structure, or
|
|
a negative value to the \textbf{.width} member.
|
|
The program will fail with ``Constraint validation failed'' message.
|
|
\item Done.
|
|
\end{enumerate}
|
|
|
|
\chapter{ASN.1 Compiler}
|
|
|
|
\section{The asn1c compiler tool}
|
|
|
|
The purpose of the ASN.1 compiler is to convert the specifications
|
|
in ASN.1 notation into some other language, such as C.
|
|
|
|
The compiler reads the specification and emits a series of target
|
|
language structures (C structs, unions, enums) describing the corresponding
|
|
ASN.1 types. The compiler also creates the code which allows automatic
|
|
serialization and deserialization of these structures using several
|
|
standardized encoding rules (BER, DER, OER, PER, XER).
|
|
|
|
Let's take the following ASN.1 example%
|
|
\footnote{\Fref{chap:Abstract-Syntax-Notation} provides a quick reference
|
|
on the ASN.1 notation.}:
|
|
\begin{asn}
|
|
RectangleModule DEFINITIONS ::= BEGIN
|
|
|
|
Rectangle ::= SEQUENCE {
|
|
height INTEGER, -- Height of the rectangle
|
|
width INTEGER -- Width of the rectangle
|
|
}
|
|
|
|
END
|
|
\end{asn}
|
|
The asn1c compiler reads this ASN.1 definition and produce the following
|
|
C type:
|
|
\begin{codesample}
|
|
typedef struct Rectangle_s {
|
|
long height;
|
|
long width;
|
|
} Rectangle_t;
|
|
\end{codesample}
|
|
The asn1c compiler also creates the code for converting this structure into
|
|
platform-independent wire representation and the decoder
|
|
of such wire representation back into local, machine-specific type.
|
|
These encoders and decoders are also called serializers and deserializers,
|
|
marshallers and unmarshallers, or codecs.
|
|
|
|
Compiling ASN.1 modules into C codecs can be as simple as invoking \cmd{asn1c}:
|
|
may be used to compile the ASN.1 modules:
|
|
\begin{bash}
|
|
asn1c %\emph{<modules.asn>}%
|
|
\end{bash}
|
|
|
|
If several ASN.1 modules contain interdependencies, all of the files
|
|
must be specified altogether:
|
|
\begin{bash}
|
|
asn1c %\emph{<module1.asn> <module2.asn> ...}%
|
|
\end{bash}
|
|
The compiler \textbf{-E} and \textbf{-EF} options are used for testing
|
|
the parser and the semantic fixer, respectively. These options will
|
|
instruct the compiler to dump out the parsed (and fixed, if \textbf{-F}
|
|
is involved) ASN.1 specification as it was understood
|
|
by the compiler. It might be useful to check whether a particular
|
|
syntactic construct is properly supported by the compiler.
|
|
\begin{bash}
|
|
asn1c %\textbf{-EF} \emph{<module-to-test.asn>}%
|
|
\end{bash}
|
|
The \textbf{-P} option is used to dump the compiled output on the
|
|
screen instead of creating a bunch of .c and .h files on disk in the
|
|
current directory. You would probably want to start with \textbf{-P}
|
|
option instead of creating a mess in your current directory. Another
|
|
option, \textbf{-R}, asks compiler to only generate the files which
|
|
need to be generated, and supress linking in the numerous support
|
|
files.
|
|
|
|
Print the compiled output instead of creating multiple source files:
|
|
\begin{bash}
|
|
asn1c %\textbf{-P} \emph{<module-to-compile-and-print.asn>}%
|
|
\end{bash}
|
|
|
|
\clearpage{}
|
|
\section{Compiler output}
|
|
|
|
The \cmd{asn1c} compiler produces a number of files:
|
|
\begin{itemize}
|
|
\item A set of .c and .h files for each type defined
|
|
in the ASN.1 specification. These files will be named similarly to
|
|
the ASN.1 types (\textbf{Rectangle.c} and \textbf{Rectangle.h} for the
|
|
RectangleModule ASN.1 module defined in the beginning of this document).
|
|
\item A set of helper .c and .h files which contain the generic encoders,
|
|
decoders and other useful routines.
|
|
Sometimes they are referred to by the term \emph{skeletons}.
|
|
There will be quite a few of them, some
|
|
of them are not even always necessary, but the overall amount of code
|
|
after compilation will be rather small anyway.
|
|
\item A \textbf{Makefile.am.libasncodecs} file which explicitly lists all the
|
|
generated files.
|
|
This makefile can be used on its own to build the just the codec library.
|
|
\item A \textbf{converter-example.c} file containing the \emph{int main()} function with a fully functioning encoder and data format converter. It can convert a given PDU between BER, XER, OER and PER. At some point you will want to replace this file with your own file containing the \emph{int main()} function.
|
|
\item A \textbf{converter-example.mk} file which binds together
|
|
\textbf{Makefile.am.libasncodecs} and \textbf{converter-example.c}
|
|
to build a versatile converter and debugger for your data formats.
|
|
\end{itemize}
|
|
It is possible to compile everything with just a couple of instructions:
|
|
\begin{bash}
|
|
asn1c -pdu=%\emph{Rectangle}% *.asn
|
|
make -f converter-example.mk # If you use `make`
|
|
\end{bash}
|
|
or
|
|
\begin{bash}
|
|
asn1c *.asn
|
|
cc -I. -DPDU=%\emph{Rectangle}% -o rectangle.exe *.c # ... or like this
|
|
\end{bash}
|
|
Refer to the \fref{chap:Quick-start-examples} for a sample
|
|
\emph{int main()} function if you want some custom logic and not satisfied
|
|
with the supplied \emph{converter-example.c}.
|
|
|
|
\clearpage{}
|
|
\section{\label{sec:Command-line-options}Command line options}
|
|
|
|
The following table summarizes the \cmd{asn1c} command line options.
|
|
|
|
\renewcommand{\arraystretch}{1.33}
|
|
\begin{longtable}{lp{4in}}
|
|
\textbf{Stage Selection Options} & \textbf{Description}\\
|
|
\midrule
|
|
{\ttfamily -E} & {\small Stop after the parsing stage and print the reconstructed ASN.1
|
|
specification code to the standard output.}\\
|
|
{\ttfamily -F} & {\small Used together with \texttt{-E}, instructs the compiler to stop after
|
|
the ASN.1 syntax tree fixing stage and dump the reconstructed ASN.1
|
|
specification to the standard output.}\\
|
|
{\ttfamily -P} & {\small Dump the compiled output to the standard output instead of
|
|
creating the target language files on disk.}\\
|
|
{\ttfamily -R} & {\small Restrict the compiler to generate only the ASN.1 tables, omitting the usual support code.}\\
|
|
{\ttfamily -S~\emph{<directory>}} & {\small Use the specified directory with ASN.1 skeleton files.}\\
|
|
{\ttfamily -X} & {\small Generate the XML DTD for the specified ASN.1 modules.}\\\\
|
|
\textbf{Warning Options} & \textbf{Description}\\
|
|
\midrule
|
|
{\ttfamily -Werror} & {\small Treat warnings as errors; abort if any warning is produced.}\\
|
|
{\ttfamily -Wdebug-parser} & {\small Enable the parser debugging during the ASN.1 parsing stage.}\\
|
|
{\ttfamily -Wdebug-lexer} & {\small Enable the lexer debugging during the ASN.1 parsing stage.}\\
|
|
{\ttfamily -Wdebug-fixer} & {\small Enable the ASN.1 syntax tree fixer debugging during the fixing stage.}\\
|
|
{\ttfamily -Wdebug-compiler} & {\small Enable debugging during the actual compile time.}\\ \\
|
|
\textbf{Language Options} & \textbf{Description}\\
|
|
\midrule
|
|
{\ttfamily -fbless-SIZE} & {\small Allow SIZE() constraint for INTEGER, ENUMERATED, and other types for which this constraint is normally prohibited by the standard.
|
|
This is a violation of an ASN.1 standard and compiler may fail to produce the meaningful code.}\\
|
|
{\ttfamily -fcompound-names} & {\small Use complex names for C structures. Using complex names prevents
|
|
name clashes in case the module reuses the same identifiers in multiple
|
|
contexts.}\\
|
|
{\ttfamily -findirect-choice} & {\small When generating code for a CHOICE type, compile the CHOICE
|
|
members as indirect pointers instead of declaring them inline. Consider
|
|
using this option together with \texttt{-fno-include-deps}
|
|
to prevent circular references.}\\
|
|
{\ttfamily -fincludes-quoted} & {\small Generate \#include lines in "double" instead of <angle> quotes.}\\
|
|
{\ttfamily -fknown-extern-type=\emph{<name>}} & {\small Pretend the specified type is known. The compiler will assume
|
|
the target language source files for the given type have been provided
|
|
manually. }\\
|
|
{\ttfamily -fline-refs} & {\small Include ASN.1 module's line numbers in generated code comments.}\\
|
|
{\ttfamily -fno-constraints} & {\small Do not generate the ASN.1 subtype constraint checking code. This
|
|
may produce a shorter executable.}\\
|
|
{\ttfamily -fno-include-deps} & {\small Do not generate the courtesy \#include lines for non-critical dependencies.}\\
|
|
{\ttfamily -funnamed-unions} & {\small Enable unnamed unions in the definitions of target language's structures.}\\
|
|
{\ttfamily -fwide-types} & {\small Use the wide integer types (INTEGER\_t, REAL\_t) instead of machine's native data types (long, double). }\\\\
|
|
\textbf{Codecs Generation Options} & \textbf{Description}\\
|
|
\midrule
|
|
{\ttfamily -no-gen-OER} & {\small Do not generate the Octet Encoding Rules (OER, X.696) support code.}\\
|
|
{\ttfamily -no-gen-PER} & {\small Do not generate the Packed Encoding Rules (PER, X.691) support code.}\\
|
|
{\ttfamily -no-gen-example} & {\small Do not generate the ASN.1 format converter example.}\\
|
|
{\ttfamily -pdu=\{\textbf{all}|\textbf{auto}|\emph{Type}\}} & {\small Create a PDU table for specified types, or discover the Protocol Data Units automatically.
|
|
In case of \texttt{-pdu=\textbf{all}}, all ASN.1 types defined in all modules wil form a PDU table. In case of \texttt{-pdu=\textbf{auto}}, all types not referenced by any other type will form a PDU table. If \texttt{\emph{Type}} is an ASN.1 type identifier, it is added to a PDU table. The last form may be specified multiple times.}\\ \\
|
|
\textbf{Output Options} & \textbf{Description}\\
|
|
\midrule
|
|
{\ttfamily -print-class-matrix} & {\small When \texttt{-EF} options are given, this option instructs the compiler to print out the collected Information Object Class matrix.}\\
|
|
{\ttfamily -print-constraints} & {\small With \texttt{-EF}, this option instructs the compiler
|
|
to explain its internal understanding of subtype constraints.}\\
|
|
{\ttfamily -print-lines} & {\small Generate \texttt{``-{}- \#line''} comments
|
|
in \texttt{-E} output.}\\
|
|
\end{longtable}
|
|
\renewcommand{\arraystretch}{1}
|
|
|
|
|
|
\chapter{API reference}
|
|
|
|
The functions desribed in this chapter are to be used by the application
|
|
programmer. These functions won't likely change change or get removed until
|
|
the next major release.
|
|
|
|
The API calls not listed here are not public and should not be used by the
|
|
application level code.
|
|
|
|
\apisection{sec:ASN_STRUCT_FREE}{ASN\_STRUCT\_FREE() macro}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
#define ASN_STRUCT_FREE(type_descriptor, struct_ptr)
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
Recursively releases memory occupied by the structure
|
|
described by the \code{type\_descriptor} and referred to
|
|
by the \code{struct\_ptr} pointer.
|
|
|
|
Does nothing when \code{struct\_ptr} is NULL.
|
|
|
|
\subsection*{Return values}
|
|
Does not return a value.
|
|
|
|
\subsection*{Example}
|
|
|
|
\begin{example}
|
|
Rectangle_t *rect = ...;
|
|
ASN_STRUCT_FREE(asn_DEF_Rectangle, rect);
|
|
\end{example}
|
|
|
|
\apisection{sec:ASN_STRUCT_RESET}{ASN\_STRUCT\_RESET() macro}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
#define ASN_STRUCT_RESET(type_descriptor, struct_ptr)
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
Recursively releases memory occupied by the members of the structure
|
|
described by the \code{type\_descriptor} and referred to
|
|
by the \code{struct\_ptr} pointer.
|
|
|
|
Does not release the memory pointed to by \code{struct\_ptr} itself.
|
|
Instead it clears the memory block by filling it out with 0 bytes.
|
|
|
|
Does nothing when \code{struct\_ptr} is NULL.
|
|
|
|
\subsection*{Return values}
|
|
Does not return a value.
|
|
|
|
\subsection*{Example}
|
|
|
|
\begin{example}
|
|
struct my_figure { /* The custom structure */
|
|
int flags; /* <some custom member> */
|
|
/* The type is generated by the ASN.1 compiler */
|
|
Rectangle_t rect;
|
|
/* other members of the structure */
|
|
};
|
|
|
|
struct my_figure *fig = ...;
|
|
ASN_STRUCT_RESET(asn_DEF_Rectangle, &fig->rect);
|
|
\end{example}
|
|
|
|
\apisection{sec:asn_check_constraints}{asn\_check\_constraints()}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
int asn_check_constraints(
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
const void *struct_ptr, /* Target language's structure */
|
|
char *errbuf, /* Returned error description */
|
|
size_t *errlen /* Length of the error description */
|
|
);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
Validate a given structure according to the ASN.1 constraints.
|
|
If \code{errbuf} and \code{errlen} are given, they shall point to the
|
|
appropriate buffer space and its length before calling this function.
|
|
Alternatively, they could be passed as \code{NULL}s.
|
|
If constraints validation fails, \code{errlen} will contain the actual
|
|
number of bytes used in \code{errbuf} to encode an error message.
|
|
The message is going to be properly 0-terminated.
|
|
|
|
\subsection*{Return values}
|
|
|
|
This function returns 0 in case all ASN.1 constraints are met
|
|
and -1 if one or more ASN.1 constraints were violated.
|
|
|
|
\subsection*{Example}
|
|
|
|
\begin{codesample}[basicstyle=\scriptsize\listingfont]
|
|
Rectangle_t *rect = ...;
|
|
|
|
char errbuf[128]; /* Buffer for error message */
|
|
size_t errlen = sizeof(errbuf); /* Size of the buffer */
|
|
|
|
int ret = asn_check_constraints(&asn_DEF_Rectangle, rectangle, errbuf, &errlen);
|
|
/* assert(errlen < sizeof(errbuf)); // Guaranteed: you may rely on that */
|
|
if(ret) {
|
|
fprintf(stderr, "Constraint validation failed: %\%%s\n", errbuf);
|
|
}
|
|
\end{codesample}
|
|
|
|
\apisection{sec:asn_decode}{asn\_decode()}
|
|
|
|
\subsection*{Synopsis}
|
|
\begin{signature}
|
|
asn_dec_rval_t asn_decode(
|
|
const asn_codec_ctx_t *opt_codec_ctx,
|
|
enum asn_transfer_syntax syntax,
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
|
|
const void *buffer, /* Data to be decoded */
|
|
size_t size /* Size of that buffer */
|
|
);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
The \code{asn\_decode()} function parses the data given by the \code{buffer}
|
|
and \code{size} arguments. The encoding rules are specified in the \code{syntax}
|
|
argument and the type to be decoded is specified by the \code{type_descriptor}.
|
|
|
|
The \code{struct_ptr_ptr} must point to the memory location which contains the
|
|
pointer to the structure being decoded. Initially the \code{*struct_ptr_ptr}
|
|
pointer is typically set to 0. In that case, \code{asn\_decode()} will
|
|
dynamically allocate memory for the structure and its members as needed
|
|
during the parsing.
|
|
If \code{*struct\_ptr\_ptr} already points to some memory, the \code{asn\_decode()}
|
|
will allocate the subsequent members as needed during the parsing.
|
|
|
|
\subsection*{Return values}
|
|
|
|
\input{asn_dec_rval.inc}
|
|
|
|
The \code{.consumed} value is in bytes, even for PER decoding.
|
|
For PER, use \code{uper\_decode()} in case you need to get
|
|
the number of consumed bits.
|
|
|
|
\subsection*{Restartability}
|
|
|
|
Some transfer syntax parsers (such as ATS\_BER) support restartability.
|
|
|
|
That means that in case the buffer has less data than expected,
|
|
the \code{asn_decode()} will process whatever is available and ask for more
|
|
data to be provided using the RC\_WMORE return \code{.code}.
|
|
|
|
Note that in the RC\_WMORE case the decoder may have processed less data than
|
|
it is available in the buffer, which means that you must be able to arrange
|
|
the next buffer to contain the unprocessed part of the previous buffer.
|
|
|
|
The \code{RC_WMORE} code may still be returned by parser not supporting
|
|
restartabilty. In such cases, the partially decoded structure shall be
|
|
discarded and the next invocation should use the extended buffer to parse
|
|
from the very beginning.
|
|
|
|
\subsection*{Example}
|
|
|
|
\begin{example}
|
|
Rectangle_t *%$\underbracket{\textrm{\listingfont rect = 0}}$%; /* %\textbf{\color{red}Note this 0\footnote{Forgetting to properly initialize the pointer to a destination structure is a major source of support requests.}!}% */
|
|
asn_dec_rval_t rval;
|
|
rval = asn_decode(0, ATS_BER, &asn_DEF_Rectangle, (void **)&rect, buffer, buf_size);
|
|
switch(rval.code) {
|
|
case RC_OK:
|
|
asn_fprint(stdout, &asn_DEF_Rectangle, rect);
|
|
ASN_STRUCT_FREE(&asn_DEF_Rectangle, rect);
|
|
break;
|
|
case RC_WMORE:
|
|
case RC_FAIL:
|
|
default:
|
|
ASN_STRUCT_FREE(&asn_DEF_Rectangle, rect);
|
|
break;
|
|
}
|
|
\end{example}
|
|
|
|
\subsection*{See also}
|
|
\seealso{sec:asn_fprint}{asn_fprint()}.
|
|
|
|
\apisection{sec:asn_encode}{asn\_encode()}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
#include <asn_application.h>
|
|
|
|
asn_enc_rval_t asn_encode(
|
|
const asn_codec_ctx_t *opt_codec_ctx,
|
|
enum asn_transfer_syntax syntax,
|
|
const asn_TYPE_descriptor_t *type_to_encode,
|
|
const void *structure_to_encode,
|
|
asn_app_consume_bytes_f *callback, void *callback_key);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
The \code{asn_encode()} function serializes the given \code{structure_to_encode} using the chosen ASN.1 transfer \code{syntax}.
|
|
|
|
During serialization, a user-specified \code{callback} is invoked zero
|
|
or more times with bytes of data to add to the output stream (if any), and
|
|
the \code{callback_key}. The signature for the callback is as follows:
|
|
|
|
\begin{signature}
|
|
typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size, void *callback_key);
|
|
\end{signature}
|
|
|
|
\subsection*{Return values}
|
|
\input{asn_enc_rval.inc}
|
|
|
|
The serialized output size is returned in \textbf{bytes} irrespectively of the
|
|
ASN.1 transfer \code{syntax} chosen.\footnote{This is different from some
|
|
lower level encoding functions, such as \api{sec:uper_encode}{uper_encode()},
|
|
which returns the number of encoded \emph{bits} instead of bytes.}
|
|
|
|
On error (when \code{.encoded} is set to -1),
|
|
the \code{errno} is set to one of the following values:
|
|
|
|
\begin{tabular}[h!]{ll}
|
|
\texttt{EINVAL} & Incorrect parameters to the function, such as NULLs \\
|
|
\texttt{ENOENT} & Encoding transfer syntax is not defined (for this type) \\
|
|
\texttt{EBADF} & The structure has invalid form or content constraint failed \\
|
|
\texttt{EIO} & The callback has returned negative value during encoding
|
|
\end{tabular}
|
|
|
|
\subsection*{Example}
|
|
\begin{example}
|
|
static int
|
|
save_to_file(const void *data, size_t size, void *key) {
|
|
FILE *fp = key;
|
|
return (fwrite(data, 1, size, fp) == size) ? 0 : -1;
|
|
}
|
|
|
|
Rectangle_t *rect = ...;
|
|
FILE *fp = ...;
|
|
asn_enc_rval_t er;
|
|
er = asn_encode(0, ATS_DER, &asn_DEF_Rectangle, rect, save_to_file, fp);
|
|
if(er.encoded == -1) {
|
|
fprintf(stderr, "Failed to encode %\%%s\n", asn_DEF_Rectangle.name);
|
|
} else {
|
|
fprintf(stderr, "%\%%s encoded in %\%%zd bytes\n", asn_DEF_Rectangle.name, er.encoded);
|
|
}
|
|
\end{example}
|
|
|
|
\apisection{sec:asn_encode_to_buffer}{asn\_encode\_to\_buffer()}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
#include <asn_application.h>
|
|
|
|
asn_enc_rval_t asn_encode_to_buffer(
|
|
const asn_codec_ctx_t *opt_codec_ctx,
|
|
enum asn_transfer_syntax syntax,
|
|
const asn_TYPE_descriptor_t *type_to_encode,
|
|
const void *structure_to_encode,
|
|
void *buffer, size_t buffer_size);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
The \code{asn_encode_to_buffer()} function serializes the given \code{structure_to_encode} using the chosen ASN.1 transfer \code{syntax}.
|
|
|
|
The function places the serialized data into the given
|
|
\code{buffer} of size \code{buffer_size}.
|
|
|
|
\subsection*{Return values}
|
|
\input{asn_enc_rval.inc}
|
|
|
|
The serialized output size is returned in \textbf{bytes} irrespectively of the
|
|
ASN.1 transfer \code{syntax} chosen.\footnote{This is different from some
|
|
lower level encoding functions, such as \api{sec:uper_encode}{uper_encode()},
|
|
which returns the number of encoded \emph{bits} instead of bytes.}
|
|
|
|
If \code{.encoded} size exceeds the specified \code{buffer_size},
|
|
the serialization effectively failed due to insufficient space. The function
|
|
will succeed if subsequently called with buffer size no less than the returned
|
|
\code{.encoded} size. This behavior modeled after \code{snprintf()}.
|
|
|
|
On error (when \code{.encoded} is set to -1),
|
|
the \code{errno} is set to one of the following values:
|
|
|
|
\begin{tabular}[h!]{ll}
|
|
\texttt{EINVAL} & Incorrect parameters to the function, such as NULLs \\
|
|
\texttt{ENOENT} & Encoding transfer syntax is not defined (for this type) \\
|
|
\texttt{EBADF} & The structure has invalid form or content constraint failed
|
|
\end{tabular}
|
|
|
|
\subsection*{Example}
|
|
\begin{example}
|
|
Rectangle_t *rect = ...;
|
|
uint8_t buffer[128];
|
|
asn_enc_rval_t er;
|
|
er = asn_encode_to_buffer(0, ATS_DER, &asn_DEF_Rectangle, rect, buffer, sizeof(buffer));
|
|
if(er.encoded == -1) {
|
|
fprintf(stderr, "Serialization of %\%%s failed.\n", asn_DEF_Rectangle.name);
|
|
} else if(er.encoded > sizeof(buffer)) {
|
|
fprintf(stderr, "Buffer of size %\%%zu is too small for %\%%s, need %\%%zu\n",
|
|
buf_size, asn_DEF_Rectangle.name, er.encoded);
|
|
}
|
|
\end{example}
|
|
|
|
\subsection*{See also}
|
|
\seealso{sec:asn_encode_to_new_buffer}{asn_encode_to_new_buffer()}.
|
|
|
|
\apisection{sec:asn_encode_to_new_buffer}{asn\_encode\_to\_new\_buffer()}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
#include <asn_application.h>
|
|
|
|
typedef struct {
|
|
void *buffer; /* NULL if failed to encode. */
|
|
asn_enc_rval_t result;
|
|
} asn_encode_to_new_buffer_result_t;
|
|
asn_encode_to_new_buffer_result_t asn_encode_to_new_buffer(
|
|
const asn_codec_ctx_t *opt_codec_ctx,
|
|
enum asn_transfer_syntax syntax,
|
|
const asn_TYPE_descriptor_t *type_to_encode,
|
|
const void *structure_to_encode);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
The \code{asn_encode_to_new_buffer()} function serializes the given \code{structure_to_encode} using the chosen ASN.1 transfer \code{syntax}.
|
|
|
|
The function places the serialized data into the newly allocated buffer
|
|
which it returns in a compound structure.
|
|
|
|
\subsection*{Return values}
|
|
|
|
On failure, the \code{.buffer} is set to \code{NULL}
|
|
and \code{.result.encoded} is set to -1. The global \code{errno} is set
|
|
to one of the following values:
|
|
|
|
\begin{tabular}[h!]{ll}
|
|
\texttt{EINVAL} & Incorrect parameters to the function, such as NULLs \\
|
|
\texttt{ENOENT} & Encoding transfer syntax is not defined (for this type) \\
|
|
\texttt{EBADF} & The structure has invalid form or content constraint failed \\
|
|
\texttt{ENOMEM} & Memory allocation failed due to system or internal limits
|
|
\end{tabular}
|
|
|
|
\noindent{}On success, the \code{.result.encoded} is set to the number of
|
|
\textbf{bytes} that it took to serialize the structure.
|
|
The \code{.buffer} contains the serialized content.
|
|
The user is responsible for freeing the \code{.buffer}.
|
|
|
|
\subsection*{Example}
|
|
\begin{example}
|
|
asn_encode_to_new_buffer_result_t res;
|
|
res = asn_encode_to_new_buffer(0, ATS_DER, &asn_DEF_Rectangle, rect);
|
|
if(res.buffer) {
|
|
/* Encoded successfully. */
|
|
free(res.buffer);
|
|
} else {
|
|
fprintf(stderr, "Failed to encode %\%%s, estimated %\%%zd bytes\n",
|
|
asn_DEF_Rectangle.name, res.result.encoded);
|
|
}
|
|
\end{example}
|
|
|
|
\subsection*{See also}
|
|
\seealso{sec:asn_encode_to_buffer}{asn_encode_to_buffer()}.
|
|
|
|
\apisection{sec:asn_fprint}{asn\_fprint()}
|
|
|
|
\subsection*{Synopsis}
|
|
\begin{signature}
|
|
int asn_fprint(FILE *stream, /* Destination file */
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
const void *struct_ptr /* Structure to be printed */
|
|
);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
The \code{asn_fprint()} function prints human readable description
|
|
of the target language's structure into the file stream specified by
|
|
\code{stream} pointer.
|
|
|
|
The output format does not conform to any standard.
|
|
|
|
The \code{asn_fprint()} function attempts to
|
|
produce a valid output even for incomplete and broken structures, which
|
|
makes it more suitable for debugging complex cases than
|
|
\api{sec:xer_fprint}{xer_fprint()}.
|
|
|
|
\subsection*{Return values}
|
|
|
|
\begin{tabular}[h!]{rl}
|
|
0 & Output was successfully made \\
|
|
-1 & Error printing out the structure
|
|
\end{tabular}
|
|
|
|
\subsection*{Example}
|
|
\begin{example}
|
|
Rectangle_t *rect = ...;
|
|
asn_fprint(stdout, &asn_DEF_Rectangle, rect);
|
|
\end{example}
|
|
|
|
\subsection*{See also}
|
|
\seealso{sec:xer_fprint}{xer_fprint()}.
|
|
|
|
\apisection{sec:asn_random_fill}{asn\_random\_fill()}
|
|
|
|
\subsection*{Synopsis}
|
|
\begin{signature}
|
|
int asn_random_fill(
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
|
|
size_t approx_max_length_limit
|
|
);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
Create or initialize a structure with random contents, according to the type
|
|
specification and optional member constraints.
|
|
|
|
For best results the code should be generated without \cmd{-no-gen-PER}
|
|
option to \cmd{asn1c}. Making PER constraints code available in runtime
|
|
will make \code{asn_random_fill} explore the edges of PER-visible constraints
|
|
and sometimes break out of extensible contstraints' ranges.
|
|
|
|
The \code{asn_random_fill()} function has a bias to generate edge case
|
|
values. This property makes it useful for debugging the application level
|
|
code and for security testing, as random data can be a good seed to fuzzing.
|
|
|
|
The \code{approx_max_length_limit} specifies the approximate limit of the
|
|
resulting structure in units closely resembling bytes. The actual result
|
|
might be several times larger or smaller than the given length limit.
|
|
A rule of thumb way to select the initial value for this parameter
|
|
is to take a typical structure and use twice its DER output size.
|
|
|
|
\subsection*{Return values}
|
|
|
|
\begin{tabular}[h!]{rl}
|
|
0 & Structure was properly initialized with random data \\
|
|
-1 & Failure to initialize the structure with random data
|
|
\end{tabular}
|
|
|
|
\apisection{sec:ber_decode}{ber\_decode()}
|
|
|
|
\subsection*{Synopsis}
|
|
\begin{signature}
|
|
asn_dec_rval_t ber_decode(
|
|
const asn_codec_ctx_t *opt_codec_ctx,
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
|
|
const void *buffer, /* Data to be decoded */
|
|
size_t size /* Size of that buffer */
|
|
);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
Decode BER, DER and CER data
|
|
(Basic Encoding Rules, Distinguished Encoding Rules, Canonical Encoding Rules),
|
|
as defined by ITU-T~X.690.
|
|
|
|
DER and CER are different subsets of BER.\newline
|
|
|
|
\noindent\emph{Consider using a more generic function \api{sec:asn_decode}{asn_decode(ATS_BER)}.}
|
|
|
|
\subsection*{Return values}
|
|
\input{asn_dec_rval.inc}
|
|
|
|
The \code{.consumed} value is in bytes.
|
|
|
|
\subsection*{Restartability}
|
|
|
|
The \code{ber_decode()} function is restartable (stream-oriented).
|
|
That means that in case the buffer has less data than expected,
|
|
the decoder will process whatever is available and ask for more data
|
|
to be provided using the RC\_WMORE return \code{.code}.
|
|
|
|
Note that in the RC\_WMORE case the decoder may have processed less data than
|
|
it is available in the buffer, which means that you must be able to arrange
|
|
the next buffer to contain the unprocessed part of the previous buffer.
|
|
|
|
\subsection*{See also}
|
|
\seealso{sec:der_encode}{der_encode()}.
|
|
|
|
\apisection{sec:der_encode}{der\_encode}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
asn_enc_rval_t der_encode(
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
const void *structure_to_encode,
|
|
asn_app_consume_bytes_f *callback,
|
|
void *callback_key
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
The \code{der_encode()} function serializes the given \code{structure_to_encode} using the DER transfer syntax (a variant of BER, Basic Encoding Rules).
|
|
|
|
During serialization, a user-specified \code{callback} is invoked zero
|
|
or more times with bytes of data to add to the output stream (if any), and
|
|
the \code{callback_key}. The signature for the callback is as follows:
|
|
|
|
\begin{signature}
|
|
typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size, void *callback_key);
|
|
\end{signature}
|
|
|
|
\noindent\emph{Consider using a more generic function \api{sec:asn_encode}{asn_encode(ATS_DER)}.}
|
|
|
|
\subsection*{Return values}
|
|
\input{asn_enc_rval.inc}
|
|
|
|
The serialized output size is returned in \textbf{bytes}.
|
|
|
|
\subsection*{Example}
|
|
\begin{example}
|
|
static int
|
|
save_to_file(const void *data, size_t size, void *key) {
|
|
FILE *fp = key;
|
|
return (fwrite(data, 1, size, fp) == size) ? 0 : -1;
|
|
}
|
|
|
|
Rectangle_t *rect = ...;
|
|
FILE *fp = ...;
|
|
asn_enc_rval_t er;
|
|
er = der_encode(&asn_DEF_Rectangle, rect, save_to_file, fp);
|
|
if(er.encoded == -1) {
|
|
fprintf(stderr, "Failed to encode %\%%s\n", asn_DEF_Rectangle.name);
|
|
} else {
|
|
fprintf(stderr, "%\%%s encoded in %\%%zd bytes\n", asn_DEF_Rectangle.name, er.encoded);
|
|
}
|
|
\end{example}
|
|
|
|
\subsection*{See also}
|
|
\seealso{sec:ber_decode}{ber_decode()},
|
|
\seealso{sec:asn_decode}{asn_decode(ATS_BER)}.
|
|
|
|
\apisection{sec:der_encode_to_buffer}{der\_encode\_to\_buffer()}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
asn_enc_rval_t der_encode_to_buffer(
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
const void *structure_to_encode,
|
|
void *buffer, size_t buffer_size);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
The \code{der_encode_to_buffer()} function serializes the given \code{structure_to_encode} using the DER transfer syntax (a variant of BER, Basic Encoding Rules).
|
|
|
|
The function places the serialized data into the given
|
|
\code{buffer} of size \code{buffer_size}.\newline
|
|
|
|
\noindent\emph{Consider using a more generic function \api{sec:asn_encode_to_buffer}{asn_encode_to_buffer(ATS_DER)}.}
|
|
|
|
\subsection*{Return values}
|
|
\input{asn_enc_rval.inc}
|
|
|
|
The serialized output size is returned in \textbf{bytes}.
|
|
|
|
The \code{.encoded} never exceeds the available buffer size.\footnote{This
|
|
behavior is different from \api{sec:asn_encode_to_buffer}{asn_encode_to_buffer()}.}
|
|
If the \code{buffer_size} is not sufficient, the \code{.encoded}
|
|
will be set to -1 and encoding would fail.
|
|
|
|
\subsection*{Example}
|
|
\begin{example}
|
|
Rectangle_t *rect = ...;
|
|
uint8_t buffer[128];
|
|
asn_enc_rval_t er;
|
|
er = der_encode_to_buffer(&asn_DEF_Rectangle, rect, buffer, sizeof(buffer));
|
|
if(er.encoded == -1) {
|
|
fprintf(stderr, "Serialization of %\%%s failed.\n", asn_DEF_Rectangle.name);
|
|
}
|
|
\end{example}
|
|
|
|
\subsection*{See also}
|
|
\seealso{sec:ber_decode}{ber_decode()},
|
|
\seealso{sec:asn_decode}{asn_decode(ATS_BER)},
|
|
\seealso{sec:asn_encode_to_buffer}{asn_encode_to_buffer(ATS_DER)}.
|
|
|
|
\apisection{sec:oer_decode}{oer\_decode()}
|
|
|
|
\subsection*{Synopsis}
|
|
\begin{signature}
|
|
asn_dec_rval_t oer_decode(
|
|
const asn_codec_ctx_t *opt_codec_ctx,
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
|
|
const void *buffer, /* Data to be decoded */
|
|
size_t size /* Size of that buffer */
|
|
);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
Decode the BASIC-OER and CANONICAL-OER (Octet Encoding Rules),
|
|
as defined by ITU-T~X.696.\newline
|
|
|
|
\noindent\emph{Consider using a more generic function \api{sec:asn_decode}{asn_decode(ATS_BASIC_OER)}.}
|
|
|
|
\subsection*{Return values}
|
|
\input{asn_dec_rval.inc}
|
|
|
|
The \code{.consumed} value is in bytes.
|
|
|
|
\subsection*{Restartability}
|
|
|
|
The \code{oer_decode()} function is restartable (stream-oriented).
|
|
That means that in case the buffer has less data than expected,
|
|
the decoder will process whatever is available and ask for more data
|
|
to be provided using the RC\_WMORE return \code{.code}.
|
|
|
|
Note that in the RC\_WMORE case the decoder may have processed less data than
|
|
it is available in the buffer, which means that you must be able to arrange
|
|
the next buffer to contain the unprocessed part of the previous buffer.
|
|
|
|
\apisection{sec:oer_encode}{oer\_encode()}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
asn_enc_rval_t oer_encode(
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
const void *structure_to_encode,
|
|
asn_app_consume_bytes_f *callback,
|
|
void *callback_key);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
The \code{oer_encode()} function serializes the given \code{structure_to_encode} using the CANONICAL-OER transfer syntax (Octet Encoding Rules, ITU-T~X.691).
|
|
|
|
During serialization, a user-specified \code{callback} is invoked zero
|
|
or more times with bytes of data to add to the output stream (if any), and
|
|
the \code{callback_key}. The signature for the callback is as follows:
|
|
|
|
\begin{signature}
|
|
typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size, void *callback_key);
|
|
\end{signature}
|
|
|
|
\noindent\emph{Consider using a more generic function \api{sec:asn_encode}{asn_encode(ATS_CANONICAL_OER)}.}
|
|
|
|
\subsection*{Return values}
|
|
\input{asn_enc_rval.inc}
|
|
|
|
The serialized output size is returned in \textbf{bytes}.
|
|
|
|
\subsection*{Example}
|
|
\begin{example}
|
|
static int
|
|
save_to_file(const void *data, size_t size, void *key) {
|
|
FILE *fp = key;
|
|
return (fwrite(data, 1, size, fp) == size) ? 0 : -1;
|
|
}
|
|
|
|
Rectangle_t *rect = ...;
|
|
FILE *fp = ...;
|
|
asn_enc_rval_t er;
|
|
er = oer_encode(&asn_DEF_Rectangle, rect, save_to_file, fp);
|
|
if(er.encoded == -1) {
|
|
fprintf(stderr, "Failed to encode %\%%s\n", asn_DEF_Rectangle.name);
|
|
} else {
|
|
fprintf(stderr, "%\%%s encoded in %\%%zd bytes\n", asn_DEF_Rectangle.name, er.encoded);
|
|
}
|
|
\end{example}
|
|
|
|
\subsection*{See also}
|
|
\seealso{sec:asn_encode}{asn_encode(ATS_CANONICAL_OER)}.
|
|
|
|
\apisection{sec:oer_encode_to_buffer}{oer\_encode\_to\_buffer()}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
asn_enc_rval_t oer_encode_to_buffer(
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
const asn_oer_constraints_t *constraints,
|
|
const void *structure_to_encode,
|
|
void *buffer, size_t buffer_size);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
The \code{oer_encode_to_buffer()} function serializes the given \code{structure_to_encode} using the CANONICAL-OER transfer syntax (Octet Encoding Rules, ITU-T~X.691).
|
|
|
|
The function places the serialized data into the given
|
|
\code{buffer} of size \code{buffer_size}.\newline
|
|
|
|
\noindent\emph{Consider using a more generic function \api{sec:asn_encode_to_buffer}{asn_encode_to_buffer(ATS_CANONICAL_OER)}.}
|
|
|
|
\subsection*{Return values}
|
|
\input{asn_enc_rval.inc}
|
|
|
|
The serialized output size is returned in \textbf{bytes}.
|
|
|
|
The \code{.encoded} never exceeds the available buffer size.\footnote{This
|
|
behavior is different from \api{sec:asn_encode_to_buffer}{asn_encode_to_buffer()}.}
|
|
If the \code{buffer_size} is not sufficient, the \code{.encoded}
|
|
will be set to -1 and encoding would fail.
|
|
|
|
\subsection*{Example}
|
|
\begin{example}
|
|
Rectangle_t *rect = ...;
|
|
uint8_t buffer[128];
|
|
asn_enc_rval_t er;
|
|
er = oer_encode_to_buffer(&asn_DEF_Rectangle, 0, rect, buffer, sizeof(buffer));
|
|
if(er.encoded == -1) {
|
|
fprintf(stderr, "Serialization of %\%%s failed.\n", asn_DEF_Rectangle.name);
|
|
}
|
|
\end{example}
|
|
|
|
\subsection*{See also}
|
|
\seealso{sec:ber_decode}{ber_decode()},
|
|
\seealso{sec:asn_decode}{asn_decode(ATS_BER)},
|
|
\seealso{sec:asn_encode_to_buffer}{asn_encode_to_buffer(ATS_DER)}.
|
|
|
|
\apisection{sec:uper_decode}{uper\_decode()}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
asn_dec_rval_t uper_decode(
|
|
const asn_codec_ctx_t *opt_codec_ctx,
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
|
|
const void *buffer, /* Data to be decoded */
|
|
size_t size, /* Size of the input data buffer, bytes */
|
|
int skip_bits, /* Number of unused leading bits, 0..7 */
|
|
int unused_bits /* Number of unused tailing bits, 0..7 */
|
|
);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
Decode the Unaligned BASIC or CANONICAL PER (Packed Encoding Rules),
|
|
as defined by ITU-T~X.691.\newline
|
|
|
|
\noindent\emph{Consider using a more generic function \api{sec:asn_decode}{asn_decode(ATS_UNALIGNED_BASIC_PER)}.}
|
|
|
|
\subsection*{Return values}
|
|
\input{asn_dec_rval.inc}
|
|
Note that the \code{.consumed} value is in bits.
|
|
Use \code{(.consumed+7)/8} to convert to bytes.
|
|
|
|
\subsection*{Restartability}
|
|
The \code{uper_decode()} function is not restartable.
|
|
Failures are final.
|
|
|
|
\apisection{sec:uper_decode_complete}{uper\_decode\_complete()}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
asn_dec_rval_t uper_decode_complete(
|
|
const asn_codec_ctx_t *opt_codec_ctx,
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
|
|
const void *buffer, /* Data to be decoded */
|
|
size_t size /* Size of data buffer */
|
|
);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
Decode a ``Production of a complete encoding'',
|
|
according to ITU-T~X.691 (08/2015) \#11.1.\newline
|
|
|
|
\noindent\emph{Consider using a more generic function \api{sec:asn_decode}{asn_decode(ATS_UNALIGNED_BASIC_PER)}.}
|
|
|
|
\subsection*{Return values}
|
|
\input{asn_dec_rval.inc}
|
|
|
|
The the \code{.consumed} value is returned in whole \emph{bytes} (NB).
|
|
|
|
\subsection*{Restartability}
|
|
The \code{uper_decode_complete()} function is not restartable.
|
|
Failures are final.
|
|
|
|
The complete encoding contains at least one byte, so on success
|
|
\code{.consumed} will be greater or equal to 1.
|
|
|
|
\apisection{sec:uper_encode}{uper\_encode()}
|
|
\apisection{sec:uper_encode_to_buffer}{uper\_encode\_to\_buffer()}
|
|
\apisection{sec:uper_encode_to_new_buffer}{uper\_encode\_to\_new\_buffer()}
|
|
\apisection{sec:xer_decode}{xer\_decode()}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
asn_dec_rval_t xer_decode(
|
|
const asn_codec_ctx_t *opt_codec_ctx,
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
void **struct_ptr_ptr,/* Pointer to a target structure's ptr */
|
|
const void *buffer, /* Data to be decoded */
|
|
size_t size /* Size of data buffer */
|
|
);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
Decode the BASIC-XER and CANONICAL-XER (XML Encoding Rules) encoding,
|
|
as defined by ITU-T~X.693.\newline
|
|
|
|
\noindent\emph{Consider using a more generic function \api{sec:asn_decode}{asn_decode(ATS_BASIC_XER)}.}
|
|
|
|
\subsection*{Return values}
|
|
\input{asn_dec_rval.inc}
|
|
|
|
The \code{.consumed} value is in bytes.
|
|
|
|
\subsection*{Restartability}
|
|
|
|
The \code{xer_decode()} function is restartable (stream-oriented).
|
|
That means that in case the buffer has less data than expected,
|
|
the decoder will process whatever is available and ask for more data
|
|
to be provided using the RC\_WMORE return \code{.code}.
|
|
|
|
Note that in the RC\_WMORE case the decoder may have processed less data than
|
|
it is available in the buffer, which means that you must be able to arrange
|
|
the next buffer to contain the unprocessed part of the previous buffer.
|
|
|
|
\apisection{sec:xer_encode}{xer\_encode()}
|
|
|
|
\subsection*{Synopsis}
|
|
|
|
\begin{signature}
|
|
enum xer_encoder_flags_e {
|
|
/* Mode of encoding */
|
|
XER_F_BASIC = 0x01, /* BASIC-XER (pretty-printing) */
|
|
XER_F_CANONICAL = 0x02 /* Canonical XER (strict rules) */
|
|
};
|
|
asn_enc_rval_t xer_encode(
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
const void *structure_to_encode,
|
|
enum xer_encoder_flags_e xer_flags,
|
|
asn_app_consume_bytes_f *callback,
|
|
void *callback_key);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
The \code{xer_encode()} function serializes the given \code{structure_to_encode} using the BASIC-XER or CANONICAL-XER transfer syntax (XML Encoding Rules, ITU-T~X.693).
|
|
|
|
During serialization, a user-specified \code{callback} is invoked zero
|
|
or more times with bytes of data to add to the output stream (if any), and
|
|
the \code{callback_key}. The signature for the callback is as follows:
|
|
|
|
\begin{signature}
|
|
typedef int(asn_app_consume_bytes_f)(const void *buffer, size_t size, void *callback_key);
|
|
\end{signature}
|
|
|
|
\noindent\emph{Consider using a more generic function \api{sec:asn_encode}{asn_encode()} with \texttt{ATS\_BASIC\_XER} or \texttt{ATS\_CANONICAL\_XER} transfer syntax option.}
|
|
|
|
\subsection*{Return values}
|
|
\input{asn_enc_rval.inc}
|
|
|
|
The serialized output size is returned in \textbf{bytes}.
|
|
|
|
\subsection*{Example}
|
|
\begin{example}
|
|
static int
|
|
save_to_file(const void *data, size_t size, void *key) {
|
|
FILE *fp = key;
|
|
return (fwrite(data, 1, size, fp) == size) ? 0 : -1;
|
|
}
|
|
|
|
Rectangle_t *rect = ...;
|
|
FILE *fp = ...;
|
|
asn_enc_rval_t er;
|
|
er = xer_encode(&asn_DEF_Rectangle, rect, XER_F_CANONICAL, save_to_file, fp);
|
|
if(er.encoded == -1) {
|
|
fprintf(stderr, "Failed to encode %\%%s\n", asn_DEF_Rectangle.name);
|
|
} else {
|
|
fprintf(stderr, "%\%%s encoded in %\%%zd bytes\n", asn_DEF_Rectangle.name, er.encoded);
|
|
}
|
|
\end{example}
|
|
|
|
\subsection*{See also}
|
|
\seealso{sec:xer_fprint}{xer_fprint()}.
|
|
|
|
\apisection{sec:xer_fprint}{xer\_fprint()}
|
|
|
|
\subsection*{Synopsis}
|
|
\begin{signature}
|
|
int xer_fprint(FILE *stream, /* Destination file */
|
|
const asn_TYPE_descriptor_t *type_descriptor,
|
|
const void *struct_ptr /* Structure to be printed */
|
|
);
|
|
\end{signature}
|
|
|
|
\subsection*{Description}
|
|
|
|
The \code{xer_fprint()} function outputs XML-based serialization
|
|
of the given structure into the file stream specified by
|
|
\code{stream} pointer.
|
|
|
|
The output conforms to a BASIC-XER transfer syntax, as defined by ITU-T~X.693.
|
|
|
|
\subsection*{Return values}
|
|
|
|
\begin{tabular}[h!]{rl}
|
|
0 & XML output was successfully made \\
|
|
-1 & Error printing out the structure
|
|
\end{tabular}
|
|
|
|
\noindent{}Since the \code{xer_fprint()} function attempts to produce a conforming output,
|
|
it will likely break on partial structures by writing incomplete data
|
|
to the output stream and returning -1. This makes it less suitable for
|
|
debugging complex cases than \api{sec:asn_fprint}{asn_fprint()}.
|
|
|
|
\subsection*{Example}
|
|
\begin{example}
|
|
Rectangle_t *rect = ...;
|
|
xer_fprint(stdout, &asn_DEF_Rectangle, rect);
|
|
\end{example}
|
|
|
|
\subsection*{See also}
|
|
\seealso{sec:asn_fprint}{asn_fprint()}.
|
|
|
|
\chapter{API usage examples}
|
|
|
|
Let's start with including the necessary header files into your
|
|
application. Normally it is enough to include the header file of
|
|
the main PDU type. For our \emph{Rectangle} module, including the \emph{Rectangle.h} file is sufficient:
|
|
\begin{codesample}
|
|
#include <Rectangle.h>
|
|
\end{codesample}
|
|
The header files defines a C structure corresponding to the ASN.1
|
|
definition of a rectangle and the declaration of the ASN.1
|
|
\emph{type descriptor}. A type descriptor is a special globally accessible
|
|
object which is used as an argument to most of the API functions provided by
|
|
the ASN.1 codec. A type descriptor starts with \emph{asn\_DEF\_\ldots{}}. For example, here is the code which frees the Rectangle\_t structure:
|
|
\begin{codesample}
|
|
Rectangle_t *rect = ...;
|
|
|
|
ASN_STRUCT_FREE(%\textbf{asn\_DEF\_}%Rectangle, rect);
|
|
\end{codesample}
|
|
This code defines a \emph{rect} pointer which points to the Rectangle\_t
|
|
structure which needs to be freed. The second line uses a generic
|
|
\api{sec:ASN_STRUCT_FREE}{ASN\_STRUCT\_FREE()} macro which invokes the memory deallocation routine
|
|
created specifically for this Rectangle\_t structure.
|
|
The \emph{asn\_DEF\_Rectangle} is the type descriptor which holds
|
|
a collection of routines and operations defined for the Rectangle\_t structure.
|
|
|
|
\section{\label{sec:Generic-Encoding}Generic encoders and decoders}
|
|
|
|
Before we start describing specific encoders and decoders, let's step back
|
|
a little and check out a simple high level way.
|
|
|
|
The asn1c runtime supplies (see \emph{asn\_application.h}) two sets of high level functions, \api{sec:asn_encode}{asn_encode*} and \api{sec:asn_decode}{asn_decode*}, which take a transfer syntax selector as an argument. The transfer syntax selector is defined as this:
|
|
|
|
\begin{codesample}[basicstyle=\scriptsize\listingfont]
|
|
/*
|
|
* A selection of ASN.1 Transfer Syntaxes to use with generalized encoders and decoders.
|
|
*/
|
|
enum asn_transfer_syntax {
|
|
ATS_INVALID,
|
|
ATS_NONSTANDARD_PLAINTEXT,
|
|
ATS_BER,
|
|
ATS_DER,
|
|
ATS_CER,
|
|
ATS_BASIC_OER,
|
|
ATS_CANONICAL_OER,
|
|
ATS_UNALIGNED_BASIC_PER,
|
|
ATS_UNALIGNED_CANONICAL_PER,
|
|
ATS_BASIC_XER,
|
|
ATS_CANONICAL_XER,
|
|
};
|
|
\end{codesample}
|
|
|
|
Using this encoding selector, encoding and decoding becomes very generic:
|
|
|
|
\noindent{}Encoding:
|
|
|
|
\begin{codesample}[basicstyle=\scriptsize\listingfont]
|
|
uint8_t buffer[128];
|
|
size_t buf_size = sizeof(buffer);
|
|
asn_enc_rval_t er;
|
|
|
|
er = %\textbf{asn\_encode\emph{\_to\_buffer}}%(0, %\textbf{ATS\_DER}%, &asn_DEF_Rectangle, buffer, buf_size);
|
|
|
|
if(er.encoded > buf_size) {
|
|
fprintf(stderr, "Buffer of size %\%%zu is too small for %\%%s, need %\%%zu\n",
|
|
buf_size, asn_DEF_Rectangle.name, er.encoded);
|
|
}
|
|
\end{codesample}
|
|
|
|
\noindent{}Decoding:
|
|
|
|
\begin{codesample}[basicstyle=\scriptsize\listingfont]
|
|
Rectangle_t *%$\underbracket{\textrm{\listingfont rect = 0}}$%; /* %\textbf{\color{red}Note this 0\footnote{Forgetting to properly initialize the pointer to a destination structure is a major source of support requests.}!}% */
|
|
|
|
... = %\textbf{asn\_decode}%(0, %\textbf{ATS\_BER}%, &asn_DEF_Rectangle, (void **)%$\underbracket{\textrm{\listingfont \&rect}}$%, buffer, buf_size);
|
|
\end{codesample}
|
|
|
|
\section{\label{sec:Decoding-BER}Decoding BER}
|
|
|
|
The Basic Encoding Rules describe the most widely used (by the ASN.1
|
|
community) way to encode and decode a given structure in a machine-independent
|
|
way. Several other encoding rules (CER, DER) define a more restrictive
|
|
versions of BER, so the generic BER parser is also capable of decoding
|
|
the data encoded by the CER and DER encoders. The opposite is not true.
|
|
|
|
\emph{The ASN.1 compiler provides the generic BER decoder which is
|
|
capable of decoding BER, CER and DER encoded data.}
|
|
|
|
The decoder is restartable (stream-oriented).
|
|
That means that in case the buffer has less data than expected,
|
|
the decoder will process whatever is available and ask for more data
|
|
to be provided using the RC\_WMORE return \code{.code}.
|
|
|
|
Note that in the RC\_WMORE case the decoder may have processed less data than
|
|
it is available in the buffer, which means that you must be able to arrange
|
|
the next buffer to contain the unprocessed part of the previous buffer.
|
|
|
|
Suppose, you have two buffers of encoded data: 100 bytes and 200 bytes.
|
|
\begin{itemize}
|
|
\item You can concatenate these buffers and feed the BER decoder with 300
|
|
bytes of data, or
|
|
\item You can feed it the first buffer of 100 bytes of data, realize that
|
|
the ber\_decoder consumed only 95 bytes from it and later feed the
|
|
decoder with 205 bytes buffer which consists of 5 unprocessed bytes
|
|
from the first buffer and the additional 200 bytes from the second
|
|
buffer.
|
|
\end{itemize}
|
|
This is not as convenient as it could be (the BER encoder could
|
|
consume the whole 100 bytes and keep these 5 bytes in some temporary
|
|
storage), but in case of existing stream based processing it might
|
|
actually fit well into existing algorithm. Suggestions are welcome.
|
|
|
|
Here is the example of BER decoding of a simple structure:
|
|
|
|
\begin{codesample}
|
|
Rectangle_t *
|
|
simple_deserializer(const void *buffer, size_t buf_size) {
|
|
asn_dec_rval_t rval;
|
|
Rectangle_t *%$\underbracket{\textrm{\listingfont rect = 0}}$%; /* %\textbf{\color{red}Note this 0\footnote{Forgetting to properly initialize the pointer to a destination structure is a major source of support requests.}!}% */
|
|
|
|
rval = %\textbf{asn\_DEF\_Rectangle.op->ber\_decoder}%(0,
|
|
&asn_DEF_Rectangle,
|
|
(void **)%$\underbracket{\textrm{\listingfont \&rect}}$%, /* Decoder %\emph{changes}% the pointer */
|
|
buffer, buf_size, 0);
|
|
|
|
if(rval%\textbf{.code}% == RC_OK) {
|
|
return rect; /* Decoding succeeded */
|
|
} else {
|
|
/* Free the partially decoded rectangle */
|
|
ASN_STRUCT_FREE(asn_DEF_Rectangle, rect);
|
|
return 0;
|
|
}
|
|
}
|
|
\end{codesample}
|
|
|
|
The code above defines a function, \emph{simple\_deserializer}, which
|
|
takes a buffer and its length and is expected to return a pointer
|
|
to the Rectangle\_t structure. Inside, it tries to convert the bytes
|
|
passed into the target structure (rect) using the BER decoder and
|
|
returns the rect pointer afterwards. If the structure cannot be deserialized,
|
|
it frees the memory which might be left allocated by the unfinished
|
|
\emph{ber\_decoder} routine and returns 0 (no data). (This \textbf{freeing
|
|
is necessary} because the ber\_decoder is a restartable procedure,
|
|
and may fail just because there is more data needs to be provided
|
|
before decoding could be finalized). The code above obviously does
|
|
not take into account the way the \emph{ber\_decoder()} failed, so
|
|
the freeing is necessary because the part of the buffer may already
|
|
be decoded into the structure by the time something goes wrong.
|
|
|
|
A little less wordy would be to invoke a globally available \emph{ber\_decode()}
|
|
function instead of dereferencing the asn\_DEF\_Rectangle type descriptor:
|
|
\begin{codesample}
|
|
rval = ber_decode(0, &asn_DEF_Rectangle, (void **)&rect, buffer, buf_size);
|
|
\end{codesample}
|
|
Note that the initial (asn\_DEF\_Rectangle.op->ber\_decoder) reference
|
|
is gone, and also the last argument (0) is no longer necessary.
|
|
|
|
These two ways of BER decoder invocations are fully equivalent.
|
|
|
|
The BER de\emph{coder} may fail because of (\emph{the following RC\_\ldots{}
|
|
codes are defined in ber\_decoder.h}):
|
|
\begin{itemize}
|
|
\item RC\_WMORE: There is more data expected than it is provided (stream
|
|
mode continuation feature);
|
|
\item RC\_FAIL: General failure to decode the buffer;
|
|
\item \ldots{} other codes may be defined as well.
|
|
\end{itemize}
|
|
Together with the return code (.code) the asn\_dec\_rval\_t type contains
|
|
the number of bytes which is consumed from the buffer. In the previous
|
|
hypothetical example of two buffers (of 100 and 200 bytes), the first
|
|
call to ber\_decode() would return with .code = RC\_WMORE and .consumed
|
|
= 95. The .consumed field of the BER decoder return value is \textbf{always}
|
|
valid, even if the decoder succeeds or fails with any other return
|
|
code.
|
|
|
|
Look into ber\_decoder.h for the precise definition of ber\_decode()
|
|
and related types.
|
|
|
|
|
|
\section{\label{sec:Encoding-DER}Encoding DER}
|
|
|
|
The Distinguished Encoding Rules is the \emph{canonical} variant of
|
|
BER encoding rules. The DER is best suited to encode the structures
|
|
where all the lengths are known beforehand. This is probably exactly
|
|
how you want to encode: either after a BER decoding or after a manual
|
|
fill-up, the target structure contains the data which size is implicitly
|
|
known before encoding. Among other uses, the DER encoding is used
|
|
to encode X.509 certificates.
|
|
|
|
As with BER decoder, the DER encoder may be invoked either directly
|
|
from the ASN.1 type descriptor (asn\_DEF\_Rectangle) or from the stand-alone
|
|
function, which is somewhat simpler:
|
|
\begin{codesample}
|
|
/*
|
|
* This is the serializer itself.
|
|
* It supplies the DER encoder with the
|
|
* pointer to the custom output function.
|
|
*/
|
|
ssize_t
|
|
simple_serializer(FILE *ostream, Rectangle_t *rect) {
|
|
asn_enc_rval_t er; /* Encoder return value */
|
|
|
|
er = der_encode(&asn_DEF_Rect, rect, write_stream, ostream);
|
|
if(er%\textbf{.encoded}% == -1) {
|
|
fprintf(stderr, "Cannot encode %\%%s: %\%%s\n",
|
|
er%\textbf{.failed\_type}%->name, strerror(errno));
|
|
return -1;
|
|
} else {
|
|
/* Return the number of bytes */
|
|
return er.encoded;
|
|
}
|
|
}
|
|
\end{codesample}
|
|
As you see, the DER encoder does not write into some sort of buffer.
|
|
It just invokes the custom function (possible, multiple
|
|
times) which would save the data into appropriate storage. The optional
|
|
argument \emph{app\_key} is opaque for the DER encoder code and just
|
|
used by \emph{write\_stream()} as the pointer to the appropriate
|
|
output stream to be used.
|
|
|
|
If the custom write function is not given (passed as 0), then the
|
|
DER encoder will essentially do the same thing (i.~e., encode the data)
|
|
but no callbacks will be invoked (so the data goes nowhere). It may
|
|
prove useful to determine the size of the structure's encoding before
|
|
actually doing the encoding%
|
|
\footnote{It is actually faster too: the encoder might skip over some computations
|
|
which aren't important for the size determination.%
|
|
}.
|
|
|
|
Look into der\_encoder.h for the precise definition of der\_encode()
|
|
and related types.
|
|
|
|
|
|
\section{\label{sec:Encoding-XER}Encoding XER}
|
|
|
|
The XER stands for XML Encoding Rules, where XML, in turn, is eXtensible
|
|
Markup Language, a text-based format for information exchange. The
|
|
encoder routine API comes in two flavors: stdio-based and callback-based.
|
|
With the callback-based encoder, the encoding process is very similar
|
|
to the DER one, described in \fref{sec:Encoding-DER}. The
|
|
following example uses the definition of write\_stream() from up there.
|
|
\begin{codesample}
|
|
/*
|
|
* This procedure generates an XML document
|
|
* by invoking the XER encoder.
|
|
* NOTE: Do not copy this code verbatim!
|
|
* If the stdio output is necessary,
|
|
* use the xer_fprint() procedure instead.
|
|
* See %\fref{sec:Printing-the-target}%.
|
|
*/
|
|
int
|
|
print_as_XML(FILE *ostream, Rectangle_t *rect) {
|
|
asn_enc_rval_t er; /* Encoder return value */
|
|
|
|
er = xer_encode(&asn_DEF_Rectangle, rect,
|
|
XER_F_BASIC, /* BASIC-XER or CANONICAL-XER */
|
|
write_stream, ostream);
|
|
|
|
return (er.encoded == -1) ? -1 : 0;
|
|
}
|
|
\end{codesample}
|
|
Look into xer\_encoder.h for the precise definition of xer\_encode()
|
|
and related types.
|
|
|
|
See \fref{sec:Printing-the-target} for the example of stdio-based
|
|
XML encoder and other pretty-printing suggestions.
|
|
|
|
|
|
\section{\label{sec:Decoding-XER}Decoding XER}
|
|
|
|
The data encoded using the XER rules can be subsequently decoded using
|
|
the xer\_decode() API call:
|
|
\begin{codesample}
|
|
Rectangle_t *
|
|
XML_to_Rectangle(const void *buffer, size_t buf_size) {
|
|
asn_dec_rval_t rval;
|
|
Rectangle_t *%$\underbracket{\textrm{\listingfont rect = 0}}$%; /* %\textbf{\color{red}Note this 0\footnote{Forgetting to properly initialize the pointer to a destination structure is a major source of support requests.}!}% */
|
|
|
|
rval = xer_decode(0, &asn_DEF_Rectangle, (void **)&rect, buffer, buf_size);
|
|
|
|
if(rval%\textbf{.code}% == RC_OK) {
|
|
return rect; /* Decoding succeeded */
|
|
} else {
|
|
/* Free partially decoded rect */
|
|
ASN_STRUCT_FREE(asn_DEF_Rectangle, rect);
|
|
return 0;
|
|
}
|
|
}
|
|
\end{codesample}
|
|
The decoder takes both BASIC-XER and CANONICAL-XER encodings.
|
|
|
|
The decoder shares its data consumption properties with BER decoder;
|
|
please read the \fref{sec:Decoding-BER} to know more.
|
|
|
|
Look into xer\_decoder.h for the precise definition of xer\_decode()
|
|
and related types.
|
|
|
|
|
|
\section{\label{sec:Validating-the-target}Validating the target structure}
|
|
|
|
Sometimes the target structure needs to be validated. For example,
|
|
if the structure was created by the application (as opposed to being
|
|
decoded from some external source), some important information required
|
|
by the ASN.1 specification might be missing. On the other hand, the
|
|
successful decoding of the data from some external source does not
|
|
necessarily mean that the data is fully valid either. It might well
|
|
be the case that the specification describes some subtype constraints
|
|
that were not taken into account during decoding, and it would actually
|
|
be useful to perform the last check when the data is ready to be encoded
|
|
or when the data has just been decoded to ensure its validity according
|
|
to some stricter rules.
|
|
|
|
The \api{sec:asn_check_constraints}{asn_check_constraints()}
|
|
function checks the type for various
|
|
implicit and explicit constraints. It is recommended to use the
|
|
\code{asn_check_constraints()}
|
|
function after each decoding and before each encoding.
|
|
|
|
\section{\label{sec:Printing-the-target}Printing the target structure}
|
|
|
|
To print out the structure for debugging purposes, use the
|
|
\api{sec:asn_fprint}{asn_fprint()} function:
|
|
\begin{codesample}
|
|
asn_fprint(stdout, &asn_DEF_Rectangle, rect);
|
|
\end{codesample}
|
|
|
|
A practical alternative to this custom format printing is to serialize
|
|
the structure into XML. The default BASIC-XER encoder performs reasonable
|
|
formatting for the output to be both useful and human readable.
|
|
Use the \api{sec:xer_fprint}{xer_fprint()} function:
|
|
\begin{codesample}
|
|
xer_fprint(stdout, &asn_DEF_Rectangle, rect);
|
|
\end{codesample}
|
|
See \fref{sec:Encoding-XER} for XML-related details.
|
|
|
|
\section{\label{sec:Freeing-the-target}Freeing the target structure}
|
|
|
|
Freeing the structure is slightly more complex than it may seem.
|
|
When the ASN.1 structure is freed, all the members of the structure
|
|
and their submembers are recursively freed as well.
|
|
The ASN\_STRUCT\_FREE() macro helps with that.
|
|
|
|
But it might not always be feasible to free the whole structure.
|
|
In the following example, the application programmer defines a custom
|
|
structure with one ASN.1-derived member (rect).
|
|
\begin{codesample}
|
|
struct my_figure { /* The custom structure */
|
|
int flags; /* <some custom member> */
|
|
/* The type is generated by the ASN.1 compiler */
|
|
Rectangle_t rect;
|
|
/* other members of the structure */
|
|
};
|
|
\end{codesample}
|
|
This member is not a reference to the Rectangle\_t, but an in-place inclusion
|
|
of the Rectangle\_t structure.
|
|
If there's a need to free the \code{rect} member, the usual procedure of
|
|
freeing everything must not be applied to the \code{\&rect} pointer itself,
|
|
because it does not point to the beginning of memory block allocated by
|
|
the memory allocation routine, but instead lies within a block allocated for
|
|
the my\_figure structure.
|
|
|
|
To solve this problem, in addition to ASN\_STRUCT\_FREE() macro, the asn1c
|
|
skeletons define the ASN\_STRUCT\_RESET() macro which doesn't free the passed
|
|
pointer and instead resets the structure into the clean and safe state.
|
|
\begin{codesample}
|
|
/* %\textbf{1. Rectangle\_t is defined within my\_figure}% */
|
|
struct my_figure {
|
|
Rectangle_t rect;
|
|
} *mf = ...;
|
|
/*
|
|
* Freeing the Rectangle_t
|
|
* without freeing the mf->rect area.
|
|
*/
|
|
ASN_STRUCT_RESET(asn_DEF_Rectangle, &mf->rect);
|
|
|
|
/* %\textbf{2. Rectangle\_t is a stand-alone pointer}% */
|
|
Rectangle_t *rect = ...;
|
|
/*
|
|
* Freeing the Rectangle_t
|
|
* and freeing the rect pointer.
|
|
*/
|
|
ASN_STRUCT_FREE(asn_DEF_Rectangle, rect);
|
|
\end{codesample}
|
|
It is safe to invoke both macros with the target structure pointer
|
|
set to 0 (NULL). In this case, the function will do nothing.
|
|
|
|
\chapter{\label{chap:Abstract-Syntax-Notation}Abstract Syntax Notation: ASN.1}
|
|
|
|
\emph{This chapter defines some basic ASN.1 concepts and describes
|
|
several most widely used types. It is by no means an authoritative
|
|
or complete reference. For more complete ASN.1 description, please
|
|
refer to Olivier Dubuisson's book \cite{Dub00} or the ASN.1 body
|
|
of standards itself \cite{ITU-T/ASN.1}.}
|
|
|
|
The Abstract Syntax Notation One is used to formally describe the
|
|
data transmitted across the network. Two communicating parties may employ
|
|
different formats of their native data types (e.~g., different number
|
|
of bits for the native integer type), thus it is important to have
|
|
a way to describe the data in a manner which is independent from the
|
|
particular machine's representation.
|
|
The ASN.1 specifications are used to achieve the following:
|
|
\begin{itemize}
|
|
\item The specification expressed in the ASN.1 notation is a formal and
|
|
precise way to communicate the structure of data to human readers;
|
|
\item The ASN.1 specifications may be used as input for automatic compilers
|
|
which produce the code for some target language (C, C++, Java, etc)
|
|
to encode and decode the data according to some encoding formats.
|
|
Several such encoding formats (called Transfer Encoding Rules)
|
|
have been defined by the ASN.1 standard.
|
|
\end{itemize}
|
|
Consider the following example:
|
|
\begin{asn}
|
|
Rectangle ::= SEQUENCE {
|
|
height INTEGER,
|
|
width INTEGER
|
|
}
|
|
\end{asn}
|
|
This ASN.1 specification describes a constructed type, \emph{Rectangle},
|
|
containing two integer fields. This specification may tell the reader
|
|
that there exists this kind of data structure and that some entity
|
|
may be prepared to send or receive it. The question on \emph{how}
|
|
that entity is going to send or receive the \emph{encoded data} is
|
|
outside the scope of ASN.1. For example, this data structure may be
|
|
encoded according to some encoding rules and sent to the destination
|
|
using the TCP protocol. The ASN.1 specifies several ways of encoding
|
|
(or ``serializing'', or ``marshaling'') the data: BER, PER, XER
|
|
and others, including CER and DER derivatives from BER.
|
|
|
|
The complete specification must be wrapped in a module, which looks
|
|
like this:
|
|
\begin{asn}
|
|
RectangleModule1
|
|
{ iso org(3) dod(6) internet(1) private(4)
|
|
enterprise(1) spelio(9363) software(1)
|
|
asn1c(5) docs(2) rectangle(1) 1 }
|
|
DEFINITIONS AUTOMATIC TAGS ::=
|
|
BEGIN
|
|
|
|
-- This is a comment which describes nothing.
|
|
Rectangle ::= SEQUENCE {
|
|
height INTEGER, -- Height of the rectangle
|
|
width INTEGER -- Width of the rectangle
|
|
}
|
|
|
|
END
|
|
\end{asn}
|
|
The module header consists of module name (RectangleModule1), the
|
|
module object identifier (\{...\}), a keyword ``DEFINITIONS'', a
|
|
set of module flags (AUTOMATIC TAGS) and ``::= BEGIN''. The module
|
|
ends with an ``END'' statement.
|
|
|
|
|
|
\section{Some of the ASN.1 Basic Types}
|
|
|
|
|
|
\subsection{The BOOLEAN type}
|
|
|
|
The BOOLEAN type models the simple binary TRUE/FALSE, YES/NO, ON/OFF
|
|
or a similar kind of two-way choice.
|
|
|
|
|
|
\subsection{The INTEGER type}
|
|
|
|
The INTEGER type is a signed natural number type without any restrictions
|
|
on its size. If the automatic checking on INTEGER value bounds are
|
|
necessary, the subtype constraints must be used.
|
|
\begin{asn}
|
|
SimpleInteger ::= INTEGER
|
|
|
|
-- An integer with a very limited range
|
|
SmallPositiveInt ::= INTEGER (0..127)
|
|
|
|
-- Integer, negative
|
|
NegativeInt ::= INTEGER (MIN..0)
|
|
\end{asn}
|
|
|
|
\subsection{The ENUMERATED type}
|
|
|
|
The ENUMERATED type is semantically equivalent to the INTEGER type
|
|
with some integer values explicitly named.
|
|
\begin{asn}
|
|
FruitId ::= ENUMERATED { apple(1), orange(2) }
|
|
|
|
-- The numbers in braces are optional,
|
|
-- the enumeration can be performed
|
|
-- automatically by the compiler
|
|
ComputerOSType ::= ENUMERATED {
|
|
FreeBSD, -- acquires value 0
|
|
Windows, -- acquires value 1
|
|
Solaris(5), -- remains 5
|
|
Linux, -- becomes 6
|
|
MacOS -- becomes 7
|
|
}
|
|
\end{asn}
|
|
|
|
\subsection{The OCTET STRING type}
|
|
|
|
This type models the sequence of 8-bit bytes. This may be used to
|
|
transmit some opaque data or data serialized by other types of encoders
|
|
(e.~g., video file, photo picture, etc).
|
|
|
|
\subsection{The OBJECT IDENTIFIER type}
|
|
|
|
The OBJECT IDENTIFIER is used to represent the unique identifier of
|
|
any object, starting from the very root of the registration tree.
|
|
If your organization needs to uniquely identify something (a router,
|
|
a room, a person, a standard, or whatever), you are encouraged to
|
|
get your own identification subtree at \url{http://www.iana.org/protocols/forms.htm}.
|
|
|
|
For example, the very first ASN.1 module in this Chapter (RectangleModule1)
|
|
has the following OBJECT IDENTIFIER: 1 3 6 1 4 1 9363 1 5 2 1 1.
|
|
\begin{asn}
|
|
ExampleOID ::= OBJECT IDENTIFIER
|
|
|
|
rectangleModule1-oid ExampleOID
|
|
::= { 1 3 6 1 4 1 9363 1 5 2 1 1 }
|
|
|
|
-- An identifier of the Internet.
|
|
internet-id OBJECT IDENTIFIER
|
|
::= { iso(1) identified-organization(3)
|
|
dod(6) internet(1) }
|
|
\end{asn}
|
|
As you see, names are optional.
|
|
|
|
|
|
\subsection{The RELATIVE-OID type}
|
|
|
|
The RELATIVE-OID type has the semantics of a subtree of an OBJECT
|
|
IDENTIFIER. There may be no need to repeat the whole sequence of numbers
|
|
from the root of the registration tree where the only thing of interest
|
|
is some of the tree's subsequence.
|
|
\begin{asn}
|
|
this-document RELATIVE-OID ::= { docs(2) usage(1) }
|
|
|
|
this-example RELATIVE-OID ::= {
|
|
this-document assorted-examples(0) this-example(1) }
|
|
\end{asn}
|
|
|
|
\section{Some of the ASN.1 String Types}
|
|
|
|
|
|
\subsection{The IA5String type}
|
|
|
|
This is essentially the ASCII, with 128 character codes available
|
|
(7 lower bits of an 8-bit byte).
|
|
|
|
|
|
\subsection{The UTF8String type}
|
|
|
|
This is the character string which encodes the full Unicode range
|
|
(4 bytes) using multibyte character sequences.
|
|
|
|
|
|
\subsection{The NumericString type}
|
|
|
|
This type represents the character string with the alphabet consisting
|
|
of numbers (``0'' to ``9'') and a space.
|
|
|
|
|
|
\subsection{The PrintableString type}
|
|
|
|
The character string with the following alphabet: space, ``\textbf{'}''
|
|
(single quote), ``\textbf{(}'', ``\textbf{)}'', ``\textbf{+}'',
|
|
``\textbf{,}'' (comma), ``\textbf{-}'', ``\textbf{.}'', ``\textbf{/}'',
|
|
digits (``0'' to ``9''), ``\textbf{:}'', ``\textbf{=}'', ``\textbf{?}'',
|
|
upper-case and lower-case letters (``A'' to ``Z'' and ``a''
|
|
to ``z'').
|
|
|
|
|
|
\subsection{The VisibleString type}
|
|
|
|
The character string with the alphabet which is more or less a subset
|
|
of ASCII between the space and the ``\textbf{\textasciitilde{}}''
|
|
symbol (tilde).
|
|
|
|
Alternatively, the alphabet may be described as the PrintableString
|
|
alphabet presented earlier, plus the following characters: ``\textbf{!}'',
|
|
``\textbf{``}'', ``\textbf{\#}'', ``\textbf{\$}'', ``\textbf{\%}'',
|
|
``\textbf{\&}'', ``\textbf{*}'', ``\textbf{;}'', ``\textbf{<}'',
|
|
``\textbf{>}'', ``\textbf{{[}}'', ``\textbf{\textbackslash{}}'',
|
|
``\textbf{{]}}'', ``\textbf{\textasciicircum{}}'', ``\textbf{\_}'',
|
|
``\textbf{`}`` (single left quote), ``\textbf{\{}'', ``\textbf{|}'',
|
|
``\textbf{\}}'', ``\textbf{\textasciitilde{}}''.
|
|
|
|
|
|
\section{ASN.1 Constructed Types}
|
|
|
|
|
|
\subsection{The SEQUENCE type}
|
|
|
|
This is an ordered collection of other simple or constructed types.
|
|
The SEQUENCE constructed type resembles the C ``struct'' statement.
|
|
\begin{asn}
|
|
Address ::= SEQUENCE {
|
|
-- The apartment number may be omitted
|
|
apartmentNumber NumericString OPTIONAL,
|
|
streetName PrintableString,
|
|
cityName PrintableString,
|
|
stateName PrintableString,
|
|
-- This one may be omitted too
|
|
zipNo NumericString OPTIONAL
|
|
}
|
|
\end{asn}
|
|
|
|
\subsection{The SET type}
|
|
|
|
This is a collection of other simple or constructed types. Ordering
|
|
is not important. The data may arrive in the order which is different
|
|
from the order of specification. Data is encoded in the order not
|
|
necessarily corresponding to the order of specification.
|
|
|
|
|
|
\subsection{The CHOICE type}
|
|
|
|
This type is just a choice between the subtypes specified in it. The
|
|
CHOICE type contains at most one of the subtypes specified, and it
|
|
is always implicitly known which choice is being decoded or encoded.
|
|
This one resembles the C ``union'' statement.
|
|
|
|
The following type defines a response code, which may be either an
|
|
integer code or a boolean ``true''/``false'' code.
|
|
\begin{asn}
|
|
ResponseCode ::= CHOICE {
|
|
intCode INTEGER,
|
|
boolCode BOOLEAN
|
|
}
|
|
\end{asn}
|
|
|
|
\subsection{The SEQUENCE OF type}
|
|
|
|
This one is the list (array) of simple or constructed types:
|
|
\begin{asn}
|
|
-- Example 1
|
|
ManyIntegers ::= SEQUENCE OF INTEGER
|
|
|
|
-- Example 2
|
|
ManyRectangles ::= SEQUENCE OF Rectangle
|
|
|
|
-- More complex example:
|
|
-- an array of structures defined in place.
|
|
ManyCircles ::= SEQUENCE OF SEQUENCE {
|
|
radius INTEGER
|
|
}
|
|
\end{asn}
|
|
|
|
\subsection{The SET OF type}
|
|
|
|
The SET OF type models the bag of structures. It resembles the SEQUENCE
|
|
OF type, but the order is not important. The elements may arrive
|
|
in the order which is not necessarily the same as the in-memory order
|
|
on the remote machines.
|
|
\begin{asn}
|
|
-- A set of structures defined elsewhere
|
|
SetOfApples :: SET OF Apple
|
|
|
|
-- Set of integers encoding the kind of a fruit
|
|
FruitBag ::= SET OF ENUMERATED { apple, orange }
|
|
\end{asn}
|
|
\begin{thebibliography}{ITU-T/ASN.1}
|
|
\bibitem[ASN1C]{ASN1C}The Open Source ASN.1 Compiler. \url{http://lionet.info/asn1c}
|
|
|
|
\bibitem[AONL]{AONL}Online ASN.1 Compiler. \url{http://lionet.info/asn1c/asn1c.cgi}
|
|
|
|
\bibitem[Dub00]{Dub00}Olivier Dubuisson --- \emph{ASN.1 Communication
|
|
between heterogeneous systems} --- Morgan Kaufmann Publishers, 2000.
|
|
\url{http://asn1.elibel.tm.fr/en/book/}. ISBN:0-12-6333361-0.
|
|
|
|
\bibitem[ITU-T/ASN.1]{ITU-T/ASN.1}ITU-T Study Group 17 --- Languages
|
|
for Telecommunication Systems \url{http://www.itu.int/ITU-T/studygroups/com17/languages/}
|
|
\end{thebibliography}
|
|
|
|
\end{document}
|