/** * "send" method handler */ STATIC XRpcElement* GWENG_MidpSend(void* ctx, const XRpcContainer* param) { /* decode parameters */ const XRpcIntElement* sidParam = XRPC_GetIntElementByName(param, ECMTGW_SEI_SEND_SID_PARAM); const XRpcIntElement* cidParam = XRPC_GetIntElementByName(param, ECMTGW_SEI_SEND_CID_PARAM); const XRpcBinaryElement* dataParam = XRPC_GetBinaryElementByName(param, ECMTGW_SEI_SEND_DATA_PARAM); if (sidParam && cidParam && dataParam) { MidpSession* midp; EcmtGateway* gw = ctx; size_t size = XRPC_GetBinaryDataSize(dataParam); I32u cid = XRPC_GetInt(cidParam); const XRpcByte* data = XRPC_GetBinaryData(dataParam); MidpSessionKey key; key.xrpcSid = XRPC_GetInt(sidParam); key.xrpcSession = XRPC_GetCurrentSession(gw->xrpc); TRACE4("GW: MidpSend(%08x.%08x.%u, %d bytes)\n", key.xrpcSession, key.xrpcSid, cid, size); DEBUG_ONLY(PRINT_Dump(DEBUG_Trace,data,size,0)); MUTEX_Lock(&gw->mutex); midp = HASH_Get(&gw->midpSessionMap,&key); if (midp) { MidpConnection* conn = HASH_Get(&midp->connMap,(HashKey)cid); if (conn) { char h[ECMT_MIDP_DEBUG_SEND_DATA_OFFSET]; I32u seq = conn->outCount++; GWENG_MidpFillHeader(h,midp->sid,ECMT_MIDP_DEBUG_OPCODE_SEND); *((I32u*)(h+ECMT_MIDP_DEBUG_SEND_CID_OFFSET)) = htonl(cid); *((I32u*)(h+ECMT_MIDP_DEBUG_SEND_SEQ_OFFSET)) = htonl(seq); GWENG_QueueAdd2(gw->handsetQueue, KECMT_MIDP_DEBUG_PLUGIN_UID, h, ECMT_MIDP_DEBUG_SEND_DATA_OFFSET, data, size); } else { TRACE1("GW: invalid conn id %u\n",cid); GWENG_MidpResetConn(gw, midp, cid, False, True); } } else { TRACE2("GW: unexpected MIDP send (%08x.%08x)\n", key.xrpcSession, key.xrpcSid); } MUTEX_Unlock(&gw->mutex); } return NULL; }
/** * ECMT message filter */ Bool GWENG_MidpFilter(EcmtReader* reader, int uid, const void* data, int datalen) { if (uid == KECMT_MIDP_DEBUG_GATEWAY_UID) { ASSERT(datalen >= ECMT_MIDP_DEBUG_HEADER_SIZE); if (datalen >= ECMT_MIDP_DEBUG_HEADER_SIZE) { MidpSession* midp; EcmtGateway* gw = reader->gw; I32u sid; I8u opcode = GWENG_MidpParseHeader(data,&sid); MUTEX_Lock(&gw->mutex); midp = HASH_Get(&gw->ecmtSessionMap,(HashKey)sid); if (midp) { GWENG_MidpHandleEcmtPacket(gw, midp, data, datalen); } else { TRACE1("GW: invalid SID 0x%08x\n",sid); } MUTEX_Unlock(&gw->mutex); } return False; } else { return True; } }
/** * "connect" method handler */ STATIC XRpcElement* GWENG_MidpConnect(void* ctx, const XRpcContainer* param) { /* decode parameters */ const XRpcIntElement* sidParam = XRPC_GetIntElementByName(param, ECMTGW_SEI_CONNECT_SID_PARAM); const XRpcIntElement* cidParam = XRPC_GetIntElementByName(param, ECMTGW_SEI_CONNECT_CID_PARAM); const XRpcShortElement* portParam = XRPC_GetShortElementByName(param, ECMTGW_SEI_CONNECT_PORT_PARAM); if (sidParam && cidParam && portParam) { MidpSession* midp; EcmtGateway* gw = ctx; I32u cid = XRPC_GetInt(cidParam); Port port = XRPC_GetShort(portParam); MidpSessionKey key; key.xrpcSid = XRPC_GetInt(sidParam); key.xrpcSession = XRPC_GetCurrentSession(gw->xrpc); TRACE4("GW: MidpConnect(%08x.%08x.%u, port %hu)\n", key.xrpcSession, key.xrpcSid, cid, port); MUTEX_Lock(&gw->mutex); midp = HASH_Get(&gw->midpSessionMap,&key); if (midp) { MidpConnection* conn = MEM_New(MidpConnection); if (conn) { memset(conn, 0, sizeof(*conn)); conn->connId = cid; if (HASH_Put(&midp->connMap, (HashKey)cid, conn)) { char pkt[ECMT_MIDP_DEBUG_CONNECT_SIZE]; GWENG_MidpFillHeader(pkt,midp->sid,ECMT_MIDP_DEBUG_OPCODE_CONNECT); *((I32u*)(pkt+ECMT_MIDP_DEBUG_CONNECT_CID_OFFSET)) = htonl(cid); *((I16u*)(pkt+ECMT_MIDP_DEBUG_CONNECT_PORT_OFFSET)) = htons(port); GWENG_QueueAdd(gw->handsetQueue, KECMT_MIDP_DEBUG_PLUGIN_UID, pkt, ECMT_MIDP_DEBUG_CONNECT_SIZE); MUTEX_Unlock(&gw->mutex); return NULL; } MEM_Free(conn); } GWENG_MidpResetConn(gw, midp, cid, False, True); } else { TRACE3("GW: unexpected MIDP connect (%08x.%08x.%u)\n", key.xrpcSession, key.xrpcSid, cid); } MUTEX_Unlock(&gw->mutex); } return NULL; }
/** * @brief Calls the registered lua onload callback function. * @param[in] L The lua state for calling lua. * @param[in] key script The name of the .ufo file holding the lua script. * @note The signature of the lua function is without any paramters: function (). * @note If the signature changes, this function should change too. */ void CL_ExecuteCallback (lua_State *L, const char* key) { /* look up the handler */ void *value = HASH_Get(cl_callback, key, strlen (key)); if (value) { int regvalue = * ((int*)value); lua_rawgeti (L, LUA_REGISTRYINDEX, regvalue); if (lua_pcall (L, 0, 0, 0) != 0) { Com_Printf ("lua error: %s\n", lua_tostring(cl_luastate, -1)); }; } }
/** * @brief Finds the lua based method on this node or its super. * @param[in] node The node to examine. * @param[in] name The name of the method to find * @param[out] fcn A reference to a LUA_METHOD value to the corresponding lua based function or to LUA_NOREF if * the method is not found * @return True if the method is found, false otherwise. * @note This method will first search for instance methods, then it will check for behaviour methods. */ bool UI_GetNodeMethod (const uiNode_t* node, const char* name, LUA_METHOD &fcn) { fcn = LUA_NOREF; // search the instance methods for(const uiNode_t* ref=node;ref;ref = ref->super) { if (ref->nodeMethods) { void* val=HASH_Get(ref->nodeMethods, name, strlen(name)); if (val != nullptr) { fcn = *((LUA_METHOD *)val); return true; } } } // no instance method found, now scan for behaviour method return UI_GetBehaviourMethod(node->behaviour, name, fcn); }
/** * "close" method handler */ STATIC XRpcElement* GWENG_MidpClose(void* ctx, const XRpcContainer* param) { /* decode parameters */ const XRpcIntElement* sidParam = XRPC_GetIntElementByName(param, ECMTGW_SEI_SEND_SID_PARAM); if (sidParam) { EcmtGateway* gw = ctx; MidpSession* midp; MidpSessionKey key; key.xrpcSid = XRPC_GetInt(sidParam); key.xrpcSession = XRPC_GetCurrentSession(gw->xrpc); MUTEX_Lock(&gw->mutex); TRACE2("GW: MidpClose(%08x.%08x)\n", key.xrpcSession, key.xrpcSid); midp = HASH_Get(&gw->midpSessionMap,&key); if (midp) { char p[ECMT_MIDP_DEBUG_CLOSE_SIZE]; GWENG_MidpFillHeader(p, midp->sid, ECMT_MIDP_DEBUG_OPCODE_CLOSE); GWENG_QueueAdd(gw->handsetQueue,KECMT_MIDP_DEBUG_PLUGIN_UID,p, ECMT_MIDP_DEBUG_CLOSE_SIZE); TRACE1("GW: closing session 0x%08lx (via XRPC)\n",midp->sid); GWENG_MidpFree(gw, midp); } else { TRACE("GW: XRPC close for non-existent session\n"); } MUTEX_Unlock(&gw->mutex); } else { TRACE("GW: close without cid!\n"); } return NULL; }
/** * "reset" method handler */ STATIC XRpcElement* GWENG_MidpReset(void* ctx, const XRpcContainer* param) { /* decode parameters */ const XRpcIntElement* sidParam = XRPC_GetIntElementByName(param, ECMTGW_SEI_CONNECT_SID_PARAM); const XRpcIntElement* cidParam = XRPC_GetIntElementByName(param, ECMTGW_SEI_CONNECT_CID_PARAM); if (sidParam && cidParam) { MidpSession* midp; EcmtGateway* gw = ctx; I32u cid = XRPC_GetInt(cidParam); MidpSessionKey key; key.xrpcSid = XRPC_GetInt(sidParam); key.xrpcSession = XRPC_GetCurrentSession(gw->xrpc); TRACE3("GW: MidpReset(%08x.%08x.%u)\n", key.xrpcSession, key.xrpcSid, cid); MUTEX_Lock(&gw->mutex); midp = HASH_Get(&gw->midpSessionMap,&key); if (midp) { GWENG_MidpResetConn(gw, midp, cid, True, False); } else { TRACE3("GW: unexpected MIDP reset (%08x.%08x.%u)\n", key.xrpcSession, key.xrpcSid, cid); } MUTEX_Unlock(&gw->mutex); } return NULL; }
/** * @brief Unit test function. */ bool HASH_test () { // return value bool result = true; /* test 1: create the hash table, delete the hash table */ hashTable_s* table = HASH_NewTable(true, true, true); HASH_DeleteTable (&table); /* check table pointer is correctly set to nil */ result = result && (table == NULL); if (!result) return false; /* check alloc total */ result = result && (_num_allocs == 0); if (!result) return false; /* test 2: create the hash table, insert 3 values, delete the hash table */ table = HASH_NewTable(true, true, true); HASH_Insert (table, "AAA", 4, "AAA", 4); HASH_Insert (table, "BBB", 4, "BBB", 4); HASH_Insert (table, "CCC", 4, "CCC", 4); if (HASH_Count(table) != 3) return false; HASH_Clear (table); if (HASH_Count(table) != 0) return false; HASH_DeleteTable (&table); /* check table pointer is correctly set to nil */ result = result && (table == NULL); if (!result) return false; /* check alloc total */ result = result && (_num_allocs == 0); if (!result) return false; /* test 3: create the hash table, insert/remove 3 values, delete the hash table */ table = HASH_NewTable(true, true, true); HASH_Insert (table, "AAA", 4, "AAA", 4); HASH_Remove (table, "AAA", 4); HASH_Insert (table, "BBB", 4, "BBB", 4); HASH_Remove (table, "BBB", 4); HASH_Insert (table, "CCC", 4, "CCC", 4); HASH_Remove (table, "CCC", 4); HASH_DeleteTable (&table); /* check table pointer is correctly set to nil */ result = result && (table == NULL); if (!result) return false; /* check alloc total */ result = result && (_num_allocs == 0); if (!result) return false; /* test 4: create the hash table, insert/count/search/delete 3 values, delete the hash table */ table = HASH_NewTable(true, true, true); HASH_Insert (table, "AAA", 4, "AAA", 4); HASH_Insert (table, "BBB", 4, "BBB", 4); HASH_Insert (table, "CCC", 4, "CCC", 4); /* check count items */ if (HASH_Count(table) != 3) return false; char* aaa = (char*)HASH_Get(table, "AAA", 4); if (strncmp (aaa, "AAA", 4) != 0) return false; char* bbb = (char*)HASH_Get(table, "BBB", 4); if (strncmp (bbb, "BBB", 4) != 0) return false; char* ccc = (char*)HASH_Get(table, "CCC", 4); if (strncmp (ccc, "CCC", 4) != 0) return false; HASH_Remove (table, "AAA", 4); HASH_Remove (table, "BBB", 4); HASH_Remove (table, "CCC", 4); if (HASH_Count(table) != 0) return false; HASH_DeleteTable (&table); /* check table pointer is correctly set to nil */ result = result && (table == NULL); if (!result) return false; /* check alloc total */ result = result && (_num_allocs == 0); if (!result) return false; /* test 5: hash function test */ const char AZ[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; char buffer[26]; /* compute the averag of the hash index of 400 random keys */ int total = 0; srand(time(NULL)); for(int i=0; i < 4000; i++) { /* create random key of random length between 4..23 charachters */ int len = 4 + (rand() % 20); memset (buffer, 0, sizeof(buffer)); for (int j=0; j < len; j++) { int v = rand() % sizeof(AZ); buffer[j]=AZ[v]; } /* compute the hash index */ int idx = default_hash (buffer, len); /* sum index */ total += idx; } /* now compute the average of the indices */ int avg = (total / 4000); /* the average idx should be somewhere halfway, allow a %10 error margin */ int idx_low = (HASH_TABLE_SIZE/2) - (HASH_TABLE_SIZE/10); int idx_high = (HASH_TABLE_SIZE/2) + (HASH_TABLE_SIZE/10); if ( !((idx_low <= avg) && (idx_high >= avg)) ) return false; /* test 6: hash table without ownership test */ table = HASH_NewTable(true, false, true); char item1[] = "AAA"; char item2[] = "BBB"; char item3[] = "CCC"; HASH_Insert (table, item1, 4, item1, 4); HASH_Insert (table, item2, 4, item2, 4); HASH_Insert (table, item3, 4, item3, 4); /* check if we get the correct value pointers */ aaa = (char*)HASH_Get(table, "AAA", 4); if (aaa != item1) return false; bbb = (char*)HASH_Get(table, "BBB", 4); if (bbb != item2) return false; ccc = (char*)HASH_Get(table, "CCC", 4); if (ccc != item3) return false; HASH_DeleteTable (&table); /* check table pointer is correctly set to nil */ result = result && (table == NULL); if (!result) return false; /* check alloc total */ result = result && (_num_allocs == 0); if (!result) return false; /* end of unit test, everything OK */ return true; }
/** * Handles ECMT packet coming from MIDP debug plugin */ STATIC void GWENG_MidpHandleEcmtPacket(EcmtGateway* gw, MidpSession* midp, const I8u* pkt, int pktlen) { I8u opcode = pkt[ECMT_MIDP_DEBUG_HEADER_OPCODE_OFFSET]; switch (opcode) { case ECMT_MIDP_DEBUG_OPCODE_SEND: ASSERT(pktlen >= ECMT_MIDP_DEBUG_SEND_MIN_SIZE); if (pktlen >= ECMT_MIDP_DEBUG_SEND_MIN_SIZE) { I32u cid = htonl(*((I32u*)(pkt+ECMT_MIDP_DEBUG_SEND_CID_OFFSET))); I32u seq = htonl(*((I32u*)(pkt+ECMT_MIDP_DEBUG_SEND_SEQ_OFFSET))); MidpConnection* conn = HASH_Get(&midp->connMap,(HashKey)cid); if (conn) { if (conn->inCount == seq) { XRpcData data; XRpcContainer* params; conn->inCount++; /* increment sequence number */ data.ptr = (I8u*)pkt + ECMT_MIDP_DEBUG_SEND_DATA_OFFSET; data.size = pktlen - ECMT_MIDP_DEBUG_SEND_DATA_OFFSET; TRACE4("GW: MidpReceive(%08x.%08x.%u, %d bytes)\n", midp->key.xrpcSession, midp->key.xrpcSid, cid, data.size); DEBUG_ONLY(PRINT_Dump(DEBUG_Trace,data.ptr,data.size,0)); params = GWENG_CreateXRpcParams(midp, ECMTGW_SEI_SEND_SID_PARAM, ECMTGW_SEI_SEND_CID_PARAM, cid); if (params) { XRpcElement* dataElem = _XRPC_CreateBinaryElement( data.ptr, data.size); if (dataElem) { if (XRPC_SetElementName(dataElem, ECMTGW_SEI_SEND_DATA_PARAM) && XRPC_AddElement(params, dataElem)) { /* submit the call */ GWENG_SubmitAsyncCall(midp, ECMTGW_SEI_SEND_METHOD, params); break; } else { XRPC_FreeElement(dataElem); } } XRPC_FreeContainer(params); } /* Terminate connection? That would probably fail too */ } else { TRACE2("GW: SEQ mismatch (expected %u, found %u)\n", conn->inCount, seq); GWENG_MidpResetConn(gw, midp, cid, True, True); } } else { TRACE1("GW: invalid conn id %u from Ecmt\n",cid); GWENG_MidpResetConn(gw, midp, cid, True, False); } } break; case ECMT_MIDP_DEBUG_OPCODE_CLOSE: ASSERT(pktlen == ECMT_MIDP_DEBUG_CLOSE_SIZE); TRACE1("GW: closing session 0x%08lx (via ECMT)\n",midp->sid); GWENG_SubmitAsyncCall(midp, ECMTGW_SEI_CLOSE_METHOD, GWENG_CreateXRpcParams(midp, ECMTGW_SEI_CLOSE_SID_PARAM, NULL, 0)); break; case ECMT_MIDP_DEBUG_OPCODE_RESET: ASSERT(pktlen == ECMT_MIDP_DEBUG_RESET_SIZE); if (pktlen == ECMT_MIDP_DEBUG_RESET_SIZE) { I32u cid = htonl(*((I32u*)(pkt+ECMT_MIDP_DEBUG_RESET_CID_OFFSET))); GWENG_SubmitAsyncCall(midp, ECMTGW_SEI_RESET_METHOD, GWENG_CreateXRpcParams(midp, ECMTGW_SEI_RESET_SID_PARAM, ECMTGW_SEI_RESET_CID_PARAM, cid)); } break; default: ASSMSG1("GW: unexpected opcode %u",opcode); break; } }