void Transport::closeComponents() { collectNewComponets(); list<IOComponent*>::iterator iter = _checkingList.begin(); while ( iter != _checkingList.end() ) { IOComponent *ioc = *iter; ANET_LOG(DEBUG,"IOC(%p)->subRef(), [%d]", ioc, ioc->getRef()); ioc->close(); ioc->subRef(); iter = _checkingList.erase(iter); } IOComponent *list, *ioc; list = _iocListHead; while (list) { ioc = list; ANET_LOG(DEBUG,"IOC(%p)->subRef(), [%d]", ioc, ioc->getRef()); list = list->_next; ioc->close(); ioc->subRef(); } _iocListHead = _iocListTail = NULL; //SHOULD clear commands at last! vector<TransportCommand>::iterator i = _commands.begin(); while (i != _commands.end()) { ANET_LOG(DEBUG,"IOC(%p)->subRef(), [%d]", i->ioc, i->ioc->getRef()); i->ioc->subRef(); i++; } _commands.clear(); }
bool BeckhoffdProperty::run(std::vector<Value> ¶ms) { //if (params.size() == 4) { IOComponent *m = IOComponent::lookup_device(params[1].asString()); if (m) { if (params.size() == 3) { long x; char *p; x = strtol(params[2].asString().c_str(), &p, 0); if (*p == 0) m->setValue(x); else { result_str = "Require integer parameter"; return false; } } else { result_str = "usage: PROPERTY name value"; return false; } result_str = "OK"; return true; } else { result_str = "Unknown device"; return false; } }
void IOComponent::setupIOMap() { boost::recursive_mutex::scoped_lock lock(processing_queue_mutex); max_offset = 0; min_offset = 1000000L; io_map.clear(); if (indexed_components) delete indexed_components; std::cout << "\n\n setupIOMap\n"; // find the highest and lowest offset location within the process data std::list<IOComponent *>::iterator iter = processing_queue.begin(); while (iter != processing_queue.end()) { IOComponent *ioc = *iter++; std::cout << ioc->getName() << " " << ioc->address << "\n"; unsigned int offset = ioc->address.io_offset; unsigned int bitpos = ioc->address.io_bitpos; offset += bitpos/8; //bitpos = bitpos % 8; if (ioc->address.bitlen>=8) offset += ioc->address.bitlen/8 - 1; if (offset > max_offset) max_offset = offset; assert(max_offset < 10000); if (offset < min_offset) min_offset = offset; } if (min_offset > max_offset) min_offset = max_offset; std::cout << "min io offset: " << min_offset << "\n"; std::cout << "max io offset: " << max_offset << "\n"; std::cout << ( (max_offset+1)*sizeof(IOComponent*)) << " bytes reserved for index io\n"; indexed_components = new std::vector<IOComponent*>( (max_offset+1) *8); if (io_process_data) delete[] io_process_data; process_data_size = max_offset+1; io_process_data = new uint8_t[process_data_size]; memset(io_process_data, 0, process_data_size); io_map.resize(max_offset+1); for (unsigned int i=0; i<=max_offset; ++i) io_map[i] = 0; iter = processing_queue.begin(); while (iter != processing_queue.end()) { IOComponent *ioc = *iter++; if (ioc->io_name == "") continue; unsigned int offset = ioc->address.io_offset; unsigned int bitpos = ioc->address.io_bitpos; offset += bitpos/8; int bytes = 1; for (unsigned int i=0; i<ioc->address.bitlen; ++i) (*indexed_components)[offset*8 + bitpos + i] = ioc; for (int i=0; i<bytes; ++i) { std::list<IOComponent *> *cl = io_map[offset+i]; if (!cl) cl = new std::list<IOComponent *>(); cl->push_back(ioc); io_map[offset+i] = cl; std::cout << "offset: " << (offset+i) << " io name: " << ioc->io_name << "\n"; } } std::cout << "\n\n\n"; io_process_mask = generateProcessMask(io_process_mask, process_data_size); }
void handle_io_sampling(uint64_t io_clock) { uint64_t now = microsecs(); if (now - last_sample < 10000) return; last_sample = now; std::set <IOComponent*>::iterator iter = regular_polls.begin(); while (iter != regular_polls.end() ) { IOComponent *ioc = *iter++; ioc->read_time = io_clock; ioc->filter(ioc->address.value); } }
/** * 主动断开 */ bool Transport::disconnect(Connection *conn) { IOComponent *ioc = NULL; if (conn == NULL || (ioc = conn->getIOComponent()) == NULL) { return false; } ioc->setAutoReconn(false); ioc->subRef(); if (ioc->_socket) { ioc->_socket->shutdown(); } return true; }
void Transport::timeoutIteration(int64_t now) { collectNewComponets(); list<IOComponent*>::iterator iter = _checkingList.begin(); while ( iter != _checkingList.end() ) { IOComponent *ioc = *iter; if (ioc->checkTimeout(now)) { iter ++; } else { ioc->subRef(); iter = _checkingList.erase(iter); } } _nextCheckTime = now + 100000; }
bool ChatServer::start(const char *host, int thread) { IOComponent *ioc = this->listen(host, triones::TPROTOCOL_TEXT); if (ioc == NULL) { printf("listen error \n"); return false; } _tp = ioc->get_trans_proto(); _id_user.set_trans_proto(_tp); init(thread); return true; }
// 处理用户发送消息 void ChatServer::handle_user_send_msg(IOComponent* ioc, SendMsg *sendmsg, Response* resp) { std::string name = ioc->get_userid(); if (name.empty()) { resp->_result = sendmsg->_from_name + " has not logined in"; return; } std::string xml = ChatXml::build_receive_xml(sendmsg->_msg, sendmsg->_from_name); std::list<std::string>& tousers = sendmsg->_to_list; std::list<std::string>::iterator it; for (it = tousers.begin(); it != tousers.end(); ++it) { size_t index = _id_user.get_hash_index(*it); BaseUser* user = NULL; IOComponent* ioc = NULL; bool send_succ = false; UNUSED(send_succ); _id_user.ct_read_lock(index); user = _id_user.get_user(index, *it); if (user) { ioc = user->get_ioc(); if (ioc) { Packet* pack = new Packet(); pack->writeBytes(xml.c_str(), xml.length()); if (!ioc->post_packet(pack)) { //printf("+++++++++++send to %s %s\n", it->c_str(), (send_succ ? "succ" : "false")); delete pack; } else { send_succ = true; } } } _id_user.ct_read_unlock(index); //printf(">>>>>>>>>>>send to %s %s\n", it->c_str(), (send_succ ? "succ" : "false")); } resp->_result = "succ"; }
void EchoServer::start() { DefaultPacketFactory factory; DefaultPacketStreamer streamer(&factory); IOComponent *ioc = _transport.listen(_spec.c_str(), &streamer, this); if (ioc == NULL) { ANET_LOG(ERROR, "listen error."); return; } ANET_LOG(INFO, "EchoServer(%s) started.", _spec.c_str()); _transport.run(); ANET_LOG(INFO, "EchoServer(%s) Quiting...", _spec.c_str()); ANET_GLOBAL_STAT.log(); ioc->close(); ioc->subRef(); }
void TCPCONNECTIONTF::testReadMaliciousDataInfinitLoop() { ANET_LOG(DEBUG, "Begin testReadMaliciousDataInfinitLoop"); int64_t now = TimeUtil::getTime(); Transport tranClient; Transport tranServer; const char sepc[] = "tcp:localhost:12346"; ConnPacketFactory factory; DefaultPacketStreamer defaultStreamer(&factory); DefaultPacketHandler defaultHandler; TCPServerAdapter adapter; MaliciousStreamer maliciousStreamer(&factory); IOComponent *listener = tranServer.listen(sepc, &defaultStreamer, &adapter); CPPUNIT_ASSERT(listener); ANET_LOG(SPAM,"After tranServer->listen()"); tranServer.eventIteration(now); ANET_LOG(SPAM,"After tranServer->eventIteration(now)"); //create a connection Connection *conn = tranClient.connect(sepc, &maliciousStreamer); ANET_LOG(SPAM,"After tranClient->connect(spec, _streamer, false)"); CPPUNIT_ASSERT(conn); tranClient.eventIteration(now); ANET_LOG(SPAM,"After tranClient->eventIteration(now)"); //accept the connection tranServer.eventIteration(now); ANET_LOG(SPAM,"After tranServer->eventIteration(now)"); conn->postPacket(new ConnPacket(11), &defaultHandler, NULL); maliciousStreamer._maliciousLen = 0x80000000 + 10; ANET_LOG(DEBUG,"before conn->writeData()"); conn->writeData(); ANET_LOG(DEBUG,"before connAcc->readData()"); tranServer.eventIteration(now); ANET_LOG(DEBUG,"after connAcc->readData()"); tranClient.eventIteration(now); CPPUNIT_ASSERT(conn->isClosed()); ANET_LOG(DEBUG,"after tranClient.eventIteration(now)"); conn->subRef(); listener->subRef(); ANET_LOG(DEBUG, "End testReadMaliciousDataInfinitLoop"); }
/** * test Server and Client memory leak * test whether packets are deleted when connection closed */ void TCPCONNECTIONTF::testMemLeak() { char spec[] = "tcp:localhost:13147"; int64_t now = TimeUtil::getTime(); Transport *tranServer = new Transport; Transport *tranClient = new Transport; ConnServerAdapter *adapter = new ConnServerAdapter; //add listener to tranServer IOComponent *listener = tranServer->listen(spec, _streamer, adapter); CPPUNIT_ASSERT(listener); tranServer->eventIteration(now); //create a connection Connection *conn = tranClient->connect(spec, _streamer, false); CPPUNIT_ASSERT(conn); tranClient->eventIteration(now); //accept the connection tranServer->eventIteration(now); // client send two packets _conn->postPacket(new ConnPacket, _handler, NULL, true); _conn->postPacket(new ConnPacket, _handler, NULL, true); tranClient->eventIteration(now); //server accept two packets tranServer->eventIteration(now); IOComponent *ioc = tranServer->_iocListTail; Connection *tmpConn = ((TCPComponent *)ioc)->_connection; //client close the connection _conn->close(); tranClient->eventIteration(now); tranServer->eventIteration(now); CPPUNIT_ASSERT_EQUAL((size_t)0, tmpConn->_outputQueue.size()); delete adapter; delete tranClient; delete tranServer; listener->subRef(); conn->subRef(); }
void Transport::eventLoop(SocketEvent *socketEvent) { IOEvent events[MAX_SOCKET_EVENTS]; while (!_stop) { // 检查是否有事件发生 int cnt = socketEvent->getEvents(1000, events, MAX_SOCKET_EVENTS); if (cnt < 0) { if(errno == EINTR)continue; SYS_LOG(INFO, "得到events出错了: %s(%d)\n", strerror(errno), errno); } for (int i = 0; i < cnt; i++) { IOComponent *ioc = events[i]._ioc; if (ioc == NULL) { continue; } if (events[i]._errorOccurred) { // 错误发生了 removeComponent(ioc); continue; } ioc->addRef(); // 读写 bool rc = true; if (events[i]._readOccurred) { rc = ioc->handleReadEvent(); } if (rc && events[i]._writeOccurred) { rc = ioc->handleWriteEvent(); } ioc->subRef(); if (!rc) { removeComponent(ioc); } } } }
void Transport::eventIteration( int64_t &now) { IOEvent events[MAX_SOCKET_EVENTS]; int cnt = _socketEvent.getEvents(100, events, MAX_SOCKET_EVENTS); now = TimeUtil::getTime(); for (int i = 0; i < cnt; i++) { IOComponent *ioc = events[i]._ioc; assert(ioc); bool rc = true; if (events[i]._errorOccurred) { // 错误发生了 rc = ioc->handleErrorEvent(); } // 读写 if (rc && events[i]._readOccurred) { rc = ioc->handleReadEvent(); } if (rc && events[i]._writeOccurred) { rc = ioc->handleWriteEvent(); } ioc->updateUseTime(now); } processCommands(); }
static uint8_t *generateUpdateMask() { // returns null if there are no updates, otherwise returns // a mask for the update data //std::cout << "generating mask\n"; if (updatedComponentsOut.empty()) return 0; unsigned int min = IOComponent::getMinIOOffset(); unsigned int max = IOComponent::getMaxIOOffset(); uint8_t *res = new uint8_t[max+1]; memset(res, 0, max+1); //std::cout << "mask is " << (max+1) << " bytes\n"; std::set<IOComponent*>::iterator iter = updatedComponentsOut.begin(); while (iter != updatedComponentsOut.end()) { IOComponent *ioc = *iter; //TBD this can be null if (ioc->ownersEnabled()) iter++; else iter = updatedComponentsOut.erase(iter); if (ioc->direction() != IOComponent::DirOutput && ioc->direction() != IOComponent::DirBidirectional) continue; unsigned int offset = ioc->address.io_offset; unsigned int bitpos = ioc->address.io_bitpos; offset += bitpos/8; bitpos = bitpos % 8; uint8_t mask = 0x01 << bitpos; // set a bit in the mask for each bit of this value for (unsigned int i=0; i<ioc->address.bitlen; ++i) { res[offset] |= mask; mask = mask << 1; if (!mask) {mask = 0x01; ++offset; } } } #if VERBOSE_DEBUG std::cout << "generated mask: "; display(res, max-min+1); std::cout << "\n"; #endif return res; }
void TCPCONNECTIONTF::testClose() { TCPServerAdapter adapter; Transport *tranServer = new Transport; char spec[] = "tcp:localhost:13345"; tranServer->start(); IOComponent *listener = tranServer->listen(spec, _streamer, &adapter); CPPUNIT_ASSERT(listener); //start client Transport *tranClient = new Transport; tranClient->start(); Connection *conn = tranClient->connect(spec, _streamer, false); CPPUNIT_ASSERT(conn); CPPUNIT_ASSERT(_conn->postPacket(new ConnPacket(31), _handler, NULL)); // the close() has not implement ANET_LOG(SPAM,"Before Calling _conn->close();"); _conn->close(); ANET_LOG(SPAM,"After Calling _conn->close();"); CPPUNIT_ASSERT(_conn->isClosed()); ANET_LOG(SPAM,"After Assert(_conn->isClosed();"); tranClient->stop(); ANET_LOG(SPAM,"After Calling tranClient->stop();"); tranClient->wait(); ANET_LOG(SPAM,"After Calling tranClient->wait();"); tranServer->stop(); ANET_LOG(SPAM,"After Calling tran_server->stop();"); tranServer->wait(); ANET_LOG(SPAM,"After Calling tranClient->wait();"); delete tranClient; delete tranServer; listener->subRef(); conn->subRef(); }
bool BeckhoffdListJSON::run(std::vector<Value> ¶ms) { cJSON *root = cJSON_CreateArray(); std::map<std::string, IOComponent*>::const_iterator iter = IOComponent::devices.begin(); while (iter != IOComponent::devices.end()) { std::string name_str = (*iter).first; IOComponent *ioc = (*iter++).second; if (name_str == "!") continue; //TBD cJSON *node = cJSON_CreateObject(); cJSON_AddStringToObject(node, "name", name_str.c_str()); cJSON_AddStringToObject(node, "class", ioc->type()); cJSON_AddNumberToObject(node, "value", ioc->value()); cJSON_AddNumberToObject(node, "module", ioc->address.module_position); ECModule *mod = ECInterface::findModule(ioc->address.module_position); if (mod) { cJSON_AddStringToObject(node, "module_name", mod->name.c_str()); } if (strcmp(ioc->type(), "Output") == 0) cJSON_AddStringToObject(node, "tab", "Outputs"); else if (strcmp(ioc->type(), "AnalogueOutput") == 0) cJSON_AddStringToObject(node, "tab", "Ana.Out"); else if (strcmp(ioc->type(), "AnalogueInput") == 0) cJSON_AddStringToObject(node, "tab", "Ana.In"); else cJSON_AddStringToObject(node, "tab", "Inputs"); cJSON_AddStringToObject(node, "state", ioc->getStateString()); // if (ioc->isOn()) // cJSON_AddStringToObject(node, "state", "on"); // else if (ioc->isOff()) // cJSON_AddStringToObject(node, "state", "off"); // else // cJSON_AddStringToObject(node, "state", "unknown"); cJSON_AddTrueToObject(node, "enabled"); cJSON_AddItemToArray(root, node); } char *res = cJSON_Print(root); cJSON_Delete(root); bool done; char *p = res; while (*p) { *p &= 0x7f; ++p; } if (res) { result_str = res; free(res); done = true; } else { error_str = "JSON error"; done = false; } return done; }
/* * 超时检查, 被run函数调用 */ void Transport::timeoutLoop() { IOComponent *mydelHead = NULL; IOComponent *mydelTail = NULL; std::vector<IOComponent*> mylist; while (!_stop) { // 先写复制到list中 _iocsMutex.lock(); if (_iocListChanged) { mylist.clear(); IOComponent *iocList = _iocListHead; while (iocList) { mylist.push_back(iocList); iocList = iocList->_next; } _iocListChanged = false; } // 加入到mydel中 if (_delListHead != NULL && _delListTail != NULL) { if (mydelTail == NULL) { mydelHead = _delListHead; } else { mydelTail->_next = _delListHead; _delListHead->_prev = mydelTail; } mydelTail = _delListTail; // 清空delList _delListHead = _delListTail = NULL; } _iocsMutex.unlock(); // 对每个iocomponent进行检查 for (int i=0; i<(int)mylist.size(); i++) { IOComponent *ioc = mylist[i]; ioc->checkTimeout(tbsys::CTimeUtil::getTime()); } // 删除掉 IOComponent *tmpList = mydelHead; int64_t nowTime = tbsys::CTimeUtil::getTime() - static_cast<int64_t>(900000000); // 15min while (tmpList) { if (tmpList->getRef() <= 0) { tmpList->subRef(); } if (tmpList->getRef() <= -10 || tmpList->getLastUseTime() < nowTime) { // 从链中删除 if (tmpList == mydelHead) { // head mydelHead = tmpList->_next; } if (tmpList == mydelTail) { // tail mydelTail = tmpList->_prev; } if (tmpList->_prev != NULL) tmpList->_prev->_next = tmpList->_next; if (tmpList->_next != NULL) tmpList->_next->_prev = tmpList->_prev; IOComponent *ioc = tmpList; tmpList = tmpList->_next; TBSYS_LOG(INFO, "DELIOC, %s, IOCount:%d, IOC:%p\n", ioc->getSocket()->getAddr().c_str(), _iocListCount, ioc); delete ioc; } else { tmpList = tmpList->_next; } } usleep(500000); // 最小间隔100ms } // 写回到_delList上,让destroy销毁 _iocsMutex.lock(); if (mydelHead != NULL) { if (_delListTail == NULL) { _delListHead = mydelHead; } else { _delListTail->_next = mydelHead; mydelHead->_prev = _delListTail; } _delListTail = mydelTail; } _iocsMutex.unlock(); }
void IOComponent::processAll(uint64_t clock, size_t data_size, uint8_t *mask, uint8_t *data, std::set<IOComponent *> &updated_machines) { io_clock = clock; // receive process data updates and mask to yield updated components current_time = microsecs(); assert(data != io_process_data); #if VERBOSE_DEBUG for (size_t ii=0; ii<data_size; ++ii) if (mask[ii]) { std::cout << "IOComponent::processAll()\n"; std::cout << "size: " << data_size << "\n"; std::cout << "pdta: "; display( io_process_data, data_size); std::cout << "\n"; std::cout << "pmsk: "; display( io_process_mask, data_size); std::cout << "\n"; std::cout << "data: "; display( data, data_size); std::cout << "\n"; std::cout << "mask: "; display( mask, data_size); std::cout << "\n"; break; } #endif assert(data_size == process_data_size); if (hardware_state == s_hardware_preinit) { // the initial process data has arrived from EtherCAT. keep the previous data as the defaults // so they can be applied asap memcpy(io_process_data, data, process_data_size); //setHardwareState(s_hardware_init); return; } // step through the incoming mask and update bits in process data uint8_t *p = data; uint8_t *m = mask; uint8_t *q = io_process_data; IOComponent *just_added = 0; for (unsigned int i=0; i<process_data_size; ++i) { if (!last_process_data) { if (*m) notifyComponentsAt(i); } // if (*m && *p==*q) { // std::cout<<"warning: incoming_data == process_data but mask indicates a change at byte " // << (int)(m-mask) << std::setw(2) << std::hex << " value: 0x" << (int)(*m) << std::dec << "\n"; // } if (*p != *q && *m) { // copy masked bits if any uint8_t bitmask = 0x01; int j = 0; // check each bit against the mask and if the mask if // set, check if the bit has changed. If the bit has // changed, notify components that use this bit and // update the bit while (bitmask) { if ( *m & bitmask) { //std::cout << "looking up " << i << ":" << j << "\n"; IOComponent *ioc = (*indexed_components)[ i*8+j ]; if (ioc && ioc != just_added) { just_added = ioc; //if (!ioc) std::cout << "no component at " << i << ":" << j << " found\n"; //else std::cout << "found " << ioc->io_name << "\n"; #if 0 if (ioc && ioc->last_event != e_none) { // pending locally sourced change on this io std::cout << " adding " << ioc->io_name << " due to event " << ioc->last_event << "\n"; updatedComponentsIn.insert(ioc); } #endif if ( (*p & bitmask) != (*q & bitmask) ) { // remotely source change on this io if (ioc) { //std::cout << " adding " << ioc->io_name << " due to bit change\n"; boost::recursive_mutex::scoped_lock lock(processing_queue_mutex); updatedComponentsIn.insert(ioc); } if (*p & bitmask) *q |= bitmask; else *q &= (uint8_t)(0xff - bitmask); } //else { // std::cout << "no change " << (unsigned int)*p << " vs " << // (unsigned int)*q << "\n";} } else { if (!ioc) std::cout << "IOComponent::processAll(): no io component at " << i <<":" <<j <<" but mask bit is set\n"; if ( (*p & bitmask) != (*q & bitmask) ) { if (*p & bitmask) *q |= bitmask; else *q &= (uint8_t)(0xff - bitmask); } } } bitmask = bitmask << 1; ++j; } } ++p; ++q; ++m; } if (hardware_state == s_operational) { // save the domain data for the next check if (!last_process_data) { last_process_data = new uint8_t[process_data_size]; } memcpy(last_process_data, io_process_data, process_data_size); } { boost::recursive_mutex::scoped_lock lock(processing_queue_mutex); if (!updatedComponentsIn.size()) return; // std::cout << updatedComponentsIn.size() << " component updates from hardware\n"; #ifdef USE_EXPERIMENTAL_IDLE_LOOP // look at the components that changed and remove them from the outgoing queue as long as the // outputs have been sent to the hardware std::set<IOComponent*>::iterator iter = updatedComponentsIn.begin(); while (iter != updatedComponentsIn.end()) { IOComponent *ioc = *iter++; ioc->read_time = io_clock; //std::cerr << "processing " << ioc->io_name << " time: " << ioc->read_time << "\n"; updatedComponentsIn.erase(ioc); if (updates_sent && updatedComponentsOut.count(ioc)) { //std::cout << "output request for " << ioc->io_name << " resolved\n"; updatedComponentsOut.erase(ioc); } //else std::cout << "still waiting for " << ioc->io_name << " event: " << ioc->last_event << "\n"; updated_machines.insert(ioc); } // for machines with updates to send, if these machines already have the same value // as the hardware (and updates have been sent) we also remove them from the // outgoing queue if (updates_sent) { iter = updatedComponentsOut.begin(); while (iter != updatedComponentsOut.end()) { IOComponent *ioc = *iter++; if (ioc->pending_value == (uint32_t)ioc->address.value) { //std::cout << "output request for " << ioc->io_name << " cleared as hardware value matches\n"; updatedComponentsOut.erase(ioc); } } } #else std::list<IOComponent *>::iterator iter = processing_queue.begin(); while (iter != processing_queue.end()) { IOComponent *ioc = *iter++; ioc->read_time = io_clock; ioc->idle(); } #endif } outputs_waiting = updatedComponentsOut.size(); }