`
阿尔萨斯
  • 浏览: 4170334 次
社区版块
存档分类
最新评论

TopCoder challenge: SimpleRouter

 
阅读更多
<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>
This implementation is by no means elegant: it does not handle error well; it uses the same space for a forward table with a rule table; it uses hand-coded parsing, which is hard to read and modify...

But it has to comply with some constraints: it has to use ONLY the standard library, it must be completed in a short time.

Then I post it here, after some polishing, for a reference.

SimpleRouter.cpp:

#include <vector><br>#include <string><br>#include <iostream><br>#include <sstream><br><br>using namespace std;<br><br>class SimpleRouter<br>{<br>public:<br> typedef unsigned short num_type;<br> typedef pair<num_type num_type> range_type;<br> typedef vector<range_type> ip_type;<br> typedef vector<ip_type> forward_table_type;<br> typedef pair<string ip_type> rule_type;<br> typedef vector<rule_type> rule_table_type;<br><br> // This method &amp; its signature is required by the problem.<br> vector<string> route(vector<string> rules, vector<string> packets);<br><br>private:<br> string route(ip_type&amp; packet);<br><br> bool range_any(const range_type&amp; ip_seg);<br> bool match(const ip_type&amp; rule_ip, const ip_type&amp; packet);<br><br> range_type parse_ip_seg(string&amp; seg);<br> ip_type parse_ip(const string&amp; ip);<br><br> string ip_seg_to_string(const range_type&amp; ip_seg);<br> string ip_to_string(const ip_type&amp; ip, char port_seperator);<br><br> string get_forward(const ip_type&amp; rule, ip_type packet);<br><br>private:<br> const static num_type min_num = 0;<br> const static num_type max_num = static_cast<num_type>(-1);<br><br> rule_table_type rule_table;<br> forward_table_type forward_table;<br><br> void build_table(vector<string>&amp; rules);<br><br>public: <br> // For debug <br> void print_table();<br> void print_ip(const ip_type&amp; ip);<br><br>};<br><br>void SimpleRouter::build_table(vector<string>&amp; rules)<br>{<br> rule_table.reserve(rules.size());<br> forward_table.reserve(rules.size());<br><br> string action, ip_str, port_str;<br> for(vector<string>::const_iterator iter = rules.begin();<br> iter != rules.end(); ++iter)<br> {<br> string::size_type end_action = iter-&gt;find_first_of(' ');<br> action = iter-&gt;substr(0, end_action);<br> ip_str = iter-&gt;substr(end_action + 1);<br><br> if(action == "FORWARD")<br> {<br> // get position of forward target<br> string::size_type temp = ip_str.find_first_of(' ') + 1;<br> string::size_type start_fwdip = ip_str.find_first_of(' ', temp) + 1;<br><br> rule_table.push_back(make_pair(action, parse_ip(ip_str.substr(0, start_fwdip - 1)))); <br> forward_table.push_back(parse_ip(ip_str.substr(start_fwdip)));<br> }<br> else<br> {<br> rule_table.push_back(make_pair(action, parse_ip(ip_str)));<br> // push a placeholder to forward table<br> forward_table.push_back(ip_type());<br> }<br> }<br>}<br><br>vector <string> SimpleRouter::route(vector<string> rules, vector<string> packets)<br>{<br> build_table(rules);<br><br> vector<string> ret;<br> for(vector<string>::iterator iter = packets.begin(); <br> iter != packets.end(); ++iter)<br> {<br> ret.push_back(route(parse_ip(*iter)));<br> }<br> return ret;<br>}<br><br>string SimpleRouter::route(ip_type&amp; packet)<br>{<br> // check rules one-by-one reversely, as the last matched rule counts<br> forward_table_type::const_reverse_iterator fwd_iter = forward_table.rbegin();<br> rule_table_type::const_reverse_iterator rule_iter = rule_table.rbegin();<br> // workaround for a VC7.1 bug<br> rule_table_type::const_reverse_iterator rule_rend = rule_table.rend();<br><br> for(; rule_iter != rule_rend; ++rule_iter, ++fwd_iter)<br> {<br> string action = rule_iter-&gt;first;<br><br> if(action == "FORWARD")<br> {<br> if(match(rule_iter-&gt;second, packet))<br> {<br> return get_forward(*fwd_iter, packet);<br> } <br> }<br> else<br> {<br> if(match(rule_iter-&gt;second, packet))<br> return action;<br> }<br> }<br><br> // match no rules<br> return "REJECT";<br>}<br><br>string SimpleRouter::get_forward(const ip_type&amp; fwd, ip_type packet)<br>{<br> // if fwd port is specified, replace packet port with fwd port<br> if(fwd.size() &gt; 4 &amp;&amp; !range_any(fwd[4]))<br> packet[4] = fwd[4];<br><br> return ip_to_string(packet, ':');<br>}<br><br>bool inline SimpleRouter::range_any(const range_type&amp; ip_seg)<br>{<br> return ip_seg.first == min_num &amp;&amp; ip_seg.second == max_num;<br>}<br><br>bool SimpleRouter::match(const ip_type&amp; rule_ip, const ip_type&amp; packet)<br>{<br> ip_type::const_iterator rule_iter = rule_ip.begin();<br> ip_type::const_iterator pk_iter = packet.begin();<br><br> for( ; rule_iter != rule_ip.end(); ++rule_iter, ++pk_iter)<br> {<br> // see if packet ip is within the range of rule<br> if(!(rule_iter-&gt;first first) ||<br> !(rule_iter-&gt;second &gt;= pk_iter-&gt;second))<br> return false;<br> }<br> return true;<br>}<br><br>string SimpleRouter::ip_seg_to_string(const range_type&amp; ip_seg)<br>{<br> char ret[12] = "*"; //the longest possible segment is 11 chars:<br> //xxxxx-xxxxx<br><br> if(!range_any(ip_seg))<br> {<br> int len = sprintf(ret, "%d", ip_seg.first);<br> if(ip_seg.first != ip_seg.second)<br> {<br> ret[len] = '-';<br> sprintf(ret + len + 1, "%d", ip_seg.second);<br> }<br> }<br><br> return ret;<br>}<br><br>string SimpleRouter::ip_to_string(const ip_type&amp; ip, char port_seperator)<br>{<br> string ret;<br> ret.reserve(44); //the longest possible ip string is 43 chars:<br> //xxx-xxx.xxx-xxx.xxx-xxx.xxx-xxx xxxxx-xxxxx<br><br> ip_type::const_iterator iter = ip.begin();<br> for(int i = 0; iter != ip.end(); ++iter, ++i)<br> {<br> ret.append(ip_seg_to_string(*iter));<br> if(i ret.append(".");<br> else if(i == 3)<br> ret.append(1, port_seperator);<br> }<br><br> return ret;<br>}<br><br>SimpleRouter::range_type SimpleRouter::parse_ip_seg(string&amp; seg)<br>{<br> if(seg == "*")<br> {<br> return make_pair(min_num, max_num);<br> }<br> else<br> {<br> string::size_type dash_pos = seg.find_first_of('-');<br><br> num_type start, end;<br> if(dash_pos == string::npos)<br> {<br> stringstream(seg) &gt;&gt; start; <br> end = start;<br> }<br> else<br> {<br> stringstream(seg.substr(0, dash_pos)) &gt;&gt; start;<br> stringstream(seg.substr(++dash_pos)) &gt;&gt; end;<br> }<br><br> return make_pair(start, end);<br> } <br>}<br><br>SimpleRouter::ip_type SimpleRouter::parse_ip(const string&amp; ip)<br>{<br> ip_type ret;<br><br> // break string ip into ip &amp; port<br> string::size_type end_ip, start_port;<br><br> end_ip = ip.find_first_of(' ');<br> start_port = (end_ip == string::npos) ? string::npos : end_ip + 1;<br><br> // parse the 4 segment of ip<br> string::size_type start_seg = 0, end_seg;<br> for(int i = 0; i {<br> end_seg = (i == 3) ? end_ip : ip.find_first_of('.', start_seg);<br> ret.push_back(parse_ip_seg(ip.substr(start_seg, end_seg - start_seg)));<br> start_seg = end_seg + 1;<br> }<br><br> // parse port(optional)<br> if(start_port != string::npos)<br> ret.push_back(parse_ip_seg(ip.substr(start_port)));<br><br> return ret;<br>}<br><br>//===================== For debug ======================<br>void SimpleRouter::print_ip(const ip_type&amp; ip)<br>{<br> cout }<br><br>void SimpleRouter::print_table()<br>{<br> rule_table_type::iterator rule_iter = rule_table.begin();<br> forward_table_type::iterator fwd_iter = forward_table.begin();<br><br> for(; rule_iter != rule_table.end(); ++rule_iter, ++fwd_iter)<br> {<br> cout first <br> print_ip(rule_iter-&gt;second);<br> if(!fwd_iter-&gt;empty())<br> {<br> cout print_ip(*fwd_iter);<br> }<br><br> cout }<br>}<br><br>//========================== Test ===========================<br>#include <iostream><br>#include <algorithm><br><br>template <class t><br>struct ArraySize<br>{};<br><br>template <class t int d><br>struct ArraySize<t><br>{<br> static const int value = D;<br>};<br><br>template <class ary><br>void InitWith(vector<string>&amp; vect, const ARY&amp; ary)<br>{<br> int size = ArraySize<ary>::value;<br><br> vect.reserve(size);<br> vect.insert(vect.begin(), ary, ary + size); <br>}<br><br>int main()<br>{<br> string rule_ary[] =<br> {<br> "REJECT *.20-252.114-157.36-91 13171-54085",<br> "ACCEPT *.*.73-180.* *",<br> "FORWARD 55.63.173.239 * 168.154.33.25",<br> "REJECT *.72-73.*.48-191 *",<br> "REJECT 20.51.*.* 4579",<br> "ACCEPT 70-166.*.*.86-182 *",<br> "REJECT 88-190.*.119-157.* 3316-27844",<br> "FORWARD *.52-221.134-250.66-207 * 116.94.120.82"<br> };<br><br> string packet_ary[] =<br> {<br> "203.11.104.45 44072",<br> "154.92.128.87 30085",<br> "20.51.68.55 4579",<br> "177.73.138.69 14319",<br> "112.65.145.82 26287",<br> "55.63.173.239 45899"<br> };<br><br> vector<string> rules, packets;<br> InitWith(rules, rule_ary);<br> InitWith(packets, packet_ary);<br><br> SimpleRouter router;<br> vector<string> ret = router.route(rules, packets);<br><br> for(vector<string>::iterator i = ret.begin(); i != ret.end(); ++i)<br> cout <br> //============ debug =============<br> cout router.print_table();<br> //================================<br>}<br><br><span style="color: rgb(0, 0, 0);">=================================================================================<br>cl /EHsc SimpleRouter.cpp<br><br>SimpleRouter<br><br>OUTPUT:<br><br><span style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">ACCEPT</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">ACCEPT</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">REJECT</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">177.73.138.69:14319</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">112.65.145.82:26287</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">55.63.173.239:45899</span><br style="color: rgb(51, 51, 51);"><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">Rule table, with forwards:</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">REJECT *.20-252.114-157.36-91 13171-54085</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">ACCEPT *.*.73-180.* *</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">FORWARD 55.63.173.239 * 168.154.33.25</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">REJECT *.72-73.*.48-191 *</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">REJECT 20.51.*.* 4579</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">ACCEPT 70-166.*.*.86-182 *</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">REJECT 88-190.*.119-157.* 3316-27844</span><br style="color: rgb(51, 51, 51);"><span style="color: rgb(51, 51, 51);">FORWARD *.52-221.134-250.66-207 * 116.94.120.82</span><br><br></span></span></string></string></string></ary></string></class></t></class></class></algorithm></iostream></string></string></string></string></string></string></string></string></num_type></string></string></string></rule_type></string></ip_type></range_type></num_type></sstream></iostream></string></vector>


分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics