From 28a8022e822fc3c1bf8f72ef7df047e68af2907a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Luttringer?= Date: Thu, 17 Jan 2008 03:43:24 +0000 Subject: [PATCH] utilisation de sll => correction du bug sur les connections amelioration de sll avec ajout de getlocalhostname et getremotehostname --- sld/trunk/Makefile.am | 20 +- sld/trunk/TODO | 6 +- sld/trunk/configure.ac | 3 +- sld/trunk/examples/conffile | 2 +- sld/trunk/src/daemon.cc | 416 ++++++++++++------------ sld/trunk/src/daemon.hh | 34 +- sld/trunk/src/options.cc | 6 +- sld/trunk/src/sld.cc | 1 - sld/trunk/src/sld.hh | 30 +- sld/trunk/src/sll/connection.cc | 522 +++++++++++++++++++++++++++++++ sld/trunk/src/sll/connection.hh | 103 ++++++ sld/trunk/src/sll/connection.hxx | 166 ++++++++++ sld/trunk/src/{ => sll}/error.cc | 68 +++- sld/trunk/src/{ => sll}/error.hh | 23 +- sld/trunk/src/sll/slm.hh | 62 ++++ 15 files changed, 1179 insertions(+), 283 deletions(-) create mode 100644 sld/trunk/src/sll/connection.cc create mode 100644 sld/trunk/src/sll/connection.hh create mode 100644 sld/trunk/src/sll/connection.hxx rename sld/trunk/src/{ => sll}/error.cc (57%) rename sld/trunk/src/{ => sll}/error.hh (74%) create mode 100644 sld/trunk/src/sll/slm.hh diff --git a/sld/trunk/Makefile.am b/sld/trunk/Makefile.am index 8288be2..655da95 100644 --- a/sld/trunk/Makefile.am +++ b/sld/trunk/Makefile.am @@ -16,16 +16,22 @@ bin_PROGRAMS= sld -sld_SOURCES= src/sld.hh \ - src/sld.cc \ - src/options.hh \ +sld_SOURCES= src/sld.cc \ src/options.cc \ - src/daemon.hh \ src/daemon.cc \ - src/log.hh \ src/log.cc \ - src/error.hh \ - src/error.cc + src/sll/error.cc \ + src/sll/connection.cc + +noinst_HEADER= src/sld.hh \ + src/options.hh \ + src/daemon.hh \ + src/log.hh \ + src/sll/slm.hh \ + src/sll/error.hh \ + src/sll/connection.hh \ + src/sll/connection.hxx + CLEANFILES= *~ '\#*' .*.swp .*~ diff --git a/sld/trunk/TODO b/sld/trunk/TODO index 922fdf8..4cb353f 100644 --- a/sld/trunk/TODO +++ b/sld/trunk/TODO @@ -1,12 +1,10 @@ IMPROVMENTS: +faire les fonctions recv et flush de connection dans sll remove static magic MAX_LINE_SIZE in sscanf Print start date and stop date in log file effacer les scripts avant de quitter Ajout une fonction qui delete un script ajouter la commande ping/pong +utiliser le gestionnaire d'option generique BUG: -- -echo -e "EXIT\ntoto" |nc -p 18136 -l localhost -when server send data after exit, daemon segfault -- diff --git a/sld/trunk/configure.ac b/sld/trunk/configure.ac index 8472f0a..e9bb891 100644 --- a/sld/trunk/configure.ac +++ b/sld/trunk/configure.ac @@ -24,7 +24,7 @@ AC_INIT([sld],[1.0],[contact@seblu.net],[sld]) AC_CONFIG_AUX_DIR([build]) # Auto Make init -AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip]) +AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip subdir-objects]) # Check platform AC_CANONICAL_HOST @@ -68,6 +68,7 @@ AC_PROG_MAKE_SET # Check for libs AC_CHECK_LIB([ssl], [SSL_library_init],,[AC_MSG_ERROR([Library ssl not found!])]) +AC_CHECK_LIB([pthread], [pthread_create],,[AC_MSG_ERROR([Library pthread not found!])]) # Set efence library AS_IF([test "x$with_efence" = "xyes" ], diff --git a/sld/trunk/examples/conffile b/sld/trunk/examples/conffile index b1385b3..b2fb0a0 100644 --- a/sld/trunk/examples/conffile +++ b/sld/trunk/examples/conffile @@ -4,7 +4,7 @@ # host login # Default = see the result of hostname command -host=trinity +# host=raptor # host password # Default = none diff --git a/sld/trunk/src/daemon.cc b/sld/trunk/src/daemon.cc index 749d68c..9c06857 100644 --- a/sld/trunk/src/daemon.cc +++ b/sld/trunk/src/daemon.cc @@ -16,6 +16,9 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "sld.hh" +#include "daemon.hh" + #include #include #include @@ -35,12 +38,8 @@ #include #include -#include "sld.hh" - SLDaemon *SLDaemon::instance_ = 0; -SLDaemon::SLDaemon() : socket_fs_(0) {} - SLDaemon &SLDaemon::Instance() { if (instance_ == 0) instance_ = new SLDaemon(); @@ -69,63 +68,78 @@ void SLDaemon::check_options() const { } void SLDaemon::run() { - char *line; - if (verbose()) logout << options; check_options(); clean_dir(options.scriptdir); net_connect: try { - connect(); + // run connection + if (verbose()) + logout << "Connecting to " << options.server.c_str() + << " on port " << options.port << "...\n"; + + c_.connect(options.server.c_str(), options.port); + + if (verbose()) + logout << "Connected to " << c_.getremotehostname() << " (" << c_.getremoteip() + << ") on port " << c_.getremoteport() << "...\n"; + + // run auth auth(); + + // parse line while (1) { - line = recvln(); + string line = c_.recvln(); // call right handler try { - if (!strcmp(line, "EXIT\n")) + if (line == "EXIT") cmd_exit(); - else if (!strcmp(line, "VERSION\n")) + else if (!strcmp(line.c_str(), "VERSION\n")) cmd_version(); - else if (!strcmp(line, "STATUS\n")) + else if (!strcmp(line.c_str(), "STATUS\n")) cmd_status(); - else if (!strcmp(line, "LIST\n")) + else if (!strcmp(line.c_str(), "LIST\n")) cmd_list(); - else if (!strcmp(line, "KILLALL\n")) + else if (!strcmp(line.c_str(), "KILLALL\n")) cmd_killall(); - else if (!strcmp(line, "KILL\n")) - cmd_kill(line); - else if (!strncmp(line, "EXEC ", 4)) - cmd_exec(line); - else if (!strncmp(line, "FILE ", 5)) - cmd_file(line); - else if (!strcmp(line, "UPDATE\n")) + else if (!strcmp(line.c_str(), "KILL\n")) + cmd_kill(line.c_str()); + else if (!strncmp(line.c_str(), "EXEC ", 4)) + cmd_exec(line.c_str()); + else if (!strncmp(line.c_str(), "FILE ", 5)) + cmd_file(line.c_str()); + else if (!strcmp(line.c_str(), "UPDATE\n")) cmd_update(); else - sendln("Invalid command."); + c_.sendln("Invalid command."); } catch (const Error &e) { - delete [] line; if (e.code() == ERR_NET) throw; else { - sendln(e.message()); + c_.sendln(e.message()); logerr << "!! " << e.message() << "\n"; } } - delete[] line; + //delete[] line; } } // recupere les erreurs de reseaux. catch (const Error &e) { if (e.code() != ERR_NET) throw; - if (socket_fs_ != 0) { + + // disconnect + if (c_.connected()) + c_.disconnect(); + +// if (socket_fs_ != 0) { if (verbose()) // TODO: Print the time at lost logerr << "Connexion lost. Retrying in " << options.retrydelay << " seconds.\n"; - fclose(socket_fs_); - socket_fs_ = 0; - } +// fclose(socket_fs_); +// socket_fs_ = 0; +// } sleep(options.retrydelay); goto net_connect; } @@ -135,121 +149,108 @@ void SLDaemon::run() { // network functions //****************************************************************************** -void SLDaemon::connect() { - struct sockaddr_in daddr; - struct hostent *h; - - // Check no existing connexion - assert(socket_fs_ == 0); - - // retrieve remote host info - h = gethostbyname(options.server.c_str()); - if (h == 0) - throw Error(ERR_NET, hstrerror(h_errno)); - - // create socket - socket_fd_ = socket(PF_INET, SOCK_STREAM, 0); - if (socket_fd_ == -1) - throw Error(ERR_NET, strerror(errno)); - - daddr.sin_family = AF_INET; - daddr.sin_port = htons(options.port); - daddr.sin_addr = *((struct in_addr *) h->h_addr); - memset(daddr.sin_zero, '\0', sizeof daddr.sin_zero); - - if (verbose()) - logout << "Connecting to " << h->h_name << " (" << inet_ntoa(*(struct in_addr*)h->h_addr) - << ") on port " << options.port << "...\n"; - - // connect - if (::connect(socket_fd_, (struct sockaddr *) &daddr, sizeof daddr) == -1) - throw Error(ERR_NET, strerror(errno)); - - if (verbose()) - logout << "Connected to " << h->h_name << " (" << inet_ntoa(*(struct in_addr*)h->h_addr) - << ") on port " << options.port << "...\n"; - - // initialize socket stream - if ((socket_fs_ = fdopen(socket_fd_, "r+")) == 0) - throw Error(ERR_NET, strerror(errno)); -} - -void SLDaemon::disconnect() { - if (socket_fs_ == 0) - return; - if (fclose(socket_fs_)) - throw Error(ERR_NET, strerror(errno)); - // TODO: print close time - if (verbose()) - logout << "Connection closed.\n"; - socket_fs_ = 0; -} - -void SLDaemon::send(long int i) { - fprintf(socket_fs_, "%li", i); -} - -void SLDaemon::send(const string str, bool buf) { - send(str.c_str(), str.length(), buf); -} - -void SLDaemon::send(const char *data, size_t len, bool buf) { - if (len == 0) - return; - if (fwrite(data, 1, len, socket_fs_) != len) - throw Error(ERR_NET, strerror(errno)); - if (!buf && fflush(socket_fs_)) - throw Error(ERR_NET, strerror(errno)); -} - -void SLDaemon::sendln(const string &s) { - if (!fprintf(socket_fs_, "%s\n", s.c_str())) - throw Error(ERR_NET, strerror(errno)); - if (verbose()) - logout << SND_DATA << s << "\n"; -} - -char *SLDaemon::recv(size_t size) { - char *data = new char[size]; - - if (fread(data, 1, size, socket_fs_) != size) { - delete[] data; - throw Error(ERR_NET, strerror(errno)); - } - return data; -} - -void SLDaemon::recv(size_t size, const string &filename) { - char *data = recv(size); - FILE *fs = fopen(filename.c_str(), "w"); - if (fs == 0) - throw Error(ERR_FILE, (string) "recv: fopen: " + strerror(errno)); - if (fwrite(data, 1, size, fs) != size) - throw Error(ERR_FILE, (string) "recv: fwrite: " + strerror(errno)); - if (fclose(fs)) - throw Error(ERR_FILE, (string) "recv: fclose: " + strerror(errno)); -} - -char *SLDaemon::recvln() { - char *line = new char[MAX_LINE_SIZE]; - - errno=0; - if (fgets(line, MAX_LINE_SIZE, socket_fs_) == 0) { - delete[] line; - if(feof(socket_fs_)) - throw Error(ERR_NET, (string) "recvln: Connexion close"); - throw Error(ERR_FILE, (string) "recvln: " + strerror(errno)); - } - if (verbose()) - logout << RCV_DATA << line; - - return line; -} - -void SLDaemon::flush() { - if (fflush(socket_fs_)) - throw Error(ERR_NET, strerror(errno)); -} +// void SLDaemon::connect() { +// struct sockaddr_in daddr; +// struct hostent *h; + +// // Check no existing connexion +// assert(socket_fs_ == 0); + +// // retrieve remote host info +// h = gethostbyname(options.server.c_str()); +// if (h == 0) +// throw Error(ERR_NET, hstrerror(h_errno)); + +// // create socket +// socket_fd_ = socket(PF_INET, SOCK_STREAM, 0); +// if (socket_fd_ == -1) +// throw Error(ERR_NET, strerror(errno)); + +// daddr.sin_family = AF_INET; +// daddr.sin_port = htons(options.port); +// daddr.sin_addr = *((struct in_addr *) h->h_addr); +// memset(daddr.sin_zero, '\0', sizeof daddr.sin_zero); + +// if (verbose()) +// logout << "Connecting to " << h->h_name << " (" << inet_ntoa(*(struct in_addr*)h->h_addr) +// << ") on port " << options.port << "...\n"; + +// // connect +// if (::connect(socket_fd_, (struct sockaddr *) &daddr, sizeof daddr) == -1) +// throw Error(ERR_NET, strerror(errno)); + +// if (verbose()) +// logout << "Connected to " << h->h_name << " (" << inet_ntoa(*(struct in_addr*)h->h_addr) +// << ") on port " << options.port << "...\n"; + +// // initialize socket stream +// if ((socket_fs_ = fdopen(socket_fd_, "r+")) == 0) +// throw Error(ERR_NET, strerror(errno)); +// } + +// void SLDaemon::disconnect() { +// if (!c_.connected()) +// return; +// c_.disconnect(); +// // TODO: print close time +// if (verbose()) +// logout << "Connection closed.\n"; +// } + +// void SLDaemon::send(long int i) { +// fprintf(socket_fs_, "%li", i); +// } + +// void SLDaemon::send(const string str, bool buf) { +// send(str.c_str(), str.length(), buf); +// } + +// void SLDaemon::send(const char *data, size_t len, bool buf) { +// if (len == 0) +// return; +// if (fwrite(data, 1, len, socket_fs_) != len) +// throw Error(ERR_NET, strerror(errno)); +// if (!buf && fflush(socket_fs_)) +// throw Error(ERR_NET, strerror(errno)); +// } + +// void SLDaemon::sendln(const string &s) { +// if (!fprintf(socket_fs_, "%s\n", s.c_str())) +// throw Error(ERR_NET, strerror(errno)); +// if (verbose()) +// logout << SND_DATA << s << "\n"; +// } + +// char *SLDaemon::recv(size_t size) { +// char *data = new char[size]; + +// if (fread(data, 1, size, socket_fs_) != size) { +// delete[] data; +// throw Error(ERR_NET, strerror(errno)); +// } +// return data; +// } + +// char *SLDaemon::recvln() { +// char *line = new char[MAX_LINE_SIZE]; + +// errno=0; +// if (fgets(line, MAX_LINE_SIZE, socket_fs_) == 0) { +// delete[] line; +// if(feof(socket_fs_)) +// throw Error(ERR_NET, (string) "recvln: Connexion close"); +// throw Error(ERR_FILE, (string) "recvln: " + strerror(errno)); +// } +// if (verbose()) +// logout << RCV_DATA << line; + +// return line; +// } + +// void SLDaemon::flush() { +// if (fflush(socket_fs_)) +// throw Error(ERR_NET, strerror(errno)); +// } //****************************************************************************** // protocol functions @@ -278,10 +279,10 @@ void SLDaemon::auth() { } snprintf(buf, MAX_LINE_SIZE, "HOST %s", options.login.c_str()); - sendln(buf); + c_.sendln(buf); snprintf(buf, MAX_LINE_SIZE, "PASS %s", buf2); - sendln(buf); + c_.sendln(buf); if (bptr->length > 0) delete[] buf2; @@ -297,13 +298,13 @@ void SLDaemon::auth() { void SLDaemon::cmd_exit() { //TODO: print date - sendln("EXIT: ok."); - disconnect(); - exit(ERR_OK); + c_.sendln("EXIT: ok."); + c_.disconnect(); + exit(ERR_NO); } void SLDaemon::cmd_version() { - sendln(VERSION); + c_.sendln(VERSION); } void SLDaemon::cmd_exec(const char *line) { @@ -312,14 +313,14 @@ void SLDaemon::cmd_exec(const char *line) { // build path char buf[MAX_LINE_SIZE]; if (sscanf(line, "EXEC %512s\n", buf) != 1) { //FIXME: Bad static magic number - sendln("EXEC: Syntax error."); + c_.sendln("EXEC: Syntax error."); return; } string path = options.scriptdir + "/" + buf; // Check transversal path attack if (strchr(buf, '/')) { - sendln("EXEC: Invalid character in job name."); + c_.sendln("EXEC: Invalid character in job name."); return; } @@ -329,27 +330,27 @@ void SLDaemon::cmd_exec(const char *line) { if (ret) { char msg[MAX_LINE_SIZE]; snprintf(msg, MAX_LINE_SIZE, "EXEC: %s: %s.", buf, strerror(errno)); - sendln(msg); + c_.sendln(msg); return; } // check for exec flag if (st.st_mode & S_IXUSR != S_IXUSR) { - sendln("EXEC: no exec flag."); + c_.sendln("EXEC: no exec flag."); return; } // check file owner if (st.st_uid != getuid()) { - sendln("EXEC: Bad file owner."); + c_.sendln("EXEC: Bad file owner."); return; } // flush before fork - flush(); + c_.flush(); //Create new process pid_t pid = fork(); if (pid == -1) { - sendln((string) "EXEC: Unable to fork: " + strerror(errno) + "."); + c_.sendln((string) "EXEC: Unable to fork: " + strerror(errno) + "."); return; } @@ -363,7 +364,7 @@ void SLDaemon::cmd_exec(const char *line) { snprintf(buf, MAX_LINE_SIZE, "EXEC: %s, pid: %d, start at: %ld.", j.name.c_str(), j.pid, j.start_time); - sendln(buf); + c_.sendln(buf); // allow sun to start if (kill(pid, SIGCONT)) { @@ -381,11 +382,11 @@ void SLDaemon::cmd_exec(const char *line) { } // try to run job - if (dup2(socket_fd_, STDOUT_FILENO) == -1) { + if (dup2(c_.getsocket(), STDOUT_FILENO) == -1) { logerr << ">> dup2" << strerror(errno) << ".\n"; exit(ERR_UNKNOWN); } - if (dup2(socket_fd_, STDERR_FILENO) == -1) { + if (dup2(c_.getsocket(), STDERR_FILENO) == -1) { logerr << ">> dup2" << strerror(errno) << ".\n"; exit(ERR_UNKNOWN); } @@ -396,7 +397,7 @@ void SLDaemon::cmd_exec(const char *line) { } void SLDaemon::cmd_file(const char *line) { - char *buf; + string buf; int ret; assert(line); @@ -404,13 +405,13 @@ void SLDaemon::cmd_file(const char *line) { // get filename char filename[MAX_LINE_SIZE]; if (sscanf(line, "FILE %512s\n", filename) != 1) { //FIXME: bad magic size - sendln("FILE: Syntax error."); + c_.sendln("FILE: Syntax error."); return; } // Check transversal path attack if (strchr(filename, '/')) { - sendln("FILE: Invalid character in filename."); + c_.sendln("FILE: Invalid character in filename."); return; } @@ -418,31 +419,29 @@ void SLDaemon::cmd_file(const char *line) { //get size int size; - buf = recvln(); - ret = sscanf(buf, "SIZE %i\n", &size); - delete[] buf; + buf = c_.recvln(); + ret = sscanf(buf.c_str(), "SIZE %i\n", &size); if (ret != 1) { - sendln("FILE: Invalid size parameter."); + c_.sendln("FILE: Invalid size parameter."); return; } //get md5 char md5[MAX_LINE_SIZE]; - buf = recvln(); - ret = sscanf(buf, "MD5 %512s\n", md5); //FIXME: bad magic size - delete[] buf; + buf = c_.recvln(); + ret = sscanf(buf.c_str(), "MD5 %512s\n", md5); //FIXME: bad magic size if (ret != 1) { - sendln("FILE: Invalid md5 parameter."); + c_.sendln("FILE: Invalid md5 parameter."); return; } //get data try { - recv(size, target); + recv2file(size, target); } catch (const Error &err) { if (err.code() == ERR_FILE) { - sendln("FILE: Data transfer error."); + c_.sendln("FILE: Data transfer error."); return; } throw; @@ -450,30 +449,30 @@ void SLDaemon::cmd_file(const char *line) { // check MD5 if (SLDaemon::md5(target) != string(md5)) { - sendln("FILE: file " + target + ": Invalid MD5."); + c_.sendln("FILE: file " + target + ": Invalid MD5."); unlink(target.c_str()); return; } // proceed chown if (chown(target.c_str(), getuid(), getgid())) { - sendln("FILE: chown of " + target + ": Unable to chown."); + c_.sendln("FILE: chown of " + target + ": Unable to chown."); unlink(target.c_str()); return; } // proceed chmod if (chmod(target.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) { - sendln("FILE: chmod of " + target + ": Unable to chmod."); + c_.sendln("FILE: chmod of " + target + ": Unable to chmod."); unlink(target.c_str()); return; } - sendln("FILE: Transfer of " + target + ": OK."); + c_.sendln("FILE: Transfer of " + target + ": OK."); } void SLDaemon::cmd_update() { - char *buf; + string buf; int ret; // get filename @@ -481,21 +480,19 @@ void SLDaemon::cmd_update() { //get size int size; - buf = recvln(); - ret = sscanf(buf, "SIZE %i\n", &size); - delete[] buf; + buf = c_.recvln(); + ret = sscanf(buf.c_str(), "SIZE %i\n", &size); if (ret != 1) { - sendln("UPDATE: Syntax error."); + c_.sendln("UPDATE: Syntax error."); return; } //get md5 char md5[MAX_LINE_SIZE]; - buf = recvln(); - ret = sscanf(buf, "MD5 %512s\n", md5); //FIXME: bad magic size - delete[] buf; + buf = c_.recvln(); + ret = sscanf(buf.c_str(), "MD5 %512s\n", md5); //FIXME: bad magic size if (ret != 1) { - sendln("UPDATE: Invalid md5 parameter."); + c_.sendln("UPDATE: Invalid md5 parameter."); return; } @@ -504,18 +501,18 @@ void SLDaemon::cmd_update() { int tempsld_fd = mkstemp(tempsld); if (tempsld_fd == 0) { - sendln((string) "UPDATE: mkstemp: " + strerror(errno) + "."); + c_.sendln((string) "UPDATE: mkstemp: " + strerror(errno) + "."); return; } close(tempsld_fd); //get data try { - recv(size, tempsld); + recv2file(size, tempsld); } catch (const Error &err) { if (err.code() == ERR_FILE) { - sendln("UPDATE: " + err.message() + "."); + c_.sendln("UPDATE: " + err.message() + "."); unlink(tempsld); return; } @@ -524,7 +521,7 @@ void SLDaemon::cmd_update() { // check MD5 if (SLDaemon::md5(tempsld) != string(md5)) { - sendln((string) "UPDATE: file " + tempsld + ": Invalid MD5."); + c_.sendln((string) "UPDATE: file " + tempsld + ": Invalid MD5."); unlink(tempsld); return; } @@ -536,7 +533,7 @@ void SLDaemon::cmd_update() { // check MD5 if (SLDaemon::md5(target.c_str()) != string(md5)) { - sendln("UPDATE: file " + target + ": Invalid MD5."); + c_.sendln("UPDATE: file " + target + ": Invalid MD5."); unlink(tempsld); return; } @@ -544,25 +541,25 @@ void SLDaemon::cmd_update() { // proceed chown if (chown(target.c_str(), getuid(), getgid())) { - sendln("FILE: chown of " + target + ": Unable to chown."); + c_.sendln("FILE: chown of " + target + ": Unable to chown."); unlink(target.c_str()); return; } // proceed chmod if (chmod(target.c_str(), S_IRUSR | S_IWUSR | S_IXUSR)) { - sendln("FILE: chmod of " + target + ": Unable to chmod."); + c_.sendln("FILE: chmod of " + target + ": Unable to chmod."); unlink(target.c_str()); return; } - sendln("UPDATE: Transfer of " + target + ": OK."); + c_.sendln("UPDATE: Transfer of " + target + ": OK."); } void SLDaemon::cmd_list() { FILE *fls = popen(string("ls -1A " + options.scriptdir).c_str(), "r"); if (fls == 0) { - sendln("LIST: Unable to list " + options.scriptdir + "."); + c_.sendln("LIST: Unable to list " + options.scriptdir + "."); return; } @@ -570,10 +567,10 @@ void SLDaemon::cmd_list() { size_t len; try { while ((len = fread(buf, 1, 255, fls)) > 0) - send(buf, len); + c_.send(buf, len); if (verbose()) logout << "LIST: data send.\n"; - flush(); + c_.flush(); } catch (...) { pclose(fls); @@ -589,12 +586,12 @@ void SLDaemon::cmd_status() { if (jobs_.size() == 0) return; - sendln("STATUS of"); + c_.sendln("STATUS of"); for (i = jobs_.begin(); i != jobs_.end(); ++i) { snprintf(buf, MAX_LINE_SIZE, " job: %s, pid: %d, start at: %ld, since: %ld seconds.", i->name.c_str(), i->pid, i->start_time,t - i->start_time); - sendln(buf); + c_.sendln(buf); } } @@ -605,7 +602,7 @@ void SLDaemon::cmd_kill(const char *line) { // retrieve pid int pid; if (sscanf(line, "KILL %i\n", &pid) != 1) { - sendln("KILL: Syntax error."); + c_.sendln("KILL: Syntax error."); return; } @@ -614,7 +611,7 @@ void SLDaemon::cmd_kill(const char *line) { int ret = kill(i->pid, SIGKILL); snprintf(buf, MAX_LINE_SIZE, "KILL: kill -SIGKILL %d (%s), return %d (%s).", i->pid, i->name.c_str(), ret, ((ret == -1) ? strerror(errno) : "OK" )); - sendln(buf); + c_.sendln(buf); } } @@ -626,7 +623,7 @@ void SLDaemon::cmd_killall() { int ret = kill(i->pid, SIGKILL); snprintf(buf, MAX_LINE_SIZE, "KILL: kill -SIGKILL %d (%s), return %d (%s).", i->pid, i->name.c_str(), ret, ((ret == -1) ? strerror(errno) : "OK" )); - sendln(buf); + c_.sendln(buf); } } @@ -658,6 +655,17 @@ string SLDaemon::md5(const string &file) const { return string(digest); } +void SLDaemon::recv2file(size_t size, const string &filename) { + char *data = c_.recv(size); + FILE *fs = fopen(filename.c_str(), "w"); + if (fs == 0) + throw Error(ERR_FILE, (string) "recv: fopen: " + strerror(errno)); + if (fwrite(data, 1, size, fs) != size) + throw Error(ERR_FILE, (string) "recv: fwrite: " + strerror(errno)); + if (fclose(fs)) + throw Error(ERR_FILE, (string) "recv: fclose: " + strerror(errno)); +} + void SLDaemon::clean_dir(const string &dir) const { DIR *ds; struct dirent *de; @@ -707,10 +715,10 @@ void sigchild(int) { if (i->pid == pid) { char buf[MAX_LINE_SIZE]; snprintf(buf, MAX_LINE_SIZE, - "JOB: %s, pid: %d, end at: %ld, since: %ld, return: %d\n", + "JOB: %s, pid: %d, end at: %ld, since: %ld, return: %d", i->name.c_str(), i->pid, t, t - i->start_time, WEXITSTATUS(status)); - write(d.socket_fd_, buf, strlen(buf)); + d.c_.sendln(buf); if (d.verbose()) logout << SND_DATA << buf; jobs_.erase(i); @@ -722,6 +730,6 @@ void sigchild(int) { void sigint(int i) { logerr << "Signal " << i << " catched.\n"; - SLDaemon::Instance().disconnect(); + SLDaemon::Instance().c_.disconnect(); exit(ERR_SIGNAL); } diff --git a/sld/trunk/src/daemon.hh b/sld/trunk/src/daemon.hh index 5dd66db..639a25e 100644 --- a/sld/trunk/src/daemon.hh +++ b/sld/trunk/src/daemon.hh @@ -19,12 +19,11 @@ #ifndef DAEMON_HH # define DAEMON_HH +# include "sld.hh" +# include "sll/connection.hh" # include "options.hh" -typedef std::string string; -typedef std::stringstream sstream; -typedef std::ostream ostream; -typedef std::ifstream ifstream; +# include // ----------------------------------------------------------------------------- // SLDAEMON CLASS @@ -61,8 +60,9 @@ public: protected: // current socket - int socket_fd_; - FILE* socket_fs_; + Connection c_; +// int socket_fd_; +// FILE* socket_fs_; // pid list typedef std::set t_job; @@ -72,16 +72,15 @@ protected: void check_options() const; // network functions - void connect(); - void disconnect(); - void send(const char *data, size_t len, bool buf = true); - void send(const string str, bool buf = true); - void send(long int i); - void sendln(const string &s); - char *recv(size_t size); - void recv(size_t size, const string &filename); - char *recvln(); - void flush(); +// void disconnect(); +// void send(const char *data, size_t len, bool buf = true); +// void send(const string str, bool buf = true); +// void send(long int i); +// void sendln(const string &s); +// char *recv(size_t size); +// void recv(size_t size, const string &filename); +// char *recvln(); +// void flush(); // protocol functions void auth(); @@ -99,12 +98,13 @@ protected: // others functions string md5(const string &file) const; + void recv2file(size_t size, const string &filename); void clean_dir(const string &dir) const; private: static SLDaemon *instance_; - SLDaemon(); + SLDaemon() {} ~SLDaemon() {} SLDaemon(const SLDaemon &) { assert(true); } SLDaemon &operator=(const SLDaemon &) { assert(true); return *instance_; } diff --git a/sld/trunk/src/options.cc b/sld/trunk/src/options.cc index 72f1d24..11045a1 100644 --- a/sld/trunk/src/options.cc +++ b/sld/trunk/src/options.cc @@ -30,7 +30,7 @@ void Options::usage(const char *argv0) const { << "usage: " << argv0 << " [-f conffile] [-d scriptdir] [-h] [-v] [-l login]" - << "[-p pass] [-H host] [-P port] [-r] [-V]" + << " [-p pass] [-H host] [-P port] [-r] [-V]" << std::endl << " -f file : read and load conf file (def: /etc/sldrc)." << std::endl << " -d dir : Scripts directory." << std::endl @@ -79,7 +79,7 @@ Options &Options::getoptions(int argc, char *argv[]) { } else if (!strcmp(argv[i], "-V")) { std::cout << "sl daemon version : " << VERSION << std::endl; - exit(ERR_OK); + exit(ERR_NO); } else if (!strcmp(argv[i], "-H")) { if (++i >= argc) @@ -130,7 +130,7 @@ Options &Options::getoptions(int argc, char *argv[]) { this->pidfile = argv[i]; } else - throw Error(ERR_USAGE, (string) "Invalid options : " + argv[i]); + throw Error(ERR_USAGE, (string) "Invalid option : " + argv[i]); } return *this; } diff --git a/sld/trunk/src/sld.cc b/sld/trunk/src/sld.cc index 8a1e8a7..150dadc 100644 --- a/sld/trunk/src/sld.cc +++ b/sld/trunk/src/sld.cc @@ -71,7 +71,6 @@ int main(int argc, char *argv[]) logerr.file(daemon.options.logfile); } - if (!register_signals()) return ERR_SIGNAL; diff --git a/sld/trunk/src/sld.hh b/sld/trunk/src/sld.hh index 6955494..a7775a7 100644 --- a/sld/trunk/src/sld.hh +++ b/sld/trunk/src/sld.hh @@ -19,44 +19,18 @@ #ifndef SLD_HH # define SLD_HH -# include -# include -# include -# include -# include -# include -# include -# include +# include "sll/slm.hh" +# include "sll/error.hh" -# include "error.hh" # include "log.hh" # include "options.hh" # include "daemon.hh" -typedef std::string string; -typedef std::stringstream sstream; -typedef std::ostream ostream; -typedef std::ifstream ifstream; - -enum { - ERR_OK = 0, - ERR_USAGE = 1, - ERR_BADPARAM = 2, - ERR_FILE = 3, - ERR_NET = 4, - ERR_PROTO = 5, - ERR_AUTH = 6, - ERR_SIGNAL = 7, - ERR_NOMEM = 41, - ERR_UNKNOWN = 42 -}; // ----------------------------------------------------------------------------- // Gonstant // ----------------------------------------------------------------------------- -static const string VERSION = "1"; -static const int MAX_LINE_SIZE = 512; static const int MAX_CONF_LINE_SIZE = 2048; static const string RCV_DATA = "<< "; static const string SND_DATA = ">> "; diff --git a/sld/trunk/src/sll/connection.cc b/sld/trunk/src/sll/connection.cc new file mode 100644 index 0000000..d78aa77 --- /dev/null +++ b/sld/trunk/src/sll/connection.cc @@ -0,0 +1,522 @@ +/* + This file is part of SLL. + Copyright (C) 2008 Sebastien LUTTRINGER + + SLL is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + SLL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SLL; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "slm.hh" +#include "connection.hh" +#include "error.hh" + +#include +#include +#include +#include +#include +#include + +/******************************************************************************* + ** Class method + ******************************************************************************/ +unsigned long int Connection::getconnid() { + static unsigned long int id = 1; + return id++; +} + +/******************************************************************************* + ** Public method + ******************************************************************************/ + +/** + * Constructor + * + * @param fd socket of the connection (-1) is not exist + */ +Connection::Connection(int fd) : socket_fd_(fd), local_port_(-1), remote_port_(-1), id_(0) { + pthread_mutex_init(&c_mutex_, 0); + pthread_mutex_init(&r_mutex_, 0); + pthread_mutex_init(&w_mutex_, 0); + + if (socket_fd_ >= 0) + id_ = getconnid(); +} + +/** + * Destructor + */ +Connection::~Connection() { + pthread_mutex_destroy(&c_mutex_); + pthread_mutex_destroy(&r_mutex_); + pthread_mutex_destroy(&w_mutex_); +} + +/** + * Disconnect socket + */ +void Connection::disconnect() { + // lock connection mutex + pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ < 0) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, "No connection established but trying to disconnect"); + } + + // lock all mutex + pthread_mutex_lock(&r_mutex_); + pthread_mutex_lock(&w_mutex_); + + disconnect_(); + + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); +} + +/** + * Create connection with @param addr on port @param port + */ +void Connection::connect(const char *addr, int port) { + // check args + if (addr == 0 || *addr == 0) + throw Error(ERR_NET, "Trying to connect on a bad address"); + + if (port <= 0 || port >= 65536) + throw Error(ERR_NET, "Trying to connect on a bad port number"); + + // take connection mutex + pthread_mutex_lock(&c_mutex_); + + // check already existant connection + if (socket_fd_ >= 0) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, "Connection already established but trying to connect"); + } + + // take read and write mutex + pthread_mutex_lock(&r_mutex_); + pthread_mutex_lock(&w_mutex_); + + // retrieve remote host info + struct hostent *h = gethostbyname(addr); + if (h == 0) { + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, (string) "Unable to resolve: " + addr + ": " + hstrerror(h_errno)); + } + + // create socket + try { socket_(); } + catch (...) { + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw; + } + + // fill sockaddr + struct sockaddr_in daddr; + daddr.sin_family = AF_INET; + daddr.sin_port = htons(port); + daddr.sin_addr = *((struct in_addr *) h->h_addr); + memset(daddr.sin_zero, '\0', sizeof daddr.sin_zero); + + // connect + if (::connect(socket_fd_, (struct sockaddr *) &daddr, sizeof daddr) == -1) { + int errno__ = errno; + disconnect_(); + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, (string) "Unable to connect to " + addr + ": " + strerror(errno__)); + } + + // set infos + try { + setlocalip_(); + setlocalport_(); + setremoteip_(); + setremoteport_(); + } + catch (...) { + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw; + } + + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); +} + +/** + * Listen on @param port with queue size of max @param max + */ +void Connection::listen(int port, int max) { + // check arg + if (port <= 0 || port >= 65536) + throw Error(ERR_NET, "Trying to listen on a bad port number"); + if (max <= 0) + throw Error(ERR_NET, "Trying to listen with bad wait queue size"); + + // take connection mutex + pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ >= 0) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, "Connection already established but trying to listen"); + } + + // lock read and write mutex + pthread_mutex_lock(&r_mutex_); + pthread_mutex_lock(&w_mutex_); + + // create socket + try { socket_(); } + catch (...) { + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw; + } + + // fill sockaddr + struct sockaddr_in saddr; + + saddr.sin_family = AF_INET; + saddr.sin_port = htons(port); + saddr.sin_addr.s_addr = INADDR_ANY; + memset(saddr.sin_zero, '\0', sizeof saddr.sin_zero); + + // bind on socket + if (bind(socket_fd_, (struct sockaddr *)&saddr, sizeof saddr) == -1) { + disconnect_(); + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, (string) "Unable to bind: " + strerror(errno)); + } + + // listen on socket + if (::listen(socket_fd_, max) == -1) { + disconnect_(); + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, (string) "Unable to listen: " + strerror(errno)); + } + + // set all infos + try { + setlocalip_(); + setlocalport_(); + } + catch (...) { + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + throw; + } + + pthread_mutex_unlock(&w_mutex_); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); +} + +/** + * Accept new connection on a listening socket + * + * @return null on error, else a new connection + */ +Connection *Connection::accept() { + // keep the socket fd + pthread_mutex_lock(&c_mutex_); + int socket_fd = socket_fd_; + pthread_mutex_unlock(&c_mutex_); + + // test socket validity + if (socket_fd < 0) + throw Error(ERR_NET, "No connection established but trying to accept"); + + struct sockaddr_in r_addr; + socklen_t r_sin_size = sizeof r_addr; + int r_fd; + + // accept is a read/write operation + pthread_mutex_lock(&r_mutex_); + pthread_mutex_lock(&w_mutex_); + + if ((r_fd = ::accept(socket_fd, (struct sockaddr *) &r_addr, &r_sin_size)) == -1) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, (string) "accept: " + strerror(errno)); + } + + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&w_mutex_); + + return new Connection(r_fd); +} + +/** + * Send data on @param buf of size @param len on socket + */ +void Connection::send(const char* buf, size_t len) { + // lock mutex for operation + pthread_mutex_lock(&c_mutex_); + pthread_mutex_lock(&w_mutex_); + + // retreive socket_fd and free conn mutex + int socket_fd = socket_fd_; + pthread_mutex_unlock(&c_mutex_); + + // test socket validity + if (socket_fd < 0) { + pthread_mutex_unlock(&w_mutex_); + throw Error(ERR_NET, "No connection established but trying to send data"); + } + + // send is a write operation + int ret = ::send(socket_fd_, buf, len, MSG_NOSIGNAL); + + // treat error + if (ret == -1) { + int errno__ = errno; + pthread_mutex_lock(&c_mutex_); + pthread_mutex_lock(&r_mutex_); + disconnect_(); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + pthread_mutex_unlock(&w_mutex_); + if (errno__ == ECONNRESET || errno__ == EPIPE) + throw Error(ERR_NET, "Connection reset by peer"); + else + throw Error(ERR_NET, "send: " + (string) strerror(errno__)); + } + + // release the mutex + pthread_mutex_unlock(&w_mutex_); +} + +/** + * Receive raw data + */ +char *Connection::recv(size_t size) { + assert(0); + return 0; +} + +/** + * Receive a line + */ +string Connection::recvln() { + // lock mutex for operation + pthread_mutex_lock(&c_mutex_); + pthread_mutex_lock(&r_mutex_); + + int socket_fd = socket_fd_; + pthread_mutex_unlock(&c_mutex_); + + // test socket validity + if (socket_fd < 0) { + pthread_mutex_unlock(&r_mutex_); + throw Error(ERR_NET, "No connection established but trying to receive line"); + } + + do { + // check EOL char + size_t offset = rbuf_.find('\n'); + if (offset != string::npos) { + string s = rbuf_.substr(0, offset); + rbuf_.erase(0, offset + 1); + pthread_mutex_unlock(&r_mutex_); + return s; + } + + // read data + static char local_buf[MAX_LINE_SIZE]; + int ret = ::recv(socket_fd, local_buf, MAX_LINE_SIZE, 0); + + if (ret == -1 || ret == 0) { + pthread_mutex_lock(&c_mutex_); + pthread_mutex_lock(&w_mutex_); + disconnect_(); + pthread_mutex_unlock(&r_mutex_); + pthread_mutex_unlock(&c_mutex_); + pthread_mutex_unlock(&r_mutex_); + + *local_buf = 0; + + if (ret == 0) + throw Error(ERR_NET, "Connection reset by peer"); + else + throw Error(ERR_NET, (string) "recvln: " + strerror(errno)); + } + local_buf[ret] = 0; + + // add read data in buffer + rbuf_ += local_buf; + + } while (1); + assert(1); +} + +void Connection::flush() { + assert(0); +} + +string Connection::getlocalip() { + // get local ip is a conn op + pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ < 0) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, "No connection established but trying to get local ip"); + } + + if (local_ip_.empty()) + try { setlocalip_(); } + catch (...) { + pthread_mutex_unlock(&c_mutex_); + throw; + } + string ip = local_ip_; + pthread_mutex_unlock(&c_mutex_); + return ip; +} + +string Connection::getlocalhostname() { + pthread_mutex_lock(&c_mutex_); + if (local_hostname_.empty()) { + char buf[256]; + if (::gethostname(buf, 256) != 0) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, (string) "Unable to get local hostname: " + strerror(errno)); + } + try { local_hostname_ = buf; } + catch (...) { + pthread_mutex_unlock(&c_mutex_); + throw; + } + } + pthread_mutex_unlock(&c_mutex_); + + return local_hostname_; +} + +int Connection::getlocalport() { + // get local port is a conn op + pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ < 0) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, "No connection established but trying to get local port"); + } + + if (local_port_ == -1) + try { setlocalport_(); } + catch (...) { + pthread_mutex_unlock(&c_mutex_); + throw; + } + + int port = local_port_; + pthread_mutex_unlock(&c_mutex_); + return port; +} + +string Connection::getremoteip() { + // get remote hostname is a conn op + pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ < 0) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, "No connection established but trying to get remote ip"); + } + + if (remote_ip_.empty()) + try { setremoteip_(); } + catch (...) { + pthread_mutex_unlock(&c_mutex_); + throw; + } + + string ip = remote_ip_; + pthread_mutex_unlock(&c_mutex_); + return ip; +} + +string Connection::getremotehostname() { + // get remote ip is a conn op + pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ < 0) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, "No connection established but trying to get remote ip"); + } + + if (remote_hostname_.empty()) + try {setremotehostname_(); } + catch (...) { + pthread_mutex_unlock(&c_mutex_); + throw; + } + + string hostname = remote_hostname_; + pthread_mutex_unlock(&c_mutex_); + return hostname; +} + +int Connection::getremoteport() { + // get remote port is a conn op + pthread_mutex_lock(&c_mutex_); + + if (socket_fd_ < 0) { + pthread_mutex_unlock(&c_mutex_); + throw Error(ERR_NET, "No connection established but trying to get remote port"); + } + + if (remote_port_ == -1) + try {setremoteport_(); } + catch (...) { + pthread_mutex_unlock(&c_mutex_); + throw; + } + + int port = remote_port_; + pthread_mutex_unlock(&c_mutex_); + return port; +} + +unsigned long int Connection::getid() { + return id_; +} + +int Connection::getsocket() { + // get socket is a conn op + pthread_mutex_lock(&c_mutex_); + int socket_fd = socket_fd_; + pthread_mutex_unlock(&c_mutex_); + + if (socket_fd < 0) + throw Error(ERR_NET, "No connection established but trying to get socket fd"); + + return socket_fd; +} + +/******************************************************************************* + ** Protected method + ******************************************************************************/ diff --git a/sld/trunk/src/sll/connection.hh b/sld/trunk/src/sll/connection.hh new file mode 100644 index 0000000..89bffbc --- /dev/null +++ b/sld/trunk/src/sll/connection.hh @@ -0,0 +1,103 @@ +/* + This file is part of SLS. + Copyright (C) 2008 Sebastien LUTTRINGER + + SLL is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + SLL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SLL; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef CONNECTION_HH +# define CONNECTION_HH + +# include + +class Connection { + // class methods +public: + unsigned long int getconnid(); + + // public methods +public: + Connection(int fd = -1); + virtual ~Connection(); + + void connect(const char *addr, int port); + void listen(int port, int max); + + void disconnect(); + inline bool connected(); + + Connection *accept(); + + // send methods + void send(const char* buf, size_t len); + inline void send(const string &data); + inline void sendln(const string &data); + + // recv methods + char *recv(size_t size); + string recvln(); + + // buffer methods + void flush(); + + // info methods + string getlocalip(); + string getlocalhostname(); + int getlocalport(); + + string getremoteip(); + string getremotehostname(); + int getremoteport(); + + unsigned long int getid(); + + int getsocket(); + + // protected methods +protected: + inline void socket_(); + inline void disconnect_(); + + inline void setlocalip_(); + inline void setlocalport_(); + inline void setremoteip_(); + inline void setremotehostname_(); + inline void setremoteport_(); + + // Protected datas +protected: + int socket_fd_; // connection socket + + // storage of info about connection + int local_port_; + int remote_port_; + + string local_ip_; + string local_hostname_; + string remote_ip_; + string remote_hostname_; + + unsigned long int id_; + + string rbuf_; // read buffer + string wbuf_; // write buffer + + pthread_mutex_t c_mutex_; // connection mutex + pthread_mutex_t r_mutex_; // read mutex + pthread_mutex_t w_mutex_; // write mutex +}; + +# include "connection.hxx" + +#endif diff --git a/sld/trunk/src/sll/connection.hxx b/sld/trunk/src/sll/connection.hxx new file mode 100644 index 0000000..3a606fb --- /dev/null +++ b/sld/trunk/src/sll/connection.hxx @@ -0,0 +1,166 @@ +/* + This file is part of SLL. + Copyright (C) 2008 Sebastien LUTTRINGER + + SLL is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + SLL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SLLo; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +# include "error.hh" + +#include +#include +#include +#include +#include + +/******************************************************************************* + ** Public method + ******************************************************************************/ + +/** + * Return the connection sate + * Cannot be const, du to mutex locking + * + * @return see description + */ +bool Connection::connected() { + // get connection mutex + + pthread_mutex_lock(&c_mutex_); + + bool ret = (socket_fd_ >= 0); + + pthread_mutex_unlock(&c_mutex_); + + return ret; +} + +/** + * Send @param data on socket + */ +void Connection::send(const string &data) { + send(data.c_str(), data.length()); +} + +/** + * Send @param data followed by '\n' on socket + */ +void Connection::sendln(const string &data) { + string tosend = data + "\n"; + send(tosend.c_str(), tosend.length()); +} + +/******************************************************************************* + ** Protected method + ******************************************************************************/ + +/** + * Free a socket + * No mutex used ! + */ +void Connection::disconnect_() { + assert(socket_fd_ >= 0); + + close(socket_fd_); + socket_fd_ = -1; +} + +/** + * Reserve a socket + * No mutex used ! + */ +void Connection::socket_() { + assert(socket_fd_ == -1); + int yes = 1; + + if ((socket_fd_ = ::socket(AF_INET, SOCK_STREAM, 0)) == -1) + throw Error(ERR_NET, (string) "Unable to open socket: " + strerror(errno)); + + if (::setsockopt(socket_fd_, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) + throw Error(ERR_NET, (string) "Unable to set socket options: " + strerror(errno)); +} + +/** + * Set local ip + * No mutex used ! + */ +void Connection::setlocalip_() { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + + if (::getsockname(socket_fd_, (struct sockaddr*) &addr, &len) != 0) + throw Error(ERR_NET, (string) "Unable to get local ip: " + strerror(errno)); + local_ip_ = inet_ntoa(addr.sin_addr); +} + +/** + * Set local port + * No mutex used ! + */ +void Connection::setlocalport_() { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + + if (::getsockname(socket_fd_, (struct sockaddr*) &addr, &len) != 0) + throw Error(ERR_NET, (string) "Unable to get local port: " + strerror(errno)); + local_port_ = ntohs(addr.sin_port); +} + +/** + * Set remote ip + * No mutex used ! + */ +void Connection::setremoteip_() { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + + // get socket + if (::getpeername(socket_fd_, (struct sockaddr*) &addr, &len) != 0) + throw Error(ERR_NET, (string) "Unable to get remote ip: " + strerror(errno)); + remote_ip_ = inet_ntoa(addr.sin_addr); +} + +/** + * Set remote hostname + * No mutex used ! + */ +void Connection::setremotehostname_() { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + + // get sockaddr_in + if (::getpeername(socket_fd_, (struct sockaddr*) &addr, &len) != 0) + throw Error(ERR_NET, (string) "Unable to get remote ip: " + strerror(errno)); + if (remote_ip_.empty()) + remote_ip_ = inet_ntoa(addr.sin_addr); + + // get hostname + struct hostent *h; + if ((h = ::gethostbyaddr(&addr.sin_addr, sizeof addr.sin_addr, AF_INET)) == 0) + throw Error(ERR_NET, (string) "Unable to get remote hostname: " + hstrerror(h_errno)); + remote_hostname_ = h->h_name; +} + +/** + * Set remote port + * No mutex used ! + */ +void Connection::setremoteport_() { + struct sockaddr_in addr; + socklen_t len = sizeof addr; + + if (::getpeername(socket_fd_, (struct sockaddr*) &addr, &len) != 0) + throw Error(ERR_NET, (string) "Unable to get remote port: " + strerror(errno)); + remote_port_ = ntohs(addr.sin_port); +} diff --git a/sld/trunk/src/error.cc b/sld/trunk/src/sll/error.cc similarity index 57% rename from sld/trunk/src/error.cc rename to sld/trunk/src/sll/error.cc index 2a085b5..429335f 100644 --- a/sld/trunk/src/error.cc +++ b/sld/trunk/src/sll/error.cc @@ -1,57 +1,100 @@ /* - This file is part of SLD. + This file is part of SLL. Copyright (C) 2008 Sebastien LUTTRINGER - SLD is free software; you can redistribute it and/or modify + SLL is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. - SLD is distributed in the hope that it will be useful, + SLL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with SLD; if not, write to the Free Software + along with SLL; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "error.hh" -#include "log.hh" +/*! +** Constructor +** +** @param i error code +** @param s error message +*/ Error::Error(int i, const string s) { val_ = i; msg_ << s; } +/*! +** Constructor by copy +** +** @param e +*/ Error::Error(const Error &e) { val_ = e.val_; msg_ << e.msg_.str(); } +/*! +** Print and error msg on std err +** +*/ void Error::print() const { if (msg_.str() != "") - logerr << msg_.str() << ".\n"; + std::cerr << msg_.str() << "." << std::endl; } +/*! +** @return a copy of message description +*/ string Error::message() const { return msg_.str(); } +/*! +** @return the error code +*/ int Error::code() const { return val_; } +/*! +** Set error code to @param v +*/ void Error::code(int v) { val_ = v; } +/*! +** Concatenate @param s before error message +*/ +void Error::prefix(const string &s) { + string buf = s + msg_.str(); + + msg_.str(""); + msg_ << buf; +} + +/*! +** Concatenate @param s to errror message +*/ +void Error::suffix(const string &s) { + msg_ << s; +} + +/*! +** Copy operator +*/ Error &Error::operator=(const Error &rhs) { val_ = rhs.val_; @@ -60,24 +103,36 @@ Error &Error::operator=(const Error &rhs) return *this; } +/*! +** Print error message to @param o stream +*/ ostream &operator<<(ostream &o, const Error &e) { o << e.msg_.str(); return o; } +/*! +** Concatenate @param val to errror message +*/ Error &operator<<(Error &e, int val) { e.msg_ << val; return e; } +/*! +** Concatenate @param s to errror message +*/ Error &operator<<(Error &e, const string &s) { e.msg_ << s; return e; } +/*! +** Concatenate @param s before error message +*/ Error &operator>>(Error &e, const string &s) { string buf = s + e.msg_.str(); @@ -86,3 +141,4 @@ Error &operator>>(Error &e, const string &s) e.msg_ << buf; return e; } + diff --git a/sld/trunk/src/error.hh b/sld/trunk/src/sll/error.hh similarity index 74% rename from sld/trunk/src/error.hh rename to sld/trunk/src/sll/error.hh index 5a99758..9d9286e 100644 --- a/sld/trunk/src/error.hh +++ b/sld/trunk/src/sll/error.hh @@ -1,46 +1,47 @@ /* - This file is part of SLD. + This file is part of SLL. Copyright (C) 2008 Sebastien LUTTRINGER - SLD is free software; you can redistribute it and/or modify + SLL is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. - SLD is distributed in the hope that it will be useful, + SLL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with SLD; if not, write to the Free Software + along with SLL; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef ERROR_HH # define ERROR_HH -# include -# include -# include - -typedef std::string string; -typedef std::stringstream sstream; -typedef std::ostream ostream; +# include "slm.hh" class Error { public: Error(int i, string s = ""); Error(const Error &e); + void print() const; string message() const; + + void suffix(const string &); + void prefix(const string &); + int code() const; void code(int); + Error &operator=(const Error &rhs); friend ostream &operator<<(ostream &o, const Error &e); friend Error &operator<<(Error &e, const string &s); friend Error &operator>>(Error &e, const string &s); friend Error &operator<<(Error &e, int val); + protected: sstream msg_; int val_; diff --git a/sld/trunk/src/sll/slm.hh b/sld/trunk/src/sll/slm.hh new file mode 100644 index 0000000..e04a2fd --- /dev/null +++ b/sld/trunk/src/sll/slm.hh @@ -0,0 +1,62 @@ +/* + This file is part of SLL. + Copyright (C) 2008 Sebastien LUTTRINGER + + SLL is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + SLL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with SLL; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef SLM_HH +# define SLM_HH + +# define _REENTRANT + +# include +# include +# include +# include +# include + +typedef std::string string; +typedef std::stringstream sstream; +typedef std::ostream ostream; +typedef std::ifstream ifstream; +typedef std::ofstream ofstream; + +enum { + ERR_NO = 0, + ERR_USAGE = 1, + ERR_BADPARAM = 2, + ERR_FILE = 3, + ERR_NET = 4, + ERR_PROTO = 5, + ERR_AUTH = 6, + ERR_DB = 7, + ERR_SRV = 8, + ERR_THREAD = 9, + ERR_PARSE = 10, + ERR_SCREENSZ = 11, + ERR_SIGNAL = 12, + ERR_NOMEM = 41, + ERR_UNKNOWN = 42 +}; + +// ----------------------------------------------------------------------------- +// Gonstant +// ----------------------------------------------------------------------------- + +static const string VERSION = (string) "testing.\nCompiled: " + __DATE__ + " " + __TIME__ + "."; +//static const string VERSION = "1.0"; +static const int MAX_LINE_SIZE = 512; + +#endif -- GitLab