void CBuzzController::ProcessOutMsgs() { /* Send robot id */ CByteArray cData; cData << m_tBuzzVM->robot; /* Send messages from FIFO */ do { /* Are there more messages? */ if(buzzoutmsg_queue_isempty(m_tBuzzVM->outmsgs)) break; /* Get first message */ buzzmsg_payload_t m = buzzoutmsg_queue_first(m_tBuzzVM->outmsgs); /* Make sure the next message fits the data buffer */ if(cData.Size() + buzzmsg_payload_size(m) + sizeof(UInt16) > m_pcRABA->GetSize()) { buzzmsg_payload_destroy(&m); break; } /* Add message length to data buffer */ cData << static_cast<UInt16>(buzzmsg_payload_size(m)); /* Add payload to data buffer */ cData.AddBuffer(reinterpret_cast<UInt8*>(m->data), buzzmsg_payload_size(m)); /* Get rid of message */ buzzoutmsg_queue_next(m_tBuzzVM->outmsgs); buzzmsg_payload_destroy(&m); } while(1); /* Pad the rest of the data with zeroes */ while(cData.Size() < m_pcRABA->GetSize()) cData << static_cast<UInt8>(0); /* Send message */ m_pcRABA->SetData(cData); }
void CBuzzController::ProcessOutMsgs() { /* Process outgoing messages */ buzzvm_process_outmsgs(m_tBuzzVM); /* Send robot id */ CByteArray cData; cData << m_tBuzzVM->robot; /* Send messages from FIFO */ do { /* Are there more messages? */ if(buzzoutmsg_queue_isempty(m_tBuzzVM)) break; /* Get first message */ buzzmsg_payload_t m = buzzoutmsg_queue_first(m_tBuzzVM); /* Make sure the message is smaller than the data buffer * Without this check, large messages would clog the queue forever */ size_t unMsgSize = buzzmsg_payload_size(m) + sizeof(UInt16); if(unMsgSize < m_pcRABA->GetSize() - sizeof(UInt16)) { /* Make sure the next message fits the data buffer */ if(cData.Size() + unMsgSize > m_pcRABA->GetSize()) { buzzmsg_payload_destroy(&m); break; } /* Add message length to data buffer */ cData << static_cast<UInt16>(buzzmsg_payload_size(m)); /* Add payload to data buffer */ cData.AddBuffer(reinterpret_cast<UInt8*>(m->data), buzzmsg_payload_size(m)); } else { RLOGERR << "Discarded oversize message (" << unMsgSize << " bytes). Max size is " << m_pcRABA->GetSize() - sizeof(UInt16) << " bytes." << std::endl; } /* Get rid of message */ buzzoutmsg_queue_next(m_tBuzzVM); buzzmsg_payload_destroy(&m); } while(1); /* Pad the rest of the data with zeroes */ while(cData.Size() < m_pcRABA->GetSize()) cData << static_cast<UInt8>(0); /* Send message */ m_pcRABA->SetData(cData); }
void buzzvm_process_inmsgs(buzzvm_t vm) { /* Go through the messages */ while(!buzzinmsg_queue_isempty(vm->inmsgs)) { /* Make sure the VM is in the right state */ if(vm->state != BUZZVM_STATE_READY) return; /* Extract the message data */ uint16_t rid; buzzmsg_payload_t msg; buzzinmsg_queue_extract(vm, &rid, &msg); /* Dispatch the message wrt its type in msg->payload[0] */ switch(buzzmsg_payload_get(msg, 0)) { case BUZZMSG_BROADCAST: { /* Deserialize the topic */ buzzobj_t topic; int64_t pos = buzzobj_deserialize(&topic, msg, 1, vm); /* Make sure there's a listener to call */ const buzzobj_t* l = buzzdict_get(vm->listeners, &topic->s.value.sid, buzzobj_t); if(!l) { /* No listener, ignore message */ break; } /* Deserialize value */ buzzobj_t value; pos = buzzobj_deserialize(&value, msg, pos, vm); /* Make an object for the robot id */ buzzobj_t rido = buzzheap_newobj(vm, BUZZTYPE_INT); rido->i.value = rid; /* Call listener */ buzzvm_push(vm, *l); buzzvm_push(vm, topic); buzzvm_push(vm, value); buzzvm_push(vm, rido); buzzvm_closure_call(vm, 3); break; } case BUZZMSG_VSTIG_PUT: { /* Deserialize the vstig id */ uint16_t id; int64_t pos = buzzmsg_deserialize_u16(&id, msg, 1); if(pos < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_VSTIG_PUT message received\n", vm->robot); break; } /* Look for virtual stigmergy */ const buzzvstig_t* vs = buzzdict_get(vm->vstigs, &id, buzzvstig_t); if(!vs) break; /* Virtual stigmergy found */ /* Deserialize key and value from msg */ buzzobj_t k; // key buzzvstig_elem_t v = // value (buzzvstig_elem_t)malloc(sizeof(struct buzzvstig_elem_s)); if(buzzvstig_elem_deserialize(&k, &v, msg, pos, vm) < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_VSTIG_PUT message received\n", vm->robot); free(v); break; } /* Deserialization successful */ /* Fetch local vstig element */ const buzzvstig_elem_t* l = buzzvstig_fetch(*vs, &k); if((!l) || /* Element not found */ ((*l)->timestamp < v->timestamp)) { /* Local element is older */ /* Local element must be updated */ /* Store element */ buzzvstig_store(*vs, &k, &v); buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, v); } else if(((*l)->timestamp == v->timestamp) && /* Same timestamp */ ((*l)->robot != v->robot)) { /* Different robot */ /* Conflict! */ /* Call conflict manager */ buzzvstig_elem_t c = buzzvstig_onconflict_call(vm, *vs, k, *l, v); if(!c) { fprintf(stderr, "[WARNING] [ROBOT %u] Error resolving PUT conflict\n", vm->robot); break; } /* Get rid of useless vstig element */ free(v); /* Did this robot lose the conflict? */ if((c->robot != vm->robot) && ((*l)->robot == vm->robot)) { /* Yes */ /* Save current local entry */ buzzvstig_elem_t ol = buzzvstig_elem_clone(vm, *l); /* Store winning value */ buzzvstig_store(*vs, &k, &c); /* Call conflict lost manager */ buzzvstig_onconflictlost_call(vm, *vs, k, ol); } else { /* This robot did not lose the conflict */ /* Just propagate the PUT message */ buzzvstig_store(*vs, &k, &c); } buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, c); } else { /* Remote element is older, ignore it */ /* Get rid of useless vstig element */ free(v); } break; } case BUZZMSG_VSTIG_QUERY: { /* Deserialize the vstig id */ uint16_t id; int64_t pos = buzzmsg_deserialize_u16(&id, msg, 1); if(pos < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_VSTIG_QUERY message received (1)\n", vm->robot); break; } /* Deserialize key and value from msg */ buzzobj_t k; // key buzzvstig_elem_t v = // value (buzzvstig_elem_t)malloc(sizeof(struct buzzvstig_elem_s)); if(buzzvstig_elem_deserialize(&k, &v, msg, pos, vm) < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_VSTIG_QUERY message received (2)\n", vm->robot); free(v); break; } /* Look for virtual stigmergy */ const buzzvstig_t* vs = buzzdict_get(vm->vstigs, &id, buzzvstig_t); if(!vs) { /* Virtual stigmergy not found, simply propagate the message */ buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_QUERY, id, k, v); free(v); break; } /* Virtual stigmergy found */ /* Fetch local vstig element */ const buzzvstig_elem_t* l = buzzvstig_fetch(*vs, &k); if(!l) { /* Element not found */ if(v->data->o.type == BUZZTYPE_NIL) { /* This robot knows nothing about the query, just propagate it */ buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_QUERY, id, k, v); free(v); } else { /* Store element and propagate PUT message */ buzzvstig_store(*vs, &k, &v); buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, v); } break; } /* Element found */ if((*l)->timestamp < v->timestamp) { /* Local element is older */ /* Store element */ buzzvstig_store(*vs, &k, &v); buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, v); } else if((*l)->timestamp > v->timestamp) { /* Local element is newer */ /* Append a PUT message to the out message queue */ buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, *l); free(v); } else if(((*l)->timestamp == v->timestamp) && /* Same timestamp */ ((*l)->robot != v->robot)) { /* Different robot */ /* Conflict! */ /* Call conflict manager */ buzzvstig_elem_t c = buzzvstig_onconflict_call(vm, *vs, k, *l, v); free(v); /* Make sure conflict manager returned with an element to process */ if(!c) break; /* Did this robot lose the conflict? */ if((c->robot != vm->robot) && ((*l)->robot == vm->robot)) { /* Yes */ /* Save current local entry */ buzzvstig_elem_t ol = buzzvstig_elem_clone(vm, *l); /* Store winning value */ buzzvstig_store(*vs, &k, &c); /* Call conflict lost manager */ buzzvstig_onconflictlost_call(vm, *vs, k, ol); } else { /* This robot did not lose the conflict */ /* Just propagate the PUT message */ buzzvstig_store(*vs, &k, &c); } buzzoutmsg_queue_append_vstig(vm, BUZZMSG_VSTIG_PUT, id, k, c); } else { /* Remote element is same as local, ignore it */ /* Get rid of useless vstig element */ free(v); } break; } case BUZZMSG_SWARM_LIST: { /* Deserialize number of swarm ids */ uint16_t nsids; int64_t pos = buzzmsg_deserialize_u16(&nsids, msg, 1); if(pos < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_SWARM_LIST message received\n", vm->robot); break; } if(nsids < 1) break; /* Deserialize swarm ids */ buzzdarray_t sids = buzzdarray_new(nsids, sizeof(uint16_t), NULL); uint16_t i; for(i = 0; i < nsids; ++i) { pos = buzzmsg_deserialize_u16(buzzdarray_makeslot(sids, i), msg, pos); if(pos < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_SWARM_LIST message received\n", vm->robot); break; } } /* Update the information */ buzzswarm_members_refresh(vm->swarmmembers, rid, sids); break; } case BUZZMSG_SWARM_JOIN: { /* Deserialize swarm id */ uint16_t sid; int64_t pos = buzzmsg_deserialize_u16(&sid, msg, 1); if(pos < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_SWARM_JOIN message received\n", vm->robot); break; } /* Update the information */ buzzswarm_members_join(vm->swarmmembers, rid, sid); break; } case BUZZMSG_SWARM_LEAVE: { /* Deserialize swarm id */ uint16_t sid; int64_t pos = buzzmsg_deserialize_u16(&sid, msg, 1); if(pos < 0) { fprintf(stderr, "[WARNING] [ROBOT %u] Malformed BUZZMSG_SWARM_LEAVE message received\n", vm->robot); break; } /* Update the information */ buzzswarm_members_leave(vm->swarmmembers, rid, sid); break; } } /* Get rid of the message */ buzzmsg_payload_destroy(&msg); } /* Update swarm membership */ buzzswarm_members_update(vm->swarmmembers); }