From 28e4ceb2e1b1a1868b5ca62fff79787b17239e2e Mon Sep 17 00:00:00 2001 From: Jan Losinshi Date: Fri, 22 Aug 2008 13:30:32 +0200 Subject: [PATCH] boodt::program_options works, dut there are other todos like fix a little crash on disconnect or do some error handling. --- socket.cxx | 133 ++++++++++++++++++++++++++++++++++++++- socket.hxx | 43 +++++++++++++ xerxes.cxx | 180 +++++++++++++++-------------------------------------- 3 files changed, 225 insertions(+), 131 deletions(-) diff --git a/socket.cxx b/socket.cxx index 7ddcf78..f67d5c6 100644 --- a/socket.cxx +++ b/socket.cxx @@ -7,17 +7,24 @@ */ #include +#include +#include +#include +#include #include "socket.hxx" +#include namespace xerxes { - Socket::Socket(int protocol, + Socket::Socket(int protocol, int type, int domain) - : fd(socket(protocol, type, domain)) + : fd(socket(protocol, type, domain)) { + std::cerr << "new socket" << std::endl; if(fd < 0) { + perror("--"); throw std::runtime_error("could not create socket."); } } @@ -35,6 +42,60 @@ namespace xerxes } } + SocketOption::SocketOption(std::string new_file) + : type(UNIX), file(new_file) + { + } + + SocketOption::SocketOption(std::string new_hostname, std::string new_port) + : type(TCP), hostname(new_hostname), port(new_port) + { + } + + Socket* + SocketOption::gen_socket() + { + if(type == TCP) + { + return new Socket(PF_INET, SOCK_STREAM, 0); + } + else + { + return new Socket(AF_UNIX, SOCK_STREAM, 0); + } + } + + + void validate(boost::any& v, + const std::vector& values, + SocketOption* target_type, int) + { + static boost::regex r("(tcp|unix):(([\\d\\w_-]|\\.|/)+)(:(\\d+))?"); + + using namespace boost::program_options; + using namespace std; + + validators::check_first_occurrence(v); + const std::string& s = validators::get_single_string(values); + + boost::smatch match; + if(regex_match(s, match, r)) + { + if(match[1] == "tcp") + { + v = boost::any(SocketOption(match[2], match[5])); + } + else + { + v = boost::any(SocketOption(match[2])); + } + } + else + { + throw validation_error("invalid value"); + } + } + MysqlData makeData(int len) { @@ -68,6 +129,37 @@ namespace xerxes { return ::connect(socket.fd, serv_addr, addrlen); } + + int + connect_inet(Socket& socket, + SocketOption& opt) + { + addrinfo hints; + addrinfo* res; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + getaddrinfo(opt.hostname.c_str(), opt.port.c_str(), &hints, &res); + int ret = connect(socket, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); + return ret; + } + + int + connect_unix(Socket& socket, + SocketOption& opt) + { + struct sockaddr_un adr; + + memset(&adr, 0, sizeof(adr)); + adr.sun_family = AF_UNIX; + strncpy(adr.sun_path, opt.file.c_str(), sizeof(adr.sun_path)); + return connect(socket, (struct sockaddr *) &adr, SUN_LEN(&adr)); + } int recv(Socket& socket, @@ -111,4 +203,41 @@ namespace xerxes { return ::bind(socket.fd, bind_address, addrlen); } + + int + bind_inet(Socket& socket, + SocketOption& opt) + { + addrinfo hints; + addrinfo* res; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; + + getaddrinfo(opt.hostname.c_str(), opt.port.c_str(), &hints, &res); + + int ret = bind(socket, res->ai_addr, res->ai_addrlen); + + freeaddrinfo(res); + return ret; + } + + + int + bind_unix(Socket& socket, + SocketOption& opt) + { + unlink(opt.file.c_str()); + + struct sockaddr_un adr; + + memset(&adr, 0, sizeof(adr)); + adr.sun_family = AF_UNIX; + strncpy(adr.sun_path, opt.file.c_str(), sizeof(adr.sun_path)); + return bind(socket, (struct sockaddr *) &adr, SUN_LEN(&adr)); + } } diff --git a/socket.hxx b/socket.hxx index a9f95e1..490bde2 100644 --- a/socket.hxx +++ b/socket.hxx @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -41,6 +44,31 @@ namespace xerxes MysqlData makeData(int len); + enum sock_opt_types + { + TCP, + UNIX + }; + + class SocketOption + { + public: + + SocketOption(std::string new_file); + SocketOption(std::string new_hostname, std::string new_port); + + Socket* gen_socket(); + + int type; + std::string file; + std::string hostname; + std::string port; + }; + + void validate(boost::any& v, + const std::vector& values, + SocketOption* target_type, int); + boost::shared_ptr accept(Socket& socket, sockaddr* address, @@ -54,6 +82,14 @@ namespace xerxes sockaddr const* const serv_address, socklen_t address_len); + int + connect_inet(Socket& socket, + SocketOption& opt); + + int + connect_unix(Socket& socket, + SocketOption& opt); + int recv(Socket& socket, MysqlData& data, @@ -70,6 +106,13 @@ namespace xerxes sockaddr const* const bind_address, socklen_t addrlen); + int + bind_inet(Socket& socket, + SocketOption& opt); + + int + bind_unix(Socket& socket, + SocketOption& opt); class SocketErr{}; class ConResetErr: public SocketErr{}; diff --git a/xerxes.cxx b/xerxes.cxx index d246afb..cb5a0c7 100644 --- a/xerxes.cxx +++ b/xerxes.cxx @@ -6,6 +6,10 @@ * Maximilian Marx */ +/** + * TODO : Fix crash on disconnect + * TODO : Do some Error handling + */ #include #include @@ -14,75 +18,8 @@ #include "socket.hxx" #include "epoll.hxx" #include -#include -#include -#include #include -enum sock_opt_types{ - TCP, - UNIX -}; - -class SocketOption { - public: - - SocketOption(std::string new_file) - : type(UNIX), file(new_file) - { - } - SocketOption(std::string new_hostname, std::string new_port) - : type(TCP), hostname(new_hostname), port(new_port) - { - } - - int type; - std::string file; - std::string hostname; - std::string port; -}; - - -void validate(boost::any& v, - const std::vector& values, - SocketOption* target_type, int) -{ - //static boost::regex r("(tcp|unix):([\\d\\w_-/.]+)(:(\\d+))?"); - static boost::regex r("(tcp|unix):(([\\d\\w_-]|\\.|/)+)(:(\\d+))?"); - - using namespace boost::program_options; - using namespace std; - - // Make sure no previous assignment to 'a' was made. - validators::check_first_occurrence(v); - // Extract the first string from 'values'. If there is more than - // one string, it's an error, and exception will be thrown. - const std::string& s = validators::get_single_string(values); - - // Do regex match and convert the interesting part to - // int. - boost::smatch match; - if(regex_match(s, match, r)) - { - cout << "1: " << match[1] << endl; // Type - cout << "2: " << match[2] << endl; // File-/Hostname - cout << "5: " << match[5] << endl; // Port - if(match[1] == "tcp") - { - cout << "TCP" << endl; - v = boost::any(SocketOption(match[2], match[5])); - } - else - { - cout << "UNIX" << endl; - v = boost::any(SocketOption(match[2])); - } - } - else - { - throw validation_error("invalid value"); - } -} @@ -98,60 +35,59 @@ main(int argc, char* argv[]) -// Declare the supported options. -po::options_description desc("Allowed options"); -desc.add_options() + // Declare the supported options. + po::options_description desc("Allowed options"); + desc.add_options() ("help", "produce help message") ("src", po::value(), "Source") ("dst", po::value(), "Destination") -; + ; -po::variables_map vm; -po::store(po::parse_command_line(argc, argv, desc), vm); -po::notify(vm); + po::variables_map vm; + po::store(po::parse_command_line(argc, argv, desc), vm); + po::notify(vm); -if (vm.count("help")) { - cout << desc << "\n"; - return 1; -} + if (vm.count("help")) + { + cout << desc << "\n"; + return 1; + } -if (vm.count("src")) { - SocketOption sock = vm["src"].as(); - if(sock.type == TCP) + + if (vm.count("src")) + { + SocketOption sock = vm["src"].as(); + } + if (vm.count("dst")) + { + SocketOption sock = vm["dst"].as(); + if(sock.type == TCP) + { + cout << "TCP Destination is " << sock.hostname << "," << sock.port << ".\n"; + } + else + { + cout << "UNIX Destination is " << sock.file << ".\n"; + } + } + else { - cout << "TCP Source is " << sock.hostname << "," << sock.port << ".\n"; + cout << "Destination was not set.\n"; + exit(0); } - else - { - cout << "UNIX Source is " << sock.file << ".\n"; - } -} else { - cout << "Source was not set.\n"; -} - - - -exit(0); - - - Socket lstn(PF_INET, SOCK_STREAM, 0); - - addrinfo hints; - addrinfo* res; - - memset(&hints, 0, sizeof(hints)); - - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; - - getaddrinfo("127.0.0.1", "13337", &hints, &res); - - bind(lstn, res->ai_addr, res->ai_addrlen); - - freeaddrinfo(res); + SocketOption src = vm["src"].as(); + Socket &lstn = *(src.gen_socket()); + if(src.type == TCP) + { + cout << "TCP Source is " << src.hostname << "," << src.port << ".\n"; + bind_inet(lstn, src); + } + else + { + cout << "UNIX Source is " << src.file << ".\n"; + bind_unix(lstn, src); + } int ret = listen(lstn, 3); if( ret != 0) @@ -177,23 +113,9 @@ exit(0); if((events[i].data.fd == -1) && (events[i].events & EPOLLIN)) { - //close(accept(lstn, 0, 0)); - //cout << "hollo!" << endl; - boost::shared_ptr target(new Socket(PF_INET, SOCK_STREAM, 0)); - addrinfo hints; - addrinfo* res; - - memset(&hints, 0, sizeof(hints)); - - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; - getaddrinfo("127.0.0.1", "3306", &hints, &res); - //getaddrinfo("127.0.0.1", "25", &hints, &res); - connect(*target, res->ai_addr, res->ai_addrlen); - freeaddrinfo(res); - + SocketOption dst = vm["dst"].as(); + boost::shared_ptr target(dst.gen_socket()); + connect_inet(*target, dst); sockets[target->fd] = target; boost::shared_ptr source(accept(lstn, 0, 0));