Merge branch 'campaignd_asio'

This commit is contained in:
loonycyborg 2016-09-15 16:34:09 +03:00
commit c16adcd8c9
22 changed files with 1380 additions and 3733 deletions

View file

@ -400,11 +400,6 @@ if env["prereqs"]:
env = conf.Finish()
campaignd_env = env.Clone()
conf = campaignd_env.Configure(**configure_args)
have_sdl_net()
campaignd_env = conf.Finish()
client_env = env.Clone()
conf = client_env.Configure(**configure_args)
have_client_prereqs = have_server_prereqs & have_sdl_other() & \
@ -458,7 +453,7 @@ if env["prereqs"]:
test_env = client_env.Clone()
conf = test_env.Configure(**configure_args)
have_test_prereqs = have_client_prereqs and conf.CheckBoost('unit_test_framework') and conf.CheckSDL("SDL2_net", header_file = "SDL_net") \
have_test_prereqs = have_client_prereqs and conf.CheckBoost('unit_test_framework') \
or Warning("WARN: Unit tests are disabled because their prerequisites are not met")
test_env = conf.Finish()
if not have_test_prereqs and "test" in env["default_targets"]:
@ -495,7 +490,7 @@ if not env['nls']:
#
print "---[applying configuration]---"
for env in [test_env, campaignd_env, client_env, env]:
for env in [test_env, client_env, env]:
build_root="#/"
if os.path.isabs(env["build_dir"]):
build_root = ""
@ -557,7 +552,7 @@ try:
except:
pass
Export(Split("env campaignd_env client_env test_env have_client_prereqs have_server_prereqs have_test_prereqs"))
Export(Split("env client_env test_env have_client_prereqs have_server_prereqs have_test_prereqs"))
SConscript(dirs = Split("po doc packaging/windows packaging/systemd"))
binaries = Split("wesnoth wesnothd cutter exploder campaignd test")
@ -571,7 +566,7 @@ builds = {
builds["glibcxx_debug"].update(builds["debug"])
build = env["build"]
for env in [test_env, campaignd_env, client_env, env]:
for env in [test_env, client_env, env]:
env["extra_flags_glibcxx_debug"] = env["extra_flags_debug"]
env.AppendUnique(**builds[build])
env.Append(CXXFLAGS = Split(os.environ.get('CXXFLAGS', [])), LINKFLAGS = Split(os.environ.get('LDFLAGS', [])))

View file

@ -113,6 +113,10 @@ Version 1.13.5+dev:
gettext plurals.
* New matches function in team and unit attack metatables, which test if the
side or weapon matches a filter.
* Networking
* Ported campaignd to use boost.asio instead of SDL_net.
* Removed unit tests for old networking stack. This was the last part that
depended on SDL_net
* Performance:
* When a heuristic determines that it's probably faster, the game predicts
battle

View file

@ -480,6 +480,36 @@
91B622221B76C0F400B00E0F /* libboost_regex-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F4EF0D5313AD4E35003C701D /* libboost_regex-mt.dylib */; };
91B622231B76C0F400B00E0F /* libboost_system-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F4EF0D5413AD4E35003C701D /* libboost_system-mt.dylib */; };
91B622241B76C0F400B00E0F /* libboost_thread-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F4EF0D5B13AD4E6D003C701D /* libboost_thread-mt.dylib */; };
91C548C31D8866ED00FE6A7B /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F4D2A99514DAED0E00CAFF31 /* CoreFoundation.framework */; };
91C548D21D886AF000FE6A7B /* server_base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C548D01D886AF000FE6A7B /* server_base.cpp */; };
91C548DA1D886BD600FE6A7B /* addon_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C548D31D886BD500FE6A7B /* addon_utils.cpp */; };
91C548DB1D886BD600FE6A7B /* blacklist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C548D51D886BD500FE6A7B /* blacklist.cpp */; };
91C548DC1D886BD600FE6A7B /* campaign_server.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C548D71D886BD500FE6A7B /* campaign_server.cpp */; };
91C548DD1D886BE300FE6A7B /* server_base.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C548D01D886AF000FE6A7B /* server_base.cpp */; };
91C548DE1D886E0A00FE6A7B /* config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B5599AA80EC62181008DD061 /* config.cpp */; };
91C548DF1D886E2100FE6A7B /* log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B5599A020EC62181008DD061 /* log.cpp */; };
91C548E01D886E2C00FE6A7B /* tstring.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999810EC62181008DD061 /* tstring.cpp */; };
91C548E11D886E7200FE6A7B /* string_utils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999AF0EC62181008DD061 /* string_utils.cpp */; };
91C548E21D886E9000FE6A7B /* libboost_system-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F4EF0D5413AD4E35003C701D /* libboost_system-mt.dylib */; };
91C548E31D886EBC00FE6A7B /* unicode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECAA3FE518E0E4EF002E8998 /* unicode.cpp */; };
91C548E41D886ECA00FE6A7B /* gettext_boost.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC4DF45419FEA7A8000EC086 /* gettext_boost.cpp */; };
91C548E51D886EF300FE6A7B /* binary_or_text.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999A70EC62181008DD061 /* binary_or_text.cpp */; };
91C548E61D886F0700FE6A7B /* hash.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B52EE8AD121359A600CFBDAB /* hash.cpp */; };
91C548E81D886F1E00FE6A7B /* libboost_locale-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = EC4DF45919FEA838000EC086 /* libboost_locale-mt.dylib */; };
91C548E91D886F6800FE6A7B /* md5.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999F00EC62181008DD061 /* md5.cpp */; };
91C548EA1D886F7500FE6A7B /* game_config.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B5599A800EC62181008DD061 /* game_config.cpp */; };
91C548EB1D886F8C00FE6A7B /* simple_wml.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B5BB6B6D0F893E7500444FBF /* simple_wml.cpp */; };
91C548EC1D886FA800FE6A7B /* filesystem_boost.cpp in Sources */ = {isa = PBXBuildFile; fileRef = ECF9D43C19F3FF9400E6C9D9 /* filesystem_boost.cpp */; };
91C548ED1D886FC500FE6A7B /* libboost_filesystem-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = ECF9D43F19F4026D00E6C9D9 /* libboost_filesystem-mt.dylib */; };
91C548EE1D886FCE00FE6A7B /* libboost_iostreams-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = F4EF0D4B13AD4D53003C701D /* libboost_iostreams-mt.dylib */; };
91C548EF1D88702800FE6A7B /* input_stream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B5BB6B5B0F893E7500444FBF /* input_stream.cpp */; };
91C548F01D88703300FE6A7B /* validation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B52EE9AB1213640400CFBDAB /* validation.cpp */; };
91C548F11D88705C00FE6A7B /* color_range.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B5599AAA0EC62181008DD061 /* color_range.cpp */; };
91C548F21D88707D00FE6A7B /* filesystem_common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EC5C70BB19EEB54900432CF4 /* filesystem_common.cpp */; };
91C548F31D8870BB00FE6A7B /* parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999AB0EC62181008DD061 /* parser.cpp */; };
91C548F41D8870C700FE6A7B /* version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999670EC62181008DD061 /* version.cpp */; };
91C548F51D8870DE00FE6A7B /* tokenizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999B10EC62181008DD061 /* tokenizer.cpp */; };
91C548F61D8870F800FE6A7B /* preprocessor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B55999AD0EC62181008DD061 /* preprocessor.cpp */; };
91C554601D73F997002DB0C8 /* faction_select.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C5545E1D73F997002DB0C8 /* faction_select.cpp */; };
91C554611D73F997002DB0C8 /* faction_select.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91C5545E1D73F997002DB0C8 /* faction_select.cpp */; };
91C554671D77A545002DB0C8 /* libpcre.1.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 91C554661D77A545002DB0C8 /* libpcre.1.dylib */; };
@ -1729,6 +1759,17 @@
91B621F51B76BCB000B00E0F /* unicode_cast.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = unicode_cast.hpp; sourceTree = "<group>"; };
91B621F61B76BCB000B00E0F /* unicode_types.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = unicode_types.hpp; sourceTree = "<group>"; };
91B621F71B76BD4600B00E0F /* multimenu.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = multimenu.hpp; sourceTree = "<group>"; };
91C548CE1D8866ED00FE6A7B /* campaignd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = campaignd; sourceTree = BUILT_PRODUCTS_DIR; };
91C548CF1D886AF000FE6A7B /* send_receive_wml_helpers.ipp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; fileEncoding = 4; path = send_receive_wml_helpers.ipp; sourceTree = "<group>"; };
91C548D01D886AF000FE6A7B /* server_base.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = server_base.cpp; sourceTree = "<group>"; };
91C548D11D886AF000FE6A7B /* server_base.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = server_base.hpp; sourceTree = "<group>"; };
91C548D31D886BD500FE6A7B /* addon_utils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = addon_utils.cpp; path = ../campaign_server/addon_utils.cpp; sourceTree = "<group>"; };
91C548D41D886BD500FE6A7B /* addon_utils.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = addon_utils.hpp; path = ../campaign_server/addon_utils.hpp; sourceTree = "<group>"; };
91C548D51D886BD500FE6A7B /* blacklist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = blacklist.cpp; path = ../campaign_server/blacklist.cpp; sourceTree = "<group>"; };
91C548D61D886BD500FE6A7B /* blacklist.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = blacklist.hpp; path = ../campaign_server/blacklist.hpp; sourceTree = "<group>"; };
91C548D71D886BD500FE6A7B /* campaign_server.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = campaign_server.cpp; path = ../campaign_server/campaign_server.cpp; sourceTree = "<group>"; };
91C548D81D886BD500FE6A7B /* campaign_server.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = campaign_server.hpp; path = ../campaign_server/campaign_server.hpp; sourceTree = "<group>"; };
91C548D91D886BD600FE6A7B /* control.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = control.hpp; path = ../campaign_server/control.hpp; sourceTree = "<group>"; };
91C5545E1D73F997002DB0C8 /* faction_select.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = faction_select.cpp; sourceTree = "<group>"; };
91C5545F1D73F997002DB0C8 /* faction_select.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = faction_select.hpp; sourceTree = "<group>"; };
91C554661D77A545002DB0C8 /* libpcre.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpcre.1.dylib; path = lib/libpcre.1.dylib; sourceTree = "<group>"; };
@ -2757,6 +2798,18 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
91C548C21D8866ED00FE6A7B /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
91C548C31D8866ED00FE6A7B /* CoreFoundation.framework in Frameworks */,
91C548E21D886E9000FE6A7B /* libboost_system-mt.dylib in Frameworks */,
91C548E81D886F1E00FE6A7B /* libboost_locale-mt.dylib in Frameworks */,
91C548ED1D886FC500FE6A7B /* libboost_filesystem-mt.dylib in Frameworks */,
91C548EE1D886FCE00FE6A7B /* libboost_iostreams-mt.dylib in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
B597C4960FACD3CD00CE81F5 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
@ -2844,6 +2897,7 @@
8D1107320486CEB800E47090 /* Wesnoth.app */,
B5BB6B4B0F890FBA00444FBF /* wesnothd */,
B597C4980FACD3CD00CE81F5 /* unit_tests */,
91C548CE1D8866ED00FE6A7B /* campaignd */,
);
name = Products;
sourceTree = "<group>";
@ -4524,8 +4578,15 @@
B5BB6B560F893DE000444FBF /* server */ = {
isa = PBXGroup;
children = (
91C548D31D886BD500FE6A7B /* addon_utils.cpp */,
91C548D41D886BD500FE6A7B /* addon_utils.hpp */,
B5BB6B7C0F893E7500444FBF /* ban.cpp */,
B5BB6B7A0F893E7500444FBF /* ban.hpp */,
91C548D51D886BD500FE6A7B /* blacklist.cpp */,
91C548D61D886BD500FE6A7B /* blacklist.hpp */,
91C548D71D886BD500FE6A7B /* campaign_server.cpp */,
91C548D81D886BD500FE6A7B /* campaign_server.hpp */,
91C548D91D886BD600FE6A7B /* control.hpp */,
B5BB6B7B0F893E7500444FBF /* forum_user_handler.cpp */,
B5BB6B790F893E7500444FBF /* forum_user_handler.hpp */,
B5BB6B5A0F893E7500444FBF /* game.cpp */,
@ -4546,8 +4607,11 @@
B54AC67E0FEA9C4A006F6FBD /* room_manager.hpp */,
B5BB6B720F893E7500444FBF /* sample_user_handler.cpp */,
B5BB6B6C0F893E7500444FBF /* sample_user_handler.hpp */,
91C548CF1D886AF000FE6A7B /* send_receive_wml_helpers.ipp */,
B5BB6B710F893E7500444FBF /* server.cpp */,
B54AC67F0FEA9C4A006F6FBD /* server.hpp */,
91C548D01D886AF000FE6A7B /* server_base.cpp */,
91C548D11D886AF000FE6A7B /* server_base.hpp */,
B5BB6B6D0F893E7500444FBF /* simple_wml.cpp */,
B5BB6B700F893E7500444FBF /* simple_wml.hpp */,
B5BB6B6E0F893E7500444FBF /* user_handler.cpp */,
@ -4640,6 +4704,22 @@
productReference = 8D1107320486CEB800E47090 /* Wesnoth.app */;
productType = "com.apple.product-type.application";
};
91C548A01D8866ED00FE6A7B /* campaignd */ = {
isa = PBXNativeTarget;
buildConfigurationList = 91C548CB1D8866ED00FE6A7B /* Build configuration list for PBXNativeTarget "campaignd" */;
buildPhases = (
91C548A11D8866ED00FE6A7B /* Sources */,
91C548C21D8866ED00FE6A7B /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = campaignd;
productName = Server;
productReference = 91C548CE1D8866ED00FE6A7B /* campaignd */;
productType = "com.apple.product-type.tool";
};
B597C4970FACD3CD00CE81F5 /* unit_tests */ = {
isa = PBXNativeTarget;
buildConfigurationList = B597C49C0FACD3EC00CE81F5 /* Build configuration list for PBXNativeTarget "unit_tests" */;
@ -4698,6 +4778,7 @@
8D1107260486CEB800E47090 /* Wesnoth */,
B5BB6B4A0F890FBA00444FBF /* wesnothd */,
B597C4970FACD3CD00CE81F5 /* unit_tests */,
91C548A01D8866ED00FE6A7B /* campaignd */,
);
};
/* End PBXProject section */
@ -5285,6 +5366,37 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
91C548A11D8866ED00FE6A7B /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
91C548DA1D886BD600FE6A7B /* addon_utils.cpp in Sources */,
91C548E51D886EF300FE6A7B /* binary_or_text.cpp in Sources */,
91C548DB1D886BD600FE6A7B /* blacklist.cpp in Sources */,
91C548DC1D886BD600FE6A7B /* campaign_server.cpp in Sources */,
91C548F11D88705C00FE6A7B /* color_range.cpp in Sources */,
91C548DE1D886E0A00FE6A7B /* config.cpp in Sources */,
91C548EC1D886FA800FE6A7B /* filesystem_boost.cpp in Sources */,
91C548F21D88707D00FE6A7B /* filesystem_common.cpp in Sources */,
91C548EA1D886F7500FE6A7B /* game_config.cpp in Sources */,
91C548E41D886ECA00FE6A7B /* gettext_boost.cpp in Sources */,
91C548E61D886F0700FE6A7B /* hash.cpp in Sources */,
91C548EF1D88702800FE6A7B /* input_stream.cpp in Sources */,
91C548DF1D886E2100FE6A7B /* log.cpp in Sources */,
91C548E91D886F6800FE6A7B /* md5.cpp in Sources */,
91C548F31D8870BB00FE6A7B /* parser.cpp in Sources */,
91C548F61D8870F800FE6A7B /* preprocessor.cpp in Sources */,
91C548DD1D886BE300FE6A7B /* server_base.cpp in Sources */,
91C548EB1D886F8C00FE6A7B /* simple_wml.cpp in Sources */,
91C548E11D886E7200FE6A7B /* string_utils.cpp in Sources */,
91C548F51D8870DE00FE6A7B /* tokenizer.cpp in Sources */,
91C548E01D886E2C00FE6A7B /* tstring.cpp in Sources */,
91C548E31D886EBC00FE6A7B /* unicode.cpp in Sources */,
91C548F01D88703300FE6A7B /* validation.cpp in Sources */,
91C548F41D8870C700FE6A7B /* version.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
B597C4950FACD3CD00CE81F5 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
@ -5898,6 +6010,7 @@
B5BB6B830F893E7500444FBF /* user_handler.cpp in Sources */,
B5BB6C790F89426400444FBF /* version.cpp in Sources */,
91FBBAD61CB6AF8900470BFE /* player_connection.cpp in Sources */,
91C548D21D886AF000FE6A7B /* server_base.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -5923,6 +6036,47 @@
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
91C548CC1D8866ED00FE6A7B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"LOCALEDIR=\\\"translations\\\"",
"FIFODIR=\\\"/var/run/wesnoth_campaignd\\\"",
);
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
INSTALL_PATH = /usr/local/bin;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/lib\"",
"$(PROJECT_DIR)/lib",
);
PRODUCT_NAME = campaignd;
};
name = Debug;
};
91C548CD1D8866ED00FE6A7B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = YES;
GCC_PREPROCESSOR_DEFINITIONS = (
"LOCALEDIR=\\\"translations\\\"",
"FIFODIR=\\\"/var/run/wesnoth_campaignd\\\"",
);
INSTALL_PATH = /usr/local/bin;
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/lib\"",
"$(PROJECT_DIR)/lib",
);
PRODUCT_NAME = campaignd;
SDKROOT = macosx;
};
name = Release;
};
B597C49A0FACD3CE00CE81F5 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
@ -6181,6 +6335,15 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
91C548CB1D8866ED00FE6A7B /* Build configuration list for PBXNativeTarget "campaignd" */ = {
isa = XCConfigurationList;
buildConfigurations = (
91C548CC1D8866ED00FE6A7B /* Debug */,
91C548CD1D8866ED00FE6A7B /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
B597C49C0FACD3EC00CE81F5 /* Build configuration list for PBXNativeTarget "unit_tests" */ = {
isa = XCConfigurationList;
buildConfigurations = (

View file

@ -47,8 +47,6 @@ if(ZLIB_INCLUDE_DIR)
include_directories(SYSTEM ${ZLIB_INCLUDE_DIR} )
endif()
set(network_implementation_files network.cpp network_worker.cpp)
if(ENABLE_SDL_GPU)
message(STATUS "Configuring SDL_gpu...")
add_definitions("-DSDL_GPU")
@ -242,7 +240,6 @@ set(libwesnoth-core_STAT_SRC
md5.cpp
mt_rng.cpp
seed_rng.cpp
thread.cpp
tstring.cpp
util.cpp
version.cpp
@ -985,7 +982,6 @@ set(wesnoth-main_SRC
whiteboard/side_actions.cpp
whiteboard/suppose_dead.cpp
whiteboard/utility.cpp
${network_implementation_files}
)
########### libwesnoth-game ###############
@ -1157,17 +1153,16 @@ if(ENABLE_SERVER)
set(wesnothd_SRC
server/ban.cpp
server/game.cpp
server/input_stream.cpp
server/metrics.cpp
server/player.cpp
server/player_connection.cpp
server/player_network.cpp
server/server.cpp
server/server_base.cpp
server/simple_wml.cpp
server/user_handler.cpp
server/forum_user_handler.cpp
server/sample_user_handler.cpp
${network_implementation_files}
)
add_executable(wesnothd WIN32
@ -1190,8 +1185,8 @@ set(campaignd_SRC
campaign_server/addon_utils.cpp
campaign_server/blacklist.cpp
campaign_server/campaign_server.cpp
server/input_stream.cpp
${network_implementation_files}
server/server_base.cpp
server/simple_wml.cpp
)
check_library_exists(rt clock_gettime "time.h" HAVE_CLOCK_GETTIME_RT)
@ -1384,7 +1379,6 @@ if(ENABLE_TESTS)
tests/test_lua.cpp
tests/test_map_location.cpp
tests/test_make_enum.cpp
tests/test_network_worker.cpp
tests/test_rng.cpp
tests/test_mp_connect.cpp
tests/test_sdl_utils.cpp

View file

@ -6,7 +6,7 @@ from glob import glob
Import("*")
for env in [test_env, campaignd_env, client_env, env]:
for env in [test_env, client_env, env]:
env.Append(CPPDEFINES = "$EXTRA_DEFINE")
#color_range.cpp should be removed, but game_config depends on it.
@ -22,7 +22,6 @@ libwesnoth_core_sources = Split("""
map/map.cpp
md5.cpp
mt_rng.cpp
network.cpp
seed_rng.cpp
serialization/binary_or_text.cpp
serialization/parser.cpp
@ -33,17 +32,14 @@ libwesnoth_core_sources = Split("""
serialization/unicode.cpp
serialization/validator.cpp
terrain/type_data.cpp
thread.cpp
tools/schema/tag.cpp
tstring.cpp
util.cpp
version.cpp
""")
libwesnoth_core_sources.extend(campaignd_env.Object("network_worker.cpp", EXTRA_DEFINE = env['raw_sockets'] and "NETWORK_USE_RAW_SOCKETS" or None))
game_config_env = campaignd_env.Clone()
filesystem_env = campaignd_env.Clone()
game_config_env = env.Clone()
filesystem_env = env.Clone()
if env["PLATFORM"] != "win32":
game_config_env.Append(CPPDEFINES = "WESNOTH_PATH='\"$datadir\"'")
if env['localedirname']:
@ -83,7 +79,7 @@ else:
filesystem_env.Object("gettext_boost.cpp")
])
libwesnoth_core = [campaignd_env.Library("wesnoth_core", libwesnoth_core_sources)]
libwesnoth_core = [env.Library("wesnoth_core", libwesnoth_core_sources)]
libwesnoth_sources = Split("""
arrow.cpp
@ -154,7 +150,7 @@ libwesnoth = client_env.Library("wesnoth", libwesnoth_sources)
dummy_video_sources = Split("""
tools/dummy_video.cpp
""")
libdummy_video = campaignd_env.Library("dummy_video", dummy_video_sources)
libdummy_video = test_env.Library("dummy_video", dummy_video_sources)
libcampaignd_sources = Split("""
addon/validation.cpp
@ -630,7 +626,7 @@ def WesnothProgram(env, target, source, can_build, **kw):
locals()[target] = bin
Export(target)
for env in [test_env, campaignd_env, client_env, env]:
for env in [test_env, client_env, env]:
env.AddMethod(WesnothProgram)
wesnoth_objects = ["wesnoth.cpp", libwesnoth_extras, libwesnoth_core, libwesnoth,
@ -642,13 +638,14 @@ client_env.WesnothProgram("wesnoth", wesnoth_objects, have_client_prereqs)
campaignd_sources = Split("""
campaign_server/addon_utils.cpp
campaign_server/blacklist.cpp
server/input_stream.cpp
server/server_base.cpp
server/simple_wml.cpp
""")
if env["PLATFORM"] == "win32": env["fifodir"] = ""
campaignd_sources.extend(campaignd_env.Object("campaign_server/campaign_server.cpp", EXTRA_DEFINE = env['fifodir'] and "FIFODIR='\"$fifodir\"'" or None))
campaignd_sources.extend(env.Object("campaign_server/campaign_server.cpp", EXTRA_DEFINE = env['fifodir'] and "FIFODIR='\"$fifodir\"'" or None))
campaignd_env.WesnothProgram("campaignd", campaignd_sources + [libwesnoth_core, libdummy_video, libcampaignd], have_server_prereqs)
env.WesnothProgram("campaignd", campaignd_sources + [libwesnoth_core, libcampaignd], have_server_prereqs)
wesnothd_sources = Split("""
server/ban.cpp
@ -659,6 +656,7 @@ wesnothd_sources = Split("""
server/player_connection.cpp
server/player_network.cpp
server/sample_user_handler.cpp
server/server_base.cpp
server/simple_wml.cpp
server/user_handler.cpp
""")
@ -727,7 +725,6 @@ test_sources = Split("""
tests/test_make_enum.cpp
tests/test_map_location.cpp
tests/test_mp_connect.cpp
tests/test_network_worker.cpp
tests/test_recall_list.cpp
tests/test_rng.cpp
tests/test_sdl_utils.cpp

View file

@ -23,7 +23,6 @@
#include "filesystem.hpp"
#include "log.hpp"
#include "network_worker.hpp"
#include "serialization/binary_or_text.hpp"
#include "serialization/parser.hpp"
#include "serialization/string_utils.hpp"
@ -57,53 +56,17 @@ static lg::log_domain log_campaignd("campaignd");
#define WRN_CS LOG_STREAM(warn, log_campaignd)
#define ERR_CS LOG_STREAM(err, log_campaignd)
//compatibility code for MS compilers
#ifndef SIGHUP
#define SIGHUP 20
#endif
/** @todo FIXME: should define SIGINT here too, but to what? */
static lg::log_domain log_config("config");
#define ERR_CONFIG LOG_STREAM(err, log_config)
#define WRN_CONFIG LOG_STREAM(warn, log_config)
static lg::log_domain log_server("server");
#define ERR_SERVER LOG_STREAM(err, log_server)
#include "server/send_receive_wml_helpers.ipp"
namespace {
/**
* Whether to reload the server configuration as soon as possible
* (e.g. after SIGHUP).
*/
sig_atomic_t need_reload = 0;
void flag_sighup(int signal)
{
assert(signal == SIGHUP);
LOG_CS << "SIGHUP caught, scheduling config reload.\n";
need_reload = 1;
}
void exit_sigint(int signal)
{
assert(signal == SIGINT);
LOG_CS << "SIGINT caught, exiting without cleanup immediately.\n";
exit(0);
}
void exit_sigterm(int signal)
{
assert(signal == SIGTERM);
LOG_CS << "SIGTERM caught, exiting without cleanup immediately.\n";
exit(128 + SIGTERM);
}
time_t monotonic_clock()
{
#if defined(_POSIX_MONOTONIC_CLOCK) && !defined(_WIN32)
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec;
#else
#warning monotonic_clock() is not truly monotonic!
return time(nullptr);
#endif
}
/* Secure password storage functions */
bool authenticate(config& campaign, const config::attribute_value& passphrase)
{
@ -136,29 +99,22 @@ void set_passphrase(config& campaign, std::string passphrase)
namespace campaignd {
server::server(const std::string& cfg_file, size_t min_threads, size_t max_threads)
: cfg_()
server::server(const std::string& cfg_file)
: server_base(default_campaignd_port, true)
, cfg_()
, cfg_file_(cfg_file)
, read_only_(false)
, compress_level_(0)
, input_()
, hooks_()
, handlers_()
, feedback_url_format_()
, blacklist_()
, blacklist_file_()
, port_(load_config())
, net_manager_(min_threads, max_threads)
, server_manager_(port_)
, flush_timer_(io_service_)
{
#ifndef _MSC_VER
signal(SIGHUP, flag_sighup);
#endif
signal(SIGINT, exit_sigint);
signal(SIGTERM, exit_sigterm);
load_config();
LOG_CS << "Port: " << port_ << " Worker threads min/max: " << min_threads
<< '/' << max_threads << '\n';
LOG_CS << "Port: " << port_ << "\n";
// Ensure all campaigns to use secure hash passphrase storage
if(!read_only_) {
@ -176,6 +132,9 @@ server::server(const std::string& cfg_file, size_t min_threads, size_t max_threa
}
register_handlers();
start_server();
flush_cfg();
}
server::~server()
@ -183,7 +142,7 @@ server::~server()
write_config();
}
int server::load_config()
void server::load_config()
{
LOG_CS << "Reading configuration from " << cfg_file_ << "...\n";
@ -196,9 +155,6 @@ int server::load_config()
LOG_CS << "READ-ONLY MODE ACTIVE\n";
}
const bool use_system_sendfile = cfg_["network_use_system_sendfile"].to_bool();
network_worker_pool::set_use_system_sendfile(use_system_sendfile);
// Seems like compression level above 6 is a waste of CPU cycles.
compress_level_ = cfg_["compress_level"].to_int(6);
@ -218,9 +174,21 @@ int server::load_config()
if(!cfg_["control_socket"].empty()) {
const std::string& path = cfg_["control_socket"].str();
if(!input_.get() || input_->path() != path) {
input_.reset(new input_stream(cfg_["control_socket"]));
#ifndef _WIN32
if(path != fifo_path_) {
const int res = mkfifo(path.c_str(),0660);
if(res != 0 && errno != EEXIST) {
ERR_CS << "could not make fifo at '" << path << "' (" << strerror(errno) << ")\n";
} else {
input_.close();
int fifo = open(path.c_str(), O_RDWR|O_NONBLOCK);
input_.assign(fifo);
LOG_CS << "opened fifo at '" << path << "'. Server commands may be written to this file.\n";
read_from_fifo();
fifo_path_ = path;
}
}
#endif
}
// Ensure the campaigns list WML exists even if empty, other functions
@ -230,11 +198,138 @@ int server::load_config()
// Certain config values are saved to WML again so that a given server
// instance's parameters remain constant even if the code defaults change
// at some later point.
cfg_["network_use_system_sendfile"] = use_system_sendfile;
cfg_["compress_level"] = compress_level_;
// But not the listening port number.
return cfg_["port"].to_int(default_campaignd_port);
port_ = cfg_["port"].to_int(default_campaignd_port);
}
void server::handle_new_client(socket_ptr socket)
{
async_receive_doc(socket,
std::bind(&server::handle_request, this, _1, _2)
);
}
void server::handle_request(socket_ptr socket, std::shared_ptr<simple_wml::document> doc)
{
config data;
read(data, doc->output());
config::all_children_iterator i = data.ordered_begin();
if(i != data.ordered_end()) {
// We only handle the first child.
const config::any_child& c = *i;
request_handlers_table::const_iterator j
= handlers_.find(c.key);
if(j != handlers_.end()) {
// Call the handler.
j->second(this, request(c.key, c.cfg, socket));
} else {
send_error("Unrecognized [" + c.key + "] request.",socket);
}
}
}
#ifndef _WIN32
void server::handle_read_from_fifo(const boost::system::error_code& error, std::size_t)
{
if(error) {
if(error == boost::asio::error::operation_aborted)
// This means fifo was closed by load_config() to open another fifo
return;
ERR_CS << "Error reading from fifo: " << error.message() << '\n';
return;
}
std::istream is(&admin_cmd_);
std::string cmd;
std::getline(is, cmd);
const control_line ctl = cmd;
if(ctl == "shut_down") {
LOG_CS << "Shut down requested by admin, shutting down...\n";
throw server_shutdown("Shut down via fifo command");
} else if(ctl == "readonly") {
if(ctl.args_count()) {
cfg_["read_only"] = read_only_ = utils::string_bool(ctl[1], true);
}
LOG_CS << "Read only mode: " << (read_only_ ? "enabled" : "disabled") << '\n';
} else if(ctl == "flush") {
LOG_CS << "Flushing config to disk...\n";
write_config();
} else if(ctl == "reload") {
if(ctl.args_count()) {
if(ctl[1] == "blacklist") {
LOG_CS << "Reloading blacklist...\n";
load_blacklist();
} else {
ERR_CS << "Unrecognized admin reload argument: " << ctl[1] << '\n';
}
} else {
LOG_CS << "Reloading all configuration...\n";
load_config();
LOG_CS << "Reloaded configuration\n";
}
} else if(ctl == "setpass") {
if(ctl.args_count() != 2) {
ERR_CS << "Incorrect number of arguments for 'setpass'\n";
} else {
const std::string& addon_id = ctl[1];
const std::string& newpass = ctl[2];
config& campaign = get_campaign(addon_id);
if(!campaign) {
ERR_CS << "Add-on '" << addon_id << "' not found, cannot set passphrase\n";
} else if(newpass.empty()) {
// Shouldn't happen!
ERR_CS << "Add-on passphrases may not be empty!\n";
} else {
set_passphrase(campaign, newpass);
write_config();
LOG_CS << "New passphrase set for '" << addon_id << "'\n";
}
}
} else {
ERR_CS << "Unrecognized admin command: " << ctl.full() << '\n';
}
read_from_fifo();
}
#endif
void server::handle_sighup(const boost::system::error_code&, int)
{
LOG_CS << "SIGHUP caught, reloading config.\n";
load_config(); // TODO: handle port number config changes
LOG_CS << "Reloaded configuration\n";
sighup_.async_wait(boost::bind(&server::handle_sighup, this, _1, _2));
}
void server::flush_cfg()
{
flush_timer_.expires_from_now(std::chrono::minutes(10));
flush_timer_.async_wait(boost::bind(&server::handle_flush, this, _1));
}
void server::handle_flush(const boost::system::error_code& error)
{
if(error) {
ERR_CS << "Error from reload timer: " << error.message() << "\n";
throw boost::system::system_error(error);
}
write_config();
flush_cfg();
}
void server::load_blacklist()
@ -300,7 +395,7 @@ void server::fire(const std::string& hook, const std::string& addon)
// exec() and family never return; if they do, we have a problem
std::cerr << "ERROR: exec failed with errno " << errno << " for addon " << addon
<< '\n';
<< '\n';
exit(errno);
} else {
@ -309,161 +404,19 @@ void server::fire(const std::string& hook, const std::string& addon)
#endif
}
void server::send_message(const std::string& msg, network::connection sock)
void server::send_message(const std::string& msg, socket_ptr sock)
{
config cfg;
cfg.add_child("message")["message"] = msg;
network::send_data(cfg, sock);
simple_wml::document doc;
doc.root().add_child("message").set_attr_dup("message", msg.c_str());
async_send_doc(sock, doc, boost::bind(&server::handle_new_client, this, _1), null_handler);
}
void server::send_error(const std::string& msg, network::connection sock)
void server::send_error(const std::string& msg, socket_ptr sock)
{
config cfg;
cfg.add_child("error")["message"] = msg;
ERR_CS << "[" << network::ip_address(sock) << "]: " << msg << '\n';
network::send_data(cfg, sock);
}
void server::run()
{
network::connection sock = 0;
time_t last_ts = monotonic_clock();
for(;;)
{
if(need_reload) {
load_config(); // TODO: handle port number config changes
need_reload = 0;
last_ts = 0;
LOG_CS << "Reloaded configuration\n";
}
try {
bool force_flush = false;
std::string admin_cmd;
if(input_ && input_->read_line(admin_cmd)) {
control_line ctl = admin_cmd;
if(ctl == "shut_down") {
LOG_CS << "Shut down requested by admin, shutting down...\n";
break;
} else if(ctl == "readonly") {
if(ctl.args_count()) {
cfg_["read_only"] = read_only_ = utils::string_bool(ctl[1], true);
}
LOG_CS << "Read only mode: " << (read_only_ ? "enabled" : "disabled") << '\n';
} else if(ctl == "flush") {
force_flush = true;
LOG_CS << "Flushing config to disk...\n";
} else if(ctl == "reload") {
if(ctl.args_count()) {
if(ctl[1] == "blacklist") {
LOG_CS << "Reloading blacklist...\n";
load_blacklist();
} else {
ERR_CS << "Unrecognized admin reload argument: " << ctl[1] << '\n';
}
} else {
LOG_CS << "Reloading all configuration...\n";
need_reload = 1;
// Avoid flush timer ellapsing
continue;
}
} else if(ctl == "setpass") {
if(ctl.args_count() != 2) {
ERR_CS << "Incorrect number of arguments for 'setpass'\n";
} else {
const std::string& addon_id = ctl[1];
const std::string& newpass = ctl[2];
config& campaign = get_campaign(addon_id);
if(!campaign) {
ERR_CS << "Add-on '" << addon_id << "' not found, cannot set passphrase\n";
} else if(newpass.empty()) {
// Shouldn't happen!
ERR_CS << "Add-on passphrases may not be empty!\n";
} else {
set_passphrase(campaign, newpass);
write_config();
LOG_CS << "New passphrase set for '" << addon_id << "'\n";
}
}
} else {
ERR_CS << "Unrecognized admin command: " << ctl.full() << '\n';
}
}
const time_t cur_ts = monotonic_clock();
// Write config to disk every ten minutes.
if(force_flush || labs(cur_ts - last_ts) >= 10*60) {
write_config();
last_ts = cur_ts;
}
network::process_send_queue();
sock = network::accept_connection();
if(sock) {
LOG_CS << "received connection from " << network::ip_address(sock) << "\n";
}
config data;
while((sock = network::receive_data(data, 0)) != network::null_connection)
{
config::all_children_iterator i = data.ordered_begin();
if(i != data.ordered_end()) {
// We only handle the first child.
const config::any_child& c = *i;
request_handlers_table::const_iterator j
= handlers_.find(c.key);
if(j != handlers_.end()) {
// Call the handler.
j->second(this, request(c.key, c.cfg, sock));
} else {
send_error("Unrecognized [" + c.key + "] request.",
sock);
}
}
}
} catch(network::error& e) {
if(!e.socket) {
ERR_CS << "fatal network error: " << e.message << "\n";
throw;
} else {
LOG_CS << "client disconnect: " << e.message << " " << network::ip_address(e.socket) << "\n";
e.disconnect();
}
} catch(const config::error& e) {
network::connection err_sock = 0;
network::connection const * err_connection = boost::get_error_info<network::connection_info>(e);
if(err_connection != nullptr) {
err_sock = *err_connection;
}
if(err_sock == 0 && sock > 0) {
err_sock = sock;
}
if(err_sock) {
ERR_CS << "client disconnect due to exception: " << e.what() << " " << network::ip_address(err_sock) << "\n";
network::disconnect(err_sock);
} else {
throw;
}
}
SDL_Delay(20);
}
ERR_CS << "[" << client_address(sock) << "]: " << msg << '\n';
simple_wml::document doc;
doc.root().add_child("error").set_attr_dup("message", msg.c_str());
async_send_doc(sock, doc, boost::bind(&server::handle_new_client, this, _1), null_handler);
}
void server::register_handler(const std::string& cmd, const request_handler& func)
@ -486,7 +439,7 @@ void server::register_handlers()
void server::handle_request_campaign_list(const server::request& req)
{
LOG_CS << "sending campaign list to " << req.addr << " using gzip";
LOG_CS << "sending campaign list to " << req.addr << " using gzip\n";
time_t epoch = time(nullptr);
config campaign_list;
@ -570,12 +523,18 @@ void server::handle_request_campaign_list(const server::request& req)
config response;
response.add_child("campaigns", campaign_list);
std::cerr << " size: " << (network::send_data(response, req.sock)/1024) << "KiB\n";
std::ostringstream ostr;
write(ostr, response);
std::string wml = ostr.str();
simple_wml::document doc(wml.c_str(), simple_wml::INIT_STATIC);
doc.compress();
async_send_doc(req.sock, doc, boost::bind(&server::handle_new_client, this, _1));
}
void server::handle_request_campaign(const server::request& req)
{
LOG_CS << "sending campaign '" << req.cfg["name"] << "' to " << req.addr << " using gzip";
LOG_CS << "sending campaign '" << req.cfg["name"] << "' to " << req.addr << " using gzip\n";
config& campaign = get_campaign(req.cfg["name"]);
@ -592,7 +551,8 @@ void server::handle_request_campaign(const server::request& req)
}
std::cerr << " size: " << size/1024 << "KiB\n";
network::send_file(campaign["filename"], req.sock);
async_send_file(req.sock, campaign["filename"],
boost::bind(&server::handle_new_client, this, _1), null_handler);
// Clients doing upgrades or some other specific thing shouldn't bump
// the downloads count. Default to true for compatibility with old
// clients that won't tell us what they are trying to do.
@ -644,11 +604,11 @@ void server::handle_upload(const server::request& req)
} catch(const utf8::invalid_utf8_exception&) {
if(!passed_name_utf8_check) {
LOG_CS << "Upload aborted - invalid_utf8_exception caught on handle_upload() check 1, "
<< "the add-on pbl info contains invalid UTF-8\n";
<< "the add-on pbl info contains invalid UTF-8\n";
send_error("Add-on rejected: The add-on name contains an invalid UTF-8 sequence.", req.sock);
} else {
LOG_CS << "Upload aborted - invalid_utf8_exception caught on handle_upload() check 2, "
<< "the internal add-ons list contains invalid UTF-8\n";
<< "the internal add-ons list contains invalid UTF-8\n";
send_error("Server error: The server add-ons list is damaged.", req.sock);
}
@ -811,8 +771,8 @@ void server::handle_delete(const server::request& req)
}
if(!authenticate(campaign, erase["passphrase"])
&& (campaigns()["master_password"].empty()
|| campaigns()["master_password"] != erase["passphrase"]))
&& (campaigns()["master_password"].empty()
|| campaigns()["master_password"] != erase["passphrase"]))
{
send_error("The passphrase is incorrect.", req.sock);
return;
@ -870,32 +830,26 @@ void server::handle_change_passphrase(const server::request& req)
} // end namespace campaignd
int main(int argc, char**argv)
int main()
{
game_config::path = filesystem::get_cwd();
lg::set_log_domain_severity("campaignd", lg::info());
lg::set_log_domain_severity("server", lg::info());
lg::timestamps(true);
try {
std::cerr << "Wesnoth campaignd v" << game_config::revision << " starting...\n";
const std::string& cfg_path = filesystem::normalize_path("server.cfg");
const std::string cfg_path = filesystem::normalize_path("server.cfg");
if(argc >= 2 && atoi(argv[1])){
campaignd::server(cfg_path, atoi(argv[1])).run();
} else {
campaignd::server(cfg_path).run();
}
campaignd::server(cfg_path).run();
} catch(config::error& /*e*/) {
std::cerr << "Could not parse config file\n";
return 1;
} catch(filesystem::io_exception& /*e*/) {
std::cerr << "File I/O error\n";
return 2;
} catch(network::error& e) {
std::cerr << "Aborted with network error: " << e.message << '\n';
return 3;
} catch(std::bad_function_call& /*e*/) {
std::cerr << "Bad request handler function call\n";
return 4;

View file

@ -16,30 +16,26 @@
#define CAMPAIGN_SERVER_HPP_INCLUDED
#include "campaign_server/blacklist.hpp"
#include "network.hpp"
#include "server/input_stream.hpp"
#include "server/server_base.hpp"
#include "server/simple_wml.hpp"
#include "utils/functional.hpp"
#include <boost/unordered_map.hpp>
#include <boost/asio/steady_timer.hpp>
#include <chrono>
namespace campaignd {
/**
* Legacy add-ons server.
*/
class server : private boost::noncopyable
class server : private boost::noncopyable, public server_base
{
public:
explicit server(const std::string& cfg_file,
size_t min_threads = 10,
size_t max_threads = 0);
explicit server(const std::string& cfg_file);
~server();
/**
* Runs the server request processing loop.
*/
void run();
private:
/**
* Client request information object.
@ -53,7 +49,7 @@ private:
const std::string& cmd;
const config& cfg;
const network::connection sock;
const socket_ptr sock;
const std::string addr;
/**
@ -69,11 +65,11 @@ private:
*/
request(const std::string& reqcmd,
const config& reqcfg,
network::connection reqsock)
socket_ptr reqsock)
: cmd(reqcmd)
, cfg(reqcfg)
, sock(reqsock)
, addr(network::ip_address(sock))
, addr(client_address(sock))
{}
};
@ -86,8 +82,6 @@ private:
bool read_only_;
int compress_level_; /**< Used for add-on archives. */
std::unique_ptr<input_stream> input_; /**< Server control socket. */
std::map<std::string, std::string> hooks_;
request_handlers_table handlers_;
@ -96,17 +90,24 @@ private:
blacklist blacklist_;
std::string blacklist_file_;
int port_;
void handle_new_client(socket_ptr socket);
void handle_request(socket_ptr socket, std::shared_ptr<simple_wml::document> doc);
const network::manager net_manager_;
const network::server_manager server_manager_;
void handle_read_from_fifo(const boost::system::error_code& error, std::size_t bytes_transferred);
void handle_sighup(const boost::system::error_code& error, int signal_number);
boost::asio::basic_waitable_timer<std::chrono::steady_clock> flush_timer_;
/**
* Starts timer to write config to disk every ten minutes.
*/
void flush_cfg();
void handle_flush(const boost::system::error_code& error);
/**
* Reads the server configuration from WML.
*
* @return The configured listening port number.
*/
int load_config();
void load_config();
/**
* Writes the server configuration WML back to disk.
@ -172,17 +173,13 @@ private:
void handle_delete(const request&);
void handle_change_passphrase(const request&);
//
// Generic responses.
//
/**
* Send a client an informational message.
*
* The WML sent consists of a document containing a single @p [message]
* child with a @a message attribute holding the value of @a msg.
*/
void send_message(const std::string& msg, network::connection sock);
void send_message(const std::string& msg, socket_ptr sock);
/**
* Send a client an error message.
@ -192,7 +189,7 @@ private:
* sending the error to the client, a line with the client IP and message
* is recorded to the server log.
*/
void send_error(const std::string& msg, network::connection sock);
void send_error(const std::string& msg, socket_ptr sock);
};
} // end namespace campaignd

View file

@ -27,49 +27,49 @@
#include <iomanip>
std::map<Uint32, Uint32> recolor_range(const color_range& new_range, const std::vector<Uint32>& old_rgb){
std::map<Uint32, Uint32> map_rgb;
std::map<uint32_t, uint32_t> recolor_range(const color_range& new_range, const std::vector<uint32_t>& old_rgb){
std::map<uint32_t, uint32_t> map_rgb;
Uint16 new_red = (new_range.mid() & 0x00FF0000)>>16;
Uint16 new_green= (new_range.mid() & 0x0000FF00)>>8;
Uint16 new_blue = (new_range.mid() & 0x000000FF);
Uint16 max_red = (new_range.max() & 0x00FF0000)>>16;
Uint16 max_green= (new_range.max() & 0x0000FF00)>>8 ;
Uint16 max_blue = (new_range.max() & 0x000000FF) ;
Uint16 min_red = (new_range.min() & 0x00FF0000)>>16;
Uint16 min_green= (new_range.min() & 0x0000FF00)>>8 ;
Uint16 min_blue = (new_range.min() & 0x000000FF) ;
uint16_t new_red = (new_range.mid() & 0x00FF0000)>>16;
uint16_t new_green= (new_range.mid() & 0x0000FF00)>>8;
uint16_t new_blue = (new_range.mid() & 0x000000FF);
uint16_t max_red = (new_range.max() & 0x00FF0000)>>16;
uint16_t max_green= (new_range.max() & 0x0000FF00)>>8 ;
uint16_t max_blue = (new_range.max() & 0x000000FF) ;
uint16_t min_red = (new_range.min() & 0x00FF0000)>>16;
uint16_t min_green= (new_range.min() & 0x0000FF00)>>8 ;
uint16_t min_blue = (new_range.min() & 0x000000FF) ;
// Map first color in vector to exact new color
Uint32 temp_rgb= old_rgb.empty() ? 0 : old_rgb[0];
Uint16 old_r=(temp_rgb & 0X00FF0000)>>16;
Uint16 old_g=(temp_rgb & 0X0000FF00)>>8;
Uint16 old_b=(temp_rgb & 0X000000FF);
Uint16 reference_avg = (( old_r + old_g + old_b) / 3);
uint32_t temp_rgb= old_rgb.empty() ? 0 : old_rgb[0];
uint16_t old_r=(temp_rgb & 0X00FF0000)>>16;
uint16_t old_g=(temp_rgb & 0X0000FF00)>>8;
uint16_t old_b=(temp_rgb & 0X000000FF);
uint16_t reference_avg = (( old_r + old_g + old_b) / 3);
for(std::vector< Uint32 >::const_iterator temp_rgb2 = old_rgb.begin();
for(std::vector< uint32_t >::const_iterator temp_rgb2 = old_rgb.begin();
temp_rgb2 != old_rgb.end(); ++temp_rgb2)
{
Uint16 old_r=((*temp_rgb2) & 0X00FF0000)>>16;
Uint16 old_g=((*temp_rgb2) & 0X0000FF00)>>8;
Uint16 old_b=((*temp_rgb2) & 0X000000FF);
uint16_t old_r=((*temp_rgb2) & 0X00FF0000)>>16;
uint16_t old_g=((*temp_rgb2) & 0X0000FF00)>>8;
uint16_t old_b=((*temp_rgb2) & 0X000000FF);
const Uint16 old_avg = (( old_r + old_g + old_b) / 3);
const uint16_t old_avg = (( old_r + old_g + old_b) / 3);
// Calculate new color
Uint32 new_r, new_g, new_b;
uint32_t new_r, new_g, new_b;
if(reference_avg && old_avg <= reference_avg){
float old_rat = static_cast<float>(old_avg)/reference_avg;
new_r=Uint32( old_rat * new_red + (1 - old_rat) * min_red);
new_g=Uint32( old_rat * new_green + (1 - old_rat) * min_green);
new_b=Uint32( old_rat * new_blue + (1 - old_rat) * min_blue);
new_r=uint32_t( old_rat * new_red + (1 - old_rat) * min_red);
new_g=uint32_t( old_rat * new_green + (1 - old_rat) * min_green);
new_b=uint32_t( old_rat * new_blue + (1 - old_rat) * min_blue);
}else if(255 - reference_avg){
float old_rat = (255.0f - static_cast<float>(old_avg)) /
(255.0f - reference_avg);
new_r=static_cast<Uint32>( old_rat * new_red + (1 - old_rat) * max_red);
new_g=static_cast<Uint32>( old_rat * new_green + (1 - old_rat) * max_green);
new_b=static_cast<Uint32>( old_rat * new_blue + (1 - old_rat) * max_blue);
new_r=static_cast<uint32_t>( old_rat * new_red + (1 - old_rat) * max_red);
new_g=static_cast<uint32_t>( old_rat * new_green + (1 - old_rat) * max_green);
new_b=static_cast<uint32_t>( old_rat * new_blue + (1 - old_rat) * max_blue);
}else{
new_r=0; new_g=0; new_b=0; // Suppress warning
assert(false);
@ -81,21 +81,21 @@ std::map<Uint32, Uint32> recolor_range(const color_range& new_range, const std::
if(new_g>255) new_g=255;
if(new_b>255) new_b=255;
Uint32 newrgb = (new_r << 16) + (new_g << 8) + (new_b );
uint32_t newrgb = (new_r << 16) + (new_g << 8) + (new_b );
map_rgb[*temp_rgb2]=newrgb;
}
return map_rgb;
}
bool string2rgb(const std::string& s, std::vector<Uint32>& result) {
result = std::vector<Uint32>();
std::vector<Uint32> out;
bool string2rgb(const std::string& s, std::vector<uint32_t>& result) {
result = std::vector<uint32_t>();
std::vector<uint32_t> out;
std::vector<std::string> rgb_vec = utils::split(s);
std::vector<std::string>::iterator c=rgb_vec.begin();
while(c!=rgb_vec.end())
{
Uint32 rgb_hex;
uint32_t rgb_hex;
if(c->length() != 6)
{
try {
@ -127,14 +127,14 @@ bool string2rgb(const std::string& s, std::vector<Uint32>& result) {
return true;
}
std::vector<Uint32> palette(color_range cr){
std::vector<uint32_t> palette(color_range cr){
// generate a color palette from a color range
std::vector<Uint32> temp,res;
std::set<Uint32> clist;
std::vector<uint32_t> temp,res;
std::set<uint32_t> clist;
// use blue to make master set of possible colors
for(int i=255;i!=0;i--){
int j=255-i;
Uint32 rgb = i;
uint32_t rgb = i;
temp.push_back(rgb);
rgb = (j << 16) + (j << 8) + 255;
temp.push_back(rgb);
@ -143,19 +143,19 @@ std::vector<Uint32> palette(color_range cr){
// Use recolor function to generate list of possible colors.
// Could use a special function, would be more efficient,
// but harder to maintain.
std::map<Uint32,Uint32> cmap = recolor_range(cr,temp);
for(std::map<Uint32,Uint32>::const_iterator k=cmap.begin(); k!=cmap.end();++k){
std::map<uint32_t,uint32_t> cmap = recolor_range(cr,temp);
for(std::map<uint32_t,uint32_t>::const_iterator k=cmap.begin(); k!=cmap.end();++k){
clist.insert(k->second);
}
res.push_back(cmap[255]);
for(std::set<Uint32>::const_iterator c=clist.begin();c!=clist.end();++c){
for(std::set<uint32_t>::const_iterator c=clist.begin();c!=clist.end();++c){
if(*c != res[0] && *c!=0 && *c != 0x00FFFFFF){
res.push_back(*c);}
}
return(res);
}
std::string rgb2highlight(Uint32 rgb)
std::string rgb2highlight(uint32_t rgb)
{
std::ostringstream h;
// Must match what the escape interpreter for marked-up-text expects
@ -165,7 +165,7 @@ std::string rgb2highlight(Uint32 rgb)
return h.str();
}
std::string rgb2highlight_pango(Uint32 rgb)
std::string rgb2highlight_pango(uint32_t rgb)
{
std::ostringstream h;
// Must match what the pango expects
@ -189,7 +189,7 @@ std::string color_range::debug() const
{
std::ostringstream o;
static const Uint32 mask = 0x00FFFFFF;
static const uint32_t mask = 0x00FFFFFF;
o << std::hex << std::setfill('0')
<< '{' << std::setw(6) << (mid_ & mask)

View file

@ -27,13 +27,12 @@
#include <map>
#include <string>
#include <vector>
#include <SDL_types.h>
#include <stdint.h>
/* Convert comma separated string into rgb values.
* Return false and empty result on error.
*/
bool string2rgb(const std::string& s, std::vector<Uint32>& result);
bool string2rgb(const std::string& s, std::vector<uint32_t>& result);
/**
* A color range definition is made of four reference RGB colors, used
@ -61,13 +60,13 @@ public:
* @param min Minimum color shade
* @param rep High-contrast reference color
*/
color_range(Uint32 mid , Uint32 max = 0x00FFFFFF , Uint32 min = 0x00000000 , Uint32 rep = 0x00808080):mid_(mid),max_(max),min_(min),rep_(rep){}
color_range(uint32_t mid , uint32_t max = 0x00FFFFFF , uint32_t min = 0x00000000 , uint32_t rep = 0x00808080):mid_(mid),max_(max),min_(min),rep_(rep){}
/**
* Constructor, which expects four reference RGB colors.
* @param v STL vector with the four reference colors in order.
*/
color_range(const std::vector<Uint32>& v)
color_range(const std::vector<uint32_t>& v)
: mid_(v.size() ? v[0] : 0x00808080),
max_(v.size() > 1 ? v[1] : 0x00FFFFFF),
min_(v.size() > 2 ? v[2] : 0x00000000),
@ -79,13 +78,13 @@ public:
color_range() : mid_(0x00808080), max_(0x00FFFFFF), min_(0x00000000), rep_(0x00808080) {}
/** Average color shade. */
Uint32 mid() const{return(mid_);}
uint32_t mid() const{return(mid_);}
/** Maximum color shade. */
Uint32 max() const{return(max_);}
uint32_t max() const{return(max_);}
/** Minimum color shade. */
Uint32 min() const{return(min_);}
uint32_t min() const{return(min_);}
/** High-contrast shade, intended for the minimap markers. */
Uint32 rep() const{return(rep_);}
uint32_t rep() const{return(rep_);}
bool operator<(const color_range& b) const
{
@ -106,13 +105,13 @@ public:
std::string debug() const;
private:
Uint32 mid_ , max_ , min_ , rep_;
uint32_t mid_ , max_ , min_ , rep_;
};
/**
* Creates a reference color palette from a color range.
*/
std::vector<Uint32> palette(color_range cr);
std::vector<uint32_t> palette(color_range cr);
/**
* Converts a source palette using the specified color_range object.
@ -123,17 +122,17 @@ std::vector<Uint32> palette(color_range cr);
* @return A STL map of colors, with the keys being source palette elements, and the values
* are the result of applying the color range conversion on it.
*/
std::map<Uint32, Uint32> recolor_range(const color_range& new_rgb, const std::vector<Uint32>& old_rgb);
std::map<uint32_t, uint32_t> recolor_range(const color_range& new_rgb, const std::vector<uint32_t>& old_rgb);
/**
* Converts a color value to WML text markup syntax for highlighting.
* For example, 0x00CC00CC becomes "<204,0,204>".
*/
std::string rgb2highlight(Uint32 rgb);
std::string rgb2highlight(uint32_t rgb);
/**
* Converts a color value to WML text markup syntax for highlighting.
* For example, 0x00CC00CC becomes "#CC00CC".
*/
std::string rgb2highlight_pango(Uint32 rgb);
std::string rgb2highlight_pango(uint32_t rgb);
#endif

View file

@ -120,11 +120,11 @@ namespace game_config
std::string shroud_prefix, fog_prefix;
std::string flag_rgb, unit_rgb;
std::vector<Uint32> red_green_scale;
std::vector<Uint32> red_green_scale_text;
std::vector<uint32_t> red_green_scale;
std::vector<uint32_t> red_green_scale_text;
static std::vector<Uint32> blue_white_scale;
static std::vector<Uint32> blue_white_scale_text;
static std::vector<uint32_t> blue_white_scale;
static std::vector<uint32_t> blue_white_scale_text;
double hp_bar_scaling = 0.666;
double xp_bar_scaling = 0.5;
@ -138,7 +138,7 @@ namespace game_config
std::map<std::string, color_range > team_rgb_range;
std::map<std::string, t_string > team_rgb_name;
std::map<std::string, std::vector<Uint32> > team_rgb_colors;
std::map<std::string, std::vector<uint32_t> > team_rgb_colors;
const version_info wesnoth_version(VERSION);
const version_info min_savegame_version(MIN_SAVEGAME_VERSION);
@ -348,7 +348,7 @@ namespace game_config
continue;
}
std::string id = *a1;
std::vector<Uint32> temp;
std::vector<uint32_t> temp;
if(!string2rgb(*a2, temp)) {
std::stringstream ss;
ss << "can't parse color string:\n" << teamC.debug() << "\n";
@ -360,7 +360,7 @@ namespace game_config
LOG_NG << "registered color range '" << id << "': " << team_rgb_range[id].debug() << '\n';
//generate palette of same name;
std::vector<Uint32> tp = palette(team_rgb_range[id]);
std::vector<uint32_t> tp = palette(team_rgb_range[id]);
if (tp.empty()) {
continue;
}
@ -371,7 +371,7 @@ namespace game_config
{
for (const config::attribute &rgb : cp.attribute_range())
{
std::vector<Uint32> temp;
std::vector<uint32_t> temp;
if(!string2rgb(rgb.second, temp)) {
ERR_NG << "Invalid color palette: " << rgb.second << std::endl;
}
@ -385,7 +385,7 @@ namespace game_config
{
std::map<std::string, color_range>::const_iterator i = team_rgb_range.find(name);
if(i == team_rgb_range.end()) {
std::vector<Uint32> temp;
std::vector<uint32_t> temp;
if(!string2rgb(name, temp)) {
throw config::error(_("Invalid color range: ") + name);
}
@ -395,13 +395,13 @@ namespace game_config
return i->second;
}
const std::vector<Uint32>& tc_info(const std::string& name)
const std::vector<uint32_t>& tc_info(const std::string& name)
{
std::map<std::string, std::vector<Uint32> >::const_iterator i = team_rgb_colors.find(name);
std::map<std::string, std::vector<uint32_t> >::const_iterator i = team_rgb_colors.find(name);
if(i == team_rgb_colors.end()) {
std::vector<Uint32> temp;
std::vector<uint32_t> temp;
if(!string2rgb(name, temp)) {
static std::vector<Uint32> stv;
static std::vector<uint32_t> stv;
ERR_NG << "Invalid color palette: " << name << std::endl;
return stv;
}
@ -411,16 +411,16 @@ namespace game_config
return i->second;
}
Uint32 red_to_green(int val, bool for_text){
const std::vector<Uint32>& color_scale =
uint32_t red_to_green(int val, bool for_text){
const std::vector<uint32_t>& color_scale =
for_text ? red_green_scale_text : red_green_scale;
val = std::max<int>(0, std::min<int>(val, 100));
int lvl = (color_scale.size()-1) * val / 100;
return color_scale[lvl];
}
Uint32 blue_to_white(int val, bool for_text){
const std::vector<Uint32>& color_scale =
uint32_t blue_to_white(int val, bool for_text){
const std::vector<uint32_t>& color_scale =
for_text ? blue_white_scale_text : blue_white_scale;
val = std::max<int>(0, std::min<int>(val, 100));
int lvl = (color_scale.size()-1) * val / 100;

File diff suppressed because it is too large Load diff

View file

@ -1,310 +0,0 @@
/*
Copyright (C) 2003 - 2016 by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/** @file */
#ifndef NETWORK_HPP_INCLUDED
#define NETWORK_HPP_INCLUDED
/**
* Enable bandwidth stats
**/
class config;
#include "exceptions.hpp"
#include <SDL_net.h>
#include <string>
#include <vector>
#include <boost/exception/error_info.hpp>
namespace threading
{
class waiter;
}
// This module wraps the network interface.
namespace network {
struct pending_statistics {
int npending_sends;
int nbytes_pending_sends;
};
pending_statistics get_pending_stats();
// A network manager must be created before networking can be used.
// It must be destroyed only after all networking activity stops.
// min_threads is the maximum number we allow to wait,
// if more threads attempt to wait, they will die.
// If min_threads == 0 no thread will ever be destroyed,
// and we will stay at the max number of threads ever needed.
// max_threads is the overall max number of helper threads.
// If we have that many threads already running, we will never create more.
// If max_threads == 0 we will always create a thread if we need it.
struct manager {
explicit manager(size_t min_threads = 1,size_t max_threads = 0);
~manager();
private:
bool free_;
manager(const manager&);
void operator=(const manager&);
};
void set_raw_data_only();
typedef int connection;
connection const null_connection = 0;
/**
* A server manager causes listening on a given port
* to occur for the duration of its lifetime.
*/
struct server_manager {
/** Parameter to pass to the constructor. */
enum CREATE_SERVER { MUST_CREATE_SERVER, /**< Will throw exception on failure. */
TRY_CREATE_SERVER, /**< Will swallow failure. */
NO_SERVER }; /**< Won't try to create a server at all. */
// Throws error.
server_manager(int port, CREATE_SERVER create_server=MUST_CREATE_SERVER);
~server_manager();
bool is_running() const;
void stop();
private:
bool free_;
connection connection_;
};
/** @name Proxy Settings Methods
*
* Methods to configure the connection of a client through a proxy server.
*/
//@{
/**
* Attempt to connect through a proxy (as opposed to directly.)
*
* Use the set_proxy_* methods to configure the connection options.
*/
void enable_connection_through_proxy();
/**
* Set the address of the proxy. Default: "localhost".
*
* @param address Network address where the proxy server should be running.
*/
void set_proxy_address ( const std::string& address );
/**
* Set the port of the proxy. Default: "3128".
*
* @param port Network port where the proxy server should be listening.
*/
void set_proxy_port ( const std::string& port );
/**
* Set the user to authenticate with the proxy. Default: "".
*
* @param user User name to use for authentication purposes.
*/
void set_proxy_user ( const std::string& user );
/**
* Set the password to authenticate with the proxy. Default: "".
*
* @param password Password to use for authentication purposes.
*/
void set_proxy_password( const std::string& password );
//@}
/** The number of peers we are connected to. */
size_t nconnections();
/** If we are currently accepting connections. */
bool is_server();
/**
* Function to attempt to connect to a remote host.
*
* @returns The new connection on success, or 0 on failure.
* @throw error
*/
connection connect(const std::string& host, int port=15000);
connection connect(const std::string& host, int port, threading::waiter& waiter);
/**
* Function to accept a connection from a remote host.
*
* If no host is attempting to connect, it will return 0 immediately.
* Otherwise returns the new connection.
*
* @throw error
*/
connection accept_connection();
/**
* Function to disconnect from a certain host,
* or close all connections if connection_num is 0.
* Returns true if the connection was disconnected.
* Returns false on failure to disconnect, since the socket is
* in the middle of sending/receiving data.
* The socket will be closed when it has finished its send/receive.
*/
bool disconnect(connection connection_num=0);
/**
* Function to queue a disconnection.
*
* Next time receive_data is called, it will generate an error
* on the given connection (and presumably then the handling of the error
* will include closing the connection).
*/
void queue_disconnect(connection connection_num);
std::string get_bandwidth_stats();
std::string get_bandwidth_stats_all();
std::string get_bandwidth_stats(int hour);
void add_bandwidth_out(const std::string& packet_type, size_t len);
void add_bandwidth_in(const std::string& packet_type, size_t len);
struct bandwidth_in {
bandwidth_in(int len) : len_(len), type_("unknown") {}
~bandwidth_in();
void set_type(const std::string& type)
{
type_ = type;
}
private:
int len_;
std::string type_;
};
typedef std::shared_ptr<bandwidth_in> bandwidth_in_ptr;
/**
* Function to receive data from either a certain connection,
* or all connections if connection_num is 0.
* Will store the data received in cfg.
* Times out after timeout milliseconds.
*
* @returns The connection that data was received from,
* or 0 if timeout occurred.
*
* @throw error If an error occurred.
*/
connection receive_data(config& cfg, connection connection_num=0, bandwidth_in_ptr* b = 0);
connection receive_data(config& cfg, connection connection_num, unsigned int timeout, bandwidth_in_ptr* b = 0);
connection receive_data(std::vector<char>& buf, bandwidth_in_ptr* = 0);
void send_file(const std::string&, connection, const std::string& packet_type = "unknown");
/**
* Function to send data down a given connection,
* or broadcast to all peers if connection_num is 0.
*
* @throw error
*/
size_t send_data(const config& cfg, connection connection_num = 0,
const std::string& packet_type = "unknown");
void send_raw_data(const char* buf, int len, connection connection_num,
const std::string& packet_type = "unknown");
/**
* Function to send any data that is in a connection's send_queue,
* up to a maximum of 'max_size' bytes --
* or the entire send queue if 'max_size' bytes is 0.
*/
void process_send_queue(connection connection_num=0, size_t max_size=0);
/** Function to send data to all peers except 'connection_num'. */
void send_data_all_except(const config& cfg, connection connection_num,
const std::string& packet_type = "unknown");
/** Function to get the remote ip address of a socket. */
std::string ip_address(connection connection_num);
struct connection_stats
{
connection_stats(int sent, int received, int connected_at);
int bytes_sent, bytes_received;
int time_connected;
};
connection_stats get_connection_stats(connection connection_num);
struct error : public game::error
{
error(const std::string& msg="", connection sock=0);
connection socket;
void disconnect();
};
typedef boost::error_info<struct tag_tcpsocket,TCPsocket> tcpsocket_info;
typedef boost::error_info<struct tag_connum,connection> connection_info;
struct statistics
{
statistics() : total(0), current(0), current_max(0) {}
void fresh_current(size_t len)
{
current = 0;
current_max = len;
}
void transfer(size_t size)
{
total += size;
current += size;
}
bool operator==(const statistics& stats) const
{
return total == stats.total && current == stats.current && current_max == stats.current_max;
}
bool operator!=(const statistics& stats) const
{
return !operator==(stats);
}
size_t total /** The accumulated bytes of the session. */ ;
size_t current /** The current buffer accumulated bytes (sent/received.) */ ;
size_t current_max /** The current buffer size (i.e. being received/sent.) */ ;
};
/** Function to see the number of bytes being processed on the current socket. */
statistics get_send_stats(connection handle);
statistics get_receive_stats(connection handle);
/** Amount of seconds after the last server ping when we assume to have timed out. */
extern unsigned int ping_timeout;
/** Minimum interval between pings. */
const int ping_interval = 30;
} // network namespace
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,77 +0,0 @@
/*
Copyright (C) 2003 - 2016 by David White <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef NETWORK_WORKER_HPP_INCLUDED
#define NETWORK_WORKER_HPP_INCLUDED
#include <map>
#include "network.hpp"
class config;
/**
* Aligns a variable on a 4 byte boundary.
*
* The address needs to be aligned on a Sparc system, if it's not aligned the
* SDLNet_Read32 call will cause a SIGBUS and the server will be terminated [1].
* Best use this alignment for all buffers used in for the SDL_Net calls.
*
* [1] http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=426318
*/
#ifdef __GNUC__
#define ALIGN_4 __attribute__ ((aligned (4)))
#else
#define ALIGN_4
#endif
namespace network_worker_pool
{
struct manager
{
explicit manager(size_t min_threads,size_t max_threads);
~manager();
private:
manager(const manager&);
void operator=(const manager&);
bool active_;
};
network::pending_statistics get_pending_stats();
void set_raw_data_only();
void set_use_system_sendfile(bool);
/** Function to asynchronously received data to the given socket. */
void receive_data(TCPsocket sock);
TCPsocket get_received_data(TCPsocket sock, config& cfg, network::bandwidth_in_ptr&);
TCPsocket get_received_data(std::vector<char>& buf);
void queue_file(TCPsocket sock, const std::string&);
void queue_raw_data(TCPsocket sock, const char* buf, int len);
size_t queue_data(TCPsocket sock, const config& buf, const std::string& packet_type);
bool is_locked(const TCPsocket sock);
bool close_socket(TCPsocket sock);
TCPsocket detect_error();
std::pair<network::statistics,network::statistics> get_current_transfer_stats(TCPsocket sock);
}
#endif

View file

@ -18,6 +18,7 @@
#include "simple_wml.hpp"
#include "player.hpp"
#include "server_base.hpp"
#ifndef _WIN32
#define BOOST_ASIO_DISABLE_THREADS
@ -33,8 +34,6 @@
namespace wesnothd
{
typedef std::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr;
class player_record
{
const socket_ptr socket_;
@ -86,8 +85,6 @@ void send_to_players(simple_wml::document& data, const Container& players, socke
void send_server_message(socket_ptr socket, const std::string& message);
std::string client_address(socket_ptr socket);
} // namespace wesnothd
#endif

View file

@ -0,0 +1,235 @@
/*
Copyright (C) 2016 by Sergey Popov <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License 2
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef SEND_RECEIVE_WML_HELPERS_HPP
#define SEND_RECEIVE_WML_HELPERS_HPP
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_SENDFILE
#include <sys/sendfile.h>
#endif
#include "server_base.hpp"
#include "simple_wml.hpp"
#include "filesystem.hpp"
template<typename Handler, typename ErrorHandler>
struct handle_doc
{
Handler handler;
ErrorHandler error_handler;
socket_ptr socket;
union DataSize
{
boost::uint32_t size;
char buf[4];
};
std::shared_ptr<DataSize> data_size;
std::shared_ptr<simple_wml::document> doc;
boost::shared_array<char> buffer;
handle_doc(socket_ptr socket, Handler handler, ErrorHandler error_handler, boost::uint32_t size, std::shared_ptr<simple_wml::document> doc) :
handler(handler), error_handler(error_handler), socket(socket), data_size(new DataSize), doc(doc)
{
data_size->size = htonl(size);
}
handle_doc(socket_ptr socket, Handler handler, ErrorHandler error_handler) :
handler(handler), error_handler(error_handler), socket(socket), data_size(new DataSize)
{
}
void operator()(const boost::system::error_code& error, std::size_t)
{
if(check_error(error, socket)) {
error_handler(socket);
return;
}
handler(socket);
}
};
template<typename Handler, typename ErrorHandler>
void async_send_doc(socket_ptr socket, simple_wml::document& doc, Handler handler, ErrorHandler error_handler)
{
try {
std::shared_ptr<simple_wml::document> doc_ptr(doc.clone());
simple_wml::string_span s = doc_ptr->output_compressed();
std::vector<boost::asio::const_buffer> buffers;
handle_doc<Handler, ErrorHandler> handle_send_doc(socket, handler, error_handler, s.size(), doc_ptr);
buffers.push_back(boost::asio::buffer(handle_send_doc.data_size->buf, 4));
buffers.push_back(boost::asio::buffer(s.begin(), s.size()));
async_write(*socket, buffers, handle_send_doc);
} catch (simple_wml::error& e) {
WRN_CONFIG << __func__ << ": simple_wml error: " << e.message << std::endl;
}
}
static void null_handler(socket_ptr)
{
}
#ifdef HAVE_SENDFILE
template <typename Handler, typename ErrorHandler>
struct sendfile_op
{
socket_ptr sock_;
int fd_;
Handler handler_;
ErrorHandler error_handler_;
off_t offset_;
std::size_t total_bytes_transferred_;
// Function call operator meeting WriteHandler requirements.
// Used as the handler for the async_write_some operation.
void operator()(boost::system::error_code ec, std::size_t)
{
// Put the underlying socket into non-blocking mode.
if (!ec)
if (!sock_->native_non_blocking())
sock_->native_non_blocking(true, ec);
if (!ec)
{
for (;;)
{
// Try the system call.
errno = 0;
int n = ::sendfile(sock_->native_handle(), fd_, &offset_, 65536);
ec = boost::system::error_code(n < 0 ? errno : 0,
boost::asio::error::get_system_category());
total_bytes_transferred_ += ec ? 0 : n;
// Retry operation immediately if interrupted by signal.
if (ec == boost::asio::error::interrupted)
continue;
// Check if we need to run the operation again.
if (ec == boost::asio::error::would_block
|| ec == boost::asio::error::try_again)
{
// We have to wait for the socket to become ready again.
sock_->async_write_some(boost::asio::null_buffers(), *this);
return;
}
if (ec || n == 0)
{
// An error occurred, or we have reached the end of the file.
// Either way we must exit the loop so we can call the handler.
break;
}
// Loop around to try calling sendfile again.
}
}
close(fd_);
if(ec)
error_handler_(sock_);
else
handler_(sock_);
}
};
template<typename Handler, typename ErrorHandler>
void async_send_file(socket_ptr socket, const std::string& filename, Handler handler, ErrorHandler error_handler)
{
std::vector<boost::asio::const_buffer> buffers;
size_t filesize = filesystem::file_size(filename);
int in_file(open(filename.c_str(), O_RDONLY));
sendfile_op<Handler, ErrorHandler> op = { socket, in_file, handler, error_handler, 0, 0 };
handle_doc<Handler, ErrorHandler> handle_send_doc(socket, handler, error_handler, filesize, nullptr);
buffers.push_back(boost::asio::buffer(handle_send_doc.data_size->buf, 4));
async_write(*socket, buffers, op);
}
#else
// TODO: Implement this for systems without sendfile()
template<typename Handler, typename ErrorHandler>
void async_send_file(socket_ptr, const std::string&, Handler, ErrorHandler)
{
assert(false && "Not implemented yet");
}
#endif
template<typename Handler>
inline void async_send_doc(socket_ptr socket, simple_wml::document& doc, Handler handler)
{
async_send_doc(socket, doc, handler, null_handler);
}
inline void async_send_doc(socket_ptr socket, simple_wml::document& doc)
{
async_send_doc(socket, doc, null_handler, null_handler);
}
template<typename Handler, typename ErrorHandler>
struct handle_receive_doc : public handle_doc<Handler, ErrorHandler>
{
std::size_t buf_size;
handle_receive_doc(socket_ptr socket, Handler handler, ErrorHandler error_handler) :
handle_doc<Handler, ErrorHandler>(socket, handler, error_handler)
{
}
void operator()(const boost::system::error_code& error, std::size_t size)
{
if(check_error(error, this->socket)) {
this->error_handler(this->socket);
return;
}
if(!this->buffer) {
assert(size == 4);
buf_size = ntohl(this->data_size->size);
this->buffer = boost::shared_array<char>(new char[buf_size]);
async_read(*(this->socket), boost::asio::buffer(this->buffer.get(), buf_size), *this);
} else {
simple_wml::string_span compressed_buf(this->buffer.get(), buf_size);
try {
this->doc.reset(new simple_wml::document(compressed_buf));
} catch (simple_wml::error& e) {
ERR_SERVER <<
client_address(this->socket) <<
"\tsimple_wml error in received data: " << e.message << std::endl;
async_send_error(this->socket, "Invalid WML received: " + e.message);
this->error_handler(this->socket);
return;
}
this->handler(this->socket, this->doc);
}
}
};
template<typename Handler, typename ErrorHandler>
inline void async_receive_doc(socket_ptr socket, Handler handler, ErrorHandler error_handler)
{
handle_receive_doc<Handler, ErrorHandler> handle_receive_doc(socket, handler, error_handler);
async_read(*socket, boost::asio::buffer(handle_receive_doc.data_size->buf, 4), handle_receive_doc);
}
template<typename Handler>
inline void async_receive_doc(socket_ptr socket, Handler handler)
{
async_receive_doc(socket, handler, null_handler);
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -21,6 +21,7 @@
#include "ban.hpp"
#include "player.hpp"
#include "simple_wml.hpp"
#include "server_base.hpp"
#include "player_connection.hpp"
#include <boost/shared_array.hpp>
@ -30,25 +31,14 @@
namespace wesnothd
{
class server
class server : public server_base
{
public:
server(int port, bool keep_alive, const std::string& config_file, size_t min_threads,size_t max_threads);
void run();
server(int port, bool keep_alive, const std::string& config_file, size_t, size_t);
private:
boost::asio::io_service io_service_;
boost::asio::ip::tcp::acceptor acceptor_;
void serve();
void accept_connection(const boost::system::error_code& error, socket_ptr socket);
void handle_new_client(socket_ptr socket);
union {
uint32_t connection_num;
char buf[4];
} handshake_response_;
void serverside_handshake(socket_ptr socket);
void handle_handshake(const boost::system::error_code& error, socket_ptr socket, boost::shared_array<char> buf);
void request_version(const boost::system::error_code& error, socket_ptr socket);
void handle_version(socket_ptr socket);
void read_version(socket_ptr socket, std::shared_ptr<simple_wml::document> doc);
@ -56,6 +46,7 @@ private:
void handle_login(socket_ptr socket, std::shared_ptr<simple_wml::document> doc);
void send_password_request(socket_ptr socket, const std::string& msg,
const std::string& user, const char* error_code = "", bool force_confirmation = false);
bool accepting_connections() const { return !graceful_restart; }
void add_player(socket_ptr socket, const wesnothd::player&);
void read_from_player(socket_ptr socket);
@ -83,7 +74,7 @@ private:
struct connection_log {
connection_log(std::string _nick, std::string _ip, time_t _log_off) :
nick(_nick), ip(_ip), log_off(_log_off) {}
nick(_nick), ip(_ip), log_off(_log_off) {}
std::string nick, ip;
time_t log_off;
@ -98,7 +89,7 @@ private:
struct login_log {
login_log(std::string _ip, int _attempts, time_t _first_attempt) :
ip(_ip), attempts(_attempts), first_attempt(_first_attempt) {}
ip(_ip), attempts(_attempts), first_attempt(_first_attempt) {}
std::string ip;
int attempts;
time_t first_attempt;
@ -127,9 +118,6 @@ private:
}
/** server socket/fifo. */
#ifndef _WIN32
boost::asio::posix::stream_descriptor input_;
#endif
std::string input_path_;
const std::string config_file_;
@ -194,9 +182,7 @@ private:
void setup_fifo();
#ifndef _WIN32
void read_from_fifo();
void handle_read_from_fifo(const boost::system::error_code& error, std::size_t bytes_transferred);
boost::asio::streambuf admin_cmd_;
#endif
void setup_handlers();
@ -231,11 +217,8 @@ private:
void dul_handler(const std::string &, const std::string &, std::string &, std::ostringstream *);
#ifndef _WIN32
boost::asio::signal_set sighup_;
void handle_sighup(const boost::system::error_code& error, int signal_number);
#endif
boost::asio::signal_set sigs_;
void handle_termination(const boost::system::error_code& error, int signal_number);
boost::asio::deadline_timer timer_;
void handle_graceful_timeout(const boost::system::error_code& error);

206
src/server/server_base.cpp Normal file
View file

@ -0,0 +1,206 @@
/*
Copyright (C) 2016 by Sergey Popov <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License 2
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "server_base.hpp"
#include "log.hpp"
#include "util.hpp"
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
static lg::log_domain log_server("server");
#define ERR_SERVER LOG_STREAM(err, log_server)
#define WRN_SERVER LOG_STREAM(warn, log_server)
#define LOG_SERVER LOG_STREAM(info, log_server)
#define DBG_SERVER LOG_STREAM(debug, log_server)
static lg::log_domain log_config("config");
#define ERR_CONFIG LOG_STREAM(err, log_config)
#define WRN_CONFIG LOG_STREAM(warn, log_config)
#include "send_receive_wml_helpers.ipp"
server_base::server_base(unsigned short port, bool keep_alive) :
port_(port),
keep_alive_(keep_alive),
io_service_(),
acceptor_(io_service_),
#ifndef _WIN32
input_(io_service_),
sighup_(io_service_, SIGHUP),
#endif
sigs_(io_service_, SIGINT, SIGTERM)
{
}
void server_base::start_server()
{
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port_);
acceptor_.open(endpoint.protocol());
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
acceptor_.set_option(boost::asio::ip::tcp::acceptor::keep_alive(keep_alive_));
acceptor_.bind(endpoint);
acceptor_.listen();
serve();
handshake_response_.connection_num = 42;
#ifndef _WIN32
sighup_.async_wait(
[=](const boost::system::error_code& error, int sig)
{ this->handle_sighup(error, sig); });
#endif
sigs_.async_wait(boost::bind(&server_base::handle_termination, this, _1, _2));
}
void server_base::serve()
{
socket_ptr socket = std::make_shared<boost::asio::ip::tcp::socket>(boost::ref(io_service_));
acceptor_.async_accept(*socket, boost::bind(&server_base::accept_connection, this, _1, socket));
}
void server_base::accept_connection(const boost::system::error_code& error, socket_ptr socket)
{
if(accepting_connections())
serve();
if(error) {
ERR_SERVER << "Accept failed: " << error.message() << "\n";
return;
}
const std::string ip = client_address(socket);
const std::string reason = is_ip_banned(ip);
if (!reason.empty()) {
LOG_SERVER << ip << "\trejected banned user. Reason: " << reason << "\n";
async_send_error(socket, "You are banned. Reason: " + reason);
return;
/*} else if (ip_exceeds_connection_limit(ip)) {
LOG_SERVER << ip << "\trejected ip due to excessive connections\n";
async_send_error(socket, "Too many connections from your IP.");
return;*/
} else {
DBG_SERVER << ip << "\tnew connection accepted\n";
serverside_handshake(socket);
}
}
void server_base::serverside_handshake(socket_ptr socket)
{
boost::shared_array<char> handshake(new char[4]);
async_read(
*socket, boost::asio::buffer(handshake.get(), 4),
boost::bind(&server_base::handle_handshake, this, _1, socket, handshake)
);
}
void server_base::handle_handshake(const boost::system::error_code& error, socket_ptr socket, boost::shared_array<char> handshake)
{
if(check_error(error, socket))
return;
if(strcmp(handshake.get(), "\0\0\0\0") != 0) {
ERR_SERVER << client_address(socket) << "\tincorrect handshake\n";
return;
}
async_write(
*socket, boost::asio::buffer(handshake_response_.buf, 4),
[=](const boost::system::error_code& error, size_t)
{ if(!check_error(error, socket)) this->handle_new_client(socket); }
);
}
void server_base::read_from_fifo() {
async_read_until(input_,
admin_cmd_, '\n',
[=](const boost::system::error_code& error, std::size_t bytes_transferred)
{ this->handle_read_from_fifo(error, bytes_transferred); }
);
}
void server_base::handle_termination(const boost::system::error_code& error, int signal_number)
{
assert(!error);
std::string signame;
if(signal_number == SIGINT) signame = "SIGINT";
else if(signal_number == SIGTERM) signame = "SIGTERM";
else signame = lexical_cast<std::string>(signal_number);
LOG_SERVER << signame << " caught, exiting without cleanup immediately.\n";
exit(128 + signal_number);
}
void server_base::run() {
try {
io_service_.run();
LOG_SERVER << "Server has shut down because event loop is out of work\n";
} catch(const server_shutdown& e) {
LOG_SERVER << "Server has been shut down: " << e.what() << "\n";
}
}
std::string client_address(socket_ptr socket)
{
boost::system::error_code error;
std::string result = socket->remote_endpoint(error).address().to_string();
if(error)
return "<unknown address>";
else
return result;
}
bool check_error(const boost::system::error_code& error, socket_ptr socket)
{
if(error) {
if(error == boost::asio::error::eof)
LOG_SERVER << client_address(socket) << "\tconnection closed\n";
else
ERR_SERVER << client_address(socket) << "\t" << error.message() << "\n";
return true;
}
return false;
}
void async_send_error(socket_ptr socket, const std::string& msg, const char* error_code)
{
simple_wml::document doc;
doc.root().add_child("error").set_attr_dup("message", msg.c_str());
if(*error_code != '\0') {
doc.child("error")->set_attr("error_code", error_code);
}
async_send_doc(socket, doc);
}
void async_send_warning(socket_ptr socket, const std::string& msg, const char* warning_code)
{
simple_wml::document doc;
doc.root().add_child("warning").set_attr_dup("message", msg.c_str());
if(*warning_code != '\0') {
doc.child("warning")->set_attr("warning_code", warning_code);
}
async_send_doc(socket, doc);
}
void async_send_message(socket_ptr socket, const std::string& msg)
{
simple_wml::document doc;
doc.root().add_child("message").set_attr_dup("message", msg.c_str());
async_send_doc(socket, doc);
}

View file

@ -0,0 +1,85 @@
/*
Copyright (C) 2016 by Sergey Popov <dave@whitevine.net>
Part of the Battle for Wesnoth Project http://www.wesnoth.org
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License 2
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
/**
* @file
* Base class for servers using Wesnoth's WML over TCP protocol.
*/
#ifndef SERVER_BASE_HPP
#define SERVER_BASE_HPP
#include "exceptions.hpp"
#include <boost/asio.hpp>
#include <boost/asio/signal_set.hpp>
#include <boost/shared_array.hpp>
typedef std::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr;
struct server_shutdown : public game::error
{
server_shutdown(const std::string& msg) : game::error(msg) {}
};
class server_base
{
public:
server_base(unsigned short port, bool keep_alive);
virtual ~server_base() {}
void run();
protected:
unsigned short port_;
bool keep_alive_;
boost::asio::io_service io_service_;
boost::asio::ip::tcp::acceptor acceptor_;
void start_server();
void serve();
void accept_connection(const boost::system::error_code& error, socket_ptr socket);
union {
boost::uint32_t connection_num;
char buf[4];
} handshake_response_;
void serverside_handshake(socket_ptr socket);
void handle_handshake(const boost::system::error_code& error, socket_ptr socket, boost::shared_array<char> buf);
virtual void handle_new_client(socket_ptr socket) = 0;
virtual bool accepting_connections() const { return true; }
virtual std::string is_ip_banned(const std::string&) const { return std::string(); }
#ifndef _WIN32
boost::asio::posix::stream_descriptor input_;
std::string fifo_path_;
void read_from_fifo();
virtual void handle_read_from_fifo(const boost::system::error_code& error, std::size_t bytes_transferred) = 0;
boost::asio::streambuf admin_cmd_;
boost::asio::signal_set sighup_;
virtual void handle_sighup(const boost::system::error_code& error, int signal_number) = 0;
#endif
boost::asio::signal_set sigs_;
void handle_termination(const boost::system::error_code& error, int signal_number);
};
std::string client_address(socket_ptr socket);
bool check_error(const boost::system::error_code& error, socket_ptr socket);
void async_send_error(socket_ptr socket, const std::string& msg, const char* error_code = "");
void async_send_warning(socket_ptr socket, const std::string& msg, const char* warning_code = "");
void async_send_message(socket_ptr socket, const std::string& msg);
#endif // SERVER_BASE_HPP

View file

@ -25,6 +25,8 @@
#include <set>
#include <stdint.h>
class game_data;
class gamemap;
struct SDL_Color;
@ -355,9 +357,9 @@ public:
//function which, when given a 1-based side will return the color used by that side.
static const color_range get_side_color_range(int side);
static Uint32 get_side_rgb(int side) { return(get_side_color_range(side).mid()); }
static Uint32 get_side_rgb_max(int side) { return(get_side_color_range(side).max()); }
static Uint32 get_side_rgb_min(int side) { return(get_side_color_range(side).min()); }
static uint32_t get_side_rgb(int side) { return(get_side_color_range(side).mid()); }
static uint32_t get_side_rgb_max(int side) { return(get_side_color_range(side).max()); }
static uint32_t get_side_rgb_min(int side) { return(get_side_color_range(side).min()); }
static SDL_Color get_side_color(int side);
static SDL_Color get_minimap_color(int side);
static std::string get_side_color_index(int side);

View file

@ -42,7 +42,6 @@
#include "game_errors.hpp"
#include "gui/core/event/handler.hpp"
#include "gui/widgets/helper.hpp"
#include "network.hpp"
#include "config.hpp"
#include "log.hpp"
@ -57,13 +56,6 @@ static void exception_translator_config(const config::error& e)
throw "config:error: " + e.message;
}
static void exception_translator_network(const network::error& e)
{
throw "network::error: " + e.message;
}
static void exception_translator_game(const game::error& e)
{
throw "game::error: " + e.message;
@ -99,7 +91,6 @@ struct wesnoth_global_fixture {
if(runtime_config::get<report_level>(runtime_config::REPORT_LEVEL) == INV_REPORT_LEVEL)
results_reporter::set_level(SHORT_REPORT);
unit_test_monitor.register_exception_translator<game::error>(&exception_translator_game);
unit_test_monitor.register_exception_translator<network::error>(&exception_translator_network);
unit_test_monitor.register_exception_translator<config::error>(&exception_translator_config);
#else
if(runtime_config::log_level() == invalid_log_level)
@ -107,7 +98,6 @@ struct wesnoth_global_fixture {
if(runtime_config::report_level() == INV_REPORT_LEVEL)
results_reporter::set_level(SHORT_REPORT);
unit_test_monitor.register_exception_translator<game::error>(&exception_translator_game);
unit_test_monitor.register_exception_translator<network::error>(&exception_translator_network);
unit_test_monitor.register_exception_translator<config::error>(&exception_translator_config);
#endif
}