TOP

ASN.1/C++ Runtime Advanced Topics

Applies to: ASN.1/C++ 6.5

C++ Compiler Macros to Optimize Size and Speed when Using the TOED

Code files generated for the Time-Optimized Encoder/Decoder contain a number of features that are either enabled or disabled by default. These features can be adjusted using C++ preprocessor macros during C++-compilation to optimize your application's performance and memory footprint. Most C++ compilers do this via the -D C++ compiler option (e.g., cc -DOSSDEBUG).

OSSDEBUG
Affects the verbosity of TOED diagnostic messages that can be retrieved with the getErrorMsg() method of the OssControl class. The OSSDEBUG macro has the following levels:
  • OSSDEBUG=0, no error message is constructed, and only an error code is returned.
  • OSSDEBUG=1, a simple error message is generated along with the error code.
  • OSSDEBUG=2 (or greater), an error message is generated that explains the specific error and in which component it occurred, along with the error code.
The default setting of the OSSDEBUG level is 2. Decrease this level to reduce the final application size and to slightly increase its performance.
OSSPRINT
Enables implementation of the ASN1Handle::print() method in TOED-based programs (as with SOED). By default, this function prints nothing and returns the NULL_FCN enumerator (error code 21). The -test compiler option enables OSSPRINT automatically.
OSS_COMPARE_VALUE
Enables implementation of the ASN1Handle::equal() method in TOED-based programs (as with SOED). By default, the ASN1Handle::equal() method does nothing and returns the UNIMPLEMENTED enumerator. The -test compiler option enables OSS_COMPARE_VALUE automatically.
OSS_COPY_VALUE
Enables implementation of the ASN1Handle::copy() method in TOED-based programs (as with SOED). By default, the ASN1Handle::copy() method does nothing and returns the UNIMPLEMENTED enumerator. The -test compiler option enables OSS_COPY_VALUE automatically.
OSS_DO_NOT_CHECK_POINTERS
Disables the check for NULL pointers within the input C++ classes of the TOED encoder. By default, this check is performed to protect the encoder from a bad input value.
OSS_NO_NESTING_CONTROL
Disables nesting control in TOED-based programs. Nesting control is a security mechanism used in decoders to prevent a possible stack overflow triggered by a specially crafted message. OSS runtime libraries provide protection from two types of nesting overflows: constructed string encodings and constructed types. They are enabled by default.
OSS_NO_STRICT_ENCODING_DECODING_CHECKING
Partially disables support for the STRICT_ENCODING_DECODING_RULES runtime flag in TOED-based programs. By default, this flag performs the checks for STRICT_ENCODING_DECODING_RULES. When the code file is C++-compiled with the OSS_NO_STRICT_ENCODING_DECODING_CHECKING macro, the following checks are disabled:
  • Incorrect fragmentation of constructed types in the PER encoding
  • Zero length extensions in the PER encoding
  • Zero length PER encodings
You cannot cancel the entire effect of the STRICT_ENCODING_DECODING_RULES runtime flag with the OSS_NO_STRICT_ENCODING_DECODING_CHECKING macro, because not all the checks are performed by the generated code file. The rest are performed by the TOED runtime; to disable these checks completely omit the STRICT_ENCODING_DECODING_RULES runtime flag from your application code.
OSS_NO_STRICT_EXTENSION_CONTROL
Disables the check for missing mandatory (non-optional) fields after the extension marker in the input PDU in TOED-based programs. By default, the check is performed.
OSS_STRICT_PER_ENCODING_OF_DEFAULT_VALUES
Provides support for the STRICT_PER_ENCODING_OF_DEFAULT_VALUES runtime flag in TOED-based programs (as with SOED). By default, this flag has no effect on the program. That is, the PER encoder produces a non-empty encoding for components defined with a DEFAULT value, even when the value to be encoded is the default value.
OSS_SKIP_UNKNOWN_CONTENT_SUPPORTED
Enables support for the OSS_SKIP_UNKNOWN_CONTENT runtime flag in the E-XER TOED-based programs. By default, this code is disabled by the C++ preprocessor to reduce the size of your program and to achieve slightly better performance (the difference is in the range of 5 to 10% for size and speed). By default, the decoder issues errors if unknown elements or attributes are present in the input XML message.

Guidelines for Improving Runtime Performance

  • Be sure to use the default TOED (Time-Optimized Encoder/Decoder) runtime rather than the SOED.
  • Do not set the DEBUGPDU flag before calling the encoder/decoder. This will disable time-consuming trace activity during encoding/decoding operations.
  • Specify the -minimize ASN.1 compiler command line option when compiling your ASN.1 syntax. This will usually lead to a smaller .cpp file and will result in only crucial constraint checking being done on values which are being encoded/decoded. Alternatively, specify the NOCONSTRAIN flag before calling the encoder/decoder, thereby disabling run-time constraint checking while retaining the ability to later enable it, if the need arises.
  • Do not specify the OSS_TRAPPING flag before calling the encoder/decoder. The flag enables the trapping of memory violations and the construction of an error message that details which field of the PDU was being processed when the memory violation occurred. If your application is fully tested, you have every reason to not specify OSS_TRAPPING. For versions prior to 4.1 specify the NOTRAPPING flag before calling the encoder/decoder.
  • Use the OSS ASN.1/C++ Memory Pools API that offers optimized dynamic memory management. A sample that demonstrates the Memory Pools API is in the samples/advanced/memory_pool subdirectory of the software installation.
  • When using the default OSS TOED library, review C++ Compiler Macros to Optimize Size and Speed when Using the TOED above and tune your application to achieve better performance by setting some of the listed macros.
  • Use ownership-transferring functions to avoid excessive copying of large memory blocks. Use the OSS.POINTER directive to additionally generate ownership-transferring functions for components of constructed types.
  • C++ compile the generated code with optimization flags.

Partial Decoding

Version 6.2 of the OSS ASN.1 Tools for C++ introduces the partial decoding feature, which allows you to

  • Decode preselected fields from incoming messages at a very high speed. The remaining fields are bypassed.
  • Modify the value of a preselected field; you can directly replace a field value in a binary message (not recommended for PER or UPER messages).

For each decoded field, the offset, length, and value are provided by the decoder to the user application via callback methods. This means that you don't need to write code or know the PDU's C++ representation details to access a deeply nested field.

Your callback method can analyze a decoded value and, by setting the return code, instruct the decoder to terminate or continue decoding.

The ASN.1/C++ Compiler generates the <module_name>_Callback class that contains your callback methods (virtual member functions); you can easily derive the class and implement the callback methods. The <module_name>_Callback class is a subclass of the OssCallback base interface.

The partial decoding feature requires the ASN.1/C++ TOED Runtime version 6.2 or later.

The BER, DER, PER, UPER, OER, and C-OER binary encoding rules support partial decoding. XER, CXER, E-XER, and JSON encoding rules do not support partial decoding.

Example

This example shows how data and info callback methods can be combined so that only zipcode values from homeAddress are processed and zipcode values from companyAddress are ignored. The result of the OSS.DataCallback directive is that myZipcode() is called for zipcode in both uses of Address. Next, the OSS.InfoCallback directive applies a filter so only the zipcode values from homeAddress are used.

ASN.1 syntax (infotest.asn):

--<OSS.DataCallback M.Address.zipcode "myZipcode">--
--<OSS.InfoCallback M.Subscriber.homeAddress" homeAddressField">--

M DEFINITIONS AUTOMATIC TAGS ::= BEGIN
Subscriber ::= SEQUENCE {
   name         VisibleString,
   company      Company,
   homeAddress  Address
}
Company ::= SEQUENCE {
   name     VisibleString,
   address  Address
}
Address ::= SEQUENCE {
   zipcode      INTEGER( 0..99999 ),
   addressline  VisibleString( SIZE (1..64) )
}
END

Subscriber PDU encoding:

/* the BER encoding of a Subscriber PDU */
char   ber_enc[] = {

    0x30, 0x5D, 0x80, 0x08, 0x4A, 0x6F, 0x68, 0x6E, 0x20, 0x44,
    0x6F, 0x65, 0xA1, 0x2D, 0x80, 0x10, 0x41, 0x62, 0x73, 0x75,
    0x72, 0x64, 0x20, 0x4C, 0x6F, 0x67, 0x69, 0x73, 0x74, 0x69,
    0x63, 0x73, 0xA1, 0x19, 0x80, 0x02, 0x30, 0x39, 0x81, 0x13,
    0x38, 0x30, 0x30, 0x2C, 0x20, 0x37, 0x74, 0x68, 0x20, 0x53,
    0x74, 0x72, 0x65, 0x65, 0x74, 0x2C, 0x20, 0x4E, 0x59, 0xA2,
    0x22, 0x80, 0x03, 0x01, 0x09, 0x32, 0x81, 0x1B, 0x33, 0x33,
    0x33, 0x2C, 0x20, 0x46, 0x6F, 0x6F, 0x62, 0x61, 0x72, 0x20,
    0x44, 0x72, 0x2E, 0x2C, 0x20, 0x42, 0x61, 0x79, 0x6F, 0x6E,
    0x6E, 0x65, 0x20, 0x4E, 0x4A
};

Generated .cpp:

/*
    A structure for data exchange between callback function calls.
    In case of multithreading it should be allocated per thread.
*/
typedef struct {
    int    flag;
} UserData;

UserData data;

/* derive the compiler generated infotest_Callback class */
class myCallbackClass : public infotest_Callback {
public:
    int myZipcode(OssGlobal *_g, long offset, long length, unsigned int flags, OSS_UINT32  *value);
    int homeAddressField(OssGlobal *_g, const char *fname, unsigned int flags);
};

/* 
    Info callback method. It sets the flag indicating that homeAddress
    field is being decoded 
*/
int myCallbackClass::homeAddressField(OssGlobal *_g, const char *fname, unsigned int flags) {
    UserData *udP = (UserData *)this->userVar;
    if (flags & OSS_DECODING_OF_COMPONENT_IN_PROGRESS) {
        ossPrint(_g, "\n\nDecoding of homeAddressField started...");
        udP->flag = 1;
    }
    else {
        ossPrint(_g, "\nDecoding of homeAddressField completed.\n\n");
        udP->flag = 0;
    }
    return OSS_CONTINUE_DECODING;
}

/* 
    myZipcode callback method implementation.
    it prints the value of zipcode field 
*/
int myCallbackClass::myZipcode(OssGlobal *_g, long offset, long length,
                                                             unsigned int flags, OSS_UINT32  *value) {
    UserData *udP = (UserData *)this->userVar;

    ossPrint(_g, "\n!myZipcode() callback...\n");

    if (udP->flag != 1) {  /* we are not in homeAddress */
        ossPrint(_g, "    we are not in homeAaddress! Continue decoding...\n");
        return OSS_CONTINUE_DECODING;
    }
    /* Print homeAddress zipcode */
    ossPrint(_g, "   zipcode value is %05d\n", *value);

    return OSS_SKIP_TO_PDU_END;
};
void testInfoCallback()
{
    Subscriber_PDU      pdu;
    infotest_Control    ctl;
    EncodedBuffer       eb;
    myCallbackClass     cback;

    cback.userVar = &data;

    ctl.setEncodingRules(OSS_BER);
    eb.set_buffer(sizeof(ber_enc), ber_enc);

    pdu.partialDecode(ctl, eb, cback);
}

Here is the output of the code sample:

!myZipcode() callback...
    we are not in homeAddress! Continue decoding...


Decoding of homeAddressField started...
!myZipcode() callback...
   zipcode value is 67890

For more details about this example, see Effect of OSS.InfoCallback.

See Also


This documentation applies to release 6.5 and later of the OSS® ASN.1 Tools for C++.

Copyright © 2017 OSS Nokalva, Inc. All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted in any form or by any means electronic, mechanical, photocopying, recording or otherwise, without the prior permission of OSS Nokalva, Inc.
Every distributed copy of the OSS® ASN.1 Tools for C++ is associated with a specific license and related unique license number. That license determines, among other things, what functions of the OSS ASN.1 Tools for C++ are available to you.