Connection.cc

00001 /* 
00002    EyeDB Object Database Management System
00003    Copyright (C) 1994-2008 SYSRA
00004    
00005    EyeDB is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009    
00010    EyeDB is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014    
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA 
00018 */
00019 
00020 /*
00021    Author: Eric Viara <viara@sysra.com>
00022 */
00023 
00024 
00025 #include <eyedbconfig.h>
00026 #include <fcntl.h>
00027 #ifdef HAVE_SYS_STAT_H
00028 #include <sys/stat.h>
00029 #endif
00030 
00031 #include "eyedb_p.h"
00032 
00033 namespace eyedb {
00034 
00035   const char Connection::LocalHost[]      = "-idb-local-host";
00036   const char Connection::DefaultHost[]    = "-idb-default-host";
00037   const char Connection::DefaultIDBPort[] = "-idb-default-idb-port";
00038 
00039   const char Connection::DefaultIDBPortValue[] = "6123";
00040 
00041 #ifdef HAVE_UNISTD_H
00042 #include <unistd.h>
00043 #endif
00044 
00045   Connection::Connection()
00046   {
00047     host = 0;
00048     port = 0;
00049     connh = 0;
00050     oql_info = 0;
00051     user_data = 0;
00052   }
00053 
00054   Connection::Connection(bool opening, const char *_host, const char *_port)
00055   {
00056     host = 0;
00057     port = 0;
00058     connh = 0;
00059     oql_info = 0;
00060     user_data = 0;
00061 
00062     if (opening) {
00063       Status status = open(_host, _port);
00064       if (status)
00065         throw *status;
00066     }
00067   }
00068 
00069   const char *Connection::getHost(void) const
00070   {
00071     return host;
00072   }
00073 
00074   const char *Connection::getIDBPort(void) const
00075   {
00076     return port;
00077   }
00078 
00079   int Connection::getServerPid(void) const
00080   {
00081     return sv_pid;
00082   }
00083 
00084   int Connection::getServerUid(void) const
00085   {
00086     return sv_uid;
00087   }
00088 
00089   extern char *prog_name;
00090 
00091 #include <pwd.h>
00092 
00093   /*
00094   extern "C" void exit(int s) {
00095     static bool e = false;
00096     if (e)
00097       return;
00098     e = true;
00099     if (Exception::getMode() == Exception::StatusMode)
00100       fprintf(stderr, "exit(int) function has been called : getting a chance to trap this call\n");
00101     Exception::setMode(Exception::ExceptionMode);
00102     Exception::make(IDB_EXIT_CALLED, "invalid called");
00103   }
00104   */
00105 
00106   static const char *
00107   getUserName()
00108   {
00109     struct passwd *p = getpwuid(getuid());
00110     if (!p)
00111       return "<unknown>";
00112     return p->pw_name;
00113   }
00114 
00115   Status Connection::open(const char *_host, const char *_port)
00116   {
00117     if (connh)
00118       return Exception::make(IDB_CONNECTION_FAILURE, "connection already made");
00119 
00120     if (!_host)
00121       return Exception::make(IDB_CONNECTION_FAILURE, "cannot connect on not specified host");
00122     if (!_port)
00123       return Exception::make(IDB_CONNECTION_FAILURE, "cannot connect on not specified eyedb port");
00124 
00125     if (!strcmp(_host, LocalHost))
00126       _host = "localhost";
00127     else if (!strcmp(_host, DefaultHost))
00128       _host = getDefaultHost();
00129 
00130     if (!_host)
00131       return Exception::make(IDB_CONNECTION_FAILURE, "default host is not set for connection");
00132 
00133     if (!strcmp(_port, DefaultIDBPort))
00134       _port = getDefaultIDBPort();
00135 
00136     if (!_port)
00137       return Exception::make(IDB_CONNECTION_FAILURE, "default eyedb port is not set for connection");
00138 
00139     std::string errmsg;
00140     if ((connOpen(_host, _port, &connh, 0, errmsg)) == RPCSuccess)
00141       {
00142         if (_host)
00143           host = strdup(_host);
00144         else
00145           host = strdup("localhost");
00146 
00147         port = strdup(_port);
00148 
00149         char hostname[256];
00150         gethostname(hostname, sizeof(hostname)-1);
00151         char *challenge;
00152         RPCStatus rpc_status = 
00153           set_conn_info(connh, (std::string(host) + ":" + port).c_str(),
00154                         0 /*getuid()*/, getUserName(), prog_name,
00155                         &sv_pid, &sv_uid, getVersionNumber(),
00156                         &challenge);
00157         if (!rpc_status && strlen(challenge) > 0) {
00158           //char *file = tempnam("/tmp", ".eyedb");
00159           //printf("CHALLENGE '%s'\n", challenge);
00160           std::string file = std::string("/tmp/") +
00161             (strrchr(challenge, '.') + 1);
00162           int fd = creat(file.c_str(), 0664);
00163           if (fd >= 0) {
00164             fchmod(fd, 0664);
00165             write(fd, challenge, strlen(challenge));
00166             rpc_status = checkAuth(connh, file.c_str());
00167             ftruncate(fd, 0);
00168 	    ::close(fd);
00169             unlink(file.c_str());
00170           }
00171         }
00172 
00173         if (rpc_status)
00174           return Exception::make(IDB_CONNECTION_FAILURE, rpc_status->err_msg);
00175 
00176         if (getenv("EYEDBWAIT")) {
00177           printf("### Connection Established for PID %d ###\n", getpid());
00178           printf("Continue? ");
00179           getchar();
00180         }
00181 
00182         //atexit(eyedb_exit);
00183 
00184         return Success;
00185       }
00186 
00187     return Exception::make(IDB_CONNECTION_FAILURE,
00188                            errmsg.c_str());
00189     //"connection refused to '%s', eyedb port '%s'",
00190     //(_host ? _host : "localhost"), _port);
00191   }
00192 
00193   Status Connection::close(void)
00194   {
00195     if (!connh)
00196       return Exception::make(IDB_CONNECTION_FAILURE, "connection not opened");
00197 
00198     Status status = StatusMake(connClose(connh));
00199     if (status)
00200       return status;
00201 
00202     connh = 0;
00203     return Success;
00204   }
00205 
00206   Status
00207   Connection::sendInterrupt()
00208   {
00209     return StatusMake(backendInterrupt(connh, 0));
00210   }
00211 
00212   Connection::~Connection()
00213   {
00214     if (connh)
00215       close();
00216     free(host);
00217     free(port);
00218     free(connh);
00219   }
00220 
00221   char *Connection::default_host;
00222   char *Connection::default_port;
00223   char *Connection::default_user;
00224   char *Connection::default_passwd;
00225 
00226   Bool Connection::set_auth_required = False;
00227 
00228   void Connection::init()
00229   {
00230 #if 0
00231     std::string value;
00232     if (!default_host) {
00233       value = ClientConfig::getCValue("host");
00234       if (value != Config::UNKNOWN_VALUE) {
00235         default_host = strdup(value.c_str());
00236       }
00237       else
00238         default_host = strdup("localhost");
00239     }
00240 
00241     if (!default_port) {
00242       value = ClientConfig::getCValue("port");
00243       if (value != Config::UNKNOWN_VALUE) {
00244         default_port = strdup(value.c_str());
00245       }
00246       else {
00247         default_port = strdup(DefaultIDBPortValue);
00248       }
00249     }
00250 
00251     if (!set_auth_required) {
00252       if (!default_user) {
00253         value = ClientConfig::getCValue("user");
00254         if (value != Config::UNKNOWN_VALUE) {
00255           setDefaultUser(strdup(value.c_str()));
00256         }
00257         else {
00258           setDefaultUser(strdup(""));
00259         }
00260       }
00261 
00262       if (!default_passwd) {
00263         value = ClientConfig::getCValue("passwd");
00264         if (value != Config::UNKNOWN_VALUE) {
00265           setDefaultPasswd(strdup(value.c_str()));
00266         }
00267         else {
00268           setDefaultPasswd(strdup(""));
00269         }
00270       }
00271     }
00272 #else
00273     const char *s;
00274 
00275     if (!default_host)
00276       default_host = strdup( (s = ClientConfig::getCValue("host")) ?
00277                              s : "localhost" );
00278     if (!default_port)
00279       default_port = strdup( (s = ClientConfig::getCValue("port")) ?
00280                                  s : DefaultIDBPortValue);
00281 
00282     if (!set_auth_required)
00283       {
00284         if (!default_user)
00285           setDefaultUser(((s = ClientConfig::getCValue("user")) ?
00286                           strdup(s) : strdup("")));
00287         if (!default_passwd)
00288           setDefaultPasswd(((s = ClientConfig::getCValue("passwd")) ?
00289                             strdup(s) : strdup("")));
00290       }
00291 #endif
00292   }
00293 
00294   void Connection::_release()
00295   {
00296     free(default_host);
00297     free(default_port);
00298 
00299     free(default_user);
00300     free(default_passwd);
00301   }
00302 
00303   void Connection::setAuthRequired(Bool _set_auth_required)
00304   {
00305     set_auth_required = _set_auth_required;
00306   }
00307 
00308   void Connection::setDefaultHost(const char *_host)
00309   {
00310     free(default_host);
00311     default_host = strdup(_host);
00312   }
00313 
00314   const char *Connection::getDefaultHost()
00315   {
00316     return default_host;
00317   }
00318 
00319   void Connection::setDefaultIDBPort(const char *_port)
00320   {
00321     free(default_port);
00322     default_port = strdup(_port);
00323   }
00324 
00325   const char *Connection::getDefaultIDBPort()
00326   {
00327     return default_port;
00328   }
00329 
00330   std::string Connection::makeUser(const char *user)
00331   {
00332     if (!strcmp(user, "@")) {
00333       struct passwd *pwd = getpwuid(getuid());
00334       if (pwd)
00335         return pwd->pw_name;
00336     }
00337     return user;
00338   }
00339 
00340   void Connection::setDefaultUser(const char *_user)
00341   {
00342     std::string u = makeUser(_user);
00343     free(default_user);
00344     default_user = strdup(u.c_str());
00345   }
00346 
00347   const char *Connection::getDefaultUser()
00348   {
00349     return default_user;
00350   }
00351 
00352   void Connection::setDefaultPasswd(const char *_passwd)
00353   {
00354     free(default_passwd);
00355     default_passwd = strdup(_passwd);
00356   }
00357 
00358   const char *Connection::getDefaultPasswd()
00359   {
00360     return default_passwd;
00361   }
00362 
00363   void *Connection::setUserData(void *ud)
00364   {
00365     void *oud = user_data;
00366     user_data = ud;
00367     return oud;
00368   }
00369 
00370   void *Connection::getUserData()
00371   {
00372     return user_data;
00373   }
00374 
00375   const void *Connection::getUserData() const
00376   {
00377     return user_data;
00378   }
00379 
00380   void *Connection::setOQLInfo(void *noql_info)
00381   {
00382     void *x = oql_info;
00383     oql_info = noql_info;
00384     return x;
00385   }
00386 
00387   void *Connection::getOQLInfo()
00388   {
00389     return oql_info;
00390   }
00391 
00392   //
00393   // Server message management
00394   //
00395 
00396   eyedblib::Thread *srv_msg_thr;
00397 
00398   struct Connection::ServerMessageContext {
00399     ConnHandle *connh;
00400     const ServerMessageDisplayer &dsp;
00401 
00402     ServerMessageContext(ConnHandle *_connh, 
00403                          const ServerMessageDisplayer &_dsp) :
00404       connh(_connh), dsp(_dsp)
00405     {
00406     }
00407   };
00408 
00409   static void *
00410   srv_msg_listen(void *x)
00411   {
00412     Connection::ServerMessageContext *srv_msg_ctx = (Connection::ServerMessageContext *)x;
00413 
00414     ConnHandle *connh = srv_msg_ctx->connh;
00415 
00416     for (;;) {
00417       int type = IDB_SERVER_MESSAGE;
00418       unsigned int size;
00419       Data data = (Data)0x111;
00420       RPCStatus rpc_status = getServerOutOfBandData(connh, &type, &data,
00421                                                     &size);
00422       if (rpc_status) {
00423         std::string msg =
00424           std::string("Thread for echoing server messages got an "
00425                       "unexepected error: #") + str_convert((long)rpc_status->err) +
00426           rpc_status->err_msg + "\n";
00427         srv_msg_ctx->dsp.display(msg.c_str());
00428         break;
00429       }
00430 
00431       assert(type == IDB_SERVER_MESSAGE);
00432       if (data) {
00433         srv_msg_ctx->dsp.display((const char *)data);
00434         free(data);
00435       }
00436     }
00437     return 0;
00438   }
00439 
00440   Status
00441   Connection::echoServerMessages(const ServerMessageDisplayer &dsp) const
00442   {
00443     if (srv_msg_thr)
00444       return Exception::make(IDB_ERROR,
00445                              "a thread is already echoing server messages");
00446 
00447     // 1st thread for remote listening
00448     ServerMessageContext *srv_msg_ctx = new ServerMessageContext(connh, dsp);
00449     srv_msg_thr = new eyedblib::Thread();
00450     srv_msg_thr->execute(srv_msg_listen, srv_msg_ctx);
00451 
00452     // 2nd thread for local listening
00453     srv_msg_ctx = new ServerMessageContext(0, dsp);
00454     srv_msg_thr = new eyedblib::Thread();
00455     srv_msg_thr->execute(srv_msg_listen, srv_msg_ctx);
00456     return Success;
00457   }
00458 
00459   void
00460   Connection::setServerMessage(const char *msg)
00461   {
00462     eyedb::setServerMessage(msg);
00463   }
00464 
00465   void
00466   Connection::setOutOfBandData(unsigned int type, unsigned char *data,
00467                                unsigned int len)
00468   {
00469     setServerOutOfBandData(type, data, len);
00470   }
00471 
00472   Bool
00473   Connection::isBackendInterrupted()
00474   {
00475     return isBackendInterrupted();
00476   }
00477 
00478   StdServerMessageDisplayer::StdServerMessageDisplayer(FILE *_fd)
00479   {
00480     fd = _fd;
00481     os = 0;
00482   }
00483 
00484   StdServerMessageDisplayer::StdServerMessageDisplayer(std::ostream &_os)
00485   {
00486     fd = 0;
00487     os = &_os;
00488   }
00489 
00490   void StdServerMessageDisplayer::display(const char *msg) const
00491   {
00492     if (fd) {
00493       /*
00494         fprintf(fd, msg);
00495         fflush(fd);
00496       */
00497       write(fileno(fd), msg, strlen(msg));
00498       return;
00499     }
00500     (*os) << msg << std::flush;
00501   }
00502 }

Generated on Mon Dec 22 18:15:53 2008 for eyedb by  doxygen 1.5.3