I am currently writing a multi-threaded C++ server using Poco and am now at the point where I need to be keeping information on which users are connected, how many connections each of them have, and given it is a proxy server, where each of those connections are proxying through to.
For this purpose I have created a ServerStats class which holds an STL list of ServerUser objects. The ServerStats class includes functions which can add and remove objects from the list as well as find a user in the list an return a pointer to them so I can access member functions within any given ServerUser object in the list.
The ServerUser class contains an STL list of ServerConnection objects and much like the ServerStats class it contains functions to add, remove and find elements within this list.
Now all of the above is working but I am now trying to make it threadsafe.
I have defined a Poco::FastMutex within the ServerStats class and can lock/unlock this in the appropriate places so that STL containers are not modified at the same time as being searched for example. I am however having an issue setting up mutexes within the ServerUser class and am getting the following compiler error:
/root/poco/Foundation/include/Poco/Mutex.h: In copy constructor âServerUser::ServerUser(const ServerUser&)â: src/SocksServer.cpp:185:
instantiated from âvoid __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = ServerUser]â /usr/include/c++/4.4/bits/stl_list.h:464: instantiated from âstd::_List_node<_Tp>* std::list<_Tp, _Alloc>::_M_create_node(const _Tp&) [with _Tp = ServerUser, _Alloc = std::allocator]â /usr/include/c++/4.4/bits/stl_list.h:1407: instantiated from âvoid std::list<_Tp, _Alloc>::_M_insert(std::_List_iterator<_Tp>, const _Tp&) [with _Tp = ServerUser, _Alloc = std::allocator]â /usr/include/c++/4.4/bits/stl_list.h:920: instantiated from âvoid std::list<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = ServerUser, _Alloc = std::allocator]â src/SocksServer.cpp:301:
instantiated from here /root/poco/Foundation/include/Poco/Mutex.h:164: error: âPoco::FastMutex::FastMutex(const Poco::FastMutex&)â is private src/SocksServer.cpp:185: error: within this context In file included from /usr/include/c++/4.4/x86_64-linux-gnu/bits/c++allocator.h:34, from /usr/include/c++/4.4/bits/allocator.h:48, from /usr/include/c++/4.4/string:43, from /root/poco/Foundation/include/Poco/Bugcheck.h:44, from /root/poco/Foundation/include/Poco/Foundation.h:147, from /root/poco/Net/include/Poco/Net/Net.h:45, from /root/poco/Net/include/Poco/Net/TCPServerParams.h:43, from src/SocksServer.cpp:1: /usr/include/c++/4.4/ext/new_allocator.h: In member function âvoid __gnu_cxx::new_allocator<_Tp>::construct(_Tp*, const _Tp&) [with _Tp = ServerUser]â: /usr/include/c++/4.4/ext/new_allocator.h:105: note: synthesized method âServerUser::ServerUser(const ServerUser&)â first required here src/SocksServer.cpp: At global scope: src/SocksServer.cpp:118: warning: âstd::string getWord(std::string)â defined but not used make: * [/root/poco/SocksServer/obj/Linux/x86_64/debug_shared/SocksServer.o] Error 1
The code for the ServerStats, ServerUser and ServerConnection classes is below:
class ServerConnection
{
public:
bool continue_connection;
int bytes_in;
int bytes_out;
string source_address;
string destination_address;
ServerConnection()
{
continue_connection = true;
}
~ServerConnection()
{
}
};
class ServerUser
{
public:
string username;
int connection_count;
string client_ip;
ServerUser()
{
}
~ServerUser()
{
}
ServerConnection* addConnection(string source_address, string destination_address)
{
//FastMutex::ScopedLock lock(_connection_mutex);
ServerConnection connection;
connection.source_address = source_address;
connection.destination_address = destination_address;
client_ip = getWord(source_address, ":");
_connections.push_back(connection);
connection_count++;
return &_connections.back();
}
void removeConnection(string source_address)
{
//FastMutex::ScopedLock lock(_connection_mutex);
for(list<ServerConnection>::iterator it = _connections.begin(); it != _connections.end(); it++)
{
if(it->source_address == source_address)
{
it = _connections.erase(it);
connection_count--;
}
}
}
void disconnect()
{
//FastMutex::ScopedLock lock(_connection_mutex);
for(list<ServerConnection>::iterator it = _connections.begin(); it != _connections.end(); it++)
{
it->continue_connection = false;
}
}
list<ServerConnection>* getConnections()
{
return &_connections;
}
private:
list<ServerConnection> _connections;
//UNCOMMENTING THIS LINE BREAKS IT:
//mutable FastMutex _connection_mutex;
};
class ServerStats
{
public:
int current_users;
ServerStats()
{
current_users = 0;
}
~ServerStats()
{
}
ServerUser* addUser(string username)
{
FastMutex::ScopedLock lock(_user_mutex);
for(list<ServerUser>::iterator it = _users.begin(); it != _users.end(); it++)
{
if(it->username == username)
{
return &(*it);
}
}
ServerUser newUser;
newUser.username = username;
_users.push_back(newUser);
current_users++;
return &_users.back();
}
void removeUser(string username)
{
FastMutex::ScopedLock lock(_user_mutex);
for(list<ServerUser>::iterator it = _users.begin(); it != _users.end(); it++)
{
if(it->username == username)
{
_users.erase(it);
current_users--;
break;
}
}
}
ServerUser* getUser(string username)
{
FastMutex::ScopedLock lock(_user_mutex);
for(list<ServerUser>::iterator it = _users.begin(); it != _users.end(); it++)
{
if(it->username == username)
{
return &(*it);
}
}
return NULL;
}
private:
list<ServerUser> _users;
mutable FastMutex _user_mutex;
};
Now I have never used C++ for a project of this size or mutexes for that matter so go easy please :)
Firstly, can anyone tell me why the above is causing a compiler error?
Secondly, can anyone suggest a better way of storing the information I require? Bear in mind that I need to update this info whenever connections come or go and it needs to be global to the whole server.