
Procedure for Calling C Encode Functions
This section describes the step-by-step procedure for calling a C BER or DER encode function. This method must be used if C code generation was done. This method can also be used as an alternative to using the control class interface if C++ code generation was done. Note that the procedures described here cannot be used if stream-based encoding is to be done (specified by the use of the -stream ASN1C command-line option). In this case, the procedures described in the Generated BER Stream-Oriented Encode Functions section.
Before any encode function can be called; the user must first initialize an encoding context. This is a variable of type OSCTXT. This variable holds all of the working data used during the encoding of a message. The context variable is declared as a normal automatic variable within the top-level calling function. It must be initialized before use. This can be accomplished by using the rtInitContext function as follows:
OSCTXT ctxt; if (rtInitContext (&ctxt) != 0) { /* initialization failed, could be a license problem */ printf ("context initialization failed (check license)\n"); return -1; }The next step is to specify an encode buffer into which the message will be encoded. This is accomplished by calling the xe_setp run-time function. The user can either pass the address of a buffer and size allocated in his or her program (referred to as a static buffer), or set these parameters to zero and let the encode function manage the buffer memory allocation (referred to as a dynamic buffer). Better performance can normally be attained by using a static buffer because this eliminates the high-overhead operation of allocating and reallocating memory.
After initializing the context and populating a variable of the structure to be encoded, an encode function can be called to encode the message. If the return status indicates success (positive length value), the run-time library function xe_getp can be called to obtain the start address of the encoded message. Note that the returned address is not the start address of the target buffer. BER encoded messages are constructed from back to front (i.e., starting at the end of the buffer and working backwards) so the start point will fall somewhere in the middle of the buffer after encoding is complete. Thisis illustrated in the following diagram:
In this example, a 1K encode buffer is declared which happens to start at address 0x100. When the context is initialized with a pointer to this buffer and size equal to 1K, it positions the internal encode pointer to the end of the buffer (address 0x500). Encoding then proceeds from back-to-front until encoding of the message is complete. In this case, the encoded message turned out to be 0x300 (768) bytes in length and the start address fell at 0x200. This is the value that would be returned by the xe_getp function.
#include employee.h /* include file generated by ASN1C */ int main () { OSOCTET msgbuf[1024], *msgptr; int msglen; OSCTXT ctxt; Employee employee; /* typedef generated by ASN1C */ /* Step 1: Initialize the context and set the buffer pointer */ if (rtInitContext (&ctxt) != 0) { /* initialization failed, could be a license problem */ printf ("context initialization failed (check license)\n"); return -1; } xe_setp (&ctxt, msgbuf, sizeof(msgbuf)); /* Step 2: Populate the structure to be encoded */ employee.name.givenName = "SMITH"; ... /* Step 3: Call the generated encode function */ msglen = asn1E_Employee (&ctxt, &employee, ASN1EXPL); /* Step 4: Check the return status (note: the test is * > 0 because the returned value is the length of the * encoded message component).. */ if (msglen > 0) { /* Step 5: If encoding is successful, call xe_getp to * fetch a pointer to the start of the encoded message. */ msgptr = xe_getp (&ctxt); ... } else { rtxErrPrint (&ctxt); return msglen; } }In general, static buffers should be used for encoding messages where possible as they offer a substantial performance benefit over dynamic buffer allocation. The problem with static buffers, however, is that you are required to estimate in advance the approximate size of the messages you will be encoding. There is no built-in formula to do this, the size of an ASN.1 message can vary widely based on data types and the number of tags required.
If performance is not a significant an issue, then dynamic buffer allocation is a good alternative. Setting the buffer pointer argument to NULL in the call to xe_setp specifies dynamic allocation. This tells the encoding functions to allocate a buffer dynamically. The address of the start of the message is obtained as before by calling xe_getp. Note that this is not the start of the allocated memory; that is maintained within the context structure. To free the memory, the rtMemFree run-time macro must be called.
#include employee.h /* include file generated by ASN1C */ main () { OSOCTET* msgptr; int msglen; OSCTXT ctxt; Employee employee; /* typedef generated by ASN1C */ if (rtInitContext (&ctxt) != 0) { /* initialization failed, could be a license problem */ printf ("context initialization failed (check license)\n"); return -1; } xe_setp (&ctxt, NULL, 0); employee.name.givenName = "SMITH"; ... msglen = asn1E_Employee (&ctxt, &employee, ASN1EXPL); if (msglen > 0) { msgptr = xe_getp (&ctxt); ... rtxMemFree (&ctxt); /* don't call free (msgptr); !!! */ } else error processing... }
Objective Systems, Inc.55 Dowlin Forge RoadExton, Pennsylvania 19341 http://www.obj-sys.com Phone: (484) 875-9841 Toll-free: (877) 307-6855 (US only) Fax: (484) 875-9830 info@obj-sys.com |