/* * %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 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; }