diff options
Diffstat (limited to 'lib/ic/c_src/ic.c')
-rw-r--r-- | lib/ic/c_src/ic.c | 612 |
1 files changed, 612 insertions, 0 deletions
diff --git a/lib/ic/c_src/ic.c b/lib/ic/c_src/ic.c new file mode 100644 index 0000000000..1ace9ea1af --- /dev/null +++ b/lib/ic/c_src/ic.c @@ -0,0 +1,612 @@ +/* + * %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->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; +} + |