/*
 * Return the number of clients held by this thread
 */
int ConnectionPool::numClientsBorrowed() {
    ClientSet *clients = reinterpret_cast<ClientSet*>(pthread_getspecific(m_borrowedClients));
    if (clients != NULL) {
        return clients->size();
    }
    return 0;
}
/*
 * Retrieve a client that is connected and authenticated
 * to the specified hostname and port. Will reuse an existing connection if one is available.
 */
voltdb::Client
ConnectionPool::acquireClient(
        std::string hostname,
        std::string username,
        std::string password,
        StatusListener *listener,
        unsigned short port,
        ClientAuthHashScheme sha)
throw (voltdb::Exception, voltdb::ConnectException, voltdb::LibEventException) {
    LockGuard guard(m_lock);
    ClientSet *clients = reinterpret_cast<ClientSet*>(pthread_getspecific(m_borrowedClients));
    if (clients == NULL) {
        clients = new ClientSet();
        pthread_setspecific( m_borrowedClients, static_cast<const void *>(clients));
    }
    char portBytes[16];
    unsigned int portInt = port;
    snprintf(portBytes, 16, "%d", portInt);
    std::string identifier = hostname + "," + std::string(portBytes) + "," + username + "," + password;

    // if a thread calls acquireClient() multiple times with the same identifier, reuse the same client
    for (ClientSet::iterator i = clients->begin(); i != clients->end(); i++) {
        if ((*i)->m_identifier == identifier) {
            return (*i)->m_client;
        }
    }

    std::vector<boost::shared_ptr<ClientStuff> > *clientStuffs = &m_clients[identifier];

    while (clientStuffs->size() > 0) {
        boost::shared_ptr<ClientStuff> clientStuff = clientStuffs->back();
        clientStuffs->pop_back();

        // run the event loop once to verify the connection is still available
        clientStuff->m_client.runOnce();

        if (clientStuff->m_listener->m_connectionLost) {
            // if this connection is lost, try the next
            continue;
        } else {
            // otherwise return this connection
            clientStuff->m_listener->m_listener = listener;
            clients->push_back(clientStuff);
            return clientStuff->m_client;
        }
    }

    // no connection available, make a new one
    DelegatingStatusListener *delegatingListener = new DelegatingStatusListener();
    Client client = voltdb::Client::create(ClientConfig( username, password, delegatingListener, sha));
    client.createConnection(hostname, port);
    boost::shared_ptr<ClientStuff> stuff(new ClientStuff(client, identifier, delegatingListener));
    stuff->m_listener->m_listener = listener;
    clients->push_back(stuff);
    return client;
}
/*
 * Cleanup function used by thread local ptr to a list of clients
 * that were borrowed from the pool. It unsets the listener and returns the client
 * to the pool.
 */
void cleanupOnScriptEnd(void *ptr) {
    if (gPool != NULL) {
        LockGuard guard(gPool->m_lock);
        ClientSet *clients = reinterpret_cast<ClientSet*>(ptr);
        if (clients != NULL) {
            boost::scoped_ptr<ClientSet> guard(clients);
            for(ClientSet::iterator i = clients->begin(); i != clients->end(); i++) {
                (*i)->m_listener->m_listener = NULL;
                gPool->m_clients[(*i)->m_identifier].push_back(*i);
            }
            pthread_setspecific(gPool->m_borrowedClients, NULL);
        }
    }
}
void ConnectionPool::closeClientConnection(Client client) throw (voltdb::Exception) {
    LockGuard guard(m_lock);
    ClientSet *clients = reinterpret_cast<ClientSet*>(pthread_getspecific(m_borrowedClients));
    if (clients == NULL) {
        //No clients closing a stale object or not owned by this thread.
        return;
    }

    for (ClientSet::iterator i = clients->begin(); i != clients->end(); i++) {
        if ((*i)->m_client == client) {
            client.close();
            (*i)->m_listener->m_listener = NULL;
            clients->erase(i);
            return;
        }
    }
}
Exemple #5
0
/**
 * getProjectList generates a list of projects on this server, each list (vector) item is 
 * actually a pinfo (project info) object, the list does NOT contain all projects, but
 * only contains projects relevant to the binary that is currently loaded in IDA
 * @param phash the IDA generated hash that is unique among the analysis files
 * @return a vector of project info objects for the provided phash
 */
vector<ProjectInfo*> *BasicConnectionManager::getProjectList(const string &phash) {
   vector<ProjectInfo*> *plist;
   //build a basic mode project list
   Basic_it bi = basicProjects.find(phash);
   if (bi != basicProjects.end()) {
      plist = (*bi).second;
   }
   else {
      plist = new vector<ProjectInfo*>;
   }
   for (Info_it it = plist->begin(); it != plist->end(); it++) {
      ClientSet *cs = projects.get((*it)->lpid);
      if (cs != NULL) {
         (*it)->connected = cs->size();
      }
   }
   return plist;
}
void ConnectionPool::returnClient(Client client) throw (voltdb::Exception) {
    LockGuard guard(m_lock);
    ClientSet *clients = reinterpret_cast<ClientSet*>(pthread_getspecific(m_borrowedClients));
    if (clients == NULL) {
        throw MisplacedClientException();
    }

    for (ClientSet::iterator i = clients->begin(); i != clients->end(); i++) {
        if ((*i)->m_client == client) {
            (*i)->m_listener->m_listener = NULL;
            m_clients[(*i)->m_identifier].push_back(*i);
            clients->erase(i);
            return;
        }
    }

    throw MisplacedClientException();
}
Exemple #7
0
/**
 * joinProject joings a particular client to a project so that it can participate in collabREation
 * @param c the client attempting to join
 * @param lpid the local project id of the project on this server
 * @return 0 on success, negative value on failure
 */
int DatabaseConnectionManager::joinProject(Client *c, uint32_t lpid) {
   int rval = -1;

   bool foundPid = false;

   uint32_t tpid = htonl(lpid);
   static const int plens[1] = {sizeof(tpid)};
   static const int pformats[1] = {1};

   const char * const parms[1] = {(char*)&tpid};

#ifdef DEBUG
   log(LINFO4, "trying to join project %u\n", lpid);
#endif
   sem_wait(&fpbp_sem);
   PGresult *rset = PQexecPrepared(dbConn, "findProjectByPid",
                       1, //int nParams,   size of arrays that follow
                       parms, //parms,  //const char * const *paramValues, array of string values
                       plens, //const int *paramLengths,
                       pformats, //const int *paramFormats,
                       1); //int resultFormat); 0 == text, 1 == binary
   sem_post(&fpbp_sem);

   ExecStatusType qres = PQresultStatus(rset);
   //expecting a single row returned
   if (qres != PGRES_TUPLES_OK || PQntuples(rset) != 1) {
      log(LSQL, "findProjectByPid: %s\n", PQerrorMessage(dbConn));
   }
   else {
      uint32_t proto = ntohl(*(uint32_t*)PQgetvalue(rset, 0, 10));
      if (proto == PROTOCOL_VERSION) {
         const char *hash = PQgetvalue(rset, 0, 1);

         uint64_t snapupdateid = ntohll(*(uint64_t*)PQgetvalue(rset, 0, 3));
   //      logln(LDEBUG, "in joinProject: " + lpid + " " + hash + " " + snapupdateid + " " + rs.getString(5) + " " + rs.getString(7));
         if (snapupdateid > 0) {  //pid is a snapshot pid
            //this should now be an error condition

            //logln(LINFO4, "Attempt to join snapshot " + lpid + " forking instead");
            //return forkProject(c, rs.getLong(4), rs.getString(7) + " + " + rs.getString(5));
            c->send_error("can't join a snapshot, you MUST fork a snapshot");
            log(LERROR, "attempted to join a snapshop instead of forking\n");
            return -1;
         }
         c->setPid(lpid);
         c->setHash(hash);

         const char *gpid = PQgetvalue(rset, 0, 2);
         c->setGpid(gpid);

         const char *owner = PQgetvalue(rset, 0, 9);
         const char *desc = PQgetvalue(rset, 0, 4);
         const char *pdesc = PQgetvalue(rset, 0, 6);
         uint32_t parent = ntohl(*(uint32_t*)PQgetvalue(rset, 0, 5));

         Project *pinfo;
         sem_wait(&map_sem);
         map<uint32_t,Project*>::iterator pi = pid_project_map.find(lpid);
         if (pi != pid_project_map.end()) {
            pinfo = (*pi).second;
         }
         else {
            pinfo = new Project(lpid, "");
            pid_project_map[lpid] = pinfo;
         }
         sem_post(&map_sem);

         //now make sure all project info is consistent with database, even if Project record already existed
         pinfo->desc = desc;
         pinfo->gpid = gpid;
         pinfo->hash = hash;
         pinfo->parent = parent;
         pinfo->pdesc = pdesc;
         pinfo->snapupdateid = snapupdateid;
         pinfo->pub = ntohll(*(uint64_t*)PQgetvalue(rset, 0, 7));
         pinfo->sub = ntohll(*(uint64_t*)PQgetvalue(rset, 0, 8));
         pinfo->owner = owner;
         pinfo->proto = proto;
         ClientSet *cs = projects.get(lpid);
         pinfo->connected = cs ? cs->size() : 0;

         if (c->getUser() == owner) { //project owner gets full perms, regardless of user, project, or requested perms
            log(LINFO3, "Project Owner joined! yay!");
            c->setPub(FULL_PERMISSIONS);
            c->setSub(FULL_PERMISSIONS);
         }
         else { //effective permissions are user perms ANDed with project perms ANDed with the perms requested by the user
            c->setPub(pinfo->pub & c->getUserPub() & c->getReqPub());
            c->setSub(pinfo->sub & c->getUserSub() & c->getReqSub());
         }

         foundPid = true;
      }
   }
   PQclear(rset);

   if (foundPid) {
      projects.addClient(c);
      rval = 0;
   }
   else {
//      log(LERROR, "ERROR: attempt to join a non-existant project: %u\n", lpid);
   }

   return rval;
}
Exemple #8
0
/**
 * getProjectList generates a list of projects on this server, each list (vector) item is
 * actually a pinfo (project info) object, the list does NOT contain all projects, but
 * only contains projects relevant to the binary that is currently loaded in IDA
 * @param phash the IDA generated hash that is unique among the analysis files
 * @return a vector of project info objects for the provided phash
 */
vector<const Project*> *DatabaseConnectionManager::getProjectList(const string &phash) {
   vector<const Project*> *plist = new vector<const Project*>;

   static const int plens[1] = {0};
   static const int pformats[1] = {0};

   const char * const parms[1] = {phash.c_str()};

   sem_wait(&fpbh_sem);
   PGresult *rset = PQexecPrepared(dbConn, "findProjectsByHash",
                       1, //int nParams,   size of arrays that follow
                       parms, //parms,  //const char * const *paramValues, array of string values
                       plens, //const int *paramLengths,
                       pformats, //const int *paramFormats,
                       1); //int resultFormat); 0 == text, 1 == binary
   sem_post(&fpbh_sem);

   ExecStatusType qres = PQresultStatus(rset);
   if (qres != PGRES_TUPLES_OK) {
      log(LSQL, "findProjectsByHash: %s\n", PQerrorMessage(dbConn));
   }
   else {
      int rows = PQntuples(rset);
      for (int i = 0; i < rows; i++) {
         uint32_t proto = ntohl(*(uint32_t*)PQgetvalue(rset, i, 10));
         if (proto != PROTOCOL_VERSION) {
            continue;
         }
         uint32_t lpid = ntohl(*(uint32_t*)PQgetvalue(rset, i, 0));
         char *desc = PQgetvalue(rset, i, 3);
         int32_t parent = -1;
         if (!PQgetisnull(rset, i, 4)) {
            parent = ntohl(*(int32_t*)PQgetvalue(rset, i, 4));
         }
         uint64_t snapupdateid = ntohll(*(uint64_t*)PQgetvalue(rset, i, 5));
         const char *pdesc = "";
         if (!PQgetisnull(rset, i, 6)) {
            pdesc = PQgetvalue(rset, i, 6);
         }

         Project *pinfo;
         sem_wait(&map_sem);
         map<uint32_t,Project*>::iterator pi = pid_project_map.find(lpid);
         if (pi != pid_project_map.end()) {
            pinfo = (*pi).second;
         }
         else {
            pinfo = new Project(lpid, "");
            pid_project_map[lpid] = pinfo;
         }
         sem_post(&map_sem);

         const char *gpid = PQgetvalue(rset, 0, 2);

         //now make sure all project info is consistent with database, even if Project record already existed
         pinfo->desc = desc;
         pinfo->gpid = gpid;
         pinfo->hash = phash;
         pinfo->parent = parent;
         pinfo->pdesc = pdesc;
         pinfo->snapupdateid = snapupdateid;
         pinfo->pub = ntohll(*(uint64_t*)PQgetvalue(rset, i, 7));
         pinfo->sub = ntohll(*(uint64_t*)PQgetvalue(rset, i, 8));
         pinfo->owner = PQgetvalue(rset, i, 9);
         pinfo->proto = proto;
         ClientSet *cs = projects.get(lpid);
         pinfo->connected = cs ? cs->size() : 0;
         plist->push_back(pinfo);
      }
   }
   PQclear(rset);
   return plist;
}
Exemple #9
0
/**
 * getProject gets informatio related to a local project
 * @param pid the local pid of a project to get info on
 * @return a  project info object for the provided pid
 */
const Project *DatabaseConnectionManager::getProject(uint32_t pid) {
   Project *pinfo = NULL;

   static const int plens[1] = {4};
   static const int pformats[1] = {1};

   pid = htonl(pid);
   const char * const parms[1] = {(char*)&pid};

   sem_wait(&fpbp_sem);
   PGresult *rset = PQexecPrepared(dbConn, "findProjectByPid",
                       1, //int nParams,   size of arrays that follow
                       parms, //parms,  //const char * const *paramValues, array of string values
                       plens, //const int *paramLengths,
                       pformats, //const int *paramFormats,
                       1); //int resultFormat); 0 == text, 1 == binary
   sem_post(&fpbp_sem);

   ExecStatusType qres = PQresultStatus(rset);
   //expecting a single row returned
   if (qres != PGRES_TUPLES_OK || PQntuples(rset) != 1) {
      log(LSQL, "findProjectByPid: %s\n", PQerrorMessage(dbConn));
   }
   else {
      uint32_t proto = ntohl(*(uint32_t*)PQgetvalue(rset, 0, 10));
      if (proto == PROTOCOL_VERSION) {
         uint32_t lpid = ntohl(*(uint32_t*)PQgetvalue(rset, 0, 0));
         char *desc = PQgetvalue(rset, 0, 4);
         int32_t parent = -1;
         if (!PQgetisnull(rset, 0, 5)) {
            parent = ntohl(*(int32_t*)PQgetvalue(rset, 0, 5));
         }
         uint64_t snapupdateid = ntohll(*(uint64_t*)PQgetvalue(rset, 0, 3));
         const char *pdesc = "";
         if (!PQgetisnull(rset, 0, 6)) {
            pdesc = PQgetvalue(rset, 0, 6);
         }

         const char *hash = PQgetvalue(rset, 0, 1);
         const char *owner = PQgetvalue(rset, 0, 9);

         sem_wait(&map_sem);
         map<uint32_t,Project*>::iterator pi = pid_project_map.find(lpid);
         if (pi != pid_project_map.end()) {
            pinfo = (*pi).second;
         }
         else {
            pinfo = new Project(lpid, "");
            pid_project_map[lpid] = pinfo;
         }
         sem_post(&map_sem);

         const char *gpid = PQgetvalue(rset, 0, 2);

         //now make sure all project info is consistent with database, even if Project record already existed
         pinfo->desc = desc;
         pinfo->gpid = gpid;
         pinfo->hash = hash;
         pinfo->parent = parent;
         pinfo->pdesc = pdesc;
         pinfo->snapupdateid = snapupdateid;
         pinfo->pub = ntohll(*(uint64_t*)PQgetvalue(rset, 0, 7));
         pinfo->sub = ntohll(*(uint64_t*)PQgetvalue(rset, 0, 8));
         pinfo->owner = owner;
         pinfo->proto = proto;
         ClientSet *cs = projects.get(lpid);
         pinfo->connected = cs ? cs->size() : 0;
      }
   }
   PQclear(rset);
   return pinfo;
}
Exemple #10
0
int main(int argc, char ** argv)
{
	string data;
	stringstream buf;
	unsigned int i;
	
	Stats stats;
	ClientSet clients;
	SocketSet sockets;
	Switchboard switchboard;
	ArgumentSet arguments(argc, argv);

	if (arguments.isset("version") || arguments.isset("v"))
	{
		cout << PACKAGE_NAME << " version " << PACKAGE_VERSION << endl;
		return 0;
	}
	
	if (arguments.isset("help") || arguments.isset("h"))
	{
		cout << endl;
		cout << "usage: istatd [-a HOST] [-p PORT]" << endl;
		cout << endl;
		cout << "    -d                 run in background" << endl;
		cout << "    -h                 print this help text" << endl;
		cout << "    -v                 print version number" << endl;
		cout << endl;
		cout << "    -c FILE            custom config file location" << endl;
		cout << "    -a HOST            listen on this address" << endl;
		cout << "    -p PORT            listen on this port" << endl;
		cout << "    -u USER            change running user" << endl;
		cout << "    -g GROUP           change running group" << endl;
		cout << endl;
		cout << "    --pid=FILE         custom pid file location" << endl;
		cout << "    --cache=DIR        custom cache file location" << endl;
		cout << "    --socket=FILE      custom socket file location" << endl;
		cout << "    --code=CODE        custom lock code" << endl;
		cout << endl;
		return 0;
	}
	
	// Load and parse configuration
	Config config(arguments.get("c", CONFIG_FILE_PATH));
	
	config.parse();
	config.validate();
	
	// Load configuration properties from command line and config file
	bool arg_d = arguments.isset("d");
	string cf_network_addr = arguments.get("a", config.get("network_addr", "0.0.0.0"));
	string cf_network_port = arguments.get("p", config.get("network_port", "5109"));
	string cf_server_user = arguments.get("u", config.get("server_user", "istat"));
	string cf_server_group = arguments.get("g", config.get("server_group", "istat"));
	string cf_server_pid = arguments.get("pid", config.get("server_pid", ""));
	string cf_cache_dir = arguments.get("cache", config.get("cache_dir", "/var/cache/istat"));
	string cf_server_socket = arguments.get("socket", config.get("server_socket", "/tmp/istatd.sock"));
   
#ifdef HAVE_LIBKSTAT
	if(-1 == kstat_init()) return 1;
#endif
	
	Daemon unixdaemon(cf_server_pid, cf_server_socket, cf_cache_dir);
	Socket listener(cf_network_addr, to_int(cf_network_port));
	SignalResponder signalresponder(&sockets, &listener, &unixdaemon, &clients);
	
	::pn_signalresponder = &signalresponder;

	// Create socket, pid file and put in background if desired
	unixdaemon.create(arg_d, cf_server_user, cf_server_group);
	
	// Get old sessions from disk cache
	clients.read_cache(cf_cache_dir);
	
	// Clear cache of saved sessions
	if (arguments.isset("clear-sessions"))
	{
		clients.clear_cache();
		return 0;
	}

	signal(SIGHUP,  handler);
	signal(SIGUSR1, handler);
	signal(SIGINT,  handler);
	signal(SIGTERM, handler);
	signal(SIGPIPE, handler);

	if (!listener.listen()) return 1;
	
	sockets += listener;
	
	// Add disks for monitoring
	if (config.get("monitor_disk") != "")
	{
		// No array found. Add value given.
		stats.add_disk(config.get("monitor_disk").c_str());
	}
	else
	{
		// Array found. Add all values in the array.
		for (i = 0; i < config.get_property("monitor_disk").get_array_size(); i++)
		{
			stats.add_disk(config.get_property("monitor_disk").get_array(i).c_str());
		}
	}
	
	// Add network interfaces for monitoring
	if (config.get("monitor_net") != "")
	{
		// No array found. Add value given.
		stats.add_net(config.get("monitor_net").c_str());
	}
	else
	{
		// Array found. Add all values in the array.
		for (i = 0; i < config.get_property("monitor_net").get_array_size(); i++)
		{
			stats.add_net(config.get_property("monitor_net").get_array(i).c_str());
		}
	}
	
#ifdef HAVE_LIBSENSORS
	unsigned int sensor_num;
	struct sensor_data sensor_data;

	sensor_num = get_sensor_num();
	
	for (i = 0; i < sensor_num; i++)
	{
		get_sensor_data(i, &sensor_data);
		
		stats.add_sensor(&sensor_data);
	}
#endif

#ifdef  HAVE_QNAPTEMP
	struct sensor_data sensor_data;
	if (have_qnaptemp()) {
		get_qnaptemp(0, &sensor_data);
		stats.add_sensor(&sensor_data);
	}
#endif

	while (1)
	{
		stats.update_system_stats();
		
		if (sockets.get_status(1))
		{
			if (sockets == listener)
			{
				Socket new_socket(listener.accept());
				
				sockets += new_socket;
			}
			else
			{
				Socket active_socket(sockets.get_ready());
		
				if (active_socket.receive(data, 1024))
				{
					switchboard.parse(&sockets, &clients, &config, &active_socket, &stats, &arguments, data);
				}
				else
				{
					sockets -= active_socket;
				}
			}
		}
	}
	
	::pn_signalresponder = NULL;
	
	return 0;
}