#include #include #include #include #include #include #include #include #include #include #include "Kaid.h" #include "KaiEngine.h" #include "OrbStreamThread.h" #include "KaiItem.h" #include "ConfigFile.h" #include "StrUtils.h" using namespace std; COrbStreamThread::COrbStreamThread (CKaiEngine * cParent, CConfigFile * cConf) { m_bTerminate = true; m_bConnected = false; m_bAuthenticated = false; m_cParent = cParent; m_cParent->verbositylog(2,"THREAD","Orbital stream thread started..."); m_cConf = cConf; m_sBuffer = ""; m_cOrbClient = NULL; } COrbStreamThread::~COrbStreamThread () { m_cParent->verbositylog(2,"THREAD","Orbital stream thread stopped..."); m_bTerminate = true; m_bConnected = false; if (m_cOrbClient) delete m_cOrbClient; // WaitThread (); } void COrbStreamThread::SendOrbAuth () { try { string sAuth ("KAI_AUTHENTICATION;" + m_cConf->Username + ";" + m_cConf->Password + ";;"); sAuth += (char) 1; m_cOrbClient->SendASCII (sAuth.c_str ()); m_cParent->m_iUpOrbCount += sAuth.size(); } catch (...) { } } void COrbStreamThread::Start (IPAddress & OrbAddr) { try { m_cOrbClient = new TCPClientSocket (OrbAddr, m_cConf->OrbPort); long one=1; m_cOrbClient->SetSockOpt(SOL_SOCKET,SO_KEEPALIVE,&one,sizeof(one)); m_cParent->verbositylog(1,"ORBSTREAM","Orbital stream established..."); m_bConnected = true; m_bTerminate = false; SendOrbAuth (); LaunchThread (); } catch (...) { } } void COrbStreamThread::Stop () { if (m_cOrbClient) delete m_cOrbClient; } void * COrbStreamThread::Execute () { int iBytesTransferred, retval; char pcBuffer[2048]; vector < string > vsMsgs; SocketSet mySet; mySet += (SocketBase *) m_cOrbClient; while (!m_bTerminate) { try { retval = select ((int) mySet + 1, mySet, NULL, NULL, NULL); if (retval == -1) throw errClientError; iBytesTransferred = m_cOrbClient->RecvData (pcBuffer, sizeof (pcBuffer) - 1); if (m_bTerminate) throw errServerDown; if (iBytesTransferred > 0) { pcBuffer[iBytesTransferred] = 0; m_sRequest = pcBuffer; m_sBuffer += m_sRequest; while(m_sBuffer.find((char)1) != string::npos) { string chunk = headc(m_sBuffer, 0x01); m_sBuffer = m_sBuffer.substr(m_sBuffer.find((char)1) + 1); HandleOrbMsg (chunk); if (m_sAnswer != "") SendStream (m_sAnswer); } vsMsgs.clear (); } } catch (SocketException & excep) { m_cParent->verbositylog(1,"ORBSTREAM","Orbital stream lost..."); if (excep == SocketException::errNotConnected) { m_bConnected = false; m_bTerminate = true; raise(SIGTERM); return NULL; } else { } if(m_cParent->m_bAttached) m_cParent->SendClientResponse("KAI_CLIENT_DETACH;"); return NULL; } catch (ThreadExceptions & excep) { m_cParent->verbositylog(1,"ORBSTREAM","Orbital stream lost..."); m_bTerminate = true; return NULL; } } return NULL; } void COrbStreamThread::SendStream (string msg) { m_cParent->verbositylog(3,"ORBSTREAM","Sending Orb command: "+msg); msg += (char) 1; m_cOrbClient->SendData (msg.c_str (), msg.size ()); if(msg.substr(0, 9) == "KAI_CHAT;") { m_cParent->m_iUpChatCount += msg.size(); } else { m_cParent->m_iUpOrbCount += msg.size(); } } void COrbStreamThread::SendClientResponse (string resp) { if (m_cParent) m_cParent->SendClientResponse (resp); } void COrbStreamThread::HandleOrbMsg (string sRequest) { m_cParent->verbositylog(3,"ORBSTREAM","Sending Orb response: "+sRequest); // Too small? if (sRequest.size () < 2) return; // Verify 2nd char is ";" etc. char Opcode = sRequest.at (0); if (sRequest.at (1) != ';') return; vector < string > vsSegments; Tokenize (sRequest, vsSegments, ";"); if(Opcode == 'A') { m_cParent->m_iDownChatCount += sRequest.size(); } else { m_cParent->m_iDownOrbCount += sRequest.size(); } // Switch on Opcode switch (Opcode) { case 'A': // A chat packet - simple SendClientResponse ("KAI_CLIENT_CHAT;" + vsSegments[1] + ";" + vsSegments[2] + ";" + vsSegments[3] + ";"); break; case 'B': // Someone has joined the room SendClientResponse ("KAI_CLIENT_JOINS_CHAT;" + vsSegments[1] + ";" + vsSegments[2] + ";"); // Add him to our list? m_cParent->AddChatUser (vsSegments[1], vsSegments[2]); break; case 'C': // Someone has left the room SendClientResponse ("KAI_CLIENT_LEAVES_CHAT;" + vsSegments[1] + ";" + vsSegments[2] + ";"); // Remove him from our list? m_cParent->RemoveChatUser (vsSegments[1], vsSegments[2]); break; case '~': { // empty contact list!! if (vsSegments.size () > 1) { // Add all the messenger contacts for (unsigned int i = 1; i < vsSegments.size (); i++) { CMessengerItem *pcContact; pcContact = new CMessengerItem (); pcContact->m_sContactName = vsSegments[i]; m_cParent->m_cMessengerContacts. push_back (pcContact); SendClientResponse ("KAI_CLIENT_ADD_CONTACT;" + pcContact-> m_sContactName + ";"); Deliver (pcContact->m_sContactName, '6', m_cConf->Username, m_cParent->MyIP (). GetAddressString (), m_cParent->MyPort (), "", 0); } } SendClientResponse ("KAI_CLIENT_CONNECTED_MESSENGER;"); // Tell the client its now online (status) m_cParent->SendClientStatus ("XLink Kai is Online.."); } break; case '=': // Simply a profile - send to client SendClientResponse ("KAI_CLIENT_USER_PROFILE;" + vsSegments[1] + ";" + vsSegments[2] + ";" + vsSegments[3] + ";" + vsSegments[4] + ";" + vsSegments[5] + ";" + vsSegments[6] + ";" + vsSegments[7] + ";" + vsSegments[8] + ";"); break; case '#': // Set the case corrected username m_bAuthenticated = true; m_cParent->LoggedIn (vsSegments[1]); break; case '?': // Orb bad m_bAuthenticated = false; m_cParent->SendClientStatus ("Authentication Failed.."); SendClientResponse ("KAI_CLIENT_AUTHENTICATION_FAILED;"); break; case '+': // Subvector users update - straight to UI SendClientResponse ("KAI_CLIENT_SUB_VECTOR_UPDATE;" + vsSegments[1] + ";" + vsSegments[2] + ";" + vsSegments[3] + ";"); break; // TODO: Join next case on single case with iif case ')': // Bad password for arena - simply pass to UI SendClientResponse ("KAI_CLIENT_VECTOR_DISALLOWED;" + vsSegments[1] + ";The supplied password was incorrect.;"); break; case '(': // arena full - simply pass to UI SendClientResponse ("KAI_CLIENT_VECTOR_DISALLOWED;" + vsSegments[1] + ";The Arena is full.;"); break; case ']': // Specific response - simple 4ward SendClientResponse ("KAI_CLIENT_APP_SPECIFIC;" + vsSegments[1] + ";" + vsSegments[2] + ";"); break; case 'D': { // If it's not our vector - bail string b, sAux; b = vsSegments[1].substr (0, vsSegments[1].rfind ("/")); if (b != m_cParent->m_sCurrentArena) return; // Here is a possible sub vector - tell the client m_cParent->AddVector (vsSegments[1], vsSegments[2]); sAux = vsSegments[1] + ";" + vsSegments[3] + ";" + vsSegments[4] + ";" + vsSegments[5] + ";" + vsSegments[6] + ";"; if (vsSegments[2] == "1") { m_cParent-> SendClientResponse ("KAI_CLIENT_USER_SUB_VECTOR;" + sAux + vsSegments[7] + ";"); } else { m_cParent-> SendClientResponse ("KAI_CLIENT_SUB_VECTOR;" + sAux); } } break; case 'K': // Simply send to client { string relay = "KAI_CLIENT_SPECIFIC_COUNT;" + vsSegments[1] + ";" + vsSegments[2] + ";" + vsSegments[3] + ";"; SendClientResponse (relay); } break; case 'E': // Not us if (vsSegments[1] == m_cConf->Username) return; // Someone has joined the vector SendClientResponse ("KAI_CLIENT_JOINS_VECTOR;" + vsSegments[2] + ";"); // If it's not our vector - bail if (vsSegments[1] != m_cParent->m_sCurrentArena) return; // Add the guy m_cParent->AddArenaContact (vsSegments[2], vsSegments[3], atoi (vsSegments[4].c_str ()), vsSegments[5], atoi (vsSegments[6].c_str ())); break; case 'F': // If it's not our vector - bail if (vsSegments[1] != m_cParent->m_sCurrentArena) return; // Someone has left the vector SendClientResponse ("KAI_CLIENT_LEAVES_VECTOR;" + vsSegments[2] + ";"); // Remove the guy m_cParent->RemoveArenaContact (vsSegments[2]); break; case 'G': { // Attached to vector sucessfully m_cParent->m_cArenaContacts.clear (); // Empty users m_cParent->m_sVectors.clear (); // Empty subs gettimeofday (&m_cParent->m_tvLastVectorChange, NULL); // Record switch m_cParent->m_sCurrentArena = vsSegments[1]; m_cParent->m_iRoutingMode = atoi(vsSegments[3].c_str()); m_cParent->m_iBusyLevel = atol(vsSegments[4].c_str()); // Echo to client string CanCreate = (vsSegments[2].empty() ? "0" : vsSegments[2]); m_cParent->m_sLastVectorChange = "KAI_CLIENT_VECTOR;" + vsSegments[1] + ";" + CanCreate + ";"; SendClientResponse (m_cParent->m_sLastVectorChange); if (vsSegments[1].length()>m_cConf->Username.length()+5 && vsSegments[1].substr( vsSegments[1].length()-(m_cConf->Username.length()+1) ) == "/"+m_cConf->Username) { // It's our room.. m_cParent->m_iArenaStatus=2; } else { // It's not our room.. m_cParent->m_iArenaStatus=1; } SendClientResponse ("KAI_CLIENT_ARENA_STATUS;" + Str(m_cParent->m_iArenaStatus) + ";" + Str(m_cParent->m_iArenaMyPlayers) + ";"); break; } case 'H': // Echo to client SendClientResponse ("KAI_CLIENT_VECTOR_DISALLOWED;" + vsSegments[1] + ";" + vsSegments[2] + ";"); break; case '8': if (m_cParent->FindUser (vsSegments[1])) m_cParent->SetOfflineContact (vsSegments[1]); break; case '9': { // A user vector supposedly in this arena is dead - if so, remove it from here and from the UI string b (vsSegments[1]. substr (0, vsSegments[1].rfind ("/"))); if (m_cParent->m_sCurrentArena == b) { // Its our bit - lets maime it up :D m_cParent->RemoveVector (vsSegments[1]); SendClientResponse ("KAI_CLIENT_REMOVE_SUB_VECTOR;" + vsSegments[1] + ";"); } break; } case 'l': // An update of the privileges on an arena - simple store // and forward to the client. SendClientResponse ("KAI_CLIENT_MODERATOR_PRIVILEGES;" + vsSegments[1] + ";" + vsSegments[2] + ";"); m_cParent->m_sStoredPrivs="KAI_CLIENT_MODERATOR_PRIVILEGES;" + vsSegments[1] + ";" + vsSegments[2] + ";"; break; case 'r': // Admin list update m_cParent->m_sStoredAdmins = vsSegments[1]; SendClientResponse ("KAI_CLIENT_ADMIN_PRIVILEGES;" + vsSegments[1] + ";"); break; case '/': { // Successful contact add CMessengerItem *newGuy; newGuy = new CMessengerItem (); newGuy->m_sContactName = vsSegments[1]; SendClientResponse ("KAI_CLIENT_ADD_CONTACT;" + vsSegments[1] + ";"); m_cParent->m_cMessengerContacts.push_back (newGuy); Deliver (vsSegments[1], '6', m_cConf->Username, m_cParent->MyIP ().GetAddressString (), m_cParent->MyPort (), "", 0); break; } case '|': { // A contact remove happened - tell the client he's gone, then remove Deliver (vsSegments[1], '8', m_cConf->Username, m_cParent->MyIP ().GetAddressString (), m_cParent->MyPort (), "", 0); m_cParent->DeleteContact (vsSegments[1]); break; } case '6': { /* Directive 6 - someone has sent and "Are you here?" request * Well, we obviously are, so lets tell them that then, * after making sure theyre in our list */ // Check if they're one of our boys - bail if not if (!m_cParent->FindUser (vsSegments[1])) break; // OK - he's good.. send him msg7 string output; char myport[5]; sprintf (myport, "%d", m_cParent->MyPort ()); output = "KAI_DELIVER;" + vsSegments[1] + ";7;" + m_cConf->Username + ";" + m_cParent->MyIP ().GetAddressString () + ";" + myport + ";;;"; SendStream (output); // We can also add him to our contacts - coz he's obviously online now int port, deepport; port = (vsSegments[3] == "") ? 0 : atoi (vsSegments[3].c_str ()); deepport = (vsSegments[5] == "") ? 0 : atoi (vsSegments[5].c_str ()); m_cParent->SetOnlineContact (vsSegments[1], vsSegments[2], port, vsSegments[4], deepport); break; } case '7': { /* One of the guys we asked is here - so lets check * him then add him */ int port; port = (vsSegments[3] == "") ? 0 : atoi (vsSegments[3].c_str ()); // deepport = (vsSegments[5] == "") ? 0 : atoi(vsSegments[5].c_str()); m_cParent->SetOnlineContact (vsSegments[1], vsSegments[2], port, "", 0); break; } case '&': // Its an avatar for our client m_cParent->SendClientResponse ("KAI_CLIENT_AVATAR;" + vsSegments[1] + ";" + vsSegments[2] + ";"); break; case 'o': m_cParent->m_sOurOrbName = vsSegments[1]; break; } } void COrbStreamThread::Deliver (string contact, char opcode, string username, string myip, int myport, string deepip, int deepport) { string output; output = "KAI_DELIVER;" + contact + ";" + opcode + ";" + username + ";" + myip + ";" + Str (myport) + ";" + deepip + ";" + Str (deepport) + ";"; SendStream (output); }