Shadowrun: Awakened 29 September 2011 - Build 871
Public Member Functions | Static Public Member Functions | Static Private Attributes
SraNetwork::ChatServer Class Reference

#include <ChatServer.h>

List of all members.

Public Member Functions

 ChatServer (void)
 ~ChatServer (void)

Static Public Member Functions

static void ClientConnectionThread ()
static void ServerConnectionThread ()

Static Private Attributes

static unsigned int lastUsedClientId = 0
static
tbb::concurrent_hash_map
< unsigned int, std::vector
< int > > 
m_mChatGroupMap
static
tbb::concurrent_hash_map
< unsigned int, std::vector
< RakString > > 
m_mPendingUserMessages
static
tbb::concurrent_hash_map
< unsigned int, std::vector
< int > > 
m_mUserChatGroupMap
static
tbb::concurrent_hash_map
< SystemAddress, unsigned int,
SystemAddressCompare
m_vChatUserRegister
static const int MAX_NUMBER_OF_CHAT_GROUPS = 2048
static const int MAX_NUMBER_OF_CHAT_GROUPS_PER_USER = 16
static const int MAX_NUMBER_OF_USERS_PER_GROUP = 2048

Detailed Description

Definition at line 50 of file ChatServer.h.


Constructor & Destructor Documentation

SraNetwork::ChatServer::ChatServer ( void  )

Definition at line 17 of file ChatServer.cpp.

    {
    }
SraNetwork::ChatServer::~ChatServer ( void  )

Definition at line 21 of file ChatServer.cpp.

    {
    }

Member Function Documentation

void SraNetwork::ChatServer::ClientConnectionThread ( ) [static]

Definition at line 25 of file ChatServer.cpp.

References SraNetwork::SendMessageToChannelPacket::channelId, SraNetwork::CHAT_CLIENT_PORT, SraNetwork::CLIENT_CHAT_PORT, RakNet::Packet::data, RakNet::RakPeerInterface::DeallocatePacket(), SraNetwork::SendMessageToChannelPacket::Deserialize(), SraNetwork::SraPacket::Deserialize(), SraNetwork::ID_CHAT_CHANNEL_MESSAGE, ID_NEW_INCOMING_CONNECTION, RakNet::Packet::length, m_mChatGroupMap, m_mUserChatGroupMap, SraNetwork::m_rClientInterface, m_vChatUserRegister, MEDIUM_PRIORITY, SraNetwork::SraPacket::opCode, RakNet::RakPeerInterface::Receive(), RELIABLE_ORDERED, RakNet::RakPeerInterface::Send(), RakNet::RakPeerInterface::SetMaximumIncomingConnections(), RakNet::RakPeerInterface::Startup(), stream, and RakNet::Packet::systemAddress.

Referenced by main().

    {
        printf("Listening for chat clients ..... \n");
        RakPeerInterface *m_rClientInterface = RakPeerInterface::GetInstance();
        SocketDescriptor chatSocket(SraNetwork::CHAT_CLIENT_PORT, 0);
        m_rClientInterface->Startup(2, &chatSocket, 1);
        m_rClientInterface->SetMaximumIncomingConnections(2); //2 ?

        bool running = true;
        while (running)
        {
            Packet* m_pPacket = m_rClientInterface->Receive();
            if (m_pPacket) 
            {
                if (m_pPacket->data[0] == ID_NEW_INCOMING_CONNECTION) 
                {
                    printf("Chat client connected\n");
                }
                else
                {
                    // Now for our own packets. 
                    BitStream stream(m_pPacket->data, m_pPacket->length, false);
                    SraPacket sraPacket;
                    sraPacket.Deserialize(&stream);
                    if (sraPacket.opCode == ID_CHAT_CHANNEL_MESSAGE)
                    {
                        SendMessageToChannelPacket chatPacket;
                        chatPacket.Deserialize(&stream);

                        printf("Client sent a message to channel %d\n", chatPacket.channelId);

                        // TODO: Maybe we should move this to a separated class, like
                        // the world server message pump ...

                        // First we have to check if the channel exists and if the user is in it.
                        // We will do this by simply checking the user chat group list:
                        tbb::concurrent_hash_map<SystemAddress, unsigned int, SystemAddressCompare>::const_accessor acc;
                        unsigned int clientID = -1;
                        if (m_vChatUserRegister.find(acc, m_pPacket->systemAddress) ) 
                        {
                            // We already have create an id for this client, so use it
                            clientID = acc->second;
                        } else
                        {
                            printf("User is not registered, ignoring the message\n");
                        }
                        
                        
                        // Whoa this is ugly and will suck a lot of performance....find a better solution!!!

                        // Search for the channel:
                        tbb::concurrent_hash_map<unsigned int, std::vector<int>>::const_accessor userGroupsAcc;
                        // Get user channel list.
                        if (m_mUserChatGroupMap.find(userGroupsAcc, clientID))
                        {
                            // now find the channel id :
                            bool found = false;
                            for (std::vector<int>::const_iterator vit = userGroupsAcc->second.begin(); vit != userGroupsAcc->second.end(); ++vit)
                            {
                                if ( *vit == chatPacket.channelId)
                                {
                                    printf("Found channel\n");
                                    found = true;
                                    break;
                                }
                            }
                            if (found)
                            {
                                // Ok the user is in this channel, so now send a message to all clients
                                // that are in this channel:
                                tbb::concurrent_hash_map<unsigned int, std::vector<int>>::const_accessor chatGroupAcc;
                                if (m_mChatGroupMap.find(chatGroupAcc, chatPacket.channelId))
                                {
                                    // iterate through all ids:
                                    for (std::vector<int>::const_iterator userIt = chatGroupAcc->second.begin(); userIt != chatGroupAcc->second.end(); ++userIt)
                                    {
                                        // ok nooow we have to get the corresponding system address from this index:
                                        int userID = *userIt;
                                        for (
                                            tbb::concurrent_hash_map<SystemAddress, unsigned int, SystemAddressCompare>::iterator it = m_vChatUserRegister.begin(); 
                                            it != m_vChatUserRegister.end(); ++it)
                                        {
                                            if ( it->second == *userIt)
                                            {
                                                printf("Sending the message to a user\n");
                                                SystemAddress addr = it->first;
                                                addr.SetPortA(CLIENT_CHAT_PORT);
                                                uint32_t sent = 
                                                    m_rClientInterface->Send(&stream, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, addr, false);
                                                printf("I have sent %d bytes", sent);
                                                // Skip the rest of the entries.
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            m_rClientInterface->DeallocatePacket(m_pPacket);
            Sleep(10);
        }
    }
void SraNetwork::ChatServer::ServerConnectionThread ( ) [static]

Definition at line 131 of file ChatServer.cpp.

References SraNetwork::JoinChannelPacket::channelId, SraNetwork::CHAT_SERVER_PORT, SraNetwork::JoinChannelPacket::clientAddress, RakNet::RakPeerInterface::Connect(), RakNet::Packet::data, RakNet::RakPeerInterface::DeallocatePacket(), SraNetwork::JoinChannelPacket::Deserialize(), SraNetwork::SraPacket::Deserialize(), SraNetwork::ID_CHAT_CHANNEL_REGISTER, ID_CONNECTION_ATTEMPT_FAILED, ID_CONNECTION_LOST, ID_CONNECTION_REQUEST_ACCEPTED, lastUsedClientId, RakNet::Packet::length, m_mChatGroupMap, m_mUserChatGroupMap, m_rServerInterface, m_vChatUserRegister, MAX_NUMBER_OF_CHAT_GROUPS, MAX_NUMBER_OF_CHAT_GROUPS_PER_USER, MAX_NUMBER_OF_USERS_PER_GROUP, MEDIUM_PRIORITY, SraNetwork::SraPacket::opCode, RakNet::RakPeerInterface::Receive(), RELIABLE_ORDERED, RakNet::RakPeerInterface::Send(), SraNetwork::JoinChannelPacket::Serialize(), SraNetwork::SERVER_CHAT_PORT, RakNet::RakPeerInterface::Shutdown(), RakNet::RakPeerInterface::Startup(), stream, RakNet::UNASSIGNED_SYSTEM_ADDRESS, and SraNetwork::WORLD_SERVER_ADDR.

Referenced by main().

    {
        //Connect to world server
        RakPeerInterface *m_rServerInterface = RakPeerInterface::GetInstance();
        SocketDescriptor chatSocket(SraNetwork::CHAT_SERVER_PORT, 0);
        m_rServerInterface->Startup(1, &chatSocket, 1);
        m_rServerInterface->Connect(SraNetwork::WORLD_SERVER_ADDR, SraNetwork::SERVER_CHAT_PORT, 0, 0, 0);

        printf("Connecting to world server\n");

        bool done = false; 
        bool result = false; //don't return in loop so we can shut down RakNet before exiting
        while (!done) //Block while connecing
        {
            Packet* m_pPacket = m_rServerInterface->Receive();
            if (m_pPacket) 
            {
                if (m_pPacket->data[0] == ID_CONNECTION_REQUEST_ACCEPTED) 
                {
                    result = true;
                } 
                else if (m_pPacket->data[0] == ID_CONNECTION_ATTEMPT_FAILED)
                {
                    printf("Failed: connection attempt failed\n");
                } else 
                {
                    printf("Failed: Unknown opcode %d\n", m_pPacket->data[0]);
                }
                m_rServerInterface->DeallocatePacket(m_pPacket);
                m_pPacket = 0;
                done = true;
            }
            Sleep(10);
        }
        if (!result)
        {
            printf("Failed to connect to world, exiting now\n");
            m_rServerInterface->Shutdown(0);
            return;
        }
        printf("Connection established, waiting for chat connections\n");

        bool running = true; //maybe we do not need this, but i don't like while(1) :P
        while (running)
        {
            Packet* m_pPacket = m_rServerInterface->Receive();
            if (m_pPacket) 
            {
                if ( m_pPacket->data[0] == ID_CONNECTION_LOST ) {
                    // Do we really need this hard connection to the world?
                    // we could also run without it.
                    printf("Lost connection to world server ! Shutting down now\n");
                    running = false;
                } 
                else
                {
                    // Now for our own packets. 
                    BitStream stream(m_pPacket->data, m_pPacket->length, false);
                    SraPacket sraPacket;
                    sraPacket.Deserialize(&stream);
                    if (sraPacket.opCode == ID_CHAT_CHANNEL_REGISTER)
                    {
                        bool success = true;
                        JoinChannelPacket joinPacket;
                        joinPacket.Deserialize(&stream);

                        printf("Received chat channel registration message for channel %d", joinPacket.channelId);

                        tbb::concurrent_hash_map<SystemAddress, unsigned int, SystemAddressCompare>::accessor acc;
                        unsigned int clientID = -1;
                        if (m_vChatUserRegister.find(acc, joinPacket.clientAddress) ) 
                        {
                            // We already have create an id for this client, so use it
                            clientID = acc->second;
                        } else
                        {
                            // Well we coooouuuld check if the modded value
                            // is already in use, but UINT_MAX is 2^32 wich should be 
                            // large enough to be quite sure this should not happen...
                            lastUsedClientId = (lastUsedClientId+1)%UINT_MAX;
                            clientID = lastUsedClientId;
                            m_vChatUserRegister.insert( acc, joinPacket.clientAddress);
                            acc->second = clientID;
                        }
                        printf("User has clientID %d ", clientID);
                        // Add requested channel to the users list of channels.
                        tbb::concurrent_hash_map<unsigned int, std::vector<int>>::accessor userGroupsAcc;
                        if (m_mUserChatGroupMap.find(userGroupsAcc, joinPacket.channelId))
                        {
                            // if we already have a list for this user, 
                            // so simply add the new channel.
                            if (userGroupsAcc->second.size() <= MAX_NUMBER_OF_CHAT_GROUPS_PER_USER)
                            {
                                printf("Adding channel to user\n");
                                userGroupsAcc->second.push_back(joinPacket.channelId);
                            } 
                            else 
                            {
                                printf("Error: User exceeded the max number of chat groups!\n");
                                success = false;
                            }
                        } 
                        else 
                        {
                            printf("Creating a new group list\n");
                            // if not, we need to create a new user list.
                            std::vector<int> userList;
                            userList.push_back(joinPacket.channelId);
                            m_mUserChatGroupMap.insert(userGroupsAcc, clientID);
                            userGroupsAcc->second = userList;
                        }

                        // Now we need to find the channel list the user wants to join
                        tbb::concurrent_hash_map<unsigned int, std::vector<int>>::accessor chatGroupsAcc;
                        if (m_mChatGroupMap.find(chatGroupsAcc, joinPacket.channelId))
                        {
                            // if we already the selected channel, 
                            // so simply add the user.
                            if (chatGroupsAcc->second.size() <= MAX_NUMBER_OF_USERS_PER_GROUP)
                            {
                                printf("Adding user to channel\n");
                                chatGroupsAcc->second.push_back(clientID);
                            }
                            else 
                            {
                                printf("Error: To many users in chat group\n");
                                success = false;
                            }
                        } 
                        else 
                        {
                            if (m_mChatGroupMap.size() <= MAX_NUMBER_OF_CHAT_GROUPS)
                            {
                                
                                printf("Creating new chat group\n");
                                // if not, we will create a new chat group
                                std::vector<int> userList;
                                userList.push_back(clientID);
                                m_mChatGroupMap.insert(chatGroupsAcc, joinPacket.channelId);
                                chatGroupsAcc->second = userList;
                            }
                            else 
                            {
                                printf("Error: Max number of chat groups exceeded\n");
                                success = false;
                            }
                        }

                        // After the joinig process has completed, we will sent a message
                        // to the user. Be sure to do this always at the end so a potential
                        // error will not send a return message.
                        if (success)
                        {
                            printf("Send success message to server/client \n");
                            // Send a message to the player that contains our ip 
                            JoinChannelPacket rp;
                            // This is used to indicate a success message.
                            rp.channelId = 0;
                            rp.clientAddress = joinPacket.clientAddress;
                            // This is kinda ugly: Because we don't have the socket 
                            // to the client, this message has to be sent back to the server
                            // and forwarded to the client.
                            BitStream bs;
                            rp.Serialize(&bs);
                            m_rServerInterface->Send(&bs, MEDIUM_PRIORITY, RELIABLE_ORDERED, 0, UNASSIGNED_SYSTEM_ADDRESS, true);
                        }
                    }
                }
            }
            m_rServerInterface->DeallocatePacket(m_pPacket);
            Sleep(10);
        }
    }

Member Data Documentation

unsigned int SraNetwork::ChatServer::lastUsedClientId = 0 [static, private]

Definition at line 79 of file ChatServer.h.

Referenced by ServerConnectionThread().

tbb::concurrent_hash_map< unsigned int, std::vector< int > > SraNetwork::ChatServer::m_mChatGroupMap [static, private]

Definition at line 76 of file ChatServer.h.

Referenced by ClientConnectionThread(), and ServerConnectionThread().

tbb::concurrent_hash_map< unsigned int, std::vector< RakString > > SraNetwork::ChatServer::m_mPendingUserMessages [static, private]

Definition at line 66 of file ChatServer.h.

tbb::concurrent_hash_map< unsigned int, std::vector< int > > SraNetwork::ChatServer::m_mUserChatGroupMap [static, private]

Definition at line 72 of file ChatServer.h.

Referenced by ClientConnectionThread(), and ServerConnectionThread().

tbb::concurrent_hash_map< SystemAddress, unsigned int, SystemAddressCompare > SraNetwork::ChatServer::m_vChatUserRegister [static, private]

Definition at line 62 of file ChatServer.h.

Referenced by ClientConnectionThread(), and ServerConnectionThread().

const int SraNetwork::ChatServer::MAX_NUMBER_OF_CHAT_GROUPS = 2048 [static, private]

Definition at line 82 of file ChatServer.h.

Referenced by ServerConnectionThread().

Definition at line 85 of file ChatServer.h.

Referenced by ServerConnectionThread().

const int SraNetwork::ChatServer::MAX_NUMBER_OF_USERS_PER_GROUP = 2048 [static, private]

Definition at line 88 of file ChatServer.h.

Referenced by ServerConnectionThread().


The documentation for this class was generated from the following files:

Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.

GNU Lesser General Public License 3 Sourceforge.net