mirror of
https://github.com/Relintai/rcpp_fw_static.git
synced 2025-05-10 22:32:08 +02:00
Initial commit. Added the current rcpp_cms as a base.
This commit is contained in:
commit
54df3653a8
128
.clang-format
Normal file
128
.clang-format
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
# Commented out parameters are those with the same value as base LLVM style
|
||||||
|
# We can uncomment them if we want to change their value, or enforce the
|
||||||
|
# chosen value in case the base style changes (last sync: Clang 6.0.1).
|
||||||
|
---
|
||||||
|
### General config, applies to all languages ###
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: DontAlign
|
||||||
|
# AlignConsecutiveAssignments: false
|
||||||
|
# AlignConsecutiveDeclarations: false
|
||||||
|
# AlignEscapedNewlines: Right
|
||||||
|
# AlignOperands: true
|
||||||
|
AlignTrailingComments: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
# AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: Inline
|
||||||
|
AllowShortIfStatementsOnASingleLine: true
|
||||||
|
# AllowShortLoopsOnASingleLine: false
|
||||||
|
# AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
# AlwaysBreakAfterReturnType: None
|
||||||
|
# AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
# AlwaysBreakTemplateDeclarations: false
|
||||||
|
# BinPackArguments: true
|
||||||
|
# BinPackParameters: true
|
||||||
|
# BraceWrapping:
|
||||||
|
# AfterClass: false
|
||||||
|
# AfterControlStatement: false
|
||||||
|
# AfterEnum: false
|
||||||
|
# AfterFunction: false
|
||||||
|
# AfterNamespace: false
|
||||||
|
# AfterObjCDeclaration: false
|
||||||
|
# AfterStruct: false
|
||||||
|
# AfterUnion: false
|
||||||
|
# AfterExternBlock: false
|
||||||
|
# BeforeCatch: false
|
||||||
|
# BeforeElse: false
|
||||||
|
# IndentBraces: false
|
||||||
|
# SplitEmptyFunction: true
|
||||||
|
# SplitEmptyRecord: true
|
||||||
|
# SplitEmptyNamespace: true
|
||||||
|
# BreakBeforeBinaryOperators: None
|
||||||
|
# BreakBeforeBraces: Attach
|
||||||
|
# BreakBeforeInheritanceComma: false
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
# BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: AfterColon
|
||||||
|
# BreakStringLiterals: true
|
||||||
|
ColumnLimit: 0
|
||||||
|
# CommentPragmas: '^ IWYU pragma:'
|
||||||
|
# CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||||
|
ConstructorInitializerIndentWidth: 8
|
||||||
|
ContinuationIndentWidth: 8
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
# DerivePointerAlignment: false
|
||||||
|
# DisableFormat: false
|
||||||
|
# ExperimentalAutoDetectBinPacking: false
|
||||||
|
# FixNamespaceComments: true
|
||||||
|
# ForEachMacros:
|
||||||
|
# - foreach
|
||||||
|
# - Q_FOREACH
|
||||||
|
# - BOOST_FOREACH
|
||||||
|
# IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '".*"'
|
||||||
|
Priority: 1
|
||||||
|
- Regex: '^<.*\.h>'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '^<.*'
|
||||||
|
Priority: 3
|
||||||
|
# IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IndentCaseLabels: true
|
||||||
|
# IndentPPDirectives: None
|
||||||
|
IndentWidth: 4
|
||||||
|
# IndentWrappedFunctionNames: false
|
||||||
|
# JavaScriptQuotes: Leave
|
||||||
|
# JavaScriptWrapImports: true
|
||||||
|
# KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
# MacroBlockBegin: ''
|
||||||
|
# MacroBlockEnd: ''
|
||||||
|
# MaxEmptyLinesToKeep: 1
|
||||||
|
# NamespaceIndentation: None
|
||||||
|
# PenaltyBreakAssignment: 2
|
||||||
|
# PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
# PenaltyBreakComment: 300
|
||||||
|
# PenaltyBreakFirstLessLess: 120
|
||||||
|
# PenaltyBreakString: 1000
|
||||||
|
# PenaltyExcessCharacter: 1000000
|
||||||
|
# PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
# PointerAlignment: Right
|
||||||
|
# RawStringFormats:
|
||||||
|
# - Delimiter: pb
|
||||||
|
# Language: TextProto
|
||||||
|
# BasedOnStyle: google
|
||||||
|
# ReflowComments: true
|
||||||
|
# SortIncludes: true
|
||||||
|
# SortUsingDeclarations: true
|
||||||
|
# SpaceAfterCStyleCast: false
|
||||||
|
# SpaceAfterTemplateKeyword: true
|
||||||
|
# SpaceBeforeAssignmentOperators: true
|
||||||
|
# SpaceBeforeParens: ControlStatements
|
||||||
|
# SpaceInEmptyParentheses: false
|
||||||
|
# SpacesBeforeTrailingComments: 1
|
||||||
|
# SpacesInAngles: false
|
||||||
|
# SpacesInContainerLiterals: true
|
||||||
|
# SpacesInCStyleCastParentheses: false
|
||||||
|
# SpacesInParentheses: false
|
||||||
|
# SpacesInSquareBrackets: false
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Always
|
||||||
|
---
|
||||||
|
### C++ specific config ###
|
||||||
|
Language: Cpp
|
||||||
|
Standard: Cpp03
|
||||||
|
---
|
||||||
|
### ObjC specific config ###
|
||||||
|
Language: ObjC
|
||||||
|
Standard: Cpp03
|
||||||
|
ObjCBlockIndentWidth: 4
|
||||||
|
# ObjCSpaceAfterProperty: false
|
||||||
|
# ObjCSpaceBeforeProtocolList: true
|
||||||
|
---
|
||||||
|
### Java specific config ###
|
||||||
|
Language: Java
|
||||||
|
# BreakAfterJavaFieldAnnotations: false
|
||||||
|
JavaImportGroups: ['org.godotengine', 'android', 'androidx', 'com.android', 'com.google', 'java', 'javax']
|
||||||
|
...
|
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
bin/**
|
||||||
|
*.dblite
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
settings.json
|
19
LICENSE
Normal file
19
LICENSE
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2020 Péter Magyar
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
14
Readme.md
Normal file
14
Readme.md
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# rcpp_cms
|
||||||
|
|
||||||
|
This is an experimental project, to implement a html framework in c++, because I'm dissatisfied with
|
||||||
|
every single framework that I've seen or used so far.
|
||||||
|
|
||||||
|
Developing websites nowadays feels more like creating a bunch of oneliner files all over the place,
|
||||||
|
which I find incredibly annoying and distracting. Not only that I'm also dissatisfied with the way most
|
||||||
|
ORMs are built, they always come off as strange to use, especially with joins. At this point I'm so fed up,
|
||||||
|
I'd rather use raw SQl. And let's not forget about auth, I have to think about implementing auth way too
|
||||||
|
much. Every single time.
|
||||||
|
|
||||||
|
I think things can be done better. At lest from my perspective.
|
||||||
|
|
||||||
|
Whether this stupid and moronic attempt will end up working or not, we'll see.
|
198
SConstruct
Normal file
198
SConstruct
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
EnsureSConsVersion(0, 98, 1)
|
||||||
|
|
||||||
|
# System
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import pickle
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
from collections import OrderedDict
|
||||||
|
#from compat import iteritems, isbasestring, open_utf8, decode_utf8, qualname
|
||||||
|
|
||||||
|
from SCons import Node
|
||||||
|
from SCons.Script import Glob
|
||||||
|
|
||||||
|
def isbasestring(s):
|
||||||
|
return isinstance(s, (str, bytes))
|
||||||
|
|
||||||
|
def add_source_files(self, sources, files, warn_duplicates=True):
|
||||||
|
# Convert string to list of absolute paths (including expanding wildcard)
|
||||||
|
if isbasestring(files):
|
||||||
|
# Keep SCons project-absolute path as they are (no wildcard support)
|
||||||
|
if files.startswith("#"):
|
||||||
|
if "*" in files:
|
||||||
|
print("ERROR: Wildcards can't be expanded in SCons project-absolute path: '{}'".format(files))
|
||||||
|
return
|
||||||
|
files = [files]
|
||||||
|
else:
|
||||||
|
dir_path = self.Dir(".").abspath
|
||||||
|
files = sorted(glob.glob(dir_path + "/" + files))
|
||||||
|
|
||||||
|
# Add each path as compiled Object following environment (self) configuration
|
||||||
|
for path in files:
|
||||||
|
obj = self.Object(path)
|
||||||
|
if obj in sources:
|
||||||
|
if warn_duplicates:
|
||||||
|
print('WARNING: Object "{}" already included in environment sources.'.format(obj))
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
sources.append(obj)
|
||||||
|
|
||||||
|
def add_library(env, name, sources, **args):
|
||||||
|
library = env.Library(name, sources, **args)
|
||||||
|
env.NoCache(library)
|
||||||
|
return library
|
||||||
|
|
||||||
|
def add_program(env, name, sources, **args):
|
||||||
|
program = env.Program(name, sources, **args)
|
||||||
|
env.NoCache(program)
|
||||||
|
return program
|
||||||
|
|
||||||
|
env_base = Environment()
|
||||||
|
|
||||||
|
env_base.__class__.add_source_files = add_source_files
|
||||||
|
env_base.__class__.add_library = add_library
|
||||||
|
env_base.__class__.add_program = add_program
|
||||||
|
|
||||||
|
if "TERM" in os.environ:
|
||||||
|
env_base["ENV"]["TERM"] = os.environ["TERM"]
|
||||||
|
|
||||||
|
env_base.AppendENVPath("PATH", os.getenv("PATH"))
|
||||||
|
env_base.AppendENVPath("PKG_CONFIG_PATH", os.getenv("PKG_CONFIG_PATH"))
|
||||||
|
env_base.disabled_modules = []
|
||||||
|
env_base.use_ptrcall = False
|
||||||
|
env_base.module_version_string = ""
|
||||||
|
env_base.msvc = False
|
||||||
|
|
||||||
|
# avoid issues when building with different versions of python out of the same directory
|
||||||
|
env_base.SConsignFile(".sconsign{0}.dblite".format(pickle.HIGHEST_PROTOCOL))
|
||||||
|
|
||||||
|
database_list = []
|
||||||
|
|
||||||
|
for x in sorted(glob.glob("database/*")):
|
||||||
|
if not os.path.isdir(x) or not os.path.exists(x + "/detect.py"):
|
||||||
|
continue
|
||||||
|
tmppath = "./" + x
|
||||||
|
|
||||||
|
sys.path.insert(0, tmppath)
|
||||||
|
import detect
|
||||||
|
|
||||||
|
if detect.is_active() and detect.can_build():
|
||||||
|
x = x.replace("database/", "") # rest of world
|
||||||
|
x = x.replace("database\\", "") # win32
|
||||||
|
database_list += [x]
|
||||||
|
|
||||||
|
sys.path.remove(tmppath)
|
||||||
|
sys.modules.pop("detect")
|
||||||
|
|
||||||
|
module_list = []
|
||||||
|
|
||||||
|
for x in sorted(glob.glob("modules/*")):
|
||||||
|
if not os.path.isdir(x) or not os.path.exists(x + "/detect.py"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
tmppath = "./" + x
|
||||||
|
|
||||||
|
sys.path.insert(0, tmppath)
|
||||||
|
import detect
|
||||||
|
|
||||||
|
if detect.is_active() and detect.can_build():
|
||||||
|
x = x.replace("modules/", "") # rest of world
|
||||||
|
x = x.replace("modules\\", "") # win32
|
||||||
|
module_list += [x]
|
||||||
|
|
||||||
|
sys.path.remove(tmppath)
|
||||||
|
sys.modules.pop("detect")
|
||||||
|
|
||||||
|
|
||||||
|
# Build options
|
||||||
|
|
||||||
|
opts = Variables([], ARGUMENTS)
|
||||||
|
|
||||||
|
opts.Add(EnumVariable("target", "Compilation target", "debug", ("debug", "release_debug", "release")))
|
||||||
|
|
||||||
|
# Compilation environment setup
|
||||||
|
opts.Add("CXX", "C++ compiler")
|
||||||
|
opts.Add("CC", "C compiler")
|
||||||
|
opts.Add("LINK", "Linker")
|
||||||
|
opts.Add("CCFLAGS", "Custom flags for both the C and C++ compilers")
|
||||||
|
opts.Add("CFLAGS", "Custom flags for the C compiler")
|
||||||
|
opts.Add("CXXFLAGS", "Custom flags for the C++ compiler")
|
||||||
|
opts.Add("LINKFLAGS", "Custom flags for the linker")
|
||||||
|
|
||||||
|
# add default include paths
|
||||||
|
env_base.Prepend(CPPPATH=["#", "libs"])
|
||||||
|
env_base.Prepend(CPPPATH=["#libs"])
|
||||||
|
env_base.Prepend(LINKFLAGS=["-lpthread"])
|
||||||
|
|
||||||
|
env_base.Append(CXX=["-o3"])
|
||||||
|
#env_base.Append(CXX=["-g2"])
|
||||||
|
|
||||||
|
env = env_base.Clone()
|
||||||
|
Export("env")
|
||||||
|
SConscript("core/SCsub")
|
||||||
|
|
||||||
|
for d in database_list:
|
||||||
|
tmppath = "./database/" + d
|
||||||
|
sys.path.insert(0, tmppath)
|
||||||
|
|
||||||
|
import detect
|
||||||
|
|
||||||
|
env_db = env_base.Clone()
|
||||||
|
|
||||||
|
# Compilation DB requires SCons 3.1.1+.
|
||||||
|
from SCons import __version__ as scons_raw_version
|
||||||
|
|
||||||
|
scons_ver = env_db._get_major_minor_revision(scons_raw_version)
|
||||||
|
|
||||||
|
if scons_ver >= (4, 0, 0):
|
||||||
|
env_db.Tool("compilation_db")
|
||||||
|
env_db.Alias("compiledb", env.CompilationDatabase())
|
||||||
|
|
||||||
|
detect.configure(env_db)
|
||||||
|
detect.configure(env)
|
||||||
|
|
||||||
|
Export("env_db")
|
||||||
|
|
||||||
|
SConscript("database/" + d + "/SCsub")
|
||||||
|
|
||||||
|
sys.path.remove(tmppath)
|
||||||
|
sys.modules.pop("detect")
|
||||||
|
|
||||||
|
for m in module_list:
|
||||||
|
tmppath = "./modules/" + m
|
||||||
|
sys.path.insert(0, tmppath)
|
||||||
|
|
||||||
|
import detect
|
||||||
|
|
||||||
|
env_mod = env_base.Clone()
|
||||||
|
|
||||||
|
# Compilation DB requires SCons 3.1.1+.
|
||||||
|
from SCons import __version__ as scons_raw_version
|
||||||
|
|
||||||
|
scons_ver = env_mod._get_major_minor_revision(scons_raw_version)
|
||||||
|
|
||||||
|
if scons_ver >= (4, 0, 0):
|
||||||
|
env_mod.Tool("compilation_db")
|
||||||
|
env_mod.Alias("compiledb", env.CompilationDatabase())
|
||||||
|
|
||||||
|
detect.configure(env_mod)
|
||||||
|
detect.configure(env)
|
||||||
|
|
||||||
|
Export("env_mod")
|
||||||
|
|
||||||
|
SConscript("modules/" + m + "/SCsub")
|
||||||
|
|
||||||
|
sys.path.remove(tmppath)
|
||||||
|
sys.modules.pop("detect")
|
||||||
|
|
||||||
|
env.prg_sources = [ "rdn_application.cpp" ]
|
||||||
|
libapp = env.add_library("application", env.prg_sources)
|
||||||
|
env.Prepend(LIBS=[libapp])
|
||||||
|
|
||||||
|
prog = env.add_program("#bin/server", ["main.cpp"])
|
||||||
|
|
6
compile_linux.sh
Executable file
6
compile_linux.sh
Executable file
@ -0,0 +1,6 @@
|
|||||||
|
g++ -o3 -g main.cpp ./core/settings.cpp ./core/request.cpp ./core/http_server.cpp ./core/file_cache.cpp ./core/application.cpp ./rdn_application.cpp \
|
||||||
|
./core/theme.cpp \
|
||||||
|
-o ./bin/server -Ilibs -lpthread -std=c++11
|
||||||
|
|
||||||
|
|
||||||
|
|
14
compile_vs.bat
Normal file
14
compile_vs.bat
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
if not defined DevEnvDir (
|
||||||
|
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" amd64
|
||||||
|
)
|
||||||
|
|
||||||
|
rem debug: /Zi (== -g)
|
||||||
|
|
||||||
|
cl main.cpp ./core/settings.cpp ./core/request.cpp ./core/http_server.cpp ./core/file_cache.cpp ./core/application.cpp ./rdn_application.cpp ./core/theme.cpp ^
|
||||||
|
/Febin/game-vc.exe ^
|
||||||
|
/EHsc /std:c++17 ^
|
||||||
|
/Ilibs ^
|
||||||
|
/link WSock32.lib Ws2_32.lib
|
||||||
|
|
4
compile_win.bat
Normal file
4
compile_win.bat
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
g++ -o3 -g main.cpp ./core/settings.cpp ./core/request.cpp ./core/http_server.cpp ./core/file_cache.cpp ./core/application.cpp ./rdn_application.cpp ./core/theme.cpp -o ./bin/server.exe -Ilibs -lWsock32 -lWs2_32 -lpthread -std=c++14
|
||||||
|
|
||||||
|
|
||||||
|
|
11
core/SCsub
Normal file
11
core/SCsub
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
Import("env")
|
||||||
|
|
||||||
|
env.core_sources = []
|
||||||
|
|
||||||
|
env.add_source_files(env.core_sources, "*.cpp")
|
||||||
|
|
||||||
|
# Build it all as a library
|
||||||
|
lib = env.add_library("core", env.core_sources)
|
||||||
|
env.Prepend(LIBS=[lib])
|
153
core/application.cpp
Normal file
153
core/application.cpp
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
#include "application.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "request.h"
|
||||||
|
|
||||||
|
#include "file_cache.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void Application::load_settings() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::setup_routes() {
|
||||||
|
default_error_handler_func = Application::default_fallback_error_handler;
|
||||||
|
|
||||||
|
error_handler_map[404] = Application::default_404_error_handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::setup_middleware() {
|
||||||
|
middlewares.push_back(HandlerInstance(Application::default_routing_middleware));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::default_routing_middleware(Object *instance, Request *request) {
|
||||||
|
std::string path = request->http_parser->getPath();
|
||||||
|
|
||||||
|
if (FileCache::get_singleton()->wwwroot_has_file(path)) {
|
||||||
|
send_file(path, request);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerInstance handler_data;
|
||||||
|
|
||||||
|
//std::function<void(Object *, Request *)> func;
|
||||||
|
|
||||||
|
if (path == "/") {
|
||||||
|
//quick shortcut
|
||||||
|
handler_data = index_func;
|
||||||
|
} else {
|
||||||
|
std::string main_route = "";
|
||||||
|
|
||||||
|
uint32_t endpos = 1;
|
||||||
|
for (; endpos < path.size(); ++endpos) {
|
||||||
|
if (path[endpos] == '/') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
main_route = path.substr(1, endpos - 1);
|
||||||
|
|
||||||
|
handler_data = main_route_map[main_route];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handler_data.handler_func) {
|
||||||
|
send_error(404, request);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
request->handler_instance = handler_data;
|
||||||
|
request->next_stage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::default_fallback_error_handler(int error_code, Request *request) {
|
||||||
|
request->response->setBody(default_generic_error_body);
|
||||||
|
request->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::default_404_error_handler(int error_code, Request *request) {
|
||||||
|
request->response->setBody(default_error_404_body);
|
||||||
|
request->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::handle_request(Request *request) {
|
||||||
|
request->middleware_stack = &middlewares;
|
||||||
|
|
||||||
|
//note that middlewares handle the routing -> Application::default_routing_middleware by default
|
||||||
|
request->next_stage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::send_error(int error_code, Request *request) {
|
||||||
|
std::function<void(int, Request *)> func = error_handler_map[error_code];
|
||||||
|
|
||||||
|
if (!func) {
|
||||||
|
default_error_handler_func(error_code, request);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
func(error_code, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::send_file(const std::string &path, Request *request) {
|
||||||
|
std::string fp = FileCache::get_singleton()->wwwroot + path;
|
||||||
|
|
||||||
|
FILE *f = fopen(fp.c_str(), "rb");
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
printf("Error: Registered file doesn't exists anymore! %s\n", path.c_str());
|
||||||
|
|
||||||
|
send_error(404, request);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long fsize = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
|
||||||
|
|
||||||
|
std::string body;
|
||||||
|
body.resize(fsize);
|
||||||
|
|
||||||
|
fread(&body[0], 1, fsize, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
//TODO set mimetype?
|
||||||
|
|
||||||
|
request->response->setBody(body);
|
||||||
|
request->send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::migrate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::Application() {
|
||||||
|
_instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Application::~Application() {
|
||||||
|
main_route_map.clear();
|
||||||
|
error_handler_map.clear();
|
||||||
|
middlewares.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
Application *Application::get_instance() {
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerInstance Application::index_func;
|
||||||
|
std::map<std::string, HandlerInstance> Application::main_route_map;
|
||||||
|
std::vector<HandlerInstance> Application::middlewares;
|
||||||
|
|
||||||
|
std::map<int, std::function<void(int, Request *)> > Application::error_handler_map;
|
||||||
|
std::function<void(int, Request *)> Application::default_error_handler_func = nullptr;
|
||||||
|
|
||||||
|
Application *Application::_instance = nullptr;
|
||||||
|
|
||||||
|
std::string Application::default_error_404_body = "<html><body>404 :(</body></html>";
|
||||||
|
std::string Application::default_generic_error_body = "<html><body>Internal server error! :(</body></html>";
|
51
core/application.h
Normal file
51
core/application.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef APPLICATION_H
|
||||||
|
#define APPLICATION_H
|
||||||
|
|
||||||
|
#include "object.h"
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "handler_instance.h"
|
||||||
|
|
||||||
|
class Request;
|
||||||
|
|
||||||
|
class Application {
|
||||||
|
public:
|
||||||
|
static std::string default_error_404_body;
|
||||||
|
static std::string default_generic_error_body;
|
||||||
|
|
||||||
|
static void handle_request(Request *request);
|
||||||
|
static void send_error(int error_code, Request *request);
|
||||||
|
static void send_file(const std::string &path, Request *request);
|
||||||
|
|
||||||
|
static void default_fallback_error_handler(int error_code, Request *request);
|
||||||
|
static void default_404_error_handler(int error_code, Request *request);
|
||||||
|
|
||||||
|
virtual void load_settings();
|
||||||
|
virtual void setup_routes();
|
||||||
|
virtual void setup_middleware();
|
||||||
|
|
||||||
|
static void default_routing_middleware(Object *instance, Request *request);
|
||||||
|
|
||||||
|
virtual void migrate();
|
||||||
|
|
||||||
|
Application();
|
||||||
|
virtual ~Application();
|
||||||
|
|
||||||
|
static Application *get_instance();
|
||||||
|
|
||||||
|
public:
|
||||||
|
static HandlerInstance index_func;
|
||||||
|
static std::map<std::string, HandlerInstance> main_route_map;
|
||||||
|
static std::vector<HandlerInstance> middlewares;
|
||||||
|
|
||||||
|
static std::map<int, std::function<void(int, Request *)> > error_handler_map;
|
||||||
|
static std::function<void(int, Request *)> default_error_handler_func;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static Application *_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
28
core/database.cpp
Normal file
28
core/database.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include "database.h"
|
||||||
|
|
||||||
|
#include "query_builder.h"
|
||||||
|
#include "table_builder.h"
|
||||||
|
#include "query_result.h"
|
||||||
|
|
||||||
|
void Database::connect(const std::string &connection_str) {
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryResult *Database::query(const std::string &query) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void Database::query_run(const std::string &query) {
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder *Database::get_query_builder() {
|
||||||
|
return new QueryBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *Database::get_table_builder() {
|
||||||
|
return new TableBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
Database::Database() {
|
||||||
|
}
|
||||||
|
|
||||||
|
Database::~Database() {
|
||||||
|
}
|
45
core/database.h
Normal file
45
core/database.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
#ifndef DATABASE_H
|
||||||
|
#define DATABASE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
enum QueryErrorCode {
|
||||||
|
OK,
|
||||||
|
ERROR
|
||||||
|
};
|
||||||
|
|
||||||
|
class QueryBuilder;
|
||||||
|
class TableBuilder;
|
||||||
|
class QueryResult;
|
||||||
|
|
||||||
|
class Database {
|
||||||
|
public:
|
||||||
|
//probably needs refcount, depending on what db engines do, todo
|
||||||
|
//virtual QueryResult *query(const std::string &sql);
|
||||||
|
//virtual QueryResult *query_async(const std::string &sql);
|
||||||
|
//or
|
||||||
|
//virtual QueryErrorCode query(QueryResult *result, const std::string &sql);
|
||||||
|
//virtual QueryErrorCode query_async(QueryResult *result, const std::string &sql);
|
||||||
|
|
||||||
|
//also
|
||||||
|
//virtual QueryResult *query_prepared(const std::string &sql, param1, param2, ...);
|
||||||
|
|
||||||
|
//query interface (codeigniter 3 style)
|
||||||
|
//virtual void where(""); etc
|
||||||
|
|
||||||
|
virtual void connect(const std::string &connection_str);
|
||||||
|
virtual QueryResult *query(const std::string &query);
|
||||||
|
virtual void query_run(const std::string &query);
|
||||||
|
|
||||||
|
virtual QueryBuilder *get_query_builder();
|
||||||
|
virtual TableBuilder *get_table_builder();
|
||||||
|
|
||||||
|
Database();
|
||||||
|
~Database();
|
||||||
|
|
||||||
|
private:
|
||||||
|
//std::vector<QueryBuilder *> _builders;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
68
core/database_manager.cpp
Normal file
68
core/database_manager.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
#include "database_manager.h"
|
||||||
|
|
||||||
|
void DatabaseManager::load() {
|
||||||
|
//go thourgh settings, and create all the defined db backends
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DatabaseManager::create_database(const std::string &name) {
|
||||||
|
Database *db = _create_database(name);
|
||||||
|
|
||||||
|
if (!db) {
|
||||||
|
printf("create_database: %s, returned db is null!", name.c_str());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
databases.push_back(db);
|
||||||
|
|
||||||
|
return databases.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseManager *DatabaseManager::get_singleton() {
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseManager::_register_db_creation_func(const std::string &name, std::function<Database *()> func) {
|
||||||
|
if (!func) {
|
||||||
|
printf("_register_db_creation_func: %s, func is wrong!", name.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_db_creation_func_map[name] = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DatabaseManager::_unregister_db_creation_func(const std::string &name) {
|
||||||
|
_db_creation_func_map.erase(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Database *DatabaseManager::_create_database(const std::string &name) {
|
||||||
|
std::function<Database *()> func = _db_creation_func_map[name];
|
||||||
|
|
||||||
|
if (!func) {
|
||||||
|
printf("_create_database: %s, func is wrong!", name.c_str());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Database *db = func();
|
||||||
|
|
||||||
|
if (!db) {
|
||||||
|
printf("_create_database: %s, returned db is null!", name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseManager::DatabaseManager() {
|
||||||
|
_instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseManager::~DatabaseManager() {
|
||||||
|
_instance = nullptr;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < databases.size(); ++i) {
|
||||||
|
delete databases[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DatabaseManager *DatabaseManager::_instance = nullptr;
|
||||||
|
|
||||||
|
std::map<std::string, std::function<Database *()> > DatabaseManager::_db_creation_func_map;
|
35
core/database_manager.h
Normal file
35
core/database_manager.h
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#ifndef DATABASE_MANAGER_H
|
||||||
|
#define DATABASE_MANAGER_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
#include "database.h"
|
||||||
|
|
||||||
|
class DatabaseManager {
|
||||||
|
public:
|
||||||
|
std::vector<Database *> databases;
|
||||||
|
|
||||||
|
void load();
|
||||||
|
|
||||||
|
static DatabaseManager *get_singleton();
|
||||||
|
|
||||||
|
//note: not threadsafe, create these at the start of your program!
|
||||||
|
uint32_t create_database(const std::string &name);
|
||||||
|
|
||||||
|
static void _register_db_creation_func(const std::string &name, std::function<Database*()> func);
|
||||||
|
static void _unregister_db_creation_func(const std::string &name);
|
||||||
|
|
||||||
|
static Database *_create_database(const std::string &name);
|
||||||
|
|
||||||
|
DatabaseManager();
|
||||||
|
~DatabaseManager();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static DatabaseManager * _instance;
|
||||||
|
|
||||||
|
static std::map<std::string, std::function<Database *()> > _db_creation_func_map;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
124
core/file_cache.cpp
Normal file
124
core/file_cache.cpp
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
#include "file_cache.h"
|
||||||
|
|
||||||
|
#include <tinydir/tinydir.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
void FileCache::wwwroot_register_file(const std::string &file_path) {
|
||||||
|
registered_files.insert(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileCache::wwwroot_deregister_file(const std::string &file_path) {
|
||||||
|
registered_files.erase(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileCache::wwwroot_has_file(const std::string &file_path) {
|
||||||
|
return registered_files.find(file_path) != registered_files.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileCache::wwwroot_refresh_cache() {
|
||||||
|
registered_files.clear();
|
||||||
|
|
||||||
|
wwwroot_evaluate_dir(wwwroot.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileCache::wwwroot_evaluate_dir(const char *path) {
|
||||||
|
tinydir_dir dir;
|
||||||
|
if (tinydir_open(&dir, path) == -1) {
|
||||||
|
printf("Error opening wwwroot!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (dir.has_next) {
|
||||||
|
tinydir_file file;
|
||||||
|
if (tinydir_readfile(&dir, &file) == -1) {
|
||||||
|
tinydir_next(&dir);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.is_dir) {
|
||||||
|
std::string np = file.path;
|
||||||
|
np = np.substr(wwwroot.size(), np.size() - wwwroot.size());
|
||||||
|
|
||||||
|
registered_files.insert(np);
|
||||||
|
} else {
|
||||||
|
if (file.name[0] == '.' && file.name[1] == '\0' || file.name[0] == '.' && file.name[1] == '.') {
|
||||||
|
tinydir_next(&dir);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
wwwroot_evaluate_dir(file.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
tinydir_next(&dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
tinydir_close(&dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileCache::get_cached_body(const std::string &path, std::string *body) {
|
||||||
|
//TODO ERROR MACRO body == null
|
||||||
|
|
||||||
|
//this shouldn't need mutexes
|
||||||
|
|
||||||
|
CacheEntry *e = cache_map[path];
|
||||||
|
|
||||||
|
if (!e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t current_timestamp = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||||
|
|
||||||
|
int64_t diff = current_timestamp - e->timestamp;
|
||||||
|
|
||||||
|
if (diff > cache_invalidation_time) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
body->append(e->body);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileCache::set_cached_body(const std::string &path, const std::string &body) {
|
||||||
|
cache_mutex.lock();
|
||||||
|
|
||||||
|
CacheEntry *e = cache_map[path];
|
||||||
|
|
||||||
|
if (!e) {
|
||||||
|
e = new CacheEntry();
|
||||||
|
cache_map[path] = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t current_timestamp = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||||
|
|
||||||
|
e->timestamp = current_timestamp;
|
||||||
|
e->body = body;
|
||||||
|
|
||||||
|
cache_mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileCache::FileCache(bool singleton) {
|
||||||
|
if (singleton) {
|
||||||
|
if (_instance) {
|
||||||
|
printf("FileCache: Filecache instance is set as singleton, but an another FileCache instance is already set up as singleton! Ignoring setting!\n");
|
||||||
|
} else {
|
||||||
|
_instance = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_invalidation_time = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileCache::~FileCache() {
|
||||||
|
registered_files.clear();
|
||||||
|
|
||||||
|
if (_instance == this)
|
||||||
|
_instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileCache *FileCache::get_singleton() {
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileCache *FileCache::_instance = nullptr;
|
52
core/file_cache.h
Normal file
52
core/file_cache.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#ifndef FILE_CACHE_H
|
||||||
|
#define FILE_CACHE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
#include <chrono>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
class FileCache {
|
||||||
|
public:
|
||||||
|
std::string wwwroot;
|
||||||
|
int cache_invalidation_time;
|
||||||
|
|
||||||
|
//Note: file path should be the url you want to access the file with, inculding lead slash
|
||||||
|
//e.g. http://127.0.0.1/a/b/d.jpg -> /a/b/d.jpg
|
||||||
|
void wwwroot_register_file(const std::string &file_path);
|
||||||
|
void wwwroot_deregister_file(const std::string &file_path);
|
||||||
|
bool wwwroot_has_file(const std::string &file_path);
|
||||||
|
void wwwroot_refresh_cache();
|
||||||
|
void wwwroot_evaluate_dir(const char *path);
|
||||||
|
|
||||||
|
bool get_cached_body(const std::string &path, std::string *body);
|
||||||
|
void set_cached_body(const std::string &path, const std::string &body);
|
||||||
|
|
||||||
|
FileCache(bool singleton = false);
|
||||||
|
virtual ~FileCache();
|
||||||
|
|
||||||
|
static FileCache *get_singleton();
|
||||||
|
|
||||||
|
std::set<std::string> registered_files;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
struct CacheEntry {
|
||||||
|
int64_t timestamp;
|
||||||
|
std::string body;
|
||||||
|
|
||||||
|
CacheEntry() {
|
||||||
|
timestamp = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::mutex cache_mutex;
|
||||||
|
|
||||||
|
std::map<std::string, CacheEntry *> cache_map;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static FileCache *_instance;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
1
core/form_validator.cpp
Normal file
1
core/form_validator.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "form_validator.h"
|
51
core/form_validator.h
Normal file
51
core/form_validator.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef FORM_H
|
||||||
|
#define FORM_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Request;
|
||||||
|
|
||||||
|
//This might be converted to a form validator
|
||||||
|
|
||||||
|
class FormField {
|
||||||
|
public:
|
||||||
|
std::string name;
|
||||||
|
std::string label;
|
||||||
|
std::map<std::string, std::string> attribues;
|
||||||
|
|
||||||
|
virtual std::string render();
|
||||||
|
|
||||||
|
virtual bool validate(Request *request, std::vector<std::string> *errors);
|
||||||
|
|
||||||
|
FormField();
|
||||||
|
virtual ~FormField();
|
||||||
|
};
|
||||||
|
|
||||||
|
class InputFormField : public FormField {
|
||||||
|
std::string render();
|
||||||
|
};
|
||||||
|
|
||||||
|
class InputTextFormField : public InputFormField {
|
||||||
|
std::string render();
|
||||||
|
};
|
||||||
|
|
||||||
|
class InputPasswordFormField : public InputFormField {
|
||||||
|
std::string render();
|
||||||
|
};
|
||||||
|
|
||||||
|
class Form {
|
||||||
|
public:
|
||||||
|
std::string name;
|
||||||
|
std::map<std::string, std::string> attribues;
|
||||||
|
std::vector<FormField *> fields;
|
||||||
|
|
||||||
|
//call Theme->render(); in it, and that will go though all attribs and call their renders
|
||||||
|
virtual std::string render();
|
||||||
|
|
||||||
|
Form();
|
||||||
|
virtual ~Form();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
13
core/handler_instance.cpp
Normal file
13
core/handler_instance.cpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#include "handler_instance.h"
|
||||||
|
|
||||||
|
#include "request.h"
|
||||||
|
#include "object.h"
|
||||||
|
|
||||||
|
HandlerInstance::HandlerInstance() {
|
||||||
|
instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HandlerInstance::HandlerInstance(std::function<void(Object *, Request *)> p_handler_func, Object *p_instance) {
|
||||||
|
handler_func = p_handler_func;
|
||||||
|
instance = p_instance;
|
||||||
|
}
|
17
core/handler_instance.h
Normal file
17
core/handler_instance.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef HANDLER_INSTANCE_H
|
||||||
|
#define HANDLER_INSTANCE_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
class Object;
|
||||||
|
class Request;
|
||||||
|
|
||||||
|
struct HandlerInstance {
|
||||||
|
std::function<void(Object *, Request *)> handler_func;
|
||||||
|
Object *instance;
|
||||||
|
|
||||||
|
HandlerInstance();
|
||||||
|
HandlerInstance(std::function<void(Object *, Request *)> p_handler_func, Object *p_instance = nullptr);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
1456
core/html_builder.cpp
Normal file
1456
core/html_builder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
315
core/html_builder.h
Normal file
315
core/html_builder.h
Normal file
@ -0,0 +1,315 @@
|
|||||||
|
#ifndef HTML_BUILDER_H
|
||||||
|
#define HTML_BUILDER_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Request;
|
||||||
|
|
||||||
|
//This might be converted to a form validator
|
||||||
|
|
||||||
|
class HTMLTag {
|
||||||
|
public:
|
||||||
|
bool simple;
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
HTMLTag *str(const std::string &str);
|
||||||
|
HTMLTag *style(const std::string &val);
|
||||||
|
HTMLTag *href(const std::string &val);
|
||||||
|
HTMLTag *cls(const std::string &val);
|
||||||
|
HTMLTag *id(const std::string &val);
|
||||||
|
HTMLTag *name(const std::string &val);
|
||||||
|
HTMLTag *method(const std::string &val);
|
||||||
|
HTMLTag *type(const std::string &val);
|
||||||
|
|
||||||
|
HTMLTag *attrib(const std::string &attr, const std::string &val);
|
||||||
|
|
||||||
|
HTMLTag *start(const std::string &p_new_tag, const bool p_simple = false);
|
||||||
|
HTMLTag *reset();
|
||||||
|
HTMLTag *close();
|
||||||
|
|
||||||
|
bool has_data();
|
||||||
|
|
||||||
|
HTMLTag();
|
||||||
|
};
|
||||||
|
|
||||||
|
class HTMLBuilder {
|
||||||
|
public:
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
void comment(const std::string &val);
|
||||||
|
HTMLTag *doctype();
|
||||||
|
void doctype(const std::string &val);
|
||||||
|
|
||||||
|
HTMLTag *a();
|
||||||
|
HTMLTag *abbr();
|
||||||
|
HTMLTag *acronym(); //Not supported in HTML5.
|
||||||
|
HTMLTag *address();
|
||||||
|
HTMLTag *applet(); //Not supported in HTML5.
|
||||||
|
HTMLTag *area();
|
||||||
|
HTMLTag *article();
|
||||||
|
HTMLTag *aside();
|
||||||
|
HTMLTag *audio();
|
||||||
|
HTMLTag *b();
|
||||||
|
HTMLTag *basefont(); //Not supported in HTML5.
|
||||||
|
HTMLTag *bdi();
|
||||||
|
HTMLTag *bdo();
|
||||||
|
HTMLTag *big(); //Not supported in HTML5.
|
||||||
|
HTMLTag *blockquote();
|
||||||
|
HTMLTag *body();
|
||||||
|
HTMLTag *br();
|
||||||
|
HTMLTag *button();
|
||||||
|
HTMLTag *canvas();
|
||||||
|
HTMLTag *caption();
|
||||||
|
HTMLTag *center(); //Not supported in HTML5.
|
||||||
|
HTMLTag *cite();
|
||||||
|
HTMLTag *code();
|
||||||
|
HTMLTag *col();
|
||||||
|
HTMLTag *colgroup();
|
||||||
|
HTMLTag *data();
|
||||||
|
HTMLTag *datalist();
|
||||||
|
HTMLTag *dd();
|
||||||
|
HTMLTag *del();
|
||||||
|
HTMLTag *details();
|
||||||
|
HTMLTag *dfn();
|
||||||
|
HTMLTag *dialog();
|
||||||
|
HTMLTag *dir(); // Not supported in HTML5.
|
||||||
|
HTMLTag *div();
|
||||||
|
HTMLTag *dl();
|
||||||
|
HTMLTag *dt();
|
||||||
|
HTMLTag *em();
|
||||||
|
HTMLTag *embed();
|
||||||
|
HTMLTag *fieldset();
|
||||||
|
HTMLTag *figcaption();
|
||||||
|
HTMLTag *figure();
|
||||||
|
HTMLTag *font(); //Not supported in HTML5.
|
||||||
|
HTMLTag *footer();
|
||||||
|
HTMLTag *form();
|
||||||
|
HTMLTag *frame(); //Not supported in HTML5.
|
||||||
|
HTMLTag *frameset(); //Not supported in HTML5.
|
||||||
|
HTMLTag *h1();
|
||||||
|
HTMLTag *h2();
|
||||||
|
HTMLTag *h3();
|
||||||
|
HTMLTag *h4();
|
||||||
|
HTMLTag *h5();
|
||||||
|
HTMLTag *h6();
|
||||||
|
HTMLTag *head();
|
||||||
|
HTMLTag *header();
|
||||||
|
HTMLTag *hr();
|
||||||
|
HTMLTag *html();
|
||||||
|
|
||||||
|
HTMLTag *i();
|
||||||
|
HTMLTag *iframe();
|
||||||
|
HTMLTag *img();
|
||||||
|
HTMLTag *input();
|
||||||
|
HTMLTag *ins();
|
||||||
|
HTMLTag *kbd();
|
||||||
|
HTMLTag *label();
|
||||||
|
HTMLTag *legend();
|
||||||
|
HTMLTag *li();
|
||||||
|
HTMLTag *link();
|
||||||
|
HTMLTag *main();
|
||||||
|
HTMLTag *map();
|
||||||
|
HTMLTag *mark();
|
||||||
|
HTMLTag *meta();
|
||||||
|
HTMLTag *meter();
|
||||||
|
|
||||||
|
HTMLTag *nav();
|
||||||
|
HTMLTag *noframes(); //Not supported in HTML5.
|
||||||
|
HTMLTag *noscript();
|
||||||
|
HTMLTag *object();
|
||||||
|
HTMLTag *ol();
|
||||||
|
HTMLTag *optgroup();
|
||||||
|
HTMLTag *option();
|
||||||
|
HTMLTag *output();
|
||||||
|
HTMLTag *p();
|
||||||
|
HTMLTag *param();
|
||||||
|
HTMLTag *picture();
|
||||||
|
HTMLTag *pre();
|
||||||
|
HTMLTag *progress();
|
||||||
|
HTMLTag *q();
|
||||||
|
HTMLTag *rp();
|
||||||
|
|
||||||
|
HTMLTag *rt();
|
||||||
|
HTMLTag *ruby();
|
||||||
|
HTMLTag *s();
|
||||||
|
HTMLTag *samp();
|
||||||
|
HTMLTag *script();
|
||||||
|
HTMLTag *section();
|
||||||
|
HTMLTag *select();
|
||||||
|
HTMLTag *small();
|
||||||
|
HTMLTag *source();
|
||||||
|
HTMLTag *span();
|
||||||
|
HTMLTag *strike(); //Not supported in HTML5
|
||||||
|
HTMLTag *strong();
|
||||||
|
HTMLTag *style();
|
||||||
|
HTMLTag *sub();
|
||||||
|
HTMLTag *summary();
|
||||||
|
HTMLTag *sup();
|
||||||
|
|
||||||
|
HTMLTag *svg();
|
||||||
|
HTMLTag *table();
|
||||||
|
HTMLTag *tbody();
|
||||||
|
HTMLTag *td();
|
||||||
|
HTMLTag *templateh();
|
||||||
|
HTMLTag *textarea();
|
||||||
|
HTMLTag *tfoot();
|
||||||
|
HTMLTag *th();
|
||||||
|
HTMLTag *thead();
|
||||||
|
HTMLTag *time();
|
||||||
|
HTMLTag *title();
|
||||||
|
HTMLTag *tr();
|
||||||
|
HTMLTag *track();
|
||||||
|
HTMLTag *tt(); //Not supported in HTML5.
|
||||||
|
HTMLTag *u();
|
||||||
|
HTMLTag *ul();
|
||||||
|
HTMLTag *var();
|
||||||
|
HTMLTag *video();
|
||||||
|
HTMLTag *wbr();
|
||||||
|
|
||||||
|
//closing tags c prefix means close
|
||||||
|
//Note simple tags should not have these like <br>
|
||||||
|
//Note that I might have a few that shouldn't be here, those will be removed as I find them
|
||||||
|
void ca();
|
||||||
|
void cabbr();
|
||||||
|
void cacronym();
|
||||||
|
void caddress();
|
||||||
|
void capplet();
|
||||||
|
void carea();
|
||||||
|
void carticle();
|
||||||
|
void caside();
|
||||||
|
void caudio();
|
||||||
|
void cb();
|
||||||
|
void cbasefont();
|
||||||
|
void cbdi();
|
||||||
|
void cbdo();
|
||||||
|
void cbig();
|
||||||
|
void cblockquote();
|
||||||
|
void cbody();
|
||||||
|
void cbutton();
|
||||||
|
void ccanvas();
|
||||||
|
|
||||||
|
void ccaption();
|
||||||
|
void ccenter();
|
||||||
|
void ccite();
|
||||||
|
void ccode();
|
||||||
|
void ccol();
|
||||||
|
void ccolgroup();
|
||||||
|
void cdata();
|
||||||
|
void cdatalist();
|
||||||
|
void cdd();
|
||||||
|
void cdel();
|
||||||
|
void cdetails();
|
||||||
|
void cdfn();
|
||||||
|
void cdialog();
|
||||||
|
void cdir();
|
||||||
|
void cdiv();
|
||||||
|
void cdl();
|
||||||
|
void cdt();
|
||||||
|
|
||||||
|
void cem();
|
||||||
|
void cembed();
|
||||||
|
void cfieldset();
|
||||||
|
void cfigcaption();
|
||||||
|
void cfigure();
|
||||||
|
void cfont();
|
||||||
|
void cfooter();
|
||||||
|
void cform();
|
||||||
|
void cframe();
|
||||||
|
void cframeset();
|
||||||
|
void ch1();
|
||||||
|
void ch2();
|
||||||
|
void ch3();
|
||||||
|
void ch4();
|
||||||
|
void ch5();
|
||||||
|
void ch6();
|
||||||
|
void chead();
|
||||||
|
void cheader();
|
||||||
|
void chr();
|
||||||
|
void chtml();
|
||||||
|
|
||||||
|
void ci();
|
||||||
|
void ciframe();
|
||||||
|
void cimg();
|
||||||
|
void cinput();
|
||||||
|
void cins();
|
||||||
|
void ckbd();
|
||||||
|
void clabel();
|
||||||
|
void clegend();
|
||||||
|
void cli();
|
||||||
|
void clink();
|
||||||
|
void cmain();
|
||||||
|
void cmap();
|
||||||
|
void cmark();
|
||||||
|
void cmeta();
|
||||||
|
void cmeter();
|
||||||
|
|
||||||
|
void cnav();
|
||||||
|
void cnoframes();
|
||||||
|
void cnoscript();
|
||||||
|
void cobject();
|
||||||
|
void c_ol();
|
||||||
|
void coptgroup();
|
||||||
|
void coption();
|
||||||
|
void coutput();
|
||||||
|
void cp();
|
||||||
|
void cparam();
|
||||||
|
void cpicture();
|
||||||
|
void cpre();
|
||||||
|
void cprogress();
|
||||||
|
void cq();
|
||||||
|
void crp();
|
||||||
|
|
||||||
|
void crt();
|
||||||
|
void cruby();
|
||||||
|
void cs();
|
||||||
|
void csamp();
|
||||||
|
void cscript();
|
||||||
|
void csection();
|
||||||
|
void cselect();
|
||||||
|
void csmall();
|
||||||
|
void csource();
|
||||||
|
void cspan();
|
||||||
|
void cstrike();
|
||||||
|
void cstrong();
|
||||||
|
void cstyle();
|
||||||
|
void csub();
|
||||||
|
void csummary();
|
||||||
|
void csup();
|
||||||
|
|
||||||
|
void csvg();
|
||||||
|
void ctable();
|
||||||
|
void ctbody();
|
||||||
|
void ctd();
|
||||||
|
void ctemplateh();
|
||||||
|
void ctextarea();
|
||||||
|
void ctfoot();
|
||||||
|
void cth();
|
||||||
|
void cthead();
|
||||||
|
void ctime();
|
||||||
|
void ctitle();
|
||||||
|
void ctr();
|
||||||
|
void ctrack();
|
||||||
|
void ctt();
|
||||||
|
void cu();
|
||||||
|
void cul();
|
||||||
|
void cvar();
|
||||||
|
void cvideo();
|
||||||
|
void cwbr();
|
||||||
|
|
||||||
|
//write
|
||||||
|
void w(const std::string &val);
|
||||||
|
//write_escaped
|
||||||
|
void we(const std::string &val);
|
||||||
|
|
||||||
|
void write_tag();
|
||||||
|
|
||||||
|
HTMLBuilder();
|
||||||
|
virtual ~HTMLBuilder();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
HTMLTag tag;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
96
core/http_server.cpp
Normal file
96
core/http_server.cpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#include "http_server.h"
|
||||||
|
|
||||||
|
#include "request.h"
|
||||||
|
#include "application.h"
|
||||||
|
|
||||||
|
#define LOG_VERBOSE 0
|
||||||
|
|
||||||
|
void HTTPServer::http_callback_handler(Request *request) {
|
||||||
|
Application::handle_request(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPServer::httpEnterCallbackDefault(const HTTPParser &httpParser, const HttpSession::Ptr &session) {
|
||||||
|
Request *request = RequestPool::get_request();
|
||||||
|
|
||||||
|
request->http_parser = &httpParser;
|
||||||
|
request->session = &session;
|
||||||
|
|
||||||
|
#if LOG_VERBOSE
|
||||||
|
std::cout << "method:" << http_method_str(static_cast<http_method>(httpParser.method())) << std::endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
http_callback_handler(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPServer::wsEnterCallbackDefault(const HttpSession::Ptr &httpSession, WebSocketFormat::WebSocketFrameType opcode, const std::string &payload) {
|
||||||
|
|
||||||
|
std::cout << "frame enter of type:" << int(opcode) << std::endl;
|
||||||
|
std::cout << "payload is:" << payload << std::endl;
|
||||||
|
// echo frame
|
||||||
|
auto frame = std::make_shared<std::string>();
|
||||||
|
|
||||||
|
WebSocketFormat::wsFrameBuild(payload.c_str(), payload.size(), *frame, WebSocketFormat::WebSocketFrameType::TEXT_FRAME, true, false);
|
||||||
|
|
||||||
|
httpSession->send(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPServer::configure() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPServer::initialize() {
|
||||||
|
if (service)
|
||||||
|
return;
|
||||||
|
|
||||||
|
configure();
|
||||||
|
|
||||||
|
service = TcpService::Create();
|
||||||
|
service->startWorkerThread(threads);
|
||||||
|
|
||||||
|
int p_port = port;
|
||||||
|
|
||||||
|
//!
|
||||||
|
if (listenBuilder)
|
||||||
|
delete listenBuilder;
|
||||||
|
|
||||||
|
listenBuilder = new wrapper::HttpListenerBuilder();
|
||||||
|
listenBuilder->configureService(service);
|
||||||
|
|
||||||
|
listenBuilder->configureSocketOptions({
|
||||||
|
[](TcpSocket &socket) {
|
||||||
|
socket.setNodelay();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
listenBuilder->configureConnectionOptions({ AddSocketOption::WithMaxRecvBufferSize(1024) });
|
||||||
|
|
||||||
|
listenBuilder->configureListen([p_port](wrapper::BuildListenConfig builder) {
|
||||||
|
builder.setAddr(false, "0.0.0.0", p_port);
|
||||||
|
});
|
||||||
|
|
||||||
|
listenBuilder->configureEnterCallback([](const HttpSession::Ptr &httpSession, HttpSessionHandlers &handlers) {
|
||||||
|
handlers.setHttpCallback(HTTPServer::httpEnterCallbackDefault);
|
||||||
|
handlers.setWSCallback(HTTPServer::wsEnterCallbackDefault);
|
||||||
|
});
|
||||||
|
|
||||||
|
listenBuilder->asyncRun();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPServer::main_loop() {
|
||||||
|
while (true) {
|
||||||
|
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||||
|
|
||||||
|
if (brynet::base::app_kbhit()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTPServer::HTTPServer() {
|
||||||
|
port = 80;
|
||||||
|
threads = 4;
|
||||||
|
listenBuilder = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
HTTPServer::~HTTPServer() {
|
||||||
|
delete listenBuilder;
|
||||||
|
}
|
42
core/http_server.h
Normal file
42
core/http_server.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef HTTP_SERVER_H
|
||||||
|
#define HTTP_SERVER_H
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <brynet/base/AppStatus.hpp>
|
||||||
|
#include <brynet/net/http/HttpFormat.hpp>
|
||||||
|
#include <brynet/net/http/HttpService.hpp>
|
||||||
|
#include <brynet/net/http/WebSocketFormat.hpp>
|
||||||
|
#include <brynet/net/wrapper/HttpServiceBuilder.hpp>
|
||||||
|
#include <brynet/net/wrapper/ServiceBuilder.hpp>
|
||||||
|
|
||||||
|
using namespace brynet;
|
||||||
|
using namespace brynet::net;
|
||||||
|
using namespace brynet::net::http;
|
||||||
|
|
||||||
|
class Request;
|
||||||
|
|
||||||
|
class HTTPServer {
|
||||||
|
public:
|
||||||
|
int port;
|
||||||
|
int threads;
|
||||||
|
std::shared_ptr<TcpService> service;
|
||||||
|
wrapper::HttpListenerBuilder *listenBuilder;
|
||||||
|
|
||||||
|
static void http_callback_handler(Request *response);
|
||||||
|
|
||||||
|
static void httpEnterCallbackDefault(const HTTPParser &httpParser, const HttpSession::Ptr &session);
|
||||||
|
static void wsEnterCallbackDefault(const HttpSession::Ptr &httpSession, WebSocketFormat::WebSocketFrameType opcode, const std::string &payload);
|
||||||
|
|
||||||
|
virtual void configure();
|
||||||
|
virtual void initialize();
|
||||||
|
|
||||||
|
void main_loop();
|
||||||
|
|
||||||
|
HTTPServer();
|
||||||
|
virtual ~HTTPServer();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
15
core/object.cpp
Normal file
15
core/object.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "object.h"
|
||||||
|
|
||||||
|
#include "database.h"
|
||||||
|
|
||||||
|
void Object::migrate() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Object::Object() {
|
||||||
|
db = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object::~Object() {
|
||||||
|
|
||||||
|
}
|
80
core/object.h
Normal file
80
core/object.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#ifndef OBJECT_H
|
||||||
|
#define OBJECT_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class Database;
|
||||||
|
|
||||||
|
//taken from GodotEngine's object.h
|
||||||
|
#define RCPP_OBJECT(m_class, m_inherits) \
|
||||||
|
private: \
|
||||||
|
void operator=(const m_class &p_rval) {} \
|
||||||
|
\
|
||||||
|
public: \
|
||||||
|
virtual std::string get_class() const override { \
|
||||||
|
return std::string(#m_class); \
|
||||||
|
} \
|
||||||
|
static void *get_class_ptr_static() { \
|
||||||
|
static int ptr; \
|
||||||
|
return &ptr; \
|
||||||
|
} \
|
||||||
|
static std::string get_class_static() { \
|
||||||
|
return std::string(#m_class); \
|
||||||
|
} \
|
||||||
|
static std::string get_parent_class_static() { \
|
||||||
|
return m_inherits::get_class_static(); \
|
||||||
|
} \
|
||||||
|
static void get_inheritance_list_static(std::list<std::string> *p_inheritance_list) { \
|
||||||
|
m_inherits::get_inheritance_list_static(p_inheritance_list); \
|
||||||
|
p_inheritance_list->push_back(std::string(#m_class)); \
|
||||||
|
} \
|
||||||
|
static std::string inherits_static() { \
|
||||||
|
return std::string(#m_inherits); \
|
||||||
|
} \
|
||||||
|
virtual bool is_class(const std::string &p_class) const override { return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); } \
|
||||||
|
virtual bool is_class_ptr(void *p_ptr) const override { return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); } \
|
||||||
|
\
|
||||||
|
static void get_valid_parents_static(std::list<std::string> *p_parents) { \
|
||||||
|
if (m_class::_get_valid_parents_static != m_inherits::_get_valid_parents_static) { \
|
||||||
|
m_class::_get_valid_parents_static(p_parents); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
m_inherits::get_valid_parents_static(p_parents); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
private:
|
||||||
|
|
||||||
|
class Object {
|
||||||
|
public:
|
||||||
|
Database *db;
|
||||||
|
|
||||||
|
virtual std::string get_class() const { return "Object"; }
|
||||||
|
static void *get_class_ptr_static() {
|
||||||
|
static int ptr;
|
||||||
|
return &ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string get_class_static() { return "Object"; }
|
||||||
|
static std::string get_parent_class_static() { return std::string(); }
|
||||||
|
|
||||||
|
static void get_inheritance_list_static(std::list<std::string> *p_inheritance_list) { p_inheritance_list->push_back("Object"); }
|
||||||
|
|
||||||
|
virtual bool is_class(const std::string &p_class) const { return (p_class == "Object"); }
|
||||||
|
virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; }
|
||||||
|
|
||||||
|
static void get_valid_parents_static(std::list<std::string> *p_parents) {}
|
||||||
|
static void _get_valid_parents_static(std::list<std::string> *p_parents) {}
|
||||||
|
|
||||||
|
//dbconnection
|
||||||
|
//setting object?
|
||||||
|
//FileCache? -> set it to the global singleton by default?
|
||||||
|
|
||||||
|
virtual void migrate();
|
||||||
|
|
||||||
|
Object();
|
||||||
|
virtual ~Object();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
30
core/query_builder.cpp
Normal file
30
core/query_builder.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include "query_builder.h"
|
||||||
|
|
||||||
|
QueryBuilder *QueryBuilder::select(const std::string ¶ms) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder *QueryBuilder::where(const std::string ¶ms) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder *QueryBuilder::from(const std::string ¶ms) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder *QueryBuilder::limit(const int min, const int max) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder *QueryBuilder::insert(const std::string &table_name, const std::string ¶ms_str) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueryBuilder::finalize() {
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder::QueryBuilder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder::~QueryBuilder() {
|
||||||
|
}
|
21
core/query_builder.h
Normal file
21
core/query_builder.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef QUERY_BUILDER_H
|
||||||
|
#define QUERY_BUILDER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class QueryBuilder {
|
||||||
|
public:
|
||||||
|
virtual QueryBuilder *select(const std::string ¶ms);
|
||||||
|
virtual QueryBuilder *where(const std::string ¶ms);
|
||||||
|
virtual QueryBuilder *from(const std::string ¶ms);
|
||||||
|
virtual QueryBuilder *limit(const int min, const int max);
|
||||||
|
virtual QueryBuilder *insert(const std::string &table_name, const std::string ¶ms_str);
|
||||||
|
virtual void finalize();
|
||||||
|
|
||||||
|
QueryBuilder();
|
||||||
|
virtual ~QueryBuilder();
|
||||||
|
|
||||||
|
std::string query_result;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
15
core/query_result.cpp
Normal file
15
core/query_result.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "query_result.h"
|
||||||
|
|
||||||
|
bool QueryResult::next_row() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *QueryResult::get_cell(const int index) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryResult::QueryResult() {
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryResult::~QueryResult() {
|
||||||
|
}
|
13
core/query_result.h
Normal file
13
core/query_result.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef QUERY_RESULT_H
|
||||||
|
#define QUERY_RESULT_H
|
||||||
|
|
||||||
|
class QueryResult {
|
||||||
|
public:
|
||||||
|
virtual bool next_row();
|
||||||
|
virtual const char*get_cell(const int index);
|
||||||
|
|
||||||
|
QueryResult();
|
||||||
|
virtual ~QueryResult();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
128
core/request.cpp
Normal file
128
core/request.cpp
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
#include "request.h"
|
||||||
|
|
||||||
|
void Request::compile_body() {
|
||||||
|
compiled_body.reserve(body.size() + head.size() + 13 + 14 + 15);
|
||||||
|
|
||||||
|
//13
|
||||||
|
compiled_body += "<html>"
|
||||||
|
"<head>";
|
||||||
|
|
||||||
|
compiled_body += head;
|
||||||
|
|
||||||
|
//14
|
||||||
|
compiled_body += "</head>"
|
||||||
|
"<body>";
|
||||||
|
|
||||||
|
compiled_body += body;
|
||||||
|
|
||||||
|
//15
|
||||||
|
compiled_body += "</body>"
|
||||||
|
"</html>";
|
||||||
|
|
||||||
|
response->setBody(compiled_body);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Request::compile_and_send_body() {
|
||||||
|
compile_body();
|
||||||
|
send();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Request::next_stage() {
|
||||||
|
if (current_middleware_index == (*middleware_stack).size()) {
|
||||||
|
handler_instance.handler_func(handler_instance.instance, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const HandlerInstance &hi = (*middleware_stack)[current_middleware_index++];
|
||||||
|
|
||||||
|
hi.handler_func(hi.instance, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Request::send() {
|
||||||
|
if (http_parser->isKeepAlive()) {
|
||||||
|
response->addHeadValue("Connection", "Keep-Alive");
|
||||||
|
|
||||||
|
std::string result = response->getResult();
|
||||||
|
|
||||||
|
(*session)->send(result.c_str(), result.size());
|
||||||
|
} else {
|
||||||
|
response->addHeadValue("Connection", "Close");
|
||||||
|
|
||||||
|
std::string result = response->getResult();
|
||||||
|
|
||||||
|
const HttpSession::Ptr lsession = (*session);
|
||||||
|
|
||||||
|
(*session)->send(result.c_str(), result.size(), [lsession]() { lsession->postShutdown(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestPool::return_request(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Request::reset() {
|
||||||
|
http_parser = nullptr;
|
||||||
|
session = nullptr;
|
||||||
|
current_middleware_index = 0;
|
||||||
|
middleware_stack = nullptr;
|
||||||
|
|
||||||
|
head.clear();
|
||||||
|
body.clear();
|
||||||
|
compiled_body.clear();
|
||||||
|
|
||||||
|
if (response)
|
||||||
|
delete response;
|
||||||
|
|
||||||
|
response = new HttpResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
Request::Request() {
|
||||||
|
response = nullptr;
|
||||||
|
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
Request::~Request() {
|
||||||
|
delete response;
|
||||||
|
}
|
||||||
|
|
||||||
|
Request *RequestPool::get_request() {
|
||||||
|
_mutex.lock();
|
||||||
|
|
||||||
|
Request *request;
|
||||||
|
|
||||||
|
if (_requests.size() == 0) {
|
||||||
|
_mutex.unlock();
|
||||||
|
|
||||||
|
request = new Request();
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
request = _requests[_requests.size() - 1];
|
||||||
|
_requests.pop_back();
|
||||||
|
|
||||||
|
_mutex.unlock();
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestPool::return_request(Request *request) {
|
||||||
|
request->reset();
|
||||||
|
|
||||||
|
_mutex.lock();
|
||||||
|
_requests.push_back(request);
|
||||||
|
_mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestPool::RequestPool() {
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestPool::~RequestPool() {
|
||||||
|
for (uint32_t i = 0; i < _requests.size(); ++i) {
|
||||||
|
delete _requests[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
_requests.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::mutex RequestPool::_mutex;
|
||||||
|
std::vector<Request *> RequestPool::_requests;
|
53
core/request.h
Normal file
53
core/request.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef REQUEST_H
|
||||||
|
#define REQUEST_H
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <brynet/net/http/HttpFormat.hpp>
|
||||||
|
#include <brynet/net/http/HttpService.hpp>
|
||||||
|
|
||||||
|
#include "handler_instance.h"
|
||||||
|
|
||||||
|
using namespace brynet;
|
||||||
|
using namespace brynet::net;
|
||||||
|
using namespace brynet::net::http;
|
||||||
|
|
||||||
|
class Request {
|
||||||
|
public:
|
||||||
|
const HTTPParser *http_parser;
|
||||||
|
const HttpSession::Ptr *session;
|
||||||
|
HttpResponse *response;
|
||||||
|
|
||||||
|
uint32_t current_middleware_index;
|
||||||
|
HandlerInstance handler_instance;
|
||||||
|
std::vector<HandlerInstance> *middleware_stack;
|
||||||
|
|
||||||
|
std::string head;
|
||||||
|
std::string body;
|
||||||
|
std::string compiled_body;
|
||||||
|
|
||||||
|
void compile_body();
|
||||||
|
void compile_and_send_body();
|
||||||
|
void next_stage();
|
||||||
|
void send();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
Request();
|
||||||
|
~Request();
|
||||||
|
};
|
||||||
|
|
||||||
|
class RequestPool {
|
||||||
|
public:
|
||||||
|
static Request *get_request();
|
||||||
|
static void return_request(Request *request);
|
||||||
|
|
||||||
|
RequestPool();
|
||||||
|
~RequestPool();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static std::mutex _mutex;
|
||||||
|
static std::vector<Request *> _requests;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
47
core/settings.cpp
Normal file
47
core/settings.cpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void Settings::parse_file(const std::string &path) {
|
||||||
|
FILE *f = fopen(path.c_str(), "r");
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
printf("Settings::parse_file: Error opening file!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
long fsize = ftell(f);
|
||||||
|
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
|
||||||
|
|
||||||
|
std::string config_str;
|
||||||
|
config_str.resize(fsize);
|
||||||
|
|
||||||
|
fread(&config_str[0], 1, fsize, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
settings.Parse(config_str.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings *Settings::get_singleton() {
|
||||||
|
return _singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings::Settings(const bool singleton) {
|
||||||
|
if (singleton) {
|
||||||
|
if (_singleton) {
|
||||||
|
printf("Settings singleton overridden!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
_singleton = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings::~Settings() {
|
||||||
|
if (_singleton == this) {
|
||||||
|
_singleton = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings *Settings::_singleton = nullptr;
|
24
core/settings.h
Normal file
24
core/settings.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef SETTINGS_H
|
||||||
|
#define SETTINGS_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
|
||||||
|
class Settings {
|
||||||
|
public:
|
||||||
|
rapidjson::Document settings;
|
||||||
|
|
||||||
|
void parse_file(const std::string &path);
|
||||||
|
|
||||||
|
static Settings *get_singleton();
|
||||||
|
|
||||||
|
Settings(const bool singleton = false);
|
||||||
|
virtual ~Settings();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static Settings *_singleton;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
54
core/table_builder.cpp
Normal file
54
core/table_builder.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "table_builder.h"
|
||||||
|
|
||||||
|
TableBuilder *TableBuilder::create_table(const std::string &name) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *TableBuilder::integer(const std::string &name) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *TableBuilder::date(const std::string &name) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *TableBuilder::varchar(const std::string &name, const int length) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *TableBuilder::not_null() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *TableBuilder::null() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *TableBuilder::auto_increment() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *TableBuilder::primary_key(const std::string &name) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *TableBuilder::primary_key() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *TableBuilder::next_row() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *TableBuilder::drop_table(const std::string &name) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TableBuilder::finalize() {
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder::TableBuilder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder::~TableBuilder() {
|
||||||
|
}
|
29
core/table_builder.h
Normal file
29
core/table_builder.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef TABLE_BUILDER_H
|
||||||
|
#define TABLE_BUILDER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class TableBuilder {
|
||||||
|
public:
|
||||||
|
virtual TableBuilder *create_table(const std::string &name);
|
||||||
|
virtual TableBuilder *integer(const std::string &name);
|
||||||
|
virtual TableBuilder *date(const std::string &name);
|
||||||
|
virtual TableBuilder *varchar(const std::string &name, const int length);
|
||||||
|
virtual TableBuilder *not_null();
|
||||||
|
virtual TableBuilder *null();
|
||||||
|
virtual TableBuilder *auto_increment();
|
||||||
|
virtual TableBuilder *primary_key(const std::string &name);
|
||||||
|
virtual TableBuilder *primary_key();
|
||||||
|
virtual TableBuilder *next_row();
|
||||||
|
|
||||||
|
virtual TableBuilder *drop_table(const std::string &name);
|
||||||
|
|
||||||
|
virtual void finalize();
|
||||||
|
|
||||||
|
TableBuilder();
|
||||||
|
virtual ~TableBuilder();
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
30
database/db_init.h
Normal file
30
database/db_init.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#ifndef DB_INIT_H
|
||||||
|
#define DB_INIT_H
|
||||||
|
|
||||||
|
#if MYSQL_PRESENT
|
||||||
|
#include "mysql/mysql_database.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PGSQL_PRESENT
|
||||||
|
#include "postgres/pgsql_database.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SQLITE_PRESENT
|
||||||
|
#include "sqlite/sqlite3_database.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void initialize_database_backends() {
|
||||||
|
#if MYSQL_PRESENT
|
||||||
|
MysqlDatabase::_register();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if PGSQL_PRESENT
|
||||||
|
PGSQLDatabase::_register();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SQLITE_PRESENT
|
||||||
|
SQLite3Database::_register();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
12
database/mysql/SCsub
Normal file
12
database/mysql/SCsub
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
Import("env_db")
|
||||||
|
Import("env")
|
||||||
|
|
||||||
|
env_db.core_sources = []
|
||||||
|
|
||||||
|
env_db.add_source_files(env_db.core_sources, "*.cpp")
|
||||||
|
|
||||||
|
# Build it all as a library
|
||||||
|
lib = env_db.add_library("database_mysql", env_db.core_sources)
|
||||||
|
env.Prepend(LIBS=[lib])
|
71
database/mysql/detect.py
Normal file
71
database/mysql/detect.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def is_active():
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_name():
|
||||||
|
return "mysql"
|
||||||
|
|
||||||
|
|
||||||
|
def can_build():
|
||||||
|
|
||||||
|
if os.name == "posix" or sys.platform == "darwin":
|
||||||
|
x11_error = os.system("pkg-config --version > /dev/null")
|
||||||
|
if x11_error:
|
||||||
|
return False
|
||||||
|
|
||||||
|
mariadb_error = os.system("pkg-config mariadb --modversion --silence-errors > /dev/null ")
|
||||||
|
mysql_error = os.system("pkg-config mysql --modversion --silence-errors > /dev/null ")
|
||||||
|
|
||||||
|
if mariadb_error and mysql_error:
|
||||||
|
print("mysql and mariadb not found..")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if not mariadb_error:
|
||||||
|
print("mariadb found!")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
if not mysql_error:
|
||||||
|
print("mysql found!")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
#todo
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_opts():
|
||||||
|
from SCons.Variables import BoolVariable, EnumVariable
|
||||||
|
|
||||||
|
return [
|
||||||
|
EnumVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", "yes", ("yes", "no")),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_flags():
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def configure(env):
|
||||||
|
mariadb_error = os.system("pkg-config mariadb --modversion --silence-errors > /dev/null ")
|
||||||
|
mysql_error = os.system("pkg-config mysql --modversion --silence-errors > /dev/null ")
|
||||||
|
|
||||||
|
if not mariadb_error:
|
||||||
|
env.ParseConfig("pkg-config mariadb --cflags --libs")
|
||||||
|
env.Append(CPPDEFINES=["MYSQL_PRESENT"])
|
||||||
|
return
|
||||||
|
|
||||||
|
if not mysql_error:
|
||||||
|
env.ParseConfig("pkg-config mysql --cflags --libs")
|
||||||
|
|
||||||
|
env.Append(CPPDEFINES=["MYSQL_PRESENT"])
|
||||||
|
|
||||||
|
# Link those statically for portability
|
||||||
|
#if env["use_static_cpp"]:
|
||||||
|
#env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])
|
120
database/mysql/mysql_database.cpp
Normal file
120
database/mysql/mysql_database.cpp
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#include "mysql_database.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include "core/database_manager.h"
|
||||||
|
|
||||||
|
#include "mysql_query_builder.h"
|
||||||
|
#include "mysql_table_builder.h"
|
||||||
|
#include "mysql_query_result.h"
|
||||||
|
|
||||||
|
void MysqlDatabase::connect(const std::string &connection_str) {
|
||||||
|
mysql = mysql_init(mysql);
|
||||||
|
mysql_options(mysql, MYSQL_OPT_NONBLOCK, 0);
|
||||||
|
|
||||||
|
std::string host = "127.0.0.1";
|
||||||
|
std::string user = "";
|
||||||
|
std::string password = "";
|
||||||
|
std::string dbname = "testappdb";
|
||||||
|
int port = 3306;
|
||||||
|
|
||||||
|
mysql = mysql_real_connect(mysql, host.c_str(), user.c_str(), password.c_str(), dbname.c_str(), port, NULL, 0);
|
||||||
|
|
||||||
|
if (mysql) {
|
||||||
|
printf("mysql connected\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryResult *MysqlDatabase::query(const std::string &query) {
|
||||||
|
if (!mysql)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
//printf("%s\n", query.c_str());
|
||||||
|
|
||||||
|
int error = mysql_real_query(mysql, query.c_str(), query.length());
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
const char *merr = mysql_error(mysql);
|
||||||
|
|
||||||
|
printf("MySQL error: %s\n", merr);
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MYSQL_RES *result = mysql_use_result(mysql);
|
||||||
|
|
||||||
|
MysqlQueryResult *res = new MysqlQueryResult();
|
||||||
|
|
||||||
|
res->result = result;
|
||||||
|
//res->next_row();
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MysqlDatabase::query_run(const std::string &query) {
|
||||||
|
if (!mysql)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//printf("%s\n", query.c_str());
|
||||||
|
|
||||||
|
int error = mysql_real_query(mysql, query.c_str(), query.length());
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
const char *merr = mysql_error(mysql);
|
||||||
|
|
||||||
|
printf("MySQL error: %s\n", merr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("query OK\n");
|
||||||
|
//printf("----------------\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
printf("----------------\n");
|
||||||
|
|
||||||
|
MYSQL_RES *result = mysql_use_result(mysql);
|
||||||
|
//MYSQL_RES *result = mysql_store_result(mysql);
|
||||||
|
|
||||||
|
MYSQL_ROW row;
|
||||||
|
while (row = mysql_fetch_row(result)) {
|
||||||
|
printf("%s\n", row[0]);
|
||||||
|
//printf("%s\n", row[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("----------------\n");
|
||||||
|
|
||||||
|
mysql_free_result(result);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder *MysqlDatabase::get_query_builder() {
|
||||||
|
return new MysqlQueryBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *MysqlDatabase::get_table_builder() {
|
||||||
|
return new MysqlTableBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
MysqlDatabase::MysqlDatabase() :
|
||||||
|
Database() {
|
||||||
|
|
||||||
|
mysql = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MysqlDatabase::~MysqlDatabase() {
|
||||||
|
mysql_close(mysql);
|
||||||
|
|
||||||
|
delete mysql;
|
||||||
|
}
|
||||||
|
|
||||||
|
Database *MysqlDatabase::_creation_func() {
|
||||||
|
return new MysqlDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MysqlDatabase::_register() {
|
||||||
|
DatabaseManager::_register_db_creation_func("mysql", MysqlDatabase::_creation_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MysqlDatabase::_unregister() {
|
||||||
|
DatabaseManager::_unregister_db_creation_func("mysql");
|
||||||
|
}
|
37
database/mysql/mysql_database.h
Normal file
37
database/mysql/mysql_database.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef MYSQL_CONNECTION
|
||||||
|
#define MYSQL_CONNECTION
|
||||||
|
|
||||||
|
#include "core/database.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
//Brynet has it aswell, and because of using namespace it is defined here aswell
|
||||||
|
//later this will be fixed better
|
||||||
|
#ifdef IS_NUM
|
||||||
|
#undef IS_NUM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <mysql.h>
|
||||||
|
|
||||||
|
class MysqlDatabase : public Database {
|
||||||
|
public:
|
||||||
|
void connect(const std::string &connection_str);
|
||||||
|
QueryResult *query(const std::string &query);
|
||||||
|
void query_run(const std::string &query);
|
||||||
|
|
||||||
|
QueryBuilder *get_query_builder();
|
||||||
|
TableBuilder *get_table_builder();
|
||||||
|
|
||||||
|
static Database *_creation_func();
|
||||||
|
static void _register();
|
||||||
|
static void _unregister();
|
||||||
|
|
||||||
|
MysqlDatabase();
|
||||||
|
~MysqlDatabase();
|
||||||
|
|
||||||
|
MYSQL *mysql;
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef IS_NUM
|
||||||
|
|
||||||
|
#endif
|
41
database/mysql/mysql_query_builder.cpp
Normal file
41
database/mysql/mysql_query_builder.cpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include "mysql_query_builder.h"
|
||||||
|
|
||||||
|
|
||||||
|
QueryBuilder *MysqlQueryBuilder::select(const std::string ¶ms) {
|
||||||
|
query_result += "SELECT " + params;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder *MysqlQueryBuilder::where(const std::string ¶ms) {
|
||||||
|
query_result += " WHERE " + params;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder *MysqlQueryBuilder::from(const std::string ¶ms) {
|
||||||
|
query_result += " FROM " + params;
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder *MysqlQueryBuilder::limit(const int min, const int max) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryBuilder *MysqlQueryBuilder::insert(const std::string &table_name, const std::string ¶ms_str) {
|
||||||
|
query_result += " INSERT INTO " + table_name + " VALUES( " + params_str + " );";
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MysqlQueryBuilder::finalize() {
|
||||||
|
query_result += ";";
|
||||||
|
}
|
||||||
|
|
||||||
|
MysqlQueryBuilder::MysqlQueryBuilder() {
|
||||||
|
|
||||||
|
}
|
||||||
|
MysqlQueryBuilder::~MysqlQueryBuilder() {
|
||||||
|
|
||||||
|
}
|
22
database/mysql/mysql_query_builder.h
Normal file
22
database/mysql/mysql_query_builder.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#ifndef MYSQL_QUERY_BUILDER_H
|
||||||
|
#define MYSQL_QUERY_BUILDER_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "core/query_builder.h"
|
||||||
|
|
||||||
|
class MysqlQueryBuilder : public QueryBuilder {
|
||||||
|
public:
|
||||||
|
QueryBuilder *select(const std::string ¶ms);
|
||||||
|
QueryBuilder *where(const std::string ¶ms);
|
||||||
|
QueryBuilder *from(const std::string ¶ms);
|
||||||
|
QueryBuilder *limit(const int min, const int max);
|
||||||
|
QueryBuilder *insert(const std::string &table_name, const std::string ¶ms_str);
|
||||||
|
void finalize();
|
||||||
|
|
||||||
|
MysqlQueryBuilder();
|
||||||
|
~MysqlQueryBuilder();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
27
database/mysql/mysql_query_result.cpp
Normal file
27
database/mysql/mysql_query_result.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "mysql_query_result.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
bool MysqlQueryResult::next_row() {
|
||||||
|
current_row = mysql_fetch_row(result);
|
||||||
|
|
||||||
|
//null if no result
|
||||||
|
return current_row;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* MysqlQueryResult::get_cell(const int index) {
|
||||||
|
if (!current_row)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return current_row[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
MysqlQueryResult::MysqlQueryResult() : QueryResult() {
|
||||||
|
result = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MysqlQueryResult::~MysqlQueryResult() {
|
||||||
|
if(result) {
|
||||||
|
mysql_free_result(result);
|
||||||
|
}
|
||||||
|
}
|
20
database/mysql/mysql_query_result.h
Normal file
20
database/mysql/mysql_query_result.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef MYSQL_QUERY_RESULT_H
|
||||||
|
#define MYSQL_QUERY_RESULT_H
|
||||||
|
|
||||||
|
#include "core/query_result.h"
|
||||||
|
|
||||||
|
#include <mysql.h>
|
||||||
|
|
||||||
|
class MysqlQueryResult : public QueryResult {
|
||||||
|
public:
|
||||||
|
bool next_row();
|
||||||
|
const char* get_cell(const int index);
|
||||||
|
|
||||||
|
MysqlQueryResult();
|
||||||
|
~MysqlQueryResult();
|
||||||
|
|
||||||
|
MYSQL_ROW current_row;
|
||||||
|
MYSQL_RES *result;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
77
database/mysql/mysql_table_builder.cpp
Normal file
77
database/mysql/mysql_table_builder.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include "mysql_table_builder.h"
|
||||||
|
|
||||||
|
TableBuilder *MysqlTableBuilder::create_table(const std::string &name) {
|
||||||
|
result += "CREATE TABLE " + name + " ( ";
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *MysqlTableBuilder::integer(const std::string &name) {
|
||||||
|
result += name + " INTEGER ";
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *MysqlTableBuilder::date(const std::string &name) {
|
||||||
|
result += name + " DATE ";
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *MysqlTableBuilder::varchar(const std::string &name, const int length) {
|
||||||
|
result += name + " VARCHAR(" + std::to_string(length) + ")";
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *MysqlTableBuilder::not_null() {
|
||||||
|
result += "NOT NULL ";
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *MysqlTableBuilder::null() {
|
||||||
|
result += "NULL ";
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *MysqlTableBuilder::auto_increment() {
|
||||||
|
result += "AUTO_INCREMENT ";
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *MysqlTableBuilder::primary_key(const std::string &name) {
|
||||||
|
result += "PRIMARY KEY (" + name + ") ";
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *MysqlTableBuilder::primary_key() {
|
||||||
|
result += "PRIMARY KEY ";
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *MysqlTableBuilder::next_row() {
|
||||||
|
result += ", ";
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MysqlTableBuilder::finalize() {
|
||||||
|
result += ");";
|
||||||
|
}
|
||||||
|
|
||||||
|
TableBuilder *MysqlTableBuilder::drop_table(const std::string &name) {
|
||||||
|
result += "DROP TABLE " + name + ";";
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
MysqlTableBuilder::MysqlTableBuilder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
MysqlTableBuilder::~MysqlTableBuilder() {
|
||||||
|
}
|
29
database/mysql/mysql_table_builder.h
Normal file
29
database/mysql/mysql_table_builder.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef MYSQL_TABLE_BUILDER_H
|
||||||
|
#define MYSQL_TABLE_BUILDER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "core/table_builder.h"
|
||||||
|
|
||||||
|
class MysqlTableBuilder : public TableBuilder {
|
||||||
|
public:
|
||||||
|
TableBuilder *create_table(const std::string &name);
|
||||||
|
TableBuilder *integer(const std::string &name);
|
||||||
|
TableBuilder *date(const std::string &name);
|
||||||
|
TableBuilder *varchar(const std::string &name, const int length);
|
||||||
|
TableBuilder *not_null();
|
||||||
|
TableBuilder *null();
|
||||||
|
TableBuilder *auto_increment();
|
||||||
|
TableBuilder *primary_key(const std::string &name);
|
||||||
|
TableBuilder *primary_key();
|
||||||
|
TableBuilder *next_row();
|
||||||
|
|
||||||
|
TableBuilder *drop_table(const std::string &name);
|
||||||
|
|
||||||
|
void finalize();
|
||||||
|
|
||||||
|
MysqlTableBuilder();
|
||||||
|
virtual ~MysqlTableBuilder();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
12
database/postgres/SCsub
Normal file
12
database/postgres/SCsub
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
Import("env_db")
|
||||||
|
Import("env")
|
||||||
|
|
||||||
|
env_db.core_sources = []
|
||||||
|
|
||||||
|
env_db.add_source_files(env_db.core_sources, "*.cpp")
|
||||||
|
|
||||||
|
# Build it all as a library
|
||||||
|
lib = env_db.add_library("database_pgsql", env_db.core_sources)
|
||||||
|
env.Prepend(LIBS=[lib])
|
55
database/postgres/detect.py
Normal file
55
database/postgres/detect.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def is_active():
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_name():
|
||||||
|
return "pgsql"
|
||||||
|
|
||||||
|
|
||||||
|
def can_build():
|
||||||
|
|
||||||
|
if os.name == "posix" or sys.platform == "darwin":
|
||||||
|
x11_error = os.system("pkg-config --version > /dev/null")
|
||||||
|
if x11_error:
|
||||||
|
return False
|
||||||
|
|
||||||
|
libpg_error = os.system("pkg-config libpq --modversion --silence-errors > /dev/null ")
|
||||||
|
|
||||||
|
if libpg_error:
|
||||||
|
print("postgres not found!")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print("postgres found!")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
#todo
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def get_opts():
|
||||||
|
from SCons.Variables import BoolVariable, EnumVariable
|
||||||
|
|
||||||
|
return [
|
||||||
|
EnumVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", "yes", ("yes", "no")),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_flags():
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def configure(env):
|
||||||
|
env.ParseConfig("pkg-config libpq --cflags --libs")
|
||||||
|
|
||||||
|
env.Append(CPPDEFINES=["PGSQL_PRESENT"])
|
||||||
|
|
||||||
|
# Link those statically for portability
|
||||||
|
#if env["use_static_cpp"]:
|
||||||
|
#env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])
|
15
database/postgres/pgsql_database.cpp
Normal file
15
database/postgres/pgsql_database.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "pgsql_database.h"
|
||||||
|
|
||||||
|
#include "core/database_manager.h"
|
||||||
|
|
||||||
|
Database *PGSQLDatabase::_creation_func() {
|
||||||
|
return new PGSQLDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PGSQLDatabase::_register() {
|
||||||
|
DatabaseManager::_register_db_creation_func("pgsql", PGSQLDatabase::_creation_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PGSQLDatabase::_unregister() {
|
||||||
|
DatabaseManager::_unregister_db_creation_func("pgsql");
|
||||||
|
}
|
33
database/postgres/pgsql_database.h
Normal file
33
database/postgres/pgsql_database.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef PGSQL_CONNECTION
|
||||||
|
#define PGSQL_CONNECTION
|
||||||
|
|
||||||
|
#include "core/database.h"
|
||||||
|
|
||||||
|
//Brynet has it aswell, and because of using namespace it is defined here aswell
|
||||||
|
//later this will be fixed better
|
||||||
|
//#ifdef IS_NUM
|
||||||
|
//#undef IS_NUM
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
#include <libpq-fe.h>
|
||||||
|
|
||||||
|
class PGSQLDatabase : public Database {
|
||||||
|
public:
|
||||||
|
static Database *_creation_func();
|
||||||
|
static void _register();
|
||||||
|
static void _unregister();
|
||||||
|
|
||||||
|
PGSQLDatabase() :
|
||||||
|
Database() {
|
||||||
|
conn = PQconnectStart("");
|
||||||
|
}
|
||||||
|
~PGSQLDatabase() {
|
||||||
|
PQfinish(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
PGconn *conn;
|
||||||
|
};
|
||||||
|
|
||||||
|
//#undef IS_NUM
|
||||||
|
|
||||||
|
#endif
|
13
database/sqlite/SCsub
Normal file
13
database/sqlite/SCsub
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
Import("env_db")
|
||||||
|
Import("env")
|
||||||
|
|
||||||
|
env_db.core_sources = []
|
||||||
|
|
||||||
|
env_db.add_source_files(env_db.core_sources, "*.cpp")
|
||||||
|
env_db.core_sources.append("./sqlite/sqlite3.c")
|
||||||
|
|
||||||
|
# Build it all as a library
|
||||||
|
lib = env_db.add_library("database_pgsql", env_db.core_sources)
|
||||||
|
env.Prepend(LIBS=[lib])
|
58
database/sqlite/detect.py
Normal file
58
database/sqlite/detect.py
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def is_active():
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_name():
|
||||||
|
return "pgsql"
|
||||||
|
|
||||||
|
|
||||||
|
def can_build():
|
||||||
|
|
||||||
|
# if os.name == "posix" or sys.platform == "darwin":
|
||||||
|
# x11_error = os.system("pkg-config --version > /dev/null")
|
||||||
|
# if x11_error:
|
||||||
|
# return False
|
||||||
|
|
||||||
|
# sqlite_error = os.system("pkg-config sqlite3 --modversion --silence-errors > /dev/null ")
|
||||||
|
|
||||||
|
# if sqlite_error:
|
||||||
|
# print("sqlite3 not found!")
|
||||||
|
# return False
|
||||||
|
|
||||||
|
# print("sqlite3 found!")
|
||||||
|
|
||||||
|
# return True
|
||||||
|
|
||||||
|
# #todo
|
||||||
|
# return False
|
||||||
|
|
||||||
|
print("sqlite3 built in!")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def get_opts():
|
||||||
|
from SCons.Variables import BoolVariable, EnumVariable
|
||||||
|
|
||||||
|
return [
|
||||||
|
# EnumVariable("debug_symbols", "Add debugging symbols to release/release_debug builds", "yes", ("yes", "no")),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_flags():
|
||||||
|
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def configure(env):
|
||||||
|
#env.ParseConfig("pkg-config sqlite3 --cflags --libs")
|
||||||
|
|
||||||
|
env.Append(CPPDEFINES=["SQLITE_PRESENT"])
|
||||||
|
|
||||||
|
# Link those statically for portability
|
||||||
|
#if env["use_static_cpp"]:
|
||||||
|
#env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])
|
2635
database/sqlite/sqlite/shell.c
Normal file
2635
database/sqlite/sqlite/shell.c
Normal file
File diff suppressed because it is too large
Load Diff
118686
database/sqlite/sqlite/sqlite3.c
Normal file
118686
database/sqlite/sqlite/sqlite3.c
Normal file
File diff suppressed because it is too large
Load Diff
186
database/sqlite/sqlite/sqlite3.def
Normal file
186
database/sqlite/sqlite/sqlite3.def
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
EXPORTS
|
||||||
|
sqlite3_aggregate_context
|
||||||
|
sqlite3_aggregate_count
|
||||||
|
sqlite3_auto_extension
|
||||||
|
sqlite3_backup_finish
|
||||||
|
sqlite3_backup_init
|
||||||
|
sqlite3_backup_pagecount
|
||||||
|
sqlite3_backup_remaining
|
||||||
|
sqlite3_backup_step
|
||||||
|
sqlite3_bind_blob
|
||||||
|
sqlite3_bind_double
|
||||||
|
sqlite3_bind_int
|
||||||
|
sqlite3_bind_int64
|
||||||
|
sqlite3_bind_null
|
||||||
|
sqlite3_bind_parameter_count
|
||||||
|
sqlite3_bind_parameter_index
|
||||||
|
sqlite3_bind_parameter_name
|
||||||
|
sqlite3_bind_text
|
||||||
|
sqlite3_bind_text16
|
||||||
|
sqlite3_bind_value
|
||||||
|
sqlite3_bind_zeroblob
|
||||||
|
sqlite3_blob_bytes
|
||||||
|
sqlite3_blob_close
|
||||||
|
sqlite3_blob_open
|
||||||
|
sqlite3_blob_read
|
||||||
|
sqlite3_blob_write
|
||||||
|
sqlite3_busy_handler
|
||||||
|
sqlite3_busy_timeout
|
||||||
|
sqlite3_changes
|
||||||
|
sqlite3_clear_bindings
|
||||||
|
sqlite3_close
|
||||||
|
sqlite3_collation_needed
|
||||||
|
sqlite3_collation_needed16
|
||||||
|
sqlite3_column_blob
|
||||||
|
sqlite3_column_bytes
|
||||||
|
sqlite3_column_bytes16
|
||||||
|
sqlite3_column_count
|
||||||
|
sqlite3_column_database_name
|
||||||
|
sqlite3_column_database_name16
|
||||||
|
sqlite3_column_decltype
|
||||||
|
sqlite3_column_decltype16
|
||||||
|
sqlite3_column_double
|
||||||
|
sqlite3_column_int
|
||||||
|
sqlite3_column_int64
|
||||||
|
sqlite3_column_name
|
||||||
|
sqlite3_column_name16
|
||||||
|
sqlite3_column_origin_name
|
||||||
|
sqlite3_column_origin_name16
|
||||||
|
sqlite3_column_table_name
|
||||||
|
sqlite3_column_table_name16
|
||||||
|
sqlite3_column_text
|
||||||
|
sqlite3_column_text16
|
||||||
|
sqlite3_column_type
|
||||||
|
sqlite3_column_value
|
||||||
|
sqlite3_commit_hook
|
||||||
|
sqlite3_compileoption_get
|
||||||
|
sqlite3_compileoption_used
|
||||||
|
sqlite3_complete
|
||||||
|
sqlite3_complete16
|
||||||
|
sqlite3_config
|
||||||
|
sqlite3_context_db_handle
|
||||||
|
sqlite3_create_collation
|
||||||
|
sqlite3_create_collation16
|
||||||
|
sqlite3_create_collation_v2
|
||||||
|
sqlite3_create_function
|
||||||
|
sqlite3_create_function16
|
||||||
|
sqlite3_create_module
|
||||||
|
sqlite3_create_module_v2
|
||||||
|
sqlite3_data_count
|
||||||
|
sqlite3_db_config
|
||||||
|
sqlite3_db_handle
|
||||||
|
sqlite3_db_mutex
|
||||||
|
sqlite3_db_status
|
||||||
|
sqlite3_declare_vtab
|
||||||
|
sqlite3_enable_load_extension
|
||||||
|
sqlite3_enable_shared_cache
|
||||||
|
sqlite3_errcode
|
||||||
|
sqlite3_errmsg
|
||||||
|
sqlite3_errmsg16
|
||||||
|
sqlite3_exec
|
||||||
|
sqlite3_expired
|
||||||
|
sqlite3_extended_errcode
|
||||||
|
sqlite3_extended_result_codes
|
||||||
|
sqlite3_file_control
|
||||||
|
sqlite3_finalize
|
||||||
|
sqlite3_free
|
||||||
|
sqlite3_free_table
|
||||||
|
sqlite3_get_autocommit
|
||||||
|
sqlite3_get_auxdata
|
||||||
|
sqlite3_get_table
|
||||||
|
sqlite3_global_recover
|
||||||
|
sqlite3_initialize
|
||||||
|
sqlite3_interrupt
|
||||||
|
sqlite3_last_insert_rowid
|
||||||
|
sqlite3_libversion
|
||||||
|
sqlite3_libversion_number
|
||||||
|
sqlite3_limit
|
||||||
|
sqlite3_load_extension
|
||||||
|
sqlite3_log
|
||||||
|
sqlite3_malloc
|
||||||
|
sqlite3_memory_alarm
|
||||||
|
sqlite3_memory_highwater
|
||||||
|
sqlite3_memory_used
|
||||||
|
sqlite3_mprintf
|
||||||
|
sqlite3_mutex_alloc
|
||||||
|
sqlite3_mutex_enter
|
||||||
|
sqlite3_mutex_free
|
||||||
|
sqlite3_mutex_leave
|
||||||
|
sqlite3_mutex_try
|
||||||
|
sqlite3_next_stmt
|
||||||
|
sqlite3_open
|
||||||
|
sqlite3_open16
|
||||||
|
sqlite3_open_v2
|
||||||
|
sqlite3_os_end
|
||||||
|
sqlite3_os_init
|
||||||
|
sqlite3_overload_function
|
||||||
|
sqlite3_prepare
|
||||||
|
sqlite3_prepare16
|
||||||
|
sqlite3_prepare16_v2
|
||||||
|
sqlite3_prepare_v2
|
||||||
|
sqlite3_profile
|
||||||
|
sqlite3_progress_handler
|
||||||
|
sqlite3_randomness
|
||||||
|
sqlite3_realloc
|
||||||
|
sqlite3_release_memory
|
||||||
|
sqlite3_reset
|
||||||
|
sqlite3_reset_auto_extension
|
||||||
|
sqlite3_result_blob
|
||||||
|
sqlite3_result_double
|
||||||
|
sqlite3_result_error
|
||||||
|
sqlite3_result_error16
|
||||||
|
sqlite3_result_error_code
|
||||||
|
sqlite3_result_error_nomem
|
||||||
|
sqlite3_result_error_toobig
|
||||||
|
sqlite3_result_int
|
||||||
|
sqlite3_result_int64
|
||||||
|
sqlite3_result_null
|
||||||
|
sqlite3_result_text
|
||||||
|
sqlite3_result_text16
|
||||||
|
sqlite3_result_text16be
|
||||||
|
sqlite3_result_text16le
|
||||||
|
sqlite3_result_value
|
||||||
|
sqlite3_result_zeroblob
|
||||||
|
sqlite3_rollback_hook
|
||||||
|
sqlite3_set_authorizer
|
||||||
|
sqlite3_set_auxdata
|
||||||
|
sqlite3_shutdown
|
||||||
|
sqlite3_sleep
|
||||||
|
sqlite3_snprintf
|
||||||
|
sqlite3_soft_heap_limit
|
||||||
|
sqlite3_sourceid
|
||||||
|
sqlite3_sql
|
||||||
|
sqlite3_status
|
||||||
|
sqlite3_step
|
||||||
|
sqlite3_stmt_status
|
||||||
|
sqlite3_strnicmp
|
||||||
|
sqlite3_table_column_metadata
|
||||||
|
sqlite3_test_control
|
||||||
|
sqlite3_thread_cleanup
|
||||||
|
sqlite3_threadsafe
|
||||||
|
sqlite3_total_changes
|
||||||
|
sqlite3_trace
|
||||||
|
sqlite3_transfer_bindings
|
||||||
|
sqlite3_update_hook
|
||||||
|
sqlite3_user_data
|
||||||
|
sqlite3_value_blob
|
||||||
|
sqlite3_value_bytes
|
||||||
|
sqlite3_value_bytes16
|
||||||
|
sqlite3_value_double
|
||||||
|
sqlite3_value_int
|
||||||
|
sqlite3_value_int64
|
||||||
|
sqlite3_value_numeric_type
|
||||||
|
sqlite3_value_text
|
||||||
|
sqlite3_value_text16
|
||||||
|
sqlite3_value_text16be
|
||||||
|
sqlite3_value_text16le
|
||||||
|
sqlite3_value_type
|
||||||
|
sqlite3_version
|
||||||
|
sqlite3_vfs_find
|
||||||
|
sqlite3_vfs_register
|
||||||
|
sqlite3_vfs_unregister
|
||||||
|
sqlite3_vmprintf
|
||||||
|
sqlite3_wal_autocheckpoint
|
||||||
|
sqlite3_wal_checkpoint
|
||||||
|
sqlite3_wal_hook
|
||||||
|
sqlite3_win32_mbcs_to_utf8
|
5915
database/sqlite/sqlite/sqlite3.h
Normal file
5915
database/sqlite/sqlite/sqlite3.h
Normal file
File diff suppressed because it is too large
Load Diff
378
database/sqlite/sqlite/sqlite3ext.h
Normal file
378
database/sqlite/sqlite/sqlite3ext.h
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
/*
|
||||||
|
** 2006 June 7
|
||||||
|
**
|
||||||
|
** The author disclaims copyright to this source code. In place of
|
||||||
|
** a legal notice, here is a blessing:
|
||||||
|
**
|
||||||
|
** May you do good and not evil.
|
||||||
|
** May you find forgiveness for yourself and forgive others.
|
||||||
|
** May you share freely, never taking more than you give.
|
||||||
|
**
|
||||||
|
*************************************************************************
|
||||||
|
** This header file defines the SQLite interface for use by
|
||||||
|
** shared libraries that want to be imported as extensions into
|
||||||
|
** an SQLite instance. Shared libraries that intend to be loaded
|
||||||
|
** as extensions by SQLite should #include this file instead of
|
||||||
|
** sqlite3.h.
|
||||||
|
*/
|
||||||
|
#ifndef _SQLITE3EXT_H_
|
||||||
|
#define _SQLITE3EXT_H_
|
||||||
|
#include "sqlite3.h"
|
||||||
|
|
||||||
|
typedef struct sqlite3_api_routines sqlite3_api_routines;
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following structure holds pointers to all of the SQLite API
|
||||||
|
** routines.
|
||||||
|
**
|
||||||
|
** WARNING: In order to maintain backwards compatibility, add new
|
||||||
|
** interfaces to the end of this structure only. If you insert new
|
||||||
|
** interfaces in the middle of this structure, then older different
|
||||||
|
** versions of SQLite will not be able to load each others' shared
|
||||||
|
** libraries!
|
||||||
|
*/
|
||||||
|
struct sqlite3_api_routines {
|
||||||
|
void * (*aggregate_context)(sqlite3_context*,int nBytes);
|
||||||
|
int (*aggregate_count)(sqlite3_context*);
|
||||||
|
int (*bind_blob)(sqlite3_stmt*,int,const void*,int n,void(*)(void*));
|
||||||
|
int (*bind_double)(sqlite3_stmt*,int,double);
|
||||||
|
int (*bind_int)(sqlite3_stmt*,int,int);
|
||||||
|
int (*bind_int64)(sqlite3_stmt*,int,sqlite_int64);
|
||||||
|
int (*bind_null)(sqlite3_stmt*,int);
|
||||||
|
int (*bind_parameter_count)(sqlite3_stmt*);
|
||||||
|
int (*bind_parameter_index)(sqlite3_stmt*,const char*zName);
|
||||||
|
const char * (*bind_parameter_name)(sqlite3_stmt*,int);
|
||||||
|
int (*bind_text)(sqlite3_stmt*,int,const char*,int n,void(*)(void*));
|
||||||
|
int (*bind_text16)(sqlite3_stmt*,int,const void*,int,void(*)(void*));
|
||||||
|
int (*bind_value)(sqlite3_stmt*,int,const sqlite3_value*);
|
||||||
|
int (*busy_handler)(sqlite3*,int(*)(void*,int),void*);
|
||||||
|
int (*busy_timeout)(sqlite3*,int ms);
|
||||||
|
int (*changes)(sqlite3*);
|
||||||
|
int (*close)(sqlite3*);
|
||||||
|
int (*collation_needed)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const char*));
|
||||||
|
int (*collation_needed16)(sqlite3*,void*,void(*)(void*,sqlite3*,int eTextRep,const void*));
|
||||||
|
const void * (*column_blob)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_bytes)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_bytes16)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_count)(sqlite3_stmt*pStmt);
|
||||||
|
const char * (*column_database_name)(sqlite3_stmt*,int);
|
||||||
|
const void * (*column_database_name16)(sqlite3_stmt*,int);
|
||||||
|
const char * (*column_decltype)(sqlite3_stmt*,int i);
|
||||||
|
const void * (*column_decltype16)(sqlite3_stmt*,int);
|
||||||
|
double (*column_double)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_int)(sqlite3_stmt*,int iCol);
|
||||||
|
sqlite_int64 (*column_int64)(sqlite3_stmt*,int iCol);
|
||||||
|
const char * (*column_name)(sqlite3_stmt*,int);
|
||||||
|
const void * (*column_name16)(sqlite3_stmt*,int);
|
||||||
|
const char * (*column_origin_name)(sqlite3_stmt*,int);
|
||||||
|
const void * (*column_origin_name16)(sqlite3_stmt*,int);
|
||||||
|
const char * (*column_table_name)(sqlite3_stmt*,int);
|
||||||
|
const void * (*column_table_name16)(sqlite3_stmt*,int);
|
||||||
|
const unsigned char * (*column_text)(sqlite3_stmt*,int iCol);
|
||||||
|
const void * (*column_text16)(sqlite3_stmt*,int iCol);
|
||||||
|
int (*column_type)(sqlite3_stmt*,int iCol);
|
||||||
|
sqlite3_value* (*column_value)(sqlite3_stmt*,int iCol);
|
||||||
|
void * (*commit_hook)(sqlite3*,int(*)(void*),void*);
|
||||||
|
int (*complete)(const char*sql);
|
||||||
|
int (*complete16)(const void*sql);
|
||||||
|
int (*create_collation)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*));
|
||||||
|
int (*create_collation16)(sqlite3*,const void*,int,void*,int(*)(void*,int,const void*,int,const void*));
|
||||||
|
int (*create_function)(sqlite3*,const char*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
|
||||||
|
int (*create_function16)(sqlite3*,const void*,int,int,void*,void (*xFunc)(sqlite3_context*,int,sqlite3_value**),void (*xStep)(sqlite3_context*,int,sqlite3_value**),void (*xFinal)(sqlite3_context*));
|
||||||
|
int (*create_module)(sqlite3*,const char*,const sqlite3_module*,void*);
|
||||||
|
int (*data_count)(sqlite3_stmt*pStmt);
|
||||||
|
sqlite3 * (*db_handle)(sqlite3_stmt*);
|
||||||
|
int (*declare_vtab)(sqlite3*,const char*);
|
||||||
|
int (*enable_shared_cache)(int);
|
||||||
|
int (*errcode)(sqlite3*db);
|
||||||
|
const char * (*errmsg)(sqlite3*);
|
||||||
|
const void * (*errmsg16)(sqlite3*);
|
||||||
|
int (*exec)(sqlite3*,const char*,sqlite3_callback,void*,char**);
|
||||||
|
int (*expired)(sqlite3_stmt*);
|
||||||
|
int (*finalize)(sqlite3_stmt*pStmt);
|
||||||
|
void (*free)(void*);
|
||||||
|
void (*free_table)(char**result);
|
||||||
|
int (*get_autocommit)(sqlite3*);
|
||||||
|
void * (*get_auxdata)(sqlite3_context*,int);
|
||||||
|
int (*get_table)(sqlite3*,const char*,char***,int*,int*,char**);
|
||||||
|
int (*global_recover)(void);
|
||||||
|
void (*interruptx)(sqlite3*);
|
||||||
|
sqlite_int64 (*last_insert_rowid)(sqlite3*);
|
||||||
|
const char * (*libversion)(void);
|
||||||
|
int (*libversion_number)(void);
|
||||||
|
void *(*malloc)(int);
|
||||||
|
char * (*mprintf)(const char*,...);
|
||||||
|
int (*open)(const char*,sqlite3**);
|
||||||
|
int (*open16)(const void*,sqlite3**);
|
||||||
|
int (*prepare)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||||
|
int (*prepare16)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||||
|
void * (*profile)(sqlite3*,void(*)(void*,const char*,sqlite_uint64),void*);
|
||||||
|
void (*progress_handler)(sqlite3*,int,int(*)(void*),void*);
|
||||||
|
void *(*realloc)(void*,int);
|
||||||
|
int (*reset)(sqlite3_stmt*pStmt);
|
||||||
|
void (*result_blob)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||||
|
void (*result_double)(sqlite3_context*,double);
|
||||||
|
void (*result_error)(sqlite3_context*,const char*,int);
|
||||||
|
void (*result_error16)(sqlite3_context*,const void*,int);
|
||||||
|
void (*result_int)(sqlite3_context*,int);
|
||||||
|
void (*result_int64)(sqlite3_context*,sqlite_int64);
|
||||||
|
void (*result_null)(sqlite3_context*);
|
||||||
|
void (*result_text)(sqlite3_context*,const char*,int,void(*)(void*));
|
||||||
|
void (*result_text16)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||||
|
void (*result_text16be)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||||
|
void (*result_text16le)(sqlite3_context*,const void*,int,void(*)(void*));
|
||||||
|
void (*result_value)(sqlite3_context*,sqlite3_value*);
|
||||||
|
void * (*rollback_hook)(sqlite3*,void(*)(void*),void*);
|
||||||
|
int (*set_authorizer)(sqlite3*,int(*)(void*,int,const char*,const char*,const char*,const char*),void*);
|
||||||
|
void (*set_auxdata)(sqlite3_context*,int,void*,void (*)(void*));
|
||||||
|
char * (*snprintf)(int,char*,const char*,...);
|
||||||
|
int (*step)(sqlite3_stmt*);
|
||||||
|
int (*table_column_metadata)(sqlite3*,const char*,const char*,const char*,char const**,char const**,int*,int*,int*);
|
||||||
|
void (*thread_cleanup)(void);
|
||||||
|
int (*total_changes)(sqlite3*);
|
||||||
|
void * (*trace)(sqlite3*,void(*xTrace)(void*,const char*),void*);
|
||||||
|
int (*transfer_bindings)(sqlite3_stmt*,sqlite3_stmt*);
|
||||||
|
void * (*update_hook)(sqlite3*,void(*)(void*,int ,char const*,char const*,sqlite_int64),void*);
|
||||||
|
void * (*user_data)(sqlite3_context*);
|
||||||
|
const void * (*value_blob)(sqlite3_value*);
|
||||||
|
int (*value_bytes)(sqlite3_value*);
|
||||||
|
int (*value_bytes16)(sqlite3_value*);
|
||||||
|
double (*value_double)(sqlite3_value*);
|
||||||
|
int (*value_int)(sqlite3_value*);
|
||||||
|
sqlite_int64 (*value_int64)(sqlite3_value*);
|
||||||
|
int (*value_numeric_type)(sqlite3_value*);
|
||||||
|
const unsigned char * (*value_text)(sqlite3_value*);
|
||||||
|
const void * (*value_text16)(sqlite3_value*);
|
||||||
|
const void * (*value_text16be)(sqlite3_value*);
|
||||||
|
const void * (*value_text16le)(sqlite3_value*);
|
||||||
|
int (*value_type)(sqlite3_value*);
|
||||||
|
char *(*vmprintf)(const char*,va_list);
|
||||||
|
/* Added ??? */
|
||||||
|
int (*overload_function)(sqlite3*, const char *zFuncName, int nArg);
|
||||||
|
/* Added by 3.3.13 */
|
||||||
|
int (*prepare_v2)(sqlite3*,const char*,int,sqlite3_stmt**,const char**);
|
||||||
|
int (*prepare16_v2)(sqlite3*,const void*,int,sqlite3_stmt**,const void**);
|
||||||
|
int (*clear_bindings)(sqlite3_stmt*);
|
||||||
|
/* Added by 3.4.1 */
|
||||||
|
int (*create_module_v2)(sqlite3*,const char*,const sqlite3_module*,void*,void (*xDestroy)(void *));
|
||||||
|
/* Added by 3.5.0 */
|
||||||
|
int (*bind_zeroblob)(sqlite3_stmt*,int,int);
|
||||||
|
int (*blob_bytes)(sqlite3_blob*);
|
||||||
|
int (*blob_close)(sqlite3_blob*);
|
||||||
|
int (*blob_open)(sqlite3*,const char*,const char*,const char*,sqlite3_int64,int,sqlite3_blob**);
|
||||||
|
int (*blob_read)(sqlite3_blob*,void*,int,int);
|
||||||
|
int (*blob_write)(sqlite3_blob*,const void*,int,int);
|
||||||
|
int (*create_collation_v2)(sqlite3*,const char*,int,void*,int(*)(void*,int,const void*,int,const void*),void(*)(void*));
|
||||||
|
int (*file_control)(sqlite3*,const char*,int,void*);
|
||||||
|
sqlite3_int64 (*memory_highwater)(int);
|
||||||
|
sqlite3_int64 (*memory_used)(void);
|
||||||
|
sqlite3_mutex *(*mutex_alloc)(int);
|
||||||
|
void (*mutex_enter)(sqlite3_mutex*);
|
||||||
|
void (*mutex_free)(sqlite3_mutex*);
|
||||||
|
void (*mutex_leave)(sqlite3_mutex*);
|
||||||
|
int (*mutex_try)(sqlite3_mutex*);
|
||||||
|
int (*open_v2)(const char*,sqlite3**,int,const char*);
|
||||||
|
int (*release_memory)(int);
|
||||||
|
void (*result_error_nomem)(sqlite3_context*);
|
||||||
|
void (*result_error_toobig)(sqlite3_context*);
|
||||||
|
int (*sleep)(int);
|
||||||
|
void (*soft_heap_limit)(int);
|
||||||
|
sqlite3_vfs *(*vfs_find)(const char*);
|
||||||
|
int (*vfs_register)(sqlite3_vfs*,int);
|
||||||
|
int (*vfs_unregister)(sqlite3_vfs*);
|
||||||
|
int (*xthreadsafe)(void);
|
||||||
|
void (*result_zeroblob)(sqlite3_context*,int);
|
||||||
|
void (*result_error_code)(sqlite3_context*,int);
|
||||||
|
int (*test_control)(int, ...);
|
||||||
|
void (*randomness)(int,void*);
|
||||||
|
sqlite3 *(*context_db_handle)(sqlite3_context*);
|
||||||
|
int (*extended_result_codes)(sqlite3*,int);
|
||||||
|
int (*limit)(sqlite3*,int,int);
|
||||||
|
sqlite3_stmt *(*next_stmt)(sqlite3*,sqlite3_stmt*);
|
||||||
|
const char *(*sql)(sqlite3_stmt*);
|
||||||
|
int (*status)(int,int*,int*,int);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
** The following macros redefine the API routines so that they are
|
||||||
|
** redirected throught the global sqlite3_api structure.
|
||||||
|
**
|
||||||
|
** This header file is also used by the loadext.c source file
|
||||||
|
** (part of the main SQLite library - not an extension) so that
|
||||||
|
** it can get access to the sqlite3_api_routines structure
|
||||||
|
** definition. But the main library does not want to redefine
|
||||||
|
** the API. So the redefinition macros are only valid if the
|
||||||
|
** SQLITE_CORE macros is undefined.
|
||||||
|
*/
|
||||||
|
#ifndef SQLITE_CORE
|
||||||
|
#define sqlite3_aggregate_context sqlite3_api->aggregate_context
|
||||||
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
|
#define sqlite3_aggregate_count sqlite3_api->aggregate_count
|
||||||
|
#endif
|
||||||
|
#define sqlite3_bind_blob sqlite3_api->bind_blob
|
||||||
|
#define sqlite3_bind_double sqlite3_api->bind_double
|
||||||
|
#define sqlite3_bind_int sqlite3_api->bind_int
|
||||||
|
#define sqlite3_bind_int64 sqlite3_api->bind_int64
|
||||||
|
#define sqlite3_bind_null sqlite3_api->bind_null
|
||||||
|
#define sqlite3_bind_parameter_count sqlite3_api->bind_parameter_count
|
||||||
|
#define sqlite3_bind_parameter_index sqlite3_api->bind_parameter_index
|
||||||
|
#define sqlite3_bind_parameter_name sqlite3_api->bind_parameter_name
|
||||||
|
#define sqlite3_bind_text sqlite3_api->bind_text
|
||||||
|
#define sqlite3_bind_text16 sqlite3_api->bind_text16
|
||||||
|
#define sqlite3_bind_value sqlite3_api->bind_value
|
||||||
|
#define sqlite3_busy_handler sqlite3_api->busy_handler
|
||||||
|
#define sqlite3_busy_timeout sqlite3_api->busy_timeout
|
||||||
|
#define sqlite3_changes sqlite3_api->changes
|
||||||
|
#define sqlite3_close sqlite3_api->close
|
||||||
|
#define sqlite3_collation_needed sqlite3_api->collation_needed
|
||||||
|
#define sqlite3_collation_needed16 sqlite3_api->collation_needed16
|
||||||
|
#define sqlite3_column_blob sqlite3_api->column_blob
|
||||||
|
#define sqlite3_column_bytes sqlite3_api->column_bytes
|
||||||
|
#define sqlite3_column_bytes16 sqlite3_api->column_bytes16
|
||||||
|
#define sqlite3_column_count sqlite3_api->column_count
|
||||||
|
#define sqlite3_column_database_name sqlite3_api->column_database_name
|
||||||
|
#define sqlite3_column_database_name16 sqlite3_api->column_database_name16
|
||||||
|
#define sqlite3_column_decltype sqlite3_api->column_decltype
|
||||||
|
#define sqlite3_column_decltype16 sqlite3_api->column_decltype16
|
||||||
|
#define sqlite3_column_double sqlite3_api->column_double
|
||||||
|
#define sqlite3_column_int sqlite3_api->column_int
|
||||||
|
#define sqlite3_column_int64 sqlite3_api->column_int64
|
||||||
|
#define sqlite3_column_name sqlite3_api->column_name
|
||||||
|
#define sqlite3_column_name16 sqlite3_api->column_name16
|
||||||
|
#define sqlite3_column_origin_name sqlite3_api->column_origin_name
|
||||||
|
#define sqlite3_column_origin_name16 sqlite3_api->column_origin_name16
|
||||||
|
#define sqlite3_column_table_name sqlite3_api->column_table_name
|
||||||
|
#define sqlite3_column_table_name16 sqlite3_api->column_table_name16
|
||||||
|
#define sqlite3_column_text sqlite3_api->column_text
|
||||||
|
#define sqlite3_column_text16 sqlite3_api->column_text16
|
||||||
|
#define sqlite3_column_type sqlite3_api->column_type
|
||||||
|
#define sqlite3_column_value sqlite3_api->column_value
|
||||||
|
#define sqlite3_commit_hook sqlite3_api->commit_hook
|
||||||
|
#define sqlite3_complete sqlite3_api->complete
|
||||||
|
#define sqlite3_complete16 sqlite3_api->complete16
|
||||||
|
#define sqlite3_create_collation sqlite3_api->create_collation
|
||||||
|
#define sqlite3_create_collation16 sqlite3_api->create_collation16
|
||||||
|
#define sqlite3_create_function sqlite3_api->create_function
|
||||||
|
#define sqlite3_create_function16 sqlite3_api->create_function16
|
||||||
|
#define sqlite3_create_module sqlite3_api->create_module
|
||||||
|
#define sqlite3_create_module_v2 sqlite3_api->create_module_v2
|
||||||
|
#define sqlite3_data_count sqlite3_api->data_count
|
||||||
|
#define sqlite3_db_handle sqlite3_api->db_handle
|
||||||
|
#define sqlite3_declare_vtab sqlite3_api->declare_vtab
|
||||||
|
#define sqlite3_enable_shared_cache sqlite3_api->enable_shared_cache
|
||||||
|
#define sqlite3_errcode sqlite3_api->errcode
|
||||||
|
#define sqlite3_errmsg sqlite3_api->errmsg
|
||||||
|
#define sqlite3_errmsg16 sqlite3_api->errmsg16
|
||||||
|
#define sqlite3_exec sqlite3_api->exec
|
||||||
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
|
#define sqlite3_expired sqlite3_api->expired
|
||||||
|
#endif
|
||||||
|
#define sqlite3_finalize sqlite3_api->finalize
|
||||||
|
#define sqlite3_free sqlite3_api->free
|
||||||
|
#define sqlite3_free_table sqlite3_api->free_table
|
||||||
|
#define sqlite3_get_autocommit sqlite3_api->get_autocommit
|
||||||
|
#define sqlite3_get_auxdata sqlite3_api->get_auxdata
|
||||||
|
#define sqlite3_get_table sqlite3_api->get_table
|
||||||
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
|
#define sqlite3_global_recover sqlite3_api->global_recover
|
||||||
|
#endif
|
||||||
|
#define sqlite3_interrupt sqlite3_api->interruptx
|
||||||
|
#define sqlite3_last_insert_rowid sqlite3_api->last_insert_rowid
|
||||||
|
#define sqlite3_libversion sqlite3_api->libversion
|
||||||
|
#define sqlite3_libversion_number sqlite3_api->libversion_number
|
||||||
|
#define sqlite3_malloc sqlite3_api->malloc
|
||||||
|
#define sqlite3_mprintf sqlite3_api->mprintf
|
||||||
|
#define sqlite3_open sqlite3_api->open
|
||||||
|
#define sqlite3_open16 sqlite3_api->open16
|
||||||
|
#define sqlite3_prepare sqlite3_api->prepare
|
||||||
|
#define sqlite3_prepare16 sqlite3_api->prepare16
|
||||||
|
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||||
|
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||||
|
#define sqlite3_profile sqlite3_api->profile
|
||||||
|
#define sqlite3_progress_handler sqlite3_api->progress_handler
|
||||||
|
#define sqlite3_realloc sqlite3_api->realloc
|
||||||
|
#define sqlite3_reset sqlite3_api->reset
|
||||||
|
#define sqlite3_result_blob sqlite3_api->result_blob
|
||||||
|
#define sqlite3_result_double sqlite3_api->result_double
|
||||||
|
#define sqlite3_result_error sqlite3_api->result_error
|
||||||
|
#define sqlite3_result_error16 sqlite3_api->result_error16
|
||||||
|
#define sqlite3_result_int sqlite3_api->result_int
|
||||||
|
#define sqlite3_result_int64 sqlite3_api->result_int64
|
||||||
|
#define sqlite3_result_null sqlite3_api->result_null
|
||||||
|
#define sqlite3_result_text sqlite3_api->result_text
|
||||||
|
#define sqlite3_result_text16 sqlite3_api->result_text16
|
||||||
|
#define sqlite3_result_text16be sqlite3_api->result_text16be
|
||||||
|
#define sqlite3_result_text16le sqlite3_api->result_text16le
|
||||||
|
#define sqlite3_result_value sqlite3_api->result_value
|
||||||
|
#define sqlite3_rollback_hook sqlite3_api->rollback_hook
|
||||||
|
#define sqlite3_set_authorizer sqlite3_api->set_authorizer
|
||||||
|
#define sqlite3_set_auxdata sqlite3_api->set_auxdata
|
||||||
|
#define sqlite3_snprintf sqlite3_api->snprintf
|
||||||
|
#define sqlite3_step sqlite3_api->step
|
||||||
|
#define sqlite3_table_column_metadata sqlite3_api->table_column_metadata
|
||||||
|
#define sqlite3_thread_cleanup sqlite3_api->thread_cleanup
|
||||||
|
#define sqlite3_total_changes sqlite3_api->total_changes
|
||||||
|
#define sqlite3_trace sqlite3_api->trace
|
||||||
|
#ifndef SQLITE_OMIT_DEPRECATED
|
||||||
|
#define sqlite3_transfer_bindings sqlite3_api->transfer_bindings
|
||||||
|
#endif
|
||||||
|
#define sqlite3_update_hook sqlite3_api->update_hook
|
||||||
|
#define sqlite3_user_data sqlite3_api->user_data
|
||||||
|
#define sqlite3_value_blob sqlite3_api->value_blob
|
||||||
|
#define sqlite3_value_bytes sqlite3_api->value_bytes
|
||||||
|
#define sqlite3_value_bytes16 sqlite3_api->value_bytes16
|
||||||
|
#define sqlite3_value_double sqlite3_api->value_double
|
||||||
|
#define sqlite3_value_int sqlite3_api->value_int
|
||||||
|
#define sqlite3_value_int64 sqlite3_api->value_int64
|
||||||
|
#define sqlite3_value_numeric_type sqlite3_api->value_numeric_type
|
||||||
|
#define sqlite3_value_text sqlite3_api->value_text
|
||||||
|
#define sqlite3_value_text16 sqlite3_api->value_text16
|
||||||
|
#define sqlite3_value_text16be sqlite3_api->value_text16be
|
||||||
|
#define sqlite3_value_text16le sqlite3_api->value_text16le
|
||||||
|
#define sqlite3_value_type sqlite3_api->value_type
|
||||||
|
#define sqlite3_vmprintf sqlite3_api->vmprintf
|
||||||
|
#define sqlite3_overload_function sqlite3_api->overload_function
|
||||||
|
#define sqlite3_prepare_v2 sqlite3_api->prepare_v2
|
||||||
|
#define sqlite3_prepare16_v2 sqlite3_api->prepare16_v2
|
||||||
|
#define sqlite3_clear_bindings sqlite3_api->clear_bindings
|
||||||
|
#define sqlite3_bind_zeroblob sqlite3_api->bind_zeroblob
|
||||||
|
#define sqlite3_blob_bytes sqlite3_api->blob_bytes
|
||||||
|
#define sqlite3_blob_close sqlite3_api->blob_close
|
||||||
|
#define sqlite3_blob_open sqlite3_api->blob_open
|
||||||
|
#define sqlite3_blob_read sqlite3_api->blob_read
|
||||||
|
#define sqlite3_blob_write sqlite3_api->blob_write
|
||||||
|
#define sqlite3_create_collation_v2 sqlite3_api->create_collation_v2
|
||||||
|
#define sqlite3_file_control sqlite3_api->file_control
|
||||||
|
#define sqlite3_memory_highwater sqlite3_api->memory_highwater
|
||||||
|
#define sqlite3_memory_used sqlite3_api->memory_used
|
||||||
|
#define sqlite3_mutex_alloc sqlite3_api->mutex_alloc
|
||||||
|
#define sqlite3_mutex_enter sqlite3_api->mutex_enter
|
||||||
|
#define sqlite3_mutex_free sqlite3_api->mutex_free
|
||||||
|
#define sqlite3_mutex_leave sqlite3_api->mutex_leave
|
||||||
|
#define sqlite3_mutex_try sqlite3_api->mutex_try
|
||||||
|
#define sqlite3_open_v2 sqlite3_api->open_v2
|
||||||
|
#define sqlite3_release_memory sqlite3_api->release_memory
|
||||||
|
#define sqlite3_result_error_nomem sqlite3_api->result_error_nomem
|
||||||
|
#define sqlite3_result_error_toobig sqlite3_api->result_error_toobig
|
||||||
|
#define sqlite3_sleep sqlite3_api->sleep
|
||||||
|
#define sqlite3_soft_heap_limit sqlite3_api->soft_heap_limit
|
||||||
|
#define sqlite3_vfs_find sqlite3_api->vfs_find
|
||||||
|
#define sqlite3_vfs_register sqlite3_api->vfs_register
|
||||||
|
#define sqlite3_vfs_unregister sqlite3_api->vfs_unregister
|
||||||
|
#define sqlite3_threadsafe sqlite3_api->xthreadsafe
|
||||||
|
#define sqlite3_result_zeroblob sqlite3_api->result_zeroblob
|
||||||
|
#define sqlite3_result_error_code sqlite3_api->result_error_code
|
||||||
|
#define sqlite3_test_control sqlite3_api->test_control
|
||||||
|
#define sqlite3_randomness sqlite3_api->randomness
|
||||||
|
#define sqlite3_context_db_handle sqlite3_api->context_db_handle
|
||||||
|
#define sqlite3_extended_result_codes sqlite3_api->extended_result_codes
|
||||||
|
#define sqlite3_limit sqlite3_api->limit
|
||||||
|
#define sqlite3_next_stmt sqlite3_api->next_stmt
|
||||||
|
#define sqlite3_sql sqlite3_api->sql
|
||||||
|
#define sqlite3_status sqlite3_api->status
|
||||||
|
#endif /* SQLITE_CORE */
|
||||||
|
|
||||||
|
#define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api = 0;
|
||||||
|
#define SQLITE_EXTENSION_INIT2(v) sqlite3_api = v;
|
||||||
|
|
||||||
|
#endif /* _SQLITE3EXT_H_ */
|
15
database/sqlite/sqlite3_database.cpp
Normal file
15
database/sqlite/sqlite3_database.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "sqlite3_database.h"
|
||||||
|
|
||||||
|
#include "core/database_manager.h"
|
||||||
|
|
||||||
|
Database *SQLite3Database::_creation_func() {
|
||||||
|
return new SQLite3Database();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SQLite3Database::_register() {
|
||||||
|
DatabaseManager::_register_db_creation_func("sqlite", SQLite3Database::_creation_func);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SQLite3Database::_unregister() {
|
||||||
|
DatabaseManager::_unregister_db_creation_func("sqlite");
|
||||||
|
}
|
42
database/sqlite/sqlite3_database.h
Normal file
42
database/sqlite/sqlite3_database.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef SQLITE3_CONNECTION
|
||||||
|
#define SQLITE3_CONNECTION
|
||||||
|
|
||||||
|
#include "core/database.h"
|
||||||
|
|
||||||
|
//Brynet has it aswell, and because of using namespace it is defined here aswell
|
||||||
|
//later this will be fixed better
|
||||||
|
//#ifdef IS_NUM
|
||||||
|
//#undef IS_NUM
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
class SQLite3Database : public Database {
|
||||||
|
public:
|
||||||
|
static Database *_creation_func();
|
||||||
|
static void _register();
|
||||||
|
static void _unregister();
|
||||||
|
|
||||||
|
SQLite3Database() :
|
||||||
|
Database() {
|
||||||
|
|
||||||
|
int ret = sqlite3_config(SQLITE_CONFIG_MULTITHREAD);
|
||||||
|
if (ret != SQLITE_OK) {
|
||||||
|
printf("SQLITE3 multithreading is not supported!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sqlite3_open("", &conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
~SQLite3Database() {
|
||||||
|
sqlite3_close(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
sqlite3 *conn;
|
||||||
|
};
|
||||||
|
|
||||||
|
//#undef IS_NUM
|
||||||
|
|
||||||
|
#endif
|
3
libs/HEADS
Normal file
3
libs/HEADS
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
RapidJSON 0ccdbf364c577803e2a751f5aededce935314313
|
||||||
|
brynet b0d13e7419628d0f7051a2bb310daaf8a506e08b
|
||||||
|
rapidxml 1.13
|
21
libs/brynet/LICENSE
Normal file
21
libs/brynet/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2017 IronsDu
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
3
libs/brynet/Version.hpp
Normal file
3
libs/brynet/Version.hpp
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define BRYNET_VERSION 1008000
|
30
libs/brynet/base/Any.hpp
Normal file
30
libs/brynet/base/Any.hpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <brynet/base/CPP_VERSION.hpp>
|
||||||
|
|
||||||
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||||
|
#include <any>
|
||||||
|
#else
|
||||||
|
#include <cstdint>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace brynet { namespace base {
|
||||||
|
|
||||||
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||||
|
using BrynetAny = std::any;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
auto cast(const BrynetAny& ud)
|
||||||
|
{
|
||||||
|
return std::any_cast<T>(&ud);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
using BrynetAny = int64_t;
|
||||||
|
template<typename T>
|
||||||
|
const T* cast(const BrynetAny& ud)
|
||||||
|
{
|
||||||
|
return static_cast<const T*>(&ud);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} }
|
47
libs/brynet/base/AppStatus.hpp
Normal file
47
libs/brynet/base/AppStatus.hpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdbool>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <brynet/base/Platform.hpp>
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
#include <conio.h>
|
||||||
|
#else
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace brynet { namespace base {
|
||||||
|
|
||||||
|
static bool app_kbhit()
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
return _kbhit();
|
||||||
|
#else
|
||||||
|
struct termios oldt;
|
||||||
|
tcgetattr(STDIN_FILENO, &oldt);
|
||||||
|
auto newt = oldt;
|
||||||
|
newt.c_lflag &= ~(ICANON | ECHO);
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
|
||||||
|
const auto oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
|
||||||
|
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
|
||||||
|
|
||||||
|
const auto ch = getchar();
|
||||||
|
|
||||||
|
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
|
||||||
|
fcntl(STDIN_FILENO, F_SETFL, oldf);
|
||||||
|
|
||||||
|
if (ch != EOF)
|
||||||
|
{
|
||||||
|
ungetc(ch, stdin);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} }
|
129
libs/brynet/base/Array.hpp
Normal file
129
libs/brynet/base/Array.hpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdbool>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace brynet { namespace base {
|
||||||
|
|
||||||
|
struct array_s
|
||||||
|
{
|
||||||
|
void* buffer;
|
||||||
|
size_t buffer_size;
|
||||||
|
size_t element_size;
|
||||||
|
size_t element_num;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void array_delete(struct array_s* self)
|
||||||
|
{
|
||||||
|
if (self == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->buffer != nullptr)
|
||||||
|
{
|
||||||
|
free(self->buffer);
|
||||||
|
self->buffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->element_num = 0;
|
||||||
|
free(self);
|
||||||
|
self = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct array_s* array_new(size_t num, size_t element_size)
|
||||||
|
{
|
||||||
|
auto ret = (struct array_s*)malloc(sizeof(struct array_s));
|
||||||
|
if (ret == nullptr)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto buffer_size = num * element_size;
|
||||||
|
|
||||||
|
ret->buffer_size = 0;
|
||||||
|
ret->element_size = 0;
|
||||||
|
ret->element_num = 0;
|
||||||
|
ret->buffer = malloc(buffer_size);
|
||||||
|
|
||||||
|
if (ret->buffer != nullptr)
|
||||||
|
{
|
||||||
|
ret->element_size = element_size;
|
||||||
|
ret->element_num = num;
|
||||||
|
ret->buffer_size = buffer_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
array_delete(ret);
|
||||||
|
ret = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* array_at(struct array_s* self, size_t index)
|
||||||
|
{
|
||||||
|
void* ret = nullptr;
|
||||||
|
|
||||||
|
if (index < self->element_num)
|
||||||
|
{
|
||||||
|
ret = (char*)(self->buffer) + (index * self->element_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool array_set(struct array_s* self, size_t index, const void* data)
|
||||||
|
{
|
||||||
|
void* old_data = array_at(self, index);
|
||||||
|
|
||||||
|
if (old_data != nullptr)
|
||||||
|
{
|
||||||
|
memcpy(old_data, data, self->element_size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool array_increase(struct array_s* self, size_t increase_num)
|
||||||
|
{
|
||||||
|
if (increase_num == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto new_buffer_size = self->buffer_size + increase_num * self->element_size;
|
||||||
|
auto new_buffer = malloc(new_buffer_size);
|
||||||
|
|
||||||
|
if (new_buffer != nullptr)
|
||||||
|
{
|
||||||
|
memcpy(new_buffer, self->buffer, self->buffer_size);
|
||||||
|
free(self->buffer);
|
||||||
|
self->buffer = new_buffer;
|
||||||
|
self->element_num += increase_num;
|
||||||
|
self->buffer_size = new_buffer_size;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t array_num(const struct array_s* self)
|
||||||
|
{
|
||||||
|
return self->element_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
} }
|
189
libs/brynet/base/Buffer.hpp
Normal file
189
libs/brynet/base/Buffer.hpp
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdbool>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace brynet { namespace base {
|
||||||
|
|
||||||
|
struct buffer_s
|
||||||
|
{
|
||||||
|
char* data;
|
||||||
|
size_t data_len;
|
||||||
|
|
||||||
|
size_t write_pos;
|
||||||
|
size_t read_pos;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void buffer_delete(struct buffer_s* self)
|
||||||
|
{
|
||||||
|
if (self == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->data != nullptr)
|
||||||
|
{
|
||||||
|
free(self->data);
|
||||||
|
self->data = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(self);
|
||||||
|
self = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct buffer_s* buffer_new(size_t buffer_size)
|
||||||
|
{
|
||||||
|
struct buffer_s* ret = (struct buffer_s*)malloc(sizeof(struct buffer_s));
|
||||||
|
if (ret == nullptr)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret->data_len = 0;
|
||||||
|
ret->read_pos = 0;
|
||||||
|
ret->write_pos = 0;
|
||||||
|
ret->data = (char*)malloc(sizeof(char) * buffer_size);
|
||||||
|
|
||||||
|
if (ret->data != nullptr)
|
||||||
|
{
|
||||||
|
ret->data_len = buffer_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer_delete(ret);
|
||||||
|
ret = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t buffer_getreadvalidcount(struct buffer_s* self)
|
||||||
|
{
|
||||||
|
return self->write_pos - self->read_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void buffer_adjustto_head(struct buffer_s* self)
|
||||||
|
{
|
||||||
|
if (self->read_pos == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto len = buffer_getreadvalidcount(self);
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
memmove(self->data, self->data + self->read_pos, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
self->read_pos = 0;
|
||||||
|
self->write_pos = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void buffer_init(struct buffer_s* self)
|
||||||
|
{
|
||||||
|
self->read_pos = 0;
|
||||||
|
self->write_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t buffer_getwritepos(struct buffer_s* self)
|
||||||
|
{
|
||||||
|
return self->write_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t buffer_getreadpos(struct buffer_s* self)
|
||||||
|
{
|
||||||
|
return self->read_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool buffer_addwritepos(struct buffer_s* self, size_t value)
|
||||||
|
{
|
||||||
|
const size_t temp = self->write_pos + value;
|
||||||
|
if (temp <= self->data_len)
|
||||||
|
{
|
||||||
|
self->write_pos = temp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool buffer_addreadpos(struct buffer_s* self, size_t value)
|
||||||
|
{
|
||||||
|
const size_t temp = self->read_pos + value;
|
||||||
|
if (temp <= self->data_len)
|
||||||
|
{
|
||||||
|
self->read_pos = temp;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t buffer_getwritevalidcount(struct buffer_s* self)
|
||||||
|
{
|
||||||
|
return self->data_len - self->write_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t buffer_getsize(struct buffer_s* self)
|
||||||
|
{
|
||||||
|
return self->data_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* buffer_getwriteptr(struct buffer_s* self)
|
||||||
|
{
|
||||||
|
if (self->write_pos < self->data_len)
|
||||||
|
{
|
||||||
|
return self->data + self->write_pos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* buffer_getreadptr(struct buffer_s* self)
|
||||||
|
{
|
||||||
|
if (self->read_pos < self->data_len)
|
||||||
|
{
|
||||||
|
return self->data + self->read_pos;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool buffer_write(struct buffer_s* self, const char* data, size_t len)
|
||||||
|
{
|
||||||
|
bool write_ret = true;
|
||||||
|
|
||||||
|
if (buffer_getwritevalidcount(self) >= len)
|
||||||
|
{
|
||||||
|
/* Ö±½ÓдÈë */
|
||||||
|
memcpy(buffer_getwriteptr(self), data, len);
|
||||||
|
buffer_addwritepos(self, len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t left_len = self->data_len - buffer_getreadvalidcount(self);
|
||||||
|
if (left_len >= len)
|
||||||
|
{
|
||||||
|
buffer_adjustto_head(self);
|
||||||
|
buffer_write(self, data, len);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
write_ret = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return write_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
} }
|
16
libs/brynet/base/CPP_VERSION.hpp
Normal file
16
libs/brynet/base/CPP_VERSION.hpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if (__cplusplus >= 201103L || \
|
||||||
|
(defined(_MSC_VER) && _MSC_VER >= 1800))
|
||||||
|
#define BRYNET_HAVE_LANG_CXX11 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (__cplusplus >= 201402L || \
|
||||||
|
(defined(_MSC_VER) && _MSC_VER >= 1900))
|
||||||
|
#define BRYNET_HAVE_LANG_CXX14 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (__cplusplus >= 201703L || \
|
||||||
|
(defined(_MSC_VER) && _MSC_VER >= 1910))
|
||||||
|
#define BRYNET_HAVE_LANG_CXX17 1
|
||||||
|
#endif
|
9
libs/brynet/base/Noexcept.hpp
Normal file
9
libs/brynet/base/Noexcept.hpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <brynet/base/CPP_VERSION.hpp>
|
||||||
|
|
||||||
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||||
|
#define BRYNET_NOEXCEPT noexcept
|
||||||
|
#else
|
||||||
|
#define BRYNET_NOEXCEPT
|
||||||
|
#endif
|
16
libs/brynet/base/NonCopyable.hpp
Normal file
16
libs/brynet/base/NonCopyable.hpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace brynet { namespace base {
|
||||||
|
|
||||||
|
class NonCopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
NonCopyable(const NonCopyable&) = delete;
|
||||||
|
const NonCopyable& operator=(const NonCopyable&) = delete;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
NonCopyable() = default;
|
||||||
|
~NonCopyable() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
398
libs/brynet/base/Packet.hpp
Normal file
398
libs/brynet/base/Packet.hpp
Normal file
@ -0,0 +1,398 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdbool>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <brynet/base/NonCopyable.hpp>
|
||||||
|
#include <brynet/base/endian/Endian.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace base {
|
||||||
|
|
||||||
|
class BasePacketWriter : public NonCopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BasePacketWriter(char* buffer,
|
||||||
|
size_t len,
|
||||||
|
bool useBigEndian = true,
|
||||||
|
bool isAutoMalloc = false)
|
||||||
|
:
|
||||||
|
mIsAutoMalloc(isAutoMalloc),
|
||||||
|
mBigEndian(useBigEndian)
|
||||||
|
{
|
||||||
|
mMaxLen = len;
|
||||||
|
mPos = 0;
|
||||||
|
mBuffer = buffer;
|
||||||
|
mMallocBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~BasePacketWriter()
|
||||||
|
{
|
||||||
|
if (mMallocBuffer != nullptr)
|
||||||
|
{
|
||||||
|
free(mMallocBuffer);
|
||||||
|
mMallocBuffer = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void init()
|
||||||
|
{
|
||||||
|
mPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getMaxLen() const
|
||||||
|
{
|
||||||
|
return mMaxLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getPos() const
|
||||||
|
{
|
||||||
|
return mPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* getData() const
|
||||||
|
{
|
||||||
|
return mBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isAutoGrow() const
|
||||||
|
{
|
||||||
|
return mIsAutoMalloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool writeBool(bool value)
|
||||||
|
{
|
||||||
|
static_assert(sizeof(bool) == sizeof(int8_t), "");
|
||||||
|
return writeBuffer((char*)&value, sizeof(value));
|
||||||
|
}
|
||||||
|
bool writeINT8(int8_t value)
|
||||||
|
{
|
||||||
|
return writeBuffer((char*)&value, sizeof(value));
|
||||||
|
}
|
||||||
|
bool writeUINT8(uint8_t value)
|
||||||
|
{
|
||||||
|
return writeBuffer((char*)&value, sizeof(value));
|
||||||
|
}
|
||||||
|
bool writeINT16(int16_t value)
|
||||||
|
{
|
||||||
|
value = endian::hostToNetwork16(value, mBigEndian);
|
||||||
|
return writeBuffer((char*)&value, sizeof(value));
|
||||||
|
}
|
||||||
|
bool writeUINT16(uint16_t value)
|
||||||
|
{
|
||||||
|
value = endian::hostToNetwork16(value, mBigEndian);
|
||||||
|
return writeBuffer((char*)&value, sizeof(value));
|
||||||
|
}
|
||||||
|
bool writeINT32(int32_t value)
|
||||||
|
{
|
||||||
|
value = endian::hostToNetwork32(value, mBigEndian);
|
||||||
|
return writeBuffer((char*)&value, sizeof(value));
|
||||||
|
}
|
||||||
|
bool writeUINT32(uint32_t value)
|
||||||
|
{
|
||||||
|
value = endian::hostToNetwork32(value, mBigEndian);
|
||||||
|
return writeBuffer((char*)&value, sizeof(value));
|
||||||
|
}
|
||||||
|
bool writeINT64(int64_t value)
|
||||||
|
{
|
||||||
|
value = endian::hostToNetwork64(value, mBigEndian);
|
||||||
|
return writeBuffer((char*)&value, sizeof(value));
|
||||||
|
}
|
||||||
|
bool writeUINT64(uint64_t value)
|
||||||
|
{
|
||||||
|
value = endian::hostToNetwork64(value, mBigEndian);
|
||||||
|
return writeBuffer((char*)&value, sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool writeBinary(const std::string& binary)
|
||||||
|
{
|
||||||
|
return writeBuffer(binary.c_str(), binary.size());
|
||||||
|
}
|
||||||
|
bool writeBinary(const char* binary, size_t binaryLen)
|
||||||
|
{
|
||||||
|
return writeBuffer(binary, binaryLen);
|
||||||
|
}
|
||||||
|
bool writeBuffer(const char* buffer, size_t len)
|
||||||
|
{
|
||||||
|
growBuffer(len);
|
||||||
|
|
||||||
|
if (mMaxLen < (mPos + len))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(mBuffer + mPos, buffer, len);
|
||||||
|
mPos += len;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasePacketWriter & operator << (const bool &v)
|
||||||
|
{
|
||||||
|
writeBool(v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
BasePacketWriter & operator << (const uint8_t &v)
|
||||||
|
{
|
||||||
|
writeUINT8(v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
BasePacketWriter & operator << (const int8_t &v)
|
||||||
|
{
|
||||||
|
writeINT8(v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
BasePacketWriter & operator << (const int16_t &v)
|
||||||
|
{
|
||||||
|
writeINT16(v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
BasePacketWriter & operator << (const uint16_t &v)
|
||||||
|
{
|
||||||
|
writeUINT16(v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
BasePacketWriter & operator << (const int32_t &v)
|
||||||
|
{
|
||||||
|
writeINT32(v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
BasePacketWriter & operator << (const uint32_t &v)
|
||||||
|
{
|
||||||
|
writeUINT32(v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
BasePacketWriter & operator << (const int64_t &v)
|
||||||
|
{
|
||||||
|
writeINT64(v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
BasePacketWriter & operator << (const uint64_t &v)
|
||||||
|
{
|
||||||
|
writeUINT64(v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
BasePacketWriter & operator << (const char* const &v)
|
||||||
|
{
|
||||||
|
writeBinary(v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
BasePacketWriter & operator << (const std::string &v)
|
||||||
|
{
|
||||||
|
writeBinary(v);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// 为了避免直接<<导致没有指定字节序导致隐藏BUG,因为此函数设置为私有
|
||||||
|
template<typename T>
|
||||||
|
BasePacketWriter & operator << (const T& v)
|
||||||
|
{
|
||||||
|
static_assert(!std::is_pointer<T>::value, "T must is't a pointer");
|
||||||
|
static_assert(std::is_class <T>::value, "T must a class or struct type");
|
||||||
|
static_assert(std::is_pod <T>::value, "T must a pod type");
|
||||||
|
writeBuffer((const char*)&v, sizeof(v));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Arg1, typename... Args>
|
||||||
|
void writev(const Arg1& arg1, const Args&... args)
|
||||||
|
{
|
||||||
|
this->operator<<(arg1);
|
||||||
|
writev(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writev()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void growBuffer(size_t len)
|
||||||
|
{
|
||||||
|
if (!mIsAutoMalloc || (mPos + len) <= mMaxLen)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto newBuffer = (char*)malloc(mMaxLen + len);
|
||||||
|
if (newBuffer == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(newBuffer, mBuffer, mPos);
|
||||||
|
|
||||||
|
if (mMallocBuffer != nullptr)
|
||||||
|
{
|
||||||
|
free(mMallocBuffer);
|
||||||
|
mMallocBuffer = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMaxLen += len;
|
||||||
|
mMallocBuffer = newBuffer;
|
||||||
|
mBuffer = newBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const bool mIsAutoMalloc;
|
||||||
|
bool mBigEndian;
|
||||||
|
size_t mPos;
|
||||||
|
size_t mMaxLen;
|
||||||
|
char* mBuffer;
|
||||||
|
char* mMallocBuffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
class BasePacketReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
BasePacketReader(const char* buffer,
|
||||||
|
size_t len,
|
||||||
|
bool useBigEndian = true) :
|
||||||
|
mBigEndian(useBigEndian),
|
||||||
|
mMaxLen(len)
|
||||||
|
{
|
||||||
|
mPos = 0;
|
||||||
|
mBuffer = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~BasePacketReader() = default;
|
||||||
|
|
||||||
|
size_t getLeft() const
|
||||||
|
{
|
||||||
|
if (mPos > mMaxLen)
|
||||||
|
{
|
||||||
|
throw std::out_of_range("current pos is greater than max len");
|
||||||
|
}
|
||||||
|
return mMaxLen - mPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* getBuffer() const
|
||||||
|
{
|
||||||
|
return mBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void skipAll()
|
||||||
|
{
|
||||||
|
mPos = mMaxLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getPos() const
|
||||||
|
{
|
||||||
|
return mPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getMaxPos() const
|
||||||
|
{
|
||||||
|
return mMaxLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addPos(size_t diff)
|
||||||
|
{
|
||||||
|
const auto tmpPos = mPos + diff;
|
||||||
|
if (tmpPos > mMaxLen)
|
||||||
|
{
|
||||||
|
throw std::out_of_range("diff is to big");
|
||||||
|
}
|
||||||
|
|
||||||
|
mPos = tmpPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool readBool()
|
||||||
|
{
|
||||||
|
static_assert(sizeof(bool) == sizeof(int8_t), "");
|
||||||
|
bool value = false;
|
||||||
|
read(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
int8_t readINT8()
|
||||||
|
{
|
||||||
|
int8_t value = 0;
|
||||||
|
read(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
uint8_t readUINT8()
|
||||||
|
{
|
||||||
|
uint8_t value = 0;
|
||||||
|
read(value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
int16_t readINT16()
|
||||||
|
{
|
||||||
|
int16_t value = 0;
|
||||||
|
read(value);
|
||||||
|
return endian::networkToHost16(value, mBigEndian);
|
||||||
|
}
|
||||||
|
uint16_t readUINT16()
|
||||||
|
{
|
||||||
|
uint16_t value = 0;
|
||||||
|
read(value);
|
||||||
|
return endian::networkToHost16(value, mBigEndian);
|
||||||
|
}
|
||||||
|
int32_t readINT32()
|
||||||
|
{
|
||||||
|
int32_t value = 0;
|
||||||
|
read(value);
|
||||||
|
return endian::networkToHost32(value, mBigEndian);
|
||||||
|
}
|
||||||
|
uint32_t readUINT32()
|
||||||
|
{
|
||||||
|
uint32_t value = 0;
|
||||||
|
read(value);
|
||||||
|
return endian::networkToHost32(value, mBigEndian);
|
||||||
|
}
|
||||||
|
int64_t readINT64()
|
||||||
|
{
|
||||||
|
int64_t value = 0;
|
||||||
|
read(value);
|
||||||
|
return endian::networkToHost64(value, mBigEndian);
|
||||||
|
}
|
||||||
|
uint64_t readUINT64()
|
||||||
|
{
|
||||||
|
uint64_t value = 0;
|
||||||
|
read(value);
|
||||||
|
return endian::networkToHost64(value, mBigEndian);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// 为了避免直接read(uintXXX)导致没有指定字节序造成隐患BUG,因为此函数设置为私有
|
||||||
|
template<typename T>
|
||||||
|
void read(T& value)
|
||||||
|
{
|
||||||
|
static_assert(std::is_same<T, typename std::remove_pointer<T>::type>::value,
|
||||||
|
"T must a nomal type");
|
||||||
|
static_assert(std::is_pod<T>::value,
|
||||||
|
"T must a pod type");
|
||||||
|
|
||||||
|
if ((mPos + sizeof(value)) > mMaxLen)
|
||||||
|
{
|
||||||
|
throw std::out_of_range("T size is to big");
|
||||||
|
}
|
||||||
|
|
||||||
|
value = *(T*)(mBuffer + mPos);
|
||||||
|
mPos += sizeof(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const bool mBigEndian;
|
||||||
|
const size_t mMaxLen;
|
||||||
|
const char* mBuffer;
|
||||||
|
size_t mPos;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<size_t SIZE>
|
||||||
|
class AutoMallocPacket : public BasePacketWriter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AutoMallocPacket(bool useBigEndian = true,
|
||||||
|
bool isAutoMalloc = false)
|
||||||
|
:
|
||||||
|
BasePacketWriter(mData, SIZE, useBigEndian, isAutoMalloc)
|
||||||
|
{}
|
||||||
|
private:
|
||||||
|
char mData[SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
using BigPacket = AutoMallocPacket<32 * 1024>;
|
||||||
|
|
||||||
|
} }
|
9
libs/brynet/base/Platform.hpp
Normal file
9
libs/brynet/base/Platform.hpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined _MSC_VER || defined __MINGW32__
|
||||||
|
#define BRYNET_PLATFORM_WINDOWS
|
||||||
|
#elif defined __APPLE_CC__ || defined __APPLE__
|
||||||
|
#define BRYNET_PLATFORM_DARWIN
|
||||||
|
#else
|
||||||
|
#define BRYNET_PLATFORM_LINUX
|
||||||
|
#endif
|
175
libs/brynet/base/Stack.hpp
Normal file
175
libs/brynet/base/Stack.hpp
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdbool>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <brynet/base/Array.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace base {
|
||||||
|
|
||||||
|
struct stack_s
|
||||||
|
{
|
||||||
|
struct array_s* array;
|
||||||
|
size_t element_size;
|
||||||
|
|
||||||
|
size_t element_num;
|
||||||
|
size_t front; /* 栈底 */
|
||||||
|
size_t num; /* 栈有效元素大小 */
|
||||||
|
};
|
||||||
|
|
||||||
|
static void stack_delete(struct stack_s* self)
|
||||||
|
{
|
||||||
|
if (self == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->array != nullptr)
|
||||||
|
{
|
||||||
|
array_delete(self->array);
|
||||||
|
self->array = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->element_num = 0;
|
||||||
|
self->front = 0;
|
||||||
|
self->num = 0;
|
||||||
|
free(self);
|
||||||
|
self = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct stack_s* stack_new(size_t num, size_t element_size)
|
||||||
|
{
|
||||||
|
struct stack_s* ret = (struct stack_s*)malloc(sizeof(struct stack_s));
|
||||||
|
if (ret == nullptr)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret->element_size = 0;
|
||||||
|
ret->element_num = 0;
|
||||||
|
ret->front = 0;
|
||||||
|
ret->num = 0;
|
||||||
|
ret->array = array_new(num, element_size);
|
||||||
|
|
||||||
|
if (ret->array != nullptr)
|
||||||
|
{
|
||||||
|
ret->element_size = element_size;
|
||||||
|
ret->element_num = num;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stack_delete(ret);
|
||||||
|
ret = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stack_init(struct stack_s* self)
|
||||||
|
{
|
||||||
|
self->front = 0;
|
||||||
|
self->num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t stack_num(struct stack_s* self)
|
||||||
|
{
|
||||||
|
return self->num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool stack_increase(struct stack_s* self, size_t increase_num)
|
||||||
|
{
|
||||||
|
struct array_s* tmp = array_new(self->element_num + increase_num,
|
||||||
|
self->element_size);
|
||||||
|
if (tmp == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
size_t current_num = self->element_num;
|
||||||
|
size_t current_stack_num = stack_num(self);
|
||||||
|
for (size_t i = 0; i < current_stack_num; ++i)
|
||||||
|
{
|
||||||
|
array_set(tmp, i, array_at(self->array, (self->front + i) % current_num));
|
||||||
|
}
|
||||||
|
|
||||||
|
self->front = 0;
|
||||||
|
array_delete(self->array);
|
||||||
|
self->array = tmp;
|
||||||
|
self->element_num = array_num(self->array);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t stack_size(struct stack_s* self)
|
||||||
|
{
|
||||||
|
return self->element_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool stack_isfull(struct stack_s* self)
|
||||||
|
{
|
||||||
|
return (self->num == self->element_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* stack的stack_push会在空间不足的时候自动增长(通过stack_increase) */
|
||||||
|
static bool stack_push(struct stack_s* self, const void* data)
|
||||||
|
{
|
||||||
|
if (stack_isfull(self))
|
||||||
|
{
|
||||||
|
stack_increase(self, stack_size(self));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack_isfull(self))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
array_set(self->array, (self->front + self->num) % self->element_num, data);
|
||||||
|
self->num++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* stack_front(struct stack_s* self)
|
||||||
|
{
|
||||||
|
void* ret = nullptr;
|
||||||
|
|
||||||
|
if (stack_num(self) > 0)
|
||||||
|
{
|
||||||
|
ret = array_at(self->array, self->front);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* stack_popfront(struct stack_s* self)
|
||||||
|
{
|
||||||
|
void* ret = stack_front(self);
|
||||||
|
|
||||||
|
if (ret != nullptr)
|
||||||
|
{
|
||||||
|
self->num--;
|
||||||
|
self->front++;
|
||||||
|
self->front %= self->element_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void* stack_popback(struct stack_s* self)
|
||||||
|
{
|
||||||
|
void* ret = nullptr;
|
||||||
|
|
||||||
|
if (stack_num(self) > 0)
|
||||||
|
{
|
||||||
|
self->num--;
|
||||||
|
ret = array_at(self->array, (self->front + self->num) % self->element_num);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
} }
|
167
libs/brynet/base/Timer.hpp
Normal file
167
libs/brynet/base/Timer.hpp
Normal file
@ -0,0 +1,167 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <queue>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <chrono>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <brynet/base/Noexcept.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace base {
|
||||||
|
|
||||||
|
class TimerMgr;
|
||||||
|
|
||||||
|
class Timer final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = std::shared_ptr<Timer>;
|
||||||
|
using WeakPtr = std::weak_ptr<Timer>;
|
||||||
|
using Callback = std::function<void(void)>;
|
||||||
|
|
||||||
|
Timer(std::chrono::steady_clock::time_point startTime,
|
||||||
|
std::chrono::nanoseconds lastTime,
|
||||||
|
Callback&& callback) BRYNET_NOEXCEPT
|
||||||
|
:
|
||||||
|
mCallback(std::move(callback)),
|
||||||
|
mStartTime(startTime),
|
||||||
|
mLastTime(lastTime)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::chrono::steady_clock::time_point& getStartTime() const
|
||||||
|
{
|
||||||
|
return mStartTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::chrono::nanoseconds& getLastTime() const
|
||||||
|
{
|
||||||
|
return mLastTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::nanoseconds getLeftTime() const
|
||||||
|
{
|
||||||
|
const auto now = std::chrono::steady_clock::now();
|
||||||
|
return getLastTime() - (now - getStartTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancel()
|
||||||
|
{
|
||||||
|
std::call_once(mExecuteOnceFlag, [this]() {
|
||||||
|
mCallback = nullptr;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void operator() ()
|
||||||
|
{
|
||||||
|
Callback callback;
|
||||||
|
std::call_once(mExecuteOnceFlag, [&callback, this]() {
|
||||||
|
callback = std::move(mCallback);
|
||||||
|
mCallback = nullptr;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (callback != nullptr)
|
||||||
|
{
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::once_flag mExecuteOnceFlag;
|
||||||
|
Callback mCallback;
|
||||||
|
const std::chrono::steady_clock::time_point mStartTime;
|
||||||
|
const std::chrono::nanoseconds mLastTime;
|
||||||
|
|
||||||
|
friend class TimerMgr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TimerMgr final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = std::shared_ptr<TimerMgr>;
|
||||||
|
|
||||||
|
template<typename F, typename ...TArgs>
|
||||||
|
Timer::WeakPtr addTimer(
|
||||||
|
std::chrono::nanoseconds timeout,
|
||||||
|
F&& callback,
|
||||||
|
TArgs&& ...args)
|
||||||
|
{
|
||||||
|
auto timer = std::make_shared<Timer>(
|
||||||
|
std::chrono::steady_clock::now(),
|
||||||
|
std::chrono::nanoseconds(timeout),
|
||||||
|
std::bind(std::forward<F>(callback), std::forward<TArgs>(args)...));
|
||||||
|
mTimers.push(timer);
|
||||||
|
|
||||||
|
return timer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addTimer(const Timer::Ptr& timer)
|
||||||
|
{
|
||||||
|
mTimers.push(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void schedule()
|
||||||
|
{
|
||||||
|
while (!mTimers.empty())
|
||||||
|
{
|
||||||
|
auto tmp = mTimers.top();
|
||||||
|
if (tmp->getLeftTime() > std::chrono::nanoseconds::zero())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mTimers.pop();
|
||||||
|
(*tmp)();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEmpty() const
|
||||||
|
{
|
||||||
|
return mTimers.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if timer empty, return zero
|
||||||
|
std::chrono::nanoseconds nearLeftTime() const
|
||||||
|
{
|
||||||
|
if (mTimers.empty())
|
||||||
|
{
|
||||||
|
return std::chrono::nanoseconds::zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = mTimers.top()->getLeftTime();
|
||||||
|
if (result < std::chrono::nanoseconds::zero())
|
||||||
|
{
|
||||||
|
return std::chrono::nanoseconds::zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
while (!mTimers.empty())
|
||||||
|
{
|
||||||
|
mTimers.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
class CompareTimer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool operator() (const Timer::Ptr& left,
|
||||||
|
const Timer::Ptr& right) const
|
||||||
|
{
|
||||||
|
const auto startDiff = left->getStartTime() - right->getStartTime();
|
||||||
|
const auto lastDiff = left->getLastTime() - right->getLastTime();
|
||||||
|
const auto diff = startDiff.count() + lastDiff.count();
|
||||||
|
return diff > 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::priority_queue<Timer::Ptr, std::vector<Timer::Ptr>, CompareTimer> mTimers;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
65
libs/brynet/base/WaitGroup.hpp
Normal file
65
libs/brynet/base/WaitGroup.hpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <atomic>
|
||||||
|
#include <memory>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <brynet/base/NonCopyable.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace base {
|
||||||
|
|
||||||
|
class WaitGroup : public NonCopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::shared_ptr<WaitGroup> Ptr;
|
||||||
|
|
||||||
|
static Ptr Create()
|
||||||
|
{
|
||||||
|
struct make_shared_enabler : public WaitGroup {};
|
||||||
|
return std::make_shared<make_shared_enabler>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void add(int i = 1)
|
||||||
|
{
|
||||||
|
mCounter += i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void done()
|
||||||
|
{
|
||||||
|
mCounter--;
|
||||||
|
mCond.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> l(mMutex);
|
||||||
|
mCond.wait(l, [&] { return mCounter <= 0; });
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Rep, class Period>
|
||||||
|
void wait(const std::chrono::duration<Rep, Period>& timeout)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> l(mMutex);
|
||||||
|
mCond.wait_for(l, timeout, [&] {
|
||||||
|
return mCounter <= 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
WaitGroup()
|
||||||
|
:
|
||||||
|
mCounter(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~WaitGroup() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::mutex mMutex;
|
||||||
|
std::atomic<int> mCounter;
|
||||||
|
std::condition_variable mCond;
|
||||||
|
};
|
||||||
|
} }
|
105
libs/brynet/base/crypto/Base64.hpp
Normal file
105
libs/brynet/base/crypto/Base64.hpp
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
#ifndef _BRYNET_BASE_BASE64_H
|
||||||
|
#define _BRYNET_BASE_BASE64_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace brynet { namespace base { namespace crypto {
|
||||||
|
|
||||||
|
static const std::string base64_chars =
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
"abcdefghijklmnopqrstuvwxyz"
|
||||||
|
"0123456789+/";
|
||||||
|
|
||||||
|
static bool is_base64(unsigned char c)
|
||||||
|
{
|
||||||
|
return (isalnum(c) || (c == '+') || (c == '/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
unsigned char char_array_3[3];
|
||||||
|
unsigned char char_array_4[4];
|
||||||
|
|
||||||
|
while (in_len--) {
|
||||||
|
char_array_3[i++] = *(bytes_to_encode++);
|
||||||
|
if (i == 3) {
|
||||||
|
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||||
|
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||||
|
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||||
|
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||||
|
|
||||||
|
for (i = 0; (i < 4); i++)
|
||||||
|
ret += base64_chars[char_array_4[i]];
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i)
|
||||||
|
{
|
||||||
|
for (j = i; j < 3; j++)
|
||||||
|
char_array_3[j] = '\0';
|
||||||
|
|
||||||
|
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
|
||||||
|
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
|
||||||
|
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
|
||||||
|
char_array_4[3] = char_array_3[2] & 0x3f;
|
||||||
|
|
||||||
|
for (j = 0; (j < i + 1); j++)
|
||||||
|
ret += base64_chars[char_array_4[j]];
|
||||||
|
|
||||||
|
while ((i++ < 3))
|
||||||
|
ret += '=';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string base64_decode(std::string const& encoded_string)
|
||||||
|
{
|
||||||
|
int in_len = encoded_string.size();
|
||||||
|
int i = 0;
|
||||||
|
int j = 0;
|
||||||
|
int in_ = 0;
|
||||||
|
unsigned char char_array_4[4], char_array_3[3];
|
||||||
|
std::string ret;
|
||||||
|
|
||||||
|
while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
|
||||||
|
char_array_4[i++] = encoded_string[in_]; in_++;
|
||||||
|
if (i == 4) {
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
char_array_4[i] = base64_chars.find(char_array_4[i]);
|
||||||
|
|
||||||
|
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||||
|
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||||
|
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||||
|
|
||||||
|
for (i = 0; (i < 3); i++)
|
||||||
|
ret += char_array_3[i];
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i) {
|
||||||
|
for (j = i; j < 4; j++)
|
||||||
|
char_array_4[j] = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < 4; j++)
|
||||||
|
char_array_4[j] = base64_chars.find(char_array_4[j]);
|
||||||
|
|
||||||
|
char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
|
||||||
|
char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
|
||||||
|
char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
|
||||||
|
|
||||||
|
for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
} } }
|
||||||
|
|
||||||
|
#endif
|
496
libs/brynet/base/crypto/SHA1.hpp
Normal file
496
libs/brynet/base/crypto/SHA1.hpp
Normal file
@ -0,0 +1,496 @@
|
|||||||
|
/*
|
||||||
|
100% free public domain implementation of the SHA-1 algorithm
|
||||||
|
by Dominik Reichl <dominik.reichl@t-online.de>
|
||||||
|
Web: http://www.dominik-reichl.de/
|
||||||
|
|
||||||
|
Version 2.1 - 2012-06-19
|
||||||
|
- Deconstructor (resetting internal variables) is now only
|
||||||
|
implemented if SHA1_WIPE_VARIABLES is defined (which is the
|
||||||
|
default).
|
||||||
|
- Renamed inclusion guard to contain a GUID.
|
||||||
|
- Demo application is now using C++/STL objects and functions.
|
||||||
|
- Unicode build of the demo application now outputs the hashes of both
|
||||||
|
the ANSI and Unicode representations of strings.
|
||||||
|
- Various other demo application improvements.
|
||||||
|
|
||||||
|
Version 2.0 - 2012-06-14
|
||||||
|
- Added 'limits.h' include.
|
||||||
|
- Renamed inclusion guard and macros for compliancy (names beginning
|
||||||
|
with an underscore are reserved).
|
||||||
|
|
||||||
|
Version 1.9 - 2011-11-10
|
||||||
|
- Added Unicode test vectors.
|
||||||
|
- Improved support for hashing files using the HashFile method that
|
||||||
|
are larger than 4 GB.
|
||||||
|
- Improved file hashing performance (by using a larger buffer).
|
||||||
|
- Disabled unnecessary compiler warnings.
|
||||||
|
- Internal variables are now private.
|
||||||
|
|
||||||
|
Version 1.8 - 2009-03-16
|
||||||
|
- Converted project files to Visual Studio 2008 format.
|
||||||
|
- Added Unicode support for HashFile utility method.
|
||||||
|
- Added support for hashing files using the HashFile method that are
|
||||||
|
larger than 2 GB.
|
||||||
|
- HashFile now returns an error code instead of copying an error
|
||||||
|
message into the output buffer.
|
||||||
|
- GetHash now returns an error code and validates the input parameter.
|
||||||
|
- Added ReportHashStl STL utility method.
|
||||||
|
- Added REPORT_HEX_SHORT reporting mode.
|
||||||
|
- Improved Linux compatibility of test program.
|
||||||
|
|
||||||
|
Version 1.7 - 2006-12-21
|
||||||
|
- Fixed buffer underrun warning that appeared when compiling with
|
||||||
|
Borland C Builder (thanks to Rex Bloom and Tim Gallagher for the
|
||||||
|
patch).
|
||||||
|
- Breaking change: ReportHash writes the final hash to the start
|
||||||
|
of the buffer, i.e. it's not appending it to the string anymore.
|
||||||
|
- Made some function parameters const.
|
||||||
|
- Added Visual Studio 2005 project files to demo project.
|
||||||
|
|
||||||
|
Version 1.6 - 2005-02-07 (thanks to Howard Kapustein for patches)
|
||||||
|
- You can set the endianness in your files, no need to modify the
|
||||||
|
header file of the CSHA1 class anymore.
|
||||||
|
- Aligned data support.
|
||||||
|
- Made support/compilation of the utility functions (ReportHash and
|
||||||
|
HashFile) optional (useful when bytes count, for example in embedded
|
||||||
|
environments).
|
||||||
|
|
||||||
|
Version 1.5 - 2005-01-01
|
||||||
|
- 64-bit compiler compatibility added.
|
||||||
|
- Made variable wiping optional (define SHA1_WIPE_VARIABLES).
|
||||||
|
- Removed unnecessary variable initializations.
|
||||||
|
- ROL32 improvement for the Microsoft compiler (using _rotl).
|
||||||
|
|
||||||
|
Version 1.4 - 2004-07-22
|
||||||
|
- CSHA1 now compiles fine with GCC 3.3 under Mac OS X (thanks to Larry
|
||||||
|
Hastings).
|
||||||
|
|
||||||
|
Version 1.3 - 2003-08-17
|
||||||
|
- Fixed a small memory bug and made a buffer array a class member to
|
||||||
|
ensure correct working when using multiple CSHA1 class instances at
|
||||||
|
one time.
|
||||||
|
|
||||||
|
Version 1.2 - 2002-11-16
|
||||||
|
- Borlands C++ compiler seems to have problems with string addition
|
||||||
|
using sprintf. Fixed the bug which caused the digest report function
|
||||||
|
not to work properly. CSHA1 is now Borland compatible.
|
||||||
|
|
||||||
|
Version 1.1 - 2002-10-11
|
||||||
|
- Removed two unnecessary header file includes and changed BOOL to
|
||||||
|
bool. Fixed some minor bugs in the web page contents.
|
||||||
|
|
||||||
|
Version 1.0 - 2002-06-20
|
||||||
|
- First official release.
|
||||||
|
|
||||||
|
================ Test Vectors ================
|
||||||
|
|
||||||
|
SHA1("abc" in ANSI) =
|
||||||
|
A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||||
|
SHA1("abc" in Unicode LE) =
|
||||||
|
9F04F41A 84851416 2050E3D6 8C1A7ABB 441DC2B5
|
||||||
|
|
||||||
|
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||||
|
in ANSI) =
|
||||||
|
84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||||
|
SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||||
|
in Unicode LE) =
|
||||||
|
51D7D876 9AC72C40 9C5B0E3F 69C60ADC 9A039014
|
||||||
|
|
||||||
|
SHA1(A million repetitions of "a" in ANSI) =
|
||||||
|
34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||||
|
SHA1(A million repetitions of "a" in Unicode LE) =
|
||||||
|
C4609560 A108A0C6 26AA7F2B 38A65566 739353C5
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
|
||||||
|
#define SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
|
||||||
|
|
||||||
|
#if !defined(SHA1_UTILITY_FUNCTIONS) && !defined(SHA1_NO_UTILITY_FUNCTIONS)
|
||||||
|
#define SHA1_UTILITY_FUNCTIONS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SHA1_STL_FUNCTIONS) && !defined(SHA1_NO_STL_FUNCTIONS)
|
||||||
|
#define SHA1_STL_FUNCTIONS
|
||||||
|
#if !defined(SHA1_UTILITY_FUNCTIONS)
|
||||||
|
#error STL functions require SHA1_UTILITY_FUNCTIONS.
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SHA1_STL_FUNCTIONS
|
||||||
|
#include <string>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <stdlib.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// You can define the endian mode in your files without modifying the SHA-1
|
||||||
|
// source files. Just #define SHA1_LITTLE_ENDIAN or #define SHA1_BIG_ENDIAN
|
||||||
|
// in your files, before including the SHA1.h header file. If you don't
|
||||||
|
// define anything, the class defaults to little endian.
|
||||||
|
#if !defined(SHA1_LITTLE_ENDIAN) && !defined(SHA1_BIG_ENDIAN)
|
||||||
|
#define SHA1_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// If you want variable wiping, #define SHA1_WIPE_VARIABLES, if not,
|
||||||
|
// #define SHA1_NO_WIPE_VARIABLES. If you don't define anything, it
|
||||||
|
// defaults to wiping.
|
||||||
|
#if !defined(SHA1_WIPE_VARIABLES) && !defined(SHA1_NO_WIPE_VARIABLES)
|
||||||
|
#define SHA1_WIPE_VARIABLES
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(SHA1_HAS_TCHAR)
|
||||||
|
#include <tchar.h>
|
||||||
|
#else
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <tchar.h>
|
||||||
|
#else
|
||||||
|
#ifndef TCHAR
|
||||||
|
#define TCHAR char
|
||||||
|
#endif
|
||||||
|
#ifndef _T
|
||||||
|
#define _T(__x) (__x)
|
||||||
|
#define _tmain main
|
||||||
|
#define _tprintf printf
|
||||||
|
#define _getts gets
|
||||||
|
#define _tcslen strlen
|
||||||
|
#define _tfopen fopen
|
||||||
|
#define _tcscpy strcpy
|
||||||
|
#define _tcscat strcat
|
||||||
|
#define _sntprintf snprintf
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Define variable types
|
||||||
|
|
||||||
|
#ifndef UINT_8
|
||||||
|
#ifdef _MSC_VER // Compiling with Microsoft compiler
|
||||||
|
#define UINT_8 unsigned __int8
|
||||||
|
#else // !_MSC_VER
|
||||||
|
#define UINT_8 unsigned char
|
||||||
|
#endif // _MSC_VER
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef UINT_32
|
||||||
|
#ifdef _MSC_VER // Compiling with Microsoft compiler
|
||||||
|
#define UINT_32 unsigned __int32
|
||||||
|
#else // !_MSC_VER
|
||||||
|
#if (ULONG_MAX == 0xFFFFFFFFUL)
|
||||||
|
#define UINT_32 unsigned long
|
||||||
|
#else
|
||||||
|
#define UINT_32 unsigned int
|
||||||
|
#endif
|
||||||
|
#endif // _MSC_VER
|
||||||
|
#endif // UINT_32
|
||||||
|
|
||||||
|
#ifndef INT_64
|
||||||
|
#ifdef _MSC_VER // Compiling with Microsoft compiler
|
||||||
|
#define INT_64 __int64
|
||||||
|
#else // !_MSC_VER
|
||||||
|
#define INT_64 long long
|
||||||
|
#endif // _MSC_VER
|
||||||
|
#endif // INT_64
|
||||||
|
|
||||||
|
#ifndef UINT_64
|
||||||
|
#ifdef _MSC_VER // Compiling with Microsoft compiler
|
||||||
|
#define UINT_64 unsigned __int64
|
||||||
|
#else // !_MSC_VER
|
||||||
|
#define UINT_64 unsigned long long
|
||||||
|
#endif // _MSC_VER
|
||||||
|
#endif // UINT_64
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
// Declare SHA-1 workspace
|
||||||
|
|
||||||
|
typedef union
|
||||||
|
{
|
||||||
|
UINT_8 c[64];
|
||||||
|
UINT_32 l[16];
|
||||||
|
} SHA1_WORKSPACE_BLOCK;
|
||||||
|
|
||||||
|
|
||||||
|
#define SHA1_MAX_FILE_BUFFER (32 * 20 * 820)
|
||||||
|
|
||||||
|
// Rotate p_val32 by p_nBits bits to the left
|
||||||
|
#ifndef ROL32
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#define ROL32(p_val32,p_nBits) _rotl(p_val32,p_nBits)
|
||||||
|
#else
|
||||||
|
#define ROL32(p_val32,p_nBits) (((p_val32)<<(p_nBits))|((p_val32)>>(32-(p_nBits))))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SHA1_LITTLE_ENDIAN
|
||||||
|
#define SHABLK0(i) (m_block->l[i] = \
|
||||||
|
(ROL32(m_block->l[i],24) & 0xFF00FF00) | (ROL32(m_block->l[i],8) & 0x00FF00FF))
|
||||||
|
#else
|
||||||
|
#define SHABLK0(i) (m_block->l[i])
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SHABLK(i) (m_block->l[i&15] = ROL32(m_block->l[(i+13)&15] ^ \
|
||||||
|
m_block->l[(i+8)&15] ^ m_block->l[(i+2)&15] ^ m_block->l[i&15],1))
|
||||||
|
|
||||||
|
// SHA-1 rounds
|
||||||
|
#define S_R0(v,w,x,y,z,i) {z+=((w&(x^y))^y)+SHABLK0(i)+0x5A827999+ROL32(v,5);w=ROL32(w,30);}
|
||||||
|
#define S_R1(v,w,x,y,z,i) {z+=((w&(x^y))^y)+SHABLK(i)+0x5A827999+ROL32(v,5);w=ROL32(w,30);}
|
||||||
|
#define S_R2(v,w,x,y,z,i) {z+=(w^x^y)+SHABLK(i)+0x6ED9EBA1+ROL32(v,5);w=ROL32(w,30);}
|
||||||
|
#define S_R3(v,w,x,y,z,i) {z+=(((w|x)&y)|(w&x))+SHABLK(i)+0x8F1BBCDC+ROL32(v,5);w=ROL32(w,30);}
|
||||||
|
#define S_R4(v,w,x,y,z,i) {z+=(w^x^y)+SHABLK(i)+0xCA62C1D6+ROL32(v,5);w=ROL32(w,30);}
|
||||||
|
|
||||||
|
|
||||||
|
class CSHA1
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||||
|
// Different formats for ReportHash(Stl)
|
||||||
|
enum REPORT_TYPE
|
||||||
|
{
|
||||||
|
REPORT_HEX = 0,
|
||||||
|
REPORT_DIGIT = 1,
|
||||||
|
REPORT_HEX_SHORT = 2
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Constructor and destructor
|
||||||
|
CSHA1()
|
||||||
|
{
|
||||||
|
(void)m_reserved0;
|
||||||
|
(void)m_reserved1;
|
||||||
|
m_block = (SHA1_WORKSPACE_BLOCK*)m_workspace;
|
||||||
|
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SHA1_WIPE_VARIABLES
|
||||||
|
~CSHA1()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
// SHA1 initialization constants
|
||||||
|
m_state[0] = 0x67452301;
|
||||||
|
m_state[1] = 0xEFCDAB89;
|
||||||
|
m_state[2] = 0x98BADCFE;
|
||||||
|
m_state[3] = 0x10325476;
|
||||||
|
m_state[4] = 0xC3D2E1F0;
|
||||||
|
|
||||||
|
m_count[0] = 0;
|
||||||
|
m_count[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash in binary data and strings
|
||||||
|
void Update(const UINT_8* pbData, UINT_32 uLen)
|
||||||
|
{
|
||||||
|
UINT_32 j = ((m_count[0] >> 3) & 0x3F);
|
||||||
|
|
||||||
|
if ((m_count[0] += (uLen << 3)) < (uLen << 3))
|
||||||
|
++m_count[1]; // Overflow
|
||||||
|
|
||||||
|
m_count[1] += (uLen >> 29);
|
||||||
|
|
||||||
|
UINT_32 i;
|
||||||
|
if ((j + uLen) > 63)
|
||||||
|
{
|
||||||
|
i = 64 - j;
|
||||||
|
memcpy(&m_buffer[j], pbData, i);
|
||||||
|
Transform(m_state, m_buffer);
|
||||||
|
|
||||||
|
for (; (i + 63) < uLen; i += 64)
|
||||||
|
Transform(m_state, &pbData[i]);
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
}
|
||||||
|
else i = 0;
|
||||||
|
|
||||||
|
if ((uLen - i) != 0)
|
||||||
|
memcpy(&m_buffer[j], &pbData[i], uLen - i);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||||
|
// Hash in file contents
|
||||||
|
bool HashFile(const TCHAR* tszFileName)
|
||||||
|
{
|
||||||
|
if (tszFileName == NULL) return false;
|
||||||
|
|
||||||
|
FILE* fpIn = _tfopen(tszFileName, _T("rb"));
|
||||||
|
if (fpIn == NULL) return false;
|
||||||
|
|
||||||
|
UINT_8* pbData = new UINT_8[SHA1_MAX_FILE_BUFFER];
|
||||||
|
if (pbData == NULL) { fclose(fpIn); return false; }
|
||||||
|
|
||||||
|
bool bSuccess = true;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
const size_t uRead = fread(pbData, 1, SHA1_MAX_FILE_BUFFER, fpIn);
|
||||||
|
|
||||||
|
if (uRead > 0)
|
||||||
|
Update(pbData, static_cast<UINT_32>(uRead));
|
||||||
|
|
||||||
|
if (uRead < SHA1_MAX_FILE_BUFFER)
|
||||||
|
{
|
||||||
|
if (feof(fpIn) == 0) bSuccess = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fpIn);
|
||||||
|
delete[] pbData;
|
||||||
|
return bSuccess;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Finalize hash; call it before using ReportHash(Stl)
|
||||||
|
void Final()
|
||||||
|
{
|
||||||
|
UINT_32 i;
|
||||||
|
|
||||||
|
UINT_8 pbFinalCount[8];
|
||||||
|
for (i = 0; i < 8; ++i)
|
||||||
|
pbFinalCount[i] = static_cast<UINT_8>((m_count[((i >= 4) ? 0 : 1)] >>
|
||||||
|
((3 - (i & 3)) * 8)) & 0xFF); // Endian independent
|
||||||
|
|
||||||
|
Update((UINT_8*)"\200", 1);
|
||||||
|
|
||||||
|
while ((m_count[0] & 504) != 448)
|
||||||
|
Update((UINT_8*)"\0", 1);
|
||||||
|
|
||||||
|
Update(pbFinalCount, 8); // Cause a Transform()
|
||||||
|
|
||||||
|
for (i = 0; i < 20; ++i)
|
||||||
|
m_digest[i] = static_cast<UINT_8>((m_state[i >> 2] >> ((3 -
|
||||||
|
(i & 3)) * 8)) & 0xFF);
|
||||||
|
|
||||||
|
// Wipe variables for security reasons
|
||||||
|
#ifdef SHA1_WIPE_VARIABLES
|
||||||
|
memset(m_buffer, 0, 64);
|
||||||
|
memset(m_state, 0, 20);
|
||||||
|
memset(m_count, 0, 8);
|
||||||
|
memset(pbFinalCount, 0, 8);
|
||||||
|
Transform(m_state, m_buffer);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SHA1_UTILITY_FUNCTIONS
|
||||||
|
bool ReportHash(TCHAR* tszReport, REPORT_TYPE rtReportType = REPORT_HEX) const
|
||||||
|
{
|
||||||
|
if (tszReport == NULL) return false;
|
||||||
|
|
||||||
|
TCHAR tszTemp[16];
|
||||||
|
|
||||||
|
if ((rtReportType == REPORT_HEX) || (rtReportType == REPORT_HEX_SHORT))
|
||||||
|
{
|
||||||
|
_sntprintf(tszTemp, 15, _T("%02X"), m_digest[0]);
|
||||||
|
_tcscpy(tszReport, tszTemp);
|
||||||
|
|
||||||
|
const TCHAR* lpFmt = ((rtReportType == REPORT_HEX) ? _T(" %02X") : _T("%02X"));
|
||||||
|
for (size_t i = 1; i < 20; ++i)
|
||||||
|
{
|
||||||
|
_sntprintf(tszTemp, 15, lpFmt, m_digest[i]);
|
||||||
|
_tcscat(tszReport, tszTemp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (rtReportType == REPORT_DIGIT)
|
||||||
|
{
|
||||||
|
_sntprintf(tszTemp, 15, _T("%u"), m_digest[0]);
|
||||||
|
_tcscpy(tszReport, tszTemp);
|
||||||
|
|
||||||
|
for (size_t i = 1; i < 20; ++i)
|
||||||
|
{
|
||||||
|
_sntprintf(tszTemp, 15, _T(" %u"), m_digest[i]);
|
||||||
|
_tcscat(tszReport, tszTemp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SHA1_STL_FUNCTIONS
|
||||||
|
bool ReportHashStl(std::basic_string<TCHAR>& strOut, REPORT_TYPE rtReportType =
|
||||||
|
REPORT_HEX) const
|
||||||
|
{
|
||||||
|
TCHAR tszOut[84];
|
||||||
|
const bool bResult = ReportHash(tszOut, rtReportType);
|
||||||
|
if (bResult) strOut = tszOut;
|
||||||
|
return bResult;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Get the raw message digest (20 bytes)
|
||||||
|
bool GetHash(UINT_8* pbDest20) const
|
||||||
|
{
|
||||||
|
if (pbDest20 == NULL) return false;
|
||||||
|
memcpy(pbDest20, m_digest, 20);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Private SHA-1 transformation
|
||||||
|
void Transform(UINT_32* pState, const UINT_8* pBuffer)
|
||||||
|
{
|
||||||
|
UINT_32 a = pState[0], b = pState[1], c = pState[2], d = pState[3], e = pState[4];
|
||||||
|
|
||||||
|
memcpy(m_block, pBuffer, 64);
|
||||||
|
|
||||||
|
// 4 rounds of 20 operations each, loop unrolled
|
||||||
|
S_R0(a, b, c, d, e, 0); S_R0(e, a, b, c, d, 1); S_R0(d, e, a, b, c, 2); S_R0(c, d, e, a, b, 3);
|
||||||
|
S_R0(b, c, d, e, a, 4); S_R0(a, b, c, d, e, 5); S_R0(e, a, b, c, d, 6); S_R0(d, e, a, b, c, 7);
|
||||||
|
S_R0(c, d, e, a, b, 8); S_R0(b, c, d, e, a, 9); S_R0(a, b, c, d, e, 10); S_R0(e, a, b, c, d, 11);
|
||||||
|
S_R0(d, e, a, b, c, 12); S_R0(c, d, e, a, b, 13); S_R0(b, c, d, e, a, 14); S_R0(a, b, c, d, e, 15);
|
||||||
|
S_R1(e, a, b, c, d, 16); S_R1(d, e, a, b, c, 17); S_R1(c, d, e, a, b, 18); S_R1(b, c, d, e, a, 19);
|
||||||
|
S_R2(a, b, c, d, e, 20); S_R2(e, a, b, c, d, 21); S_R2(d, e, a, b, c, 22); S_R2(c, d, e, a, b, 23);
|
||||||
|
S_R2(b, c, d, e, a, 24); S_R2(a, b, c, d, e, 25); S_R2(e, a, b, c, d, 26); S_R2(d, e, a, b, c, 27);
|
||||||
|
S_R2(c, d, e, a, b, 28); S_R2(b, c, d, e, a, 29); S_R2(a, b, c, d, e, 30); S_R2(e, a, b, c, d, 31);
|
||||||
|
S_R2(d, e, a, b, c, 32); S_R2(c, d, e, a, b, 33); S_R2(b, c, d, e, a, 34); S_R2(a, b, c, d, e, 35);
|
||||||
|
S_R2(e, a, b, c, d, 36); S_R2(d, e, a, b, c, 37); S_R2(c, d, e, a, b, 38); S_R2(b, c, d, e, a, 39);
|
||||||
|
S_R3(a, b, c, d, e, 40); S_R3(e, a, b, c, d, 41); S_R3(d, e, a, b, c, 42); S_R3(c, d, e, a, b, 43);
|
||||||
|
S_R3(b, c, d, e, a, 44); S_R3(a, b, c, d, e, 45); S_R3(e, a, b, c, d, 46); S_R3(d, e, a, b, c, 47);
|
||||||
|
S_R3(c, d, e, a, b, 48); S_R3(b, c, d, e, a, 49); S_R3(a, b, c, d, e, 50); S_R3(e, a, b, c, d, 51);
|
||||||
|
S_R3(d, e, a, b, c, 52); S_R3(c, d, e, a, b, 53); S_R3(b, c, d, e, a, 54); S_R3(a, b, c, d, e, 55);
|
||||||
|
S_R3(e, a, b, c, d, 56); S_R3(d, e, a, b, c, 57); S_R3(c, d, e, a, b, 58); S_R3(b, c, d, e, a, 59);
|
||||||
|
S_R4(a, b, c, d, e, 60); S_R4(e, a, b, c, d, 61); S_R4(d, e, a, b, c, 62); S_R4(c, d, e, a, b, 63);
|
||||||
|
S_R4(b, c, d, e, a, 64); S_R4(a, b, c, d, e, 65); S_R4(e, a, b, c, d, 66); S_R4(d, e, a, b, c, 67);
|
||||||
|
S_R4(c, d, e, a, b, 68); S_R4(b, c, d, e, a, 69); S_R4(a, b, c, d, e, 70); S_R4(e, a, b, c, d, 71);
|
||||||
|
S_R4(d, e, a, b, c, 72); S_R4(c, d, e, a, b, 73); S_R4(b, c, d, e, a, 74); S_R4(a, b, c, d, e, 75);
|
||||||
|
S_R4(e, a, b, c, d, 76); S_R4(d, e, a, b, c, 77); S_R4(c, d, e, a, b, 78); S_R4(b, c, d, e, a, 79);
|
||||||
|
|
||||||
|
// Add the working vars back into state
|
||||||
|
pState[0] += a;
|
||||||
|
pState[1] += b;
|
||||||
|
pState[2] += c;
|
||||||
|
pState[3] += d;
|
||||||
|
pState[4] += e;
|
||||||
|
|
||||||
|
// Wipe variables
|
||||||
|
#ifdef SHA1_WIPE_VARIABLES
|
||||||
|
a = b = c = d = e = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Member variables
|
||||||
|
UINT_32 m_state[5];
|
||||||
|
UINT_32 m_count[2];
|
||||||
|
UINT_32 m_reserved0[1]; // Memory alignment padding
|
||||||
|
UINT_8 m_buffer[64];
|
||||||
|
UINT_8 m_digest[20];
|
||||||
|
UINT_32 m_reserved1[3]; // Memory alignment padding
|
||||||
|
|
||||||
|
UINT_8 m_workspace[64];
|
||||||
|
SHA1_WORKSPACE_BLOCK* m_block; // SHA1 pointer to the byte array above
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SHA1_H_A545E61D43E9404E8D736869AB3CBFE7
|
140
libs/brynet/base/endian/Endian.hpp
Normal file
140
libs/brynet/base/endian/Endian.hpp
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cstdbool>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <brynet/net/SocketLibTypes.hpp>
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_LINUX
|
||||||
|
#include <endian.h>
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
#include <sys/_endian.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace brynet { namespace base { namespace endian {
|
||||||
|
|
||||||
|
inline uint64_t hl64ton(uint64_t hostValue)
|
||||||
|
{
|
||||||
|
uint64_t ret = 0;
|
||||||
|
uint32_t high, low;
|
||||||
|
|
||||||
|
low = hostValue & 0xFFFFFFFF;
|
||||||
|
high = (hostValue >> 32) & 0xFFFFFFFF;
|
||||||
|
low = htonl(low);
|
||||||
|
high = htonl(high);
|
||||||
|
ret = low;
|
||||||
|
ret <<= 32;
|
||||||
|
ret |= high;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t ntohl64(uint64_t netValue)
|
||||||
|
{
|
||||||
|
uint64_t ret = 0;
|
||||||
|
uint32_t high, low;
|
||||||
|
|
||||||
|
low = netValue & 0xFFFFFFFF;
|
||||||
|
high = (netValue >> 32) & 0xFFFFFFFF;
|
||||||
|
low = ntohl(low);
|
||||||
|
high = ntohl(high);
|
||||||
|
ret = low;
|
||||||
|
ret <<= 32;
|
||||||
|
ret |= high;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? hl64ton(host64) : host64;
|
||||||
|
}
|
||||||
|
inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? htonl(host32) : host32;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? htons(host16) : host16;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t networkToHost64(uint64_t net64, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? ntohl64(net64) : net64;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t networkToHost32(uint32_t net32, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? ntohl(net32) : net32;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t networkToHost16(uint16_t net16, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? ntohs(net16) : net16;
|
||||||
|
}
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX
|
||||||
|
inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? htobe64(host64) : host64;
|
||||||
|
}
|
||||||
|
inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? htobe32(host32) : host32;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? htobe16(host16) : host16;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t networkToHost64(uint64_t net64, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? be64toh(net64) : net64;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t networkToHost32(uint32_t net32, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? be32toh(net32) : net32;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t networkToHost16(uint16_t net16, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? be16toh(net16) : net16;
|
||||||
|
}
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
inline uint64_t hostToNetwork64(uint64_t host64, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? hl64ton(host64) : host64;
|
||||||
|
}
|
||||||
|
inline uint32_t hostToNetwork32(uint32_t host32, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? htonl(host32) : host32;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t hostToNetwork16(uint16_t host16, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? htons(host16) : host16;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t networkToHost64(uint64_t net64, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? ntohl64(net64) : net64;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint32_t networkToHost32(uint32_t net32, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? ntohl(net32) : net32;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint16_t networkToHost16(uint16_t net16, bool convert = true)
|
||||||
|
{
|
||||||
|
return convert ? ntohs(net16) : net16;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} } }
|
89
libs/brynet/net/AsyncConnector.hpp
Normal file
89
libs/brynet/net/AsyncConnector.hpp
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <brynet/net/detail/ConnectorDetail.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace net {
|
||||||
|
|
||||||
|
class ConnectOption final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using CompletedCallback = std::function<void(TcpSocket::Ptr)>;
|
||||||
|
using ProcessTcpSocketCallback = std::function<void(TcpSocket&)>;
|
||||||
|
using FailedCallback = std::function<void()>;
|
||||||
|
using ConnectOptionFunc = detail::ConnectOptionFunc;
|
||||||
|
|
||||||
|
static ConnectOptionFunc WithAddr(const std::string& ip, int port)
|
||||||
|
{
|
||||||
|
return [ip, port](detail::ConnectOptionsInfo& option) {
|
||||||
|
option.ip = ip;
|
||||||
|
option.port = port;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
static ConnectOptionFunc WithTimeout(std::chrono::nanoseconds timeout)
|
||||||
|
{
|
||||||
|
return [timeout](detail::ConnectOptionsInfo& option) {
|
||||||
|
option.timeout = timeout;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
static ConnectOptionFunc WithCompletedCallback(CompletedCallback callback)
|
||||||
|
{
|
||||||
|
return [callback](detail::ConnectOptionsInfo& option) {
|
||||||
|
option.completedCallback = callback;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
static ConnectOptionFunc AddProcessTcpSocketCallback(ProcessTcpSocketCallback process)
|
||||||
|
{
|
||||||
|
return [process](detail::ConnectOptionsInfo& option) {
|
||||||
|
option.processCallbacks.push_back(process);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
static ConnectOptionFunc WithFailedCallback(FailedCallback callback)
|
||||||
|
{
|
||||||
|
return [callback](detail::ConnectOptionsInfo& option) {
|
||||||
|
option.faledCallback = callback;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::chrono::nanoseconds ExtractTimeout(const std::vector<ConnectOptionFunc>& options)
|
||||||
|
{
|
||||||
|
detail::ConnectOptionsInfo option;
|
||||||
|
for (const auto& func : options)
|
||||||
|
{
|
||||||
|
func(option);
|
||||||
|
}
|
||||||
|
return option.timeout;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AsyncConnector : public detail::AsyncConnectorDetail,
|
||||||
|
public std::enable_shared_from_this<AsyncConnector>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = std::shared_ptr<AsyncConnector>;
|
||||||
|
|
||||||
|
void startWorkerThread()
|
||||||
|
{
|
||||||
|
detail::AsyncConnectorDetail::startWorkerThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopWorkerThread()
|
||||||
|
{
|
||||||
|
detail::AsyncConnectorDetail::stopWorkerThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void asyncConnect(const std::vector<detail::ConnectOptionFunc>& options)
|
||||||
|
{
|
||||||
|
detail::AsyncConnectorDetail::asyncConnect(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Ptr Create()
|
||||||
|
{
|
||||||
|
class make_shared_enabler : public AsyncConnector {};
|
||||||
|
return std::make_shared<make_shared_enabler>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AsyncConnector() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
20
libs/brynet/net/Channel.hpp
Normal file
20
libs/brynet/net/Channel.hpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace brynet { namespace net {
|
||||||
|
|
||||||
|
class EventLoop;
|
||||||
|
|
||||||
|
class Channel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Channel() = default;
|
||||||
|
|
||||||
|
private:
|
||||||
|
virtual void canSend() = 0;
|
||||||
|
virtual void canRecv() = 0;
|
||||||
|
virtual void onClose() = 0;
|
||||||
|
|
||||||
|
friend class EventLoop;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
55
libs/brynet/net/CurrentThread.hpp
Normal file
55
libs/brynet/net/CurrentThread.hpp
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <brynet/base/Platform.hpp>
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <Windows.h>
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <linux/unistd.h>
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace brynet { namespace net { namespace current_thread {
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
using THREAD_ID_TYPE = DWORD;
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
using THREAD_ID_TYPE = int;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static THREAD_ID_TYPE& tid()
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
static __declspec(thread) THREAD_ID_TYPE cachedTid = 0;
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
static __thread THREAD_ID_TYPE cachedTid = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (cachedTid == 0)
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
cachedTid = GetCurrentThreadId();
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX
|
||||||
|
cachedTid = static_cast<pid_t>(::syscall(SYS_gettid));
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
// warning: 'syscall' is deprecated:
|
||||||
|
// first deprecated in macOS 10.12 - syscall(2) is unsupported;
|
||||||
|
// please switch to a supported interface.
|
||||||
|
uint64_t tid64;
|
||||||
|
pthread_threadid_np(NULL, &tid64);
|
||||||
|
cachedTid = (pid_t)tid64;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedTid;
|
||||||
|
}
|
||||||
|
|
||||||
|
} } }
|
444
libs/brynet/net/EventLoop.hpp
Normal file
444
libs/brynet/net/EventLoop.hpp
Normal file
@ -0,0 +1,444 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
#include <mutex>
|
||||||
|
#include <memory>
|
||||||
|
#include <atomic>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <cassert>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <brynet/base/Timer.hpp>
|
||||||
|
#include <brynet/base/NonCopyable.hpp>
|
||||||
|
#include <brynet/base/Noexcept.hpp>
|
||||||
|
#include <brynet/net/SocketLibFunction.hpp>
|
||||||
|
#include <brynet/net/CurrentThread.hpp>
|
||||||
|
|
||||||
|
#include <brynet/net/Channel.hpp>
|
||||||
|
#include <brynet/net/Socket.hpp>
|
||||||
|
#include <brynet/net/Exception.hpp>
|
||||||
|
#include <brynet/net/detail/WakeupChannel.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace net {
|
||||||
|
|
||||||
|
class Channel;
|
||||||
|
class TcpConnection;
|
||||||
|
using TcpConnectionPtr = std::shared_ptr<TcpConnection>;
|
||||||
|
|
||||||
|
class EventLoop : public brynet::base::NonCopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = std::shared_ptr<EventLoop>;
|
||||||
|
using UserFunctor = std::function<void(void)>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
EventLoop()
|
||||||
|
BRYNET_NOEXCEPT
|
||||||
|
:
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
mIOCP(CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 1)),
|
||||||
|
mWakeupChannel(std::make_unique<detail::WakeupChannel>(mIOCP))
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX
|
||||||
|
mEpollFd(epoll_create(1))
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
mKqueueFd(kqueue())
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
mPGetQueuedCompletionStatusEx = NULL;
|
||||||
|
auto kernel32_module = GetModuleHandleA("kernel32.dll");
|
||||||
|
if (kernel32_module != NULL) {
|
||||||
|
mPGetQueuedCompletionStatusEx = reinterpret_cast<sGetQueuedCompletionStatusEx>(GetProcAddress(
|
||||||
|
kernel32_module,
|
||||||
|
"GetQueuedCompletionStatusEx"));
|
||||||
|
FreeLibrary(kernel32_module);
|
||||||
|
}
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX
|
||||||
|
auto eventfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||||
|
mWakeupChannel.reset(new detail::WakeupChannel(eventfd));
|
||||||
|
linkChannel(eventfd, mWakeupChannel.get());
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
const int NOTIFY_IDENT = 42; // Magic number we use for our filter ID.
|
||||||
|
mWakeupChannel.reset(new detail::WakeupChannel(mKqueueFd, NOTIFY_IDENT));
|
||||||
|
//Add user event
|
||||||
|
struct kevent ev;
|
||||||
|
EV_SET(&ev, NOTIFY_IDENT, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL);
|
||||||
|
|
||||||
|
struct timespec timeout = { 0, 0 };
|
||||||
|
kevent(mKqueueFd, &ev, 1, NULL, 0, &timeout);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mIsAlreadyPostWakeup = false;
|
||||||
|
mIsInBlock = true;
|
||||||
|
|
||||||
|
reallocEventSize(1024);
|
||||||
|
mSelfThreadID = -1;
|
||||||
|
mTimer = std::make_shared<brynet::base::TimerMgr>();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~EventLoop() BRYNET_NOEXCEPT
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
CloseHandle(mIOCP);
|
||||||
|
mIOCP = INVALID_HANDLE_VALUE;
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX
|
||||||
|
close(mEpollFd);
|
||||||
|
mEpollFd = -1;
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
close(mKqueueFd);
|
||||||
|
mKqueueFd = -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(int64_t milliseconds)
|
||||||
|
{
|
||||||
|
tryInitThreadID();
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert(isInLoopThread());
|
||||||
|
#endif
|
||||||
|
if (!isInLoopThread())
|
||||||
|
{
|
||||||
|
throw BrynetCommonException("only loop in io thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mAfterLoopFunctors.empty())
|
||||||
|
{
|
||||||
|
milliseconds = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
ULONG numComplete = 0;
|
||||||
|
if (mPGetQueuedCompletionStatusEx != nullptr)
|
||||||
|
{
|
||||||
|
if (!mPGetQueuedCompletionStatusEx(mIOCP,
|
||||||
|
mEventEntries.data(),
|
||||||
|
static_cast<ULONG>(mEventEntries.size()),
|
||||||
|
&numComplete,
|
||||||
|
static_cast<DWORD>(milliseconds),
|
||||||
|
false))
|
||||||
|
{
|
||||||
|
numComplete = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (auto& e : mEventEntries)
|
||||||
|
{
|
||||||
|
const auto timeout = (numComplete == 0) ? static_cast<DWORD>(milliseconds) : 0;
|
||||||
|
/* don't check the return value of GQCS */
|
||||||
|
GetQueuedCompletionStatus(mIOCP,
|
||||||
|
&e.dwNumberOfBytesTransferred,
|
||||||
|
&e.lpCompletionKey,
|
||||||
|
&e.lpOverlapped,
|
||||||
|
timeout);
|
||||||
|
if (e.lpOverlapped == nullptr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++numComplete;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mIsInBlock = false;
|
||||||
|
|
||||||
|
for (ULONG i = 0; i < numComplete; ++i)
|
||||||
|
{
|
||||||
|
auto channel = (Channel*)mEventEntries[i].lpCompletionKey;
|
||||||
|
assert(channel != nullptr);
|
||||||
|
const auto ovl = reinterpret_cast<const port::Win::OverlappedExt*>(mEventEntries[i].lpOverlapped);
|
||||||
|
if (ovl->OP == port::Win::OverlappedType::OverlappedRecv)
|
||||||
|
{
|
||||||
|
channel->canRecv();
|
||||||
|
}
|
||||||
|
else if (ovl->OP == port::Win::OverlappedType::OverlappedSend)
|
||||||
|
{
|
||||||
|
channel->canSend();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX
|
||||||
|
int numComplete = epoll_wait(mEpollFd, mEventEntries.data(), mEventEntries.size(), milliseconds);
|
||||||
|
|
||||||
|
mIsInBlock = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < numComplete; ++i)
|
||||||
|
{
|
||||||
|
auto channel = (Channel*)(mEventEntries[i].data.ptr);
|
||||||
|
auto event_data = mEventEntries[i].events;
|
||||||
|
|
||||||
|
if (event_data & EPOLLRDHUP)
|
||||||
|
{
|
||||||
|
channel->canRecv();
|
||||||
|
channel->onClose();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event_data & EPOLLIN)
|
||||||
|
{
|
||||||
|
channel->canRecv();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event_data & EPOLLOUT)
|
||||||
|
{
|
||||||
|
channel->canSend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
struct timespec timeout = { milliseconds / 1000, (milliseconds % 1000) * 1000 * 1000 };
|
||||||
|
int numComplete = kevent(mKqueueFd, NULL, 0, mEventEntries.data(), mEventEntries.size(), &timeout);
|
||||||
|
|
||||||
|
mIsInBlock = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < numComplete; ++i)
|
||||||
|
{
|
||||||
|
auto channel = (Channel*)(mEventEntries[i].udata);
|
||||||
|
const struct kevent& event = mEventEntries[i];
|
||||||
|
|
||||||
|
if (event.filter == EVFILT_USER)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.filter == EVFILT_READ)
|
||||||
|
{
|
||||||
|
channel->canRecv();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.filter == EVFILT_WRITE)
|
||||||
|
{
|
||||||
|
channel->canSend();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mIsAlreadyPostWakeup = false;
|
||||||
|
mIsInBlock = true;
|
||||||
|
|
||||||
|
processAsyncFunctors();
|
||||||
|
processAfterLoopFunctors();
|
||||||
|
|
||||||
|
if (static_cast<size_t>(numComplete) == mEventEntries.size())
|
||||||
|
{
|
||||||
|
reallocEventSize(mEventEntries.size() + 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
mTimer->schedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop指定毫秒数,但如果定时器不为空,则loop时间为当前最近定时器的剩余时间和milliseconds的较小值
|
||||||
|
void loopCompareNearTimer(int64_t milliseconds)
|
||||||
|
{
|
||||||
|
tryInitThreadID();
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
assert(isInLoopThread());
|
||||||
|
#endif
|
||||||
|
if (!isInLoopThread())
|
||||||
|
{
|
||||||
|
throw BrynetCommonException("only loop in IO thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mTimer->isEmpty())
|
||||||
|
{
|
||||||
|
auto nearTimeout = std::chrono::duration_cast<std::chrono::milliseconds>(mTimer->nearLeftTime());
|
||||||
|
milliseconds = std::min<int64_t>(milliseconds, nearTimeout.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
loop(milliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回true表示实际发生了wakeup所需的操作(此返回值不代表接口本身操作成功与否,因为此函数永远成功)
|
||||||
|
bool wakeup()
|
||||||
|
{
|
||||||
|
if (!isInLoopThread() && mIsInBlock && !mIsAlreadyPostWakeup.exchange(true))
|
||||||
|
{
|
||||||
|
return mWakeupChannel->wakeup();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void runAsyncFunctor(UserFunctor&& f)
|
||||||
|
{
|
||||||
|
if (isInLoopThread())
|
||||||
|
{
|
||||||
|
f();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pushAsyncFunctor(std::move(f));
|
||||||
|
wakeup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void runFunctorAfterLoop(UserFunctor&& f)
|
||||||
|
{
|
||||||
|
assert(isInLoopThread());
|
||||||
|
if (!isInLoopThread())
|
||||||
|
{
|
||||||
|
throw BrynetCommonException("only push after functor in io thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
mAfterLoopFunctors.emplace_back(std::move(f));
|
||||||
|
}
|
||||||
|
brynet::base::Timer::WeakPtr runAfter(std::chrono::nanoseconds timeout, UserFunctor&& callback)
|
||||||
|
{
|
||||||
|
auto timer = std::make_shared<brynet::base::Timer>(
|
||||||
|
std::chrono::steady_clock::now(),
|
||||||
|
std::chrono::nanoseconds(timeout),
|
||||||
|
std::move(callback));
|
||||||
|
|
||||||
|
if (isInLoopThread())
|
||||||
|
{
|
||||||
|
mTimer->addTimer(timer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto timerMgr = mTimer;
|
||||||
|
runAsyncFunctor([timerMgr, timer]() {
|
||||||
|
timerMgr->addTimer(timer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return timer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool isInLoopThread() const
|
||||||
|
{
|
||||||
|
return mSelfThreadID == current_thread::tid();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void reallocEventSize(size_t size)
|
||||||
|
{
|
||||||
|
mEventEntries.resize(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void processAfterLoopFunctors()
|
||||||
|
{
|
||||||
|
mCopyAfterLoopFunctors.swap(mAfterLoopFunctors);
|
||||||
|
for (const auto& x : mCopyAfterLoopFunctors)
|
||||||
|
{
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
mCopyAfterLoopFunctors.clear();
|
||||||
|
}
|
||||||
|
void processAsyncFunctors()
|
||||||
|
{
|
||||||
|
swapAsyncFunctors();
|
||||||
|
|
||||||
|
for (const auto& x : mCopyAsyncFunctors)
|
||||||
|
{
|
||||||
|
x();
|
||||||
|
}
|
||||||
|
mCopyAsyncFunctors.clear();
|
||||||
|
}
|
||||||
|
void swapAsyncFunctors()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lck(mAsyncFunctorsMutex);
|
||||||
|
assert(mCopyAsyncFunctors.empty());
|
||||||
|
mCopyAsyncFunctors.swap(mAsyncFunctors);
|
||||||
|
}
|
||||||
|
void pushAsyncFunctor(UserFunctor&& f)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lck(mAsyncFunctorsMutex);
|
||||||
|
mAsyncFunctors.emplace_back(std::move(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_LINUX
|
||||||
|
int getEpollHandle() const
|
||||||
|
{
|
||||||
|
return mEpollFd;
|
||||||
|
}
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
int getKqueueHandle() const
|
||||||
|
{
|
||||||
|
return mKqueueFd;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
bool linkChannel(BrynetSocketFD fd, const Channel* ptr) BRYNET_NOEXCEPT
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
return CreateIoCompletionPort((HANDLE)fd, mIOCP, (ULONG_PTR)ptr, 0) != nullptr;
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX
|
||||||
|
struct epoll_event ev = { 0, { nullptr } };
|
||||||
|
ev.events = EPOLLET | EPOLLIN | EPOLLOUT | EPOLLRDHUP;
|
||||||
|
ev.data.ptr = (void*)ptr;
|
||||||
|
return epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &ev) == 0;
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
struct kevent ev[2];
|
||||||
|
memset(&ev, 0, sizeof(ev));
|
||||||
|
int n = 0;
|
||||||
|
EV_SET(&ev[n++], fd, EVFILT_READ, EV_ADD | EV_CLEAR, NOTE_TRIGGER, 0, (void*)ptr);
|
||||||
|
EV_SET(&ev[n++], fd, EVFILT_WRITE, EV_ADD | EV_CLEAR, NOTE_TRIGGER, 0, (void*)ptr);
|
||||||
|
|
||||||
|
struct timespec now = { 0, 0 };
|
||||||
|
return kevent(mKqueueFd, ev, n, NULL, 0, &now) == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
TcpConnectionPtr getTcpConnection(BrynetSocketFD fd)
|
||||||
|
{
|
||||||
|
auto it = mTcpConnections.find(fd);
|
||||||
|
if (it != mTcpConnections.end())
|
||||||
|
{
|
||||||
|
return (*it).second;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void addTcpConnection(BrynetSocketFD fd, TcpConnectionPtr tcpConnection)
|
||||||
|
{
|
||||||
|
mTcpConnections[fd] = std::move(tcpConnection);
|
||||||
|
}
|
||||||
|
void removeTcpConnection(BrynetSocketFD fd)
|
||||||
|
{
|
||||||
|
mTcpConnections.erase(fd);
|
||||||
|
}
|
||||||
|
void tryInitThreadID()
|
||||||
|
{
|
||||||
|
std::call_once(mOnceInitThreadID, [this]() {
|
||||||
|
mSelfThreadID = current_thread::tid();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
std::vector<OVERLAPPED_ENTRY> mEventEntries;
|
||||||
|
|
||||||
|
typedef BOOL(WINAPI *sGetQueuedCompletionStatusEx) (HANDLE, LPOVERLAPPED_ENTRY, ULONG, PULONG, DWORD, BOOL);
|
||||||
|
sGetQueuedCompletionStatusEx mPGetQueuedCompletionStatusEx;
|
||||||
|
HANDLE mIOCP;
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX
|
||||||
|
std::vector<epoll_event> mEventEntries;
|
||||||
|
int mEpollFd;
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
std::vector<struct kevent> mEventEntries;
|
||||||
|
int mKqueueFd;
|
||||||
|
#endif
|
||||||
|
std::unique_ptr<detail::WakeupChannel> mWakeupChannel;
|
||||||
|
|
||||||
|
std::atomic_bool mIsInBlock;
|
||||||
|
std::atomic_bool mIsAlreadyPostWakeup;
|
||||||
|
|
||||||
|
std::mutex mAsyncFunctorsMutex;
|
||||||
|
std::vector<UserFunctor> mAsyncFunctors;
|
||||||
|
std::vector<UserFunctor> mCopyAsyncFunctors;
|
||||||
|
|
||||||
|
std::vector<UserFunctor> mAfterLoopFunctors;
|
||||||
|
std::vector<UserFunctor> mCopyAfterLoopFunctors;
|
||||||
|
|
||||||
|
std::once_flag mOnceInitThreadID;
|
||||||
|
current_thread::THREAD_ID_TYPE mSelfThreadID;
|
||||||
|
|
||||||
|
brynet::base::TimerMgr::Ptr mTimer;
|
||||||
|
std::unordered_map<BrynetSocketFD, TcpConnectionPtr> mTcpConnections;
|
||||||
|
|
||||||
|
friend class TcpConnection;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
41
libs/brynet/net/Exception.hpp
Normal file
41
libs/brynet/net/Exception.hpp
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
namespace brynet { namespace net {
|
||||||
|
|
||||||
|
class ConnectException : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ConnectException(const std::string& message)
|
||||||
|
:
|
||||||
|
std::runtime_error(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit ConnectException(const char* message)
|
||||||
|
:
|
||||||
|
std::runtime_error(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BrynetCommonException : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit BrynetCommonException(const std::string& message)
|
||||||
|
:
|
||||||
|
std::runtime_error(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit BrynetCommonException(const char* message)
|
||||||
|
:
|
||||||
|
std::runtime_error(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
58
libs/brynet/net/ListenThread.hpp
Normal file
58
libs/brynet/net/ListenThread.hpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <brynet/net/detail/ListenThreadDetail.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace net {
|
||||||
|
|
||||||
|
class ListenThread : public detail::ListenThreadDetail,
|
||||||
|
public std::enable_shared_from_this<ListenThread>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = std::shared_ptr<ListenThread>;
|
||||||
|
using AccepCallback = std::function<void(TcpSocket::Ptr)>;;
|
||||||
|
using TcpSocketProcessCallback = std::function<void(TcpSocket&)>;
|
||||||
|
|
||||||
|
void startListen()
|
||||||
|
{
|
||||||
|
detail::ListenThreadDetail::startListen();
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopListen()
|
||||||
|
{
|
||||||
|
detail::ListenThreadDetail::stopListen();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Ptr Create(bool isIPV6,
|
||||||
|
const std::string& ip,
|
||||||
|
int port,
|
||||||
|
const AccepCallback& callback,
|
||||||
|
const std::vector<TcpSocketProcessCallback> & processCallbacks = {})
|
||||||
|
{
|
||||||
|
class make_shared_enabler : public ListenThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
make_shared_enabler(bool isIPV6,
|
||||||
|
const std::string& ip,
|
||||||
|
int port,
|
||||||
|
const AccepCallback& callback,
|
||||||
|
const std::vector<TcpSocketProcessCallback>& processCallbacks)
|
||||||
|
:
|
||||||
|
ListenThread(isIPV6, ip, port, callback, processCallbacks)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
return std::make_shared<make_shared_enabler>(isIPV6, ip, port, callback, processCallbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ListenThread(bool isIPV6,
|
||||||
|
const std::string& ip,
|
||||||
|
int port,
|
||||||
|
const AccepCallback& callback,
|
||||||
|
const std::vector<TcpSocketProcessCallback>& processCallbacks)
|
||||||
|
:
|
||||||
|
detail::ListenThreadDetail(isIPV6, ip, port, callback, processCallbacks)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
266
libs/brynet/net/Poller.hpp
Normal file
266
libs/brynet/net/Poller.hpp
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdbool>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <brynet/net/SocketLibTypes.hpp>
|
||||||
|
#include <brynet/base/Stack.hpp>
|
||||||
|
|
||||||
|
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace brynet { namespace base {
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
const static int CHECK_READ_FLAG = (POLLIN | POLLRDNORM | POLLRDBAND);
|
||||||
|
const static int CHECK_WRITE_FLAG = (POLLOUT | POLLWRNORM);
|
||||||
|
const static int CHECK_ERROR_FLAG = (POLLERR | POLLHUP);
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
const static int CHECK_READ_FLAG = (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI);
|
||||||
|
const static int CHECK_WRITE_FLAG = (POLLOUT | POLLWRNORM | POLLWRBAND);
|
||||||
|
const static int CHECK_ERROR_FLAG = (POLLERR | POLLHUP);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum CheckType
|
||||||
|
{
|
||||||
|
ReadCheck = 0x1,
|
||||||
|
WriteCheck = 0x2,
|
||||||
|
ErrorCheck = 0x4,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct poller_s
|
||||||
|
{
|
||||||
|
struct pollfd* pollFds;
|
||||||
|
int nfds;
|
||||||
|
int limitSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void upstep_pollfd(struct poller_s* self, int upSize)
|
||||||
|
{
|
||||||
|
if (upSize <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pollfd* newPollfds = (struct pollfd*)malloc(
|
||||||
|
sizeof(struct pollfd) * (self->limitSize + upSize));
|
||||||
|
if (newPollfds == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->pollFds != nullptr)
|
||||||
|
{
|
||||||
|
memcpy(newPollfds, self->pollFds, sizeof(struct pollfd) * self->nfds);
|
||||||
|
free(self->pollFds);
|
||||||
|
self->pollFds = nullptr;
|
||||||
|
}
|
||||||
|
self->pollFds = newPollfds;
|
||||||
|
self->limitSize += upSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct pollfd* find_pollfd(struct poller_s* self, BrynetSocketFD fd)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < self->nfds; i++)
|
||||||
|
{
|
||||||
|
if (self->pollFds[i].fd == fd)
|
||||||
|
{
|
||||||
|
return self->pollFds + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void try_remove_pollfd(struct poller_s* self, BrynetSocketFD fd)
|
||||||
|
{
|
||||||
|
int pos = -1;
|
||||||
|
for (int i = 0; i < self->nfds; i++)
|
||||||
|
{
|
||||||
|
if (self->pollFds[i].fd == fd)
|
||||||
|
{
|
||||||
|
pos = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos != -1)
|
||||||
|
{
|
||||||
|
memmove(self->pollFds + pos,
|
||||||
|
self->pollFds + pos + 1,
|
||||||
|
sizeof(struct pollfd) * (self->nfds - pos - 1));
|
||||||
|
self->nfds--;
|
||||||
|
assert(self->nfds >= 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct poller_s* poller_new(void)
|
||||||
|
{
|
||||||
|
struct poller_s* ret = (struct poller_s*)malloc(sizeof(struct poller_s));
|
||||||
|
if (ret != nullptr)
|
||||||
|
{
|
||||||
|
ret->pollFds = NULL;
|
||||||
|
ret->limitSize = 0;
|
||||||
|
ret->nfds = 0;
|
||||||
|
upstep_pollfd(ret, 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void poller_delete(struct poller_s* self)
|
||||||
|
{
|
||||||
|
free(self->pollFds);
|
||||||
|
self->pollFds = nullptr;
|
||||||
|
self->nfds = 0;
|
||||||
|
self->limitSize = 0;
|
||||||
|
|
||||||
|
free(self);
|
||||||
|
self = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void poller_add(struct poller_s* self, BrynetSocketFD fd, int type)
|
||||||
|
{
|
||||||
|
if (self->limitSize == self->nfds)
|
||||||
|
{
|
||||||
|
upstep_pollfd(self, 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->limitSize <= self->nfds)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pollfd* pf = find_pollfd(self, fd);
|
||||||
|
if (pf == nullptr)
|
||||||
|
{
|
||||||
|
/*real add*/
|
||||||
|
pf = self->pollFds + self->nfds;
|
||||||
|
pf->events = 0;
|
||||||
|
pf->fd = fd;
|
||||||
|
|
||||||
|
self->nfds++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type & ReadCheck)
|
||||||
|
{
|
||||||
|
pf->events |= CHECK_READ_FLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type & WriteCheck)
|
||||||
|
{
|
||||||
|
pf->events |= CHECK_WRITE_FLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type & ErrorCheck)
|
||||||
|
{
|
||||||
|
//pf->events |= CHECK_ERROR_FLAG; TODO::on windows, not supports
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void poller_del(struct poller_s* self, BrynetSocketFD fd, int type)
|
||||||
|
{
|
||||||
|
struct pollfd* pf = find_pollfd(self, fd);
|
||||||
|
if (pf == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type & ReadCheck)
|
||||||
|
{
|
||||||
|
pf->events &= ~CHECK_READ_FLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type & WriteCheck)
|
||||||
|
{
|
||||||
|
pf->events &= ~CHECK_WRITE_FLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type & ErrorCheck)
|
||||||
|
{
|
||||||
|
pf->events &= ~CHECK_ERROR_FLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pf->events == 0)
|
||||||
|
{
|
||||||
|
try_remove_pollfd(self, fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void poller_remove(struct poller_s* self, BrynetSocketFD fd)
|
||||||
|
{
|
||||||
|
try_remove_pollfd(self, fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool check_event(const struct pollfd* pf, enum CheckType type)
|
||||||
|
{
|
||||||
|
if (pf == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((type & ReadCheck) &&
|
||||||
|
(pf->revents & CHECK_READ_FLAG))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if ((type & WriteCheck) &&
|
||||||
|
(pf->revents & CHECK_WRITE_FLAG))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if ((type & ErrorCheck) &&
|
||||||
|
(pf->revents & CHECK_ERROR_FLAG))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void poller_visitor(struct poller_s* self,
|
||||||
|
enum CheckType type,
|
||||||
|
struct stack_s* result)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < self->nfds; i++)
|
||||||
|
{
|
||||||
|
if (check_event(self->pollFds + i, type))
|
||||||
|
{
|
||||||
|
stack_push(result, &self->pollFds[i].fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int poller_poll(struct poller_s* self, long overtime)
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
int ret = WSAPoll(&self->pollFds[0], self->nfds, overtime);
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
int ret = poll(self->pollFds, self->nfds, overtime);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (ret == BRYNET_SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
ret = (BRYNET_ERRNO != BRYNET_EINTR) ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool poller_check(struct poller_s* self, BrynetSocketFD fd, enum CheckType type)
|
||||||
|
{
|
||||||
|
const struct pollfd* pf = find_pollfd(self, fd);
|
||||||
|
if (pf == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return check_event(pf, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
} }
|
155
libs/brynet/net/PromiseReceive.hpp
Normal file
155
libs/brynet/net/PromiseReceive.hpp
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <brynet/net/TcpService.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace net {
|
||||||
|
|
||||||
|
/* binary search in memory */
|
||||||
|
void memsearch(const char *hay, size_t haysize, const char *needle, size_t needlesize, size_t& result, bool& isOK)
|
||||||
|
{
|
||||||
|
size_t haypos, needlepos;
|
||||||
|
haysize -= needlesize;
|
||||||
|
|
||||||
|
for (haypos = 0; haypos <= haysize; haypos++)
|
||||||
|
{
|
||||||
|
for (needlepos = 0; needlepos < needlesize; needlepos++)
|
||||||
|
{
|
||||||
|
if (hay[haypos + needlepos] != needle[needlepos])
|
||||||
|
{
|
||||||
|
// Next character in haystack.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needlepos == needlesize)
|
||||||
|
{
|
||||||
|
result = haypos;
|
||||||
|
isOK = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isOK = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class PromiseReceive;
|
||||||
|
|
||||||
|
std::shared_ptr<PromiseReceive> setupPromiseReceive(const TcpConnection::Ptr& session);
|
||||||
|
|
||||||
|
class PromiseReceive : public std::enable_shared_from_this<PromiseReceive>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = std::shared_ptr<PromiseReceive>;
|
||||||
|
using Handle = std::function<bool(const char* buffer, size_t len)>;
|
||||||
|
|
||||||
|
PromiseReceive::Ptr receive(size_t len, Handle handle)
|
||||||
|
{
|
||||||
|
return receive(std::make_shared<size_t>(len), std::move(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
PromiseReceive::Ptr receive(std::shared_ptr<size_t> len, Handle handle)
|
||||||
|
{
|
||||||
|
return helpReceive(std::move(len), "", std::move(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
PromiseReceive::Ptr receiveUntil(std::string str, Handle handle)
|
||||||
|
{
|
||||||
|
if (str.empty())
|
||||||
|
{
|
||||||
|
throw std::runtime_error("str is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
return helpReceive(nullptr, std::move(str), std::move(handle));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
PromiseReceive::Ptr helpReceive(std::shared_ptr<size_t> len, std::string str, Handle handle)
|
||||||
|
{
|
||||||
|
auto pr = std::make_shared<PendingReceive>();
|
||||||
|
pr->len = std::move(len);
|
||||||
|
pr->str = std::move(str);
|
||||||
|
pr->handle = std::move(handle);
|
||||||
|
mPendingReceives.push_back(std::move(pr));
|
||||||
|
|
||||||
|
return shared_from_this();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t process(const char* buffer, const size_t len)
|
||||||
|
{
|
||||||
|
size_t procLen = 0;
|
||||||
|
|
||||||
|
while (!mPendingReceives.empty() && len >= procLen)
|
||||||
|
{
|
||||||
|
auto pendingReceive = mPendingReceives.front();
|
||||||
|
if (pendingReceive->len != nullptr)
|
||||||
|
{
|
||||||
|
const auto tryReceiveLen = *pendingReceive->len;
|
||||||
|
if ((len - procLen) < tryReceiveLen)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPendingReceives.pop_front();
|
||||||
|
procLen += tryReceiveLen;
|
||||||
|
if (pendingReceive->handle(buffer + procLen - tryReceiveLen, tryReceiveLen) && tryReceiveLen > 0)
|
||||||
|
{
|
||||||
|
mPendingReceives.push_front(pendingReceive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!pendingReceive->str.empty())
|
||||||
|
{
|
||||||
|
size_t pos = 0;
|
||||||
|
bool isOK = false;
|
||||||
|
auto data = buffer + procLen;
|
||||||
|
memsearch(buffer + procLen,
|
||||||
|
len - procLen,
|
||||||
|
pendingReceive->str.c_str(),
|
||||||
|
pendingReceive->str.size(),
|
||||||
|
pos,
|
||||||
|
isOK);
|
||||||
|
|
||||||
|
if (!isOK)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mPendingReceives.pop_front();
|
||||||
|
procLen += (pos + pendingReceive->str.size());
|
||||||
|
if (pendingReceive->handle(data, pos))
|
||||||
|
{
|
||||||
|
mPendingReceives.push_front(pendingReceive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return procLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PendingReceive
|
||||||
|
{
|
||||||
|
std::shared_ptr<size_t> len;
|
||||||
|
std::string str;
|
||||||
|
Handle handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::deque<std::shared_ptr<PendingReceive>> mPendingReceives;
|
||||||
|
|
||||||
|
friend std::shared_ptr<PromiseReceive> setupPromiseReceive(const TcpConnection::Ptr& session);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<PromiseReceive> setupPromiseReceive(const TcpConnection::Ptr& session)
|
||||||
|
{
|
||||||
|
auto promiseReceive = std::make_shared<PromiseReceive>();
|
||||||
|
session->setDataCallback([promiseReceive](const char* buffer,
|
||||||
|
size_t len) {
|
||||||
|
return promiseReceive->process(buffer, len);
|
||||||
|
});
|
||||||
|
|
||||||
|
return promiseReceive;
|
||||||
|
}
|
||||||
|
|
||||||
|
} }
|
174
libs/brynet/net/SSLHelper.hpp
Normal file
174
libs/brynet/net/SSLHelper.hpp
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <brynet/base/NonCopyable.hpp>
|
||||||
|
#include <brynet/base/Platform.hpp>
|
||||||
|
#include <brynet/base/Noexcept.hpp>
|
||||||
|
|
||||||
|
#ifdef BRYNET_USE_OPENSSL
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace brynet { namespace net {
|
||||||
|
|
||||||
|
#ifdef BRYNET_USE_OPENSSL
|
||||||
|
|
||||||
|
#ifndef CRYPTO_THREADID_set_callback
|
||||||
|
static void cryptoSetThreadIDCallback(CRYPTO_THREADID* id)
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
CRYPTO_THREADID_set_numeric(id,
|
||||||
|
static_cast<unsigned long>(GetCurrentThreadId()));
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
CRYPTO_THREADID_set_numeric(id,
|
||||||
|
static_cast<unsigned long>(pthread_self()));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CRYPTO_set_locking_callback
|
||||||
|
static std::unordered_map<int, std::shared_ptr<std::mutex>> cryptoLocks;
|
||||||
|
static void cryptoLockingCallback(int mode,
|
||||||
|
int type,
|
||||||
|
const char* file, int line)
|
||||||
|
{
|
||||||
|
(void)file;
|
||||||
|
(void)line;
|
||||||
|
if (mode & CRYPTO_LOCK)
|
||||||
|
{
|
||||||
|
cryptoLocks[type]->lock();
|
||||||
|
}
|
||||||
|
else if (mode & CRYPTO_UNLOCK)
|
||||||
|
{
|
||||||
|
cryptoLocks[type]->unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static std::once_flag initCryptoThreadSafeSupportOnceFlag;
|
||||||
|
static void InitCryptoThreadSafeSupport()
|
||||||
|
{
|
||||||
|
#ifndef CRYPTO_THREADID_set_callback
|
||||||
|
CRYPTO_THREADID_set_callback(cryptoSetThreadIDCallback);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CRYPTO_set_locking_callback
|
||||||
|
for (int i = 0; i < CRYPTO_num_locks(); i++)
|
||||||
|
{
|
||||||
|
cryptoLocks[i] = std::make_shared<std::mutex>();
|
||||||
|
}
|
||||||
|
CRYPTO_set_locking_callback(cryptoLockingCallback);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class SSLHelper : public brynet::base::NonCopyable,
|
||||||
|
public std::enable_shared_from_this<SSLHelper>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = std::shared_ptr<SSLHelper>;
|
||||||
|
|
||||||
|
#ifdef BRYNET_USE_OPENSSL
|
||||||
|
bool initSSL(const std::string& certificate,
|
||||||
|
const std::string& privatekey)
|
||||||
|
{
|
||||||
|
std::call_once(initCryptoThreadSafeSupportOnceFlag,
|
||||||
|
InitCryptoThreadSafeSupport);
|
||||||
|
|
||||||
|
if (mOpenSSLCTX != nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (certificate.empty() || privatekey.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mOpenSSLCTX = SSL_CTX_new(SSLv23_method());
|
||||||
|
SSL_CTX_set_client_CA_list(mOpenSSLCTX,
|
||||||
|
SSL_load_client_CA_file(certificate.c_str()));
|
||||||
|
SSL_CTX_set_verify_depth(mOpenSSLCTX, 10);
|
||||||
|
|
||||||
|
if (SSL_CTX_use_certificate_chain_file(mOpenSSLCTX,
|
||||||
|
certificate.c_str()) <= 0)
|
||||||
|
{
|
||||||
|
SSL_CTX_free(mOpenSSLCTX);
|
||||||
|
mOpenSSLCTX = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SSL_CTX_use_PrivateKey_file(mOpenSSLCTX,
|
||||||
|
privatekey.c_str(),
|
||||||
|
SSL_FILETYPE_PEM) <= 0)
|
||||||
|
{
|
||||||
|
SSL_CTX_free(mOpenSSLCTX);
|
||||||
|
mOpenSSLCTX = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SSL_CTX_check_private_key(mOpenSSLCTX))
|
||||||
|
{
|
||||||
|
SSL_CTX_free(mOpenSSLCTX);
|
||||||
|
mOpenSSLCTX = nullptr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroySSL()
|
||||||
|
{
|
||||||
|
if (mOpenSSLCTX != nullptr)
|
||||||
|
{
|
||||||
|
SSL_CTX_free(mOpenSSLCTX);
|
||||||
|
mOpenSSLCTX = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SSL_CTX* getOpenSSLCTX()
|
||||||
|
{
|
||||||
|
return mOpenSSLCTX;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
static Ptr Create()
|
||||||
|
{
|
||||||
|
class make_shared_enabler : public SSLHelper {};
|
||||||
|
return std::make_shared<make_shared_enabler>();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SSLHelper() BRYNET_NOEXCEPT
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_USE_OPENSSL
|
||||||
|
mOpenSSLCTX = nullptr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~SSLHelper() BRYNET_NOEXCEPT
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_USE_OPENSSL
|
||||||
|
destroySSL();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
#ifdef BRYNET_USE_OPENSSL
|
||||||
|
SSL_CTX* mOpenSSLCTX;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
230
libs/brynet/net/Socket.hpp
Normal file
230
libs/brynet/net/Socket.hpp
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <exception>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include <brynet/base/NonCopyable.hpp>
|
||||||
|
#include <brynet/net/SocketLibFunction.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace net {
|
||||||
|
|
||||||
|
class TcpConnection;
|
||||||
|
|
||||||
|
class UniqueFd final : public brynet::base::NonCopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit UniqueFd(BrynetSocketFD fd)
|
||||||
|
:
|
||||||
|
mFD(fd)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~UniqueFd()
|
||||||
|
{
|
||||||
|
brynet::net::base::SocketClose(mFD);
|
||||||
|
}
|
||||||
|
|
||||||
|
UniqueFd(const UniqueFd& other) = delete;
|
||||||
|
UniqueFd& operator=(const UniqueFd& other) = delete;
|
||||||
|
|
||||||
|
BrynetSocketFD getFD() const
|
||||||
|
{
|
||||||
|
return mFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BrynetSocketFD mFD;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TcpSocket : public brynet::base::NonCopyable
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
class TcpSocketDeleter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void operator()(TcpSocket* ptr) const
|
||||||
|
{
|
||||||
|
delete ptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
using Ptr = std::unique_ptr<TcpSocket, TcpSocketDeleter>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Ptr Create(BrynetSocketFD fd, bool serverSide)
|
||||||
|
{
|
||||||
|
class make_unique_enabler : public TcpSocket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
make_unique_enabler(BrynetSocketFD fd, bool serverSide)
|
||||||
|
:
|
||||||
|
TcpSocket(fd, serverSide)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ptr(new make_unique_enabler(fd, serverSide));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setNodelay() const
|
||||||
|
{
|
||||||
|
brynet::net::base::SocketNodelay(mFD);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setNonblock() const
|
||||||
|
{
|
||||||
|
return brynet::net::base::SocketNonblock(mFD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSendSize(int sdSize) const
|
||||||
|
{
|
||||||
|
brynet::net::base::SocketSetSendSize(mFD, sdSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setRecvSize(int rdSize) const
|
||||||
|
{
|
||||||
|
brynet::net::base::SocketSetRecvSize(mFD, rdSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string getRemoteIP() const
|
||||||
|
{
|
||||||
|
return brynet::net::base::GetIPOfSocket(mFD);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isServerSide() const
|
||||||
|
{
|
||||||
|
return mServerSide;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TcpSocket(BrynetSocketFD fd, bool serverSide)
|
||||||
|
:
|
||||||
|
mFD(fd),
|
||||||
|
mServerSide(serverSide)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~TcpSocket()
|
||||||
|
{
|
||||||
|
brynet::net::base::SocketClose(mFD);
|
||||||
|
}
|
||||||
|
|
||||||
|
BrynetSocketFD getFD() const
|
||||||
|
{
|
||||||
|
return mFD;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const BrynetSocketFD mFD;
|
||||||
|
const bool mServerSide;
|
||||||
|
|
||||||
|
friend class TcpConnection;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EintrError : public std::exception
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
class AcceptError : public std::runtime_error
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AcceptError(int errorCode)
|
||||||
|
:
|
||||||
|
std::runtime_error(std::to_string(errorCode)),
|
||||||
|
mErrorCode(errorCode)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int getErrorCode() const
|
||||||
|
{
|
||||||
|
return mErrorCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mErrorCode;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ListenSocket : public brynet::base::NonCopyable
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
class ListenSocketDeleter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void operator()(ListenSocket* ptr) const
|
||||||
|
{
|
||||||
|
delete ptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
using Ptr = std::unique_ptr<ListenSocket, ListenSocketDeleter>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TcpSocket::Ptr accept()
|
||||||
|
{
|
||||||
|
const auto clientFD = brynet::net::base::Accept(mFD, nullptr, nullptr);
|
||||||
|
if (clientFD == BRYNET_INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
if (BRYNET_ERRNO == EMFILE)
|
||||||
|
{
|
||||||
|
// Thanks libev and muduo.
|
||||||
|
// Read the section named "The special problem of
|
||||||
|
// accept()ing when you can't" in libev's doc.
|
||||||
|
// By Marc Lehmann, author of libev.
|
||||||
|
mIdle.reset();
|
||||||
|
TcpSocket::Create(brynet::net::base::Accept(mFD, nullptr, nullptr), true);
|
||||||
|
mIdle = brynet::net::TcpSocket::Create(::open("/dev/null", O_RDONLY | O_CLOEXEC), true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (BRYNET_ERRNO == EINTR)
|
||||||
|
{
|
||||||
|
throw EintrError();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw AcceptError(BRYNET_ERRNO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TcpSocket::Create(clientFD, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Ptr Create(BrynetSocketFD fd)
|
||||||
|
{
|
||||||
|
class make_unique_enabler : public ListenSocket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit make_unique_enabler(BrynetSocketFD fd)
|
||||||
|
: ListenSocket(fd)
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ptr(new make_unique_enabler(fd));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit ListenSocket(BrynetSocketFD fd)
|
||||||
|
:
|
||||||
|
mFD(fd)
|
||||||
|
{
|
||||||
|
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
mIdle = brynet::net::TcpSocket::Create(::open("/dev/null", O_RDONLY | O_CLOEXEC), true);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~ListenSocket()
|
||||||
|
{
|
||||||
|
brynet::net::base::SocketClose(mFD);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const BrynetSocketFD mFD;
|
||||||
|
#if defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
brynet::net::TcpSocket::Ptr mIdle;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
friend class TcpConnection;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
329
libs/brynet/net/SocketLibFunction.hpp
Normal file
329
libs/brynet/net/SocketLibFunction.hpp
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
#include <brynet/net/SocketLibTypes.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace net { namespace base {
|
||||||
|
|
||||||
|
static bool InitSocket()
|
||||||
|
{
|
||||||
|
bool ret = true;
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
static WSADATA g_WSAData;
|
||||||
|
static bool WinSockIsInit = false;
|
||||||
|
if (WinSockIsInit)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (WSAStartup(MAKEWORD(2, 2), &g_WSAData) == 0)
|
||||||
|
{
|
||||||
|
WinSockIsInit = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DestroySocket()
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
WSACleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SocketNodelay(BrynetSocketFD fd)
|
||||||
|
{
|
||||||
|
const int flag = 1;
|
||||||
|
return ::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&flag, sizeof(flag));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool SocketBlock(BrynetSocketFD fd)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
unsigned long ul = false;
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
err = ioctlsocket(fd, FIONBIO, &ul);
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
err = ioctl(fd, FIONBIO, &ul);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return err != BRYNET_SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool SocketNonblock(BrynetSocketFD fd)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
unsigned long ul = true;
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
err = ioctlsocket(fd, FIONBIO, &ul);
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
err = ioctl(fd, FIONBIO, &ul);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return err != BRYNET_SOCKET_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SocketSetSendSize(BrynetSocketFD fd, int sd_size)
|
||||||
|
{
|
||||||
|
return ::setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (const char*)&sd_size, sizeof(sd_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SocketSetRecvSize(BrynetSocketFD fd, int rd_size)
|
||||||
|
{
|
||||||
|
return ::setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (const char*)&rd_size, sizeof(rd_size));
|
||||||
|
}
|
||||||
|
|
||||||
|
static BrynetSocketFD SocketCreate(int af, int type, int protocol)
|
||||||
|
{
|
||||||
|
return ::socket(af, type, protocol);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SocketClose(BrynetSocketFD fd)
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
::closesocket(fd);
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
::close(fd);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static BrynetSocketFD Connect(bool isIPV6, const std::string& server_ip, int port)
|
||||||
|
{
|
||||||
|
InitSocket();
|
||||||
|
|
||||||
|
struct sockaddr_in ip4Addr = sockaddr_in();
|
||||||
|
struct sockaddr_in6 ip6Addr = sockaddr_in6();
|
||||||
|
struct sockaddr_in* paddr = &ip4Addr;
|
||||||
|
int addrLen = sizeof(ip4Addr);
|
||||||
|
|
||||||
|
BrynetSocketFD clientfd = isIPV6 ?
|
||||||
|
SocketCreate(AF_INET6, SOCK_STREAM, 0) :
|
||||||
|
SocketCreate(AF_INET, SOCK_STREAM, 0);
|
||||||
|
|
||||||
|
if (clientfd == BRYNET_INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
return clientfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ptonResult = false;
|
||||||
|
if (isIPV6)
|
||||||
|
{
|
||||||
|
ip6Addr.sin6_family = AF_INET6;
|
||||||
|
ip6Addr.sin6_port = htons(port);
|
||||||
|
ptonResult = inet_pton(AF_INET6,
|
||||||
|
server_ip.c_str(),
|
||||||
|
&ip6Addr.sin6_addr) > 0;
|
||||||
|
paddr = (struct sockaddr_in*) & ip6Addr;
|
||||||
|
addrLen = sizeof(ip6Addr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ip4Addr.sin_family = AF_INET;
|
||||||
|
ip4Addr.sin_port = htons(port);
|
||||||
|
ptonResult = inet_pton(AF_INET,
|
||||||
|
server_ip.c_str(),
|
||||||
|
&ip4Addr.sin_addr) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ptonResult)
|
||||||
|
{
|
||||||
|
SocketClose(clientfd);
|
||||||
|
return BRYNET_INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (::connect(clientfd, (struct sockaddr*)paddr, addrLen) < 0)
|
||||||
|
{
|
||||||
|
if (EINTR == BRYNET_ERRNO)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
SocketClose(clientfd);
|
||||||
|
return BRYNET_INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BrynetSocketFD Listen(bool isIPV6, const char* ip, int port, int back_num)
|
||||||
|
{
|
||||||
|
InitSocket();
|
||||||
|
|
||||||
|
struct sockaddr_in ip4Addr = sockaddr_in();
|
||||||
|
struct sockaddr_in6 ip6Addr = sockaddr_in6();
|
||||||
|
struct sockaddr_in* paddr = &ip4Addr;
|
||||||
|
int addrLen = sizeof(ip4Addr);
|
||||||
|
|
||||||
|
const auto socketfd = isIPV6 ?
|
||||||
|
socket(AF_INET6, SOCK_STREAM, 0) :
|
||||||
|
socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (socketfd == BRYNET_INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
return BRYNET_INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ptonResult = false;
|
||||||
|
if (isIPV6)
|
||||||
|
{
|
||||||
|
ip6Addr.sin6_family = AF_INET6;
|
||||||
|
ip6Addr.sin6_port = htons(port);
|
||||||
|
ptonResult = inet_pton(AF_INET6, ip, &ip6Addr.sin6_addr) > 0;
|
||||||
|
paddr = (struct sockaddr_in*) & ip6Addr;
|
||||||
|
addrLen = sizeof(ip6Addr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ip4Addr.sin_family = AF_INET;
|
||||||
|
ip4Addr.sin_port = htons(port);
|
||||||
|
ip4Addr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
ptonResult = inet_pton(AF_INET, ip, &ip4Addr.sin_addr) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int reuseaddr_value = 1;
|
||||||
|
if (!ptonResult ||
|
||||||
|
::setsockopt(socketfd,
|
||||||
|
SOL_SOCKET,
|
||||||
|
SO_REUSEADDR,
|
||||||
|
(const char*)&reuseaddr_value,
|
||||||
|
sizeof(int)) < 0)
|
||||||
|
{
|
||||||
|
SocketClose(socketfd);
|
||||||
|
return BRYNET_INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int bindRet = ::bind(socketfd, (struct sockaddr*)paddr, addrLen);
|
||||||
|
if (bindRet == BRYNET_SOCKET_ERROR ||
|
||||||
|
listen(socketfd, back_num) == BRYNET_SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
SocketClose(socketfd);
|
||||||
|
return BRYNET_INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
return socketfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string getIPString(const struct sockaddr* sa)
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
using PAddrType = PVOID;
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
using PAddrType = const void*;
|
||||||
|
#endif
|
||||||
|
char tmp[INET6_ADDRSTRLEN] = { 0 };
|
||||||
|
switch (sa->sa_family)
|
||||||
|
{
|
||||||
|
case AF_INET:
|
||||||
|
inet_ntop(AF_INET, (PAddrType)(&(((const struct sockaddr_in*)sa)->sin_addr)),
|
||||||
|
tmp, sizeof(tmp));
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
inet_ntop(AF_INET6, (PAddrType)(&(((const struct sockaddr_in6*)sa)->sin6_addr)),
|
||||||
|
tmp, sizeof(tmp));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return "Unknown AF";
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string GetIPOfSocket(BrynetSocketFD fd)
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
struct sockaddr name = sockaddr();
|
||||||
|
int namelen = sizeof(name);
|
||||||
|
if (::getpeername(fd, (struct sockaddr*) & name, &namelen) == 0)
|
||||||
|
{
|
||||||
|
return getIPString(&name);
|
||||||
|
}
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
struct sockaddr_in name = sockaddr_in();
|
||||||
|
socklen_t namelen = sizeof(name);
|
||||||
|
if (::getpeername(fd, (struct sockaddr*) & name, &namelen) == 0)
|
||||||
|
{
|
||||||
|
return getIPString((const struct sockaddr*) & name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SocketSend(BrynetSocketFD fd, const char* buffer, int len)
|
||||||
|
{
|
||||||
|
int transnum = ::send(fd, buffer, len, 0);
|
||||||
|
if (transnum < 0 && BRYNET_EWOULDBLOCK == BRYNET_ERRNO)
|
||||||
|
{
|
||||||
|
transnum = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send error if transnum < 0 */
|
||||||
|
return transnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BrynetSocketFD Accept(BrynetSocketFD listenSocket, struct sockaddr* addr, socklen_t* addrLen)
|
||||||
|
{
|
||||||
|
return ::accept(listenSocket, addr, addrLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sockaddr_in6 getPeerAddr(BrynetSocketFD sockfd)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 peeraddr = sockaddr_in6();
|
||||||
|
auto addrlen = static_cast<socklen_t>(sizeof peeraddr);
|
||||||
|
if (::getpeername(sockfd, (struct sockaddr*)(&peeraddr), &addrlen) < 0)
|
||||||
|
{
|
||||||
|
return peeraddr;
|
||||||
|
}
|
||||||
|
return peeraddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct sockaddr_in6 getLocalAddr(BrynetSocketFD sockfd)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 localaddr = sockaddr_in6();
|
||||||
|
auto addrlen = static_cast<socklen_t>(sizeof localaddr);
|
||||||
|
if (::getsockname(sockfd, (struct sockaddr*)(&localaddr), &addrlen) < 0)
|
||||||
|
{
|
||||||
|
return localaddr;
|
||||||
|
}
|
||||||
|
return localaddr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool IsSelfConnect(BrynetSocketFD fd)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 localaddr = getLocalAddr(fd);
|
||||||
|
struct sockaddr_in6 peeraddr = getPeerAddr(fd);
|
||||||
|
|
||||||
|
if (localaddr.sin6_family == AF_INET)
|
||||||
|
{
|
||||||
|
const struct sockaddr_in* laddr4 = reinterpret_cast<struct sockaddr_in*>(&localaddr);
|
||||||
|
const struct sockaddr_in* raddr4 = reinterpret_cast<struct sockaddr_in*>(&peeraddr);
|
||||||
|
return laddr4->sin_port == raddr4->sin_port
|
||||||
|
&& laddr4->sin_addr.s_addr == raddr4->sin_addr.s_addr;
|
||||||
|
}
|
||||||
|
else if (localaddr.sin6_family == AF_INET6)
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
return localaddr.sin6_port == peeraddr.sin6_port
|
||||||
|
&& memcmp(&localaddr.sin6_addr.u.Byte,
|
||||||
|
&peeraddr.sin6_addr.u.Byte,
|
||||||
|
sizeof localaddr.sin6_addr.u.Byte) == 0;
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
return localaddr.sin6_port == peeraddr.sin6_port
|
||||||
|
&& memcmp(&localaddr.sin6_addr.s6_addr,
|
||||||
|
&peeraddr.sin6_addr.s6_addr,
|
||||||
|
sizeof localaddr.sin6_addr.s6_addr) == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} } }
|
71
libs/brynet/net/SocketLibTypes.hpp
Normal file
71
libs/brynet/net/SocketLibTypes.hpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <brynet/base/Platform.hpp>
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <WinError.h>
|
||||||
|
#include <winsock.h>
|
||||||
|
#include <Ws2tcpip.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/eventfd.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/event.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unsupported OS, please commit an issuse."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
typedef SOCKET BrynetSocketFD;
|
||||||
|
#define BRYNET_ERRNO WSAGetLastError()
|
||||||
|
#define BRYNET_ENOTSOCK WSAENOTSOCK
|
||||||
|
#define BRYNET_EWOULDBLOCK WSAEWOULDBLOCK
|
||||||
|
#define BRYNET_EINTR WSAEINTR
|
||||||
|
#define BRYNET_ECONNABORTED WSAECONNABORTED
|
||||||
|
#define BRYNET_SOCKET_ERROR SOCKET_ERROR
|
||||||
|
#define BRYNET_INVALID_SOCKET INVALID_SOCKET
|
||||||
|
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX || defined BRYNET_PLATFORM_DARWIN
|
||||||
|
#define BRYNET_ERRNO errno
|
||||||
|
#define BRYNET_ENOTSOCK EBADF
|
||||||
|
#define BRYNET_EWOULDBLOCK EAGAIN
|
||||||
|
#define BRYNET_EINTR EINTR
|
||||||
|
#define BRYNET_ECONNABORTED ECONNABORTED
|
||||||
|
typedef int BrynetSocketFD;
|
||||||
|
#define BRYNET_SOCKET_ERROR (-1)
|
||||||
|
#define BRYNET_INVALID_SOCKET (-1)
|
||||||
|
#endif
|
1132
libs/brynet/net/TcpConnection.hpp
Normal file
1132
libs/brynet/net/TcpConnection.hpp
Normal file
File diff suppressed because it is too large
Load Diff
91
libs/brynet/net/TcpService.hpp
Normal file
91
libs/brynet/net/TcpService.hpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <brynet/net/detail/TCPServiceDetail.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace net {
|
||||||
|
|
||||||
|
class AddSocketOption
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using AddSocketOptionFunc = detail::AddSocketOptionFunc;
|
||||||
|
using AddSocketOptionInfo = detail::AddSocketOptionInfo;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static AddSocketOptionFunc AddEnterCallback(
|
||||||
|
TcpConnection::EnterCallback callback)
|
||||||
|
{
|
||||||
|
return [callback](AddSocketOptionInfo& option) {
|
||||||
|
option.enterCallback.push_back(callback);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#ifdef BRYNET_USE_OPENSSL
|
||||||
|
static AddSocketOptionFunc WithClientSideSSL()
|
||||||
|
{
|
||||||
|
return [](AddSocketOptionInfo& option) {
|
||||||
|
option.useSSL = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
static AddSocketOptionFunc WithServerSideSSL(SSLHelper::Ptr sslHelper)
|
||||||
|
{
|
||||||
|
return [sslHelper](AddSocketOptionInfo& option) {
|
||||||
|
option.sslHelper = sslHelper;
|
||||||
|
option.useSSL = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
static AddSocketOptionFunc WithMaxRecvBufferSize(size_t size)
|
||||||
|
{
|
||||||
|
return [size](AddSocketOptionInfo& option) {
|
||||||
|
option.maxRecvBufferSize = size;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
static AddSocketOptionFunc WithForceSameThreadLoop(bool same)
|
||||||
|
{
|
||||||
|
return [same](AddSocketOptionInfo& option) {
|
||||||
|
option.forceSameThreadLoop = same;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class TcpService : public detail::TcpServiceDetail,
|
||||||
|
public std::enable_shared_from_this<TcpService>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = std::shared_ptr<TcpService>;
|
||||||
|
using FrameCallback = detail::TcpServiceDetail::FrameCallback;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Ptr Create()
|
||||||
|
{
|
||||||
|
struct make_shared_enabler : public TcpService {};
|
||||||
|
return std::make_shared<make_shared_enabler>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void startWorkerThread(size_t threadNum,
|
||||||
|
FrameCallback callback = nullptr)
|
||||||
|
{
|
||||||
|
detail::TcpServiceDetail::startWorkerThread(threadNum, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopWorkerThread()
|
||||||
|
{
|
||||||
|
detail::TcpServiceDetail::stopWorkerThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Options>
|
||||||
|
bool addTcpConnection(TcpSocket::Ptr socket,
|
||||||
|
const Options& ... options)
|
||||||
|
{
|
||||||
|
return detail::TcpServiceDetail::addTcpConnection(std::move(socket), options...);
|
||||||
|
}
|
||||||
|
|
||||||
|
EventLoop::Ptr getRandomEventLoop()
|
||||||
|
{
|
||||||
|
return detail::TcpServiceDetail::getRandomEventLoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TcpService() = default;
|
||||||
|
};
|
||||||
|
|
||||||
|
} }
|
27
libs/brynet/net/detail/AddSocketOptionInfo.hpp
Normal file
27
libs/brynet/net/detail/AddSocketOptionInfo.hpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <brynet/net/TcpConnection.hpp>
|
||||||
|
#include <brynet/net/SSLHelper.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace net { namespace detail {
|
||||||
|
|
||||||
|
class AddSocketOptionInfo final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AddSocketOptionInfo()
|
||||||
|
{
|
||||||
|
useSSL = false;
|
||||||
|
forceSameThreadLoop = false;
|
||||||
|
maxRecvBufferSize = 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<TcpConnection::EnterCallback> enterCallback;
|
||||||
|
SSLHelper::Ptr sslHelper;
|
||||||
|
bool useSSL;
|
||||||
|
bool forceSameThreadLoop;
|
||||||
|
size_t maxRecvBufferSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
using AddSocketOptionFunc = std::function<void(AddSocketOptionInfo& option)>;
|
||||||
|
|
||||||
|
} } }
|
161
libs/brynet/net/detail/ConnectorDetail.hpp
Normal file
161
libs/brynet/net/detail/ConnectorDetail.hpp
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <cassert>
|
||||||
|
#include <set>
|
||||||
|
#include <map>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <brynet/base/NonCopyable.hpp>
|
||||||
|
#include <brynet/base/CPP_VERSION.hpp>
|
||||||
|
#include <brynet/base/Any.hpp>
|
||||||
|
#include <brynet/base/Noexcept.hpp>
|
||||||
|
#include <brynet/net/SocketLibFunction.hpp>
|
||||||
|
#include <brynet/net/Poller.hpp>
|
||||||
|
#include <brynet/net/Exception.hpp>
|
||||||
|
#include <brynet/net/EventLoop.hpp>
|
||||||
|
#include <brynet/net/Socket.hpp>
|
||||||
|
#include <brynet/net/detail/ConnectorWorkInfo.hpp>
|
||||||
|
|
||||||
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||||
|
#include <shared_mutex>
|
||||||
|
#else
|
||||||
|
#include <mutex>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace brynet { namespace net { namespace detail {
|
||||||
|
|
||||||
|
class AsyncConnectorDetail : public brynet::base::NonCopyable
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
void startWorkerThread()
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||||
|
std::lock_guard<std::shared_mutex> lck(mThreadGuard);
|
||||||
|
#else
|
||||||
|
std::lock_guard<std::mutex> lck(mThreadGuard);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (mThread != nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mIsRun = std::make_shared<bool>(true);
|
||||||
|
mWorkInfo = std::make_shared<detail::ConnectorWorkInfo>();
|
||||||
|
mEventLoop = std::make_shared<EventLoop>();
|
||||||
|
|
||||||
|
auto eventLoop = mEventLoop;
|
||||||
|
auto workerInfo = mWorkInfo;
|
||||||
|
auto isRun = mIsRun;
|
||||||
|
|
||||||
|
mThread = std::make_shared<std::thread>([eventLoop, workerInfo, isRun]() {
|
||||||
|
while (*isRun)
|
||||||
|
{
|
||||||
|
detail::RunOnceCheckConnect(eventLoop, workerInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
workerInfo->causeAllFailed();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopWorkerThread()
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||||
|
std::lock_guard<std::shared_mutex> lck(mThreadGuard);
|
||||||
|
#else
|
||||||
|
std::lock_guard<std::mutex> lck(mThreadGuard);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (mThread == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mEventLoop->runAsyncFunctor([this]() {
|
||||||
|
*mIsRun = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (mThread->joinable())
|
||||||
|
{
|
||||||
|
mThread->join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::system_error & e)
|
||||||
|
{
|
||||||
|
(void)e;
|
||||||
|
}
|
||||||
|
|
||||||
|
mEventLoop = nullptr;
|
||||||
|
mWorkInfo = nullptr;
|
||||||
|
mIsRun = nullptr;
|
||||||
|
mThread = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void asyncConnect(const std::vector<detail::ConnectOptionFunc>& options)
|
||||||
|
{
|
||||||
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||||
|
std::shared_lock<std::shared_mutex> lck(mThreadGuard);
|
||||||
|
#else
|
||||||
|
std::lock_guard<std::mutex> lck(mThreadGuard);
|
||||||
|
#endif
|
||||||
|
detail::ConnectOptionsInfo option;
|
||||||
|
for (const auto& func : options)
|
||||||
|
{
|
||||||
|
func(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option.completedCallback == nullptr && option.faledCallback == nullptr)
|
||||||
|
{
|
||||||
|
throw ConnectException("all callback is nullptr");
|
||||||
|
}
|
||||||
|
if (option.ip.empty())
|
||||||
|
{
|
||||||
|
throw ConnectException("addr is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(*mIsRun))
|
||||||
|
{
|
||||||
|
throw ConnectException("work thread already stop");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto workInfo = mWorkInfo;
|
||||||
|
auto address = detail::AsyncConnectAddr(std::move(option.ip),
|
||||||
|
option.port,
|
||||||
|
option.timeout,
|
||||||
|
std::move(option.completedCallback),
|
||||||
|
std::move(option.faledCallback),
|
||||||
|
std::move(option.processCallbacks));
|
||||||
|
mEventLoop->runAsyncFunctor([workInfo, address]() {
|
||||||
|
workInfo->processConnect(address);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AsyncConnectorDetail()
|
||||||
|
{
|
||||||
|
mIsRun = std::make_shared<bool>(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~AsyncConnectorDetail()
|
||||||
|
{
|
||||||
|
stopWorkerThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<EventLoop> mEventLoop;
|
||||||
|
|
||||||
|
std::shared_ptr<detail::ConnectorWorkInfo> mWorkInfo;
|
||||||
|
std::shared_ptr<std::thread> mThread;
|
||||||
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||||
|
std::shared_mutex mThreadGuard;
|
||||||
|
#else
|
||||||
|
std::mutex mThreadGuard;
|
||||||
|
#endif
|
||||||
|
std::shared_ptr<bool> mIsRun;
|
||||||
|
};
|
||||||
|
|
||||||
|
} } }
|
368
libs/brynet/net/detail/ConnectorWorkInfo.hpp
Normal file
368
libs/brynet/net/detail/ConnectorWorkInfo.hpp
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <brynet/base/NonCopyable.hpp>
|
||||||
|
#include <brynet/base/CPP_VERSION.hpp>
|
||||||
|
#include <brynet/net/SocketLibTypes.hpp>
|
||||||
|
#include <brynet/net/Socket.hpp>
|
||||||
|
#include <brynet/net/Poller.hpp>
|
||||||
|
|
||||||
|
#ifdef BRYNET_HAVE_LANG_CXX17
|
||||||
|
#include <shared_mutex>
|
||||||
|
#else
|
||||||
|
#include <mutex>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace brynet { namespace net { namespace detail {
|
||||||
|
|
||||||
|
class ConnectOptionsInfo;
|
||||||
|
using ConnectOptionFunc = std::function<void(ConnectOptionsInfo & option)>;
|
||||||
|
|
||||||
|
class AsyncConnectAddr final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using CompletedCallback = std::function<void(TcpSocket::Ptr)>;
|
||||||
|
using ProcessTcpSocketCallback = std::function<void(TcpSocket&)>;
|
||||||
|
using FailedCallback = std::function<void()>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AsyncConnectAddr(std::string&& ip,
|
||||||
|
int port,
|
||||||
|
std::chrono::nanoseconds timeout,
|
||||||
|
CompletedCallback&& successCB,
|
||||||
|
FailedCallback&& failedCB,
|
||||||
|
std::vector<ProcessTcpSocketCallback>&& processCallbacks)
|
||||||
|
:
|
||||||
|
mIP(std::move(ip)),
|
||||||
|
mPort(port),
|
||||||
|
mTimeout(timeout),
|
||||||
|
mSuccessCB(std::move(successCB)),
|
||||||
|
mFailedCB(std::move(failedCB)),
|
||||||
|
mProcessCallbacks(std::move(processCallbacks))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& getIP() const
|
||||||
|
{
|
||||||
|
return mIP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getPort() const
|
||||||
|
{
|
||||||
|
return mPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CompletedCallback& getSuccessCB() const
|
||||||
|
{
|
||||||
|
return mSuccessCB;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FailedCallback& getFailedCB() const
|
||||||
|
{
|
||||||
|
return mFailedCB;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<ProcessTcpSocketCallback>& getProcessCallbacks() const
|
||||||
|
{
|
||||||
|
return mProcessCallbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::nanoseconds getTimeout() const
|
||||||
|
{
|
||||||
|
return mTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::string mIP;
|
||||||
|
const int mPort;
|
||||||
|
const std::chrono::nanoseconds mTimeout;
|
||||||
|
const CompletedCallback mSuccessCB;
|
||||||
|
const FailedCallback mFailedCB;
|
||||||
|
const std::vector<ProcessTcpSocketCallback> mProcessCallbacks;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ConnectorWorkInfo final : public brynet::base::NonCopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = std::shared_ptr<ConnectorWorkInfo>;
|
||||||
|
|
||||||
|
ConnectorWorkInfo() BRYNET_NOEXCEPT
|
||||||
|
{
|
||||||
|
mPoller.reset(brynet::base::poller_new());
|
||||||
|
mPollResult.reset(brynet::base::stack_new(1024, sizeof(BrynetSocketFD)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkConnectStatus(int millsecond)
|
||||||
|
{
|
||||||
|
if (poller_poll(mPoller.get(), millsecond) <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::set<BrynetSocketFD> totalFds;
|
||||||
|
std::set<BrynetSocketFD> successFds;
|
||||||
|
|
||||||
|
poller_visitor(mPoller.get(), brynet::base::WriteCheck, mPollResult.get());
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
auto p = stack_popfront(mPollResult.get());
|
||||||
|
if (p == nullptr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto fd = *(BrynetSocketFD*)p;
|
||||||
|
totalFds.insert(fd);
|
||||||
|
if (isConnectSuccess(fd, false) &&
|
||||||
|
!brynet::net::base::IsSelfConnect(fd))
|
||||||
|
{
|
||||||
|
successFds.insert(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto fd : totalFds)
|
||||||
|
{
|
||||||
|
poller_remove(mPoller.get(), fd);
|
||||||
|
|
||||||
|
const auto it = mConnectingInfos.find(fd);
|
||||||
|
if (it == mConnectingInfos.end())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto socket = TcpSocket::Create(fd, false);
|
||||||
|
const auto& connectingInfo = it->second;
|
||||||
|
if (successFds.find(fd) != successFds.end())
|
||||||
|
{
|
||||||
|
for (const auto& process : connectingInfo.processCallbacks)
|
||||||
|
{
|
||||||
|
process(*socket);
|
||||||
|
}
|
||||||
|
if (connectingInfo.successCB != nullptr)
|
||||||
|
{
|
||||||
|
connectingInfo.successCB(std::move(socket));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (connectingInfo.failedCB != nullptr)
|
||||||
|
{
|
||||||
|
connectingInfo.failedCB();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mConnectingInfos.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isConnectSuccess(BrynetSocketFD clientfd, bool willCheckWrite) const
|
||||||
|
{
|
||||||
|
if (willCheckWrite && !poller_check(mPoller.get(), clientfd, brynet::base::WriteCheck))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int error = BRYNET_SOCKET_ERROR;
|
||||||
|
int len = sizeof(error);
|
||||||
|
if (getsockopt(clientfd,
|
||||||
|
SOL_SOCKET,
|
||||||
|
SO_ERROR,
|
||||||
|
(char*)&error,
|
||||||
|
(socklen_t*)&len) == BRYNET_SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return error == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkTimeout()
|
||||||
|
{
|
||||||
|
for (auto it = mConnectingInfos.begin(); it != mConnectingInfos.end();)
|
||||||
|
{
|
||||||
|
const auto now = std::chrono::steady_clock::now();
|
||||||
|
if ((now - it->second.startConnectTime) < it->second.timeout)
|
||||||
|
{
|
||||||
|
++it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fd = it->first;
|
||||||
|
auto cb = it->second.failedCB;
|
||||||
|
|
||||||
|
poller_remove(mPoller.get(), fd);
|
||||||
|
mConnectingInfos.erase(it++);
|
||||||
|
|
||||||
|
brynet::net::base::SocketClose(fd);
|
||||||
|
if (cb != nullptr)
|
||||||
|
{
|
||||||
|
//TODO::don't modify mConnectingInfos in cb
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void processConnect(const AsyncConnectAddr& addr)
|
||||||
|
{
|
||||||
|
struct sockaddr_in server_addr = sockaddr_in();
|
||||||
|
BrynetSocketFD clientfd = BRYNET_INVALID_SOCKET;
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
const int ExpectedError = WSAEWOULDBLOCK;
|
||||||
|
#else
|
||||||
|
const int ExpectedError = EINPROGRESS;
|
||||||
|
#endif
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
brynet::net::base::InitSocket();
|
||||||
|
|
||||||
|
clientfd = brynet::net::base::SocketCreate(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (clientfd == BRYNET_INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
brynet::net::base::SocketNonblock(clientfd);
|
||||||
|
server_addr.sin_family = AF_INET;
|
||||||
|
inet_pton(AF_INET, addr.getIP().c_str(), &server_addr.sin_addr.s_addr);
|
||||||
|
server_addr.sin_port = static_cast<decltype(server_addr.sin_port)>(htons(addr.getPort()));
|
||||||
|
|
||||||
|
n = connect(clientfd, (struct sockaddr*) & server_addr, sizeof(struct sockaddr));
|
||||||
|
if (n == 0)
|
||||||
|
{
|
||||||
|
if (brynet::net::base::IsSelfConnect(clientfd))
|
||||||
|
{
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (BRYNET_ERRNO != ExpectedError)
|
||||||
|
{
|
||||||
|
goto FAILED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConnectingInfo ci;
|
||||||
|
ci.startConnectTime = std::chrono::steady_clock::now();
|
||||||
|
ci.successCB = addr.getSuccessCB();
|
||||||
|
ci.failedCB = addr.getFailedCB();
|
||||||
|
ci.timeout = addr.getTimeout();
|
||||||
|
ci.processCallbacks = addr.getProcessCallbacks();
|
||||||
|
|
||||||
|
mConnectingInfos[clientfd] = ci;
|
||||||
|
poller_add(mPoller.get(), clientfd, brynet::base::WriteCheck);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (addr.getSuccessCB() != nullptr)
|
||||||
|
{
|
||||||
|
auto tcpSocket = TcpSocket::Create(clientfd, false);
|
||||||
|
for (const auto& process : addr.getProcessCallbacks())
|
||||||
|
{
|
||||||
|
process(*tcpSocket);
|
||||||
|
}
|
||||||
|
addr.getSuccessCB()(std::move(tcpSocket));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
FAILED:
|
||||||
|
if (clientfd != BRYNET_INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
brynet::net::base::SocketClose(clientfd);
|
||||||
|
clientfd = BRYNET_INVALID_SOCKET;
|
||||||
|
(void)clientfd;
|
||||||
|
}
|
||||||
|
if (addr.getFailedCB() != nullptr)
|
||||||
|
{
|
||||||
|
addr.getFailedCB()();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void causeAllFailed()
|
||||||
|
{
|
||||||
|
auto copyMap = mConnectingInfos;
|
||||||
|
mConnectingInfos.clear();
|
||||||
|
|
||||||
|
for (const auto& v : copyMap)
|
||||||
|
{
|
||||||
|
auto fd = v.first;
|
||||||
|
auto cb = v.second.failedCB;
|
||||||
|
|
||||||
|
poller_remove(mPoller.get(), fd);
|
||||||
|
brynet::net::base::SocketClose(fd);
|
||||||
|
if (cb != nullptr)
|
||||||
|
{
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
class ConnectingInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConnectingInfo()
|
||||||
|
{
|
||||||
|
timeout = std::chrono::nanoseconds::zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::chrono::steady_clock::time_point startConnectTime;
|
||||||
|
std::chrono::nanoseconds timeout;
|
||||||
|
AsyncConnectAddr::CompletedCallback successCB;
|
||||||
|
AsyncConnectAddr::FailedCallback failedCB;
|
||||||
|
std::vector<AsyncConnectAddr::ProcessTcpSocketCallback> processCallbacks;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<BrynetSocketFD, ConnectingInfo> mConnectingInfos;
|
||||||
|
|
||||||
|
class PollerDeleter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void operator()(struct brynet::base::poller_s* ptr) const
|
||||||
|
{
|
||||||
|
brynet::base::poller_delete(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
class StackDeleter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void operator()(struct brynet::base::stack_s* ptr) const
|
||||||
|
{
|
||||||
|
brynet::base::stack_delete(ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<struct brynet::base::poller_s, PollerDeleter> mPoller;
|
||||||
|
std::unique_ptr<struct brynet::base::stack_s, StackDeleter> mPollResult;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void RunOnceCheckConnect(
|
||||||
|
const std::shared_ptr<brynet::net::EventLoop>& eventLoop,
|
||||||
|
const std::shared_ptr<ConnectorWorkInfo>& workerInfo)
|
||||||
|
{
|
||||||
|
eventLoop->loop(std::chrono::milliseconds(10).count());
|
||||||
|
workerInfo->checkConnectStatus(0);
|
||||||
|
workerInfo->checkTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConnectOptionsInfo final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ConnectOptionsInfo()
|
||||||
|
:
|
||||||
|
port(0),
|
||||||
|
timeout(std::chrono::seconds(10))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ip;
|
||||||
|
int port;
|
||||||
|
std::chrono::nanoseconds timeout;
|
||||||
|
std::vector<AsyncConnectAddr::ProcessTcpSocketCallback> processCallbacks;
|
||||||
|
AsyncConnectAddr::CompletedCallback completedCallback;
|
||||||
|
AsyncConnectAddr::FailedCallback faledCallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
} } }
|
67
libs/brynet/net/detail/IOLoopData.hpp
Normal file
67
libs/brynet/net/detail/IOLoopData.hpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <thread>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <brynet/base/NonCopyable.hpp>
|
||||||
|
#include <brynet/net/EventLoop.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace net { namespace detail {
|
||||||
|
|
||||||
|
class TcpServiceDetail;
|
||||||
|
|
||||||
|
class IOLoopData : public brynet::base::NonCopyable,
|
||||||
|
public std::enable_shared_from_this<IOLoopData>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Ptr = std::shared_ptr<IOLoopData>;
|
||||||
|
|
||||||
|
static Ptr Create(EventLoop::Ptr eventLoop,
|
||||||
|
std::shared_ptr<std::thread> ioThread)
|
||||||
|
{
|
||||||
|
class make_shared_enabler : public IOLoopData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
make_shared_enabler(EventLoop::Ptr eventLoop,
|
||||||
|
std::shared_ptr<std::thread> ioThread)
|
||||||
|
:
|
||||||
|
IOLoopData(std::move(eventLoop), std::move(ioThread))
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
return std::make_shared<make_shared_enabler>(std::move(eventLoop),
|
||||||
|
std::move(ioThread));
|
||||||
|
}
|
||||||
|
|
||||||
|
const EventLoop::Ptr& getEventLoop() const
|
||||||
|
{
|
||||||
|
return mEventLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const std::shared_ptr<std::thread>& getIOThread() const
|
||||||
|
{
|
||||||
|
return mIOThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
IOLoopData(EventLoop::Ptr eventLoop,
|
||||||
|
std::shared_ptr<std::thread> ioThread)
|
||||||
|
:
|
||||||
|
mEventLoop(std::move(eventLoop)),
|
||||||
|
mIOThread(std::move(ioThread))
|
||||||
|
{}
|
||||||
|
virtual ~IOLoopData() = default;
|
||||||
|
|
||||||
|
const EventLoop::Ptr mEventLoop;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::shared_ptr<std::thread> mIOThread;
|
||||||
|
|
||||||
|
friend class TcpServiceDetail;
|
||||||
|
};
|
||||||
|
|
||||||
|
using IOLoopDataPtr = std::shared_ptr<IOLoopData>;
|
||||||
|
|
||||||
|
} } }
|
169
libs/brynet/net/detail/ListenThreadDetail.hpp
Normal file
169
libs/brynet/net/detail/ListenThreadDetail.hpp
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
|
#include <thread>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <brynet/base/NonCopyable.hpp>
|
||||||
|
#include <brynet/base/Noexcept.hpp>
|
||||||
|
#include <brynet/net/SocketLibFunction.hpp>
|
||||||
|
#include <brynet/net/AsyncConnector.hpp>
|
||||||
|
#include <brynet/net/wrapper/ConnectionBuilder.hpp>
|
||||||
|
#include <brynet/net/Socket.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace net { namespace detail {
|
||||||
|
|
||||||
|
class ListenThreadDetail : public brynet::base::NonCopyable
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
using AccepCallback = std::function<void(TcpSocket::Ptr)>;
|
||||||
|
using TcpSocketProcessCallback = std::function<void(TcpSocket&)>;
|
||||||
|
|
||||||
|
void startListen()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lck(mListenThreadGuard);
|
||||||
|
|
||||||
|
if (mListenThread != nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto fd = brynet::net::base::Listen(mIsIPV6, mIP.c_str(), mPort, 512);
|
||||||
|
if (fd == BRYNET_INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
throw BrynetCommonException(
|
||||||
|
std::string("listen error of:") + std::to_string(BRYNET_ERRNO));
|
||||||
|
}
|
||||||
|
|
||||||
|
mRunListen = std::make_shared<bool>(true);
|
||||||
|
|
||||||
|
auto listenSocket = std::shared_ptr<ListenSocket>(ListenSocket::Create(fd));
|
||||||
|
auto isRunListen = mRunListen;
|
||||||
|
auto callback = mCallback;
|
||||||
|
auto processCallbacks = mProcessCallbacks;
|
||||||
|
mListenThread = std::make_shared<std::thread>(
|
||||||
|
[isRunListen, listenSocket, callback, processCallbacks]() mutable {
|
||||||
|
while (*isRunListen)
|
||||||
|
{
|
||||||
|
auto clientSocket = runOnceListen(listenSocket);
|
||||||
|
if (clientSocket == nullptr)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*isRunListen)
|
||||||
|
{
|
||||||
|
for (const auto& process : processCallbacks)
|
||||||
|
{
|
||||||
|
process(*clientSocket);
|
||||||
|
}
|
||||||
|
callback(std::move(clientSocket));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopListen()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lck(mListenThreadGuard);
|
||||||
|
|
||||||
|
if (mListenThread == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*mRunListen = false;
|
||||||
|
auto selfIP = mIP;
|
||||||
|
if (selfIP == "0.0.0.0")
|
||||||
|
{
|
||||||
|
selfIP = "127.0.0.1";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto connector = AsyncConnector::Create();
|
||||||
|
connector->startWorkerThread();
|
||||||
|
|
||||||
|
wrapper::SocketConnectBuilder connectBuilder;
|
||||||
|
connectBuilder
|
||||||
|
.configureConnector(connector)
|
||||||
|
.configureConnectOptions({
|
||||||
|
ConnectOption::WithTimeout(std::chrono::seconds(2)),
|
||||||
|
ConnectOption::WithAddr(selfIP, mPort)
|
||||||
|
})
|
||||||
|
.syncConnect();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (mListenThread->joinable())
|
||||||
|
{
|
||||||
|
mListenThread->join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::system_error & e)
|
||||||
|
{
|
||||||
|
(void)e;
|
||||||
|
}
|
||||||
|
mListenThread = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ListenThreadDetail(bool isIPV6,
|
||||||
|
const std::string& ip,
|
||||||
|
int port,
|
||||||
|
const AccepCallback& callback,
|
||||||
|
const std::vector<TcpSocketProcessCallback>& processCallbacks)
|
||||||
|
:
|
||||||
|
mIsIPV6(isIPV6),
|
||||||
|
mIP(ip),
|
||||||
|
mPort(port),
|
||||||
|
mCallback(callback),
|
||||||
|
mProcessCallbacks(processCallbacks)
|
||||||
|
{
|
||||||
|
if (mCallback == nullptr)
|
||||||
|
{
|
||||||
|
throw BrynetCommonException("accept callback is nullptr");
|
||||||
|
}
|
||||||
|
mRunListen = std::make_shared<bool>(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~ListenThreadDetail() BRYNET_NOEXCEPT
|
||||||
|
{
|
||||||
|
stopListen();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static brynet::net::TcpSocket::Ptr runOnceListen(const std::shared_ptr<ListenSocket>& listenSocket)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return listenSocket->accept();
|
||||||
|
}
|
||||||
|
catch (const EintrError & e)
|
||||||
|
{
|
||||||
|
std::cerr << "accept eintr execption:" << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
catch (const AcceptError & e)
|
||||||
|
{
|
||||||
|
std::cerr << "accept execption:" << e.what() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const bool mIsIPV6;
|
||||||
|
const std::string mIP;
|
||||||
|
const int mPort;
|
||||||
|
const AccepCallback mCallback;
|
||||||
|
const std::vector<TcpSocketProcessCallback> mProcessCallbacks;
|
||||||
|
|
||||||
|
std::shared_ptr<bool> mRunListen;
|
||||||
|
std::shared_ptr<std::thread> mListenThread;
|
||||||
|
std::mutex mListenThreadGuard;
|
||||||
|
};
|
||||||
|
|
||||||
|
} } }
|
198
libs/brynet/net/detail/TCPServiceDetail.hpp
Normal file
198
libs/brynet/net/detail/TCPServiceDetail.hpp
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <functional>
|
||||||
|
#include <thread>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <memory>
|
||||||
|
#include <random>
|
||||||
|
|
||||||
|
#include <brynet/base/NonCopyable.hpp>
|
||||||
|
#include <brynet/base/Noexcept.hpp>
|
||||||
|
#include <brynet/net/TcpConnection.hpp>
|
||||||
|
#include <brynet/net/SSLHelper.hpp>
|
||||||
|
#include <brynet/net/Socket.hpp>
|
||||||
|
#include <brynet/net/detail/IOLoopData.hpp>
|
||||||
|
#include <brynet/net/detail/AddSocketOptionInfo.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace net { namespace detail {
|
||||||
|
|
||||||
|
class TcpServiceDetail : public brynet::base::NonCopyable
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
using FrameCallback = std::function<void(const EventLoop::Ptr&)>;
|
||||||
|
const static unsigned int sDefaultLoopTimeOutMS = 100;
|
||||||
|
|
||||||
|
void startWorkerThread(size_t threadNum,
|
||||||
|
FrameCallback callback = nullptr)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lck(mServiceGuard);
|
||||||
|
std::lock_guard<std::mutex> lock(mIOLoopGuard);
|
||||||
|
|
||||||
|
if (!mIOLoopDatas.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mRunIOLoop = std::make_shared<bool>(true);
|
||||||
|
|
||||||
|
mIOLoopDatas.resize(threadNum);
|
||||||
|
for (auto& v : mIOLoopDatas)
|
||||||
|
{
|
||||||
|
auto eventLoop = std::make_shared<EventLoop>();
|
||||||
|
auto runIoLoop = mRunIOLoop;
|
||||||
|
v = IOLoopData::Create(eventLoop,
|
||||||
|
std::make_shared<std::thread>(
|
||||||
|
[callback, runIoLoop, eventLoop]() {
|
||||||
|
while (*runIoLoop)
|
||||||
|
{
|
||||||
|
eventLoop->loopCompareNearTimer(sDefaultLoopTimeOutMS);
|
||||||
|
if (callback != nullptr)
|
||||||
|
{
|
||||||
|
callback(eventLoop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopWorkerThread()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lck(mServiceGuard);
|
||||||
|
std::lock_guard<std::mutex> lock(mIOLoopGuard);
|
||||||
|
|
||||||
|
*mRunIOLoop = false;
|
||||||
|
|
||||||
|
for (const auto& v : mIOLoopDatas)
|
||||||
|
{
|
||||||
|
v->getEventLoop()->wakeup();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (v->getIOThread()->joinable())
|
||||||
|
{
|
||||||
|
v->getIOThread()->join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (std::system_error & e)
|
||||||
|
{
|
||||||
|
(void)e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mIOLoopDatas.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Options>
|
||||||
|
bool addTcpConnection(TcpSocket::Ptr socket,
|
||||||
|
const Options& ... options)
|
||||||
|
{
|
||||||
|
return _addTcpConnection(std::move(socket), { options... });
|
||||||
|
}
|
||||||
|
|
||||||
|
EventLoop::Ptr getRandomEventLoop()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mIOLoopGuard);
|
||||||
|
|
||||||
|
const auto ioLoopSize = mIOLoopDatas.size();
|
||||||
|
if (ioLoopSize == 0)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else if (ioLoopSize == 1)
|
||||||
|
{
|
||||||
|
return mIOLoopDatas.front()->getEventLoop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return mIOLoopDatas[mRandom() % ioLoopSize]->getEventLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpServiceDetail() BRYNET_NOEXCEPT
|
||||||
|
:
|
||||||
|
mRandom(static_cast<unsigned int>(
|
||||||
|
std::chrono::system_clock::now().time_since_epoch().count()))
|
||||||
|
{
|
||||||
|
mRunIOLoop = std::make_shared<bool>(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~TcpServiceDetail() BRYNET_NOEXCEPT
|
||||||
|
{
|
||||||
|
stopWorkerThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _addTcpConnection(TcpSocket::Ptr socket,
|
||||||
|
const std::vector<AddSocketOptionFunc>& optionFuncs)
|
||||||
|
{
|
||||||
|
AddSocketOptionInfo options;
|
||||||
|
for (const auto& v : optionFuncs)
|
||||||
|
{
|
||||||
|
if (v != nullptr)
|
||||||
|
{
|
||||||
|
v(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.maxRecvBufferSize <= 0)
|
||||||
|
{
|
||||||
|
throw BrynetCommonException("buffer size is zero");
|
||||||
|
}
|
||||||
|
|
||||||
|
EventLoop::Ptr eventLoop;
|
||||||
|
if (options.forceSameThreadLoop)
|
||||||
|
{
|
||||||
|
eventLoop = getSameThreadEventLoop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eventLoop = getRandomEventLoop();
|
||||||
|
}
|
||||||
|
if (eventLoop == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto wrapperEnterCallback = [options](const TcpConnection::Ptr& tcpConnection) {
|
||||||
|
for (const auto& callback : options.enterCallback)
|
||||||
|
{
|
||||||
|
callback(tcpConnection);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.useSSL && options.sslHelper == nullptr)
|
||||||
|
{
|
||||||
|
options.sslHelper = SSLHelper::Create();
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpConnection::Create(std::move(socket),
|
||||||
|
options.maxRecvBufferSize,
|
||||||
|
wrapperEnterCallback,
|
||||||
|
eventLoop,
|
||||||
|
options.sslHelper);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
EventLoop::Ptr getSameThreadEventLoop()
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mIOLoopGuard);
|
||||||
|
for (const auto& v : mIOLoopDatas)
|
||||||
|
{
|
||||||
|
if (v->getEventLoop()->isInLoopThread())
|
||||||
|
{
|
||||||
|
return v->getEventLoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<IOLoopDataPtr> mIOLoopDatas;
|
||||||
|
mutable std::mutex mIOLoopGuard;
|
||||||
|
std::shared_ptr<bool> mRunIOLoop;
|
||||||
|
|
||||||
|
std::mutex mServiceGuard;
|
||||||
|
std::mt19937 mRandom;
|
||||||
|
};
|
||||||
|
|
||||||
|
} } }
|
139
libs/brynet/net/detail/WakeupChannel.hpp
Normal file
139
libs/brynet/net/detail/WakeupChannel.hpp
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
#include <mutex>
|
||||||
|
#include <memory>
|
||||||
|
#include <atomic>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include <brynet/base/NonCopyable.hpp>
|
||||||
|
#include <brynet/net/SocketLibFunction.hpp>
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
#include <brynet/net/port/Win.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <brynet/net/Channel.hpp>
|
||||||
|
#include <brynet/net/Socket.hpp>
|
||||||
|
|
||||||
|
namespace brynet { namespace net { namespace detail {
|
||||||
|
|
||||||
|
#ifdef BRYNET_PLATFORM_WINDOWS
|
||||||
|
class WakeupChannel final : public Channel, public brynet::base::NonCopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit WakeupChannel(HANDLE iocp)
|
||||||
|
:
|
||||||
|
mIOCP(iocp),
|
||||||
|
mWakeupOvl(port::Win::OverlappedType::OverlappedRecv)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wakeup() BRYNET_NOEXCEPT
|
||||||
|
{
|
||||||
|
return PostQueuedCompletionStatus(mIOCP,
|
||||||
|
0,
|
||||||
|
reinterpret_cast<ULONG_PTR>(this),
|
||||||
|
&mWakeupOvl.base);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void canRecv() BRYNET_NOEXCEPT override
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void canSend() BRYNET_NOEXCEPT override
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onClose() BRYNET_NOEXCEPT override
|
||||||
|
{
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE mIOCP;
|
||||||
|
port::Win::OverlappedExt mWakeupOvl;
|
||||||
|
};
|
||||||
|
#elif defined BRYNET_PLATFORM_LINUX
|
||||||
|
class WakeupChannel final : public Channel, public brynet::base::NonCopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit WakeupChannel(BrynetSocketFD fd) : mUniqueFd(fd)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wakeup()
|
||||||
|
{
|
||||||
|
uint64_t one = 1;
|
||||||
|
return write(mUniqueFd.getFD(), &one, sizeof one) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void canRecv() override
|
||||||
|
{
|
||||||
|
char temp[1024 * 10];
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
auto n = read(mUniqueFd.getFD(), temp, sizeof(temp));
|
||||||
|
if (n == -1 || static_cast<size_t>(n) < sizeof(temp))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void canSend() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void onClose() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
UniqueFd mUniqueFd;
|
||||||
|
};
|
||||||
|
|
||||||
|
#elif defined BRYNET_PLATFORM_DARWIN
|
||||||
|
class WakeupChannel final : public Channel, public brynet::base::NonCopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit WakeupChannel(int kqueuefd, int ident)
|
||||||
|
:
|
||||||
|
mKqueueFd(kqueuefd),
|
||||||
|
mUserEvent(ident)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wakeup()
|
||||||
|
{
|
||||||
|
struct kevent ev;
|
||||||
|
EV_SET(&ev, mUserEvent, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL);
|
||||||
|
|
||||||
|
struct timespec timeout = { 0, 0 };
|
||||||
|
return kevent(mKqueueFd, &ev, 1, NULL, 0, &timeout) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void canRecv() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void canSend() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void onClose() override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int mKqueueFd;
|
||||||
|
int mUserEvent;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} } }
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user