Commit 4d0ffbff authored by louiz’'s avatar louiz’

Initial commit

Connect to steam, log in, get the contact list, and keepalive
parents
cmake_minimum_required(VERSION 2.6)
project(vaporo)
set(${PROJECT_NAME}_VERSION_MAJOR 1)
set(${PROJECT_NAME}_VERSION_MINOR 0)
set(${PROJECT_NAME}_VERSION_SUFFIX "~dev")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -pedantic -Wall -Wextra")
# Define a __FILENAME__ macro to get the filename of each file, instead of
# the full path as in __FILE__
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D__FILENAME__='\"$(subst ${CMAKE_SOURCE_DIR}/,,$(abspath $<))\"'")
#
## Look for external libraries
#
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/SteamPP/cmake/Modules/")
if(WITH_BOTAN)
find_package(BOTAN REQUIRED)
elseif(NOT WITHOUT_BOTAN)
find_package(BOTAN)
endif()
if(WITH_CARES)
find_package(CARES REQUIRED)
elseif(NOT WITHOUT_CARES)
find_package(CARES)
endif()
#
## Get the software version
#
set(ARCHIVE_NAME ${CMAKE_PROJECT_NAME}-${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR})
if(${PROJECT_NAME}_VERSION_SUFFIX MATCHES ".+")
set(ARCHIVE_NAME ${ARCHIVE_NAME}-${${PROJECT_NAME}_VERSION_SUFFIX})
endif()
if(${PROJECT_NAME}_VERSION_SUFFIX MATCHES "^~dev$")
# If we are on a dev version, append the hash of the current git HEAD to
# the version
include(FindGit)
if(GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
execute_process(COMMAND git --git-dir=${CMAKE_SOURCE_DIR}/.git rev-parse --short HEAD
OUTPUT_VARIABLE GIT_REVISION
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(GIT_REVISION)
set(${PROJECT_NAME}_VERSION_SUFFIX "${${PROJECT_NAME}_VERSION_SUFFIX} (${GIT_REVISION})")
set(ARCHIVE_NAME ${ARCHIVE_NAME}-${GIT_REVISION})
endif()
endif()
endif()
set(VAPORO_VERSION
${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}${${PROJECT_NAME}_VERSION_SUFFIX})
# To be able to include the config.h file generated by cmake
include_directories("${CMAKE_CURRENT_BINARY_DIR}/src/")
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/src/")
# Include the Steam++ library headers
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/SteamPP/")
# Include the SteamKit headers generated by the protobuf compiler
include_directories("${CMAKE_CURRENT_BINARY_DIR}/SteamPP/")
if(BOTAN_FOUND)
include_directories(SYSTEM ${BOTAN_INCLUDE_DIRS})
endif()
if(CARES_FOUND)
include_directories(${CARES_INCLUDE_DIRS})
endif()
set(POLLER_DOCSTRING "Choose the poller between POLL and EPOLL (Linux-only)")
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(POLLER "EPOLL" CACHE STRING ${POLLER_DOCSTRING})
else()
set(POLLER "POLL" CACHE STRING ${POLLER_DOCSTRING})
endif()
if((NOT ${POLLER} MATCHES "POLL") AND
(NOT ${POLLER} MATCHES "EPOLL"))
message(FATAL_ERROR "POLLER must be either POLL or EPOLL")
endif()
#
## utils
#
file(GLOB source_utils
src/utils/*.[hc]pp)
add_library(utils STATIC ${source_utils})
#
## config
#
file(GLOB source_config
src/config/*.[hc]pp)
add_library(config STATIC ${source_config})
target_link_libraries(config utils)
#
## logger
#
file(GLOB source_logger
src/logger/*.[hc]pp)
add_library(logger STATIC ${source_logger})
target_link_libraries(logger config)
#
## network
#
file(GLOB source_network
src/network/*.[hc]pp)
add_library(network STATIC ${source_network})
target_link_libraries(network logger)
if(BOTAN_FOUND)
target_link_libraries(network ${BOTAN_LIBRARIES})
endif()
if(CARES_FOUND)
target_link_libraries(network ${CARES_LIBRARIES})
endif()
#
## SteamPP
#
add_subdirectory("SteamPP/")
#
## Steam
#
file(GLOB source_steam
src/steam/*[hc]pp)
add_library(steam STATIC ${source_steam})
target_link_libraries(steam network logger)
#
## Main executable
#
add_executable(${PROJECT_NAME} src/main.cpp)
target_link_libraries(${PROJECT_NAME}
steam
steam++
)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/src/config.h)
#
## Install target
#
install(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION bin)
#
## Dist target
## Generate a release tarball from the git sources
#
add_custom_target(dist
COMMAND git archive --prefix=${ARCHIVE_NAME}/ --format=tar HEAD
| xz > ${CMAKE_CURRENT_BINARY_DIR}/${ARCHIVE_NAME}.tar.xz
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
#define SYSTEM_NAME "${CMAKE_SYSTEM}"
#cmakedefine VAPORO "${VAPORO_VERSION}"
#include <steam/steam_client.hpp>
#include <network/poller.hpp>
#include <utils/timed_events.hpp>
int main()
{
auto p = std::make_shared<Poller>();
SteamClient client(p);
client.start();
auto timeout = TimedEventsManager::instance().get_timeout();
while (p->poll(timeout) != -1)
{
TimedEventsManager::instance().execute_expired_events();
log_debug("poll");
timeout = TimedEventsManager::instance().get_timeout();
log_debug("Timeout: " << timeout.count());
}
return 0;
}
#include <steam/steam_client.hpp>
#include <logger/logger.hpp>
#include <network/poller.hpp>
#include <utils/timed_events.hpp>
#include <cstring>
#include <functional>
#include <fstream>
SteamClient::SteamClient(std::shared_ptr<Poller> poller):
TCPSocketHandler(poller),
sentry{}
{
this->load_sentry();
this->steam = std::make_unique<SteamPPClient>(
[this](std::size_t length, std::function<void(unsigned char* buffer)> fill_my_buffer)
{
log_debug("Steam client wants to write " << length << " bytes");
unsigned char buffer[length];
fill_my_buffer(buffer);
this->send_data({reinterpret_cast<char*>(buffer), length});
},
[this](std::function<void()> callback, int timeout)
{
log_debug("set_interval called, timeout = " << timeout);
TimedEvent keepalive(std::chrono::seconds(timeout),
[callback]()
{
log_debug("Calling the interval callback stuff");
callback();
});
TimedEventsManager::instance().add_event(std::move(keepalive));
});
this->steam->onHandshake = std::bind(&SteamClient::on_handshake, this);
this->steam->onLogOn = std::bind(&SteamClient::on_log_on, this,
std::placeholders::_1, std::placeholders::_2);
this->steam->onSentry = std::bind(&SteamClient::on_sentry, this,
std::placeholders::_1);
this->steam->onRelationships = std::bind(&SteamClient::on_relationships, this,
std::placeholders::_1,
std::placeholders::_2,
std::placeholders::_3);
this->steam->onUserInfo = std::bind(&SteamClient::on_user_info, this,
std::placeholders::_1, std::placeholders::_2,
std::placeholders::_3, std::placeholders::_4,
std::placeholders::_5, std::placeholders::_6);
}
void SteamClient::start()
{
this->connect("146.66.152.12", "27017", false);
}
void SteamClient::on_connected()
{
log_debug("We are connected, calling steam->connected()");
this->wanted_size = this->steam->connected();
log_debug("done, wanted_size: " << this->wanted_size);
}
void SteamClient::on_connection_failed(const std::string& reason)
{
log_debug("Connection failed: " << reason);
}
void SteamClient::on_connection_close(const std::string& error)
{
log_debug("Connection closed: " << error);
}
void SteamClient::parse_in_buffer(const size_t size)
{
log_debug("Data received: " << size);
log_debug("We have: " << this->in_buf.size() << " and steam wants " << this->wanted_size);
if (this->in_buf.size() >= this->wanted_size)
{
// Maybe do not get the to_send, just use the whole in_buf
auto to_send = this->in_buf.substr(0, this->wanted_size);
this->in_buf = this->in_buf.substr(this->wanted_size);
this->wanted_size = this->steam->readable(reinterpret_cast<const unsigned char*>(to_send.data()));
log_debug("New wanted_size: " << this->wanted_size);
if (this->in_buf.size() >= this->wanted_size)
this->parse_in_buffer(0);
}
}
void SteamClient::on_handshake()
{
log_debug("onHandshake");
// TODO read from the config file
if (this->sentry[0] != '\0')
this->steam->LogOn("", "", reinterpret_cast<const unsigned char*>(this->sentry));
else
this->steam->LogOn("", "", nullptr, "2BP2N");
log_debug("LogOn() called");
}
void SteamClient::on_log_on(Steam::EResult result, Steam::SteamID steam_id)
{
log_debug("on_log_on: " << static_cast<std::size_t>(result) << " steamid: " << steam_id.steamID64);
}
void SteamClient::on_sentry(const unsigned char* hash)
{
log_debug("on_sentry");
::memcpy(this->sentry, hash, 20);
log_debug("Sentry: " << std::string(reinterpret_cast<const char*>(hash), 20));
this->save_sentry();
}
void SteamClient::on_relationships(bool incremental,
std::map<Steam::SteamID, Steam::EFriendRelationship>& users,
std::map<Steam::SteamID, Steam::EClanRelationship>& groups)
{
log_debug("on_relationships: " << incremental);
Steam::SteamID users_info[users.size()];
log_debug("-- Friends --");
std::size_t i = 0u;
for (auto it = users.begin(); it != users.end(); ++it)
{
const Steam::SteamID& id = it->first;
const Steam::EFriendRelationship& relationship = it->second;
log_debug("SteamID: " << id.steamID64 << " with type " << static_cast<int>(relationship));
users_info[i++] = id;
}
log_debug("Requesting user info for " << i << " friends");
this->steam->RequestUserInfo(i, users_info);
log_debug("-- Groups --");
for (auto it = groups.begin(); it != groups.end(); ++it)
{
const Steam::SteamID& id = it->first;
const Steam::EClanRelationship& relationship = it->second;
log_debug("SteamID: " << id.steamID64 << " with type " << static_cast<int>(relationship));
}
}
void SteamClient::on_user_info(Steam::SteamID user, Steam::SteamID* source, const char* name,
Steam::EPersonaState* state, const unsigned char avatar_hash[20],
const char* game_name)
{
log_debug("on_user_info: " << name);
if (state)
{
log_debug("status: " << static_cast<int>(*state));
}
else
{
log_debug("offline");
}
if (game_name)
{
log_debug("Game name: " << game_name);
}
}
void SteamClient::save_sentry()
{
std::ofstream sentry_file("./sentry.bin", std::ios::binary);
sentry_file.write(reinterpret_cast<char*>(this->sentry), 20);
}
void SteamClient::load_sentry()
{
std::ifstream sentry_file("./sentry.bin", std::ios::binary);
if (!sentry_file.good())
{
log_debug("No sentry file found, or failed to open it, not loading any sentry");
}
else
{
log_debug("Loading sentry from file");
sentry_file.read(reinterpret_cast<char*>(this->sentry), 20);
}
}
#ifndef STEAM_CLIENT_HPP_INCLUDED
#define STEAM_CLIENT_HPP_INCLUDED
#include <network/tcp_socket_handler.hpp>
#include <steam++.h>
#include <memory>
class Poller;
class SteamClient: public TCPSocketHandler
{
using SteamPPClient = Steam::SteamClient;
public:
SteamClient(std::shared_ptr<Poller> poller);
~SteamClient() = default;
void start();
void on_connected() override final;
void on_connection_failed(const std::string& reason) override final;
void on_connection_close(const std::string& error) override final;
void parse_in_buffer(const size_t size) override final;
/**
* Callback called by the steam object on some events
*/
void on_handshake();
void on_log_on(Steam::EResult result, Steam::SteamID steam_id);
void on_sentry(const unsigned char* hash);
void save_sentry();
void load_sentry();
void on_relationships(bool incremental,
std::map<Steam::SteamID, Steam::EFriendRelationship>& users,
std::map<Steam::SteamID, Steam::EClanRelationship>& groups);
void on_user_info(Steam::SteamID user, Steam::SteamID* source, const char* name,
Steam::EPersonaState* state, const unsigned char avatar_hash[20],
const char* game_name);
private:
std::unique_ptr<SteamPPClient> steam;
/**
* The size wanted by steam in the next readable() call
*/
std::size_t wanted_size;
unsigned char sentry[20];
SteamClient(const SteamClient&) = delete;
SteamClient(SteamClient&&) = delete;
SteamClient& operator=(const SteamClient&) = delete;
SteamClient& operator=(SteamClient&&) = delete;
};
#endif /* STEAM_CLIENT_HPP_INCLUDED */
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment