6 Using the C Client Back-end
6.1 Introduction
The mapping of OMG IDL to the C programming language when C Server switch is the back-end of choice is identical to the one used in C IDL mapping. The only difference is on the generated code, and that the idl functions are translated to C functions for the C client.
6.2 When to Use the C-Client?
A C-client uses the same communication protocol as an Erlang client to genservers, as it is actually a C-genserver client. Therefore, the C-client can be used for:
- Calling functions served by C-servers generated by the C-server back-end.
- Calling functions served by Erlang-genservers generated by the Erlang genserver back-end.
6.3 What Kind of Code is Produced?
The code produced is a collection of:
- C source files that contain interface code.
These files are named after the< Scoped Interface Name >s.c
convention
- C source files that contain code for:
- type conversion
- memory allocation
- data encoding / decoding into buffers
- C header files that contain function headers and type definitions.
All functions found in the code are exported. The user is free to define his own client if there is a need for this. The basic client generated is a
synchronous
client, but anasynchronous
client can be implemented by proper use of exported functions.6.4 What Does This Code Do when Used?
The main functionality of a C client is to:
- Encode call request messages.
- Write messages to a specified file descriptor.
- Read from a specified file descriptor.
- Decode the reply messages.
- Return output values
6.5 What Is the Interface of the Functions Produced?
The C source defines the following functions:
- One client function for each IDL function.
- One specific message encoder function for each IDL function.
- One specific call function for each function defined in the interface.
- One generic reply message decoder function for each IDL interface.
- One specific return value decoder function for each IDL function.
The interface for the client function is:
< Return Value > < Scoped Function Name > ( < Interface Object > oe_obj, < Parameters > CORBA_Environment *oe_env );
Where:
< Return Value >
is the return value is the value to be returned as defined by the IDL specification for the operation.
< Interface Object > oe_obj
is the client interface object.
< Parameters >
are the parameters to the operation in the same order as defined by the IDL specdication for the operation.
CORBA_Environment *oe_env
is a pointer to the current client environment as described in section 3.6.
The interface for the message encoding functions is:
int < Scoped Function Name >__client_enc(< Interface Object > oe_obj, < Input Parameters > CORBA_Environment *oe_env );
Where:
< Interface Object > oe_obj
is the client interface object.
< Input Parameters >
are all theinput
parameters to the operation in the same order as defined by the IDL specification for the operation.
CORBA_Environment *oe_env
is a pointer to the current client environment as described in section 3.6.
- the return value for the client is an
int
which is positive or zero when the call is succeed, negative otherwise
The interface for the specific result value decoder is:
int < Scoped Function Name >__client_dec(< Interface Object > oe_obj, < Return/Out Values > CORBA_Environment *oe_env);
Where:
< Interface Object > oe_obj
is the client interface object.
< Return/Out Values >
are return values in order similar to the IDL defined function's.
CORBA_Environment *oe_env
is a pointer to the current client environment as described in section 3.6.
- the return value for the client is an
int
which is positive or zero when the call is succeed, negative otherwise
The interface for the generic decoding function is:
int < Scoped Interface Name >__receive_info(< Interface Object > oe_obj, CORBA_Environment *oe_env );
Where:
< Interface Object > oe_obj
is the client interface object.
CORBA_Environment *oe_env
is a pointer to the current client environment as described in section 3.6.
- the return value for the client is an
int
which is positive or zero when the call is succeed, negative otherwise
6.6 Functions Used for Internal Purposes
Depending on the data defined and used in the IDL code, C-source files may be generated that hold functions used internally. This is the case when other types than the elementary IDL types are used by the IDL file definitions. All these files must be compiled and linked to the other code.
6.7 Which Header Files to Include?
The only header files that must be included are :
- the interface files, the files named
< Scoped Interface Name >.h
.
6.8 Which Directories/Libraries/Options must Be Included under C-compiling?
Under compilation you will have to include :
- the directory
$OTPROOT/ usr/ include
Under linking you will have to link with :
- the libraries under
$OTPROOT/ usr/ lib
- -lerl_interface -lei -lnsl -lsocket -lic
6.9 Compiling the Code
In the Erlang shell type:
ic:gen(< filename >, [{be, c_client}])
.6.10 An Example
In this example, a file "random.idl" is generates code for the plain erlang back-end:
- Main file: "random.idl"
module rmod { interface random { double produce(); oneway void init(in long seed1, in long seed2, in long seed3); }; };
Compile the file:
Erlang (BEAM) emulator version 4.9 Eshell V4.9 (abort with ^G) 1> ic:gen(random,[{be, c_client}]). Erlang IDL compiler version 3.2 ok 2>When the file "random.idl" is compiled it produces five files, two for the top scope, two for the interface scope, and one for the module scope. The header files for top scope and interface are empty and not shown here. In this case only the file for the interface
rmod_random.erl
is important:.
- C file for interface: "rmod_random.c"
#include <stdlib.h> #include <string.h> #include "ic.h" #include "erl_interface.h" #include "ei.h" #include "rmod_random.h" /* * Object interface function "rmod_random_produce" */ CORBA_double rmod_random_produce(rmod_random oe_obj, CORBA_Environment *oe_env) { CORBA_double oe_result; int oe_msgType = 0; erlang_msg oe_msg; /* Initiating the message reference */ strcpy(oe_env->_unique.node,erl_thisnodename()); oe_env->_unique.creation = erl_thiscreation(); oe_env->_unique.id = 0; /* Initiating exception indicator */ oe_env->_major = CORBA_NO_EXCEPTION; /* Creating call message */ if (rmod_random_produce__client_enc(oe_obj, oe_env) < 0) { if (oe_env->_major == CORBA_NO_EXCEPTION) CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, MARSHAL, "Cannot encode message"); return oe_result; } /* Sending call request */ if (strlen(oe_env->_regname) == 0) { if (ei_send_encoded(oe_env->_fd, oe_env->_to_pid, oe_env->_outbuf, oe_env->_iout) < 0) { CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE, "Cannot connect to server"); return oe_result; } } else if (ei_send_reg_encoded(oe_env->_fd, oe_env->_from_pid, oe_env->_regname, oe_env->_outbuf, oe_env->_iout) < 0) { CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE, "Cannot connect to server"); return oe_result; } /* Receiving reply message */ do { if ((oe_msgType = ei_receive_encoded(oe_env->_fd, &oe_env->_inbuf, &oe_env->_inbufsz, &oe_msg, &oe_env->_iin)) < 0) { CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, MARSHAL, "Cannot decode message"); return oe_result; } } while (oe_msgType != ERL_SEND && oe_msgType != ERL_REG_SEND); /* Extracting message header */ if (rmod_random__receive_info(oe_obj, oe_env) < 0) { CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, MARSHAL, "Bad message"); return oe_result; } /* Extracting return value(s) */ if (rmod_random_produce__client_dec(oe_obj, &oe_result, oe_env) < 0) { CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, DATA_CONVERSION, "Bad return/out value(s)"); } return oe_result; } /* * Encodes the function call for "rmod_random_produce" */ int rmod_random_produce__client_enc(rmod_random oe_obj, CORBA_Environment *oe_env) { int oe_error_code = 0; oe_env->_iout = 0; oe_ei_encode_version(oe_env); oe_ei_encode_tuple_header(oe_env, 3); oe_ei_encode_atom(oe_env, "$gen_call"); oe_ei_encode_tuple_header(oe_env, 2); if ((oe_error_code = oe_ei_encode_pid(oe_env,oe_env->_from_pid)) < 0) return oe_error_code; if ((oe_error_code = oe_ei_encode_ref(oe_env,&oe_env->_unique)) < 0) return oe_error_code; oe_ei_encode_atom(oe_env, "produce"); return 0; } /* * Decodes the return value for "rmod_random_produce" */ int rmod_random_produce__client_dec(rmod_random oe_obj, CORBA_double* oe_result, CORBA_Environment *oe_env) { int oe_error_code = 0; /* Decode result value: CORBA_double* oe_result */ if ((oe_error_code = ei_decode_double(oe_env->_inbuf, &oe_env->_iin, oe_result)) < 0) return oe_error_code; return 0; } /* * Object interface function "rmod_random_init" */ void rmod_random_init(rmod_random oe_obj, CORBA_long seed1, CORBA_long seed2, CORBA_long seed3, CORBA_Environment *oe_env) { /* Initiating exception indicator */ oe_env->_major = CORBA_NO_EXCEPTION; /* Creating call message */ if (rmod_random_init__client_enc(oe_obj, seed1, seed2, seed3, oe_env) < 0) { if (oe_env->_major == CORBA_NO_EXCEPTION) CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, MARSHAL, "Cannot encode message"); } /* Sending call request */ if (oe_env->_major == CORBA_NO_EXCEPTION) { if (strlen(oe_env->_regname) == 0) { if (ei_send_encoded(oe_env->_fd, oe_env->_to_pid, oe_env->_outbuf, oe_env->_iout) < 0) { CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE, "Cannot connect to server"); } } else if (ei_send_reg_encoded(oe_env->_fd, oe_env->_from_pid, oe_env->_regname, oe_env->_outbuf, oe_env->_iout) < 0) { CORBA_exc_set(oe_env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE, "Cannot connect to server"); } } } /* * Encodes the function call for "rmod_random_init" */ int rmod_random_init__client_enc(rmod_random oe_obj, CORBA_long seed1, CORBA_long seed2, CORBA_long seed3, CORBA_Environment *oe_env) { int oe_error_code = 0; oe_env->_iout = 0; oe_ei_encode_version(oe_env); oe_ei_encode_tuple_header(oe_env, 2); oe_ei_encode_atom(oe_env, "$gen_cast"); oe_ei_encode_tuple_header(oe_env, 4); oe_ei_encode_atom(oe_env, "init"); /* Encode parameter: CORBA_long seed1 */ if ((oe_error_code = oe_ei_encode_long(oe_env, seed1)) < 0) return oe_error_code; /* Encode parameter: CORBA_long seed2 */ if ((oe_error_code = oe_ei_encode_long(oe_env, seed2)) < 0) return oe_error_code; /* Encode parameter: CORBA_long seed3 */ if ((oe_error_code = oe_ei_encode_long(oe_env, seed3)) < 0) return oe_error_code; return 0; } /* * Generic function, used to return received message information. * Not used by oneways. Allways generated. */ int rmod_random__receive_info(rmod_random oe_obj, CORBA_Environment *oe_env) { int oe_error_code = 0; int oe_rec_version = 0; erlang_ref oe_unq; oe_env->_iin = 0; oe_env->_received = 0; if ((oe_error_code = ei_decode_version(oe_env->_inbuf, &oe_env->_iin, &oe_rec_version)) < 0) return oe_error_code; if ((oe_error_code = ei_decode_tuple_header(oe_env->_inbuf, &oe_env->_iin, &oe_env->_received)) < 0) return oe_error_code; if ((oe_error_code = ei_decode_ref(oe_env->_inbuf, &oe_env->_iin, &oe_unq)) < 0) return oe_error_code; /* Checking message reference*/ if(strcmp(oe_env->_unique.node,oe_unq.node) != 0) return -1; if(oe_env->_unique.id != oe_unq.id) return -1; return 0; }
Compiling the code:
- Please read the
ReadMe
file att theic-3.2/examples/c-client
directory
In the same directory you can find all the code for this example
Due to changes to allow buffer expansion, a new receiving function some changes in CORBA_Environment initialization are applied. The example in the ic-3.2/examples/c-client directory demonstrates these changes.
Running the example:
- Please check the
ReadMe
file att theic-3.2/examples/c-client
directory
In the same directory you can find all the code for this example