Merge branch 'campaignd_asio'
This commit is contained in:
commit
c16adcd8c9
22 changed files with 1380 additions and 3733 deletions
13
SConstruct
13
SConstruct
|
@ -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', [])))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = (
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
1208
src/network.cpp
1208
src/network.cpp
File diff suppressed because it is too large
Load diff
310
src/network.hpp
310
src/network.hpp
|
@ -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
|
@ -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
|
|
@ -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
|
||||
|
|
235
src/server/send_receive_wml_helpers.ipp
Normal file
235
src/server/send_receive_wml_helpers.ipp
Normal 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
|
@ -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
206
src/server/server_base.cpp
Normal 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);
|
||||
}
|
85
src/server/server_base.hpp
Normal file
85
src/server/server_base.hpp
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue