コード例 #1
0
ファイル: Admintest.cpp プロジェクト: cyclefusion/cyphesis
void Admintest::test_LogoutOperation_other_but_unconnected()
{
    Account_LogoutOperation_called = 0;
    m_account->m_connection = 0;

    long cid = m_id_counter++;
    std::string cid_str = String::compose("%1", cid);
    Account * ac2 = new Admin(0,
                              "f3332c00-5d2b-45c1-8cf4-3429bdf2845f",
                              "c0e095f0-575c-477c-bafd-2055d6958d4d",
                              cid_str, cid);

    m_server->addObject(ac2);

    ASSERT_EQUAL(m_server->getObject(cid_str), ac2);

    Atlas::Objects::Operation::Logout op;
    OpVector res;

    Anonymous arg;
    arg->setId(cid_str);
    op->setArgs1(arg);

    m_account->LogoutOperation(op, res);

    ASSERT_EQUAL(res.size(), 1u);
    ASSERT_EQUAL(res.front()->getClassNo(),
                 Atlas::Objects::Operation::ERROR_NO);

    ASSERT_NULL(Account_LogoutOperation_called);

    delete ac2;
}
コード例 #2
0
ファイル: Admintest.cpp プロジェクト: cyclefusion/cyphesis
void Admintest::test_GetOperation_obj_OOG()
{
    long cid = m_id_counter++;
    std::string cid_str = String::compose("%1", cid);
    Router * to = new TestObject(cid_str, cid);

    m_server->addObject(to);

    Atlas::Objects::Operation::Get op;
    OpVector res;

    Anonymous arg;
    arg->setObjtype("obj");
    arg->setId(cid_str);
    op->setArgs1(arg);

    m_account->GetOperation(op, res);

    ASSERT_EQUAL(res.size(), 1u);

    const Operation & reply = res.front();

    ASSERT_EQUAL(reply->getClassNo(),
                 Atlas::Objects::Operation::INFO_NO);
    ASSERT_EQUAL(reply->getArgs().size(), 1u);

    const Root & reply_arg = reply->getArgs().front();

    ASSERT_TRUE(!reply_arg->isDefaultId());
    ASSERT_EQUAL(reply_arg->getId(), to->getId());

    delete to;
}
コード例 #3
0
void AccountServerLobbyintegration::setup()
{
    LocatedEntity * gw = new Entity(compose("%1", m_id_counter),
                                    m_id_counter++);
    m_server = new ServerRouting(*new TestWorld(*gw),
                                 "59331d74-bb5d-4a54-b1c2-860999a4e344",
                                 "93e1f67f-63c5-4b07-af4c-574b2273563d",
                                 compose("%1", m_id_counter), m_id_counter++,
                                 compose("%1", m_id_counter), m_id_counter++);
    for (int i = 0; i < 3; ++i) {
        m_account = new TestAccount(*m_server,
                                    m_id_counter++,
                                    m_id_counter++);
        m_server->addAccount(m_account);
        m_server->m_lobby.addAccount(m_account);
    }
    ASSERT_NOT_NULL(m_account);
}
コード例 #4
0
void AccountConnectionintegration::test_account_creation()
{
    // Basic player account creation
    {

        ASSERT_NOT_NULL(m_connection);
        ASSERT_TRUE(m_connection->objects().empty());

        Create op;
        Anonymous create_arg;
        create_arg->setParents(std::list<std::string>(1, "player"));
        create_arg->setAttr("username", "39d409ec");
        create_arg->setAttr("password", "6a6e71bab281");
        op->setArgs1(create_arg);

        ASSERT_TRUE(test_sent_ops.empty());

        // Send the operation to create the account
        m_connection->externalOperation(op, *m_connection);

        // There should be a response op
        ASSERT_TRUE(!test_sent_ops.empty());
        ASSERT_EQUAL(test_sent_ops.size(), 1u);
        // and the account creation should have created an object bound
        // to this connection.
        ASSERT_TRUE(!m_connection->objects().empty());

        // Check the response is an info indicating successful account
        // creation.
        const Operation & reply = test_sent_ops.front();
        ASSERT_EQUAL(reply->getClassNo(), Atlas::Objects::Operation::INFO_NO);
        // The Info response should have an argument describing the created
        // account
        const std::vector<Root> & reply_args = reply->getArgs();
        ASSERT_TRUE(!reply_args.empty());
        RootEntity account = smart_dynamic_cast<RootEntity>(reply_args.front());
        ASSERT_TRUE(account.isValid());

        // The account ID should be provided
        ASSERT_TRUE(!account->isDefaultId());
        const std::string account_id = account->getId();
        ASSERT_TRUE(!account_id.empty());

        // Check the account has been registered in the server object
        Router * account_router_ptr = m_server->getObject(account_id);
        ASSERT_NOT_NULL(account_router_ptr);

        // Check the account has been logged into the lobby
        const AccountDict & lobby_dict = m_server->m_lobby.getAccounts();
        AccountDict::const_iterator I = lobby_dict.find(account_id);
        ASSERT_TRUE(I != lobby_dict.end());
        Account * account_ptr = I->second;
        ASSERT_EQUAL(account_router_ptr, account_ptr);

        // Basic login as now been established by account creation

        // Set up some other account details
        create_arg->setAttr("username", "89cae312");
        create_arg->setAttr("password", "d730b8bd2d6c");

        // and try an additional account creation, which should fail.
        // Multiple logins are ok, but there is no reason to allow multiple
        // account creations.
        test_sent_ops.clear();
        m_connection->externalOperation(op, *m_connection);
        ASSERT_TRUE(!test_sent_ops.empty());
        ASSERT_EQUAL(test_sent_ops.size(), 1u);

        const Operation & error_reply = test_sent_ops.front();
        ASSERT_EQUAL(error_reply->getClassNo(),
                     Atlas::Objects::Operation::ERROR_NO);

        Player::playableTypes.insert(test_valid_character_type);

        Anonymous character_arg;
        character_arg->setParents(std::list<std::string>(1, test_valid_character_type));
        character_arg->setName("938862f2-4db2-4e8e-b944-7b0935e569db");

        Create character_op;
        character_op->setArgs1(character_arg);
        character_op->setFrom(account_id);

        test_sent_ops.clear();
        m_connection->externalOperation(character_op, *m_connection);
        // FIXME the above went through Account::externalOperation, so there
        // is no reply in res. The reply has gone directly to the Link::send
        // method. Add a way of checking, once there are better stubs.
        ASSERT_TRUE(!test_sent_ops.empty());
        ASSERT_EQUAL(test_sent_ops.size(), 2u);

        const Operation & create_reply = test_sent_ops.front();
        ASSERT_EQUAL(create_reply->getClassNo(),
                     Atlas::Objects::Operation::INFO_NO);


        // TODO Character creation etc?
        // TODO Lobby interaction?
        // TODO Logout ?
    }
}
コード例 #5
0
void AccountConnectionintegration::test_account_creation()
{
    // Basic player account creation
    {

        ASSERT_NOT_NULL(m_connection);
        ASSERT_TRUE(m_connection->objects().empty());

        Create op;
        Anonymous create_arg;
        create_arg->setParent("player");
        create_arg->setAttr("username", "39d409ec");
        create_arg->setAttr("password", "6a6e71bab281");
        op->setArgs1(create_arg);

        ASSERT_TRUE(test_sent_ops.empty());

        // Send the operation to create the account
        m_connection->externalOperation(op, *m_connection);

        // There should be a response op
        ASSERT_TRUE(!test_sent_ops.empty());
        ASSERT_EQUAL(test_sent_ops.size(), 1u);
        // and the account creation should have created an object bound
        // to this connection.
        ASSERT_TRUE(!m_connection->objects().empty());

        // Check the response is an info indicating successful account
        // creation.
        const Operation & reply = test_sent_ops.front();
        ASSERT_EQUAL(reply->getClassNo(), Atlas::Objects::Operation::INFO_NO);
        // The Info response should have an argument describing the created
        // account
        const std::vector<Root> & reply_args = reply->getArgs();
        ASSERT_TRUE(!reply_args.empty());
        RootEntity account = smart_dynamic_cast<RootEntity>(reply_args.front());
        ASSERT_TRUE(account.isValid());

        // The account ID should be provided
        ASSERT_TRUE(!account->isDefaultId());
        const std::string account_id = account->getId();
        ASSERT_TRUE(!account_id.empty());

        // Check the account has been registered in the server object
        Router * account_router_ptr = m_server->getObject(account_id);
        ASSERT_NOT_NULL(account_router_ptr);

        // Check the account has been logged into the lobby
        const auto & lobby_dict = m_server->m_lobby.getAccounts();
        auto I = lobby_dict.find(account_id);
        ASSERT_TRUE(I != lobby_dict.end());
        auto account_ptr = I->second;
        ASSERT_EQUAL(account_router_ptr, account_ptr);

        // Basic login as now been established by account creation

        // Set up some other account details
        create_arg->setAttr("username", "89cae312");
        create_arg->setAttr("password", "d730b8bd2d6c");

        // and try an additional account creation, which should fail.
        // Multiple logins are ok, but there is no reason to allow multiple
        // account creations.
        test_sent_ops.clear();
        m_connection->externalOperation(op, *m_connection);
        ASSERT_TRUE(!test_sent_ops.empty());
        ASSERT_EQUAL(test_sent_ops.size(), 1u);

        const Operation & error_reply = test_sent_ops.front();
        ASSERT_EQUAL(error_reply->getClassNo(),
                     Atlas::Objects::Operation::ERROR_NO);


        // TODO Character creation etc?
        // TODO Lobby interaction?
        // TODO Logout ?
    }
}
コード例 #6
0
ファイル: server.cpp プロジェクト: anthonypesce/cyphesis
int main(int argc, char ** argv)
{
    if (security_init() != 0) {
        log(CRITICAL, "Security initialisation Error. Exiting.");
        return EXIT_SECURITY_ERROR;
    }

    if (security_check() != SECURITY_OKAY) {
        log(CRITICAL, "Security check error. Exiting.");
        return EXIT_SECURITY_ERROR;
    }

    interactive_signals();

    int config_status = loadConfig(argc, argv, USAGE_SERVER);
    if (config_status < 0) {
        if (config_status == CONFIG_VERSION) {
            std::cout << argv[0] << " (cyphesis) " << consts::version
                      << " (Cyphesis build " << consts::buildId << ")"
                      << std::endl << std::flush;

            return 0;
        } else if (config_status == CONFIG_HELP) {
            showUsage(argv[0], USAGE_SERVER);
            return 0;
        } else if (config_status != CONFIG_ERROR) {
            log(ERROR, "Unknown error reading configuration.");
        }
        // Fatal error loading config file.
        return EXIT_CONFIG_ERROR;
    }

    if (daemon_flag) {
        int pid = daemonise();
        if (pid == -1) {
            return EXIT_FORK_ERROR;
        } else if (pid > 0) {
            return EXIT_SUCCESS;
        }
    }

    readConfigItem(instance, "usedatabase", database_flag);

    // If we are a daemon logging to syslog, we need to set it up.
    initLogger();

    // Initialise the persistance subsystem. If we have been built with
    // database support, this will open the various databases used to
    // store server data.
    if (database_flag) {
        Persistence * p = Persistence::instance();
        int dbstatus = p->init();
        if (dbstatus < 0) {
            database_flag = false;
            log(ERROR, "Error opening database. Database disabled.");
            if (dbstatus == DATABASE_TABERR) {
                log(INFO, "Database connection established, "
                    "but unable to create required tables.");
                log(INFO, "Please ensure that any obsolete database "
                    "tables have been removed.");
            } else {
                log(INFO, "Unable to connect to the RDBMS.");
                log(INFO, "Please ensure that the RDBMS is running, "
                    "the cyphesis database exists and is accessible "
                    "to the user running cyphesis.");
            }
            log(INFO, String::compose("To disable this message please run:\n\n"
                                      "    cyconfig --%1:usedatabase=false\n\n"
                                      "to permanently disable database usage.",
                                      instance));
        }
    }

    // If the restricted flag is set in the config file, then we
    // don't allow connecting users to create accounts. Accounts must
    // be created manually by the server administrator.
    if (restricted_flag) {
        log(INFO, "Setting restricted mode.");
    }

    readConfigItem(instance, "inittime", timeoffset);

    std::string server_name;
    if (readConfigItem(instance, "servername", server_name) != 0) {
        if (instance == CYPHESIS) {
            server_name = get_hostname();
        } else {
            server_name = instance;
        }
    }

    int nice = 1;
    readConfigItem(instance, "nice", nice);

    // Start up the python subsystem.
    init_python_api(ruleset_name);

    Inheritance::instance();
    new BulletDomain;

    SystemTime time;
    time.update();

    WorldRouter * world = new WorldRouter(time);

    Ruleset::init(ruleset_name);

    TeleportAuthenticator::init();

    StorageManager * store = new StorageManager(*world);

    // This ID is currently generated every time, but should perhaps be
    // persistent in future.
    std::string server_id, lobby_id;
    long int_id, lobby_int_id;

    if (((int_id = newId(server_id)) < 0) ||
            ((lobby_int_id = newId(lobby_id)) < 0)) {
        log(CRITICAL, "Unable to get server IDs from Database");
        return EXIT_DATABASE_ERROR;
    }

    // Create the core server object, which stores central data,
    // and track objects
    ServerRouting * server = new ServerRouting(*world, ruleset_name,
            server_name,
            server_id, int_id,
            lobby_id, lobby_int_id);

    // Create commserver instance that will handle connections from clients.
    // The commserver will create the other server related objects, and the
    // world object pair (World + WorldRouter), and initialise the admin
    // account. The primary ruleset name is passed in so it
    // can be stored and queried by clients.
    CommServer * commServer = new CommServer;

    if (commServer->setup() != 0) {
        log(CRITICAL, "Internal error setting up network infrastructure");
        return EXIT_SOCKET_ERROR;
    }

    // This is where we should restore the database, before
    // the listen sockets are open. Unlike earlier code, we are
    // attempting to construct the internal state from the database,
    // not creating a new world using the contents of the database as a
    // template

    if (database_flag) {
        // log(INFO, _("Restoring world from database..."));

        store->restoreWorld();
        // FIXME Do the following steps.
        // Read the world entity if any from the database, or set it up.
        // If it was there, make sure it did not get any of the wrong
        // position or orientation data.
        store->initWorld();

        // log(INFO, _("Restored world."));

        CommPSQLSocket * dbsocket = new CommPSQLSocket(*commServer,
                Persistence::instance()->m_db);
        commServer->addSocket(dbsocket);
        commServer->addIdle(dbsocket);

        IdleConnector * storage_idle = new IdleConnector(*commServer);
        storage_idle->idling.connect(sigc::mem_fun(store, &StorageManager::tick));
        commServer->addIdle(storage_idle);
    } else {
        std::string adminId;
        long intId = newId(adminId);
        assert(intId >= 0);

        Admin * admin = new Admin(0, "admin", "BAD_HASH", adminId, intId);
        server->addAccount(admin);
    }

    // Add the test object, and call it regularly so it can do what it does.
    // UpdateTester * update_tester = new UpdateTester(*commServer);
    // commServer->addIdle(update_tester);

    shared_ptr<CommClientFactory<CommUserClient, Connection> > atlas_clients =
        make_shared<CommClientFactory<CommUserClient, Connection>,
        ServerRouting & >(*server);
    if (client_port_num < 0) {
        client_port_num = dynamic_port_start;
        for (; client_port_num <= dynamic_port_end; client_port_num++) {
            if (TCPListenFactory::listen(*commServer,
                                         client_port_num,
                                         atlas_clients) == 0) {
                break;
            }
        }
        if (client_port_num > dynamic_port_end) {
            log(ERROR, String::compose("Could not find free client listen "
                                       "socket in range %1-%2. Init failed.",
                                       dynamic_port_start, dynamic_port_end));
            log(INFO, String::compose("To allocate 8 more ports please run:"
                                      "\n\n    cyconfig "
                                      "--cyphesis:dynamic_port_end=%1\n\n",
                                      dynamic_port_end + 8));
            return EXIT_PORT_ERROR;
        }
        log(INFO, String::compose("Auto configuring new instance \"%1\" "
                                  "to use port %2.",
                                  instance, client_port_num));
        global_conf->setItem(instance, "tcpport", client_port_num,
                             varconf::USER);
        global_conf->setItem(CYPHESIS, "dynamic_port_start",
                             client_port_num + 1, varconf::USER);
    } else if (TCPListenFactory::listen(*commServer,
                                        client_port_num,
                                        atlas_clients) != 0) {
        log(ERROR, String::compose("Could not create client listen socket "
                                   "on port %1. Init failed.",
                                   client_port_num));
        return EXIT_SOCKET_ERROR;
    }

#ifdef HAVE_SYS_UN_H
    CommUnixListener * localListener = new CommUnixListener(*commServer,
            make_shared<CommClientFactory<CommAdminClient, TrustedConnection>,
            ServerRouting &>(*server));
    if (localListener->setup(client_socket_name) != 0) {
        log(ERROR, String::compose("Could not create local listen socket "
                                   "with address \"%1\"",
                                   localListener->getPath()));
        delete localListener;
    } else {
        commServer->addSocket(localListener);
    }

    CommUnixListener * pythonListener = new CommUnixListener(*commServer,
            make_shared<CommPythonClientFactory>());
    if (pythonListener->setup(python_socket_name) != 0) {
        log(ERROR, String::compose("Could not create python listen socket "
                                   "with address %1.",
                                   pythonListener->getPath()));
        delete pythonListener;
    } else {
        commServer->addSocket(pythonListener);
    }
#endif

    if (TCPListenFactory::listen(*commServer,
                                 http_port_num,
                                 make_shared<CommHttpClientFactory>()) != 0) {
        log(ERROR, String::compose("Could not create http listen"
                                   " socket on port %1.", http_port_num));

    }

    if (useMetaserver) {
        CommMetaClient * cmc = new CommMetaClient(*commServer);
        if (cmc->setup(mserver) == 0) {
            commServer->addIdle(cmc);
        } else {
            log(ERROR, "Error creating metaserver comm channel.");
            delete cmc;
        }
    }

#if defined(HAVE_AVAHI)

    CommMDNSPublisher * cmdns = new CommMDNSPublisher(*commServer,
            *server);
    if (cmdns->setup() == 0) {
        commServer->addSocket(cmdns);
        commServer->addIdle(cmdns);
    } else {
        log(ERROR, "Unable to register service with MDNS daemon.");
        delete cmdns;
    }

#endif // defined(HAVE_AVAHI)

    // Configuration is now complete, and verified as somewhat sane, so
    // we save the updated user config.

    updateUserConfiguration();

    log(INFO, "Running");
    logEvent(START, "- - - Standalone server startup");

    // Inform things that want to know that we are running.
    running();

    // Reduce our system priority to make it easier to debug a runaway
    // server.
    if (nice != 0) {
        reduce_priority(nice);
    }

    // Loop until the exit flag is set. The exit flag can be set anywhere in
    // the code easily.
    while (!exit_flag) {
        try {
            time.update();
            bool busy = world->idle(time);
            commServer->idle(time, busy);
            commServer->poll(busy);
        }
        catch (...) {
            // It is hoped that commonly thrown exception, particularly
            // exceptions that can be caused  by external influences
            // should be caught close to where they are thrown. If
            // an exception makes it here then it should be debugged.
            log(ERROR, "Exception caught in main()");
        }
    }
    // exit flag has been set so we close down the databases, and indicate
    // to the metaserver (if we are using one) that this server is going down.
    // It is assumed that any preparation for the shutdown that is required
    // by the game has been done before exit flag was set.
    log(NOTICE, "Performing clean shutdown...");

    delete commServer;

    delete server;

    delete store;

    delete world;

    Persistence::instance()->shutdown();

    EntityBuilder::instance()->flushFactories();
    EntityBuilder::del();
    ArithmeticBuilder::del();
    TeleportAuthenticator::del();

    Inheritance::clear();

    // Shutdown the python interpretter. This frees lots of memory, and if
    // the malloc heap is in any way corrupt, a segfault is likely to
    // occur at this point. Previous occassions where pointers have been
    // deleted twice elsewhere in the code, have resulted in a segfault
    // at this point. AlRiddoch 10th November 2001
    shutdown_python_api();

    delete global_conf;

    log(INFO, "Clean shutdown complete.");
    logEvent(STOP, "- - - Standalone server shutdown");
    return 0;
}