/*
* %CopyrightBegin%
*
* Copyright Ericsson AB 1998-2009. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* %CopyrightEnd%
*
*/
#include <ic.h>
static int oe_send(CORBA_Environment *env);
void CORBA_free(void *p)
{
if (p != NULL)
free(p);
}
CORBA_char *CORBA_string_alloc(CORBA_unsigned_long len)
{
return (CORBA_char *) malloc(len+1);
}
CORBA_wchar *CORBA_wstring_alloc(CORBA_unsigned_long len)
{
return (CORBA_wchar *) malloc(len*(__OE_WCHAR_SIZE_OF__+1));
}
CORBA_Environment *CORBA_Environment_alloc(int inbufsz, int outbufsz)
{
CORBA_Environment *env;
env = malloc(sizeof(CORBA_Environment));
if (env != NULL) {
/* CORBA */
env->_major = CORBA_NO_EXCEPTION;
/* Set by user */
env->_fd= -1;
env->_inbufsz = inbufsz;
env->_inbuf = malloc(inbufsz);
env->_outbufsz = outbufsz;
env->_outbuf = malloc(outbufsz);
env->_memchunk = __OE_MEMCHUNK__;
env->_regname[0] = '\0';
env->_to_pid = NULL;
env->_from_pid = NULL;
/* Set by client or server */
env->_iin = 0;
env->_iout = 0;
env->_operation[0] = '\0';
env->_received = 0;
/* env->_caller */
/* env->_unique */
env->_exc_id = NULL;
env->_exc_value = NULL;
env->_ref_counter_1 = 0;
env->_ref_counter_2 = 0;
env->_ref_counter_3 = 0;
}
return env;
}
#if 0
/* NOT EXPORTED SO FAR */
void CORBA_Environment_free(CORBA_Environment *env)
{
CORBA_free(env->_inbuf);
CORBA_free(env->_outbuf);
CORBA_exception_free(env);
CORBA_free(env);
}
#endif
CORBA_char *CORBA_exception_id(CORBA_Environment *env)
{
return env->_exc_id;
}
void *CORBA_exception_value(CORBA_Environment *env)
{
return env->_exc_value;
}
void CORBA_exception_free(CORBA_Environment *env)
{
/* Setting major value */
env->_major=CORBA_NO_EXCEPTION;
/* Freeing storage */
CORBA_free(env->_exc_id);
CORBA_free(env->_exc_value);
env->_exc_id = env->_exc_value = NULL;
}
void CORBA_exc_set(CORBA_Environment *env,
CORBA_exception_type Major,
CORBA_char *Id,
CORBA_char *Value)
{
int ilen,vlen;
/* Create exception only if exception not already set */
if (env->_major == CORBA_NO_EXCEPTION) {
/* Counting lengths */
ilen = strlen(Id)+1;
vlen = strlen(Value)+1;
/* Allocating storage */
env->_exc_id = (CORBA_char *) malloc(ilen);
env->_exc_value = (CORBA_char *) malloc(vlen);
/* Initiating */
env->_major = Major;
strcpy(env->_exc_id,Id);
strcpy(env->_exc_value,Value);
}
}
#define ERLANG_REF_NUM_SIZE 18
#define ERLANG_REF_MASK (~(~((unsigned int)0) << ERLANG_REF_NUM_SIZE))
/* Initiating message reference */
void ic_init_ref(CORBA_Environment *env, erlang_ref *ref)
{
strcpy(ref->node, erl_thisnodename());
ref->node_org_enc = ERLANG_LATIN1;
ref->len = 3;
++env->_ref_counter_1;
env->_ref_counter_1 &= ERLANG_REF_MASK;
if (env->_ref_counter_1 == 0)
if (++env->_ref_counter_2 == 0)
++env->_ref_counter_3;
ref->n[0] = env->_ref_counter_1;
ref->n[1] = env->_ref_counter_2;
ref->n[2] = env->_ref_counter_3;
ref->creation = erl_thiscreation();
}
/* Comparing message references */
int ic_compare_refs(erlang_ref *ref1, erlang_ref *ref2)
{
int i;
if(strcmp(ref1->node, ref2->node) != 0)
return -1;
if (ref1->len != ref2->len)
return -1;
for (i = 0; i < ref1->len; i++)
if (ref1->n[i] != ref2->n[i])
return -1;
return 0;
}
/* Length counter for wide strings */
int ic_wstrlen(CORBA_wchar * p)
{
int len = 0;
while(1) {
if (p[len] == 0)
return len;
len+=1;
}
}
/* Wide string compare function */
int ic_wstrcmp(CORBA_wchar * ws1, CORBA_wchar * ws2)
{
int index = 0;
while(1) {
if (ws1[index] == ws2[index]) {
if (ws1[index] == 0)
return 0;
index += 1;
} else
return -1;
}
}
/* For backward compatibility -- replaced by prepare_request_decoding() */
int ___call_info___(CORBA_Object obj, CORBA_Environment *env)
{
return oe_prepare_request_decoding(env);
}
/* #define DEBUG_MAP */
#if defined(DEBUG_MAP)
#define PRINT_MAPS(P, M, S) print_maps(P, M, S)
#define PRINT_MAP(T, M) print_map(T, "", M)
static void print_map(char *title, char *prefix, oe_map_t *map)
{
if (map == NULL) {
fprintf(stdout, "%s => NULL\n", title);
return;
}
fprintf(stdout, "%s%s\n", prefix, title);
{
int j, len = map->length;
fprintf(stdout, "%s length: %d\n", prefix, len);
fprintf(stdout, "%s operations: 0x%X%d\n", prefix, map->operations);
for (j = 0 ; j < len ; j++) {
fprintf(stdout, "%s operation[%d]:\n", prefix, j);
if (map->operations[j].interface != NULL) {
fprintf(stdout, "%s intf: %s\n", prefix,
map->operations[j].interface);
} else {
fprintf(stdout, "%s intf: NULL\n", prefix);
}
fprintf(stdout, "%s name: %s\n", prefix,
map->operations[j].name);
fprintf(stdout, "%s func: 0x%X\n", prefix,
map->operations[j].function);
}
}
fflush(stdout);
}
static void print_maps(char* title, oe_map_t * maps, int size)
{
int i;
char p[64];
fprintf(stdout, "%s\n", title);
for (i = 0 ; i < size ; i++) {
sprintf(p, "map[%d]:", i);
print_map(p, " ", &maps[i]);
}
fprintf(stdout, "\n");
fflush(stdout);
}
#else
#define PRINT_MAPS(P, M, S)
#define PRINT_MAP(T, M)
#endif /* if defined(DEBUG_MAP) */
/* Generic server switch */
int oe_exec_switch(CORBA_Object obj, CORBA_Environment *env, oe_map_t *map)
{
/* Setting local variables */
int res = 0;
int index = 0;
/* XXX map may be NULL !! */
int length = map->length;
char* op = env->_operation;
PRINT_MAP("switching on map", map);
/* Initiating exception indicator */
env->_major = CORBA_NO_EXCEPTION;
if ((res = oe_prepare_request_decoding(env) < 0))
return res;
#if defined(DEBUG_MAP)
fprintf(stdout, "looking for operation: %s\n", op); fflush(stdout);
#endif
for (index = 0; index < length; index++) {
#if defined(DEBUG_MAP)
fprintf(stdout, "map->operations[%d].name: %s\n",
index, map->operations[index].name);
fflush(stdout);
#endif
if(strcmp(map->operations[index].name, op) == 0) {
#if defined(DEBUG_MAP)
fprintf(stdout, "calling map->operations[%d].function: 0x%X\n",
index, map->operations[index].function);
fflush(stdout);
#endif
return map->operations[index].function(obj, env);
}
}
/* Bad call */
CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, BAD_OPERATION,
"Invalid operation");
return -1;
}
/* For backward compatibility */
int ___switch___(CORBA_Object obj, CORBA_Environment *env, oe_map_t *map)
{
return oe_exec_switch(obj, env, map);
}
oe_map_t* oe_merge_maps(oe_map_t *maps, int size)
{
int i, j, length, len, maplen, malloc_size;
void *memp;
oe_map_t *merged;
if ((maps == NULL) || (size <= 0))
return NULL;
PRINT_MAPS("merging maps", maps, size);
length = 0;
for (i = 0; i < size; i++)
length += (maps[i].length);
maplen = OE_ALIGN(sizeof(oe_map_t));
malloc_size = maplen + OE_ALIGN(length*sizeof(oe_operation_t));
if ((memp = malloc(malloc_size)) == NULL)
return NULL;
merged = memp;
merged->length = length;
merged->operations = (oe_operation_t *)((char*)memp + maplen);
for (i = 0, len = 0; i < size; i++) {
for(j = 0 ; j < maps[i].length; j++)
merged->operations[len+j] = maps[i].operations[j];
len += maps[i].length;
}
PRINT_MAP("merged map", merged);
return merged;
}
/* For backward compatibility */
oe_map_t* ___merge___(oe_map_t *maps, int size)
{
return oe_merge_maps(maps, size);
}
/* Client send message (Erlang distribution protocol) */
static int oe_send(CORBA_Environment *env)
{
if (strlen(env->_regname) == 0) {
if (ei_send_encoded(env->_fd, env->_to_pid, env->_outbuf,
env->_iout) < 0) {
/* XXX Cannot send to peer? */
CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE,
"Cannot connect to server");
return -1;
}
} else {
if (ei_send_reg_encoded(env->_fd, env->_from_pid,
env->_regname, env->_outbuf,
env->_iout) < 0) {
/* XXX Cannot send to peer? */
CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, NO_RESPONSE,
"Cannot connect to server");
return -1;
}
}
return 0;
}
/* Send notification (gen_server client) */
int oe_send_notification(CORBA_Environment *env)
{
return oe_send(env);
}
/* Send request and receive reply (gen_server client) */
int oe_send_request_and_receive_reply(CORBA_Environment *env)
{
int msgType = 0;
erlang_msg msg;
if (oe_send(env) < 0)
return -1;
do {
if ((msgType = ei_receive_encoded(env->_fd,
&env->_inbuf,
&env->_inbufsz,
&msg, &env->_iin)) < 0) {
CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL,
"Cannot decode message");
return -1;
}
} while (msgType != ERL_SEND && msgType != ERL_REG_SEND);
/* Extracting return message header */
if (oe_prepare_reply_decoding(env) < 0) {
CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL, "Bad message");
return -1;
}
return 0;
}
/* Prepare notification encoding (gen_server client) */
int oe_prepare_notification_encoding(CORBA_Environment *env)
{
env->_iout = 0;
oe_ei_encode_version(env);
oe_ei_encode_tuple_header(env, 2);
oe_ei_encode_atom(env, "$gen_cast");
return 0;
}
/* Prepare request encoding (gen_server client) */
int oe_prepare_request_encoding(CORBA_Environment *env)
{
int error = 0;
env->_iout = 0;
oe_ei_encode_version(env);
oe_ei_encode_tuple_header(env, 3);
oe_ei_encode_atom(env, "$gen_call");
oe_ei_encode_tuple_header(env, 2);
if ((error = oe_ei_encode_pid(env, env->_from_pid)) < 0)
return error;
if ((error = oe_ei_encode_ref(env, &env->_unique)) < 0)
return error;
return 0;
}
/* Prepare reply decoding (gen_server client) */
int oe_prepare_reply_decoding(CORBA_Environment *env)
{
int error = 0;
int version = 0;
erlang_ref unique;
env->_iin = 0;
env->_received = 0;
if ((error = ei_decode_version(env->_inbuf,
&env->_iin,
&version)) < 0)
return error;
if ((error = ei_decode_tuple_header(env->_inbuf,
&env->_iin,
&env->_received)) < 0)
return error;
if ((error = ei_decode_ref(env->_inbuf,
&env->_iin,
&unique)) < 0)
return error;
return ic_compare_refs(&env->_unique, &unique);
}
/* Prepare request decoding (gen_server server) */
int oe_prepare_request_decoding(CORBA_Environment *env)
{
char gencall_atom[10];
int error = 0;
int version = 0;
env->_iin = 0;
env->_received = 0;
memset(gencall_atom, 0, 10);
ei_decode_version(env->_inbuf, &env->_iin, &version);
ei_decode_tuple_header(env->_inbuf, &env->_iin, &env->_received);
ei_decode_atom(env->_inbuf, &env->_iin, gencall_atom);
if (strcmp(gencall_atom, "$gen_cast") == 0) {
if ((error = ei_decode_atom(env->_inbuf, &env->_iin,
env->_operation)) < 0) {
ei_decode_tuple_header(env->_inbuf, &env->_iin, &env->_received);
if ((error = ei_decode_atom(env->_inbuf, &env->_iin,
env->_operation)) < 0) {
CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, BAD_OPERATION,
"Bad Message, cannot extract operation");
return error;
}
env->_received -= 1;
} else
env->_received -= 2;
return 0;
}
if (strcmp(gencall_atom, "$gen_call") == 0) {
ei_decode_tuple_header(env->_inbuf, &env->_iin, &env->_received);
if ((error = ei_decode_pid(env->_inbuf, &env->_iin,
&env->_caller)) < 0) {
CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL,
"Bad Message, bad caller identity");
return error;
}
if ((error = ei_decode_ref(env->_inbuf, &env->_iin,
&env->_unique)) < 0) {
CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL,
"Bad Message, bad message reference");
return error;
}
if ((error = ei_decode_atom(env->_inbuf, &env->_iin,
env->_operation)) < 0) {
ei_decode_tuple_header(env->_inbuf, &env->_iin, &env->_received);
if ((error = ei_decode_atom(env->_inbuf, &env->_iin,
env->_operation)) < 0) {
CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, BAD_OPERATION,
"Bad Message, cannot extract operation");
return error;
}
env->_received -= 1;
return 0;
}
else {
env->_received -= 2;
return 0;
}
}
CORBA_exc_set(env, CORBA_SYSTEM_EXCEPTION, MARSHAL,
"Bad message, neither cast nor call");
return -1;
}
/* Prepare reply encoding (gen_server server) */
int oe_prepare_reply_encoding(CORBA_Environment *env)
{
env->_iout = 0;
oe_ei_encode_version(env);
oe_ei_encode_tuple_header(env, 2);
oe_ei_encode_ref(env, &env->_unique);
return 0;
}
/* ---- Function for making it more easy to implement a server */
/* Server receive (possibly) send reply (gen_server server) */
int oe_server_receive(CORBA_Environment *env, oe_map_t *map)
{
int res = 0, loop = 1;
erlang_msg msg;
while (res >= 0 && loop > 0) {
res = ei_receive_encoded(env->_fd, &env->_inbuf, &env->_inbufsz,
&msg, &env->_iin);
switch(res) {
case ERL_SEND:
case ERL_REG_SEND:
oe_exec_switch(NULL, env, map);
switch(env->_major) {
case CORBA_NO_EXCEPTION:
break;
case CORBA_SYSTEM_EXCEPTION:
/* XXX stderr */
fprintf(stderr, "Request failure, reason : %s\n",
(char *) CORBA_exception_value(env));
CORBA_exception_free(env);
break;
default: /* Should not happen */
CORBA_exception_free(env);
break;
}
/* send reply */
/* XXX We are required to set env->_iout = 0 if oneway?? */
if (env->_iout > 0)
ei_send_encoded(env->_fd, &env->_caller, env->_outbuf,
env->_iout);
loop = 0;
break;
case ERL_TICK:
break;
default:
/* XXX */
if (res < 0) {
fprintf(stderr, "Result negative: %d\n", res);
loop = 0;
}
break;
}
}
return 0;
}