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
00035
00036
00037
00038
00039
00040 #include "aesop-srv.h"
00041
00042 #include <math.h>
00043
00044
00045 #include "srv-converse.h"
00046 #include "srv-hosts.h"
00047 #include "srv-msg-router.h"
00048 #include "srv-physics.h"
00049 #include "srv-players.h"
00050 #include "srv-users.h"
00051
00052 #include "common/wave_ex.h"
00053 #include "conversation/conversation.h"
00054 #include "aesop-proto/message.h"
00055 #include "aesop-proto/protocol.h"
00056 #include "crypto/crypto.h"
00057 #include "datahash/datahash_util.h"
00058 #include "map-dynamics/map-dynamics.h"
00059 #include "map-manager/map-manager.h"
00060 #include "netrq/netrq.h"
00061 #include "perf/perf.h"
00062 #include "story/story.h"
00063 #include "threadpool/threadpool.h"
00064 #include "threadsafe/threadsafe_counter.h"
00065 #include "threadsafe/threadsafe_map.h"
00066 #include "threadsafe/threadsafe_queue.h"
00067 #include "xdrbuf/xdrbuf.h"
00068
00069
00070 namespace aesop {
00071
00072
00073
00074 Server::~Server(void) throw() { }
00075
00076
00077 typedef threadsafe_map<int, std::string> name_map_t;
00078
00079
00080
00081 class handler_intercept_t {
00082 public:
00083
00084 handler_intercept_t(IN const threadsafe_refcount& in_trc) throw() :
00085 trc(in_trc) {
00086 fn = NULL;
00087 state.clear();
00088 map = NULL;
00089 }
00090
00091
00092 msg_handler_fn fn;
00093 handler_state_t state;
00094 name_map_t * map;
00095
00096 private:
00097
00098 threadsafe_refcount trc;
00099 };
00100
00101
00102
00103 typedef std::vector<conn_id_t> vec_conn_t;
00104
00105
00106
00107 static const int s_maxNetQueueLength = 256;
00108
00109
00110 static const int s_bcastBuffer = 128;
00111
00112
00114
00115
00116
00118
00119 static void
00120 interceptHandler
00121 (
00122 IN void * context
00123 )
00124 {
00125 perf::Timer timer("aesop_srv::interceptHandler");
00126 ASSERT(context, "null");
00127 handler_intercept_t * ctx = (handler_intercept_t *) context;
00128 ASSERT(ctx, "null");
00129
00130
00131 smart_ptr<handler_intercept_t> smart_hi = ctx;
00132
00133 ASSERT(ctx->fn, "null handler fn?");
00134 ASSERT(ctx->state.story, "null story?");
00135 ASSERT(ctx->state.updates, "null updates interface");
00136
00137 ctx->fn(ctx->state);
00138 }
00139
00140
00141
00143
00144
00145
00147
00148 class QueryContext : public netrq::Request {
00149 public:
00150 QueryContext(IN dword_t objectId) throw() {
00151 sprintf(m_id, "qr%ld", (long) objectId);
00152 m_objectId = objectId;
00153 }
00154 ~QueryContext(void) throw() { }
00155
00156 void write(IO xdrbuf::Output * output) {
00157
00158 smart_ptr<PhysicsObject> obj =
00159 getPhysicsObjectById(m_objectId);
00160 if (!obj) {
00161 DPRINTF("Client asked for object not there");
00162
00163
00164
00165 } else {
00166 DPRINTF("Telling client about object %ld",
00167 (long) m_objectId);
00168 smart_ptr<Instance> instance =
00169 getInstanceFromPhysicsObject(obj);
00170 if (!instance)
00171 return;
00172
00173 const char * typeId = instance->getTypeId();
00174 int tiLength = strlen(typeId);
00175
00176 point3d_t pos = obj->getPosition();
00177
00178
00179
00180 MapDynamics * dyn =
00181 getMapDynamicsFromPhysicsObject(obj);
00182 if (!dyn) {
00183 return;
00184 }
00185
00186 Map * map = dyn->getMap();
00187 ASSERT(map, "null");
00188
00189 const char * mapId = map->getId();
00190 int miLength = strlen(mapId);
00191
00192
00193 output->openPacklet('q');
00194 output->addInt32Packlet('i',
00195 (int32_t *) &m_objectId, 1);
00196 output->addStringPacklet(
00197 't', typeId, tiLength);
00198 output->addStringPacklet(
00199 'm', mapId, miLength);
00200 output->closePacklet('q');
00201 }
00202 }
00203
00204 int getMaxBytes(void) const throw() {
00205 return 255 + 255 + 4 + 4 + 4 * 2;
00206 }
00207
00208 const char * getId(void) const throw() { return m_id; }
00209
00210 private:
00211 char m_id[32];
00212 dword_t m_objectId;
00213 };
00214
00215
00216
00217 class AuthContext : public netrq::Request {
00218 public:
00219 AuthContext(IN dword_t token,
00220 IN const char * key) {
00221 ASSERT(token, "null");
00222 ASSERT(key, "null");
00223 sprintf(m_id, "auth%ld", (long) token);
00224 m_token = token;
00225 m_encryptedDesKey = key;
00226 }
00227 ~AuthContext(void) throw() { }
00228
00229 void write(IN xdrbuf::Output * output) {
00230 ASSERT(output, "null");
00231
00232 output->openPacklet('c');
00233 output->addInt32Packlet('t',
00234 (int32_t *) &m_token, 1);
00235 output->openPacklet('k');
00236
00237 const char * key = m_encryptedDesKey.c_str();
00238 int len = m_encryptedDesKey.length();
00239 while (len) {
00240 int send = len;
00241 if (send > 255) {
00242 send = 255;
00243 }
00244 output->addStringPacklet('a', key, send);
00245 key += send;
00246 len -= send;
00247 }
00248 output->closePacklet('k');
00249 output->closePacklet('c');
00250 }
00251
00252 int getMaxBytes(void) const throw() {
00253 return 4 + 512 + 5 * 2;
00254 }
00255
00256 const char * getId(void) const throw() { return m_id; }
00257
00258 private:
00259 char m_id[32];
00260 dword_t m_token;
00261 std::string m_encryptedDesKey;
00262 };
00263
00264
00265
00266 class ObjectExistsResponse : public netrq::Request {
00267 public:
00268 ~ObjectExistsResponse(void) throw() { }
00269
00270
00271 const char * getId(void) const throw() { return m_requestId; }
00272 int getMaxBytes(void) const throw() { return 6; }
00273 void write(IO xdrbuf::Output * output) {
00274 ASSERT(output, "null");
00275
00276
00277 smart_ptr<PhysicsObject> obj =
00278 getPhysicsObjectById(m_objectId);
00279 if (obj && obj->getId()) {
00280
00281 return;
00282 }
00283
00284
00285 output->addInt32Packlet('d',
00286 (int32_t *) &m_objectId, 1);
00287 }
00288
00289
00290 static smart_ptr<netrq::Request> create(IN const char * requestId,
00291 IN long objectId) {
00292 ASSERT(requestId, "null");
00293 ASSERT(objectId, "null");
00294
00295 smart_ptr<ObjectExistsResponse> local =
00296 new ObjectExistsResponse;
00297 ASSERT(local, "out of memory");
00298
00299 strcpy(local->m_requestId, requestId);
00300 local->m_objectId = objectId;
00301
00302 return local;
00303 }
00304 private:
00305
00306 ObjectExistsResponse(void) throw() { }
00307
00308
00309 char m_requestId[64];
00310 dword_t m_objectId;
00311 };
00312
00313
00314
00316
00317
00318
00320
00321 class ServerImpl : public StateUpdates,
00322 public Server,
00323 public converse::ConversationRouter {
00324 public:
00325 ServerImpl(void) throw();
00326 ~ServerImpl(void) throw() { }
00327
00328
00329 void initialize(IN smart_ptr<Datahash>& params,
00330 IN smart_ptr<ServerGameLogic>& gameLogic);
00331
00332
00333 int exec(void);
00334 void requestStopTS(IN int retval);
00335
00336
00337
00338 void enqueueMessageTS(IN conn_id_t connId,
00339 IN smart_ptr<MessageBuffer>& message);
00340 void newTcpConnectionTS(IN conn_id_t connId,
00341 IN long token);
00342 void notifyDialogReplyTS(IN conn_id_t conn_id,
00343 IN const char * conversationGuid,
00344 IN int dialogId,
00345 IN int playerId,
00346 IN const Datahash * reply);
00347 bool setPlayerUserAccountTS(IN conn_id_t conn_id,
00348 IN int playerId,
00349 IN const char * username,
00350 IN const char * usertag,
00351 OUT std::string& diagnostic);
00352 void newGameTS(IN conn_id_t connId,
00353 IN int playerId);
00354 void requestShutdownTS(void);
00355
00356
00357 void routeConversationTS(IN const char * guid,
00358 IN int dialogId,
00359 IN int playerId,
00360 IN conn_id_t connId,
00361 IN const char * dialogData);
00362
00363 private:
00364
00365 struct request_t {
00366
00367 request_t(void) throw() { this->clear(); }
00368 void clear(void) throw() {
00369 conn_id = 0;
00370 message = NULL;
00371 }
00372 bool is_empty(void) const throw() {
00373 return (!conn_id && !message);
00374 }
00375
00376
00377 conn_id_t conn_id;
00378 smart_ptr<MessageBuffer> message;
00379 };
00380 typedef threadsafe_queue<request_t> msg_queue_t;
00381
00382
00383 void checkMessages(IN long microseconds);
00384 void handleMessage(IN const envelope_t& env,
00385 IN const MessageBuffer * msg);
00386 void handleUdp(IN const envelope_t& env,
00387 IN const MessageBuffer * msg);
00388 void parseHostConnectUdp(IN const netlib::envelope_t& env,
00389 IO xdrbuf::Input * input);
00390 void parseHostAuthUdp(IN host_rec_t& hr,
00391 IN const xdrbuf::PackletHeader& ph,
00392 IO xdrbuf::Input * input);
00393 void parsePlayerUdp(IN host_rec_t& hr,
00394 IO xdrbuf::Input * input);
00395 void parseQueryUdp(IN host_rec_t& hr,
00396 IN const xdrbuf::PackletHeader& ph,
00397 IO xdrbuf::Input * input);
00398 void parseGameUdp(IN host_rec_t& hr,
00399 IN const xdrbuf::PackletHeader& ph,
00400 IO xdrbuf::Input * input);
00401 void parseExistsUdp(IN host_rec_t& hr,
00402 IO xdrbuf::Input * input);
00403 void sendUdp(void);
00404 const char * getStoryGuidTS(void);
00405 void newPlayer(IN host_rec_t& hr, IN int playerId);
00406 bool isAdmin(IN conn_id_t udpConnID, IN int playerId);
00407 void checkPlayers(void);
00408 void sendBroadcast(void);
00409
00410
00411 smart_ptr<story::Story> m_story;
00412 smart_ptr<MessageRouter> m_router;
00413 smart_ptr<threadpool::Pool> m_threadpool;
00414 smart_ptr<Datahash> m_params;
00415 smart_ptr<converse::ConversationManager> m_conversationMgr;
00416 smart_ptr<UserManager> m_userMgr;
00417 smart_ptr<PlayerManager> m_playerMgr;
00418 smart_ptr<HostManager> m_hostMgr;
00419 smart_ptr<MapManager> m_mapMgr;
00420 smart_ptr<ServerGameLogic> m_gameLogic;
00421 smart_ptr<xdrbuf::Input> m_xdrInput;
00422 smart_ptr<xdrbuf::Output> m_xdrBcast;
00423 msg_queue_t m_outboundMessages;
00424 float m_requestedHz;
00425 float m_udpHz;
00426 bool m_shutdown;
00427 int m_retval;
00428 conn_id_t m_tcpConn;
00429 int m_udpPort;
00430 int m_tcpPort;
00431 conn_id_t m_udpConn;
00432 conn_id_t m_udpBcast;
00433 threadsafe_refcount m_workerTrc;
00434 name_map_t m_threadNames;
00435 int m_threadCounter;
00436 eServerMode m_smode;
00437 dword_t m_udpClock;
00438 int m_bcastDelay;
00439 std::string m_publicName;
00440 };
00441
00442
00443
00444 ServerImpl::ServerImpl(void)
00445 throw()
00446 {
00447 m_shutdown = false;
00448 m_retval = 0;
00449 m_threadCounter = 0;
00450 m_requestedHz = 0;
00451 m_udpHz = 0;
00452 m_udpPort = 0;
00453 m_tcpPort = 0;
00454 m_udpConn = 0;
00455 m_tcpConn = 0;
00456 m_udpBcast = 0;
00457 m_smode = eServerMode_Invalid;
00458 m_udpClock = 0;
00459 m_bcastDelay = 4;
00460 }
00461
00462
00463
00464 void
00465 ServerImpl::initialize
00466 (
00467 IN smart_ptr<Datahash>& params,
00468 IN smart_ptr<ServerGameLogic>& gameLogic
00469 )
00470 {
00471 ASSERT(params, "null");
00472 ASSERT(gameLogic, "null");
00473
00474 DPRINTF("In Server::initialize()...");
00475
00476
00477 m_params = params;
00478
00479
00480 m_gameLogic = gameLogic;
00481
00482
00483 ASSERT(!m_xdrInput, "Alread have an input parser?");
00484 m_xdrInput = xdrbuf::Input::create();
00485 ASSERT(m_xdrInput, "Failed to create xdr input parser");
00486
00487
00488 ASSERT(!m_xdrBcast, "Already have an output buffer");
00489 m_xdrBcast = xdrbuf::Output::create(s_bcastBuffer);
00490 ASSERT(m_xdrBcast, "null");
00491
00492
00493 m_requestedHz = getFloat(params, "requestedHz");
00494 if (m_requestedHz < 1.0 || m_requestedHz > 200.0) {
00495 WAVE_EX(wex);
00496 wex << "Invalid requested Hz: " << m_requestedHz;
00497 wex << ". Should be be between 1 and 200 Hz";
00498 }
00499
00500
00501 m_udpHz = getFloat(params, "udpHz");
00502 if (m_udpHz < 1 || m_udpHz > 20) {
00503 WAVE_EX(wex);
00504 wex << "Invalid udp Hz: " << m_udpHz;
00505 }
00506
00507 int udpSize = getInt(params, "udpSize");
00508 if (udpSize < 64 || udpSize > 1024) {
00509 WAVE_EX(wex);
00510 wex << "Invalid udp packet size: " << udpSize;
00511 }
00512
00513
00514 const char * locale = i18n::getHostLocale();
00515 ASSERT_THROW(locale, "failed to determine host locale?");
00516 DPRINTF("Using locale: '%s'", locale);
00517
00518
00519 const char * story_dir = getString(params, "storyDir");
00520 m_story = story::Story::create(locale, story_dir);
00521 ASSERT(m_story, "failed to load story");
00522
00523
00524 smart_ptr<Datahash> pool_params = getSubhash(params, "threadpool");
00525 ASSERT(pool_params, "should have subhash for threadpool init");
00526 m_threadpool = threadpool::Pool::create(pool_params);
00527 ASSERT(m_threadpool, "failed to create thread pool for server");
00528
00529
00530
00531 netlib::map_ip_addr_t ips;
00532 netlib::getLocalInterfaces(ips);
00533 netlib::ip_addr_t bestGuess;
00534 DPRINTF("Checking server interfaces:");
00535 for (netlib::map_ip_addr_t::const_iterator i = ips.begin();
00536 i != ips.end(); ++i) {
00537 const char * name = i->first.c_str();
00538 const netlib::ip_addr_t& ip = i->second;
00539
00540 ip.dump(name);
00541 if (!ip.isLoopback()) {
00542 bestGuess = ip;
00543 }
00544 }
00545 if (!bestGuess.isValid()) {
00546 DPRINTF("No non-loopback interfaces available!");
00547 DPRINTF("Server is using loopback interface only");
00548 bestGuess.setLoopback();
00549 }
00550 bestGuess.setBroadcast();
00551
00552
00553 netlib::address_t bcastAddress;
00554 int clientPort = eDefaultPort_clientUdp;
00555 const char * clientPortStr =
00556 getString(params, "clientPort", eDatahash_Optional);
00557 if (!clientPortStr) {
00558 DPRINTF("No client UDP port specified, using default: %d",
00559 clientPort);
00560 } else {
00561 DPRINTF("Overriding default client port of %d", clientPort);
00562 clientPort = atoi(clientPortStr);
00563 DPRINTF(" with new port value: %d", clientPort);
00564 ASSERT2(clientPort > 0, "Bad client udp port: " << clientPort);
00565 }
00566 const char * bcastIP =
00567 getString(params, "broadcastAddress", eDatahash_Optional);
00568 if (!bcastIP) {
00569 DPRINTF("No broadcastAddress specified, using auto-detected address");
00570 bcastAddress.ip = bestGuess;
00571 bcastAddress.port = clientPort;
00572 } else {
00573 DPRINTF("Overriding autodetected broadcast address");
00574 bestGuess.dump("autodetected broadcast address");
00575 bcastAddress.set(bcastIP, clientPort);
00576 }
00577 bcastAddress.dump("UDP broadcast address");
00578 m_publicName = getString(params, "publicName");
00579
00580
00581 m_udpPort = getInt(params, "udpPort");
00582 ASSERT(m_udpPort > 0, "Bad udp port: %d", m_udpPort);
00583 ASSERT(!m_udpConn, "already have a UDP listener?");
00584 netlib::address_t udpAddress;
00585 udpAddress.setlocal(m_udpPort);
00586 udpAddress.dump("UDP address");
00587
00588 m_udpConn = netlib::createUdpLocal(udpAddress);
00589 ASSERT(m_udpConn, "null");
00590 ASSERT(!m_udpBcast, "already have a UDP broadcaster?");
00591 m_udpBcast = netlib::createUdpBroadcast(bcastAddress);
00592 ASSERT2(m_udpBcast, "null");
00593
00594
00595 m_router = MessageRouter::create();
00596 ASSERT(m_router, "Failed to create message router");
00597
00598
00599 m_conversationMgr = converse::ConversationManager::create(this);
00600 ASSERT(m_conversationMgr, "failed to create conversation manager");
00601
00602
00603 m_userMgr = UserManager::create(params);
00604 ASSERT(m_userMgr, "failed to create user manager");
00605
00606
00607 m_playerMgr = PlayerManager::create(m_userMgr);
00608 ASSERT(m_playerMgr, "failed to create player manager");
00609
00610
00611 m_hostMgr = HostManager::create(udpSize);
00612 ASSERT(m_hostMgr, "failed to create host manager");
00613
00614
00615 m_mapMgr = MapManager::create(params, m_story);
00616 ASSERT(m_mapMgr, "failed to create map manager");
00617
00618
00619 m_gameLogic->setPlayerManager(m_playerMgr);
00620 m_gameLogic->setMapManager(m_mapMgr);
00621
00622
00623 m_tcpPort = getInt(params, "tcpPort");
00624 ASSERT(m_tcpPort > 0, "Bad listening port: %d", m_tcpPort);
00625 int backlog = getInt(params, "tcpBacklog");
00626 ASSERT(backlog > 0, "Bad max backlog: %d", backlog);
00627 ASSERT(!m_tcpConn, "already have a tcp listener?");
00628 netlib::address_t tcpAddress;
00629 tcpAddress.setlocal(m_tcpPort);
00630 tcpAddress.dump("TCP Address");
00631 m_tcpConn = netlib::createTcpListener(tcpAddress, backlog);
00632 ASSERT(m_tcpConn, "failed to create tcp listener socket");
00633
00634
00635 initializeTypeInstanceLibrary(m_story);
00636
00637
00638 m_smode = eServerMode_Idle;
00639 }
00640
00641
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676 int
00677 ServerImpl::exec
00678 (
00679 void
00680 )
00681 {
00682 perf::Timer timer("aesop-srv::main-loop");
00683
00684
00685 ASSERT(m_requestedHz > 0 && m_requestedHz < 1000,
00686 "Bad server frequency? %f hz", m_requestedHz);
00687 int loop_us = (int) (1.0e6 / m_requestedHz);
00688 int max_usec = loop_us + 1000;
00689 loop_us -= 1000;
00690 DPRINTF("Server loop requested to run at %.1f hz", m_requestedHz);
00691 DPRINTF(" That means %d microseconds per loop", loop_us);
00692 ASSERT(loop_us > 0 && loop_us < 1000 * 1000,
00693 "Bad loop microseconds? %d", loop_us);
00694
00695
00696 DPRINTF("UDP packets requested at %.1f hz", m_udpHz);
00697 int udpSend = (int) ((m_requestedHz / m_udpHz) + 0.5);
00698 DPRINTF("Sending udp packets every %d cycles", udpSend);
00699
00700
00701 perf::time_t dt(0, loop_us);
00702
00703
00704 ASSERT2(m_bcastDelay > 0, "Bad delay: " << m_bcastDelay);
00705 perf::time_t bcastDt(m_bcastDelay, 0);
00706
00707
00708 perf::time_t target = perf::getNow();
00709 target.increment(dt);
00710
00711
00712 perf::time_t targetBcast = perf::getNow();
00713 targetBcast.increment(bcastDt);
00714
00715 perf::time_t benchmark = perf::getNow();
00716 static const int s_benchmarkCount = (int) (3 * m_requestedHz);
00717
00718
00719 int udpCount = 0;
00720 perf::time_t lastLoopTime = perf::getNow();
00721 for (long loop_counter = 0; !m_shutdown; ++loop_counter, udpCount++) {
00722
00723
00724 perf::time_t now = perf::getNow();
00725 perf::time_t delta = now;
00726 delta.decrement(lastLoopTime);
00727 lastLoopTime = now;
00728
00729
00730 if (now.isGreaterThan(targetBcast)) {
00731 this->sendBroadcast();
00732 targetBcast = now;
00733 targetBcast.increment(bcastDt);
00734 }
00735
00736
00737
00738 if (s_benchmarkCount == loop_counter) {
00739 loop_counter = 0;
00740 perf::time_t delta = now;
00741 delta.decrement(benchmark);
00742 double delta_t = delta.getSeconds();
00743 if (delta_t > 0.01) {
00744 double hz = s_benchmarkCount / delta_t;
00745 double dr = (hz / m_requestedHz) - 1.0;
00746
00747
00748
00749 double s = dt.getSeconds();
00750 s *= 1.0 + 0.15 * dr;
00751 int usec = (int) (1000 * 1000 * s);
00752 if (usec >= 0 && usec < max_usec) {
00753 perf::time_t new_dt(0, usec);
00754 dt = new_dt;
00755 }
00756 }
00757 benchmark = now;
00758 }
00759
00760
00761 this->checkPlayers();
00762
00763
00764 float delta_seconds = (float) delta.getSeconds();
00765 if (delta_seconds < 1.0e-6) {
00766
00767 delta_seconds = 1.0e-6;
00768 }
00769 m_mapMgr->tickMaps(delta_seconds);
00770
00771
00772 {
00773 perf::Timer timer("game-logic-tick");
00774 m_gameLogic->tick(delta_seconds);
00775 }
00776
00777
00778 if (udpCount >= udpSend) {
00779 udpCount = 0;
00780 try {
00781 this->sendUdp();
00782 } catch (std::exception& e) {
00783 DPRINTF("Failed to send UDP packets: %s",
00784 e.what());
00785 }
00786 }
00787
00788
00789 while (true) {
00790 perf::time_t now = perf::getNow();
00791 if (now.isGreaterThan(target)) {
00792 target = now;
00793 target.increment(dt);
00794 break;
00795 }
00796
00797
00798 request_t req;
00799 if (m_outboundMessages.pop_front(req)) {
00800 ASSERT(!req.is_empty(),
00801 "empty message in queue");
00802 netlib::enqueueMessage(req.conn_id,
00803 req.message);
00804 }
00805
00806
00807 perf::time_t delta;
00808 delta = target;
00809 delta.decrement(now);
00810 this->checkMessages(delta.getMicroseconds());
00811 }
00812 }
00813 DPRINTF("Shutting down server!");
00814
00815
00816 DPRINTF("Waiting for worker threads to exit...");
00817 for (;;) {
00818 long lCount = m_workerTrc.getRefCount();
00819 if (lCount < 2) {
00820 break;
00821 }
00822 DPRINTF(" Waiting for %ld workers to exit...", lCount - 1);
00823
00824
00825 name_map_t::iterator_t i;
00826 m_threadNames.getIterator(i);
00827 int nThread;
00828 std::string name;
00829 while (m_threadNames.getNextElement(i, nThread, name)) {
00830 DPRINTF(" Thread %3d = %s", nThread, name.c_str());
00831 }
00832
00833
00834 sleep(1);
00835 }
00836
00837
00838 netlib::dumpStats();
00839
00840
00841 return m_retval;
00842 }
00843
00844
00845
00846 void
00847 ServerImpl::requestStopTS
00848 (
00849 IN int retval
00850 )
00851 {
00852
00853
00854
00855
00856
00857
00858 m_retval = retval;
00859 m_shutdown = true;
00860 }
00861
00862
00863
00865
00866
00867
00868
00869
00871
00872 void
00873 ServerImpl::enqueueMessageTS
00874 (
00875 IN conn_id_t connId,
00876 IN smart_ptr<MessageBuffer>& message
00877 )
00878 {
00879 ASSERT(connId, "null");
00880 ASSERT(message, "null");
00881
00882
00883 request_t req;
00884 req.conn_id = connId;
00885 req.message = message;
00886 m_outboundMessages.push_back(req);
00887 }
00888
00889
00890
00891 void
00892 ServerImpl::newTcpConnectionTS
00893 (
00894 IN conn_id_t connId,
00895 IN long token
00896 )
00897 {
00898 ASSERT(connId, "null");
00899 ASSERT(token, "null");
00900
00901
00902
00903
00904 host_rec_t hr;
00905 if (!m_hostMgr->getHostByUdpConnectionID(token, hr)) {
00906 DPRINTF("Unrecognized host in new tcp connection");
00907 return;
00908 }
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918
00919
00920
00921
00922
00923
00924
00925
00926 hr.tcpConn = connId;
00927 m_hostMgr->updateHost(hr);
00928 }
00929
00930
00931
00932 void
00933 ServerImpl::newPlayer
00934 (
00935 IN host_rec_t& hr,
00936 IN int playerId
00937 )
00938 {
00939 ASSERT(hr.isValid(), "invalid");
00940 ASSERT(playerId > 0, "Bad player ID: %d", playerId);
00941
00942
00943
00944
00945
00946
00947
00948 if (eHostMode_Authorized != hr.mode) {
00949 DPRINTF("Host is not authorized to add players");
00950 return;
00951 }
00952
00953
00954 if (!hr.tcpConn) {
00955 DPRINTF("Cannot add players: no tcp connection");
00956 return;
00957 }
00958
00959
00960 player_rec_t pr;
00961 pr.udpConnId = hr.udpConn;
00962 pr.playerId = playerId;
00963 m_playerMgr->updatePlayer(pr);
00964
00965
00966 std::ostringstream oss;
00967 oss << "new-player:" << pr.udpConnId << ":" << playerId;
00968
00969
00970 new_player_conv_data_t data;
00971 data.updates = this;
00972 data.userMgr = m_userMgr;
00973 data.connId = hr.tcpConn;
00974 data.playerId = playerId;
00975 ASSERT(data.isValid(), "should be valid now");
00976
00977 smart_ptr<converse::ConversationHost> host =
00978 createNewPlayerConversationHost(hr.desKey, data);
00979 ASSERT(host, "null");
00980
00981
00982 ASSERT(m_conversationMgr, "null");
00983 m_conversationMgr->updateConversationTS(oss.str().c_str(), hr.tcpConn,
00984 playerId, host);
00985 }
00986
00987
00988
00989 void
00990 ServerImpl::notifyDialogReplyTS
00991 (
00992 IN conn_id_t conn_id,
00993 IN const char * conversationGuid,
00994 IN int dialogId,
00995 IN int playerId,
00996 IN const Datahash * reply
00997 )
00998 {
00999 ASSERT(conn_id, "Null");
01000 ASSERT(conversationGuid, "null");
01001 ASSERT(dialogId > 0, "Bad dialog id: %d", dialogId);
01002 ASSERT(playerId > 0, "Bad player id: %d", playerId);
01003 ASSERT(reply, "null");
01004
01005
01006
01007 ASSERT(m_conversationMgr, "null");
01008 m_conversationMgr->handleDialogReplyTS(conversationGuid,
01009 dialogId,
01010 conn_id,
01011 playerId,
01012 reply);
01013 }
01014
01015
01016
01017 bool
01018 ServerImpl::setPlayerUserAccountTS
01019 (
01020 IN conn_id_t conn_id,
01021 IN int playerId,
01022 IN const char * username,
01023 IN const char * usertag,
01024 OUT std::string& diagnostic
01025 )
01026 {
01027 ASSERT(conn_id, "null");
01028 ASSERT(playerId > 0, "bad player id: %d", playerId);
01029 ASSERT(username, "null");
01030 ASSERT(usertag, "null");
01031 ASSERT(m_userMgr, "null");
01032 diagnostic.clear();
01033
01034
01035 bool isAdmin = m_userMgr->isAdminTS(username);
01036 if (isAdmin) {
01037 DPRINTF("User '%s' is an admin!", username);
01038 }
01039
01040
01041 host_rec_t hr;
01042 if (!m_hostMgr->getHostByTcpConnectionID(conn_id, hr)) {
01043 DPRINTF("Cannot set player user account: bad host");
01044 return false;
01045 }
01046
01047
01048 player_rec_t pr;
01049 if (!m_playerMgr->getPlayerByHostAndPlayerId(hr.udpConn, playerId, pr)) {
01050 diagnostic = "Internal Error: No record for this player!";
01051 return false;
01052 }
01053
01054
01055 pr.username.set(username);
01056 pr.playerTag.set(usertag);
01057 if (isAdmin) {
01058 pr.flags |= ePrivilege_Admin;
01059 }
01060
01061
01062 m_playerMgr->updatePlayer(pr);
01063
01064
01065 return true;
01066 }
01067
01068
01069
01070 void
01071 ServerImpl::newGameTS
01072 (
01073 IN conn_id_t connId,
01074 IN int playerId
01075 )
01076 {
01077 ASSERT(connId, "null");
01078 ASSERT(playerId > 0, "Bad player id: %d", playerId);
01079
01080
01081
01082
01083 host_rec_t hr;
01084 if (!m_hostMgr->getHostByTcpConnectionID(connId, hr)) {
01085 DPRINTF("new game request ignored: bad host?");
01086 return;
01087 }
01088 conn_id_t hostId = hr.udpConn;
01089
01090
01091
01092 if (!this->isAdmin(hr.udpConn, playerId)) {
01093 DPRINTF("Player %d is not admin, cannot start game",
01094 playerId);
01095 return;
01096 }
01097
01098
01099 DPRINTF("playerId=%d from connection 0x%04lx has requested a new game",
01100 playerId, (long) hostId);
01101
01102
01103 m_mapMgr->clear();
01104
01105
01106 std::string id = m_story->getStartingMapId();
01107 DPRINTF(" Starting map id='%s'", id.c_str());
01108 m_mapMgr->requestLoad(id.c_str());
01109 }
01110
01111
01112
01113 void
01114 ServerImpl::requestShutdownTS
01115 (
01116 void
01117 )
01118 {
01119
01120
01121
01122
01123
01124
01125
01126 DPRINTF("Requested to shut down! Setting shutdown flag...");
01127 m_shutdown = true;
01128 }
01129
01130
01131
01133
01134
01135
01137
01138 void
01139 ServerImpl::routeConversationTS
01140 (
01141 IN const char * guid,
01142 IN int dialogId,
01143 IN int playerId,
01144 IN conn_id_t connId,
01145 IN const char * dialogData
01146 )
01147 {
01148 ASSERT(guid, "null");
01149 ASSERT(dialogId >= 0, "Bad dialog id: %d", dialogId);
01150 ASSERT(playerId > 0, "Bad player id: %d", playerId);
01151 ASSERT(connId, "null");
01152 ASSERT(dialogData, "null");
01153
01154 smart_ptr<MessageBuffer> msg;
01155
01156
01157 if (!dialogId) {
01158 DPRINTF("Ending conversation: %s", guid);
01159 msg = createTerminateConversationMessage(playerId, guid);
01160 } else {
01161
01162 msg = createConversationDialogMessage(playerId, guid,
01163 dialogId, dialogData);
01164 }
01165 ASSERT(msg, "null");
01166
01167
01168 this->enqueueMessageTS(connId, msg);
01169 }
01170
01171
01172
01174
01175
01176
01178
01179 void
01180 ServerImpl::checkMessages
01181 (
01182 IN long microseconds
01183 )
01184 {
01185 perf::Timer timer("aesop-srv::checkMessages");
01186 ASSERT(microseconds >= 0, "Bad microseconds: %ld", microseconds);
01187
01188 envelope_t env;
01189 smart_ptr<MessageBuffer> msg;
01190 if (!netlib::getNextMessage(microseconds, env, msg))
01191 return;
01192
01193 try {
01194
01195 if (netlib::eType_UDPRemote == env.type) {
01196
01197 this->handleUdp(env, msg);
01198 } else if (netlib::eType_TCP == env.type) {
01199
01200 this->handleMessage(env, msg);
01201 } else {
01202 DPRINTF("Unknown message type! %d", env.type);
01203 }
01204
01205 } catch (std::exception& e) {
01206 dumpMessage(std::cerr, "Exception handling this message",
01207 env, msg);
01208 DPRINTF("Exception: %s", e.what());
01209 }
01210 }
01211
01212
01213
01214 void
01215 ServerImpl::handleMessage
01216 (
01217 IN const envelope_t& env,
01218 IN const MessageBuffer * msg
01219 )
01220 {
01221 perf::Timer timer("aesop-srv::handleMessage");
01222 ASSERT(!env.is_empty(), "empty envelope");
01223 ASSERT(msg, "null");
01224
01225
01226 tcp_payload_t payload;
01227 getTcpPayload(msg->getData(), payload);
01228 ASSERT(!payload.is_empty(), "empty");
01229
01230 DPRINTF("Got message: %s", payload.command.c_str());
01231
01232
01233 msg_handler_fn handler = m_router->getHandler(payload);
01234 if (!handler) {
01235 return;
01236 }
01237
01238
01239 smart_ptr<handler_intercept_t> hi =
01240 new handler_intercept_t(m_workerTrc);
01241 ASSERT(hi, "out of memory");
01242 hi->fn = handler;
01243 hi->state.src_env = env;
01244 hi->state.payload = payload;
01245 hi->state.story = m_story;
01246 hi->state.updates = this;
01247 hi->map = &m_threadNames;
01248
01249
01250 ++m_threadCounter;
01251 m_threadNames.insert(m_threadCounter, payload.command.c_str());
01252
01253
01254
01255
01256
01257 void * ctx = (void *) ((handler_intercept_t *) hi);
01258 m_threadpool->addRequest(interceptHandler, ctx);
01259 hi.disown();
01260
01261
01262 }
01263
01264
01265
01266 void
01267 ServerImpl::handleUdp
01268 (
01269 IN const envelope_t& env,
01270 IN const MessageBuffer * msg
01271 )
01272 {
01273 perf::Timer timer("Server::handleUdp");
01274 ASSERT(msg, "null");
01275
01276
01277
01278
01279
01280
01281
01282
01283
01284
01285 ASSERT(m_xdrInput, "should have parser by now");
01286 m_xdrInput->reset((const byte_t *) msg->getData(), msg->getBytes());
01287
01288
01289 xdrbuf::PackletHeader ph = m_xdrInput->getNextPackletHeader();
01290 if ('h' != ph.getName()) {
01291
01292 DPRINTF("Malformed UDP packet--no header?");
01293 return;
01294 }
01295 int32_t host_state[2];
01296 m_xdrInput->readInt32s(host_state, 2);
01297
01298
01299 dword_t token = host_state[0];
01300 conn_id_t conn_id = 0;
01301 host_rec_t hr;
01302
01303 if (token) {
01304
01305
01306 netlib::connection_info_t ci;
01307 if (!netlib::getConnectionInfo(token, ci)) {
01308 DPRINTF("Input UDP token was not valid");
01309 return;
01310 }
01311
01312
01313 if (ci.address != env.address) {
01314 DPRINTF("UDP sender does not match token");
01315 return;
01316 }
01317
01318
01319 conn_id = (conn_id_t) token;
01320 }
01321
01322 if (conn_id) {
01323
01324 if (!m_hostMgr->getHostByUdpConnectionID(conn_id, hr)) {
01325 DPRINTF("No host record for conn id: 0x%04lx",
01326 (long) conn_id);
01327 return;
01328 }
01329
01330
01331 dword_t clock = (dword_t) host_state[1];
01332 hr.lastUdpReceived = clock;
01333 m_hostMgr->updateHost(hr);
01334 }
01335
01336
01337 while (!m_xdrInput->endOfStream()) {
01338 xdrbuf::PackletHeader ph = m_xdrInput->getNextPackletHeader();
01339 char name = ph.getName();
01340
01341 switch (name) {
01342
01343 case 'a':
01344 this->parseHostAuthUdp(hr, ph, m_xdrInput);
01345 break;
01346
01347 case 'c':
01348 this->parseHostConnectUdp(env, m_xdrInput);
01349 break;
01350
01351 case 'e':
01352 this->parseExistsUdp(hr, m_xdrInput);
01353 break;
01354
01355 case 'g':
01356 this->parseGameUdp(hr, ph, m_xdrInput);
01357 break;
01358
01359 case 'p':
01360 this->parsePlayerUdp(hr, m_xdrInput);
01361 break;
01362
01363 case 'q':
01364 this->parseQueryUdp(hr, ph, m_xdrInput);
01365 break;
01366
01367 default:
01368 DPRINTF("Unknown packlet name! '%c'", name);
01369 }
01370 }
01371
01372 }
01373
01374
01375
01376 void
01377 ServerImpl::parseHostConnectUdp
01378 (
01379 IN const netlib::envelope_t& env,
01380 IO xdrbuf::Input * input
01381 )
01382 {
01383 ASSERT(input, "null");
01384
01385
01386
01387
01388 DPRINTF("Connection attempt...");
01389
01390
01391
01392 xdrbuf::PackletHeader ph = input->getNextPackletHeader();
01393 if ('v' != ph.getName()) {
01394 WAVE_EX(wex);
01395 wex << "Invalid packlet header during connection";
01396 }
01397 int32_t l[3];
01398 input->readInt32s(l, 3);
01399 if (eProtocol_Long != l[0]) {
01400 WAVE_EX(wex);
01401 wex << "Protocol versions do not match";
01402 }
01403 dword_t token = l[1];
01404 if (!token) {
01405 WAVE_EX(wex);
01406 wex << "Invalid client connection token";
01407 }
01408 int port = (int) l[2];
01409 if (!port) {
01410 WAVE_EX(wex);
01411 wex << "Invalid client UDP port";
01412 }
01413
01414 DPRINTF(" token = %ld", (long) token);
01415 DPRINTF(" port = %d", port);
01416
01417
01418 ph = input->getNextPackletHeader();
01419 if ('p' != ph.getName() ||
01420 xdrbuf::ePacklet_ParentBegin != ph.getType()) {
01421 WAVE_EX(wex);
01422 wex << "Invalid packlet header during connection";
01423 }
01424
01425
01426 const long maxSize = 1024;
01427 char buffer[maxSize];
01428 char * offset = buffer;
01429 int read = 0;
01430 while (true) {
01431 xdrbuf::PackletHeader subph = input->getNextPackletHeader();
01432 if ('p' == subph.getName()) {
01433 break;
01434 }
01435 if (xdrbuf::ePacklet_String != subph.getType()) {
01436 WAVE_EX(wex);
01437 wex << "Unexpected packlet while reading public key";
01438 }
01439
01440 int len = subph.getDataCount();
01441 if (read + len > maxSize - 1) {
01442 WAVE_EX(wex);
01443 wex << "Public key is too long!";
01444 }
01445
01446 input->readString(offset, len);
01447 offset += len;
01448 read += len;
01449 }
01450 buffer[read] = 0;
01451
01452
01453 ph = input->getNextPackletHeader();
01454 if ('c' != ph.getName() ||
01455 xdrbuf::ePacklet_ParentEnd != ph.getType()) {
01456 WAVE_EX(wex);
01457 wex << "Invalid end of connection packlet";
01458 }
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468 host_rec_t hr;
01469 aesop::HostManager::iterator_t i;
01470 m_hostMgr->getIterator(i);
01471 while (m_hostMgr->getNextHost(i, hr)) {
01472 netlib::connection_info_t ci;
01473 if (netlib::getConnectionInfo(hr.udpConn, ci)) {
01474 if (env.address == ci.address) {
01475 DPRINTF("Already connected!");
01476 DPRINTF(" Removing old host record");
01477 m_hostMgr->removeHost(hr.udpConn);
01478
01479 }
01480 }
01481 }
01482
01483
01484 std::string server = netlib::getServerFromIP(env.address.ip);
01485 DPRINTF(" server='%s'", server.c_str());
01486 netlib::address_t address(server.c_str(), port);
01487 ASSERT2(address.isValid(), "Invalid client udp address");
01488 conn_id_t hostId = netlib::createUdpRemote(m_udpConn, address);
01489 if (!hostId) {
01490 WAVE_EX(wex);
01491 wex << "Failed to create remote UDP connection";
01492 }
01493
01494
01495 m_hostMgr->addHost(hostId, token, buffer);
01496 if (!m_hostMgr->getHostByUdpConnectionID(hostId, hr)) {
01497 WAVE_EX(wex);
01498 wex << "Cannot find a just-added host?";
01499 }
01500 ASSERT(hr.netQueue, "null network request queue for host");
01501 ASSERT(hr.desKey, "null");
01502 ASSERT(hr.publicKey, "null");
01503
01504
01505 std::string desKey = hr.desKey->serialize();
01506 std::string encryptedDesKey = hr.publicKey->encrypt(desKey.c_str());
01507 smart_ptr<netrq::Request> rc =
01508 new AuthContext(hostId, encryptedDesKey.c_str());
01509 hr.netQueue->addRequest(m_udpClock + 2, rc);
01510
01511 DPRINTF("Host should have connected! connId=%08lx", (long) hostId);
01512 }
01513
01514
01515
01516 void
01517 ServerImpl::parseHostAuthUdp
01518 (
01519 IN host_rec_t& hr,
01520 IN const xdrbuf::PackletHeader& ph,
01521 IN xdrbuf::Input * input
01522 )
01523 {
01524 ASSERT(input, "null");
01525
01526 if (!hr.isValid()) {
01527 WAVE_EX(wex);
01528 wex << "Ignoring auth attempt from invalid host";
01529 }
01530 if (eHostMode_Authorized == hr.mode) {
01531 DPRINTF("Host is already authorized!");
01532 return;
01533 }
01534 DPRINTF("Host is attempting to authenticate");
01535
01536
01537
01538
01539 if (xdrbuf::ePacklet_String != ph.getType()) {
01540 WAVE_EX(wex);
01541 wex << "Invalid packlet type";
01542 }
01543
01544 const int maxSize = 1024;
01545 int len = ph.getDataCount();
01546 if (len < 1 || len > maxSize - 1) {
01547 WAVE_EX(wex);
01548 wex << "Bad password length: " << len;
01549 }
01550
01551 char buffer[maxSize];
01552 input->readString(buffer, len);
01553 buffer[len] = 0;
01554
01555 DPRINTF("Received string: %s", buffer);
01556 ASSERT(hr.desKey, "null");
01557 std::string decrypted = hr.desKey->decrypt(buffer);
01558 DPRINTF("Got host password: '%s'", decrypted.c_str());
01559
01560 hr.mode = eHostMode_Authorized;
01561 m_hostMgr->updateHost(hr);
01562 }
01563
01564
01565
01566 void
01567 ServerImpl::parsePlayerUdp
01568 (
01569 IN host_rec_t& hr,
01570 IO xdrbuf::Input * input
01571 )
01572 {
01573 ASSERT(input, "null");
01574
01575
01576
01577
01578 if (!hr.isValid()) {
01579 WAVE_EX(wex);
01580 wex << "Cannot process player data from invalid host";
01581 }
01582
01583
01584 xdrbuf::PackletHeader ph = input->getNextPackletHeader();
01585 char name = ph.getName();
01586 if ('i' != name) {
01587 WAVE_EX(wex);
01588 wex << "Invalid packlet in player UDP data. Expected ID 'i' ";
01589 wex << "but received '" << name << "' instead.";
01590 }
01591 int32_t playerId = -1;
01592 input->readInt32s(&playerId, 1);
01593 if (playerId < 1) {
01594 WAVE_EX(wex);
01595 wex << "Invalid player id: " << playerId;
01596 }
01597
01598
01599 player_rec_t rec;
01600 player_rec_t * pr = NULL;
01601 if (m_playerMgr->getPlayerByHostAndPlayerId(hr.udpConn, playerId, rec))
01602 {
01603
01604 pr = &rec;
01605 }
01606 if (!pr) {
01607
01608
01609 this->newPlayer(hr, playerId);
01610 }
01611
01612
01613 for (;;) {
01614 ph = input->getNextPackletHeader();
01615 name = ph.getName();
01616
01617 switch (name) {
01618 case 'p':
01619 return;
01620
01621 case 'm':
01622 {
01623
01624 float f[7];
01625 input->readFloats(f, 7);
01626 float dt = f[3];
01627 if (dt > 0.0 && pr && pr->obj) {
01628
01629
01630 point3d_t delta(f[0], f[1], f[2]);
01631
01632
01633
01634
01635
01636
01637 float r2 = dotProduct(delta, delta);
01638 float r = sqrt(r2);
01639 if (r > 0.4) {
01640 delta = (0.4 / r) * delta;
01641 }
01642 pr->obj->requestMove(delta, dt);
01643
01644
01645
01646 point3d_t euler(0, f[5], 0);
01647 quaternion_t q;
01648 q.setEulerZYX(euler);
01649 pr->obj->setOrientation(q);
01650 }
01651 }
01652 break;
01653
01654 default:
01655 {
01656 WAVE_EX(wex);
01657 wex << "Unrecognized player packet: '";
01658 wex << name << "'";
01659 }
01660 }
01661 }
01662 }
01663
01664
01665
01666 void
01667 ServerImpl::parseQueryUdp
01668 (
01669 IN host_rec_t& hr,
01670 IN const xdrbuf::PackletHeader& ph,
01671 IO xdrbuf::Input * input
01672 )
01673 {
01674 ASSERT(input, "null");
01675
01676
01677
01678
01679 if (!hr.isValid()) {
01680 WAVE_EX(wex);
01681 wex << "Cannot process query from invalid host";
01682 }
01683
01684
01685 if (xdrbuf::ePacklet_Int32s != ph.getType()) {
01686 WAVE_EX(wex);
01687 wex << "query packlets should be of type int32";
01688 }
01689 dword_t objId;
01690 input->readInt32s((int32_t *) &objId, 1);
01691
01692
01693 if (!objId) {
01694 WAVE_EX(wex);
01695 wex << "Invalid object ID requested";
01696 }
01697
01698
01699 ASSERT(hr.netQueue, "null");
01700 if (hr.netQueue->size() > s_maxNetQueueLength) {
01701 DPRINTF("Dropping client request");
01702 return;
01703 }
01704
01705 smart_ptr<netrq::Request> ctx = new QueryContext(objId);
01706 ASSERT(ctx, "out of memory");
01707 hr.netQueue->addRequest(m_udpClock + 2, ctx);
01708 }
01709
01710
01711
01712 void
01713 ServerImpl::parseGameUdp
01714 (
01715 IN host_rec_t& hr,
01716 IN const xdrbuf::PackletHeader& ph,
01717 IO xdrbuf::Input * input
01718 )
01719 {
01720 perf::Timer timer("parseGameUdp");
01721 ASSERT(input, "null");
01722 ASSERT(m_gameLogic, "null");
01723
01724 m_gameLogic->parseGameData(hr.udpConn, input);
01725 }
01726
01727
01728
01729 void
01730 ServerImpl::parseExistsUdp
01731 (
01732 IN host_rec_t& hr,
01733 IO xdrbuf::Input * input
01734 )
01735 {
01736 ASSERT(input, "null");
01737
01738
01739
01740 dword_t objectId;
01741 input->readInt32s((int32_t *) &objectId, 1);
01742 if (objectId < 1) {
01743 WAVE_EX(wex);
01744 wex << "Bad object ID: " << objectId;
01745 }
01746
01747
01748 char buffer[64];
01749 sprintf(buffer, "er-%ld", (long) objectId);
01750 if (hr.netQueue->containsRequest(buffer))
01751 return;
01752
01753
01754 smart_ptr<netrq::Request> request =
01755 ObjectExistsResponse::create(buffer, objectId);
01756 ASSERT(request, "null");
01757 hr.netQueue->addRequest(m_udpClock, request);
01758 }
01759
01760
01761
01762 void
01763 ServerImpl::sendUdp
01764 (
01765 void
01766 )
01767 {
01768
01769
01770
01771
01772 ++m_udpClock;
01773
01774
01775 addPhysicsMessagesToQueue(m_udpClock, m_hostMgr, m_playerMgr, m_mapMgr);
01776
01777
01778 vec_conn_t badConns;
01779 HostManager::iterator_t i;
01780 host_rec_t hr;
01781 m_hostMgr->getIterator(i);
01782 while (m_hostMgr->getNextHost(i, hr)) {
01783 if (!hr.outbuf || !hr.udpConn) {
01784 DPRINTF("No way to send");
01785 continue;
01786 }
01787
01788
01789 if (!netlib::isValidConnection(hr.udpConn)) {
01790 DPRINTF("Removing host record! 0x%04lx",
01791 (long) hr.udpConn);
01792 badConns.push_back(hr.udpConn);
01793 continue;
01794 }
01795
01796
01797 hr.outbuf->clear();
01798
01799
01800
01801
01802
01803
01804
01805
01806 int32_t l[6];
01807 l[0] = hr.udpToken;
01808 l[1] = m_udpClock;
01809 l[2] = hr.lastUdpReceived;
01810 l[3] = m_smode;
01811 l[4] = hr.mode;
01812 l[5] = m_tcpPort;
01813
01814
01815 hr.outbuf->addInt32Packlet('h', l, 6);
01816
01817
01818 PlayerManager::iterator_t i;
01819 m_playerMgr->getIterator(hr.udpConn, i);
01820 player_rec_t pr;
01821 while (m_playerMgr->getNextPlayer(i, pr)) {
01822
01823 dword_t objectId = pr.obj ? pr.obj->getId() : 0;
01824
01825
01826
01827
01828
01829 int32_t l[3];
01830 l[0] = pr.playerId;
01831 l[1] = pr.getMode();
01832 l[2] = objectId;
01833 hr.outbuf->addInt32Packlet('p', l, 3);
01834 }
01835
01836
01837 netrq::sendMessagesFromQueue(hr.outbuf, m_udpClock, hr.netQueue);
01838
01839
01840
01841
01842
01843 smart_ptr<MessageBuffer> msg = MessageBuffer::create();
01844 ASSERT(msg, "null");
01845 const byte_t * data = hr.outbuf->getData();
01846 int bytes = hr.outbuf->getDataBytes();
01847 ASSERT(bytes > 0, "Bad bytes: %d", bytes);
01848 msg->reserve(bytes);
01849 msg->appendData((const char *) data, bytes);
01850 msg->close();
01851
01852
01853 netlib::enqueueMessage(hr.udpConn, msg);
01854 }
01855
01856
01857
01858 for (vec_conn_t::iterator ib = badConns.begin(); ib != badConns.end();
01859 ++ib) {
01860 conn_id_t conn_id = *ib;
01861 DPRINTF(" Removing host with connection ID 0x%04lx",
01862 (long) conn_id);
01863 m_hostMgr->removeHost(conn_id);
01864 }
01865 }
01866
01867
01868
01869 const char *
01870 ServerImpl::getStoryGuidTS
01871 (
01872 void
01873 )
01874 {
01875 ASSERT(m_story, "null");
01876
01877 return m_story->getUuid();
01878 }
01879
01880
01881
01882 bool
01883 ServerImpl::isAdmin
01884 (
01885 IN conn_id_t udpConnID,
01886 IN int playerId
01887 )
01888 {
01889 ASSERT(udpConnID, "null");
01890 ASSERT(playerId > 0, "bad player id: %d", playerId);
01891 ASSERT(m_playerMgr, "null");
01892
01893
01894 player_rec_t pr;
01895 if (!m_playerMgr->getPlayerByHostAndPlayerId(udpConnID, playerId, pr)) {
01896 return false;
01897 }
01898 return ePrivilege_Admin & pr.flags;
01899 }
01900
01901
01902
01903 void
01904 ServerImpl::checkPlayers
01905 (
01906 void
01907 )
01908 {
01909
01910
01911
01912
01913
01914
01915 PlayerManager::iterator_t i;
01916 m_playerMgr->getIterator(0, i);
01917 player_rec_t pr;
01918 while (m_playerMgr->getNextPlayer(i, pr)) {
01919 if (pr.isAuthenticated() &&
01920 !pr.isInMap()) {
01921 try {
01922
01923 if (m_gameLogic->requestPlayerStartTS(pr)) {
01924 m_playerMgr->updatePlayer(pr);
01925 }
01926 } catch (std::exception& e) {
01927 DPRINTF("Exception: %s", e.what());
01928 }
01929 }
01930 }
01931 }
01932
01933
01934
01935 void
01936 ServerImpl::sendBroadcast
01937 (
01938 void
01939 )
01940 {
01941 ASSERT2(m_udpBcast, "No UDP broadcast point?");
01942 ASSERT2(m_xdrBcast, "null");
01943 ASSERT2(m_story, "null");
01944
01945
01946
01947 m_xdrBcast->clear();
01948
01949
01950 int len = m_publicName.length();
01951 m_xdrBcast->addStringPacklet('s', m_publicName.c_str(), len);
01952
01953
01954 const char * uuid = m_story->getUuid();
01955 ASSERT2(uuid, "null");
01956 len = strlen(uuid);
01957 m_xdrBcast->addStringPacklet('u', uuid, len);
01958
01959
01960 int32_t port = m_udpPort;
01961 m_xdrBcast->addInt32Packlet('p', &port, 1);
01962
01963
01964
01965 smart_ptr<MessageBuffer> msg = MessageBuffer::create();
01966 ASSERT(msg, "null");
01967 const byte_t * data = m_xdrBcast->getData();
01968 int bytes = m_xdrBcast->getDataBytes();
01969 ASSERT(bytes > 0, "Bad bytes: %d", bytes);
01970 msg->reserve(bytes);
01971 msg->appendData((const char *) data, bytes);
01972 msg->close();
01973
01974
01975 netlib::enqueueMessage(m_udpBcast, msg);
01976
01977
01978 }
01979
01980
01981
01983
01984
01985
01987
01988 smart_ptr<Server>
01989 Server::create
01990 (
01991 IN smart_ptr<Datahash>& params,
01992 IN smart_ptr<ServerGameLogic>& gameLogic
01993 )
01994 {
01995 ASSERT(params, "null");
01996 ASSERT(gameLogic, "null");
01997
01998 smart_ptr<ServerImpl> local = new ServerImpl;
01999 ASSERT(local, "out of memory");
02000
02001
02002 local->initialize(params, gameLogic);
02003
02004 return local;
02005 }
02006
02007
02008 };
02009