void handle_push(MSICall *call, const MSIMessage *msg) { assert(call); LOGGER_DEBUG(call->session->messenger->log, "Session: %p Handling 'push' friend: %d", call->session, call->friend_number); if (!msg->capabilities.exists) { LOGGER_WARNING(call->session->messenger->log, "Session: %p Invalid capabilities on 'push'"); call->error = msi_EInvalidMessage; goto FAILURE; } switch (call->state) { case msi_CallActive: { /* Only act if capabilities changed */ if (call->peer_capabilities != msg->capabilities.value) { LOGGER_INFO(call->session->messenger->log, "Friend is changing capabilities to: %u", msg->capabilities.value); call->peer_capabilities = msg->capabilities.value; if (invoke_callback(call, msi_OnCapabilities) == -1) { goto FAILURE; } } } break; case msi_CallRequesting: { LOGGER_INFO(call->session->messenger->log, "Friend answered our call"); /* Call started */ call->peer_capabilities = msg->capabilities.value; call->state = msi_CallActive; if (invoke_callback(call, msi_OnStart) == -1) { goto FAILURE; } } break; /* Pushes during initialization state are ignored */ case msi_CallInactive: // fall-through case msi_CallRequested: { LOGGER_WARNING(call->session->messenger->log, "Ignoring invalid push"); } break; } return; FAILURE: send_error(call->session->messenger, call->friend_number, call->error); kill_call(call); }
void on_peer_status(Messenger *m, uint32_t friend_number, uint8_t status, void *data) { (void)m; MSISession *session = (MSISession *)data; switch (status) { case 0: { /* Friend is now offline */ LOGGER_DEBUG(m->log, "Friend %d is now offline", friend_number); pthread_mutex_lock(session->mutex); MSICall *call = get_call(session, friend_number); if (call == NULL) { pthread_mutex_unlock(session->mutex); return; } invoke_callback(call, msi_OnPeerTimeout); /* Failure is ignored */ kill_call(call); pthread_mutex_unlock(session->mutex); } break; default: break; } }
void handle_pop(MSICall *call, const MSIMessage *msg) { assert(call); LOGGER_DEBUG(call->session->messenger->log, "Session: %p Handling 'pop', friend id: %d", call->session, call->friend_number); /* callback errors are ignored */ if (msg->error.exists) { LOGGER_WARNING(call->session->messenger->log, "Friend detected an error: %d", msg->error.value); call->error = msg->error.value; invoke_callback(call, msi_OnError); } else { switch (call->state) { case msi_CallInactive: { LOGGER_ERROR(call->session->messenger->log, "Handling what should be impossible case"); abort(); } case msi_CallActive: { /* Hangup */ LOGGER_INFO(call->session->messenger->log, "Friend hung up on us"); invoke_callback(call, msi_OnEnd); } break; case msi_CallRequesting: { /* Reject */ LOGGER_INFO(call->session->messenger->log, "Friend rejected our call"); invoke_callback(call, msi_OnEnd); } break; case msi_CallRequested: { /* Cancel */ LOGGER_INFO(call->session->messenger->log, "Friend canceled call invite"); invoke_callback(call, msi_OnEnd); } break; } } kill_call(call); }
static void callback_uiComboboxOnSelected( uiCombobox* c, void* d ) { lua_State* L = (lua_State*) d; if( L ) { lua_pushinteger( L, uiComboboxSelected( c ) ); invoke_callback( L, c, callback_OnSelected, 1 ); } }
static void callback_uiSliderOnChanged( uiSlider* c, void* d ) { lua_State* L = (lua_State*) d; if( L ) { lua_pushinteger( L, uiSliderValue( c ) ); invoke_callback( L, c, callback_OnChanged, 1 ); } }
static void callback_uiCheckboxOnToggled( uiCheckbox* c, void* d ) { lua_State* L = (lua_State*) d; if( L ) { lua_pushboolean( L, uiCheckboxChecked( c ) ); invoke_callback( L, c, callback_OnToggled, 1 ); } }
static void callback_uiMenuItemOnClicked( uiMenuItem* i, uiWindow* w, void* d ) { lua_State* L = (lua_State*) d; if( L ) { object_copy( L, w ); invoke_callback( (lua_State*) d, i, callback_OnClicked, 1 ); } }
static void callback_uiMultilineEntryOnChanged( uiMultilineEntry* c, void* d ) { lua_State* L = (lua_State*) d; if( L ) { char* str = uiMultilineEntryText( c ); lua_pushstring( L, str ); uiFreeText( str ); invoke_callback( L, c, callback_OnChanged, 1 ); } }
static void callback_uiEditableComboboxOnChanged( uiEditableCombobox* c, void* d ) { lua_State* L = (lua_State*) d; if( L ) { object_create( L, uiNewCombobox(), uiComboboxSignature, control_common, combobox_functions, 0 ); char* text = uiEditableComboboxText( c ); lua_pushstring( L, text ); invoke_callback( L, c, callback_OnChanged, 1 ); uiFreeText( text ); } }
static void callback_uiColorButtonOnChanged( uiColorButton* c, void* d ) { lua_State* L = (lua_State*) d; if( L ) { double r,g,b,a; uiColorButtonColor( c, &r, &g, &b, &a ); lua_pushnumber( L, r ); lua_pushnumber( L, g ); lua_pushnumber( L, b ); lua_pushnumber( L, a ); invoke_callback( L, c, callback_OnChanged, 4 ); } }
/**@brief Timeout handler for the advertisement slot timer. */ static void adv_slot_timeout(void * p_context) { ret_code_t err_code; uint32_t active_slot_index = (uint32_t)p_context; es_adv_timing_evt_t evt; evt.slot_no = m_adv_timing_result.timing_results[active_slot_index].slot_no; evt.evt_id = m_adv_timing_result.timing_results[active_slot_index].is_etlm ? ES_ADV_TIMING_EVT_ADV_ETLM : ES_ADV_TIMING_EVT_ADV_SLOT; // Trigger an event for the next slot if this slot is not the last to be advertised in this event. // Note: since we check 'm_adv_timing_result.len_timing_results > 1' we can safely cast the result of // the subtraction to a uint32. if (m_non_conn_adv_active && \ m_adv_timing_result.len_timing_results > 1 && \ active_slot_index < (uint32_t)(m_adv_timing_result.len_timing_results - 1)) { err_code = app_timer_start( m_es_slot_timer, APP_TIMER_TICKS(m_adv_timing_result.timing_results[active_slot_index].delay_ms, APP_TIMER_PRESCALER), (void*)(active_slot_index + 1)); APP_ERROR_CHECK(err_code); } #if APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1 static uint32_t adv_event_cnt = 0; if (active_slot_index == 0) { adv_event_cnt++; } if (frame_to_adv_is_tlm(&evt) && !tlm_should_be_advertised(adv_event_cnt)) { return; } #endif // APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1 invoke_callback(&evt); }
/**@brief Update advertisement data and start connectable advertisements. */ static void connectable_adv_start(void) { ble_gap_adv_params_t connectable_adv_params; ble_advdata_t scrsp_data; ble_uuid_t scrp_uuids[] = {{BLE_UUID_ESCS_SERVICE, m_ecs_uuid_type}}; memset(&scrsp_data, 0, sizeof(scrsp_data)); scrsp_data.name_type = BLE_ADVDATA_FULL_NAME; scrsp_data.include_appearance = false; scrsp_data.uuids_complete.uuid_cnt = sizeof(scrp_uuids) / sizeof(scrp_uuids[0]); scrsp_data.uuids_complete.p_uuids = scrp_uuids; // As the data to be written does not depend on the slot_no, we can safely send es_adv_frame_fill_connectable_adv_data(&scrsp_data); get_adv_params(&connectable_adv_params, false, m_remain_connectable); adv_start(&connectable_adv_params); invoke_callback(ES_ADV_EVT_CONNECTABLE_ADV_STARTED); }
/**@brief Function handling events from @ref es_adv_timing.c. * * @param[in] p_evt Advertisement timing event. */ static void adv_timing_callback(const es_adv_timing_evt_t * p_evt) { ret_code_t err_code; ble_gap_adv_params_t non_connectable_adv_params; const es_slot_reg_t * p_reg = es_slot_get_registry(); // As new advertisement data will be loaded, stop advertising. err_code = sd_ble_gap_adv_stop(); if (err_code != NRF_ERROR_INVALID_STATE) { APP_ERROR_CHECK(err_code); } // If a non-eTLM frame is to be advertised. if (p_evt->evt_id == ES_ADV_TIMING_EVT_ADV_SLOT) { err_code = sd_ble_gap_tx_power_set(p_reg->slots[p_evt->slot_no].radio_tx_pwr); APP_ERROR_CHECK(err_code); es_adv_frame_fill_non_connectable_adv_data(p_evt->slot_no, false); } // If an eTLM frame is to be advertised else if (p_evt->evt_id == ES_ADV_TIMING_EVT_ADV_ETLM) { err_code = sd_ble_gap_tx_power_set(p_reg->slots[p_reg->tlm_slot].radio_tx_pwr); APP_ERROR_CHECK(err_code); es_adv_frame_fill_non_connectable_adv_data(p_evt->slot_no, true); } invoke_callback(ES_ADV_EVT_NON_CONN_ADV); get_adv_params(&non_connectable_adv_params, true, m_remain_connectable); adv_start(&non_connectable_adv_params); }
static int callback_uiWindowOnClosing( uiWindow* w, void* d ) { invoke_callback( (lua_State*) d, w, callback_OnClosing, 0 ); return 0; }
void handle_init(MSICall *call, const MSIMessage *msg) { assert(call); LOGGER_DEBUG(call->session->messenger->log, "Session: %p Handling 'init' friend: %d", call->session, call->friend_number); if (!msg->capabilities.exists) { LOGGER_WARNING(call->session->messenger->log, "Session: %p Invalid capabilities on 'init'"); call->error = msi_EInvalidMessage; goto FAILURE; } switch (call->state) { case msi_CallInactive: { /* Call requested */ call->peer_capabilities = msg->capabilities.value; call->state = msi_CallRequested; if (invoke_callback(call, msi_OnInvite) == -1) { goto FAILURE; } } break; case msi_CallActive: { /* If peer sent init while the call is already * active it's probable that he is trying to * re-call us while the call is not terminated * on our side. We can assume that in this case * we can automatically answer the re-call. */ LOGGER_INFO(call->session->messenger->log, "Friend is recalling us"); MSIMessage out_msg; msg_init(&out_msg, requ_push); out_msg.capabilities.exists = true; out_msg.capabilities.value = call->self_capabilities; send_message(call->session->messenger, call->friend_number, &out_msg); /* If peer changed capabilities during re-call they will * be handled accordingly during the next step */ } break; case msi_CallRequested: // fall-through case msi_CallRequesting: { LOGGER_WARNING(call->session->messenger->log, "Session: %p Invalid state on 'init'"); call->error = msi_EInvalidState; goto FAILURE; } } return; FAILURE: send_error(call->session->messenger, call->friend_number, call->error); kill_call(call); }
static void dispatch_callback(ffi_cif* cif, void* resp, void** cbargs, void* user_data) { callback* cb = ((callback *)user_data); JavaVM* jvm = cb->vm; JNIEnv* env = NULL; int was_attached = (*jvm)->GetEnv(jvm, (void *)&env, JNI_VERSION_1_4) == JNI_OK; jboolean needs_detach = was_attached ? JNI_FALSE : JNI_TRUE; thread_storage* tls = was_attached ? get_thread_storage(env) : NULL; if (!was_attached) { int attach_status = 0; JavaVMAttachArgs args; int daemon = JNI_FALSE; args.version = JNI_VERSION_1_2; args.name = NULL; args.group = NULL; if (cb->behavior_flags & CB_HAS_INITIALIZER) { AttachOptions options; options.daemon = JNI_FALSE; // default non-daemon options.detach = JNI_TRUE; // default detach behavior options.name = NULL; args.group = initializeThread(cb, &options); daemon = options.daemon ? JNI_TRUE : JNI_FALSE; needs_detach = options.detach ? JNI_TRUE : JNI_FALSE; args.name = options.name; } if (daemon) { attach_status = (*jvm)->AttachCurrentThreadAsDaemon(jvm, (void*)&env, &args); } else { attach_status = (*jvm)->AttachCurrentThread(jvm, (void *)&env, &args); } tls = get_thread_storage(env); if (tls) { snprintf(tls->name, sizeof(tls->name), "%s", args.name ? args.name : "<unconfigured native thread>"); tls->needs_detach = needs_detach; tls->jvm_thread = JNI_FALSE; } // Dispose of allocated memory free(args.name); if (attach_status != JNI_OK) { fprintf(stderr, "JNA: Can't attach native thread to VM for callback: %d\n", attach_status); return; } if (args.group) { (*env)->DeleteWeakGlobalRef(env, args.group); } } if (!tls) { fprintf(stderr, "JNA: couldn't obtain thread-local storage\n"); return; } // Give the callback glue its own local frame to ensure all local references // are properly disposed if ((*env)->PushLocalFrame(env, 16) < 0) { fprintf(stderr, "JNA: Out of memory: Can't allocate local frame\n"); } else { invoke_callback(env, cb, cif, resp, cbargs); // Make note of whether the callback wants to avoid detach needs_detach = tls->needs_detach && !tls->jvm_thread; (*env)->PopLocalFrame(env, NULL); } if (needs_detach) { if ((*jvm)->DetachCurrentThread(jvm) != 0) { fprintf(stderr, "JNA: could not detach thread\n"); } } }
// 压入待解析数据 void parse(char const* data, std::size_t size) { char const* buf = data; std::size_t len = size; while (len) { if (0 == pos_) { // 缓冲区中无数据, 直接在上层缓冲区中尝试组包. if (len < head_size) { // 不足一个封包头, 写入缓冲区即可 write_buffer(buf, len); return ; } else { // 有完整的封包头, 进一步检测是否有完整的封包. std::size_t packet_len = Sizer()(packethead(buf)) + head_size; if (packet_len > size_) { // 封包长错误 invoke_callback(generate_error(bee::parse_error), 0, 0, 0); return ; } if (len < packet_len) { // 不足一个封包, 放入缓冲区中, 等待后续数据. write_buffer(buf, len); return ; } else { // 有完整的封包, 直接处理. invoke_callback(error_code(), &packethead(buf), buf + head_size, packet_len - head_size); buf += packet_len; len -= packet_len; continue; } } } else if (pos_ < head_size) { // 缓冲区中有数据, 但不足一个封包头, 尝试拼足一个封包头 std::size_t delta = head_size - pos_; std::size_t cpy_size = (std::min)(delta, len); write_buffer(buf, cpy_size); buf += cpy_size; len -= cpy_size; continue; } else { // 缓冲区中有完整的封包头 std::size_t packet_len = Sizer()(packethead(buf_)) + head_size; if (packet_len > size_) { // 封包长错误 invoke_callback(generate_error(bee::parse_error), 0, 0, 0); return ; } std::size_t delta = packet_len - pos_; if (delta > len) { // 无法拼出一个完整的封包 write_buffer(buf, len); return ; } else { // 可以拼出一个完整的封包 write_buffer(buf, delta); invoke_callback(error_code(), &packethead(buf_), buf_ + head_size, pos_ - head_size); pos_ = 0; buf += delta; len -= delta; continue; } } } }