2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Author : Maxim Mamontov <faust@stargazer.dp.ua>
25 #include "stg/json_parser.h"
26 #include "stg/json_generator.h"
27 #include "stg/users.h"
29 #include "stg/logger.h"
30 #include "stg/common.h"
32 #include <yajl/yajl_gen.h>
42 using STG::JSON::Parser;
43 using STG::JSON::PairsParser;
44 using STG::JSON::EnumParser;
45 using STG::JSON::NodeParser;
47 using STG::JSON::MapGen;
48 using STG::JSON::StringGen;
53 double CONN_TIMEOUT = 5;
54 double PING_TIMEOUT = 1;
72 std::map<std::string, Packet> packetCodes;
73 std::map<std::string, Stage> stageCodes;
75 class PacketParser : public EnumParser<Packet>
78 PacketParser(NodeParser* next, Packet& packet, std::string& packetStr)
79 : EnumParser(next, packet, packetStr, packetCodes)
81 if (!packetCodes.empty())
83 packetCodes["ping"] = PING;
84 packetCodes["pong"] = PONG;
85 packetCodes["data"] = DATA;
89 class StageParser : public EnumParser<Stage>
92 StageParser(NodeParser* next, Stage& stage, std::string& stageStr)
93 : EnumParser(next, stage, stageStr, stageCodes)
95 if (!stageCodes.empty())
97 stageCodes["authorize"] = AUTHORIZE;
98 stageCodes["authenticate"] = AUTHENTICATE;
99 stageCodes["preacct"] = PREACCT;
100 stageCodes["accounting"] = ACCOUNTING;
101 stageCodes["postauth"] = POSTAUTH;
105 class TopParser : public NodeParser
109 : m_packetParser(this, m_packet, m_packetStr),
110 m_stageParser(this, m_stage, m_stageStr),
111 m_pairsParser(this, m_data)
114 virtual NodeParser* parseStartMap() { return this; }
115 virtual NodeParser* parseMapKey(const std::string& value)
117 std::string key = ToLower(value);
120 return &m_packetParser;
121 else if (key == "stage")
122 return &m_stageParser;
123 else if (key == "pairs")
124 return &m_pairsParser;
128 virtual NodeParser* parseEndMap() { return this; }
130 const std::string& packetStr() const { return m_packetStr; }
131 Packet packet() const { return m_packet; }
132 const std::string& stageStr() const { return m_stageStr; }
133 Stage stage() const { return m_stage; }
134 const Config::Pairs& data() const { return m_data; }
137 std::string m_packetStr;
139 std::string m_stageStr;
141 Config::Pairs m_data;
143 PacketParser m_packetParser;
144 StageParser m_stageParser;
145 PairsParser m_pairsParser;
148 class ProtoParser : public Parser
151 ProtoParser() : Parser( &m_topParser ) {}
153 const std::string& packetStr() const { return m_topParser.packetStr(); }
154 Packet packet() const { return m_topParser.packet(); }
155 const std::string& stageStr() const { return m_topParser.stageStr(); }
156 Stage stage() const { return m_topParser.stage(); }
157 const Config::Pairs& data() const { return m_topParser.data(); }
160 TopParser m_topParser;
163 class PacketGen : public Gen
166 PacketGen(const std::string& type)
169 m_gen.add("packet", m_type);
171 void run(yajl_gen_t* handle) const
175 PacketGen& add(const std::string& key, const std::string& value)
177 m_gen.add(key, new StringGen(value));
180 PacketGen& add(const std::string& key, MapGen* map)
195 Impl(USERS& users, PLUGIN_LOGGER& logger, const Config& config, int fd, const std::string& remote);
198 int sock() const { return m_sock; }
203 bool isOk() const { return m_ok; }
207 PLUGIN_LOGGER& m_logger;
208 const Config& m_config;
210 std::string m_remote;
213 time_t m_lastActivity;
214 ProtoParser m_parser;
220 bool answer(const USER& user);
225 static bool write(void* data, const char* buf, size_t size);
228 Conn::Conn(USERS& users, PLUGIN_LOGGER& logger, const Config& config, int fd, const std::string& remote)
229 : m_impl(new Impl(users, logger, config, fd, remote))
237 int Conn::sock() const
239 return m_impl->sock();
244 return m_impl->read();
249 return m_impl->tick();
252 bool Conn::isOk() const
254 return m_impl->isOk();
257 Conn::Impl::Impl(USERS& users, PLUGIN_LOGGER& logger, const Config& config, int fd, const std::string& remote)
264 m_lastPing(time(NULL)),
265 m_lastActivity(m_lastPing)
274 bool Conn::Impl::read()
276 static std::vector<char> buffer(1024);
277 ssize_t res = ::read(m_sock, buffer.data(), buffer.size());
280 m_logger("Failed to read data from '" + m_remote + "': " + strerror(errno));
284 m_lastActivity = time(NULL);
287 if (!m_parser.done())
290 m_logger("Failed to read data from '" + m_remote + "': " + strerror(errno));
295 return m_parser.append(buffer.data(), res);
298 bool Conn::Impl::tick()
300 time_t now = time(NULL);
301 if (difftime(now, m_lastActivity) > CONN_TIMEOUT)
303 m_logger("Connection to " + m_remote + " timed out.");
307 if (difftime(now, m_lastPing) > PING_TIMEOUT)
312 bool Conn::Impl::process()
314 switch (m_parser.packet())
317 return processPing();
319 return processPong();
321 return processData();
323 m_logger("Received invalid packet type: " + m_parser.packetStr());
327 bool Conn::Impl::processPing()
332 bool Conn::Impl::processPong()
334 m_lastActivity = time(NULL);
338 bool Conn::Impl::processData()
340 int handle = m_users.OpenSearch();
342 USER_PTR user = NULL;
344 while (m_users.SearchNext(handle, &user))
350 for (Config::Pairs::const_iterator it = m_config.match.begin(); it != m_config.match.end(); ++it)
352 Config::Pairs::const_iterator pos = m_parser.data().find(it->first);
353 if (pos == m_parser.data().end())
358 if (user->GetParamValue(it->second) != pos->second)
373 m_users.CloseSearch(handle);
378 bool Conn::Impl::answer(const USER& user)
380 boost::scoped_ptr<MapGen> reply(new MapGen);
381 for (Config::Pairs::const_iterator it = m_config.reply.begin(); it != m_config.reply.end(); ++it)
382 reply->add(it->first, new StringGen(user.GetParamValue(it->second)));
384 boost::scoped_ptr<MapGen> modify(new MapGen);
385 for (Config::Pairs::const_iterator it = m_config.modify.begin(); it != m_config.modify.end(); ++it)
386 modify->add(it->first, new StringGen(user.GetParamValue(it->second)));
388 PacketGen gen("data");
389 gen.add("result", "ok")
390 .add("reply", reply.get())
391 .add("modify", modify.get());
393 m_lastPing = time(NULL);
395 return generate(gen, &Conn::Impl::write, this);
398 bool Conn::Impl::answerNo()
400 PacketGen gen("data");
401 gen.add("result", "ok");
403 m_lastPing = time(NULL);
405 return generate(gen, &Conn::Impl::write, this);
408 bool Conn::Impl::sendPing()
410 PacketGen gen("ping");
412 m_lastPing = time(NULL);
414 return generate(gen, &Conn::Impl::write, this);
417 bool Conn::Impl::sendPong()
419 PacketGen gen("pong");
421 m_lastPing = time(NULL);
423 return generate(gen, &Conn::Impl::write, this);
426 bool Conn::Impl::write(void* data, const char* buf, size_t size)
428 Conn::Impl& conn = *static_cast<Conn::Impl*>(data);
431 ssize_t res = ::write(conn.m_sock, buf, size);
434 conn.m_logger("Failed to write pong to '" + conn.m_remote + "': " + strerror(errno));