itevad – How to write your own protocol and its stack – part 5

Previous_Part_4

In this post, we will begin our Itevad Protocol Text Encoder. Again, with the help of ASN.1 compiler, we have already got the structure of Itevad itself. Moreover, we have implemented binary encoder and decoder in previous post. For text encoder, all we need to do is parse the structure of Itevad msg and then translate it into text. Cheers!

/* Message examples for Text ItevadProtocol */
[root@localhost ItevadBin]# cat itevad_text_msg.example
Itevad/1 [31.31.31.31]:7777
Transaction = 1 {
 Ask = "who r you?"
}

Itevad/2 [11.11.11.11]:6666
Reply = 1 {
 Answer = "i am itevad"
}
[root@localhost ItevadBin]#


/* Text encoder for Text Itevad Protocol */
[root@localhost Itevad2]# cat itevadTxtEncoder.c
/*
Itevad Protocol Text Encoder Example
http://daveti.blog.com
April 5, 2012
Reference: Using the Open Source ASN.1 Compiler
by Lev Walkin
*/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include "ItevadMessage.h"

#define TEXT_ENCODE_BUFFER_SIZE_MAX 1000

#define PTR_MOVE( step, forward, backward) 
 { 
 forward += step; 
 backward -= step; 
 if ( backward < 0) 
 { 
 fprintf( stderr, "No buffer left" 
 " - backward: %dn", backward); 
 } 
 }

/*
Text encoding helper function
to convert OCTET_STRING to string.
*/
char *txt_octetString2String( OCTET_STRING_t *octetString)
{
 /* Defensive checking */
 if ( octetString == NULL)
 {
 fprintf( stderr, "Invalid parametern");
 return NULL;
 }
 if ( octetString->size <= 0)
 {
 fprintf( stderr, "Empty Octet stringn");
 return NULL;
 }

 /* Allocate the string buffer from HEAP */
 char *string = (char *)calloc( 1, (octetString->size+1));

 /* Convert the uint8_t into ASCII characters */
 int i;
 for ( i = 0; i < octetString->size; i++)
 {
 string[ i] = (char)octetString->buf[ i];
 }

 /* Though redundant - just make it clear:) */
 string[ octetString->size] = '';

 return string;
}

/*
Text encoding core function
to convert the ItevadMessage_t type
into Text based Itevad message.
*/
int txt_encode( char *encodeBuffer, ItevadMessage_t *itevadMsg)
{
 /* Defensive checking */
 if ( (encodeBuffer == NULL) || (itevadMsg == NULL))
 {
 fprintf( stderr, "Invalid parametersn");
 return -1;
 }

 /* Go thru itevadMsg to do Text encoding */

 char *txtPtr = encodeBuffer;
 int lengthOfBuffer = TEXT_ENCODE_BUFFER_SIZE_MAX;
 int numOfChar = 0;

 /* Construct msg header */
 numOfChar = snprintf( txtPtr, lengthOfBuffer,
 "Itevad/%d ", itevadMsg->version);
 PTR_MOVE( numOfChar, txtPtr, lengthOfBuffer);

 /* Construct IP address */
 if ( itevadMsg->ip4Address.address.size != 4)
 {
 fprintf( stderr, "Invalid IP address size: %dn",
 itevadMsg->ip4Address.address.size);
 return -1;
 }
 numOfChar = snprintf( txtPtr, lengthOfBuffer,
 "[%u.%u.%u.%u]",
 itevadMsg->ip4Address.address.buf[ 0],
 itevadMsg->ip4Address.address.buf[ 1],
 itevadMsg->ip4Address.address.buf[ 2],
 itevadMsg->ip4Address.address.buf[ 3]);
 PTR_MOVE( numOfChar, txtPtr, lengthOfBuffer);

 /* Construct the port number if it is available */
 if ( itevadMsg->ip4Address.portNumber != NULL)
 {
 numOfChar = snprintf( txtPtr, lengthOfBuffer,
 ":%ld", *(itevadMsg->ip4Address.portNumber));
 PTR_MOVE( numOfChar, txtPtr, lengthOfBuffer);
 }

 /* Move to a new line */
 numOfChar = snprintf( txtPtr, lengthOfBuffer, "%s", "n");
 PTR_MOVE( numOfChar, txtPtr, lengthOfBuffer);

 /* Construct the Transaction */
 long transId = 0;
 char *contentP = NULL;
 switch ( itevadMsg->messageBody.present)
{
 case MessageBody_PR_messageRequest:
 {
 /* Get the transId */
 if ( asn_INTEGER2long(
 &(itevadMsg->messageBody.choice.messageRequest.transactionId),
 &(transId)) == -1)
 {
 fprintf( stderr, "Encode transId in messageRequest errorn");
 return -1;
 }

 /* Get the ask content */
 contentP = txt_octetString2String(
 &(itevadMsg->messageBody.choice.messageRequest.askContent));

 numOfChar = snprintf( txtPtr, lengthOfBuffer,
 "Transaction = %ld {n"
 "tAsk = "%s"n"
 "}n",
 transId, contentP);
 }
 break;

 case MessageBody_PR_messageReply:
 {
 /* Get the transId */
 if ( asn_INTEGER2long(
 &(itevadMsg->messageBody.choice.messageReply.transactionId),
 &(transId)) == -1)
 {
 fprintf( stderr, "Encode transId in messageReply errorn");
 return -1;
 }

 /* Get the answer content */
 contentP = txt_octetString2String(
 &(itevadMsg->messageBody.choice.messageReply.answerContent));

 numOfChar = snprintf( txtPtr, lengthOfBuffer,
 "Reply = %ld {n"
 "tAnswer = "%s"n"
 "}n",
 transId, contentP);
 }
 break;

 default:
 {
 fprintf( stderr, "Invalid message type: %dn",
 itevadMsg->messageBody.present);
 return -1;
 }
 break;
 }

 free( contentP);
 PTR_MOVE( numOfChar, txtPtr, lengthOfBuffer);

 return (txtPtr - encodeBuffer);
}

int main( int ac, char **av)
{
 /* Type to encode */
 ItevadMessage_t *itevadMsg;

 /* Return value for Text encoding */
 int ec;

 /* Text encoding buffer */
 char textEncodeBuffer[ TEXT_ENCODE_BUFFER_SIZE_MAX] = {0};

 /* Allocate the ItevadMessage_t */
 itevadMsg = calloc( 1, sizeof(ItevadMessage_t));
 if ( !itevadMsg)
 {
 perror("calloc() failed");
 exit(71); /* better, EX_OSERR */
 }

 /* Initialize the ItevadMessage members */

 /* Set version number - 1 */
 itevadMsg->version = 1;

 /* Set IPv4 address - "1111" */
 if ( OCTET_STRING_fromString( &(itevadMsg->ip4Address.address), "1111") == -1)
 {
 perror("OCTET_STRING_fromString() failed for encoding 'address'");
 exit(71);
 }

 /* Set port number - 7777 */
 long portNumber = 7777;
 itevadMsg->ip4Address.portNumber = &portNumber;

 /* Set the msg as a request */
 itevadMsg->messageBody.present = MessageBody_PR_messageRequest;

 /* Set the transId - 0xffff */
 long transId = 0xffff;
 if ( asn_long2INTEGER( &(itevadMsg->messageBody.choice.messageRequest.transactionId),
 transId) == -1)
 {
 perror("asn_long2INTEGER() failed for encoding 'transId'");
 exit(71);
 }

 /* Set the askContent - 'who r you?' */
 const char* askContent = "who r you?";
 if ( OCTET_STRING_fromString( &(itevadMsg->messageBody.choice.messageRequest.askContent),
 askContent) == -1)
 {
 perror("OCTET_STRING_fromString() failed for encoding 'askContent'");
 exit(71);
 }

 /* Text encode the data if filename is given */
 if ( ac < 2)
 {
 fprintf( stderr, "Specify filename for Text outputn");
 }
 else
 {
 /* NOTE: need memory deallocaiton before exit ! */

 /* Encode the ItevadMessage type as Text */
 ec = txt_encode( textEncodeBuffer, itevadMsg);

 if ( ec == -1)
 {
 fprintf( stderr, "Could not encode ItevadMessagen");
 exit(65); /* Better, EX_DATAERR */
 }
 else
 {
 /* Write the encoded msg into file */
 const char *filename = av[ 1];
 FILE *fp = fopen( filename, "wb"); /* for Text output */
 if ( !fp)
 {
 perror( filename);
 exit(71);
 }
 fprintf( fp, "%s", textEncodeBuffer);
 fclose( fp);

 fprintf( stderr, "Created %s with Text encoded ItevadMessagen", filename);
 }
 } /* else... */

 /* Also print the constructured Itevad XER encoded (XML) */
 xer_fprint( stdout, &asn_DEF_ItevadMessage, itevadMsg);

 /* NOTE: Need memory deallocaiton here! */

 /* Encoding finished successfully */
 return 0;
}
[root@localhost Itevad2]#


/* Generate and run itevadTxtEncoderBin */
[root@localhost itevad2]# gcc -I. -o itevadTxtEncoderBin *.c
[root@localhost Itevad2]# ./itevadTxtEncoderBin itevad_text.msg
Created itevad_text.msg with Text encoded ItevadMessage
<ItevadMessage>
    <version>1</version>
    <ip4Address>
        <address>31 31 31 31</address>
        <portNumber>7777</portNumber>
    </ip4Address>
    <messageBody>
        <messageRequest>
            <transactionId>65535</transactionId>
            <askContent>who r you?</askContent>
        </messageRequest>
    </messageBody>
</ItevadMessage>
[root@localhost Itevad2]# cat itevad_text.msg
Itevad/1 [49.49.49.49]:7777
Transaction = 65535 {
 Ask = "who r you?"
}
[root@localhost Itevad2]#

About daveti

Interested in kernel hacking, compilers, machine learning and guitars.
This entry was posted in Dave's Tools, H.248/MEGACO/EGCP, Programming, Stuff about Compiler and tagged , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.