# # # patch "README" # from [ac0ae174796b5559a1550aa7ca5f95060dce5fa2] # to [9d6513187b124d5da68f44aaf14830dd4c7cabb0] # # patch "administrator.cc" # from [e6271c8806d89446734f9c93ce08a24a63dfb4a3] # to [eba2e7b41eebc17106d65e4e960f6ff879f11655] # # patch "administrator.hh" # from [2e5057dacae5de057174d7424c7b572ab1c72258] # to [a83c72863bdd49f0d1b0f19c0fe162679a641857] # # patch "channel.cc" # from [c640472ee1249d74eeffcc952e779b2980d555dc] # to [f63e867befc8845dfbf993d6e638916ce5b2bfe6] # # patch "channel.hh" # from [0416de1474ad63b22f1e662a752e93129e3cf9f2] # to [d0f7fc0f54521a2e18a2878eafed1d9a7e441a15] # # patch "server.cc" # from [495a7153e9c9d2d314624c99d8edc5dec5c059db] # to [337aa17cc392eba09b14af9e1a4081ea93fb54c0] # # patch "server.hh" # from [11f759e526dd912e587ab12079cc60752efad741] # to [393e13acf9ef6b89982a19e6feeb6f0588ef95e7] # # patch "server_manager.cc" # from [444fdd0e31957863451d6ca36706879dfce87c9f] # to [5c701d81bee22a2275ea098acd51ad7c5ed6f0fb] # # patch "server_manager.hh" # from [1152c59274ff86e1192341696acfe57a15a146a2] # to [222e58ae1ba6b9ffc74b01cf7eae4a5dfb1cdf03] # # patch "sock.hh" # from [4b136726ab92c01b4378e5bb1c1b56e2a4c11acf] # to [0d39d1441b34e9dfbc506499fa8a5fe7aa964f3f] # # patch "usher.cc" # from [6489eda7b440f9f5228dbd9b9e13c906cbff8b73] # to [152cec4e3210169e12a02cc24cbb86c32ea21db3] # ============================================================ --- README ac0ae174796b5559a1550aa7ca5f95060dce5fa2 +++ README 9d6513187b124d5da68f44aaf14830dd4c7cabb0 @@ -46,6 +46,7 @@ userpass "username" "password" monotone "mtn" "-k" "my_key" listenaddr "0.0.0.0:4691" +automateaddr "127.1.2.3:5541" adminaddr "127.0.0.1:12345" logdir "/var/log/usher/" @@ -83,6 +84,11 @@ Normal address and portnumber on which the usher process should listen for incoming connections Default: listenaddr "0.0.0.0:4691" + +automateaddr "
:" + Normal address and portnumber on which the usher process should listen for + incoming automate connections + Default: none logdir "/path/for/logfiles/" A path (ending in a slash) where logfiles usher produces should be stored. ============================================================ --- administrator.cc e6271c8806d89446734f9c93ce08a24a63dfb4a3 +++ administrator.cc eba2e7b41eebc17106d65e4e960f6ff879f11655 @@ -47,7 +47,7 @@ administrator::administrator(server_mana } administrator::administrator(server_manager &sm, string const &cf) - : port(-1), serverport(-1), manager(sm), conffile(cf) + : port(-1), serverport(-1), au_serverport(-1), manager(sm), conffile(cf) { reload_conffile(); } @@ -201,7 +201,8 @@ void } void -administrator::initialize(string const & ap, string const & sp) +administrator::initialize(string const & ap, string const & sp, + string const & au) { sock oldport(-1); if (!ap.empty()) @@ -231,6 +232,20 @@ administrator::initialize(string const & if (oldport != -1) oldport.close(); } + + if (!au.empty()) + { + oldport = au_serverport; + try { + au_serverport = start(au); + } catch (errstr & s) { + cerr<<"Could not initialize server port: "< > opts = defaults::defaults; admins.clear(); - string ap, sp; + string ap, sp, au; if (serverport == -1) sp = defaults::listenport; for (vector::iterator i = st.items.begin(); @@ -344,6 +359,11 @@ administrator::reload_conffile() if (!i->values.empty()) sp = i->values[0].parsed; } + else if (i->key == "automateaddr") + { + if (!i->values.empty()) + au = i->values[0].parsed; + } else { vector vals; @@ -355,7 +375,7 @@ administrator::reload_conffile() opts[i->key] = vals; } } - initialize(ap, sp); + initialize(ap, sp, au); manager.set_opts(opts); manager.reload_servers(); } ============================================================ --- administrator.hh 2e5057dacae5de057174d7424c7b572ab1c72258 +++ administrator.hh a83c72863bdd49f0d1b0f19c0fe162679a641857 @@ -19,6 +19,7 @@ struct administrator { sock port; sock serverport; + sock au_serverport; struct cstate { bool auth; @@ -32,7 +33,8 @@ struct administrator string conffile; administrator(server_manager &sm, string const &cf); bool process(cstate & cs); - void initialize(string const & ap, string const & sp); + void initialize(string const & ap, string const & sp, + string const & au); void add_to_select(int & maxfd, fd_set & rd, fd_set & wr, fd_set & er); void process_selected(fd_set & rd, fd_set & wr, fd_set & er); void reload_conffile(); ============================================================ --- channel.cc c640472ee1249d74eeffcc952e779b2980d555dc +++ channel.cc f63e867befc8845dfbf993d6e638916ce5b2bfe6 @@ -34,25 +34,28 @@ string sockname(sock & s) return out; } -channel::channel(sock & c, server_manager &sm) +channel::channel(sock & c, server_manager &sm, connection_type k) : num(++counter), - cli(c), srv(-1), - have_routed(false), no_server(false), - manager(sm) + cli(c), srv(-1), + have_routed(false), no_server(false), + manager(sm), + kind(k) { name = sockname(cli); - char * dat; - int size; - make_packet(greeting, dat, size); - char *p; - int n; - sbuf.getwrite(p, n); - if (n < size) size = n; - memcpy(p, dat, size); - sbuf.fixwrite(size); - delete[] dat; + if (kind == netsync_connection) { + char * dat; + int size; + make_packet(greeting, dat, size); + char *p; + int n; + sbuf.getwrite(p, n); + if (n < size) size = n; + memcpy(p, dat, size); + sbuf.fixwrite(size); + delete[] dat; - cli.write_from(sbuf); + cli.write_from(sbuf); + } } channel::~channel() @@ -120,25 +123,57 @@ channel::process_selected(fd_set & rd, f if (c > 0 && FD_ISSET(c, &rd)) { if (!cli.read_to(cbuf)) c = -1; if (!have_routed) { - string reply_srv, reply_pat; - if (extract_reply(cbuf, reply_srv, reply_pat)) { - try { - serversock ss = manager.connect_to_server(reply_srv, reply_pat, - name); - srv = ss; - have_routed = true; - s = srv; - } catch (errstr & e) { - char * dat; - int size; - sbuf.getwrite(p, n); - make_packet("!" + e.name, dat, size); - if (n < size) size = n; - memcpy(p, dat, size); - sbuf.fixwrite(size); - delete[] dat; - no_server = true; + if (kind == netsync_connection) { + string reply_srv, reply_pat; + if (extract_reply(cbuf, reply_srv, reply_pat)) { + try { + serversock ss = manager.connect_to_server(reply_srv, reply_pat, + name, kind); + srv = ss; + have_routed = true; + s = srv; + } catch (errstr & e) { + char * dat; + int size; + sbuf.getwrite(p, n); + make_packet("!" + e.name, dat, size); + if (n < size) size = n; + memcpy(p, dat, size); + sbuf.fixwrite(size); + delete[] dat; + no_server = true; + } } + } else /* kind == automate_connection */ { + if (cbuf.canread()) { + char *dat; + int len; + cbuf.getread(dat, len); + int eol = 0; + while (eol < len && dat[eol] != '\n' && dat[eol] != '\r') { + ++eol; + } + if (eol != len) { + string sname(dat, eol); + cbuf.fixread(eol); + try { + serversock ss = manager.connect_to_server(sname, name, kind); + srv = ss; + have_routed = true; + s = srv; + } catch (errstr & e) { + string err("Cannot connect to server: "); + err += e.name; + err += "\n"; + sbuf.getwrite(p, n); + int size = err.size(); + if (n < size) size = n; + memcpy(p, err.c_str(), size); + sbuf.fixwrite(size); + no_server = true; + } + } + } } } } ============================================================ --- channel.hh 0416de1474ad63b22f1e662a752e93129e3cf9f2 +++ channel.hh d0f7fc0f54521a2e18a2878eafed1d9a7e441a15 @@ -14,6 +14,7 @@ struct channel struct channel { + connection_type kind; static int counter; int num; sock cli; @@ -24,7 +25,7 @@ struct channel buffer sbuf; server_manager &manager; string name; - channel(sock & c, server_manager &sm); + channel(sock & c, server_manager &sm, connection_type k); ~channel(); bool is_finished(); void add_to_select(int & maxfd, fd_set & rd, fd_set & wr, fd_set & er); ============================================================ --- server.cc 495a7153e9c9d2d314624c99d8edc5dec5c059db +++ server.cc 337aa17cc392eba09b14af9e1a4081ea93fb54c0 @@ -91,7 +91,7 @@ server::server(server_manager &sm) } server::server(server_manager &sm) - : enabled(true), local(false), pid(-1), port(0), + : enabled(true), local(false), pid(-1), port(0), au_port(0), connection_count(0), last_conn_time(0), manager(sm) { } @@ -143,7 +143,7 @@ check_address_empty(string const & addr, sockaddr_in a; memset (&a, 0, sizeof (a)); if (!inet_aton(addr.c_str(), (in_addr *) &a.sin_addr.s_addr)) - throw errstr("bad ip address format", 0); + throw errstr("(check_address_empty) bad ip address format", 0); a.sin_port = htons(port); a.sin_family = AF_INET; int r = bind(s, (sockaddr *) &a, sizeof(a)); @@ -188,14 +188,14 @@ make_outgoing(int port, string const & a a.sin_port = htons(port); if (!inet_aton(address.c_str(), (in_addr *) &a.sin_addr.s_addr)) - throw errstr("bad ip address format", 0); + throw errstr(string("(make outgoing) bad ip address format <") + address + ">", 0); tosserr(connect(s, (sockaddr *) &a, sizeof (a)), "connect()"); return s; } sock -server::connect(string const &name) +server::connect(string const &name, connection_type kind) { if (!enabled) throw errstr("This server is disabled."); @@ -217,9 +217,14 @@ server::connect(string const &name) for (int i = 0; i < 3 && pid == -1; ++i) { if (i > 0 || port == 0) find_addr(addr, port); + if (i > 0 || au_port == 0) + find_addr(au_addr, au_port); vector args = opts["monotone"]; args.push_back("serve"); - args.push_back("--bind=" + addr + ":" + lexical_cast(port)); + args.push_back("--bind=" + addr + ":" + + lexical_cast(port)); + args.push_back("--bind-automate=" + au_addr + ":" + + lexical_cast(au_port)); for (vector::iterator j = arguments.begin(); j != arguments.end(); ++j) args.push_back(*j); @@ -228,7 +233,12 @@ server::connect(string const &name) } if (pid == -1) throw errstr("Cannot fork server."); - sock s = make_outgoing(port, addr); + sock s(-1); + if (kind == netsync_connection) { + s = make_outgoing(port, addr); + } else { + s = make_outgoing(au_port, au_addr); + } ++connection_count; clients.insert(name); return s; @@ -326,10 +336,10 @@ int fork_server(string const &logfile, v exit(6); } else { close(err[1]); - char head[256]; + char head[1024]; int got = 0; int r = 0, w = 0; - bool line = false; + int lines = 0; // the first line output on the server's stderr will be either // "mtn: beginning service on : " or // "mtn: network error: bind(2) error: Address already in use" @@ -339,21 +349,27 @@ int fork_server(string const &logfile, v // because read() doesn't block on EOF. do { usleep(10*1000); - r = read(err[0], head + got, 256 - got); + r = read(err[0], head + got, sizeof(head) - got); if (r) cerr<<"Read '"< 0) { - for (int i = 0; i < r && !line; ++i) + for (int i = 0; i < r && lines < 2; ++i) if (head[got+i] == '\n') - line = true; + ++lines; got += r; } w = waitpid(pid, 0, WNOHANG); - } while((!w || r > 0) && !line && got < 256); + } while((!w || r > 0) && lines < 2 && got < sizeof(head)); head[got] = 0; close(err[0]); - if (string(head).find("beginning service") != string::npos) - return pid; + string h(head); + string beginning("beginning service"); + int found = h.find(beginning); + if (found != string::npos) { + found = h.find(beginning, found + beginning.size()); + if (found != string::npos) + return pid; + } kill(pid, SIGKILL); int status; do {r = waitpid(pid, &status, 0);} while (r==-1 && errno == EINTR); ============================================================ --- server.hh 11f759e526dd912e587ab12079cc60752efad741 +++ server.hh 393e13acf9ef6b89982a19e6feeb6f0588ef95e7 @@ -35,8 +35,13 @@ struct server bool local; int pid; vector arguments; + string addr; int port; + + string au_addr; + int au_port; + int connection_count; set clients; int last_conn_time; @@ -45,7 +50,7 @@ struct server server(server_manager &sm); ~server(); serverstate get_state(); - sock connect(string const &name); + sock connect(string const &name, connection_type kind); void disconnect(string const &name); void maybekill(); void yeskill(); ============================================================ --- server_manager.cc 444fdd0e31957863451d6ca36706879dfce87c9f +++ server_manager.cc 5c701d81bee22a2275ea098acd51ad7c5ed6f0fb @@ -183,7 +183,8 @@ server_manager::connect_to_server(string serversock server_manager::connect_to_server(string const &host, string const &pattern, - string const &name) + string const &name, + connection_type kind) { if (!connections_allowed) throw errstr("All servers are disabled."); @@ -203,7 +204,7 @@ server_manager::connect_to_server(string } if (srv) { - sock s = srv->connect(name); + sock s = srv->connect(name, kind); serversock ss(s); map, serverdata>::iterator i = servers.find(srv); if (i == servers.end()) @@ -220,6 +221,41 @@ server_manager::connect_to_server(string throw errstr("Could not find a monotone instance for the pattern '" + pattern + "', perhaps make it less generic?."); } } + +serversock +server_manager::connect_to_server(string const &srvname, + string const &cliname, + connection_type kind) +{ + if (!connections_allowed) + throw errstr("All servers are disabled."); + + shared_ptr srv; + map >::iterator i; + i = by_name.find(srvname); + if (i != by_name.end()) + srv = i->second; + + if (srv) + { + sock s = srv->connect(cliname, kind); + serversock ss(s); + map, serverdata>::iterator i = servers.find(srv); + if (i == servers.end()) + throw errstr("server_manager is inconsistent"); + ss.srv = i->second.name; + ++total_connections; + if (srv->local && srv->connection_count == 1) + { + live.insert(srv); + } + return ss; + } + else { + throw errstr("Could not find a monotone instance named '" + srvname + "'."); + } +} + void server_manager::disconnect_from_server(serversock const &s, string const &name) ============================================================ --- server_manager.hh 1152c59274ff86e1192341696acfe57a15a146a2 +++ server_manager.hh 222e58ae1ba6b9ffc74b01cf7eae4a5dfb1cdf03 @@ -70,8 +70,13 @@ public: void allow_connections(bool allow=true); string start_stop_server(string const &srv, bool start); void reload_servers(); - serversock connect_to_server(string const &host, string const &pattern, - string const &name); + serversock connect_to_server(string const &host, + string const &pattern, + string const &name, + connection_type kind); + serversock connect_to_server(string const & srvname, + string const & cliname, + connection_type kind); void disconnect_from_server(serversock const &s, string const &name); string get_server_state(string const &name); ============================================================ --- sock.hh 4b136726ab92c01b4378e5bb1c1b56e2a4c11acf +++ sock.hh 0d39d1441b34e9dfbc506499fa8a5fe7aa964f3f @@ -6,6 +6,8 @@ struct buffer; struct buffer; +enum connection_type { netsync_connection, automate_connection }; + struct sock { int *s; ============================================================ --- usher.cc 6489eda7b440f9f5228dbd9b9e13c906cbff8b73 +++ usher.cc 152cec4e3210169e12a02cc24cbb86c32ea21db3 @@ -130,7 +130,7 @@ int main (int argc, char **argv) while(sigaction(SIGTERM, &sa, &sa_old) == -1 && errno == EINTR); while(sigaction(SIGINT, &sa, &sa_old) == -1 && errno == EINTR); - if (admin.serverport == -1) + if (admin.serverport == -1 || admin.au_serverport == -1) { std::cerr<<"Cannot open port.\n"; exit(1); @@ -146,6 +146,11 @@ int main (int argc, char **argv) FD_ZERO (&er); FD_SET (admin.serverport, &rd); int nfds = admin.serverport; + if (admin.au_serverport != -1) { + FD_SET (admin.au_serverport, &rd); + if (nfds < admin.au_serverport) + nfds = admin.au_serverport; + } channel *newchan = 0; for (std::list::iterator i = channels.begin(); @@ -173,7 +178,7 @@ int main (int argc, char **argv) sock cli = tosserr(accept(admin.serverport, (struct sockaddr *) &client_address, &l), "accept()"); if (manager.get_connections_allowed()) - newchan = new channel(cli, manager); + newchan = new channel(cli, manager, netsync_connection); else { char * dat; int size; @@ -185,6 +190,22 @@ int main (int argc, char **argv) cerr<<"During new connection: "<::iterator> finished; for (std::list::iterator i = channels.begin(); i != channels.end(); ++i) {