+namespace
+{
+
+double CONN_TIMEOUT = 60;
+double PING_TIMEOUT = 10;
+
+enum Packet
+{
+ PING,
+ PONG,
+ DATA
+};
+
+enum Stage
+{
+ AUTHORIZE,
+ AUTHENTICATE,
+ PREACCT,
+ ACCOUNTING,
+ POSTAUTH
+};
+
+std::map<std::string, Packet> packetCodes;
+std::map<std::string, Stage> stageCodes;
+
+class PacketParser : public EnumParser<Packet>
+{
+ public:
+ PacketParser(NodeParser* next, Packet& packet, std::string& packetStr)
+ : EnumParser(next, packet, packetStr, packetCodes)
+ {
+ if (!packetCodes.empty())
+ return;
+ packetCodes["ping"] = PING;
+ packetCodes["pong"] = PONG;
+ packetCodes["data"] = DATA;
+ }
+};
+
+class StageParser : public EnumParser<Stage>
+{
+ public:
+ StageParser(NodeParser* next, Stage& stage, std::string& stageStr)
+ : EnumParser(next, stage, stageStr, stageCodes)
+ {
+ if (!stageCodes.empty())
+ return;
+ stageCodes["authorize"] = AUTHORIZE;
+ stageCodes["authenticate"] = AUTHENTICATE;
+ stageCodes["preacct"] = PREACCT;
+ stageCodes["accounting"] = ACCOUNTING;
+ stageCodes["postauth"] = POSTAUTH;
+ }
+};
+
+class TopParser : public NodeParser
+{
+ public:
+ typedef void (*Callback) (void* /*data*/);
+ TopParser(Callback callback, void* data)
+ : m_packetParser(this, m_packet, m_packetStr),
+ m_stageParser(this, m_stage, m_stageStr),
+ m_pairsParser(this, m_data),
+ m_callback(callback), m_callbackData(data)
+ {}
+
+ virtual NodeParser* parseStartMap() { return this; }
+ virtual NodeParser* parseMapKey(const std::string& value)
+ {
+ std::string key = ToLower(value);
+
+ if (key == "packet")
+ return &m_packetParser;
+ else if (key == "stage")
+ return &m_stageParser;
+ else if (key == "pairs")
+ return &m_pairsParser;
+
+ return this;
+ }
+ virtual NodeParser* parseEndMap() { m_callback(m_callbackData); return this; }
+
+ const std::string& packetStr() const { return m_packetStr; }
+ Packet packet() const { return m_packet; }
+ const std::string& stageStr() const { return m_stageStr; }
+ Stage stage() const { return m_stage; }
+ const Config::Pairs& data() const { return m_data; }
+
+ private:
+ std::string m_packetStr;
+ Packet m_packet;
+ std::string m_stageStr;
+ Stage m_stage;
+ Config::Pairs m_data;
+
+ PacketParser m_packetParser;
+ StageParser m_stageParser;
+ PairsParser m_pairsParser;
+
+ Callback m_callback;
+ void* m_callbackData;
+};
+
+class ProtoParser : public Parser
+{
+ public:
+ ProtoParser(TopParser::Callback callback, void* data)
+ : Parser( &m_topParser ),
+ m_topParser(callback, data)
+ {}
+
+ const std::string& packetStr() const { return m_topParser.packetStr(); }
+ Packet packet() const { return m_topParser.packet(); }
+ const std::string& stageStr() const { return m_topParser.stageStr(); }
+ Stage stage() const { return m_topParser.stage(); }
+ const Config::Pairs& data() const { return m_topParser.data(); }
+
+ private:
+ TopParser m_topParser;
+};
+
+class PacketGen : public Gen
+{
+ public:
+ PacketGen(const std::string& type)
+ : m_type(type)
+ {
+ m_gen.add("packet", m_type);
+ }
+ void run(yajl_gen_t* handle) const
+ {
+ m_gen.run(handle);
+ }
+ PacketGen& add(const std::string& key, const std::string& value)
+ {
+ m_gen.add(key, new StringGen(value));
+ return *this;
+ }
+ PacketGen& add(const std::string& key, MapGen* map)
+ {
+ m_gen.add(key, map);
+ return *this;
+ }
+ PacketGen& add(const std::string& key, MapGen& map)
+ {
+ m_gen.add(key, map);
+ return *this;
+ }
+ private:
+ MapGen m_gen;
+ StringGen m_type;
+};
+
+}
+
+class Conn::Impl
+{
+ public:
+ Impl(USERS& users, PLUGIN_LOGGER& logger, const Config& config, int fd, const std::string& remote);
+ ~Impl();
+
+ int sock() const { return m_sock; }
+
+ bool read();
+ bool tick();
+
+ bool isOk() const { return m_ok; }
+
+ private:
+ USERS& m_users;
+ PLUGIN_LOGGER& m_logger;
+ const Config& m_config;
+ int m_sock;
+ std::string m_remote;
+ bool m_ok;
+ time_t m_lastPing;
+ time_t m_lastActivity;
+ ProtoParser m_parser;
+
+ const Config::Pairs& stagePairs(Config::Pairs Config::Section::* pairs) const
+ {
+ switch (m_parser.stage())
+ {
+ case AUTHORIZE: return m_config.autz.*pairs;
+ case AUTHENTICATE: return m_config.auth.*pairs;
+ case POSTAUTH: return m_config.postauth.*pairs;
+ case PREACCT: return m_config.preacct.*pairs;
+ case ACCOUNTING: return m_config.acct.*pairs;
+ }
+ throw std::runtime_error("Invalid stage: '" + m_parser.stageStr() + "'.");
+ }
+
+ const Config::Pairs& match() const { return stagePairs(&Config::Section::match); }
+ const Config::Pairs& modify() const { return stagePairs(&Config::Section::modify); }
+ const Config::Pairs& reply() const { return stagePairs(&Config::Section::reply); }
+
+ static void process(void* data);
+ void processPing();
+ void processPong();
+ void processData();
+ bool answer(const USER& user);
+ bool answerNo();
+ bool sendPing();
+ bool sendPong();
+
+ static bool write(void* data, const char* buf, size_t size);
+};
+
+Conn::Conn(USERS& users, PLUGIN_LOGGER& logger, const Config& config, int fd, const std::string& remote)
+ : m_impl(new Impl(users, logger, config, fd, remote))