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 };