int main(int argc, char** argv) { /** * Argument Wrangling * */ boost::program_options::options_description desc( "PacketPlayer" ); boost::program_options::variables_map vm; boost::asio::io_service io_service; //boost::array<char, MAX_PACKET_BYTES> recvBuffer; boost::asio::ip::udp::endpoint sender_endpoint; //size_t bytes_recvd; PacketReader* p; /** * Note: options inside the configuration file that are NOT listed here * become ignored and are not accessible. */ desc.add_options() ( "help,h", "Display help message" ) ( "server", boost::program_options::value<std::string>()->default_value("localhost"), "MetaServer host. \nDefault:localhost" ) ( "port", boost::program_options::value<int>()->default_value(8453), "MetaServer port. \nDefault:8453" ) ( "playonly", boost::program_options::value<std::string>(), "Play output info only.\nDefault: false" ) ( "file", boost::program_options::value<std::string>(), "Binary Packet logfile.\nDefault: none" ) ; try { boost::program_options::store( boost::program_options::parse_command_line(argc, argv, desc), vm ); boost::program_options::notify(vm); /** * Special case for help */ if ( vm.count("help") ) { std::cout << desc << std::endl; return 0; } std::cout << "Server : " << vm["server"].as<std::string>() << std::endl; std::cout << "Port : " << vm["port"].as<int>() << std::endl; std::cout << "---------------" << std::endl; for (boost::program_options::variables_map::iterator it=vm.begin(); it!=vm.end(); ++it ) { if ( it->second.value().type() == typeid(int) ) { std::cout << it->first.c_str() << "=" << it->second.as<int>() << std::endl; } else if (it->second.value().type() == typeid(std::string) ) { std::cout << it->first.c_str() << "=" << it->second.as<std::string>().c_str() << std::endl; } else if (it->second.value().type() == typeid(attribute_list) ) { std::cout << it->first.c_str() << "=Attribute List" << std::endl; } } std::cout << "-------------------------" << std::endl; /** * because boost query is too stupid to take port as an int */ std::stringstream port_str; port_str << vm["port"].as<int>(); /** * Wrangle the file etc options */ std::string file = ""; bool playOnly = false; if( vm.count("playonly") ) { std::string s = vm["playonly"].as<std::string>(); if ( boost::iequals(s,"true") ) { playOnly = true; } } if( vm.count("file") ) { file = vm["file"].as<std::string>(); } if ( file.empty() ) { std::cout << "--file option not specified, but is required" << std::endl; return 13; } /** * Initialize reader */ p = new PacketReader(); int pkts = p->parseBinaryFile(file); if( playOnly ) { while(p->hasPacket()) { MetaServerPacket msp = p->pop(); unsigned int i = msp.getPacketType(); std::string s = msp.getOutBound() ? ">>>>" : "<<<<"; std::cout << "Packet ["; std::cout << std::setfill('0') << std::setw(10) << msp.getSequence(); std::cout << "] " << s << " : " << NMT_PRETTY[i] << std::endl; } } else { std::cout << "TODO: play packets to listed metaserver" << std::endl; } std::cout << "Packet File : " << file << std::endl; std::cout << "Packet Count: " << pkts << std::endl; } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << std::endl; } std::cout << "All Done!" << std::endl; return 0; }
/** * Convenience method that evaluates what type of packet and call appropriate handle method * @param msp incoming metaserver packet * @param rsp outgoing metaserver packet to be filled */ void MetaServer::processMetaserverPacket(MetaServerPacket& msp, MetaServerPacket& rsp) { /* * Packet Sequence: store this so that we can replay the packets in the * same order after the fact * Time Offset: time in milliseconds relative to the "start time". The start time * is defined as the first packet to be processed. I chose this because * it will be possible to replay the packets in the correct order, at * exactly the same rate, relative to the start of the first packet */ if ( m_PacketSequence == 0 ) m_startTime = boost::posix_time::microsec_clock::local_time(); ++m_PacketSequence; msp.setSequence(m_PacketSequence); msp.setTimeOffset( getDeltaMillis() ); switch(msp.getPacketType()) { case NMT_SERVERKEEPALIVE: processSERVERKEEPALIVE(msp,rsp); break; case NMT_SERVERSHAKE: processSERVERSHAKE(msp,rsp); break; case NMT_TERMINATE: processTERMINATE(msp,rsp); break; case NMT_CLIENTKEEPALIVE: processCLIENTKEEPALIVE(msp,rsp); break; case NMT_CLIENTSHAKE: processCLIENTSHAKE(msp,rsp); break; case NMT_LISTREQ: processLISTREQ(msp,rsp); break; case NMT_SERVERATTR: processSERVERATTR(msp,rsp); break; case NMT_CLIENTATTR: processCLIENTATTR(msp,rsp); break; case NMT_CLIENTFILTER: processCLIENTFILTER(msp,rsp); break; default: --m_PacketSequence; m_Logger.debug("Packet Type [%u] not supported.", msp.getPacketType()); break; } /* * Flag response packets sequence and offset tagging */ ++m_PacketSequence; rsp.setSequence(m_PacketSequence); rsp.setTimeOffset( getDeltaMillis() ); /* * Packet Logging */ if ( m_logPackets ) { // always log the incoming packets, even if they are bad ( as a bad incoming packet could be the cause // of an issue ) m_PacketLogger->LogPacket(msp); // we don't want to log if: // 1) sequence is 0 : this means the sequence is not set ... this means something has gone astray elsewhere // 2) packet type is NULL : these responses are never sent to the client if ( rsp.getSequence() != 0 && rsp.getPacketType() != NMT_NULL ) m_PacketLogger->LogPacket(rsp); } }