void LX::CommandModeQuick(Port &port, OperationEnvironment &env) { SendSYN(port); env.Sleep(500); SendSYN(port); env.Sleep(500); SendSYN(port); env.Sleep(500); }
void LX::CommandModeQuick(Port &port, OperationEnvironment &env) { SendSYN(port); env.Sleep(std::chrono::milliseconds(500)); SendSYN(port); env.Sleep(std::chrono::milliseconds(500)); SendSYN(port); env.Sleep(std::chrono::milliseconds(500)); }
/////////////////////////////////////////////////////////////////////////////// /// CSRConnection::CSRConnection /// @description Send function for the CSRConnection. Sending using this /// protocol involves an alternating bit scheme. Messages can expire and /// delivery won't be attempted after the deadline is passed. Killed messages /// are noted in the next outgoing message. The reciever tracks the killed /// messages and uses them to help maintain ordering. /// @pre The protocol is intialized. /// @post At least one message is in the channel and actively being resent. /// The send window is greater than or equal to one. The timer for the /// resend is freshly set or is currently running for a resend. /// If a message is written to the channel, the m_killable flag is set. /// @param msg The message to write to the channel. /////////////////////////////////////////////////////////////////////////////// void CSRConnection::Send(CMessage msg) { Logger.Debug << __PRETTY_FUNCTION__ << std::endl; ptree x = static_cast<ptree>(msg); unsigned int msgseq; if(m_outsync == false) { SendSYN(); } CMessage outmsg(x); msgseq = m_outseq; outmsg.SetSequenceNumber(msgseq); m_outseq = (m_outseq+1) % SEQUENCE_MODULO; outmsg.SetSourceUUID(GetConnection()->GetConnectionManager().GetUUID()); outmsg.SetSourceHostname(GetConnection()->GetConnectionManager().GetHostname()); outmsg.SetProtocol(GetIdentifier()); outmsg.SetSendTimestampNow(); if(!outmsg.HasExpireTime()) { Logger.Notice<<"Set Expire time"<<std::endl; outmsg.SetExpireTimeFromNow(boost::posix_time::milliseconds(3000)); } m_window.push_back(outmsg); if(m_window.size() == 1) { Write(outmsg); boost::system::error_code x; Resend(x); } }
/////////////////////////////////////////////////////////////////////////////// /// CSRConnection::CSRConnection /// @description Handles refiring ACKs and Sent Messages. /// @pre The connection has received or sent at least one message. /// @post One of the following conditions or combination of states is /// upheld: /// 1) An ack for a message that has not yet expired has been resent and /// a timer to call resend has been set. /// 2) Message(s) has/have expired and are removed from the queue. The /// flag to send kills is set. /// 3) The window is empty and no message is set to the channel, the /// timer is not re-set. /// 4) A message expired and then next message will cause the sequence /// numbers to wrap, (or they have wrapped since the last time a message /// was successfully sent) so a sync is inserted at the front of the queue /// to skip that case on the receiver side. The sendkill flag is cleared /// and the sendkill value is cleared. /// 5) If there is still a message to resend, the timer is reset. /// @param err The timer error code. If the err is 0 then the timer expired /////////////////////////////////////////////////////////////////////////////// void CSRConnection::Resend(const boost::system::error_code& err) { Logger.Debug << __PRETTY_FUNCTION__ << std::endl; if(!err) { boost::posix_time::ptime now; now = boost::posix_time::microsec_clock::universal_time(); CMessage ack; // Check if the front of the queue is an ACK if(m_currentack.GetStatus() == freedm::broker::CMessage::Accepted) { if(!m_currentack.IsExpired()) { Write(m_currentack); m_timeout.cancel(); m_timeout.expires_from_now(boost::posix_time::milliseconds(REFIRE_TIME)); m_timeout.async_wait(boost::bind(&CSRConnection::Resend,this, boost::asio::placeholders::error)); } } while(m_window.size() > 0 && m_window.front().IsExpired()) { //First message in the window should be the only one //ever to have been written. m_sendkills = true; Logger.Notice<<"Message Expired: "<<m_window.front().GetHash() <<":"<<m_window.front().GetSequenceNumber()<<std::endl; m_window.pop_front(); } if(m_window.size() > 0) { if(m_sendkills && m_sendkill > m_window.front().GetSequenceNumber()) { // If we have expired a message and caused the seqnos // to wrap, we resync the connection. This shouldn't // happen very often. // If we wrap, don't send kills m_sendkills = false; m_sendkill = 0; SendSYN(); } if(m_sendkills) { // kill will be set to the last message accepted by receiver // (and whose ack has been received) ptree x; x.put("src.kill",m_sendkill); m_window.front().SetProtocolProperties(x); } Write(m_window.front()); // Head of window can be killed. m_timeout.cancel(); m_timeout.expires_from_now(boost::posix_time::milliseconds(REFIRE_TIME)); m_timeout.async_wait(boost::bind(&CSRConnection::Resend,this, boost::asio::placeholders::error)); } } }
/////////////////////////////////////////////////////////////////////////////// /// CConnection::Send /// @description: Given a message and wether or not it should be sequenced, /// write that message to the channel. /// @pre: The CConnection object is initialized. /// @post: If the window is in not full, the message will have been written to /// to the channel. Before being sent the message has been signed with the /// UUID, source hostname and sequence number (if it is being sequenced). /// If the message is being sequenced and the window is not already full, /// the timeout timer is cancelled and reset. /// @param p_mesg: A CMessage to write to the channel. /// @param sequence: if true, the message will be sequenced and reliably /// delievered in order. Otherwise it is immediately fired and forgotten. /// this is mostly meant for use with ACKs. True by default. /////////////////////////////////////////////////////////////////////////////// void CConnection::Send(CMessage p_mesg, bool sequence) { Logger::Debug << __PRETTY_FUNCTION__ << std::endl; //Make a call to the dispatcher to sign the messages //With a bunch of shiny stuff. ptree x = static_cast<ptree>(p_mesg); unsigned int msgseq; //m_dispatch.HandleWrite(x); CMessage outmsg(x); // Sign the message with the hostname, uuid, and squencenumber if(sequence == true) { if(m_synched == false) { m_synched = true; SendSYN(); } msgseq = m_outsequenceno; outmsg.SetSequenceNumber(msgseq); m_outsequenceno = (m_outsequenceno+1) % GetSequenceModulo(); } outmsg.SetSourceUUID(GetConnectionManager().GetUUID()); outmsg.SetSourceHostname(GetConnectionManager().GetHostname()); if(sequence == true) { // If it isn't squenced then don't put it in the queue. m_queue.Push( QueueItem(msgseq,outmsg) ); } // Before, we would put it into a queue to be sent later, now we are going // to immediately write it to channel. if(m_queue.size() <= GetWindowSize() || sequence == false) { // Only try to write to the socket if the window isn't already full. // Or it is an unsequenced message HandleSend(outmsg); if(sequence == true) { m_timeout.cancel(); m_timeout.expires_from_now(boost::posix_time::milliseconds(1000)); m_timeout.async_wait(boost::bind(&CConnection::Resend,this, boost::asio::placeholders::error)); } } }
bool LX::CommandMode(Port &port, OperationEnvironment &env) { /* switch to command mode, first attempt */ if (!SendSYN(port) || !port.FullFlush(env, 50, 200)) return false; /* the port is clean now; try the SYN/ACK procedure up to three times */ for (unsigned i = 0; i < 100 && !env.IsCancelled(); ++i) if (Connect(port, env)) /* make sure all remaining ACKs are flushed */ return port.FullFlush(env, 200, 500); return false; }
/////////////////////////////////////////////////////////////////////////////// /// CSRConnection::Recieve /// @description Accepts a message into the protocol, if that message should /// be accepted. If this function returns true, the message is passed to /// the dispatcher. Since this message accepts SYNs there might be times /// when processing and state changes but the message is marked as "rejected" /// this is normal. /// @pre Accept logic can be complicated, there are several scenarios that /// should be addressed. /// 1) A bad request has been recieved /// 2) A SYN message is recieved for the first time /// 3) A SYN message is recieved as a duplicate. /// 4) A Message has been recieved before the connection has been synced. /// 5) A Message has been recieved with the expected sequenceno with or /// without a kill flag. /// 6) A message has been recieved with a kill flag. The kill is greater /// than the expected sequence number /// 7) A message has been recieved with a kill flag. The kill is less than /// the expected sequence number. However, the message's number is less /// than the expected sequence number /// 8) A message has been received with a kill flag. The kill is less than /// the expected sequence number and the message's sequence number is /// greater than the expected sequence number. /// @post Cases are handled as follows: /// 1) The connection is resynced. /// 2) The message is ACKed, the send time of the sync is noted, and the /// connection is synced. /// 3) The SYN is ignored. /// 4) A bad request message is generated and sent to the source. /// 5) The message is accepted. /// 6) The message is rejected. Kills should only ever be less than the /// expected sequence number unless the message is arrived out of order /// 7) The message is simply old but still arriving at the socket, and can /// be rejected. /// 8) The message should be accepted because one or more message expired /// in the gap of sequence numbers. /// @return True if the message is accepted, false otherwise. /////////////////////////////////////////////////////////////////////////////// bool CSRConnection::Recieve(const CMessage &msg) { Logger.Debug << __PRETTY_FUNCTION__ << std::endl; unsigned int kill = 0; bool usekill = false; //If true, we should accept any inseq if(msg.GetStatus() == freedm::broker::CMessage::BadRequest) { //See if we are already trying to sync: if(m_window.front().GetStatus() != freedm::broker::CMessage::Created) { if(m_outsynctime != msg.GetSendTimestamp()) { m_outsynctime = msg.GetSendTimestamp(); SendSYN(); } else { Logger.Notice<<"Already synced for this time"<<std::endl; } } return false; } if(msg.GetStatus() == freedm::broker::CMessage::Created) { //Check to see if we've already seen this SYN: if(msg.GetSendTimestamp() == m_insynctime) { return false; Logger.Notice<<"Duplicate Sync"<<std::endl; } Logger.Notice<<"Got Sync"<<std::endl; m_inseq = (msg.GetSequenceNumber()+1)%SEQUENCE_MODULO; m_insynctime = msg.GetSendTimestamp(); m_inresyncs++; m_insync = true; SendACK(msg); return false; } if(m_insync == false) { Logger.Notice<<"Connection Needs Resync"<<std::endl; //If the connection hasn't been synchronized, we want to //tell them it is a bad request so they know they need to sync. freedm::broker::CMessage outmsg; // Presumably, if we are here, the connection is registered outmsg.SetSourceUUID(GetConnection()->GetConnectionManager().GetUUID()); outmsg.SetSourceHostname(GetConnection()->GetConnectionManager().GetHostname()); outmsg.SetStatus(freedm::broker::CMessage::BadRequest); outmsg.SetSequenceNumber(m_inresyncs%SEQUENCE_MODULO); outmsg.SetSendTimestamp(msg.GetSendTimestamp()); outmsg.SetProtocol(GetIdentifier()); Write(outmsg); return false; } // See if the message contains kill data. If it does, read it and mark // we should use it. try { ptree pp = msg.GetProtocolProperties(); kill = pp.get<unsigned int>("src.kill"); usekill = true; } catch(std::exception &e) { kill = msg.GetSequenceNumber(); usekill = false; } //Consider the window you expect to see // If the killed message is the one immediately preceeding this // message in terms of sequence number we should accept it if(msg.GetSequenceNumber() == m_inseq) { //m_insync = true; m_inseq = (m_inseq+1)%SEQUENCE_MODULO; return true; } else if(usekill == true && kill< m_inseq && msg.GetSequenceNumber() > m_inseq) { //m_inseq will be right for the next expected message. m_inseq = (msg.GetSequenceNumber()+1)%SEQUENCE_MODULO; return true; } else if(usekill == true) { Logger.Notice<<"KILL: "<<kill<<" INSEQ "<<m_inseq<<" SEQ: " <<msg.GetSequenceNumber()<<std::endl; } // Justin case. return false; }
/** * Send SYN and wait for ACK. * * @return true on success */ static inline bool Connect(Port &port, OperationEnvironment &env, unsigned timeout_ms=500) { return SendSYN(port) && ExpectACK(port, env, timeout_ms); }