# # patch "ChangeLog" # from [746912cbb100ebc57364b0e9c8d3785cb3cc5f7d] # to [c472ec862675aabab5b00c7a463564a22747966c] # # patch "netcmd.cc" # from [75a0d51313f112ec54f83d29eca1d1077d2547bb] # to [38e6b3a85549ed7c7e5f109623d9ea1b802fc340] # # patch "netcmd.hh" # from [8bea78d5e3429c65cc158c90450a7473528ceb07] # to [87007edfa58287e177df2f3246b28eaa5c5f6146] # # patch "netsync.cc" # from [5a4a894840cdd806535dd34121a150ea8d7a0870] # to [f29b8cf04f7f4ef176165d31cd446c359233007a] # ======================================================================== --- ChangeLog 746912cbb100ebc57364b0e9c8d3785cb3cc5f7d +++ ChangeLog c472ec862675aabab5b00c7a463564a22747966c @@ -1,3 +1,12 @@ +2005-09-16 Timothy Brownawell + + * netcmd.{cc,hh}, netsync.cc: new netcmd types: usher_cmd and + usher_reply_cmd. They are not included in the HMAC, and do not + occur during normal communication. Purpose: running multiple servers + from the same port. This allows a special server to ask for the + client's include pattern, and then forward the connection to a real + monotone server. + 2005-09-15 Timothy Brownawell * app_state.{cc,hh}: restrictions now understand --exclude ======================================================================== --- netcmd.cc 75a0d51313f112ec54f83d29eca1d1077d2547bb +++ netcmd.cc 38e6b3a85549ed7c7e5f109623d9ea1b802fc340 @@ -62,7 +62,8 @@ cmd_code == other.cmd_code && payload == other.payload; } - + +// note: usher_reply_cmd does not get included in the hmac. void netcmd::write(string & out, chained_hmac & hmac) const { @@ -71,11 +72,15 @@ out += static_cast(cmd_code); insert_variable_length_string(payload, out); - string digest = hmac.process(out, oldlen); - I(hmac.hmac_length == constants::netsync_hmac_value_length_in_bytes); - out.append(digest); + if (cmd_code != usher_reply_cmd) + { + string digest = hmac.process(out, oldlen); + I(hmac.hmac_length == constants::netsync_hmac_value_length_in_bytes); + out.append(digest); + } } +// note: usher_cmd does not get included in the hmac. bool netcmd::read(string_queue & inbuf, chained_hmac & hmac) { @@ -107,6 +112,7 @@ case static_cast(data_cmd): case static_cast(delta_cmd): case static_cast(nonexistant_cmd): + case static_cast(usher_cmd): cmd_code = static_cast(cmd_byte); break; default: @@ -124,21 +130,30 @@ throw bad_decode(F("oversized payload of '%d' bytes") % payload_len); // there might not be enough data yet in the input buffer - if (inbuf.size() < pos + payload_len + constants::netsync_hmac_value_length_in_bytes) + unsigned int minsize; + if (cmd_code == usher_cmd) + minsize = pos + payload_len; + else + minsize = pos + payload_len + constants::netsync_hmac_value_length_in_bytes; + if (inbuf.size() < minsize) { return false; } // grab it before the data gets munged I(hmac.hmac_length == constants::netsync_hmac_value_length_in_bytes); - string digest = hmac.process(inbuf, 0, pos + payload_len); + string digest; + if (cmd_code != usher_cmd) + digest = hmac.process(inbuf, 0, pos + payload_len); payload = extract_substring(inbuf, pos, payload_len, "netcmd payload"); // they might have given us bogus data - string cmd_digest = extract_substring(inbuf, pos, - constants::netsync_hmac_value_length_in_bytes, - "netcmd HMAC"); + string cmd_digest; + if (cmd_code != usher_cmd) + cmd_digest = extract_substring(inbuf, pos, + constants::netsync_hmac_value_length_in_bytes, + "netcmd HMAC"); inbuf.pop_front(pos); if (cmd_digest != digest) throw bad_decode(F("bad HMAC checksum (got %s, wanted %s)\n" @@ -544,7 +559,25 @@ payload += item(); } +void +netcmd::read_usher_cmd(utf8 & greeting) const +{ + size_t pos = 0; + std::string str; + extract_variable_length_string(payload, str, pos, "error netcmd, message"); + greeting = utf8(str); + assert_end_of_buffer(payload, pos, "error netcmd payload"); +} +void +netcmd::write_usher_reply_cmd(utf8 const & pattern) +{ + cmd_code = usher_reply_cmd; + payload.clear(); + insert_variable_length_string(pattern(), payload); +} + + #ifdef BUILD_UNIT_TESTS #include "unit_tests.hh" ======================================================================== --- netcmd.hh 8bea78d5e3429c65cc158c90450a7473528ceb07 +++ netcmd.hh 87007edfa58287e177df2f3246b28eaa5c5f6146 @@ -44,7 +44,16 @@ send_delta_cmd = 9, data_cmd = 10, delta_cmd = 11, - nonexistant_cmd = 12 + nonexistant_cmd = 12, + + // usher commands + // usher_cmd is sent by a server farm (or anyone else who wants to serve + // from multiple databases over the same port), and the reply (containing + // the client's include pattern) is used to choose a server to forward the + // connection to. + // usher_cmd is never sent by the monotone server itself. + usher_cmd = 100, + usher_reply_cmd = 101 } netcmd_code; @@ -158,6 +167,9 @@ void write_nonexistant_cmd(netcmd_item_type type, id const & item); + void read_usher_cmd(utf8 & greeting) const; + void write_usher_reply_cmd(utf8 const & pattern); + }; #endif // __NETCMD_HH__ ======================================================================== --- netsync.cc 5a4a894840cdd806535dd34121a150ea8d7a0870 +++ netsync.cc f29b8cf04f7f4ef176165d31cd446c359233007a @@ -442,6 +442,7 @@ delta const & del); bool process_nonexistant_cmd(netcmd_item_type type, id const & item); + bool process_usher_cmd(utf8 const & msg); bool merkle_node_exists(netcmd_item_type type, size_t level, @@ -2976,6 +2977,23 @@ } bool +session::process_usher_cmd(utf8 const & msg) +{ + if (greeting().size()) + { + if (greeting()[0] == '!') + P(F("Received warning from usher: %s") % greeting().substr(1)); + else + L(F("Received greeting from usher: %s") % greeting().substr(1)); + } + netcmd cmdout; + cmdout.write_usher_reply_cmd(our_include_pattern); + write_netcmd_and_try_flush(cmdout); + L(F("Sent reply.")); + return true; +} + +bool session::merkle_node_exists(netcmd_item_type type, size_t level, prefix const & pref) @@ -3193,6 +3211,16 @@ return process_nonexistant_cmd(type, item); } break; + case usher_cmd: + { + utf8 greeting; + cmd.read_usher_cmd(greeting); + return process_usher_cmd(greeting); + } + break; + case usher_reply_cmd: + return false;// should not happen + break; } return false; }