Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

clientThread.cpp

Go to the documentation of this file.
00001 /********************************************************************
00002 Description:
00003 part of the 3Dsia project
00004 created: StonedBones, 31.1.2000
00005 
00006 History:
00007     date,   name,       changes,                    in funtion
00008     180400  StonedBones added dynamic packetlength
00009     310100  StonedBones created source
00010 
00011 ********************************************************************/
00012 
00013 #include <string.h>
00014 #include <pthread.h>
00015 #include <unistd.h>
00016 
00017 #include <stdio.h>
00018 
00019 #include "../common/intToChar.h"
00020 #include "../common/protocol.h"
00021 #include "../common/buffer.h"
00022 #include "../common/options.h"
00023 #include "../common/generic.h"
00024 #include "../common/communication.h"
00025 #include "../common/databaseAccess.h"
00026 
00027 #ifdef AUTHENTICATE_SHADOW
00028 #include "authentication/shadow/shadow.h"
00029 #endif
00030 
00031 #include "clientThread.h"
00032 #include "clientControlThread.h"
00033 #include "frontEnd.h"
00034 
00035 #include <odb/odatabase.h>
00036 #include <odb/generic.h>
00037 
00038 
00039 /*...................................................................
00040 Description: The Client Thread (CT)
00041 Args: CTArgs* args: various arguments (see header-file)
00042 Returns: <none>
00043 Created: StonedBones, 31.1.2000
00044 ToDo:
00045     270300, xandi, each functionality should be a function or a method of a class.. however..
00046 
00047 Comments:
00048     040400, xandi, maybe it would be useful not to register the user
00049                     using its name, but rather its socket; then
00050                     one user could log in several times (for whatever that would be good for)
00051 
00052 Changes:
00053     added PROT_REGISTER_ENTITY,             xandi, 250300
00054     added PROT_MATRIX_STUFF,                xandi, 250300
00055     added primitive object handling,        xandi, 270300
00056     added some pthread things,              xandi, 020400
00057     added a database access class.. very rudimentary (anyone improve that?), xandi, 020400
00058     moved all globalDatabase and coreThread handling code to classes (dataBaseAccess, coreAccess), xandi, 040400
00059     removed globalDatabase-access           xandi, 060400
00060     changed: inArgs is now the same buffer as coreBufferOut[client]
00061 
00062 -------------------------------------------------------------------*/
00063 
00064 extern map<int,Buffer*> clientBufferIn; 
00065 
00066 void* ClientThread ( void* my_Socket )
00067     {
00068     int mySocket = *(int*) my_Socket;
00069     extern FrontEnd* frontEnd;
00070 
00071     int myObjectID;
00072 
00073     string myUsername;
00074 
00075     packet*   pak = 0;
00076 
00077     ComArgs   inArgs;
00078     ComArgs   outArgs;
00079 
00080     bool      killClient;
00081     killClient = false;
00082 
00083     string    msg;
00084     msg = "[cT] ClientThread for client on socket";
00085     msg += intToChar (mySocket);
00086     msg += " started";
00087     frontEnd->displayDebugMessage (msg.c_str ());
00088 
00089     DatabaseAccess dbAccess( mySocket );
00090 
00091     Buffer* myBuffer = clientBufferIn[mySocket];
00092     inArgs.buffer    = myBuffer;
00093     inArgs.socket    = mySocket;
00094 
00095     outArgs.buffer = new Buffer ();
00096     outArgs.socket = mySocket;
00097 
00098     pthread_t incomingThread;
00099     pthread_t outgoingThread;
00100 
00101     bool check  = pthread_create ( &incomingThread, NULL, IncomingThread, &inArgs );
00102          check += pthread_create ( &outgoingThread, NULL, OutgoingThread, &outArgs );
00103 
00104     if ( check )
00105         {
00106         frontEnd->displayDebugMessage ("[cT] Error in ClientThread: can't create Communication-Threads!");
00107         /*clean up the buffers and stuff like that..  */
00108         pthread_exit (NULL);
00109         }
00110 
00111     while (1)
00112         {
00113         if ( !inArgs.buffer->isEmpty () )
00114             {
00115             pak = inArgs.buffer->read ();
00116 
00117             #ifdef DEBUG
00118             fprintf(stderr,"[cT] got a packet\n");
00119             #endif
00120 
00121             switch (pak->h.header[0])
00122                 {
00123                 case PROT_HANDSHAKE:
00124                     {
00125                     #ifdef DEBUG
00126                     frontEnd->displayDebugMessage ("[cT] Handshake request received");
00127                     #endif
00128                     Handshake (outArgs.buffer, pak);
00129                     break;
00130                     }
00131 
00132                 case PROT_AUTHENTICATE:
00133                     {
00134                     #ifdef DEBUG
00135                     frontEnd->displayDebugMessage ("[cT] Authentication request received");
00136                     #endif
00137 
00138                     #ifdef DEBUG
00139                     fprintf(stderr,"[cT] authenticate with %s\n",pak->data.c_str ());
00140                     #endif
00141                     if (Authenticate (inArgs.buffer, pak))
00142                         {
00143                         #ifdef DEBUG
00144                         frontEnd->displayDebugMessage ("[cT] Authentication successful !");
00145                         #endif
00146                         pak->data = "Authentication successful !";
00147                         outArgs.buffer->write (pak);
00148                         }
00149                    else
00150                         {
00151                         #ifdef DEBUG2
00152                         string msg;
00153                         msg  = "[cT.";
00154                         msg += intToChar (mySocket);
00155                         msg += "Authentication with ";
00156                         msg += pak->data;
00157                         msg += " failed! \n";
00158                         frontEnd->displayDebugMessage (msg.c_str());
00159                         #endif
00160                         killClient = true;
00161                         delete pak;
00162                         pak = 0;
00163                         }
00164 
00165                    break;
00166                    }
00167 
00168 
00169                 case PROT_REGISTER_ENTITY:
00170                     {
00171                     #ifdef DEBUG
00172                     fprintf(stderr,"[cT] RegisterEntity\n");
00173                     #endif
00174 
00175                     myUsername = pak->data;
00176 
00177                     dbAccess.addEntity ( myUsername );
00178 
00179                     delete pak;
00180                     pak = 0;
00181                     break;
00182                     }
00183 
00184                 case PROT_ADD_OBJECT_REPLY:
00185                     {
00186                     /************************************************++
00187                     header[1]   Object ID
00188                     header[2]   classtype
00189                     ++*************************************************/
00190                     #ifdef DEBUG
00191                     fprintf(stderr,"[cT] PROT_ADD_OBJECT_REPLY ---- %d\n",pak->h.header[1]);
00192                     #endif
00193                     switch ( pak->h.header[2] )
00194                         {
00195                         case CLT_ENTITY:
00196                             {
00197                             #ifdef DEBUG3
00198                             fprintf(stderr,"[cT] Registering of Entity %s successful\n",myUsername.c_str());
00199                             #endif
00200                             myObjectID = pak->h.header[1];
00201 
00202                             dbAccess.addAtom ( myObjectID, AT_SOCKET, (long) mySocket );
00203                             dbAccess.addAtom ( myObjectID, AT_USERNAME, myUsername );
00204 
00205                             delete pak;
00206                             pak = 0;
00207                             packet* xpak = new packet;
00208 
00209                             xpak->h.header[0] = PROT_REGISTER_ENTITY_REPLY;
00210                             xpak->h.header[1] = myObjectID;
00211 
00212                             outArgs.buffer->write (xpak);
00213                             break;
00214                             }
00215 
00216                         case CLT_OBJECT:
00217                             {
00218                             #ifdef DEBUG2
00219                             fprintf(stderr,"[cT] CLT_OBJECT: not yet implemented\n");
00220                             #endif
00221                             delete pak;
00222                             pak = 0;
00223                             break;
00224                             }
00225 
00226                         default:
00227                             {
00228                             fprintf(stderr,"[cT] ---=[%d]=--- UNKNOWN CLASS??? WTF???\n",pak->h.header[2]);
00229                             delete pak;
00230                             pak = 0;
00231                             break;
00232                             }
00233                         }
00234 
00235                     break;
00236                     }
00237 
00238 
00239                 case PROT_CHANGE_POSITION:
00240                     {
00241                     #ifdef DEBUG2
00242                     fprintf(stderr,"[cT] %d (socket %d) is changing position <--------------------------------------------\n",myObjectID,mySocket);
00243                     #endif
00244                     dbAccess.addAtom ( myObjectID, AT_POSITION, pak->data );
00245 
00246                     delete pak;
00247                     pak = 0;
00248                     break;
00249                     }
00250 
00251                 case PROT_AVATAR_HULL:
00252                     {
00253                     #ifdef DEBUG
00254                     fprintf(stderr,"[cT] adding the avatar hull for %d...\n",myObjectID);
00255                     #endif
00256                     dbAccess.addAtom ( myObjectID, AT_3DSIAGRAPH, pak->data );
00257 
00258                     delete pak;
00259                     pak = 0;
00260                     break;
00261                     }
00262 
00263                 case PROT_GET_ALL_CHANGED:
00264                     {
00265                     #ifdef DEBUG
00266                     fprintf(stderr,"%d",mySocket);
00267                     #endif
00268 
00269                     dbAccess.getAllObjects();
00270 
00271                     delete pak;
00272                     pak = 0;
00273                     break;
00274                     }
00275 
00276 
00277                 case PROT_GET_ALL_OBJECTS_REPLY:
00278                     {
00279                     /************************************************++
00280                     header[1]   Object ID
00281                     header[2]   classtype
00282                     ++*************************************************/
00283 
00284                     //choose those you want
00285 
00286                     #ifdef DEBUG
00287                     fprintf(stderr,"[cT.%d] PROT_GET_ALL_OBJECTS_REPLY -- objectID: %d\n",mySocket,pak->h.header[1]);
00288                     #endif
00289                     dbAccess.getObject ( pak->h.header[1] );
00290 
00291                     delete pak;
00292                     pak = 0;
00293                     break;
00294                     }
00295 
00296 
00297                 case PROT_GET_OBJECT_REPLY:
00298                     {
00299                     /************************************************++
00300                     header[1]   Object ID
00301                     //the classtype would be interesting too
00302                     data        the name of the object
00303                     ++*************************************************/
00304 
00305                     //forward the object itself to the client
00306                     #ifdef DEBUG2
00307                     fprintf(stderr,"[cT.%d] PROT_GET_OBJECT_REPLY -- objectID: %d\n",mySocket,pak->h.header[1]);
00308                     #endif
00309                     int objectID;
00310                     objectID = pak->h.header[1];
00311 
00312                     pak->h.header[0] = PROT_RECEIVE_OBJECT;
00313                     pak->h.header[1] = objectID;
00314 
00315                     outArgs.buffer->write (pak);
00316 
00317 //                    dbAccess.getAllAtoms ( objectID );
00318                     break;
00319                     }
00320 
00321                 case PROT_GET_ALL_ATOMS_REPLY:
00322                     {
00323                     /************************************************++
00324                     header[1]  Atom ID
00325                     header[2]  Object ID
00326                     header[3]  AtomType of Atom
00327                     ++*************************************************/
00328 
00329                     //choose those you want
00330 
00331                     #ifdef DEBUG2
00332                     fprintf(stderr,"[cT.%d] PROT_GET_ALL_ATOMS_REPLY -- objectID: %d\n",mySocket,pak->h.header[1]);
00333                     #endif
00334                     dbAccess.getAtom ( pak->h.header[1], pak->h.header[2], pak->h.header[3] );
00335 
00336                     delete pak;
00337                     pak = 0;
00338                     break;
00339                     }
00340 
00341 
00342                 case PROT_GET_ATOM_REPLY:
00343                     {
00344                     /************************************************++
00345                     header[1]  ObjectID
00346                     header[2]  atom type
00347                     header[3]  atomID
00348                     header[4]  valueType
00349                     data       The atom data
00350                     ++*************************************************/
00351 
00352                     //forward the atom to the client
00353 
00354                     #ifdef DEBUG2
00355                     fprintf(stderr,"[cT.%d] PROT_GET_ATOM_REPLY -- objectID: %d atomID: %d\n",mySocket,pak->h.header[1],pak->h.header[3]);
00356                     #endif
00357 
00358                     pak->h.header[0] = PROT_RECEIVE_ATOM;
00359 
00360 
00361                     outArgs.buffer->write (pak);
00362 
00363                     break;
00364                     }
00365 
00366                 case PROT_KILL_CLIENT:
00367                     {
00368                     string msg;
00369                     msg  = "[cT.";
00370                     msg += intToChar (mySocket);
00371                     msg += "] PROT_KILL_CLIENT received !\n";
00372 
00373                     frontEnd->displayDebugMessage (msg.c_str());
00374                     killClient = true;
00375 
00376                     delete pak;
00377                     pak = 0;
00378                     break;
00379                     }
00380 
00381                 case PROT_CHAT_MSG:
00382                     {
00383                     #ifdef DEBUG2
00384                     string msg;
00385                     msg  = "[cT.";
00386                     msg += intToChar (mySocket);
00387                     msg += "] Chat message - {";
00388                     msg += pak->data;
00389                     msg += "} -\n";
00390 
00391                     frontEnd->displayDebugMessage (msg.c_str());
00392                     #endif
00393 
00394                     dbAccess.addAtom (myObjectID, AT_CHATMSG, pak->data);
00395                     delete pak;
00396                     break;
00397                     }
00398 
00399 
00400                 default:
00401                     {
00402                     #ifdef DEBUG2
00403                     frontEnd->displayDebugMessage ("[cT] unknown packet received !");
00404                     #endif
00405                     frontEnd->displayDebugMessage (pak->data.c_str ());
00406                     killClient = true;
00407 
00408                     delete pak;
00409                     pak = 0;
00410                     break;
00411                     }
00412                 }
00413             }
00414 
00415         if (killClient)
00416              break;
00417         }
00418 
00419     pak = new packet;
00420     pak->h.header[0] = PROT_KILL_CLIENT;  // tell the outgoing thread to die
00421     outArgs.buffer->write (pak);
00422 
00423     msg = "ClientThread for client on socket";
00424     msg += intToChar (mySocket);
00425     msg += " dying !";
00426 
00427     frontEnd->displayDebugMessage (msg.c_str ());
00428 
00429 
00430     pthread_cancel ( incomingThread );
00431     pthread_cancel ( outgoingThread );
00432 
00433     close ( mySocket );
00434 
00435     /*
00436     todo:
00437     - remove your buffers
00438     - say bye bye
00439     */
00440 
00441     pthread_exit (NULL);
00442     }
00443 
00444 
00445 /*...................................................................
00446 Description: handshake with client
00447 Args: Buffer* in: incoming buffer; Buffer* out: outgoing buffer; packet* act: last received packet
00448 Returns: true on success
00449 Created: StonedBones, 5.2.2000
00450 [ToDo:]
00451 [Comments:]
00452 Changes:
00453 -------------------------------------------------------------------*/
00454 
00455 bool Handshake (Buffer* out, packet* pak) {
00456     extern FrontEnd* frontEnd;
00457 
00458     if ((pak->h.header[0] != PROT_HANDSHAKE) || (pak->h.header[1] != HANDSHAKE_GREETING))
00459         {
00460         frontEnd->displayDebugMessage ("Error: handshake failed: invalid packet");
00461         return false;
00462         }
00463 
00464     if ((pak->h.header[2] != VERSION_MAJOR) || (pak->h.header[3] != VERSION_MINOR))
00465         {
00466         frontEnd->displayDebugMessage ("Error: handshake failed: wrong client version");
00467         return false;
00468         }
00469 
00470     #ifdef DEBUG
00471     frontEnd->displayDebugMessage ("Handshake packet valid");
00472     #endif
00473 
00474     out->write (pak);
00475     return true;
00476 };
00477 
00478 /*...................................................................
00479 Description: manages the user authentication
00480 Args: Buffer* in: incoming buffer; Buffer* out: outgoing buffer; packet* pak: last received packet
00481 Returns: true on success
00482 Created: StonedBones, 5.2.2000
00483 [ToDo:]
00484 [Comments:]
00485 Changes:
00486 -------------------------------------------------------------------*/
00487 
00488 bool Authenticate (Buffer* in, packet* pak)
00489     {
00490     if (pak->h.header[0] != PROT_AUTHENTICATE)
00491         return false;
00492 
00493     #ifdef AUTHENTICATE_SHADOW
00494     if (pak->h.header[1] == AUTH_PASSWORD)
00495         return AuthenticateShadow ( pak, in );
00496     #endif
00497 
00498     return false;
00499     };

Generated at Sat May 13 13:50:18 2000 for 3Dsia by doxygen 1.1.2 written by Dimitri van Heesch, © 1997-2000