# # # delete "network/automate_listener.cc" # # delete "network/automate_listener.hh" # # rename "network/netsync_listener.cc" # to "network/listener.cc" # # rename "network/netsync_listener.hh" # to "network/listener.hh" # # add_file "automate_reader.cc" # content [f647cff8c945367fbf054eb9fd3a14ff738e330b] # # add_file "automate_reader.hh" # content [284ff60073d0e4861ab516408fa82a8f7a295b04] # # patch "Makefile.am" # from [aa109db4ce20ea27d2ae26d5e290132ec90a6d71] # to [e29ee415bc56883dd9c62f15e5e9def9bac5ed60] # # patch "cmd_automate.cc" # from [e69f8931e124a95c59576bb69503012696b41bd1] # to [5b824613dc07803f950b05f32e060cbe50e1a992] # # patch "cmd_netsync.cc" # from [931c0a9755060974d512348749020c453f308c0a] # to [4533379042014dbf02c238a72bbb2be0b1c4c3bc] # # patch "netcmd.cc" # from [2863e7b2aed2d4866ad80cf92f2e08266c3d94eb] # to [f072c3a9f31c0a9b9ed8b8d84ec821c707e1ec4d] # # patch "netcmd.hh" # from [224e57110c5007f2b551d59cf1d108fa26abc37a] # to [f4e7e7874dcfd14ad78d9a9c9d803930d6cc17c8] # # patch "netsync.cc" # from [c527128f45e61964ab7419054f9d24963a1a819e] # to [8fe90f10954441c004634552f77f2861cf4e6df0] # # patch "network/automate_session.cc" # from [5e6e88a11cdcf49ee651351c5d7284755c953f54] # to [f0282ea40425e1f130f900c9bfc16c49cf3303c4] # # patch "network/automate_session.hh" # from [b9eb6d161bfb175f616ef8fd4cdc86b33778e077] # to [3de5d2137e5f57ed0288da858b2ffef1c9dd7bb3] # # patch "network/listener.cc" # from [3f5307dd5310d07c89da689808978710c101858d] # to [bf0b8fe763407336b63901e36a976e98220e3aa9] # # patch "network/listener.hh" # from [5974625ca14d0f63d7bf803bb908a4dd665b0d40] # to [770859fce5cde9d778bd3e03babd933188acdee5] # # patch "network/session.cc" # from [8911d09f563ff70cdefff537034b7c8c371afb32] # to [1994ca2bf271f581a99502da7858864044e5b041] # # patch "network/session.hh" # from [02803a0b67e3e3e93397511cdaee5976defb1196] # to [aa75d92f160cbacefca549ff1c7f5b9a21c3ed50] # # patch "options_list.hh" # from [0f8703c132d9e847766cfbc2f9ce72bc2469ef8f] # to [556f0e2b7f83c5baece9886bcf2ef842ef2fc29e] # ============================================================ --- automate_reader.cc f647cff8c945367fbf054eb9fd3a14ff738e330b +++ automate_reader.cc f647cff8c945367fbf054eb9fd3a14ff738e330b @@ -0,0 +1,138 @@ +// Copyright (C) 2005 and later by various people +// see monotone commit logs for details and authors +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + + +#include "base.hh" +#include "automate_reader.hh" + +#include + +#include "sanity.hh" + +using std::istream; +using std::pair; +using std::streamsize; +using std::string; +using std::vector; + +bool automate_reader::get_string(string & out) +{ + out.clear(); + if (loc == none || loc == eof) + { + return false; + } + size_t size(0); + char c; + read(&c, 1); + if (c == 'e') + { + loc = none; + return false; + } + while(c <= '9' && c >= '0') + { + size = (size*10)+(c-'0'); + read(&c, 1); + } + E(c == ':', origin::user, + F("Bad input to automate stdio: expected ':' after string size")); + char *str = new char[size]; + size_t got = 0; + while(got < size) + { + int n = read(str+got, size-got); + got += n; + } + out = string(str, size); + delete[] str; + L(FL("Got string '%s'") % out); + return true; +} +streamsize automate_reader::read(char *buf, size_t nbytes, bool eof_ok) +{ + streamsize rv; + + rv = in.rdbuf()->sgetn(buf, nbytes); + + E(eof_ok || rv > 0, origin::user, + F("Bad input to automate stdio: unexpected EOF")); + return rv; +} +void automate_reader::go_to_next_item() +{ + if (loc == eof) + return; + string starters("ol"); + string whitespace(" \r\n\t"); + string foo; + while (loc != none) + get_string(foo); + char c('e'); + do + { + if (read(&c, 1, true) == 0) + { + loc = eof; + return; + } + } + while (whitespace.find(c) != string::npos); + switch (c) + { + case 'o': loc = opt; break; + case 'l': loc = cmd; break; + default: + E(false, origin::user, + F("Bad input to automate stdio: unknown start token '%c'") % c); + } +} +automate_reader::automate_reader(istream & is) : in(is), loc(none) +{} +bool automate_reader::get_command(vector > & params, + vector & cmdline) +{ + params.clear(); + cmdline.clear(); + if (loc == none) + go_to_next_item(); + if (loc == eof) + return false; + else if (loc == opt) + { + string key, val; + while(get_string(key) && get_string(val)) + params.push_back(make_pair(key, val)); + go_to_next_item(); + } + E(loc == cmd, origin::user, + F("Bad input to automate stdio: expected '%c' token") % cmd); + string item; + while (get_string(item)) + { + cmdline.push_back(item); + } + E(cmdline.size() > 0, origin::user, + F("Bad input to automate stdio: command name is missing")); + return true; +} +void automate_reader::reset() +{ + loc = none; +} + + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: ============================================================ --- automate_reader.hh 284ff60073d0e4861ab516408fa82a8f7a295b04 +++ automate_reader.hh 284ff60073d0e4861ab516408fa82a8f7a295b04 @@ -0,0 +1,40 @@ +// Copyright (C) 2005 and later by various people +// see monotone commit logs for details and authors +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + + +#ifndef __AUTOMATE_READER_HH__ +#define __AUTOMATE_READER_HH__ + +#include + +class automate_reader +{ + std::istream & in; + enum location {opt, cmd, none, eof}; + location loc; + bool get_string(std::string & out); + std::streamsize read(char *buf, size_t nbytes, bool eof_ok = false); + void go_to_next_item(); +public: + automate_reader(std::istream & is); + bool get_command(std::vector > & params, + std::vector & cmdline); + void reset(); +}; + +#endif + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: ============================================================ --- Makefile.am aa109db4ce20ea27d2ae26d5e290132ec90a6d71 +++ Makefile.am e29ee415bc56883dd9c62f15e5e9def9bac5ed60 @@ -39,6 +39,7 @@ MOST_SOURCES = \ rev_types.hh mtn-sanity.cc mtn-sanity.hh ui.cc ui.hh \ app_state.cc app_state.hh \ automate_ostream.hh \ + automate_reader.hh automate_reader.cc \ botan_pipe_cache.hh \ commands.cc commands.hh $(CMD_SOURCES) \ diff_output.cc diff_output.hh \ @@ -60,11 +61,10 @@ MOST_SOURCES = \ refiner.cc refiner.hh \ enumerator.cc enumerator.hh \ netsync.cc \ - network/automate_listener.hh network/automate_listener.cc \ network/automate_session.hh network/automate_session.cc \ network/listener_base.hh network/listener_base.cc \ network/make_server.hh network/make_server.cc \ - network/netsync_listener.hh network/netsync_listener.cc \ + network/listener.hh network/listener.cc \ network/netsync_session.hh network/netsync_session.cc \ network/reactable.hh network/reactable.cc \ network/reactor.hh network/reactor.cc \ ============================================================ --- cmd_automate.cc e69f8931e124a95c59576bb69503012696b41bd1 +++ cmd_automate.cc 5b824613dc07803f950b05f32e060cbe50e1a992 @@ -15,6 +15,7 @@ #include "cmd.hh" #include "app_state.hh" #include "automate_ostream.hh" +#include "automate_reader.hh" #include "ui.hh" #include "lua.hh" #include "lua_hooks.hh" @@ -136,120 +137,7 @@ CMD_AUTOMATE(interface_version, "", // set length, rather than waiting until we have all of the output. -class automate_reader -{ - istream & in; - enum location {opt, cmd, none, eof}; - location loc; - bool get_string(std::string & out) - { - out.clear(); - if (loc == none || loc == eof) - { - return false; - } - size_t size(0); - char c; - read(&c, 1); - if (c == 'e') - { - loc = none; - return false; - } - while(c <= '9' && c >= '0') - { - size = (size*10)+(c-'0'); - read(&c, 1); - } - E(c == ':', origin::user, - F("Bad input to automate stdio: expected ':' after string size")); - char *str = new char[size]; - size_t got = 0; - while(got < size) - { - int n = read(str+got, size-got); - got += n; - } - out = std::string(str, size); - delete[] str; - L(FL("Got string '%s'") % out); - return true; - } - std::streamsize read(char *buf, size_t nbytes, bool eof_ok = false) - { - std::streamsize rv; - rv = in.rdbuf()->sgetn(buf, nbytes); - - E(eof_ok || rv > 0, origin::user, - F("Bad input to automate stdio: unexpected EOF")); - return rv; - } - void go_to_next_item() - { - if (loc == eof) - return; - string starters("ol"); - string whitespace(" \r\n\t"); - string foo; - while (loc != none) - get_string(foo); - char c('e'); - do - { - if (read(&c, 1, true) == 0) - { - loc = eof; - return; - } - } - while (whitespace.find(c) != std::string::npos); - switch (c) - { - case 'o': loc = opt; break; - case 'l': loc = cmd; break; - default: - E(false, origin::user, - F("Bad input to automate stdio: unknown start token '%c'") % c); - } - } -public: - automate_reader(istream & is) : in(is), loc(none) - {} - bool get_command(vector > & params, - vector & cmdline) - { - params.clear(); - cmdline.clear(); - if (loc == none) - go_to_next_item(); - if (loc == eof) - return false; - else if (loc == opt) - { - string key, val; - while(get_string(key) && get_string(val)) - params.push_back(make_pair(key, val)); - go_to_next_item(); - } - E(loc == cmd, origin::user, - F("Bad input to automate stdio: expected '%c' token") % cmd); - string item; - while (get_string(item)) - { - cmdline.push_back(item); - } - E(cmdline.size() > 0, origin::user, - F("Bad input to automate stdio: command name is missing")); - return true; - } - void reset() - { - loc = none; - } -}; - - CMD_AUTOMATE(stdio, "", N_("Automates several commands in one run"), "", ============================================================ --- cmd_netsync.cc 931c0a9755060974d512348749020c453f308c0a +++ cmd_netsync.cc 4533379042014dbf02c238a72bbb2be0b1c4c3bc @@ -195,6 +195,8 @@ build_client_connection_info(options & o { find_key(opts, db, keys, lua, project, info, need_key); } + + info.client.connection_type = netsync_connection_info::netsync_connection; } static void @@ -227,6 +229,42 @@ extract_client_connection_info(options & need_key); } +CMD_AUTOMATE(remote_stdio, + N_("[ADDRESS[:PORTNUMBER]"), + N_("Opens an 'automate stdio' connection to a remote server"), + "", + options::opts::max_netsync_version | + options::opts::min_netsync_version) +{ + if (args.size() != 1) + throw usage(execid); + + database db(app); + key_store keys(app); + project_t project(db); + + netsync_connection_info info; + info.client.unparsed = idx(args, 0); + parse_uri(info.client.unparsed(), info.client.uri, origin::user); + + info.client.use_argv = + app.lua.hook_get_netsync_connect_command(info.client.uri, + info.client.include_pattern, + info.client.exclude_pattern, + global_sanity.debug_p(), + info.client.argv); + app.opts.use_transport_auth = app.lua.hook_use_transport_auth(info.client.uri); + if (app.opts.use_transport_auth) + { + find_key(app.opts, db, keys, app.lua, project, info, true); + } + + info.client.connection_type = netsync_connection_info::automate_connection; + + run_netsync_protocol(app, app.opts, app.lua, project, keys, + client_voice, source_and_sink_role, info); +} + CMD(push, "push", "", CMD_REF(network), N_("[ADDRESS[:PORTNUMBER] [PATTERN ...]]"), N_("Pushes branches to a netsync server"), @@ -527,8 +565,7 @@ CMD_NO_WORKSPACE(serve, "serve", "", CMD options::opts::max_netsync_version | options::opts::min_netsync_version | options::opts::bind | options::opts::pidfile | - options::opts::bind_stdio | options::opts::no_transport_auth | - options::opts::bind_automate_uris) + options::opts::bind_stdio | options::opts::no_transport_auth) { if (!args.empty()) throw usage(execid); ============================================================ --- netcmd.cc 2863e7b2aed2d4866ad80cf92f2e08266c3d94eb +++ netcmd.cc f072c3a9f31c0a9b9ed8b8d84ec821c707e1ec4d @@ -194,8 +194,8 @@ netcmd::read(u8 min_version, u8 max_vers { throw bad_decode(F("bad HMAC checksum (got %s, wanted %s)\n" "this suggests data was corrupted in transit") - % cmd_digest - % digest); + % encode_hexenc(cmd_digest, origin::network) + % encode_hexenc(digest, origin::network)); } L(FL("read packet with code %d and version %d") @@ -565,7 +565,7 @@ netcmd::read_automate_cmd(key_id & clien netcmd::read_automate_cmd(key_id & client, id & nonce1, rsa_oaep_sha_data & hmac_key_encrypted, - rsa_sha1_signature & signature) + rsa_sha1_signature & signature) const { size_t pos = 0; client = key_id(extract_substring(payload, pos, @@ -611,7 +611,7 @@ netcmd::read_automate_command_cmd(vector void netcmd::read_automate_command_cmd(vector & args, - vector > & opts) + vector > & opts) const { size_t pos = 0; { @@ -670,7 +670,7 @@ netcmd::read_automate_packet_cmd(int & c netcmd::read_automate_packet_cmd(int & command_num, int & err_code, bool & last, - string & packet_data) + string & packet_data) const { size_t pos = 0; ============================================================ --- netcmd.hh 224e57110c5007f2b551d59cf1d108fa26abc37a +++ netcmd.hh f4e7e7874dcfd14ad78d9a9c9d803930d6cc17c8 @@ -202,19 +202,19 @@ public: void read_automate_cmd(key_id & client, id & nonce1, rsa_oaep_sha_data & hmac_key_encrypted, - rsa_sha1_signature & signature); + rsa_sha1_signature & signature) const; void write_automate_cmd(key_id const & client, id const & nonce1, rsa_oaep_sha_data & hmac_key_encrypted, rsa_sha1_signature & signature); void read_automate_command_cmd(std::vector & args, - std::vector > & opts); + std::vector > & opts) const; void write_automate_command_cmd(std::vector const & args, std::vector > const & opts); void read_automate_packet_cmd(int & command_num, int & err_code, bool & last, - std::string & packet_data); + std::string & packet_data) const; void write_automate_packet_cmd(int command_num, int err_code, bool last, @@ -233,6 +233,11 @@ struct netsync_connection_info { std::list addrs; } server; + enum conn_type + { + netsync_connection, + automate_connection + }; struct { globish include_pattern; @@ -241,6 +246,7 @@ struct netsync_connection_info utf8 unparsed; std::vector argv; bool use_argv; + conn_type connection_type; } client; }; ============================================================ --- netsync.cc c527128f45e61964ab7419054f9d24963a1a819e +++ netsync.cc 8fe90f10954441c004634552f77f2861cf4e6df0 @@ -18,8 +18,8 @@ #include "app_state.hh" #include "database.hh" #include "lua.hh" -#include "network/automate_listener.hh" -#include "network/netsync_listener.hh" +#include "network/automate_session.hh" +#include "network/listener.hh" #include "network/netsync_session.hh" #include "network/reactor.hh" #include "network/session.hh" @@ -93,8 +93,7 @@ static void } static void -call_server(options & opts, - lua_hooks & lua, +call_server(app_state & app, project_t & project, key_store & keys, protocol_role role, @@ -109,7 +108,7 @@ call_server(options & opts, P(F("connecting to %s") % info.client.unparsed); shared_ptr server - = build_stream_to_server(opts, lua, + = build_stream_to_server(app.opts, app.lua, info, constants::netsync_default_port, timeout); @@ -119,14 +118,23 @@ call_server(options & opts, Netxx::SockOpt socket_options(server->get_socketfd(), false); socket_options.set_non_blocking(); - shared_ptr sess(new session(opts, lua, project, keys, + shared_ptr sess(new session(app, project, keys, client_voice, info.client.unparsed(), server)); - shared_ptr wrapped(new netsync_session(sess.get(), - opts, lua, project, - keys, role, - info.client.include_pattern, - info.client.exclude_pattern)); + shared_ptr wrapped; + switch (info.client.connection_type) + { + case netsync_connection_info::netsync_connection: + wrapped.reset(new netsync_session(sess.get(), + app.opts, app.lua, project, + keys, role, + info.client.include_pattern, + info.client.exclude_pattern)); + break; + case netsync_connection_info::automate_connection: + wrapped.reset(new automate_session(app, sess.get())); + break; + } sess->set_inner(wrapped); reactor react; @@ -187,8 +195,7 @@ static shared_ptr } static shared_ptr -session_from_server_sync_item(options & opts, - lua_hooks & lua, +session_from_server_sync_item(app_state & app, project_t & project, key_store & keys, server_initiated_sync_request const & request) @@ -205,7 +212,7 @@ session_from_server_sync_item(options & { P(F("connecting to %s") % info.client.unparsed); shared_ptr server - = build_stream_to_server(opts, lua, + = build_stream_to_server(app.opts, app.lua, info, constants::netsync_default_port, Netxx::Timeout(constants::netsync_timeout_seconds)); @@ -223,12 +230,12 @@ session_from_server_sync_item(options & role = sink_role; shared_ptr - sess(new session(opts, lua, project, keys, + sess(new session(app, project, keys, client_voice, info.client.unparsed(), server)); shared_ptr wrapped(new netsync_session(sess.get(), - opts, lua, project, + app.opts, app.lua, project, keys, role, info.client.include_pattern, info.client.exclude_pattern, @@ -261,19 +268,11 @@ serve_connections(app_state & app, shared_ptr guard(new transaction_guard(project.db)); reactor react; - shared_ptr listen(new listener(opts, lua, project, keys, + shared_ptr listen(new listener(app, project, keys, react, role, addresses, guard, use_ipv6)); react.add(listen, *guard); - if (!app.opts.bind_automate_uris.empty()) - { - shared_ptr al(new automate_listener(app, guard, - react, use_ipv6)); - react.add(al, *guard); - } - - while (true) { if (!guard) @@ -289,7 +288,7 @@ serve_connections(app_state & app, = server_initiated_sync_requests.front(); server_initiated_sync_requests.pop_front(); shared_ptr sess - = session_from_server_sync_item(opts, lua, project, keys, + = session_from_server_sync_item(app, project, keys, request); if (sess) @@ -368,7 +367,7 @@ run_netsync_protocol(app_state & app, shared_ptr str(new Netxx::PipeStream(0,1)); shared_ptr - sess(new session(opts, lua, project, keys, + sess(new session(app, project, keys, server_voice, "stdio", str)); serve_single_connection(project, sess); @@ -380,7 +379,7 @@ run_netsync_protocol(app_state & app, else { I(voice == client_voice); - call_server(opts, lua, project, keys, + call_server(app, project, keys, role, info); } } ============================================================ --- network/automate_session.cc 5e6e88a11cdcf49ee651351c5d7284755c953f54 +++ network/automate_session.cc f0282ea40425e1f130f900c9bfc16c49cf3303c4 @@ -11,10 +11,12 @@ #include "network/automate_session.hh" #include "app_state.hh" +#include "automate_reader.hh" #include "work.hh" #include "vocab_cast.hh" using std::make_pair; +using std::ostringstream; using std::pair; using std::set; using std::string; @@ -24,217 +26,195 @@ CMD_FWD_DECL(automate); CMD_FWD_DECL(automate); -bool automate_session::skip_ws(size_t & pos, size_t len) +automate_session::automate_session(app_state & app, + session * owner) : + wrapped_session(owner), + app(app), + command_number(0), + is_done(false) +{ } + +void automate_session::send_command() { - static string whitespace(" \r\n\t"); - while (pos < len && whitespace.find(inbuf[pos]) != string::npos) + // read an automate command on stdin, then package it up and send it + automate_reader ar(std::cin); + vector > read_opts; + vector read_args; + + if (ar.get_command(read_opts, read_args)) { - ++pos; + netcmd cmd_out(get_version()); + cmd_out.write_automate_command_cmd(read_args, read_opts); + write_netcmd(cmd_out); } - if (pos == len) - return false; - return true; -} - -bool automate_session::read_str(size_t & pos, size_t len, string & out) -{ - if (pos >= len) - return false; - if (!skip_ws(pos, len)) - return false; - size_t size = 0; - char c = inbuf[pos++]; - while (pos < len && c <= '9' && c >= '0') + else { - size = (size * 10) + (c - '0'); - c = inbuf[pos++]; + is_done = true; } - if (pos == len && c <= '9' && c >= '0') - return false; - - if (c != ':') - throw bad_decode(F("bad automate stdio input; cannot read string")); - - if (pos + size > len) - return false; - - out = inbuf.substr(pos, size); - pos += size; - return true; } -bool automate_session::read_cmd(Command & cmd) +bool automate_session::have_work() const { - cmd.opts.clear(); - cmd.args.clear(); + return false; +} - size_t len = inbuf.size(); - if (len < 2) - return false; - size_t pos = 0; - if (!skip_ws(pos, len)) - return false; - if (inbuf[pos] == 'o') - { - ++pos; - while (inbuf[pos] != 'e') - { - string opt, val; - if (!read_str(pos, len, opt)) - return false; - if (!read_str(pos, len, val)) - return false; - cmd.opts.push_back(make_pair(opt, val)); - if (!skip_ws(pos, len)) - return false; - if (pos == len) - return false; - }; - ++pos; - } - if (inbuf[pos] == 'l') - { - ++pos; - while (inbuf[pos] != 'e') - { - string arg; - if (!read_str(pos, len, arg)) - return false; - cmd.args.push_back(arg); - if (!skip_ws(pos, len)) - return false; - if (pos == len) - return false; - } - ++pos; - } - else - throw bad_decode(F("bad automate stdio input; cannot find command")); +void automate_session::request_service() +{ + request_automate(); +} - if (cmd.args.empty()) - throw bad_decode(F("bad automate stdio input: empty command")); - inbuf.pop_front(pos); - return true; +void automate_session::accept_service() +{ + send_command(); } -void automate_session::note_bytes_in(int count) +string automate_session::usher_reply_data() const { - protocol_state = working_state; + return string(); } -void automate_session::note_bytes_out(int count) +bool automate_session::finished_working() const { - size_t len = inbuf.size(); - size_t pos = 0; - if (output_empty() && !skip_ws(pos, len)) - { - protocol_state = confirmed_state; - } + return is_done; } -automate_session::automate_session(app_state & app, - protocol_voice voice, - string const & peer_id, - shared_ptr str) : - session_base(voice, peer_id, str), - app(app), armed(false), - os(oss, app.opts.automate_stdio_size) -{ } - -bool automate_session::arm() +void automate_session::prepare_to_confirm(key_identity_info const & remote_key, + bool use_transport_auth) { - if (!armed) - { - if (output_overfull()) - { - return false; - } - armed = read_cmd(cmd); - } - return armed; + // nothing to do } -bool automate_session::do_work(transaction_guard & guard) +bool automate_session::do_work(transaction_guard & guard, + netcmd const * const cmd_in) { - try + if (!cmd_in) + return true; + + switch(cmd_in->get_cmd_code()) { - if (!arm()) - return true; - } - catch (bad_decode & bd) - { - W(F("stdio protocol error processing %s : '%s'") - % peer_id % bd.what); - return false; - } - armed = false; + case automate_command_cmd: + { + vector in_args; + vector > in_opts; + cmd_in->read_automate_command_cmd(in_args, in_opts); + ++command_number; - args_vector args; - for (vector::iterator i = cmd.args.begin(); - i != cmd.args.end(); ++i) - { - args.push_back(arg_type(*i, origin::user)); - } + args_vector args; + for (vector::iterator i = in_args.begin(); + i != in_args.end(); ++i) + { + args.push_back(arg_type(*i, origin::user)); + } - oss.str(string()); + ostringstream oss; + bool have_err = false; + string err; - try - { - options::options_type opts; - opts = options::opts::all_options() - options::opts::globals(); - opts.instantiate(&app.opts).reset(); + try + { + options::options_type opts; + opts = options::opts::all_options() - options::opts::globals(); + opts.instantiate(&app.opts).reset(); - command_id id; - for (args_vector::const_iterator iter = args.begin(); - iter != args.end(); iter++) - id.push_back(typecast_vocab(*iter)); + command_id id; + for (args_vector::const_iterator iter = args.begin(); + iter != args.end(); iter++) + id.push_back(typecast_vocab(*iter)); - set< command_id > matches = - CMD_REF(automate)->complete_command(id); + set< command_id > matches = + CMD_REF(automate)->complete_command(id); - if (matches.empty()) - { - E(false, origin::user, - F("no completions for this command")); - } - else if (matches.size() > 1) - { - E(false, origin::user, - F("multiple completions possible for this command")); - } + if (matches.empty()) + { + E(false, origin::network, + F("no completions for this command")); + } + else if (matches.size() > 1) + { + E(false, origin::network, + F("multiple completions possible for this command")); + } - id = *matches.begin(); + id = *matches.begin(); - I(args.size() >= id.size()); - for (command_id::size_type i = 0; i < id.size(); i++) - args.erase(args.begin()); + I(args.size() >= id.size()); + string cmd_printable; + for (command_id::size_type i = 0; i < id.size(); i++) + { + if (!cmd_printable.empty()) + cmd_printable += " "; + cmd_printable += (*args.begin())(); + args.erase(args.begin()); + } - command const * cmd = CMD_REF(automate)->find_command(id); - I(cmd != NULL); - automate const * acmd = reinterpret_cast< automate const * >(cmd); + L(FL("Executing %s for remote peer %s") + % cmd_printable % get_peer()); - opts = options::opts::globals() | acmd->opts(); + command const * cmd = CMD_REF(automate)->find_command(id); + I(cmd != NULL); + automate const * acmd = reinterpret_cast< automate const * >(cmd); - if (cmd->use_workspace_options()) - { - // Re-read the ws options file, rather than just copying - // the options from the previous apts.opts object, because - // the file may have changed due to user activity. - workspace::check_format(); - workspace::get_options(app.opts); - } + opts = options::opts::globals() | acmd->opts(); - opts.instantiate(&app.opts).from_key_value_pairs(this->cmd.opts); - acmd->exec_from_automate(app, id, args, os); + if (cmd->use_workspace_options()) + { + // Re-read the ws options file, rather than just copying + // the options from the previous apts.opts object, because + // the file may have changed due to user activity. + workspace::check_format(); + workspace::get_options(app.opts); + } + + opts.instantiate(&app.opts).from_key_value_pairs(in_opts); + acmd->exec_from_automate(app, id, args, oss); + } + catch (recoverable_failure & f) + { + have_err = true; + err = f.what(); + } + + netcmd out_cmd(get_version()); + out_cmd.write_automate_packet_cmd(command_number, 0, + !have_err, oss.str()); + write_netcmd(out_cmd); + if (have_err) + { + netcmd err_cmd(get_version()); + err_cmd.write_automate_packet_cmd(command_number, 2, + true, err); + write_netcmd(err_cmd); + } + + return true; + + } + case automate_packet_cmd: + { + int command_num; + int err_code; + bool last; + string packet_data; + cmd_in->read_automate_packet_cmd(command_num, err_code, + last, packet_data); + + std::cout<get_cmd_code()); } - catch (recoverable_failure & f) - { - os.set_err(2); - os << f.what(); - } - os.end_cmd(); - queue_output(oss.str()); - return true; } // Local Variables: ============================================================ --- network/automate_session.hh b9eb6d161bfb175f616ef8fd4cdc86b33778e077 +++ network/automate_session.hh 3de5d2137e5f57ed0288da858b2ffef1c9dd7bb3 @@ -12,36 +12,32 @@ #include "automate_ostream.hh" #include "cmd.hh" -#include "network/session_base.hh" +#include "network/wrapped_session.hh" -class automate_session : public session_base +class automate_session : public wrapped_session { app_state & app; typedef commands::command_id command_id; typedef commands::command command; typedef commands::automate automate; - struct Command - { - std::vector > opts; - std::vector args; - }; - bool skip_ws(size_t & pos, size_t len); - bool read_str(size_t & pos, size_t len, std::string & out); - bool read_cmd(Command & cmd); - bool armed; - Command cmd; + size_t command_number; - void note_bytes_in(int count); - void note_bytes_out(int count); - std::ostringstream oss; - automate_ostream os; + bool is_done; + + void send_command(); public: automate_session(app_state & app, - protocol_voice voice, - std::string const & peer_id, - boost::shared_ptr str); - bool arm(); - bool do_work(transaction_guard & guard); + session * owner); + + bool do_work(transaction_guard & guard, + netcmd const * const in_cmd); + bool have_work() const; + void request_service(); + void accept_service(); + std::string usher_reply_data() const; + bool finished_working() const; + void prepare_to_confirm(key_identity_info const & remote_key, + bool use_transport_auth); }; #endif ============================================================ --- network/netsync_listener.cc 3f5307dd5310d07c89da689808978710c101858d +++ network/listener.cc bf0b8fe763407336b63901e36a976e98220e3aa9 @@ -9,7 +9,7 @@ // PURPOSE. #include "base.hh" -#include "network/netsync_listener.hh" +#include "network/listener.hh" #include "netxx/sockopt.h" #include "netxx/stream.h" @@ -27,8 +27,7 @@ using boost::shared_ptr; using boost::lexical_cast; using boost::shared_ptr; -listener::listener(options & opts, - lua_hooks & lua, +listener::listener(app_state & app, project_t & project, key_store & keys, reactor & react, @@ -37,7 +36,7 @@ listener::listener(options & opts, shared_ptr &guard, bool use_ipv6) : listener_base(shared_ptr()), - opts(opts), lua(lua), project(project), keys(keys), + app(app), project(project), keys(keys), react(react), role(role), timeout(static_cast(constants::netsync_timeout_seconds)), guard(guard), @@ -72,7 +71,7 @@ listener::do_io(Netxx::Probe::ready_type shared_ptr(new Netxx::Stream(client.get_socketfd(), timeout)); - shared_ptr sess(new session(opts, lua, project, keys, + shared_ptr sess(new session(app, project, keys, server_voice, lexical_cast(client), str)); ============================================================ --- network/netsync_listener.hh 5974625ca14d0f63d7bf803bb908a4dd665b0d40 +++ network/listener.hh 770859fce5cde9d778bd3e03babd933188acdee5 @@ -8,8 +8,8 @@ // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. -#ifndef __NETSYNC_LISTENER_HH__ -#define __NETSYNC_LISTENER_HH__ +#ifndef __LISTENER_HH__ +#define __LISTENER_HH__ #include @@ -17,10 +17,7 @@ #include "network/listener_base.hh" #include "vocab.hh" -//#include - -class options; -class lua_hooks; +class app_state; class key_store; class project_t; class reactor; @@ -28,8 +25,7 @@ class listener : public listener_base class listener : public listener_base { - options & opts; - lua_hooks & lua; + app_state & app; project_t & project; key_store & keys; @@ -42,8 +38,7 @@ public: Netxx::Address addr; public: - listener(options & opts, - lua_hooks & lua, + listener(app_state & app, project_t & project, key_store & keys, reactor & react, ============================================================ --- network/session.cc 8911d09f563ff70cdefff537034b7c8c371afb32 +++ network/session.cc 1994ca2bf271f581a99502da7858864044e5b041 @@ -10,10 +10,12 @@ #include "base.hh" #include "network/session.hh" +#include "app_state.hh" #include "key_store.hh" #include "database.hh" #include "keys.hh" #include "lua_hooks.hh" +#include "network/automate_session.hh" #include "network/netsync_session.hh" #include "options.hh" #include "project.hh" @@ -29,16 +31,16 @@ size_t session::session_num = 0; size_t session::session_num = 0; -session::session(options & opts, lua_hooks & lua, project_t & project, +session::session(app_state & app, project_t & project, key_store & keys, protocol_voice voice, std::string const & peer, shared_ptr sock) : session_base(voice, peer, sock), - version(opts.max_netsync_version), - max_version(opts.max_netsync_version), - min_version(opts.min_netsync_version), - use_transport_auth(opts.use_transport_auth), + version(app.opts.max_netsync_version), + max_version(app.opts.max_netsync_version), + min_version(app.opts.min_netsync_version), + use_transport_auth(app.opts.use_transport_auth), signing_key(keys.signing_key), cmd_in(0), armed(false), @@ -52,8 +54,7 @@ session::session(options & opts, lua_hoo completed_hello(false), error_code(0), session_id(++session_num), - opts(opts), - lua(lua), + app(app), project(project), keys(keys), peer(peer) @@ -412,7 +413,7 @@ session::request_netsync(protocol_role r key_identity_info remote_key; remote_key.id = remote_peer_key_id; if (!remote_key.id.inner()().empty()) - project.complete_key_identity(keys, lua, remote_key); + project.complete_key_identity(keys, app.lua, remote_key); wrapped->on_begin(session_id, remote_key); } @@ -420,7 +421,32 @@ session::request_automate() void session::request_automate() { - // TODO + MM(use_transport_auth); + id nonce2(mk_nonce()); + rsa_oaep_sha_data hmac_key_encrypted; + rsa_sha1_signature sig; + if (use_transport_auth) + { + project.db.encrypt_rsa(remote_peer_key_id, nonce2(), hmac_key_encrypted); + + if (signing_key.inner()() != "") + { + keys.make_signature(project.db, signing_key, hello_nonce(), sig); + } + } + + netcmd request(version); + request.write_automate_cmd(signing_key, hello_nonce, + hmac_key_encrypted, sig); + write_netcmd(request); + set_session_key(nonce2()); + + key_identity_info remote_key; + remote_key.id = remote_peer_key_id; + if (!remote_key.id.inner()().empty()) + project.complete_key_identity(keys, app.lua, remote_key); + + wrapped->on_begin(session_id, remote_key); } void @@ -619,8 +645,7 @@ bool session::handle_service_request() { case is_netsync: wrapped.reset(new netsync_session(this, - opts, - lua, + app.opts, app.lua, project, keys, corresponding_role(role), @@ -628,6 +653,7 @@ bool session::handle_service_request() their_exclude)); break; case is_automate: + wrapped.reset(new automate_session(app, this)); break; } @@ -636,7 +662,7 @@ bool session::handle_service_request() { client_identity.id = client_id; if (!client_identity.id.inner()().empty()) - project.complete_key_identity(keys, lua, client_identity); + project.complete_key_identity(keys, app.lua, client_identity); } wrapped->on_begin(session_id, client_identity); ============================================================ --- network/session.hh 02803a0b67e3e3e93397511cdaee5976defb1196 +++ network/session.hh aa75d92f160cbacefca549ff1c7f5b9a21c3ed50 @@ -16,6 +16,7 @@ #include "netcmd.hh" #include "vocab.hh" +class app_state; class key_store; class lua_hooks; class options; @@ -54,8 +55,7 @@ class session : public session_base size_t session_id; static size_t session_num; - options & opts; - lua_hooks & lua; + app_state & app; project_t & project; key_store & keys; std::string peer; @@ -66,7 +66,7 @@ public: bool handle_service_request(); public: - session(options & opts, lua_hooks & lua, project_t & project, + session(app_state & app, project_t & project, key_store & keys, protocol_voice voice, std::string const & peer, ============================================================ --- options_list.hh 0f8703c132d9e847766cfbc2f9ce72bc2469ef8f +++ options_list.hh 556f0e2b7f83c5baece9886bcf2ef842ef2fc29e @@ -119,14 +119,6 @@ OPTION(bind_opts, bind_stdio, false, "st } #endif -OPT(bind_automate_uris, "bind-automate", std::list, , - gettext_noop("serve 'automate stdio' connections on this address")) -#ifdef option_bodies -{ - bind_automate_uris.push_back(utf8(arg, origin::user)); -} -#endif - OPT(max_netsync_version, "max-netsync-version", u8, constants::netcmd_current_protocol_version, gettext_noop("cause monotone to lie about the maximum netsync "