00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "aesop-client.h"
00035
00036 #include "object-sync.h"
00037
00038
00039 #include "common/wave_ex.h"
00040 #include "conversation/conversation.h"
00041 #include "aesop-map/map.h"
00042 #include "aesop-proto/message.h"
00043 #include "aesop-proto/protocol.h"
00044 #include "crypto/crypto.h"
00045 #include "datahash/datahash_text.h"
00046 #include "datahash/datahash_util.h"
00047 #include "dialog/request.h"
00048 #include "map-manager/map-manager.h"
00049 #include "netrq/netrq.h"
00050 #include "perf/perf.h"
00051 #include "story/story.h"
00052 #include "typeinst/typeinst.h"
00053 #include "xdrbuf/xdrbuf.h"
00054
00055
00056 namespace aesop {
00057
00058
00060
00063 typedef netlib::conn_id_t conn_id_t;
00064 typedef netlib::envelope_t envelope_t;
00065 typedef netlib::MessageBuffer MessageBuffer;
00066
00067 static const int s_maxIdLength = 32;
00068
00069
00070 static const int s_bigNumber = 32000;
00071 static const int s_smallNumber = 2;
00072
00073 static int s_authCountdown = 0;
00074
00075 static const float s_maxTimeDelta = 0.1;
00076 static const float s_minTimeDelta = 1.0e-4;
00077
00078
00079 static const int s_udpOutSize = 824;
00080
00081
00082
00083 ClientHost::~ClientHost(void) throw() { }
00084 Client::~Client(void) throw() { }
00085
00086
00087
00088 struct client_player_record_t {
00089
00090 client_player_record_t(void) throw() { this->clear(); }
00091 void clear(void) throw() {
00092 objectId = 0;
00093 delta.clear();
00094 euler.clear();
00095 }
00096
00097
00098 dword_t objectId;
00099 point3d_t delta;
00100 point3d_t euler;
00101 };
00102
00103
00104
00105 static const float s_minStateMessageWaitTime = 0.5;
00106 static const float s_maxStateMessageWaitTime = 3.0;
00107
00108
00109 typedef std::map<int, smart_ptr<client_player_record_t> > player_map_t;
00110
00111
00112
00113 typedef std::map<std::string, smart_ptr<Map> > id_map_t;
00114
00115
00116
00117 struct converse_rec_t {
00118
00119 converse_rec_t(void) throw() { this->clear(); }
00120 void clear(void) throw() {
00121 dialogId = 0;
00122 playerId = 0;
00123 connId = 0;
00124 }
00125
00126
00127 int dialogId;
00128 int playerId;
00129 conn_id_t connId;
00130 };
00131
00132 typedef std::map<std::string, smart_ptr<converse_rec_t> > conversation_map_t;
00133
00134
00136
00137
00138
00140
00141 static const char *
00142 getServerHashKey
00143 (
00144 IN const server_info_t& si,
00145 IO char * buffer
00146 )
00147 {
00148 ASSERT2(si.isValid(), "invalid");
00149 ASSERT(buffer, "null");
00150
00151 const byte_t * pb = si.address.ip.addr;
00152 sprintf(buffer, "%d.%d.%d.%d:%d",
00153 pb[0], pb[1], pb[2], pb[3], si.address.port);
00154
00155 return buffer;
00156 }
00157
00158
00159
00161
00162
00163
00164
00166
00167 static const char * s_reqIdConnect = "connect";
00168 static const char * s_reqIdAuthorize = "auth";
00169
00170
00171 class QueryObjectRequest: public netrq::Request {
00172 public:
00173 ~QueryObjectRequest(void) throw() { }
00174
00175
00176 void write(IN xdrbuf::Output * output) {
00177 ASSERT(output, "null");
00178
00179 output->addInt32Packlet('q',
00180 (int32_t *) &m_objectId, 1);
00181 }
00182
00183 const char * getId(void) const throw() { return m_reqId; }
00184
00185 int getMaxBytes(void) const throw() {
00186 return 4 + 2;
00187 }
00188
00189
00190 int getRetryInterval(void) const throw() { return 24; }
00191
00192
00193 static smart_ptr<netrq::Request> create(IN long objectId) {
00194 ASSERT(objectId, "null");
00195
00196 smart_ptr<QueryObjectRequest> local =
00197 new QueryObjectRequest;
00198 ASSERT(local, "out of memory");
00199
00200 sprintf(local->m_reqId, "qo%ld", objectId);
00201 local->m_objectId = objectId;
00202
00203 return local;
00204 }
00205
00206 private:
00207
00208 QueryObjectRequest(void) throw() { }
00209
00210
00211 dword_t m_objectId;
00212 char m_reqId[64];
00213 };
00214
00215
00216
00217 class ConnectContext : public netrq::Request {
00218 public:
00219 ~ConnectContext(void) throw() { }
00220
00221 void write(IN xdrbuf::Output * output) {
00222 ASSERT(output, "null");
00223 output->openPacklet('c');
00224 int32_t l[3];
00225 l[0] = eProtocol_Long;
00226 l[1] = m_token;
00227 l[2] = m_port;
00228 output->addInt32Packlet('v', l, 3);
00229 output->openPacklet('p');
00230 const char * key = m_key.c_str();
00231 int len = m_key.length();
00232 while (len) {
00233 int send = len;
00234 if (send > 255) {
00235 send = 255;
00236 }
00237
00238 output->addStringPacklet('a', key, send);
00239 key += send;
00240 len -= send;
00241 }
00242 output->closePacklet('p');
00243 output->closePacklet('c');
00244 }
00245
00246 int getMaxBytes(void) const throw() {
00247 return 384;
00248 }
00249
00250 const char * getId(void) const throw()
00251 { return s_reqIdConnect; }
00252
00253 static smart_ptr<netrq::Request> create(IN long token,
00254 IN int port,
00255 IN const char * publicKey) {
00256 ASSERT(token, "null");
00257 ASSERT(port, "null");
00258 ASSERT(publicKey, "null");
00259
00260 smart_ptr<ConnectContext> cc = new ConnectContext;
00261 ASSERT(cc, "out of memory");
00262
00263 cc->m_token = token;
00264 cc->m_port = port;
00265 cc->m_key = publicKey;
00266
00267 return cc;
00268 }
00269
00270 private:
00271 ConnectContext(void) { }
00272
00273 long m_token;
00274 int m_port;
00275 std::string m_key;
00276 };
00277
00278
00279
00280 class AuthorizeContext : public netrq::Request {
00281 public:
00282 AuthorizeContext(IN const char * password) {
00283 ASSERT(password, "null");
00284 m_password = password;
00285 }
00286 ~AuthorizeContext(void) throw() { }
00287
00288 void write(IN xdrbuf::Output * output) {
00289 ASSERT(output, "null");
00290
00291 output->addStringPacklet('a',
00292 m_password.c_str(),
00293 m_password.length());
00294 }
00295
00296 int getMaxBytes(void) const throw() {
00297 return 259 + 2;
00298 }
00299
00300 const char * getId(void) const throw()
00301 { return s_reqIdAuthorize; }
00302 private:
00303 std::string m_password;
00304 };
00305
00306
00307
00309
00310
00311
00313
00314 class ClientImpl : public Client,
00315 public dialog::Host,
00316 public converse::ConversationRouter {
00317 public:
00318 ClientImpl(void) throw();
00319 ~ClientImpl(void) throw() { }
00320
00321
00322 void initialize(IN ClientHost * host,
00323 IN smart_ptr<story::Story>& story,
00324 IN smart_ptr<Datahash>& params);
00325
00326
00327 story::Story * getStory(void) throw() { return m_story; }
00328 eClientState getState(void) throw() { return m_clientState; }
00329 bool getServer(OUT server_info_t& si);
00330 const server_map_t& getDiscoveredServers(void) { return m_servers; }
00331 bool requestConnect(IN const char * serverKey);
00332 float tick(void);
00333 bool createPlayer(IN int playerId);
00334 void startLocalConversation(IN const char * guid,
00335 IN int playerId,
00336 IN smart_ptr<converse::ConversationHost> host);
00337 bool isConversationUnderway(IN const char * guid);
00338 void newGame(IN int playerId);
00339 void requestMove(IN int playerId,
00340 IN const point3d_t& delta,
00341 IN const point3d_t& euler,
00342 OUT point3d_t& newPosition);
00343 bool getPlacement(IN int playerId,
00344 OUT placement_t& placement);
00345 smart_ptr<PhysicsObject> getPlayerObject(IN int playerId);
00346
00347
00348 void notifySubmit(IN const char * id,
00349 IN const Datahash * data);
00350
00351
00352 void routeConversationTS(IN const char * guid,
00353 IN int dialogId,
00354 IN int playerId,
00355 IN conn_id_t connId,
00356 IN const char * dialogData);
00357
00358 private:
00359
00360 client_player_record_t * getPlayer(IN int playerId);
00361 converse_rec_t * getConversation(IN const char * conversationGuid);
00362 void deleteConversation(IN const char * guid,
00363 IN int playerId);
00364 void checkHostState(void);
00365 void handleMessage(IN const envelope_t& envelope,
00366 IN const MessageBuffer * msg);
00367 void handleUDP(IN const envelope_t& envelope,
00368 IN const MessageBuffer * msg);
00369 void handleBroadcast(IN xdrbuf::PackletHeader ph,
00370 IN const envelope_t& env);
00371 void readConnectUDP(IO xdrbuf::Input * input);
00372 void readDestroyUDP(IO xdrbuf::Input * input);
00373 void readPlayerUDP(IO xdrbuf::Input * input);
00374 void readQueryUDP(IN const xdrbuf::PackletHeader& ph,
00375 IO xdrbuf::Input * input);
00376 void readObjectUDP(IO xdrbuf::Input * input);
00377 void setKeys(IN const char * encryptedDesKey);
00378 void sendUdpPacket(IN float dt);
00379
00380
00381 ClientHost * m_host;
00382 server_map_t m_servers;
00383 server_info_t m_server;
00384 eClientState m_clientState;
00385 conn_id_t m_tcpConnID;
00386 conn_id_t m_localUdpConnID;
00387 conn_id_t m_remoteUdpConnID;
00388 player_map_t m_players;
00389 conversation_map_t m_conversations;
00390 smart_ptr<converse::ConversationManager> m_conversationMgr;
00391 eHostMode m_hMode;
00392 smart_ptr<crypto::RSAKey> m_rsaKey;
00393 smart_ptr<crypto::DESKey> m_desKey;
00394 bool m_haveProtocol;
00395 int m_localUdpPort;
00396 int m_remoteUdpPort;
00397 int m_serverTcpPort;
00398 dword_t m_udpMostRecentClock;
00399 dword_t m_udpClock;
00400 dword_t m_lastUdpServerSaw;
00401 long m_udpConnToken;
00402 id_map_t m_maps;
00403 smart_ptr<xdrbuf::Input> m_udpIn;
00404 smart_ptr<xdrbuf::Output> m_udpOut;
00405 smart_ptr<ObjectSync> m_syncMgr;
00406 smart_ptr<MapManager> m_mapMgr;
00407 smart_ptr<story::Story> m_story;
00408 smart_ptr<netrq::Queue> m_netQueue;
00409 perf::time_t m_lastTime;
00410 float m_lastdt;
00411 float m_lastUdpSent;
00412 };
00413
00414
00415
00416 ClientImpl::ClientImpl(void) throw()
00417 {
00418 m_host = NULL;
00419 m_server.clear();
00420 m_clientState = eClientState_Invalid;
00421 m_tcpConnID = 0;
00422 m_localUdpConnID = 0;
00423 m_remoteUdpConnID = 0;
00424 m_haveProtocol = false;
00425 m_localUdpPort = 0;
00426 m_remoteUdpPort = 0;
00427 m_serverTcpPort = 0;
00428 m_hMode = eHostMode_Invalid;
00429 m_udpMostRecentClock = 0;
00430 m_udpClock = 0;
00431 m_lastUdpServerSaw = 0;
00432 m_udpConnToken = 0;
00433 m_lastdt = 0.0;
00434 m_lastUdpSent = 0.0;
00435 }
00436
00437
00438
00439 void
00440 ClientImpl::initialize
00441 (
00442 IN ClientHost * host,
00443 IN smart_ptr<story::Story>& story,
00444 IN smart_ptr<Datahash>& params
00445 )
00446 {
00447 ASSERT(host, "null");
00448 ASSERT(story, "null");
00449 ASSERT(params, "null");
00450
00451
00452 ASSERT(!m_host, "already have a host?");
00453 m_host = host;
00454
00455
00456 ASSERT(!m_story, "already have a story?");
00457 m_story = story;
00458
00459
00460 ASSERT(s_udpOutSize > 31 && s_udpOutSize < 1025,
00461 "Bad udp output buffer size: %d", s_udpOutSize);
00462 ASSERT(!m_udpOut, "Already have a udp output buffer?");
00463 m_udpOut = xdrbuf::Output::create(s_udpOutSize);
00464 ASSERT(m_udpOut, "failed to create xdr output buffer");
00465
00466
00467 ASSERT(!m_udpIn, "Already have a udp input buffer?");
00468 m_udpIn = xdrbuf::Input::create();
00469 ASSERT(m_udpIn, "Failed to create xdr input parser");
00470
00471
00472 m_localUdpPort = eDefaultPort_clientUdp;
00473 DPRINTF("Default client UDP port: %d", m_localUdpPort);
00474 const char * udpOverride =
00475 getString(params, "udpPort", eDatahash_Optional);
00476 if (udpOverride) {
00477 DPRINTF("Overriding client UDP port: %s", udpOverride);
00478 m_localUdpPort = atoi(udpOverride);
00479 }
00480 if (m_localUdpPort <= 0) {
00481 WAVE_EX(wex);
00482 wex << "Bad local UDP port: " << m_localUdpPort;
00483 }
00484
00485
00486 m_rsaKey = crypto::RSAKey::create();
00487 ASSERT(m_rsaKey, "failed to create RSA key");
00488
00489
00490 ASSERT(!m_netQueue, "already have a network request queue?");
00491 m_netQueue = netrq::Queue::create();
00492 ASSERT(m_netQueue, "failed to create network request queue");
00493
00494
00495 netlib::address_t udpAddress;
00496 udpAddress.setlocal(m_localUdpPort);
00497 udpAddress.dump("udp address");
00498 m_localUdpConnID = netlib::createUdpLocal(udpAddress);
00499 ASSERT(m_localUdpConnID, "failed to create local udp port?");
00500
00501
00502 ASSERT(!m_mapMgr, "already have a map manager?");
00503 m_mapMgr = MapManager::create(params, m_story);
00504 ASSERT(m_mapMgr, "null");
00505
00506
00507 ASSERT(!m_syncMgr, "already have an object synchronization manager?");
00508 m_syncMgr = ObjectSync::create(m_mapMgr);
00509 ASSERT(m_syncMgr, "null");
00510
00511
00512 ASSERT(!m_conversationMgr, "Already have a conversation manager?");
00513 m_conversationMgr = converse::ConversationManager::create(this);
00514 ASSERT(m_conversationMgr, "null");
00515
00516
00517 initializeTypeInstanceLibrary(m_story);
00518
00519
00520 m_clientState = eClientState_Searching;
00521 }
00522
00523
00524
00526
00527
00528
00530
00531 bool
00532 ClientImpl::getServer
00533 (
00534 OUT server_info_t& si
00535 )
00536 {
00537 si = m_server;
00538 return si.isValid();
00539 }
00540
00541
00542
00543 bool
00544 ClientImpl::requestConnect
00545 (
00546 IN const char * serverKey
00547 )
00548 {
00549 ASSERT(serverKey, "null");
00550
00551
00552 if (m_server.isValid()) {
00553 DPRINTF("Ignoring request to connect: we are connected!");
00554 return false;
00555 }
00556
00557 DPRINTF("Player wants this server: %s", serverKey);
00558 m_server.clear();
00559 bool found = m_servers.lookup(serverKey, m_server);
00560 if (!found) {
00561 DPRINTF("No such server: %s", serverKey);
00562 return false;
00563 }
00564
00565
00566 ASSERT_THROW(!m_remoteUdpConnID,
00567 "Not connected but have a remote UDP connection?");
00568 m_remoteUdpConnID =
00569 netlib::createUdpRemote(m_localUdpConnID, m_server.address);
00570 ASSERT(m_remoteUdpConnID, "failed to create remote udp connection");
00571
00572
00573 return true;
00574 }
00575
00576
00577
00578 float
00579 ClientImpl::tick
00580 (
00581 void
00582 )
00583 {
00584
00585 this->checkHostState();
00586
00587
00588 m_conversationMgr->updateAll();
00589
00590
00591
00592 envelope_t env;
00593 smart_ptr<MessageBuffer> msg;
00594 long microseconds = 500;
00595 try {
00596 usleep(10 * microseconds);
00597 if (netlib::getNextMessage(microseconds, env, msg)) {
00598 this->handleMessage(env, msg);
00599 }
00600 } catch (std::exception& e) {
00601 netlib::dumpMessage(std::cerr, "Error handling this message",
00602 env, msg);
00603 DPRINTF("Exception: %s", e.what());
00604 }
00605
00606
00607 perf::time_t now = perf::getNow();
00608 perf::time_t delta = now;
00609 delta.decrement(m_lastTime);
00610 m_lastTime = now;
00611 float dt = (float) delta.getSeconds();
00612 if (dt > s_maxTimeDelta) {
00613 dt = s_maxTimeDelta;
00614 } else if (dt <= s_minTimeDelta) {
00615
00616 dt = s_minTimeDelta;
00617 }
00618 m_lastdt = dt;
00619
00620
00621 m_mapMgr->tickMaps(dt);
00622
00623
00624
00625 m_lastUdpSent += dt;
00626 const float s_sendHz = 50.0;
00627 const float s_sendRate = 1.0 / s_sendHz;
00628 if (m_lastUdpSent > s_sendRate) {
00629 this->sendUdpPacket(m_lastUdpSent);
00630 m_lastUdpSent = 0.0;
00631 }
00632
00633
00634 if (m_udpClock)
00635 m_syncMgr->clientUpdate(m_udpClock);
00636
00637
00638 return dt;
00639 }
00640
00641
00642
00643 bool
00644 ClientImpl::createPlayer
00645 (
00646 IN int playerId
00647 )
00648 {
00649 ASSERT(playerId > 0, "Bad player id: %d", playerId);
00650
00651
00652 if (this->getPlayer(playerId)) {
00653
00654 return false;
00655 }
00656
00657
00658 DPRINTF("New client player");
00659 smart_ptr<client_player_record_t> player = new client_player_record_t;
00660 ASSERT(player, "out of memory");
00661
00662 m_players[playerId] = player;
00663 ASSERT(2 == player.get_ref_count(), "Bad count");
00664
00665
00666 return true;
00667 }
00668
00669
00670
00671 void
00672 ClientImpl::startLocalConversation
00673 (
00674 IN const char * guid,
00675 IN int playerId,
00676 IN smart_ptr<converse::ConversationHost> host
00677 )
00678 {
00679 ASSERT(guid, "null");
00680 ASSERT(playerId > 0, "Bad player id: %d", playerId);
00681 ASSERT(host, "null");
00682 ASSERT(m_conversationMgr, "null");
00683
00684
00685 if (this->getConversation(guid)) {
00686 return;
00687 }
00688
00689
00690 smart_ptr<converse_rec_t> cr = new converse_rec_t;
00691 ASSERT(cr, "out of memory");
00692
00693 cr->playerId = playerId;
00694 cr->connId = 0;
00695 cr->dialogId = host->getCurrentDialogIdTS();
00696 m_conversations[guid] = cr;
00697
00698
00699 m_conversationMgr->updateConversationTS(guid, 0, playerId, host);
00700 }
00701
00702
00703
00704 bool
00705 ClientImpl::isConversationUnderway
00706 (
00707 IN const char * guid
00708 )
00709 {
00710 ASSERT(guid, "null");
00711
00712
00713 if (this->getConversation(guid))
00714 return true;
00715 return false;
00716 }
00717
00718
00719
00720 void
00721 ClientImpl::newGame
00722 (
00723 IN int playerId
00724 )
00725 {
00726 ASSERT(playerId > 0, "Bad player id: %d", playerId);
00727
00728 DPRINTF("Requesting new game!");
00729
00730 smart_ptr<netlib::MessageBuffer> msg = createNewGameMessage(playerId);
00731 ASSERT(msg, "null");
00732
00733 netlib::enqueueMessage(m_tcpConnID, msg);
00734 }
00735
00736
00737
00738 void
00739 ClientImpl::requestMove
00740 (
00741 IN int playerId,
00742 IN const point3d_t& delta,
00743 IN const point3d_t& euler,
00744 OUT point3d_t& newPosition
00745 )
00746 {
00747 ASSERT(playerId > 0, "Bad player id: %d", playerId);
00748
00749 client_player_record_t * prec = this->getPlayer(playerId);
00750 if (!prec) {
00751
00752 DPRINTF("Unrecognized player id: %d", playerId);
00753 return;
00754 }
00755 if (!prec->objectId) {
00756
00757
00758 return;
00759 }
00760
00761
00762 if (!m_syncMgr->clientMoveRequest(prec->objectId, delta, m_lastdt,
00763 newPosition)) {
00764 DPRINTF("Object ID not found? %lu", (long) prec->objectId);
00765 }
00766
00767
00768 prec->delta += delta;
00769 prec->euler = euler;
00770 }
00771
00772
00773
00774 bool
00775 ClientImpl::getPlacement
00776 (
00777 IN int playerId,
00778 OUT placement_t& placement
00779 )
00780 {
00781 ASSERT(playerId > 0, "Bad player id: %d", playerId);
00782 placement.clear();
00783
00784 client_player_record_t * prec = this->getPlayer(playerId);
00785 if (!prec || !prec->objectId) {
00786 return false;
00787 }
00788
00789
00790 object_state_t state;
00791 if (!m_syncMgr->getState(prec->objectId, state) ||
00792 !state.physicsObject) {
00793 return false;
00794 }
00795 placement.position = state.physicsObject->getPosition();
00796
00797
00798
00799
00800 placement.rotation.setEulerZYX(prec->euler);
00801
00802
00803 return true;
00804 }
00805
00806
00807
00808 smart_ptr<PhysicsObject>
00809 ClientImpl::getPlayerObject
00810 (
00811 IN int playerId
00812 )
00813 {
00814 ASSERT(playerId > 0, "Bad player id: %d", playerId);
00815
00816 client_player_record_t * prec = this->getPlayer(playerId);
00817 if (!prec || !prec->objectId) {
00818
00819 return NULL;
00820 }
00821
00822
00823
00824 ASSERT(m_syncMgr, "null");
00825 object_state_t os;
00826 if (!m_syncMgr->getState(prec->objectId, os))
00827 return NULL;
00828
00829 return os.physicsObject;
00830 }
00831
00832
00833
00835
00836
00837
00839
00840 void
00841 ClientImpl::notifySubmit
00842 (
00843 IN const char * id,
00844 IN const Datahash * data
00845 )
00846 {
00847 ASSERT(id, "null");
00848 ASSERT(data, "null");
00849
00850 DPRINTF("Received submit for conversation: %s", id);
00851
00852
00853 converse_rec_t * cr = this->getConversation(id);
00854 if (!cr) {
00855 DPRINTF("Received submit for unknown conversation?");
00856 DPRINTF(" id='%s'", id);
00857 return;
00858 }
00859
00860
00861 if (!cr->connId) {
00862 DPRINTF(" Local conversation!");
00863 ASSERT(m_conversationMgr, "null");
00864
00865 m_conversationMgr->handleDialogReplyTS(id, cr->dialogId,
00866 0, cr->playerId, data);
00867
00868 return;
00869 }
00870
00871
00872
00873 std::ostringstream reply;
00874 writeHashToStream(data, reply);
00875
00876 DPRINTF("Constructed reply:\n%s", reply.str().c_str());
00877
00878
00879 smart_ptr<MessageBuffer> msg =
00880 createConversationReplyMessage(cr->playerId, id, cr->dialogId,
00881 reply.str().c_str());
00882
00883 netlib::enqueueMessage(m_tcpConnID, msg);
00884 }
00885
00886
00887
00889
00890
00891
00893
00894 void
00895 ClientImpl::routeConversationTS
00896 (
00897 IN const char * guid,
00898 IN int dialogId,
00899 IN int playerId,
00900 IN conn_id_t connId,
00901 IN const char * dialogData
00902 )
00903 {
00904 ASSERT(guid, "null");
00905 ASSERT(dialogId >= 0, "Bad dialog id: %d", dialogId);
00906 ASSERT(playerId > 0, "bad player id: %d", playerId);
00907 ASSERT(!connId, "Should only be used for local conversations!");
00908 ASSERT(dialogData, "null");
00909 ASSERT(m_host, "null");
00910 ASSERT(m_conversationMgr, "null");
00911
00912
00913
00914
00915 if (!dialogId) {
00916 DPRINTF("Destroying this conversation/dialog: %s", guid);
00917 this->deleteConversation(guid, playerId);
00918 return;
00919 }
00920
00921
00922 converse_rec_t * cr = this->getConversation(guid);
00923 if (!cr) {
00924 DPRINTF("Unable to find conversation: '%s'", guid);
00925 } else {
00926 cr->dialogId = dialogId;
00927 }
00928
00929
00930 std::istringstream iss(dialogData);
00931 smart_ptr<Datahash> hash = readHashFromStream("local dialog", iss);
00932
00933
00934 m_host->requestDialog(guid, playerId, hash, this);
00935 }
00936
00937
00938
00940
00941
00942
00944
00945 client_player_record_t *
00946 ClientImpl::getPlayer
00947 (
00948 IN int id
00949 )
00950 {
00951 ASSERT(id > 0, "Bad input id: %d", id);
00952
00953 player_map_t::iterator i = m_players.find(id);
00954 if (m_players.end() == i) {
00955
00956 return NULL;
00957 }
00958 ASSERT(i->second, "null player in map");
00959
00960 return i->second;
00961 }
00962
00963
00964
00965 converse_rec_t *
00966 ClientImpl::getConversation
00967 (
00968 IN const char * guid
00969 )
00970 {
00971 ASSERT(guid, "null");
00972
00973 conversation_map_t::iterator i = m_conversations.find(guid);
00974 if (m_conversations.end() == i) {
00975 return NULL;
00976 }
00977
00978 return i->second;
00979 }
00980
00981
00982
00983 void
00984 ClientImpl::deleteConversation
00985 (
00986 IN const char * guid,
00987 IN int playerId
00988 )
00989 {
00990 ASSERT(guid, "null");
00991 ASSERT(playerId > 0, "Bad player id: %d", playerId);
00992
00993 conversation_map_t::iterator i = m_conversations.find(guid);
00994 if (m_conversations.end() == i) {
00995 DPRINTF("Cannot delete unknown conversation: %s", guid);
00996 return;
00997 }
00998
00999
01000 ASSERT(m_host, "null");
01001 m_host->destroyDialog(guid, playerId);
01002
01003
01004 m_conversations.erase(guid);
01005 }
01006
01007
01008
01020
01021
01022 void
01023 ClientImpl::checkHostState
01024 (
01025 void
01026 )
01027 {
01028
01029
01030
01031 ASSERT(eClientState_Invalid != m_clientState,
01032 "why is state invalid now?");
01033
01034
01035 if (m_remoteUdpConnID) {
01036
01037 m_clientState = eClientState_Connecting;
01038 } else {
01039 m_clientState = eClientState_Searching;
01040 return;
01041 }
01042
01043
01044 if (eHostMode_Invalid == m_hMode) {
01045
01046
01047
01048 if (m_netQueue->containsRequest(s_reqIdConnect))
01049 return;
01050
01051
01052
01053 ASSERT(m_rsaKey, "null");
01054 smart_ptr<crypto::RSAPublicKey> pubkey =
01055 m_rsaKey->getPublicKey();
01056 ASSERT(pubkey, "null");
01057 std::string publicKey = pubkey->serialize();
01058
01059
01060 long token = m_remoteUdpConnID;
01061 smart_ptr<netrq::Request> rc =
01062 ConnectContext::create(token, m_localUdpPort,
01063 publicKey.c_str());
01064 ASSERT(rc, "null");
01065
01066
01067 m_netQueue->addRequest(m_udpClock + 1, rc);
01068 return;
01069 } else if (eHostMode_Connected == m_hMode && m_desKey) {
01070 DPRINTF("Connected! Now need to authorize...");
01071
01072
01073 ASSERT(m_desKey, "null");
01074
01075
01076 if (s_authCountdown) {
01077 --s_authCountdown;
01078 return;
01079 }
01080 s_authCountdown = 10;
01081
01082
01083 DPRINTF("Sending host level password...");
01084 std::string encryptedPassword = m_desKey->encrypt("", 12);
01085 DPRINTF("Encrypted password: %s", encryptedPassword.c_str());
01086 smart_ptr<netrq::Request> rc =
01087 new AuthorizeContext(encryptedPassword.c_str());
01088 m_netQueue->addRequest(m_udpClock + 1, rc);
01089 return;
01090 } else if (eHostMode_Authorized == m_hMode) {
01091
01092
01093 }
01094
01095
01096 if (eHostMode_Authorized != m_hMode)
01097 return;
01098
01099
01100 if (m_udpConnToken && !m_tcpConnID && m_serverTcpPort) {
01101 ASSERT2(m_server.isValid(), "Invalid server");
01102 netlib::address_t address = m_server.address;
01103 address.port = m_serverTcpPort;
01104 address.dump("Attempting TCP connection here");
01105 m_tcpConnID = netlib::createTcpConnection(address);
01106 ASSERT2(m_tcpConnID, "Failed to create TCP connection");
01107
01108
01109 smart_ptr<netlib::MessageBuffer> msg =
01110 createTcpConnectMessage(m_udpConnToken);
01111 ASSERT(msg, "failed to create tcp connect message");
01112 netlib::enqueueMessage(m_tcpConnID, msg);
01113 }
01114
01115
01116 if (m_udpConnToken && m_tcpConnID && m_remoteUdpConnID) {
01117 m_clientState = eClientState_Connected;
01118 }
01119 }
01120
01121
01122
01123 void
01124 ClientImpl::handleMessage
01125 (
01126 IN const envelope_t& env,
01127 IN const MessageBuffer * msg
01128 )
01129 {
01130 ASSERT(!env.is_empty(), "empty");
01131 ASSERT(msg, "null");
01132
01133
01134 if (netlib::eType_UDPRemote == env.type) {
01135 this->handleUDP(env, msg);
01136 return;
01137 }
01138
01139
01140 tcp_payload_t payload;
01141 getTcpPayload(msg->getData(), payload);
01142 ASSERT(!payload.is_empty(), "empty");
01143
01144
01145 const char * namespace_ = payload.namespace_.c_str();
01146 ASSERT(namespace_, "null");
01147 if (strcmp("client", namespace_)) {
01148 DPRINTF("Invalid message namespace: '%s'", namespace_);
01149 return;
01150 }
01151
01152 const char * command = payload.command.c_str();
01153 ASSERT(command, "null");
01154 const Datahash * data = payload.arguments;
01155 ASSERT(data, "null");
01156
01157 if (!strcmp(command, "converse-dialog")) {
01158 DPRINTF("Got a dialog request!");
01159 smart_ptr<Datahash> dialog = getSubhash(data, "dialog");
01160 int playerId = getInt(data, "playerId");
01161 if (playerId < 1) {
01162 WAVE_EX(wex);
01163 wex << "Bad player id: " << playerId;
01164 }
01165 std::string conGuid = getString(data, "conversationGuid");
01166 int dialogId = getInt(data, "dialogId");
01167 if (dialogId <= 0) {
01168 WAVE_EX(wex);
01169 wex << "Bad dialog id: " << dialogId;
01170 }
01171
01172
01173 smart_ptr<converse_rec_t> cr = new converse_rec_t;
01174 ASSERT(cr, "out of memory");
01175 cr->dialogId = dialogId;
01176 cr->playerId = playerId;
01177 cr->connId = m_tcpConnID;
01178 m_conversations[conGuid] = cr;
01179
01180
01181 m_host->requestDialog(conGuid.c_str(), playerId, dialog, this);
01182 } else if (!strcmp(command, "converse-end")) {
01183 DPRINTF("Got a request to end a conversation");
01184 std::string guid = getString(data, "conversationGuid");
01185 int playerId = getInt(data, "playerId");
01186 if (playerId < 1) {
01187 WAVE_EX(wex);
01188 wex << "Bad player id: " << playerId;
01189 }
01190
01191
01192 this->deleteConversation(guid.c_str(), playerId);
01193
01194 } else if (!strcmp(command, "error")) {
01195 DPRINTF("Received error from server!");
01196 eErrorCode code = (eErrorCode) getLong(data, "errorCode");
01197 DPRINTF(" Error code: 0x%05x", code);
01198 std::string message = getString(data, "message");
01199 DPRINTF(" Message: %s", message.c_str());
01200 if (eErrorCode_Fatal & code) {
01201 ASSERT(false, "Got fatal error, stopping: %s",
01202 message.c_str());
01203 }
01204
01205 } else {
01206 DPRINTF("Unknown command: '%s'", command);
01207 }
01208 }
01209
01210
01211
01212 void
01213 ClientImpl::handleUDP
01214 (
01215 IN const envelope_t& env,
01216 IN const MessageBuffer * msg
01217 )
01218 {
01219 perf::Timer("clib::handleUDP");
01220 ASSERT(!env.is_empty(), "empty");
01221 ASSERT(msg, "null");
01222
01223
01224
01225
01226 ASSERT(m_udpIn, "should have input buffer now");
01227 m_udpIn->reset((const byte_t *) msg->getData(), msg->getBytes());
01228
01229
01230 xdrbuf::PackletHeader ph = m_udpIn->getNextPackletHeader();
01231
01232
01233 if ('s' == ph.getName()) {
01234 this->handleBroadcast(ph, env);
01235 return;
01236 }
01237
01238
01239 if ('h' != ph.getName()) {
01240 DPRINTF("Malformed input UDP packet?");
01241 return;
01242 }
01243
01244
01245 if (eClientState_Connected != m_clientState &&
01246 eClientState_Connecting != m_clientState) {
01247 DPRINTF("Ignoring incoming UDP packets");
01248 return;
01249 }
01250
01251
01252
01253
01254
01255
01256
01257
01258 int32_t l[6];
01259 m_udpIn->readInt32s(l, 6);
01260
01261
01262 dword_t token = l[0];
01263 netlib::connection_info_t ci;
01264 if (!netlib::getConnectionInfo(token, ci)) {
01265 DPRINTF("Input udp connection token is invalid");
01266 return;
01267 }
01268 if (ci.address.ip != env.address.ip) {
01269 DPRINTF("UDP sender does not match connection token");
01270 DPRINTF("From token:");
01271 ci.address.dump(" our record");
01272 DPRINTF("From envelope:");
01273 env.address.dump(" msg record");
01274 return;
01275 }
01276
01277
01278
01279
01280 dword_t clock = l[1];
01281 if (clock < m_udpMostRecentClock) {
01282 DPRINTF("Message is old!");
01283 return;
01284 }
01285 m_udpMostRecentClock = clock;
01286
01287
01288
01289 m_lastUdpServerSaw = l[2];
01290 dword_t delta = m_udpClock - m_lastUdpServerSaw;
01291 if (delta > 3) {
01292 DPRINTF("Server is %lu messages behind!", (long) delta);
01293 }
01294
01295
01296 eServerMode smode = (eServerMode) l[3];
01297 ASSERT(eServerMode_Idle == smode, "mode: %d", smode);
01298 m_hMode = (eHostMode) l[4];
01299
01300
01301 if (m_serverTcpPort != l[5]) {
01302 DPRINTF("Got new server TCP port!");
01303 if (m_tcpConnID) {
01304 netlib::closeConnection(m_tcpConnID);
01305 m_tcpConnID = 0;
01306 }
01307 m_serverTcpPort = l[5];
01308 }
01309
01310
01311 while (!m_udpIn->endOfStream()) {
01312 xdrbuf::PackletHeader ph = m_udpIn->getNextPackletHeader();
01313 char name = ph.getName();
01314
01315
01316 switch (name) {
01317
01318 case 'c':
01319 this->readConnectUDP(m_udpIn);
01320 break;
01321
01322 case 'd':
01323 this->readDestroyUDP(m_udpIn);
01324 break;
01325
01326 case 'o':
01327 this->readObjectUDP(m_udpIn);
01328 break;
01329
01330 case 'p':
01331 this->readPlayerUDP(m_udpIn);
01332 break;
01333
01334 case 'q':
01335 this->readQueryUDP(ph, m_udpIn);
01336 break;
01337
01338 default:
01339 {
01340 WAVE_EX(wex);
01341 wex << "Unknown packlet name: '" << name << "'";
01342 }
01343 }
01344 }
01345 }
01346
01347
01348
01349 void
01350 ClientImpl::handleBroadcast
01351 (
01352 IN xdrbuf::PackletHeader ph,
01353 IN const envelope_t& env
01354 )
01355 {
01356
01357
01358 const int bufsize = 255;
01359 char buffer[bufsize + 1];
01360
01361
01362 server_info_t si;
01363 std::string uuid;
01364 int port = 0;
01365
01366
01367
01368 bool firstPass = true;
01369
01370
01371 while (!m_udpIn->endOfStream()) {
01372 char name = 's';
01373 if (!firstPass) {
01374 ph = m_udpIn->getNextPackletHeader();
01375 name = ph.getName();
01376 }
01377 firstPass = false;
01378
01379
01380 switch (name) {
01381 case 's':
01382 {
01383 int len = ph.getDataCount();
01384 ASSERT2(len <= bufsize, "server public name is "
01385 << "too big: " << len << " characters");
01386 m_udpIn->readString(buffer, len);
01387 buffer[len] = 0;
01388 si.publicName = buffer;
01389 }
01390 break;
01391
01392 case 'u':
01393 {
01394 int len = ph.getDataCount();
01395 ASSERT2(len <= bufsize, "server UUID is "
01396 << "too big: " << len << " characters");
01397 m_udpIn->readString(buffer, len);
01398 buffer[len] = 0;
01399 uuid = buffer;
01400 }
01401 break;
01402
01403 case 'p':
01404 {
01405 int32_t i32;
01406 m_udpIn->readInt32s(&i32, 1);
01407 port = i32;
01408 }
01409 break;
01410
01411 default:
01412 {
01413
01414
01415
01416 DPRINTF("Unknown packlet in broadcast: '%c'",
01417 name);
01418 return;
01419 }
01420 }
01421 }
01422
01423
01424 if (port < 1) {
01425 DPRINTF("Unspecified or invalid port: %d", port);
01426 return;
01427 }
01428
01429
01430 si.address = env.address;
01431 si.address.port = port;
01432 if (!si.isValid()) {
01433 DPRINTF("Invalid server information--ignoring broadcast");
01434 return;
01435 }
01436
01437
01438 if (strcmp(uuid.c_str(), m_story->getUuid())) {
01439 DPRINTF("Ignoring broadcast from server with different story.");
01440 DPRINTF(" Our uuid: '%s'", m_story->getUuid());
01441 DPRINTF(" Server uuid: '%s'", uuid.c_str());
01442 si.address.dump(" Server address");
01443 return;
01444 }
01445
01446
01447
01448 getServerHashKey(si, buffer);
01449
01450
01451
01452 m_servers.insert(buffer, si);
01453
01454 }
01455
01456
01457
01458 void
01459 ClientImpl::readConnectUDP
01460 (
01461 IO xdrbuf::Input * input
01462 )
01463 {
01464 ASSERT(input, "null");
01465
01466
01467 xdrbuf::PackletHeader ph = input->getNextPackletHeader();
01468 if ('t' != ph.getName() || xdrbuf::ePacklet_Int32s != ph.getType()) {
01469 WAVE_EX(wex);
01470 wex << "Invalid packlet while parsing connection response";
01471 }
01472 input->readInt32s((int32_t *) &m_udpConnToken, 1);
01473
01474
01475 ph = input->getNextPackletHeader();
01476 if ('k' != ph.getName() ||
01477 xdrbuf::ePacklet_ParentBegin != ph.getType()) {
01478 WAVE_EX(wex);
01479 wex << "Invalid packlet when expecting encrypted DES key";
01480 }
01481 int maxSize = 1024;
01482 char buffer[maxSize];
01483 char * offset = buffer;
01484 int read = 0;
01485
01486 while (true) {
01487 xdrbuf::PackletHeader ph = input->getNextPackletHeader();
01488 if ('k' == ph.getName() &&
01489 xdrbuf::ePacklet_ParentEnd == ph.getType())
01490 break;
01491
01492 if (xdrbuf::ePacklet_String != ph.getType()) {
01493 WAVE_EX(wex);
01494 wex << "Invalid packlet while reading des key";
01495 }
01496
01497 int bytes = ph.getDataCount();
01498 if (read + bytes > maxSize - 1) {
01499 WAVE_EX(wex);
01500 wex << "Encrypted DES key is too big!";
01501 }
01502
01503 input->readString(offset, bytes);
01504 read += bytes;
01505 offset += bytes;
01506 }
01507 buffer[read] = 0;
01508
01509
01510 ph = input->getNextPackletHeader();
01511 if ('c' != ph.getName() || xdrbuf::ePacklet_ParentEnd != ph.getType()) {
01512 WAVE_EX(wex);
01513 wex << "Expected end of connection response packlet";
01514 }
01515
01516
01517 this->setKeys(buffer);
01518 }
01519
01520
01521
01522 void
01523 ClientImpl::readDestroyUDP
01524 (
01525 IO xdrbuf::Input * input
01526 )
01527 {
01528 ASSERT(input, "null");
01529
01530
01531 dword_t objectId;
01532 input->readInt32s((int32_t *) &objectId, 1);
01533 if (objectId < 1) {
01534 WAVE_EX(wex);
01535 wex << "Bad object ID: " << objectId;
01536 }
01537
01538
01539
01540
01541 m_syncMgr->removeObject(objectId);
01542 }
01543
01544
01545
01546 void
01547 ClientImpl::readPlayerUDP
01548 (
01549 IO xdrbuf::Input * inbuf
01550 )
01551 {
01552 ASSERT(inbuf, "null");
01553
01554
01555
01556
01557 int32_t l[3];
01558 inbuf->readInt32s(l, 3);
01559
01560
01561 int playerId = (int) l[0];
01562
01563 dword_t objectId = l[2];
01564
01565
01566 if (playerId < 1) {
01567 WAVE_EX(wex);
01568 wex << "Bad player id from server: " << playerId;
01569 }
01570
01571 client_player_record_t * cpr = this->getPlayer(playerId);
01572 if (!cpr) {
01573 DPRINTF("Server has player we don't?: %d", playerId);
01574 return;
01575 }
01576 ASSERT(cpr, "null");
01577
01578
01579 cpr->objectId = objectId;
01580
01581
01582
01583
01584 ASSERT(m_syncMgr, "null");
01585 ASSERT(m_host, "null");
01586 if (!objectId) {
01587
01588 smart_ptr<MapDynamics> nullMap;
01589 m_host->notifyPlayerMap(playerId, nullMap);
01590 return;
01591 }
01592
01593
01594 object_state_t state;
01595 if (!m_syncMgr->getState(objectId, state)) {
01596 return;
01597 }
01598
01599
01600 m_host->notifyPlayerMap(playerId, state.dyn);
01601 }
01602
01603
01604
01605 void
01606 ClientImpl::readQueryUDP
01607 (
01608 IN const xdrbuf::PackletHeader& ph_in,
01609 IO xdrbuf::Input * input
01610 )
01611 {
01612 ASSERT(input, "null");
01613
01614 DPRINTF("Got query response");
01615
01616
01617
01618
01619 if (xdrbuf::ePacklet_ParentBegin != ph_in.getType()) {
01620 WAVE_EX(wex);
01621 wex << "invalid (non-parent) packlet type for query response";
01622 }
01623
01624
01625 dword_t objectId;
01626 xdrbuf::PackletHeader ph = input->getNextPackletHeader();
01627 if ('i' != ph.getName() ||
01628 xdrbuf::ePacklet_Int32s != ph.getType() ||
01629 1 != ph.getDataCount()) {
01630 WAVE_EX(wex);
01631 wex << "invalid object ID packlet in query response";
01632 }
01633 input->readInt32s((int32_t *) &objectId, 1);
01634
01635
01636 ph = input->getNextPackletHeader();
01637 int c = ph.getDataCount();
01638 if ('t' != ph.getName() ||
01639 xdrbuf::ePacklet_String != ph.getType() ||
01640 c > eAESOP_MaxIdLength) {
01641 WAVE_EX(wex);
01642 wex << "invalid object type ID in query response";
01643 }
01644 char buffer[eAESOP_IdBufferSize];
01645 input->readString(buffer, c);
01646 buffer[c] = 0;
01647
01648
01649 ph = input->getNextPackletHeader();
01650 c = ph.getDataCount();
01651 if ('m' != ph.getName() ||
01652 xdrbuf::ePacklet_String != ph.getType() ||
01653 c > eAESOP_MaxIdLength) {
01654 WAVE_EX(wex);
01655 wex << "invalid map ID in query response";
01656 }
01657 char mapId[eAESOP_IdBufferSize];
01658 input->readString(mapId, c);
01659 mapId[c] = 0;
01660
01661
01662 ph = input->getNextPackletHeader();
01663 if ('q' != ph.getName() ||
01664 xdrbuf::ePacklet_ParentEnd != ph.getType()) {
01665 WAVE_EX(wex);
01666 wex << "Unrecognized packlet in query response";
01667 }
01668
01669
01670 DPRINTF("Have a type ID for object %ld: '%s'",
01671 (long) objectId, buffer);
01672 DPRINTF(" mapId = '%s'", mapId);
01673 m_syncMgr->setTypeId(objectId, buffer);
01674 m_syncMgr->setMapId(objectId, mapId);
01675
01676
01677 sprintf(buffer, "qo%ld", (long) objectId);
01678 m_netQueue->removeRequest(buffer);
01679 }
01680
01681
01682
01683 void
01684 ClientImpl::readObjectUDP
01685 (
01686 IO xdrbuf::Input * inbuf
01687 )
01688 {
01689 ASSERT(inbuf, "null");
01690
01691
01692
01693
01694 dword_t objectId = 0;
01695 state_update_t update;
01696 bool havePosition = false;
01697 bool haveAnimation = false;
01698
01699 const int bufsize = 512;
01700 char buffer[bufsize];
01701 buffer[0] = 0;
01702
01703
01704 bool halt = false;
01705 while (!halt) {
01706 xdrbuf::PackletHeader ph = inbuf->getNextPackletHeader();
01707 char name = ph.getName();
01708
01709 switch (name) {
01710 case 'i':
01711
01712 inbuf->readInt32s((int32_t *) &objectId, 1);
01713 break;
01714
01715 case 'p':
01716
01717 inbuf->readFloats(&update.position.x, 3);
01718 havePosition = true;
01719 break;
01720
01721 case 'o':
01722
01723 if (xdrbuf::ePacklet_ParentEnd == ph.getType()) {
01724 halt = true;
01725 } else {
01726 inbuf->readFloats(&update.orientation.x, 4);
01727 }
01728 break;
01729
01730 case 'l':
01731
01732 inbuf->readFloats(&update.linear.x, 3);
01733 break;
01734
01735 case 'a':
01736
01737 inbuf->readFloats(&update.angular.x, 3);
01738 break;
01739
01740 case 'n':
01741
01742 {
01743 int len = ph.getDataCount();
01744 if (len >= bufsize) {
01745 DPRINTF("ERROR: animation state too big?");
01746 } else {
01747 haveAnimation = true;
01748 inbuf->readString(buffer, len);
01749 buffer[len] = 0;
01750
01751
01752 }
01753 }
01754 break;
01755
01756 default:
01757 {
01758 WAVE_EX(wex);
01759 wex << "Unrecognized packlet name '" << name;
01760 wex << "' while parsing map object";
01761 }
01762 }
01763 }
01764
01765
01766 if (!objectId) {
01767 WAVE_EX(wex);
01768 wex << "No or null object ID received";
01769 }
01770 if (!havePosition) {
01771 WAVE_EX(wex);
01772 wex << "No position received for object: " << objectId;
01773 }
01774
01775
01776
01777
01778 ASSERT(m_syncMgr, "null");
01779 m_syncMgr->serverUpdate(objectId, m_lastUdpServerSaw, update);
01780
01781
01782 object_state_t state;
01783 ASSERT(m_syncMgr->getState(objectId, state),
01784 "Just updated this object, it should exist! id=%lu",
01785 (long) objectId);
01786 if (state.physicsObject) {
01787
01788 if (haveAnimation) {
01789 m_host->updateAnimation(state.physicsObject, buffer);
01790 }
01791 return;
01792 }
01793
01794
01795
01796
01797 smart_ptr<netrq::Request> ctx = QueryObjectRequest::create(objectId);
01798 ASSERT(ctx, "null");
01799
01800
01801 if (netrq::Queue::eQueue_Success == m_netQueue->addRequest(m_udpClock + 3, ctx)) {
01802 ASSERT(ctx.get_ref_count() > 1, "bad ref count");
01803 }
01804 }
01805
01806
01807
01808 void
01809 ClientImpl::setKeys
01810 (
01811 IN const char * encryptedDesKey
01812 )
01813 {
01814 ASSERT(encryptedDesKey, "null");
01815
01816 std::string desKey = m_rsaKey->decrypt(encryptedDesKey);
01817 DPRINTF("decrypted DES key: %s", desKey.c_str());
01818
01819 m_desKey = crypto::DESKey::create(desKey.c_str());
01820 ASSERT(m_desKey, "null");
01821
01822
01823 m_host->notifyKey(m_desKey);
01824 }
01825
01826
01827
01828
01865
01866
01867 void
01868 ClientImpl::sendUdpPacket
01869 (
01870 IN float dt
01871 )
01872 {
01873 perf::Timer timer("Client::sendUdpPacket");
01874 ASSERT(dt > 0.0, "Bad time delta: %f", dt);
01875 ASSERT(m_udpOut, "Should have a udp output buffer by now");
01876 if (!m_remoteUdpConnID) {
01877 return;
01878 }
01879
01880
01881 ++m_udpClock;
01882
01883
01884 m_syncMgr->addRequests(m_netQueue, m_udpClock);
01885
01886
01887
01888 m_udpOut->clear();
01889
01890
01891
01892
01893 int32_t l[3];
01894 l[0] = m_udpConnToken;
01895 l[1] = m_udpClock;
01896 m_udpOut->addInt32Packlet('h', l, 2);
01897
01898 if (eHostMode_Authorized == m_hMode) {
01899
01900 for (player_map_t::iterator i = m_players.begin(); i != m_players.end();
01901 ++i)
01902 {
01903 int id = i->first;
01904 client_player_record_t * pr = i->second;
01905 ASSERT(pr, "null player record in map");
01906
01907
01908 m_udpOut->openPacklet('p');
01909
01910
01911 dword_t dwId = id;
01912 m_udpOut->addInt32Packlet('i', (int32_t *) &dwId, 1);
01913
01914
01915 object_state_t state;
01916 if (pr->objectId &&
01917 m_syncMgr->getState(pr->objectId, state) &&
01918 state.physicsObject) {
01919
01920
01921
01922 float f[7];
01923 f[0] = pr->delta.x;
01924 f[1] = pr->delta.y;
01925 f[2] = pr->delta.z;
01926 f[3] = dt;
01927 f[4] = pr->euler.x;
01928 f[5] = pr->euler.y;
01929 f[6] = pr->euler.z;
01930 m_udpOut->addFloatPacklet('m', f, 7);
01931
01932
01933 pr->delta.clear();
01934 }
01935
01936
01937 m_udpOut->closePacklet('p');
01938 }
01939 }
01940
01941
01942
01943 netrq::sendMessagesFromQueue(m_udpOut, m_udpClock, m_netQueue);
01944
01945
01946 m_udpOut->openPacklet('g');
01947 {
01948 perf::Timer timer("appendGameData");
01949 m_host->appendGameData(m_udpOut);
01950 }
01951 m_udpOut->closePacklet('g');
01952
01953
01954
01955
01956 smart_ptr<MessageBuffer> mb = MessageBuffer::create();
01957 ASSERT(mb, "failed to create message buffer");
01958 const byte_t * pb = m_udpOut->getData();
01959 int bytes = m_udpOut->getDataBytes();
01960 ASSERT(bytes > 0, "Bad udp byte count: %d", bytes);
01961 mb->reserve(bytes);
01962 mb->appendData((const char *) pb, bytes);
01963 mb->close();
01964
01965
01966 netlib::enqueueMessage(m_remoteUdpConnID, mb);
01967 }
01968
01969
01970
01972
01973
01974
01976
01977 smart_ptr<Client>
01978 Client::create
01979 (
01980 IN ClientHost * host,
01981 IN smart_ptr<story::Story>& story,
01982 IN smart_ptr<Datahash>& params
01983 )
01984 {
01985 ASSERT(host, "null");
01986 ASSERT(story, "null");
01987 ASSERT(params, "null");
01988
01989 smart_ptr<ClientImpl> local = new ClientImpl;
01990 ASSERT(local, "null");
01991
01992 local->initialize(host, story, params);
01993
01994 return local;
01995 }
01996
01997
01998
01999 };
02000