5.6. Byte-Sequence client & server

In this more advanced example, we will see how we can set up a client exchanging byte sequences with server. The idl definition (byteseq.idl) covers in-, out- and inout-parameters and looks like:

Example 5-22. byteseq.idl

module Examples {
         
        module ByteSeq {
                typedef sequence<octet> Chunk;
                 
                interface Storage {
                        void  set (in Chunk chunk);
                        Chunk get ();
                };
        };
};
Then you have to generate the skeleton and stub files. In addition to these two files the ORBit IDL compiler also generates a common file and a header file. The common file implements the memory management functions and other things, useful in the client as well as in the server. The sequence to generate the C source files is rather simple. $orbit-idl-2 --skeleton-impl byteseq.idl geenrates all the files we will use in this example.

FileUsage for ClientUsage for Server
byteseq.hreadonlyreadonly
byteseq-common.creadonlyreadonly
byteseq-stubs.creadonly-
byteseq-skels.c-readonly
byteseq-skelimpl.c-template for user code

Files remaining to write are listed in following table, starting with byteseq-client.c in following chapter.

byteseq-client.cwrite the client code
byteseq-server.cwrite the generic code for servant creation

5.6.1. Byte-Sequence client

Example 5-23. byteseq-client.c

/* byteseq-client.c hacked by Frank Rehberger
 * <F.Rehberger@xtradyne.de>.  */

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <orbit/orbit.h>

#include "byteseq.h"

#include "examples-toolkit.h" /* ie. etk_etk_abort_if_exception() */
 
static CORBA_ORB  global_orb = CORBA_OBJECT_NIL; /* global orb */
 
/* Is called in case of process signals. it invokes CORBA_ORB_shutdown()
 * function, which will terminate the processes main loop.
 */
static
void
client_shutdown (int sig)
{
        CORBA_Environment  local_ev[1];
        CORBA_exception_init(local_ev);
 
        if (global_orb != CORBA_OBJECT_NIL)
        {
                 CORBA_ORB_shutdown (global_orb, FALSE, local_ev); 
                etk_abort_if_exception (local_ev, "caught exception");
        }
}
 
        
/* Inits ORB @orb using @argv arguments for configuration. For each
 * ORBit options consumed from vector @argv the counter of @argc_ptr
 * will be decremented. Signal handler is set to call
 * echo_client_shutdown function in case of SIGINT and SIGTERM
 * signals.  If error occures @ev points to exception object on
 * return.
 */
static
void
client_init (int               *argc_ptr,
	     char              *argv[],
             CORBA_ORB         *orb,
             CORBA_Environment *ev)
{
        /* init signal handling */
 
        signal(SIGINT,  client_shutdown);
        signal(SIGTERM, client_shutdown);
         
        /* create Object Request Broker (ORB) */
         
         (*orb) = CORBA_ORB_init(argc_ptr, argv, "orbit-local-mt-orb", ev); 
        if (etk_raised_exception(ev)) return;
}

/* Releases @servant object and finally destroys @orb. If error
 * occures @ev points to exception object on return.
 */
static
void
client_cleanup (CORBA_ORB                 orb,
                Examples_ByteSeq_Storage  servant,
                CORBA_Environment        *ev)
{
        /* releasing managed object */
         CORBA_Object_release(servant, ev); 
        if (etk_raised_exception(ev)) return;
 
        /* tear down the ORB */
        if (orb != CORBA_OBJECT_NIL)
        {
                /* going to destroy orb.. */
                 CORBA_ORB_destroy(orb, ev); 
                if (etk_raised_exception(ev)) return;
        }
}

/**
 *
 */
static
void
client_run_set (Examples_ByteSeq_Storage  servant,
		CORBA_Environment        *ev)
{

	CORBA_long LEN      = 4*1024; /* 4KB */ 
	CORBA_long ITER     = 10; 

	CORBA_long iter     = 0; 

	Examples_ByteSeq_Chunk* chunk = NULL;


	/* flood service witth large chunks of byte streams */
	for (iter = 0; iter < ITER; ++iter)
	{
		CORBA_long len      = 0; 
		CORBA_octet elem    = 'A';

		g_print ("+");

	 	chunk = ORBit_sequence_alloc (TC_CORBA_sequence_CORBA_octet,0); 

		for (len = 0; len < LEN; ++len)
		 	ORBit_sequence_append (chunk, &elem); 

		 Examples_ByteSeq_Storage_set (servant, chunk, ev);  
		if (etk_raised_exception(ev)) return;

		CORBA_free (chunk);
	}
}

/**
 *
 */
static
void
client_run_get (Examples_ByteSeq_Storage  servant,
		CORBA_Environment        *ev)
{
	CORBA_long n=10;
	CORBA_long i=0;

	Examples_ByteSeq_Chunk* chunk = NULL; 

	/* increment sequence length, beginning with 0 up to 2048 */
	for (i=0; i<n; ++i)
	{
		g_print ("-");

		 chunk = Examples_ByteSeq_Storage_get (servant, ev);  
		if (etk_raised_exception(ev)) return;

 		CORBA_free (chunk);
	}
}

/*
 * main 
 */
int
main(int argc, char* argv[])
{
	CORBA_char *filename = "byteseq.ref";

        Examples_ByteSeq_Storage  servant = CORBA_OBJECT_NIL;

        CORBA_Environment ev[1];
        CORBA_exception_init(ev);

	 client_init (&argc, argv, &global_orb, ev); 
	etk_abort_if_exception(ev, "init failed");

	g_print ("Reading service reference from file \"%s\"\n", filename);

	 servant = (Examples_ByteSeq_Storage) 
		etk_import_object_from_file (global_orb,
					     filename,
					     ev); 
        etk_abort_if_exception(ev, "exporting IOR failed");

	 client_run_set (servant, ev); 
        etk_abort_if_exception(ev, "client stopped");
 
	 client_run_get (servant, ev); 
        etk_abort_if_exception(ev, "client stopped");
 
	 client_cleanup (global_orb, servant, ev); 
        etk_abort_if_exception(ev, "cleanup failed");
 
        exit (0);
}

5.6.2. Byte-Sequence server

Example 5-24. byteseq-server.c

/*
 * byteseq-server program. Hacked from Examples test suite 
 * by Frank Rehberger <F.Rehberger@xtradyne.de>
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <orbit/orbit.h>

#include "byteseq.h"
#include "byteseq-skelimpl.c" 

#include "examples-toolkit.h" /* provides etk_abort_if_exception() */

static CORBA_ORB          global_orb = CORBA_OBJECT_NIL; /* global orb */
static PortableServer_POA root_poa   = CORBA_OBJECT_NIL; /* root POA
	
/* Is called in case of process signals. it invokes CORBA_ORB_shutdown()
 * function, which will terminate the processes main loop.
 */
static
void
server_shutdown (int sig)
{
	CORBA_Environment  local_ev[1];
	CORBA_exception_init(local_ev);

        if (global_orb != CORBA_OBJECT_NIL)
        {
                 CORBA_ORB_shutdown (global_orb, FALSE, local_ev); 
                etk_abort_if_exception (local_ev, "caught exception");
        }
}

/* Inits ORB @orb using @argv arguments for configuration. For each
 * ORBit options consumed from vector @argv the counter of @argc_ptr
 * will be decremented. Signal handler is set to call
 * echo_server_shutdown function in case of SIGINT and SIGTERM
 * signals.  If error occures @ev points to exception object on
 * return.
 */static 
void 
server_init (int                 *argc_ptr, 
	     char                *argv[],
	     CORBA_ORB           *orb,
	     PortableServer_POA  *poa,
	     CORBA_Environment   *ev)
{
	PortableServer_POAManager  poa_manager = CORBA_OBJECT_NIL; 

	CORBA_Environment  local_ev[1];
	CORBA_exception_init(local_ev);

	/* init signal handling */
	signal(SIGINT,  server_shutdown);
	signal(SIGTERM, server_shutdown);
	
	/* create Object Request Broker (ORB) */
	
         (*orb) = CORBA_ORB_init(argc_ptr, argv, "orbit-local-mt-orb", ev); 
	if (etk_raised_exception(ev)) 
		goto failed_orb;

         (*poa) = (PortableServer_POA) 
		CORBA_ORB_resolve_initial_references(*orb, "RootPOA", ev); 
	if (etk_raised_exception(ev)) 
		goto failed_poa;

         poa_manager = PortableServer_POA__get_the_POAManager(*poa, ev); 
	if (etk_raised_exception(ev)) 
		goto failed_poamanager;

	 PortableServer_POAManager_activate(poa_manager, ev); 
	if (etk_raised_exception(ev)) 
		goto failed_activation;

         CORBA_Object_release ((CORBA_Object) poa_manager, ev); 
	return;

 failed_activation:
 failed_poamanager:
        CORBA_Object_release ((CORBA_Object) poa_manager, local_ev);
 failed_poa:
	CORBA_ORB_destroy(*orb, local_ev);		
 failed_orb:
	return;
}

/* Entering main loop @orb handles incoming request and delegates to
 * servants. If error occures @ev points to exception object on
 * return.
 */
static void 
server_run (CORBA_ORB          orb,
	    CORBA_Environment *ev)
{
        /* enter main loop until SIGINT or SIGTERM */
	
         CORBA_ORB_run(orb, ev); 
	if (etk_raised_exception(ev)) return;

        /* user pressed SIGINT or SIGTERM and in signal handler
	 * CORBA_ORB_shutdown(.) has been called */
}

/* Releases @servant object and finally destroys @orb. If error
 * occures @ev points to exception object on return.
 */
static void 
server_cleanup (CORBA_ORB           orb,
		PortableServer_POA  poa,
		CORBA_Object        ref,
		CORBA_Environment  *ev)
{
	PortableServer_ObjectId   *objid       = NULL;

	 objid = PortableServer_POA_reference_to_id (poa, ref, ev); 
	if (etk_raised_exception(ev)) return;
		
	/* Servant: deactivatoin - will invoke  __fini destructor */
	 PortableServer_POA_deactivate_object (poa, objid, ev); 
	if (etk_raised_exception(ev)) return;

	 PortableServer_POA_destroy (poa, TRUE, FALSE, ev); 
	if (etk_raised_exception(ev)) return;

	CORBA_free (objid);

         CORBA_Object_release ((CORBA_Object) poa, ev); 
	if (etk_raised_exception(ev)) return;
	
         CORBA_Object_release (ref, ev); 
	if (etk_raised_exception(ev)) return;

        /* ORB: tear down the ORB */
        if (orb != CORBA_OBJECT_NIL)
        {
                /* going to destroy orb.. */
                 CORBA_ORB_destroy(orb, ev); 
		if (etk_raised_exception(ev)) return;
        }
}

/* Creates servant and registers in context of ORB @orb. The ORB will
 * delegate incoming requests to specific servant object.  @return
 * object reference. If error occures @ev points to exception object
 * on return.
 */
static CORBA_Object
server_activate_service (CORBA_ORB           orb,
			 PortableServer_POA  poa,
			 CORBA_Environment  *ev)
{
	Examples_ByteSeq_Storage ref = CORBA_OBJECT_NIL;

	 ref = impl_Examples_ByteSeq_Storage__create (poa, ev); 
	if (etk_raised_exception(ev)) 
		return CORBA_OBJECT_NIL;
	
	return ref;
}

/* 
 * main 
 */

int
main (int argc, char *argv[])
{
	CORBA_Object servant = CORBA_OBJECT_NIL;
	
	CORBA_char filename[] = "byteseq.ref";

	CORBA_Environment  ev[1];
	CORBA_exception_init(ev);
	
	 server_init (&argc, argv, &global_orb, &root_poa, ev); 
	etk_abort_if_exception(ev, "failed ORB init");

	 servant = server_activate_service (global_orb, root_poa, ev); 
	etk_abort_if_exception(ev, "failed activating service");

	g_print ("Writing service reference to: %s\n\n", filename);

	 etk_export_object_to_file (global_orb, 
				   servant, 
				   filename, 
				   ev); 
	etk_abort_if_exception(ev, "failed exporting IOR");
	
	 server_run (global_orb, ev); 
	etk_abort_if_exception(ev, "failed entering main loop");

	 server_cleanup (global_orb, root_poa, servant, ev); 
	etk_abort_if_exception(ev, "failed cleanup");

	exit (0);
}

Example 5-25. byteseq-skelimpl.c

/* This is a template file generated by command */
/* orbit-idl-2 --skeleton-impl byteseq.idl */
/* User must edit this file, inserting servant  */
/* specific code between markers. */

#include "byteseq.h"

/*** App-specific servant structures ***/

typedef struct
{
   POA_Examples_ByteSeq_Storage servant;
   PortableServer_POA poa;

   /* ------ add private attributes here ------ */  
    Examples_ByteSeq_Chunk * chunk; 
   /* ------ ---------- end ------------ ------ */
} impl_POA_Examples_ByteSeq_Storage;

/*** Implementation stub prototypes ***/

static void
impl_Examples_ByteSeq_Storage__fini(impl_POA_Examples_ByteSeq_Storage *
				    servant, CORBA_Environment * ev);
static void
impl_Examples_ByteSeq_Storage_set(impl_POA_Examples_ByteSeq_Storage * servant,
				  const Examples_ByteSeq_Chunk * chunk,
				  CORBA_Environment * ev);

static Examples_ByteSeq_Chunk
   *impl_Examples_ByteSeq_Storage_get(impl_POA_Examples_ByteSeq_Storage *
				      servant, CORBA_Environment * ev);


/*** epv structures ***/

static PortableServer_ServantBase__epv impl_Examples_ByteSeq_Storage_base_epv
   = {
   NULL,			/* _private data */
   (gpointer) & impl_Examples_ByteSeq_Storage__fini,	/* finalize routine */
   NULL,			/* default_POA routine */
};
static POA_Examples_ByteSeq_Storage__epv impl_Examples_ByteSeq_Storage_epv = {
   NULL,			/* _private */
   (gpointer) & impl_Examples_ByteSeq_Storage_set,

   (gpointer) & impl_Examples_ByteSeq_Storage_get
};

/*** vepv structures ***/

static POA_Examples_ByteSeq_Storage__vepv impl_Examples_ByteSeq_Storage_vepv = {
   &impl_Examples_ByteSeq_Storage_base_epv,
   &impl_Examples_ByteSeq_Storage_epv,
};

/*** Stub implementations ***/

static Examples_ByteSeq_Storage
impl_Examples_ByteSeq_Storage__create(PortableServer_POA poa,
				      CORBA_Environment * ev)
{
   Examples_ByteSeq_Storage retval;
   impl_POA_Examples_ByteSeq_Storage *newservant;
   PortableServer_ObjectId *objid;

   newservant = g_new0(impl_POA_Examples_ByteSeq_Storage, 1);
   newservant->servant.vepv = &impl_Examples_ByteSeq_Storage_vepv;
   newservant->poa =
      (PortableServer_POA) CORBA_Object_duplicate((CORBA_Object) poa, ev);

   POA_Examples_ByteSeq_Storage__init((PortableServer_Servant) newservant,
				      ev);
   /* Before servant is going to be activated all
    * private attributes must be initialized.  */

   /* ------ init private attributes here ------ */
    newservant->chunk = ORBit_sequence_alloc (TC_CORBA_sequence_CORBA_octet, 64);    
   /* ------ ---------- end ------------- ------ */

   objid = PortableServer_POA_activate_object(poa, newservant, ev);
   CORBA_free(objid);
   retval = PortableServer_POA_servant_to_reference(poa, newservant, ev);

   return retval;
}

/**
 * impl_Examples_ByteSeq_Storage__fini
 * 
 * Destructor called after servant has been deactivated finally.
 * In case any operation is invoked, application is being delayed.
**/
static void
impl_Examples_ByteSeq_Storage__fini(impl_POA_Examples_ByteSeq_Storage *
				    servant, CORBA_Environment * ev)
{
   CORBA_Object_release((CORBA_Object) servant->poa, ev);

   /* No further remote method calls are delegated to 
    * servant and you may free your private attributes. */
   /* ------ free private attributes here ------ */
    CORBA_free (servant->chunk); 
   /* ------ ---------- end ------------- ------ */

   POA_Examples_ByteSeq_Storage__fini((PortableServer_Servant) servant, ev);

   g_free(servant);
}

static void
impl_Examples_ByteSeq_Storage_set(impl_POA_Examples_ByteSeq_Storage * servant,
				  const Examples_ByteSeq_Chunk * chunk,
				  CORBA_Environment * ev)
{
   /* ------   insert method code here   ------ */
    ORBit_sequence_set_size (servant->chunk, chunk->_length);
    
   {
           CORBA_long i=0;
           for (i = 0; i < chunk->_length; ++i)
                   ORBit_sequence_index (servant->chunk, i)
                           = ORBit_sequence_index (chunk, i);
   } 
   /* ------ ---------- end ------------ ------ */
}

static Examples_ByteSeq_Chunk *
impl_Examples_ByteSeq_Storage_get(impl_POA_Examples_ByteSeq_Storage * servant,
				  CORBA_Environment * ev)
{
   Examples_ByteSeq_Chunk *retval;

   /* ------   insert method code here   ------ */
    retval = ORBit_sequence_alloc (TC_CORBA_sequence_CORBA_octet,
                                  servant->chunk->_length);

   {
           CORBA_long i=0;
           for (i = 0; i < servant->chunk->_length; ++i)
                   ORBit_sequence_index (retval, i)
                           = ORBit_sequence_index (servant->chunk, i);
   } 
   /* ------ ---------- end ------------ ------ */

   return retval;
}

5.6.3. Compiling client & server

Example 5-26. Makefile

PREFIX ?= /usr
CC = gcc
TARGETS=byteseq-client byteseq-server
ORBIT_IDL=$(PREFIX)/bin/orbit-idl-2
CFLAGS=-g -DORBIT2=1 -D_REENTRANT -I$(PREFIX)/include/orbit-2.0 \
         -I$(PREFIX)/include/linc-1.0 -I$(PREFIX)/include/glib-2.0 \
         -I$(PREFIX)/lib/glib-2.0/include 
LDFLAGS= -Wl,--export-dynamic  -L$(PREFIX)/lib -lORBit-2 -llinc -lgmodule-2.0 \
             -ldl -lgobject-2.0 -lgthread-2.0 -lpthread -lglib-2.0 -lm        \
             -lORBitCosNaming-2
IDLOUT=byteseq-common.c byteseq-stubs.c byteseq-skels.c byteseq.h

all: $(IDLOUT) byteseq-client byteseq-server

byteseq-server.o: byteseq-server.c byteseq-skelimpl.c
byteseq-client : byteseq-client.o byteseq-stubs.o byteseq-common.o examples-toolkit.o
byteseq-server : byteseq-server.o byteseq-skels.o byteseq-common.o examples-toolkit.o 

$(IDLOUT): byteseq.idl
	$(ORBIT_IDL) byteseq.idl

%-skelimpl.c: %.idl
	$(ORBIT_IDL) --skeleton-impl $^

clean:
	rm -rf *.o *~ $(IDLOUT) 

distclean: clean
	rm -rf byteseq-client byteseq-server