# # # delete "src/err.cc" # # delete "src/err.hh" # # add_file "src/errors.hh" # content [d3fe807ae35194c2fd706ede01cfab783089d930] # # patch "Makefile.am" # from [a056a379689ed17f2721f38b0720e06e180aa92c] # to [443d98abbda1648681d594ad1edb36c009ee84f2] # # patch "src/administrator.cc" # from [33dbec7c90bba3186e1ac8bdc0f330d5e69d051e] # to [9a961611868513551cb1d8fb91c4435002153bcd] # # patch "src/administrator.hh" # from [c756387bfa2f309132080e32998cfc604332dd74] # to [8a76353507cb98bafdedbc4ea056c2f839846408] # # patch "src/buffer.cc" # from [87fb8d5e206256a7465122079a484549c749cb21] # to [04f719ba7d1187823244ec9312b1b25dece12cb5] # # patch "src/channel.cc" # from [51dc47d98c34d4f105a406239e1651b6f02ce8ab] # to [76c07f0088776688f7d9bdb8554ac654488c3c67] # # patch "src/channel.hh" # from [735dbda7d6bff2c88dc92a00471c8ff0819276d8] # to [3a97687c17a68c983872de2792defd9e48028168] # # patch "src/forked_server_manager.cc" # from [930dc65c50248bc2ad2fc8081009f604f12fdaa9] # to [50e353cd2e8f142c5bea4c1b199411d370b56514] # # patch "src/server.cc" # from [e1cba7287a23428df1e096313ce83c40e8d9398c] # to [16bafa0b185392f1f2b66d076ece2eed13420d89] # # patch "src/server_manager.cc" # from [8f6ede9a44390b4248f76df87d714f9b7ed61538] # to [07555ae385e3faf087de1daf3895567ba5f61964] # # patch "src/sock.cc" # from [549572c3603311bf995150a8c702fd7835cd7259] # to [252c7d0ef2a0ff126887a6994708ee177dd855af] # # patch "src/sock.hh" # from [1f15888612ba01181f42b3757f5302fd89ee1b72] # to [0917e736d673fa6d15fcefea8f1f0e16a63b9bc2] # # patch "src/usher.cc" # from [fd473bf1d86f0b93fb0e63d971202d1e758d4686] # to [e1a459e734d3e707038f8f3653a64a248fa7f746] # ============================================================ --- src/administrator.cc 33dbec7c90bba3186e1ac8bdc0f330d5e69d051e +++ src/administrator.cc 9a961611868513551cb1d8fb91c4435002153bcd @@ -8,7 +8,6 @@ // PURPOSE. #include "administrator.hh" -#include "err.hh" #include "io.hh" #include @@ -29,11 +28,6 @@ using boost::lexical_cast; #include using boost::lexical_cast; -#include -#include -#include -#include -#include namespace defaults { @@ -98,8 +92,8 @@ administrator::process(cstate & cs) try { string const &name = manager.lookup_server_name(host, pattern); cs.buf = "OK: " + name + "\n"; - } catch (errstr & e) { - cs.buf = "ERROR: " + e.name + "\n"; + } catch (std::exception & e) { + cs.buf = string("ERROR: ") + e.what() + "\n"; } } else if (cmd == "STATUS") { string srv; @@ -125,9 +119,9 @@ administrator::process(cstate & cs) { oss< >::iterator> del; ============================================================ --- src/administrator.hh c756387bfa2f309132080e32998cfc604332dd74 +++ src/administrator.hh 8a76353507cb98bafdedbc4ea056c2f839846408 @@ -22,8 +22,6 @@ using std::map; #include using std::map; -#include - struct administrator { sock port; ============================================================ --- src/buffer.cc 87fb8d5e206256a7465122079a484549c749cb21 +++ src/buffer.cc 04f719ba7d1187823244ec9312b1b25dece12cb5 @@ -8,8 +8,9 @@ // PURPOSE. #include "buffer.hh" -#include "err.hh" +#include + #include buffer::buffer() @@ -60,7 +61,8 @@ buffer::fixread(int n) void buffer::fixread(int n) { - if (n < 0) throw errstr("negative read\n", 0); + if (n < 0) + throw std::logic_error("negative read"); readpos += n; if (readpos == writepos) { readpos = writepos = 0; @@ -75,6 +77,6 @@ buffer::fixwrite(int n) buffer::fixwrite(int n) { if (n < 0) - throw errstr("negative write\n", 0); + throw std::logic_error("negative write"); writepos += n; } ============================================================ --- src/channel.cc 51dc47d98c34d4f105a406239e1651b6f02ce8ab +++ src/channel.cc 76c07f0088776688f7d9bdb8554ac654488c3c67 @@ -10,7 +10,7 @@ #include "channel.hh" #include "query_client.hh" #include "server_manager.hh" -#include "err.hh" +#include "errors.hh" #include using std::max; @@ -18,38 +18,17 @@ using std::max; #include #include -#include -#include #include using boost::lexical_cast; -string sockname(sock & s) -{ - struct sockaddr_in sai; - socklen_t len = sizeof(sai); - if (getpeername(s, (sockaddr*)&sai, &len) == -1) - return "(error)"; - string out; - char *ip = (char*)&sai.sin_addr.s_addr; - for (int i = 0; i < 4; ++i, ++ip) - { - out += lexical_cast(*ip); - if (i < 3) - out += "."; - } - out += ":"; - out += lexical_cast(ntohs(sai.sin_port)); - return out; -} - channel::channel(sock & c, server_manager &sm) : num(++counter), cli(c), srv(-1), have_routed(false), no_server(false), manager(sm) { - name = sockname(cli); + name = cli.peername(); char * dat; int size; make_packet(greeting, dat, size); @@ -101,27 +80,10 @@ bool } bool -channel::process_selected(fd_set & rd, fd_set & wr, fd_set & er) +channel::process_selected(fd_set & rd, fd_set & wr, fd_set & ) { int c = cli; int s = srv; -/* NB: read oob data before normal reads */ - if (c > 0 && FD_ISSET(c, &er)) { - char d; - errno = 0; - if (recv(c, &d, 1, MSG_OOB) < 1) - cli.close(), c = -1; - else - send(s, &d, 1, MSG_OOB); - } - if (s > 0 && FD_ISSET(s, &er)) { - char d; - errno = 0; - if (recv(s, &d, 1, MSG_OOB) < 1) - srv.close(), s = -1; - else - send(c, &d, 1, MSG_OOB); - } char *p=0; int n; @@ -137,11 +99,11 @@ channel::process_selected(fd_set & rd, f srv = ss; have_routed = true; s = srv; - } catch (errstr & e) { + } catch (std::exception & e) { char * dat; int size; sbuf.getwrite(p, n); - make_packet("!" + e.name, dat, size); + make_packet(string("!") + e.what(), dat, size); if (n < size) size = n; memcpy(p, dat, size); sbuf.fixwrite(size); ============================================================ --- src/channel.hh 735dbda7d6bff2c88dc92a00471c8ff0819276d8 +++ src/channel.hh 3a97687c17a68c983872de2792defd9e48028168 @@ -17,8 +17,6 @@ using boost::shared_ptr; #include using boost::shared_ptr; -#include - struct server_manager; struct channel ============================================================ --- src/err.cc 7717f0db771e798c8199e90c4b4976bcc8449784 +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (C) 2006 Timothy Brownawell -// -// 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 "err.hh" - -#include - -errstr::errstr(std::string const & s) - : name(s), err(0) -{ -} - -errstr::errstr(std::string const & s, int e) - : name(s), err(e) -{ -} - -int tosserr(int ret, std::string const & name) -{ - if (ret == -1) - throw errstr(name, errno); - if (ret < 0) - throw errstr(name, ret); - return ret; -} ============================================================ --- src/err.hh afc918b5b245956aa6c8a1abb0808ab0c0bddfdf +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (C) 2006 Timothy Brownawell -// -// 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 __ERR_HH_ -#define __ERR_HH_ - -#include - -struct errstr -{ - std::string name; - int err; - errstr(std::string const & s); - errstr(std::string const & s, int e); -}; - -int tosserr(int ret, std::string const & name); - -#endif ============================================================ --- src/server.cc e1cba7287a23428df1e096313ce83c40e8d9398c +++ src/server.cc 16bafa0b185392f1f2b66d076ece2eed13420d89 @@ -8,7 +8,8 @@ // PURPOSE. #include "server.hh" -#include "err.hh" + +#include "errors.hh" #include "server_manager.hh" #include @@ -148,24 +149,6 @@ server::get_state() return ss; } -static bool -check_address_empty(string const & addr, int port) -{ - sock s = tosserr(socket(AF_INET, SOCK_STREAM, 0), "socket()"); - int yes = 1; - tosserr(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - &yes, sizeof(yes)), "setsockopt"); - 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); - a.sin_port = htons(port); - a.sin_family = AF_INET; - int r = bind(s, (sockaddr *) &a, sizeof(a)); - s.close(); - return r == 0; -} - static void find_addr(string & addr, int & port) { @@ -189,31 +172,14 @@ find_addr(string & addr, int & port) lexical_cast(curraddr[1]) + "." + lexical_cast(curraddr[2]) + "." + lexical_cast(curraddr[3]); - } while (!check_address_empty(addr, port)); + } while (!sock::is_address_empty(addr, port)); } -static sock -make_outgoing(int port, string const & address) -{ - sock s = tosserr(socket(AF_INET, SOCK_STREAM, 0), "socket()"); - - struct sockaddr_in a; - memset(&a, 0, sizeof(a)); - a.sin_family = AF_INET; - 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); - - tosserr(connect(s, (sockaddr *) &a, sizeof (a)), "connect()"); - return s; -} - sock server::connect(string const &name) { if (!enabled) - throw errstr("This server is disabled."); + throw std::runtime_error("This server is disabled."); map, server_manager::serverdata>::iterator i = manager.servers.find(self()); map > opts = manager.get_opts(); @@ -242,8 +208,8 @@ server::connect(string const &name) } } if (local && pid == -1) - throw errstr("Cannot fork server."); - sock s = make_outgoing(port, addr); + throw std::runtime_error("Cannot fork server."); + sock s = sock::connect(addr, port); ++connection_count; clients.insert(name); return s; ============================================================ --- src/server_manager.cc 8f6ede9a44390b4248f76df87d714f9b7ed61538 +++ src/server_manager.cc 07555ae385e3faf087de1daf3895567ba5f61964 @@ -9,8 +9,8 @@ #include "server_manager.hh" #include "serverlist_reader.hh" -#include "err.hh" +#include "errors.hh" #include using std::max; using std::min; @@ -131,7 +131,7 @@ server_manager::reload_servers() { srv->arguments = ss.local_args; if (ss.local_args.empty()) - throw errstr("'local' server has no arguments. Perhaps they need to be quoted?"); + throw config_error("'local' server has no arguments. Perhaps they need to be quoted?"); } else { @@ -186,7 +186,7 @@ server_manager::find_server(string peern string const &pattern) { if (servers.empty()) - throw errstr("There are no servers defined."); + throw rejected_request("There are no servers defined."); // peername can be a bare host:port, a scheme://host:port, // or a scheme://host:port/name if (peername.find('/') != string::npos) { @@ -200,7 +200,7 @@ server_manager::find_server(string peern if (iter != by_name.end()) return iter->second; else - throw errstr("No server named '" + name + "'"); + throw rejected_request("No server named '" + name + "'"); } else { peername.erase(0, scheme_delim + 3); } @@ -212,19 +212,19 @@ server_manager::find_server(string peern if (srv) return srv; else if (by_pattern.empty()) - throw errstr("No server for hostname '" + peername + "'"); + throw rejected_request("No server for hostname '" + peername + "'"); } if (!pattern.empty() && !by_pattern.empty()) { srv = find_by_prefix(by_pattern, pattern); if (srv) return srv; else if (by_host.empty()) - throw errstr("No server for pattern '" + pattern + "'"); + throw rejected_request("No server for pattern '" + pattern + "'"); } if (srv) return srv; else - throw errstr("No server for host '" + peername + "' or pattern '" + pattern + "'"); + throw rejected_request("No server for host '" + peername + "' or pattern '" + pattern + "'"); } string const & @@ -237,7 +237,7 @@ server_manager::lookup_server_name(strin if (i != servers.end()) return i->second.name; else - throw errstr("server_manager is inconsistent"); + throw std::logic_error("server_manager is inconsistent"); } serversock @@ -246,17 +246,17 @@ server_manager::connect_to_server(string string const &name) { if (!connections_allowed) - throw errstr("All servers are disabled."); + throw rejected_request("All servers are disabled."); shared_ptr srv = find_server(peername, pattern); if (!srv) - throw errstr("usher internal error"); + throw std::logic_error("usher internal error"); sock s = srv->connect(name); serversock ss(s); map, serverdata>::iterator i = servers.find(srv); if (i == servers.end()) - throw errstr("server_manager is inconsistent"); + throw std::logic_error("server_manager is inconsistent"); ss.srv = i->second.name; ++total_connections; if (srv->local && srv->connection_count == 1) @@ -283,7 +283,7 @@ server_manager::get_server_state(string map >::iterator i = by_name.find(name); if (i != by_name.end()) return boost::lexical_cast(i->second->get_state()); - throw errstr("No such server."); + throw rejected_request("No such server."); } set @@ -327,7 +327,7 @@ server_manager::start_stop_server(string i->second->maybekill(); return boost::lexical_cast(i->second->get_state()); } else - throw errstr("No such server."); + throw rejected_request("No such server."); } void @@ -338,7 +338,7 @@ server_manager::kill_server_now(string c i->second->enabled = false; i->second->yeskill(); } else - throw errstr("No such server."); + throw rejected_request("No such server."); } void ============================================================ --- src/sock.cc 549572c3603311bf995150a8c702fd7835cd7259 +++ src/sock.cc 252c7d0ef2a0ff126887a6994708ee177dd855af @@ -9,15 +9,22 @@ #include "sock.hh" #include "buffer.hh" -#include "err.hh" +#include "errors.hh" -#include -#include +// fcntl #include +#include +// accept +#include #include +// sockaddr_in #include +// inet_aton #include -#include +// strerror +#include +// errno +#include using std::set; using std::string; @@ -27,6 +34,147 @@ using boost::lexical_cast; #include using boost::lexical_cast; + +void check_errno(int r, std::string const & msg_prefix) +{ + if (r == -1) + { + char * msg = strerror(errno); + throw platform_error((msg_prefix + ": ") + msg); + } +} + +void set_nonblock(sock fd) +{ + int r = fcntl(fd, F_SETFL, O_NONBLOCK); + check_errno(r, "cannot set non-blocking mode"); +} + +sock sock::accept() +{ + sockaddr_in addr; + socklen_t len = sizeof(addr); + memset(&addr, 0, len); + sock ret = ::accept(*this, (struct sockaddr*)&addr, &len); + check_errno(ret, "cannot accept connection"); + + set_nonblock(ret); + return ret; +} + +void set_reuse(sock s) +{ + int yes = 1; + int r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + check_errno(r, "cannot set REUSEADDR"); +} + +sock create_socket() +{ + sock s = socket(AF_INET, SOCK_STREAM, 0); + check_errno(s, "cannot create socket"); + + return s; +} + +void populate_address(sockaddr_in & addr, std::string const & address, int port) +{ + if (!inet_aton(address.c_str(), (in_addr*)&addr.sin_addr.s_addr)) { + throw platform_error("bad IP address: " + address); + } + addr.sin_port = htons(port); + addr.sin_family = AF_INET; +} + +bool do_bind(sock s, std::string const & address, int port, + bool throw_on_error = true) +{ + sockaddr_in addr; + populate_address(addr, address, port); + int r = bind(s, (sockaddr*)&addr, sizeof(addr)); + if (!throw_on_error) + return r != -1; + check_errno(r, "cannot bind to address"); + return true; +} + +sock listen_nonblocking(std::string const & address, int port) +{ + sock s = create_socket(); + set_reuse(s); + + do_bind(s, address, port); + + std::cerr<<"bound to "<(*ip); + if (i < 3) + out += "."; + } + out += ":"; + out += lexical_cast(ntohs(sai.sin_port)); + return out; +} + +sock sock::connect(std::string const & address, int port) +{ + sock s = create_socket(); + + sockaddr_in addr; + populate_address(addr, address, port); + + // yes, we connect before setting nonblocking mode + // FIXME: really this should be changed for the case of + // remote (unmanaged) servers, so connecting to a remote + // server doesn't stall in the case of network issues. + // (outgoing connections are only made to servers listed + // in the config file) + + int r = ::connect(s, (sockaddr *) &addr, sizeof (addr)); + check_errno(r, "cannot connect"); + + set_nonblock(s); + + return s; +} + +void do_close(int s) +{ + int r; + do { + r = close(s); + } while (r == -1 && errno == EINTR); + check_errno(r, "close failed"); +} + + sock::operator int() { if (!s) @@ -56,7 +204,7 @@ sock::deref() if (s && !(--s[1])) { try { close(); - } catch(errstr & e) { + } catch(std::exception & e) { // if you want it to throw errors, call close manually } delete[] s; @@ -95,13 +243,7 @@ sock::close() { if (!s || s[0] == -1) return; - shutdown(s[0], SHUT_RDWR); - while (::close(s[0]) < 0) { - if (errno == EIO) - throw errstr("close failed", errno); - if (errno != EINTR) - break; - } + do_close(s[0]); s[0]=-1; } @@ -109,9 +251,11 @@ sock::close_all_socks() sock::close_all_socks() { for (set::iterator i = all_socks.begin(); i != all_socks.end(); ++i) { - while (::close((*i)[0]) < 0) - if (errno != EINTR) - break; + try { + do_close((*i)[0]); + } catch (std::exception & e) { + // oh well... + } } } @@ -153,21 +297,7 @@ start(string const & addr, int port) sock start(string const & addr, int port) { - sock s = tosserr(socket(AF_INET, SOCK_STREAM, 0), "socket()"); - tosserr(fcntl(s, F_SETFL, O_NONBLOCK), "fcntl()"); - int yes = 1; - tosserr(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, - &yes, sizeof(yes)), "setsockopt"); - 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); - a.sin_port = htons(port); - a.sin_family = AF_INET; - tosserr(bind(s, (sockaddr *) &a, sizeof(a)), "bind"); - cerr<<"bound to "< #include -#include +#include #include #include #include #include #include -#include -#include #include #include #include -#include #include #include @@ -177,12 +173,7 @@ int main (int argc, char **argv) return 0; if (FD_ISSET(admin.serverport, &rd)) { try { - struct sockaddr_in client_address; - unsigned int l = sizeof(client_address); - memset(&client_address, 0, l); - sock cli = tosserr(accept(admin.serverport, (struct sockaddr *) - &client_address, &l), "accept()"); - tosserr(fcntl(cli, F_SETFL, O_NONBLOCK), "fcntl()"); + sock cli = admin.serverport.accept(); if (manager.get_connections_allowed()) newchan = new channel(cli, manager); else { @@ -192,8 +183,8 @@ int main (int argc, char **argv) write(cli, dat, size); delete[] dat; } - } catch(errstr & s) { - cerr<<"During new connection: "<::iterator> finished; @@ -203,9 +194,9 @@ int main (int argc, char **argv) i->process_selected(rd, wr, er); if (i->is_finished()) finished.push_back(i); - } catch (errstr & e) { + } catch (std::exception & e) { finished.push_back(i); - cerr<<"Error proccessing connection "<num<<": "<num<<": "<::iterator>::iterator i = finished.begin(); ============================================================ --- Makefile.am a056a379689ed17f2721f38b0720e06e180aa92c +++ Makefile.am 443d98abbda1648681d594ad1edb36c009ee84f2 @@ -6,7 +6,7 @@ usher_SOURCES = src/administrator.cc src src/basic_io_serverlist_reader.hh \ src/buffer.cc src/buffer.hh \ src/channel.cc src/channel.hh \ - src/err.cc src/err.hh \ + src/errors.hh \ src/io.cc src/io.hh \ src/query_client.cc src/query_client.hh \ src/server.cc src/server.hh \ ============================================================ --- src/forked_server_manager.cc 930dc65c50248bc2ad2fc8081009f604f12fdaa9 +++ src/forked_server_manager.cc 50e353cd2e8f142c5bea4c1b199411d370b56514 @@ -9,7 +9,6 @@ #include "forked_server_manager.hh" #include "serverlist_reader.hh" -#include "err.hh" #include using std::max; ============================================================ --- /dev/null +++ src/errors.hh d3fe807ae35194c2fd706ede01cfab783089d930 @@ -0,0 +1,27 @@ +#ifndef __ERRORS_HH__ +#define __ERRORS_HH__ + +#include + +// something wrong with the config file +class config_error : public std::runtime_error +{ +public: + config_error(std::string const & w) : runtime_error(w) {} +}; + +// won't or can't fulfill a client request +class rejected_request : public std::runtime_error +{ +public: + rejected_request(std::string const & w) : runtime_error(w) {} +}; + +// failed OS calls +class platform_error : public std::runtime_error +{ +public: + platform_error(std::string const & w) : runtime_error(w) {} +}; + +#endif