Archive for the 'C++' Category

Compilar ASN.1 a C/C++

Aviso, Este es un articulo muy tecnico, completamente de programacion en C/C++. Si eres nuevo en Linux, seguramente no te interese, como siempre puedes leerlo / o no bajo tu propia responsabilidad. Si no te interesa, En este sitio se tocan muchos temas y seguramente encuentres algun otro que te pueda interesar mas.

En mi trabajo creamos aplicaciones para codificar y decodificar informacion mediante ASN.1, es una de las formas que empleamos para transmitir/recibir informacion entre host que son heterogeneos, por ejemplo para enviar informacion de un Linux a una estacion Sun Solaris, o a cualquier otra plataforma. En este pequeño articulo comento una breve introduccion a ASN.1 y como lo podemos usar en nuestras aplicaciones C/C++.

¿Que es ASN.1?

Como bien dice la wikipedia, ASN.1 (Abstract Syntax Notation One) es una notacion flexible y estandard que describe estructuras de datos para representarlas, codificarlas, transmitirlas y decodificarlas.

Veamos un ejemplo:

Podriamos tener la siguiente definicion de una estructura en ASN.1:

FooProtocol DEFINITIONS ::= BEGIN
FooQuestion ::= SEQUENCE
{
trackingNumber INTEGER,
question VisibleString
}
FooAnswer ::= SEQUENCE
{
questionNumber INTEGER,
answer BOOLEAN
}
END

Y de acuerdo a esta definicion podriamos querer transmitir la siguiente informacion:

myQuestion FooQuestion ::= {
trackingNumber 5,
question "Anybody there?"
}

Es decir, una estructura de tipo «FooQuestion» que tiene dos campos, uno llamado trackingNumber con valor igual a 5 y otro llamado question con valor «Anybody there?»

Esto realmente cuando lo codificamos no se envia como texto plano sino como una secuencia de Bytes:

30 13 02 01 05 1a 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f

Que significa lo siguiente:

30 -- es un tag que indica SEQUENCE
13 -- longitud en octetos
02 -- tag que indica que lo que sigue es un INTEGER
01 -- longitud en octetos (1 byte)
05 -- valor del dato
1a -- tag que indica que lo que sigue es un VisibleString
0e -- longitud en octetos (14 bytes)
41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f -- el valor ("Anybody there?" codificado en ASCII)

Realmente y basicamente es una secuencia donde 1 byte indica lo que viene a continuacion, otro byte o bytes indica el tamaño de lo que sigue y a continuacion viene el dato. Todo ello codificado como ves en una secuencia de bytes.

Cuando al receptor le llegue ese chorizo de bytes, lo sabe decodificar y rellena la estructura correspondiente.

Pues bien, nuestras aplicaciones para trabajar con este formato codificado deben implementar las funciones que se encarguen de codificar y decodificar estas estructuras. Pero para ello contamos con snacc, que nos hace la vida mas facil y nos autogenera las cabeceras .h y librerias .c necesarias sin tener que escribir el codigo.

snacc es un compilador de sintaxis ASN.1 a C/C++.

Para instalarlo en Ubuntu ejecutamos:

$ sudo apt-get install snacc

Tras instalarlo. si lo ejecutamos sin mas, nos muestra la siguiente informacion:


jose@soledad:~/Desktop/snacc4J$ snacc
Usage: snacc [-h] [-P] [-t] [-v] [-e] [-d] [-p] [-f]
[-c | -C | -[T|O] <table output file> | -idl ]
[-u <useful types ASN.1 file>]
[-mm] [-mf <max file name length>]
[-l <neg number>]
<ASN.1 file list>
-h prints this msg
-c generate C encoders and decoders (default)
-C generate C++ encoders and decoders
-novolat for broken C++ compilers: return *this after calling abort()
-T <filename> write a type table file for the ASN.1 modules to file filename
-O <filename> writes the type table file in the original (<1.3b2) format
-idl generate CORBA IDL
-u <filename> specifies the ASN.1 file with definition of the useful types
(i.e. PrintableString). See the useful.asn1 file (in the
snacc/asn1specs/ directory).
-P print the parsed ASN.1 modules to stdout from their parse trees
(helpful debugging)
-t generate type definitions
-v generate value definitions (limited)
-e generate encode routines
-d generate decode routines
-p generate print routines
-f generate hierarchical free routines (C only)
note: if none of -t -v -e -d -p -f are given, all are generated.
These do not affect type tables.
-mm mangle output file name into module name (by default, the output file
inherits the input file's name, with only the suffix replaced)
-mf <num> num is maximum file name length for the generated source files
-l <neg num> where to start error longjmp values decending from (obscure).
Use `-' as the ASN.1 source file name to parse stdin.
This ASN.1 compiler produces C or C++ BER encoders and decoders or type tables.
Version 1.3, 1997-10-20.
Please see snacc@cs.ubc.ca for new versions and where to send bug reports and comments.
Copyright (C) 1993 Michael Sample and UBC
Copyright (C) 1994, 1995 by Robert Joop and GMD FOKUS
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
jose@soledad:~/Desktop/snacc4J$

Ahora bien, vamos a escribir un fichero de definicion ASN.1 como ejemplo y ver como generar la cabecera y fichero con el cuerpo que luego emplearemos en nuestros propios programas.

Por ejemplo escribi el siguiente fichero y llamalo «Persona.ASN1»


Ejemplo DEFINITIONS ::= BEGIN
Persona ::= SEQUENCE {
nombre [0] PrintableString (SIZE(1..30)),
edad [1] INTEGER,
sexo [2] Sexo OPTIONAL
}
Sexo ::= ENUMERATED {
desconocido (0),
masculino (1),
femenino (2)
}
END

Para compilarlo ejecutamos:

$ snacc -u /usr/include/snacc/asn1/asn-useful.asn1 Persona.ASN1

y automaticamente nos genera 2 ficheros:

/*
* Persona.h
*
* "Ejemplo" ASN.1 module C type definitions and prototypes
*
* This .h file was generated by snacc on Wed May 30 13:03:29 2007
*
* UBC snacc written compiler by Mike Sample
*
* NOTE: This is a machine generated file--editing not recommended
*/
#ifndef _Persona_h_
#define _Persona_h_
typedef enum
{
DESCONOCIDO = 0,
MASCULINO = 1,
FEMENINO = 2
} Sexo; /* ENUMERATED { DESCONOCIDO (0), MASCULINO (1), FEMENINO (2) } */
#define BEncSexoContent BEncAsnEnumContent
#define BDecSexoContent BDecAsnEnumContent
#define PrintSexo PrintAsnEnum
#define FreeSexo FreeAsnEnum
typedef struct Persona /* SEQUENCE */
{
PrintableString nombre; /* [0] PrintableString (SIZE (1..30)) */
AsnInt edad; /* [1] INTEGER */
Sexo* sexo; /* [2] Sexo OPTIONAL */
} Persona;
AsnLen BEncPersonaContent PROTO ((BUF_TYPE b, Persona *v));
void BDecPersonaContent PROTO ((BUF_TYPE b, AsnTag tagId0, AsnLen elmtLen0, Persona *v, AsnLen *bytesDecoded, ENV_TYPE env));
void PrintPersona PROTO ((FILE* f, Persona *v, unsigned short int indent));
void FreePersona PROTO ((Persona *v));
#endif /* conditional include of Persona.h */

y

/*
* Persona.c
*
* "Ejemplo" ASN.1 module encode/decode/print/free C src.
*
* This file was generated by snacc on Wed May 30 13:03:29 2007
*
* UBC snacc written by Mike Sample
*
* NOTE: This is a machine generated file - editing not recommended
*/
#include "asn-incl.h"
#include "Persona.h"
AsnLen
BEncPersonaContent PARAMS ((b, v),
BUF_TYPE b _AND_
Persona *v)
{
AsnLen totalLen = 0;
AsnLen itemLen;
AsnLen listLen;
void *component;
if (NOT_NULL ((v->sexo)))
{
BEncEocIfNec (b);
itemLen = BEncSexoContent (b, (v->sexo));
BEncDefLenTo127 (b, itemLen);
itemLen++;
itemLen += BEncTag1 (b, UNIV, PRIM, 10);
itemLen += BEncConsLen (b, itemLen);
itemLen += BEncTag1 (b, CNTX, CONS, 2);
totalLen += itemLen;
}
BEncEocIfNec (b);
itemLen = BEncAsnIntContent (b, (&v->edad));
BEncDefLenTo127 (b, itemLen);
itemLen++;
itemLen += BEncTag1 (b, UNIV, PRIM, 2);
itemLen += BEncConsLen (b, itemLen);
itemLen += BEncTag1 (b, CNTX, CONS, 1);
totalLen += itemLen;
BEncEocIfNec (b);
itemLen = BEncPrintableStringContent (b, (&v->nombre));
itemLen += BEncDefLen (b, itemLen);
itemLen += BEncTag1 (b, UNIV, PRIM, 19);
itemLen += BEncConsLen (b, itemLen);
itemLen += BEncTag1 (b, CNTX, CONS, 0);
totalLen += itemLen;
return totalLen;
} /* BEncPersonaContent */
void
BDecPersonaContent PARAMS ((b, tagId0, elmtLen0, v, bytesDecoded, env),
BUF_TYPE b _AND_
AsnTag tagId0 _AND_
AsnLen elmtLen0 _AND_
Persona *v _AND_
AsnLen *bytesDecoded _AND_
ENV_TYPE env)
{
int seqDone = FALSE;
AsnLen totalElmtsLen1 = 0;
AsnLen elmtLen1;
AsnTag tagId1;
int mandatoryElmtCount1 = 0;
AsnLen totalElmtsLen2 = 0;
AsnLen elmtLen2;
AsnTag tagId2;
tagId1 = BDecTag (b, &totalElmtsLen1, env);
if (((tagId1 == MAKE_TAG_ID (CNTX, CONS, 0))))
{
elmtLen1 = BDecLen (b, &totalElmtsLen1, env);
tagId2 = BDecTag (b, &totalElmtsLen1, env);
if ((tagId2 != MAKE_TAG_ID (UNIV, PRIM, PRINTABLESTRING_TAG_CODE)) &&
(tagId2 != MAKE_TAG_ID (UNIV, CONS, PRINTABLESTRING_TAG_CODE)))
{
Asn1Error ("Unexpected Tag\n");
longjmp (env, -100);
}
elmtLen2 = BDecLen (b, &totalElmtsLen1, env);
BDecPrintableStringContent (b, tagId2, elmtLen2, (&v->nombre), &totalElmtsLen1, env);
if (elmtLen1 == INDEFINITE_LEN)
BDecEoc (b, &totalElmtsLen1, env);
tagId1 = BDecTag (b, &totalElmtsLen1, env);
}
else
longjmp (env, -101);
if (((tagId1 == MAKE_TAG_ID (CNTX, CONS, 1))))
{
elmtLen1 = BDecLen (b, &totalElmtsLen1, env);
tagId2 = BDecTag (b, &totalElmtsLen1, env);
if (tagId2 != MAKE_TAG_ID (UNIV, PRIM, INTEGER_TAG_CODE))
{
Asn1Error ("Unexpected Tag\n");
longjmp (env, -102);
}
elmtLen2 = BDecLen (b, &totalElmtsLen1, env);
BDecAsnIntContent (b, tagId2, elmtLen2, (&v->edad), &totalElmtsLen1, env);
if (elmtLen1 == INDEFINITE_LEN)
BDecEoc (b, &totalElmtsLen1, env);
if ((elmtLen0 != INDEFINITE_LEN) && (totalElmtsLen1 == elmtLen0))
seqDone = TRUE;
else
{
tagId1 = BDecTag (b, &totalElmtsLen1, env);
if ((elmtLen0 == INDEFINITE_LEN) && (tagId1 == EOC_TAG_ID))
{
BDEC_2ND_EOC_OCTET (b, &totalElmtsLen1, env)
seqDone = TRUE;
}
}
}
else
longjmp (env, -103);
if ((!seqDone) && ((tagId1 == MAKE_TAG_ID (CNTX, CONS, 2))))
{
elmtLen1 = BDecLen (b, &totalElmtsLen1, env);
tagId2 = BDecTag (b, &totalElmtsLen1, env);
if (tagId2 != MAKE_TAG_ID (UNIV, PRIM, ENUM_TAG_CODE))
{
Asn1Error ("Unexpected Tag\n");
longjmp (env, -104);
}
elmtLen2 = BDecLen (b, &totalElmtsLen1, env);
(v->sexo) = (Sexo*) Asn1Alloc (sizeof (Sexo));
CheckAsn1Alloc ((v->sexo), env);
BDecSexoContent (b, tagId2, elmtLen2, (v->sexo), &totalElmtsLen1, env);
if (elmtLen1 == INDEFINITE_LEN)
BDecEoc (b, &totalElmtsLen1, env);
seqDone = TRUE;
if (elmtLen0 == INDEFINITE_LEN)
BDecEoc (b, &totalElmtsLen1, env);
else if (totalElmtsLen1 != elmtLen0)
longjmp (env, -105);
}
if (!seqDone)
longjmp (env, -106);
(*bytesDecoded) += totalElmtsLen1;
} /* BDecPersonaContent */
void
PrintPersona PARAMS ((f, v, indent),
FILE* f _AND_
Persona *v _AND_
unsigned short int indent)
{
if (v == NULL)
return;
fprintf (f,"{ -- SEQUENCE --\n");
Indent (f, indent + stdIndentG);
fprintf (f,"nombre ");
PrintPrintableString (f, (&v->nombre), indent + stdIndentG);
fprintf (f, ",\n");
Indent (f, indent + stdIndentG);
fprintf (f,"edad ");
PrintAsnInt (f, (&v->edad), indent + stdIndentG);
if (NOT_NULL ((v->sexo)))
{
fprintf (f,",\n");
Indent (f, indent + stdIndentG);
fprintf (f,"sexo ");
PrintSexo (f, (v->sexo), indent + stdIndentG);
}
fprintf (f,"\n");
Indent (f, indent);
fprintf (f,"}");
} /* PrintPersona */
void
FreePersona PARAMS ((v),
Persona *v)
{
if (v == NULL)
return;
FreePrintableString ((&v->nombre));
FreeAsnInt ((&v->edad));
if (NOT_NULL ((v->sexo)))
{
FreeSexo ((v->sexo));
Asn1Free ((v->sexo));
}
} /* FreePersona */

Que ya podremos emplear en nuestros programas para implementar las rutinas de codificacion y decodificacion.

El ejemplo para el fichero ASN.1 lo he sacado de la siguiente direccion.





¿Es compatible tu equipo con Ubuntu?


( Muchos fondos de pantalla, aqui )

DESCARGATE SCIFI LIFE

365 Dias de Soledad
Me debes los sueños, las promesas y las noches rotas. Me debes la paz, la sonrisa y la esperanza robadas. Me debes la sangre, las lágrimas y el sudor vertido. Me debes las noches vacías, los abrazos anhelados. Me debes un beso de ajenjo de tu amarga boca.

The Ubuntu Counter Project - user number # 11961
Geo Visitors Map

Archivos

May 2024
L M X J V S D
 12345
6789101112
13141516171819
20212223242526
2728293031  

Blog Stats

  • 31.400.124 hits